Commit a5f00fd1 authored by Manos Koukoutos's avatar Manos Koukoutos Committed by Commit Bot

[wasm] OpcodeLength should detect invalid opcodes

OpcodeLength in function-body-decoder was implemented in a way that did
not detect invalid non-prefixed opcodes, even when {validate} was on.
This CL brings its behavior in line with prefixed opcodes and validation
requirements.

Change-Id: I53fec32f13bd18a2ed0c7a7666d69fc09603db56
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2552516
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#71368}
parent 0b3fe3ad
...@@ -1582,52 +1582,46 @@ class WasmDecoder : public Decoder { ...@@ -1582,52 +1582,46 @@ class WasmDecoder : public Decoder {
return true; return true;
} }
// Returns the length of the opcode under {pc}.
static uint32_t OpcodeLength(WasmDecoder* decoder, const byte* pc) { static uint32_t OpcodeLength(WasmDecoder* decoder, const byte* pc) {
WasmOpcode opcode = static_cast<WasmOpcode>(*pc); WasmOpcode opcode = static_cast<WasmOpcode>(*pc);
switch (opcode) { switch (opcode) {
#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name: /********** Control opcodes **********/
FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE) case kExprUnreachable:
FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE) case kExprNop:
#undef DECLARE_OPCODE_CASE case kExprElse:
{ case kExprEnd:
MemoryAccessImmediate<validate> imm(decoder, pc + 1, UINT32_MAX); case kExprReturn:
return 1;
case kExprTry:
case kExprIf:
case kExprLoop:
case kExprBlock: {
BlockTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1);
return 1 + imm.length; return 1 + imm.length;
} }
case kExprBr: case kExprBr:
case kExprBrIf: { case kExprBrIf:
case kExprBrOnNull: {
BranchDepthImmediate<validate> imm(decoder, pc + 1); BranchDepthImmediate<validate> imm(decoder, pc + 1);
return 1 + imm.length; return 1 + imm.length;
} }
case kExprGlobalGet: case kExprBrTable: {
case kExprGlobalSet: { BranchTableImmediate<validate> imm(decoder, pc + 1);
GlobalIndexImmediate<validate> imm(decoder, pc + 1); BranchTableIterator<validate> iterator(decoder, imm);
return 1 + imm.length; return 1 + iterator.length();
}
case kExprTableGet:
case kExprTableSet: {
TableIndexImmediate<validate> imm(decoder, pc + 1);
return 1 + imm.length;
}
case kExprCallFunction:
case kExprReturnCall: {
CallFunctionImmediate<validate> imm(decoder, pc + 1);
return 1 + imm.length;
} }
case kExprCallIndirect: case kExprThrow: {
case kExprReturnCallIndirect: { ExceptionIndexImmediate<validate> imm(decoder, pc + 1);
CallIndirectImmediate<validate> imm(WasmFeatures::All(), decoder,
pc + 1);
return 1 + imm.length; return 1 + imm.length;
} }
case kExprCatch:
case kExprTry: case kExprRethrow:
case kExprIf: // fall through return 1;
case kExprLoop: case kExprBrOnExn: {
case kExprBlock: { BranchOnExceptionImmediate<validate> imm(decoder, pc + 1);
BlockTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1);
return 1 + imm.length; return 1 + imm.length;
} }
case kExprLet: { case kExprLet: {
BlockTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1); BlockTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1);
uint32_t locals_length; uint32_t locals_length;
...@@ -1637,35 +1631,42 @@ class WasmDecoder : public Decoder { ...@@ -1637,35 +1631,42 @@ class WasmDecoder : public Decoder {
return 1 + imm.length + (locals_result ? locals_length : 0); return 1 + imm.length + (locals_result ? locals_length : 0);
} }
case kExprThrow: { /********** Misc opcodes **********/
ExceptionIndexImmediate<validate> imm(decoder, pc + 1); case kExprCallFunction:
case kExprReturnCall: {
CallFunctionImmediate<validate> imm(decoder, pc + 1);
return 1 + imm.length; return 1 + imm.length;
} }
case kExprCallIndirect:
case kExprBrOnExn: { case kExprReturnCallIndirect: {
BranchOnExceptionImmediate<validate> imm(decoder, pc + 1); CallIndirectImmediate<validate> imm(WasmFeatures::All(), decoder,
pc + 1);
return 1 + imm.length; return 1 + imm.length;
} }
case kExprCallRef:
case kExprBrOnNull: { case kExprReturnCallRef:
BranchDepthImmediate<validate> imm(decoder, pc + 1); case kExprDrop:
case kExprSelect:
return 1;
case kExprSelectWithType: {
SelectTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1);
return 1 + imm.length; return 1 + imm.length;
} }
case kExprLocalGet: case kExprLocalGet:
case kExprLocalSet: case kExprLocalSet:
case kExprLocalTee: { case kExprLocalTee: {
LocalIndexImmediate<validate> imm(decoder, pc + 1); LocalIndexImmediate<validate> imm(decoder, pc + 1);
return 1 + imm.length; return 1 + imm.length;
} }
case kExprSelectWithType: { case kExprGlobalGet:
SelectTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1); case kExprGlobalSet: {
GlobalIndexImmediate<validate> imm(decoder, pc + 1);
return 1 + imm.length; return 1 + imm.length;
} }
case kExprBrTable: { case kExprTableGet:
BranchTableImmediate<validate> imm(decoder, pc + 1); case kExprTableSet: {
BranchTableIterator<validate> iterator(decoder, imm); TableIndexImmediate<validate> imm(decoder, pc + 1);
return 1 + iterator.length(); return 1 + imm.length;
} }
case kExprI32Const: { case kExprI32Const: {
ImmI32Immediate<validate> imm(decoder, pc + 1); ImmI32Immediate<validate> imm(decoder, pc + 1);
...@@ -1675,6 +1676,10 @@ class WasmDecoder : public Decoder { ...@@ -1675,6 +1676,10 @@ class WasmDecoder : public Decoder {
ImmI64Immediate<validate> imm(decoder, pc + 1); ImmI64Immediate<validate> imm(decoder, pc + 1);
return 1 + imm.length; return 1 + imm.length;
} }
case kExprF32Const:
return 5;
case kExprF64Const:
return 9;
case kExprRefNull: { case kExprRefNull: {
HeapTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1); HeapTypeImmediate<validate> imm(WasmFeatures::All(), decoder, pc + 1);
return 1 + imm.length; return 1 + imm.length;
...@@ -1686,15 +1691,28 @@ class WasmDecoder : public Decoder { ...@@ -1686,15 +1691,28 @@ class WasmDecoder : public Decoder {
FunctionIndexImmediate<validate> imm(decoder, pc + 1); FunctionIndexImmediate<validate> imm(decoder, pc + 1);
return 1 + imm.length; return 1 + imm.length;
} }
case kExprRefAsNonNull:
return 1;
#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
// clang-format off
/********** Simple and memory opcodes **********/
FOREACH_SIMPLE_OPCODE(DECLARE_OPCODE_CASE)
FOREACH_SIMPLE_PROTOTYPE_OPCODE(DECLARE_OPCODE_CASE)
return 1;
FOREACH_LOAD_MEM_OPCODE(DECLARE_OPCODE_CASE)
FOREACH_STORE_MEM_OPCODE(DECLARE_OPCODE_CASE) {
MemoryAccessImmediate<validate> imm(decoder, pc + 1, UINT32_MAX);
return 1 + imm.length;
}
// clang-format on
case kExprMemoryGrow: case kExprMemoryGrow:
case kExprMemorySize: { case kExprMemorySize: {
MemoryIndexImmediate<validate> imm(decoder, pc + 1); MemoryIndexImmediate<validate> imm(decoder, pc + 1);
return 1 + imm.length; return 1 + imm.length;
} }
case kExprF32Const:
return 5; /********** Prefixed opcodes **********/
case kExprF64Const:
return 9;
case kNumericPrefix: { case kNumericPrefix: {
uint32_t length = 0; uint32_t length = 0;
opcode = decoder->read_prefixed_opcode<validate>(pc, &length); opcode = decoder->read_prefixed_opcode<validate>(pc, &length);
...@@ -1743,7 +1761,9 @@ class WasmDecoder : public Decoder { ...@@ -1743,7 +1761,9 @@ class WasmDecoder : public Decoder {
return length + imm.length; return length + imm.length;
} }
default: default:
if (validate) {
decoder->DecodeError(pc, "invalid numeric opcode"); decoder->DecodeError(pc, "invalid numeric opcode");
}
return length; return length;
} }
} }
...@@ -1751,17 +1771,13 @@ class WasmDecoder : public Decoder { ...@@ -1751,17 +1771,13 @@ class WasmDecoder : public Decoder {
uint32_t length = 0; uint32_t length = 0;
opcode = decoder->read_prefixed_opcode<validate>(pc, &length); opcode = decoder->read_prefixed_opcode<validate>(pc, &length);
switch (opcode) { switch (opcode) {
#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name: // clang-format off
FOREACH_SIMD_0_OPERAND_OPCODE(DECLARE_OPCODE_CASE) FOREACH_SIMD_0_OPERAND_OPCODE(DECLARE_OPCODE_CASE)
#undef DECLARE_OPCODE_CASE
return length; return length;
#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name:
FOREACH_SIMD_1_OPERAND_OPCODE(DECLARE_OPCODE_CASE) FOREACH_SIMD_1_OPERAND_OPCODE(DECLARE_OPCODE_CASE)
#undef DECLARE_OPCODE_CASE
return length + 1; return length + 1;
#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name: // clang-format on
FOREACH_SIMD_MEM_OPCODE(DECLARE_OPCODE_CASE) FOREACH_SIMD_MEM_OPCODE(DECLARE_OPCODE_CASE)
#undef DECLARE_OPCODE_CASE
case kExprPrefetchT: case kExprPrefetchT:
case kExprPrefetchNT: { case kExprPrefetchNT: {
MemoryAccessImmediate<validate> imm(decoder, pc + length, MemoryAccessImmediate<validate> imm(decoder, pc + length,
...@@ -1786,7 +1802,9 @@ class WasmDecoder : public Decoder { ...@@ -1786,7 +1802,9 @@ class WasmDecoder : public Decoder {
case kExprI8x16Shuffle: case kExprI8x16Shuffle:
return length + kSimd128Size; return length + kSimd128Size;
default: default:
if (validate) {
decoder->DecodeError(pc, "invalid SIMD opcode"); decoder->DecodeError(pc, "invalid SIMD opcode");
}
return length; return length;
} }
} }
...@@ -1795,22 +1813,18 @@ class WasmDecoder : public Decoder { ...@@ -1795,22 +1813,18 @@ class WasmDecoder : public Decoder {
opcode = decoder->read_prefixed_opcode<validate>(pc, &length, opcode = decoder->read_prefixed_opcode<validate>(pc, &length,
"atomic_index"); "atomic_index");
switch (opcode) { switch (opcode) {
#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name: FOREACH_ATOMIC_OPCODE(DECLARE_OPCODE_CASE) {
FOREACH_ATOMIC_OPCODE(DECLARE_OPCODE_CASE)
#undef DECLARE_OPCODE_CASE
{
MemoryAccessImmediate<validate> imm(decoder, pc + length, MemoryAccessImmediate<validate> imm(decoder, pc + length,
UINT32_MAX); UINT32_MAX);
return length + imm.length; return length + imm.length;
} }
#define DECLARE_OPCODE_CASE(name, opcode, sig) case kExpr##name: FOREACH_ATOMIC_0_OPERAND_OPCODE(DECLARE_OPCODE_CASE) {
FOREACH_ATOMIC_0_OPERAND_OPCODE(DECLARE_OPCODE_CASE)
#undef DECLARE_OPCODE_CASE
{
return length + 1; return length + 1;
} }
default: default:
if (validate) {
decoder->DecodeError(pc, "invalid Atomics opcode"); decoder->DecodeError(pc, "invalid Atomics opcode");
}
return length; return length;
} }
} }
...@@ -1853,7 +1867,6 @@ class WasmDecoder : public Decoder { ...@@ -1853,7 +1867,6 @@ class WasmDecoder : public Decoder {
pc + length); pc + length);
return length + imm.length; return length + imm.length;
} }
case kExprI31New: case kExprI31New:
case kExprI31GetS: case kExprI31GetS:
case kExprI31GetU: case kExprI31GetU:
...@@ -1866,16 +1879,36 @@ class WasmDecoder : public Decoder { ...@@ -1866,16 +1879,36 @@ class WasmDecoder : public Decoder {
pc + length + ht1.length); pc + length + ht1.length);
return length + ht1.length + ht2.length; return length + ht1.length + ht2.length;
} }
default: default:
// This is unreachable except for malformed modules. // This is unreachable except for malformed modules.
if (validate) {
decoder->DecodeError(pc, "invalid gc opcode"); decoder->DecodeError(pc, "invalid gc opcode");
}
return length; return length;
} }
} }
default:
// clang-format off
/********** Asmjs opcodes **********/
FOREACH_ASMJS_COMPAT_OPCODE(DECLARE_OPCODE_CASE)
return 1; return 1;
// Prefixed opcodes (already handled, included here for completeness of
// switch)
FOREACH_SIMD_OPCODE(DECLARE_OPCODE_CASE)
FOREACH_NUMERIC_OPCODE(DECLARE_OPCODE_CASE)
FOREACH_ATOMIC_OPCODE(DECLARE_OPCODE_CASE)
FOREACH_ATOMIC_0_OPERAND_OPCODE(DECLARE_OPCODE_CASE)
FOREACH_GC_OPCODE(DECLARE_OPCODE_CASE)
UNREACHABLE();
// clang-format on
#undef DECLARE_OPCODE_CASE
}
// Invalid modules will reach this point.
if (validate) {
decoder->DecodeError(pc, "invalid opcode");
} }
return 1;
} }
// TODO(clemensb): This is only used by the interpreter; move there. // TODO(clemensb): This is only used by the interpreter; move there.
......
...@@ -183,6 +183,12 @@ TEST_F(WasmLoopAssignmentAnalyzerTest, Malformed) { ...@@ -183,6 +183,12 @@ TEST_F(WasmLoopAssignmentAnalyzerTest, Malformed) {
CHECK_NULL(assigned); CHECK_NULL(assigned);
} }
TEST_F(WasmLoopAssignmentAnalyzerTest, InvalidOpcode) {
byte code[] = {WASM_LOOP(0xFF)};
BitVector* assigned = Analyze(code, code + arraysize(code));
EXPECT_EQ(assigned, nullptr);
}
TEST_F(WasmLoopAssignmentAnalyzerTest, regress_642867) { TEST_F(WasmLoopAssignmentAnalyzerTest, regress_642867) {
static const byte code[] = { static const byte code[] = {
WASM_LOOP(WASM_ZERO, kExprLocalSet, 0xFA, 0xFF, 0xFF, 0xFF, WASM_LOOP(WASM_ZERO, kExprLocalSet, 0xFA, 0xFF, 0xFF, 0xFF,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment