Repository: tetratelabs/wazero
Pull request #693 (2022-07-13 07:25:42)

func_validation: do not modify original types in unreachable state
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>


Patch:
diff --git a/internal/engine/interpreter/interpreter.go b/internal/engine/interpreter/interpreter.go
index b3054ce9..b3b23f6f 100644
--- a/internal/engine/interpreter/interpreter.go
+++ b/internal/engine/interpreter/interpreter.go
@@ -4078,7 +4078,6 @@ func (ce *callEngine) callNativeFunc(ctx context.Context, callCtx *wasm.CallCont
 			ce.pushValue(retLo)
 			ce.pushValue(retHi)
 			frame.pc++
-			frame.pc++
 		}
 	}
 	ce.popFrame()
diff --git a/internal/wasm/func_validation.go b/internal/wasm/func_validation.go
index f9c645cc..013f5096 100644
--- a/internal/wasm/func_validation.go
+++ b/internal/wasm/func_validation.go
@@ -464,11 +464,14 @@ func (m *Module) validateFunctionWithMaxStackValues(
 				return fmt.Errorf("cannot pop the required operand for %s", OpcodeBrTableName)
 			}
 			lnLabel := controlBlockStack[len(controlBlockStack)-1-int(ln)]
-			expTypes := lnLabel.blockType.Results
-			if lnLabel.op == OpcodeLoop {
-				// Loop operation doesn't require results since the continuation is
-				// the beginning of the loop.
-				expTypes = []ValueType{}
+			var expTypes []ValueType
+			if lnLabel.op != OpcodeLoop { // Loop operation doesn't require results since the continuation is the beginning of the loop.
+				expTypes = make([]ValueType, len(lnLabel.blockType.Results))
+				// Below, we might modify the slice in case of unreachable. Therefore,
+				// we have to copy the content of block result types, otherwise the original
+				// function type might result in invalid value types if the block is the outermost label
+				// which equals the function's type.
+				copy(expTypes, lnLabel.blockType.Results)
 			}
 
 			if enabledFeatures.Get(FeatureReferenceTypes) {
diff --git a/internal/wazeroir/format.go b/internal/wazeroir/format.go
index 39772b31..ae8223b1 100644
--- a/internal/wazeroir/format.go
+++ b/internal/wazeroir/format.go
@@ -185,6 +185,12 @@ func formatOperation(w io.StringWriter, b Operation) {
 		str = fmt.Sprintf("v128.const [%#x, %#x]", o.Lo, o.Hi)
 	case *OperationV128Add:
 		str = fmt.Sprintf("v128.add (shape=%s)", shapeName(o.Shape))
+	case *OperationV128ITruncSatFromF:
+		if o.Signed {
+			str = fmt.Sprintf("v128.ITruncSatFrom%sS", shapeName(o.OriginShape))
+		} else {
+			str = fmt.Sprintf("v128.ITruncSatFrom%sU", shapeName(o.OriginShape))
+		}
 	default:
 		panic("unreachable: a bug in wazeroir implementation")
 	}


Test patch:
diff --git a/internal/wasm/func_validation_test.go b/internal/wasm/func_validation_test.go
index 51265377..7dfdfc2e 100644
--- a/internal/wasm/func_validation_test.go
+++ b/internal/wasm/func_validation_test.go
@@ -3348,3 +3348,36 @@ func TestDecodeBlockType(t *testing.T) {
 		}
 	})
 }
+
+// TestFuncValidation_UnreachableBrTable_NotModifyTypes ensures that we do not modify the
+// original function type during the function validation with the presence of unreachable br_table
+// targeting the function return label.
+func TestFuncValidation_UnreachableBrTable_NotModifyTypes(t *testing.T) {
+	funcType := &FunctionType{Params: []ValueType{},
+		// Meaning that the signature of outermost label has non-trivial results.
+		Results: []ValueType{i32, i64},
+	}
+	m := &Module{
+		TypeSection:     []*FunctionType{funcType},
+		FunctionSection: []Index{0},
+		CodeSection: []*Code{
+			{Body: []byte{
+				OpcodeUnreachable,
+				// Having br_table in unreachable state.
+				OpcodeI32Const, 1,
+				// Setting the destination as lalbels of index 0 which
+				// is the function return. Therefore, the expected value types
+				// for each label can be "any".
+				OpcodeBrTable, 0, 0, 0,
+				OpcodeEnd,
+			}},
+		},
+	}
+	err := m.validateFunction(FeatureReferenceTypes, 0, nil, nil, nil, nil, nil)
+	require.NoError(t, err)
+
+	afterValidationResultTypes := funcType.Results
+	require.Equal(t, 2, len(afterValidationResultTypes))
+	require.Equal(t, i32, afterValidationResultTypes[0])
+	require.Equal(t, i64, afterValidationResultTypes[1])
+}