Repository: tetratelabs/wazero
Pull request #2097 (2024-02-27 02:55:39)

validation: returns error on unexpected end of function

mathetake: found in https://github.com/tetratelabs/wazero/actions/runs/8057956650/job/22009991155

Patch:
diff --git a/internal/wasm/func_validation.go b/internal/wasm/func_validation.go
index 0d72f384..592ac869 100644
--- a/internal/wasm/func_validation.go
+++ b/internal/wasm/func_validation.go
@@ -95,6 +95,10 @@ func (m *Module) validateFunctionWithMaxStackValues(
 			fmt.Printf("handling %s, stack=%s, blocks: %v\n", instName, valueTypeStack.stack, controlBlockStack)
 		}
 
+		if len(controlBlockStack.stack) == 0 {
+			return fmt.Errorf("unexpected end of function at pc=%#x", pc)
+		}
+
 		if OpcodeI32Load <= op && op <= OpcodeI64Store32 {
 			if memory == nil {
 				return fmt.Errorf("memory must exist for %s", InstructionName(op))
@@ -1815,9 +1819,6 @@ func (m *Module) validateFunctionWithMaxStackValues(
 			valueTypeStack.pushStackLimit(len(bt.Params))
 			pc += num
 		} else if op == OpcodeElse {
-			if len(controlBlockStack.stack) == 0 {
-				return fmt.Errorf("redundant Else instruction at %#x", pc)
-			}
 			bl := &controlBlockStack.stack[len(controlBlockStack.stack)-1]
 			bl.elseAt = pc
 			// Check the type soundness of the instructions *before* entering this else Op.
@@ -1831,9 +1832,6 @@ func (m *Module) validateFunctionWithMaxStackValues(
 				valueTypeStack.push(p)
 			}
 		} else if op == OpcodeEnd {
-			if len(controlBlockStack.stack) == 0 {
-				return fmt.Errorf("redundant End instruction at %#x", pc)
-			}
 			bl := controlBlockStack.pop()
 			bl.endAt = pc
 


Test patch:
diff --git a/internal/integration_test/fuzzcases/fuzzcases_test.go b/internal/integration_test/fuzzcases/fuzzcases_test.go
index e9f15364..3d9cc928 100644
--- a/internal/integration_test/fuzzcases/fuzzcases_test.go
+++ b/internal/integration_test/fuzzcases/fuzzcases_test.go
@@ -3,6 +3,7 @@ package fuzzcases
 import (
 	"context"
 	"embed"
+	"encoding/hex"
 	"fmt"
 	"math"
 	"runtime"
@@ -1032,3 +1033,13 @@ func Test2096(t *testing.T) {
 	}
 	nodiff.RequireNoDiffT(t, getWasmBinary(t, "2096"), true, true)
 }
+
+func Test2097(t *testing.T) {
+	bin, err := hex.DecodeString("0061736d010000000107016000037f7f7f02010003030200000a49022f0010010004001001027d00024002400240024002400240440000000000000000000b0b0b0b0b0b000b0005000b000b1703017c017c017e00000000000000000000000b43420b0b")
+	require.NoError(t, err)
+
+	r := wazero.NewRuntime(context.Background())
+	_, err = r.Instantiate(ctx, bin)
+	require.Error(t, err)
+	require.Contains(t, err.Error(), "unexpected end of function")
+}
diff --git a/internal/wasm/func_validation_test.go b/internal/wasm/func_validation_test.go
index 57edb5a3..f7e53324 100644
--- a/internal/wasm/func_validation_test.go
+++ b/internal/wasm/func_validation_test.go
@@ -3586,7 +3586,7 @@ func TestFunctionValidation_redundantEnd(t *testing.T) {
 	}
 	err := m.validateFunction(&stacks{}, api.CoreFeaturesV2,
 		0, nil, nil, nil, nil, nil, bytes.NewReader(nil))
-	require.EqualError(t, err, "redundant End instruction at 0x1")
+	require.EqualError(t, err, "unexpected end of function at pc=0x1")
 }
 
 // TestFunctionValidation_redundantEnd is found in th validation fuzzing.
@@ -3598,7 +3598,7 @@ func TestFunctionValidation_redundantElse(t *testing.T) {
 	}
 	err := m.validateFunction(&stacks{}, api.CoreFeaturesV2,
 		0, nil, nil, nil, nil, nil, bytes.NewReader(nil))
-	require.EqualError(t, err, "redundant Else instruction at 0x1")
+	require.EqualError(t, err, "unexpected end of function at pc=0x1")
 }
 
 func Test_SplitCallStack(t *testing.T) {