Commit df269e6e authored by jfb's avatar jfb Committed by Commit bot

WebAssembly: skip unknown sections, add names

Sets the code up so it'll be easier to have section names as strings instead of
hard-coded numbers. Using strings will require synchronizing with sexpr-wasm.

Mostly NFC (besides now skipping *all* unknown sections).

R=titzer@chromium.org

Review URL: https://codereview.chromium.org/1743773002

Cr-Commit-Position: refs/heads/master@{#34464}
parent 62bc168d
......@@ -231,9 +231,22 @@ class Decoder {
return traceOffEnd<uint32_t>();
}
// Consume {size} bytes and send them to the bit bucket, advancing {pc_}.
void consume_bytes(int size) {
if (checkAvailable(size)) {
pc_ += size;
} else {
pc_ = limit_;
}
}
// Check that at least {size} bytes exist between {pc_} and {limit_}.
bool checkAvailable(int size) {
if (pc_ < start_ || (pc_ + size) > limit_) {
intptr_t pc_overflow_value = std::numeric_limits<intptr_t>::max() - size;
if (size < 0 || (intptr_t)pc_ > pc_overflow_value) {
error(pc_, nullptr, "reading %d bytes would underflow/overflow", size);
return false;
} else if (pc_ < start_ || limit_ < (pc_ + size)) {
error(pc_, nullptr, "expected %d bytes, fell off end", size);
return false;
} else {
......
......@@ -78,14 +78,21 @@ class ModuleDecoder : public Decoder {
// Decode the module sections.
while (pc_ < limit_) {
TRACE("DecodeSection\n");
WasmSectionDeclCode section =
static_cast<WasmSectionDeclCode>(consume_u8("section"));
// Each section should appear at most once.
if (section < kMaxModuleSectionCode) {
CheckForPreviousSection(sections, section, false);
sections[section] = true;
uint8_t section_u8 = consume_u8("section");
if (section_u8 >= kMaxModuleSectionCode) {
// Skip unknown section.
int length;
uint32_t section_bytes = consume_u32v(&length, "section size");
consume_bytes(section_bytes);
continue;
}
// Each section should appear at most once.
auto section = static_cast<WasmSectionDeclCode>(section_u8);
CheckForPreviousSection(sections, section, false);
sections[section] = true;
switch (section) {
case kDeclEnd:
// Terminate section decoding.
......@@ -279,23 +286,8 @@ class ModuleDecoder : public Decoder {
}
break;
}
case kDeclWLL: {
// Reserved for experimentation by the Web Low-level Language project
// which is augmenting the binary encoding with source code meta
// information. This section does not affect the semantics of the code
// and can be ignored by the runtime. https://github.com/JSStats/wll
int length = 0;
uint32_t section_size = consume_u32v(&length, "section size");
if (pc_ + section_size > limit_ || pc_ + section_size < pc_) {
error(pc_ - length, "invalid section size");
break;
}
pc_ += section_size;
break;
}
default:
error(pc_ - 1, nullptr, "unrecognized section 0x%02x", section);
break;
case kMaxModuleSectionCode:
UNREACHABLE(); // Already skipped unknown sections.
}
}
......
......@@ -25,22 +25,29 @@ const size_t kMaxStringSize = 256;
const uint32_t kWasmMagic = 0x6d736100;
const uint32_t kWasmVersion = 0x0a;
enum WasmSectionDeclCode {
kDeclMemory = 0x00,
kDeclSignatures = 0x01,
kDeclFunctions = 0x02,
kDeclGlobals = 0x03,
kDeclDataSegments = 0x04,
kDeclFunctionTable = 0x05,
kDeclEnd = 0x06,
kDeclStartFunction = 0x07,
kDeclImportTable = 0x08,
kDeclExportTable = 0x09,
kDeclWLL = 0x11,
// WebAssembly sections are named as strings in the binary format, but
// internally V8 uses an enum to handle them.
//
// Entries have the form F(enumerator, string).
#define FOR_EACH_WASM_SECTION_TYPE(F) \
F(kDeclMemory, "memory") \
F(kDeclSignatures, "signatures") \
F(kDeclFunctions, "functions") \
F(kDeclGlobals, "globals") \
F(kDeclDataSegments, "data_segments") \
F(kDeclFunctionTable, "function_table") \
F(kDeclEnd, "end") \
F(kDeclStartFunction, "start_function") \
F(kDeclImportTable, "import_table") \
F(kDeclExportTable, "export_table")
enum WasmSectionDeclCode : uint32_t {
#define F(enumerator, string) enumerator,
FOR_EACH_WASM_SECTION_TYPE(F)
#undef F
kMaxModuleSectionCode
};
static const int kMaxModuleSectionCode = 0x11;
enum WasmFunctionDeclBit {
kDeclFunctionName = 0x01,
kDeclFunctionImport = 0x02,
......
......@@ -932,28 +932,27 @@ TEST_F(WasmFunctionVerifyTest, Ok_v_v_empty) {
if (result.val) delete result.val;
}
TEST_F(WasmModuleVerifyTest, WLLSectionNoLen) {
TEST_F(WasmModuleVerifyTest, UnknownSectionNoLen) {
const byte data[] = {
kDeclWLL, // section without length.
kMaxModuleSectionCode, // unknown section without length.
};
EXPECT_FAILURE(data);
}
TEST_F(WasmModuleVerifyTest, WLLSectionEmpty) {
static const byte data[] = {
kDeclWLL, 0, // empty section
};
ModuleResult result = DecodeModule(data, data + arraysize(data));
EXPECT_TRUE(result.ok());
if (result.val) delete result.val;
TEST_F(WasmModuleVerifyTest, UnknownSectionEmpty) {
for (int i = 0; i < 255 - kMaxModuleSectionCode; ++i) {
const byte data[] = {
byte(kMaxModuleSectionCode + i), 0, // empty unknown section
};
ModuleResult result = DecodeModule(data, data + arraysize(data));
EXPECT_TRUE(result.ok());
if (result.val) delete result.val;
}
}
TEST_F(WasmModuleVerifyTest, WLLSectionOne) {
TEST_F(WasmModuleVerifyTest, UnknownSectionOne) {
static const byte data[] = {
kDeclWLL,
kMaxModuleSectionCode,
1, // LEB128 1
0, // one byte section
};
......@@ -962,47 +961,108 @@ TEST_F(WasmModuleVerifyTest, WLLSectionOne) {
if (result.val) delete result.val;
}
TEST_F(WasmModuleVerifyTest, WLLSectionTen) {
TEST_F(WasmModuleVerifyTest, UnknownSectionTen) {
static const byte data[] = {
kDeclWLL,
10, // LEB128 10
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // 10 byte section
kMaxModuleSectionCode,
10, // LEB128 10
1,
2,
3,
4,
5,
6,
7,
8,
9,
10, // 10 byte section
};
ModuleResult result = DecodeModule(data, data + arraysize(data));
EXPECT_TRUE(result.ok());
if (result.val) delete result.val;
}
TEST_F(WasmModuleVerifyTest, WLLSectionOverflow) {
TEST_F(WasmModuleVerifyTest, UnknownSectionOverflow) {
static const byte data[] = {
kDeclWLL,
11, // LEB128 11
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // 10 byte section
kMaxModuleSectionCode,
11, // LEB128 11
1,
2,
3,
4,
5,
6,
7,
8,
9,
10, // 10 byte section
};
EXPECT_FAILURE(data);
}
TEST_F(WasmModuleVerifyTest, WLLSectionUnderflow) {
TEST_F(WasmModuleVerifyTest, UnknownSectionUnderflow) {
static const byte data[] = {
kDeclWLL, 0xff, 0xff, 0xff, 0xff, 0x0f, // LEB128 0xffffffff
1, 2, 3, 4, // 4 byte section
kMaxModuleSectionCode,
0xff,
0xff,
0xff,
0xff,
0x0f, // LEB128 0xffffffff
1,
2,
3,
4, // 4 byte section
};
EXPECT_FAILURE(data);
}
TEST_F(WasmModuleVerifyTest, WLLSectionLoop) {
TEST_F(WasmModuleVerifyTest, UnknownSectionLoop) {
// Would infinite loop decoding if wrapping and allowed.
static const byte data[] = {
kDeclWLL, 0xfa, 0xff, 0xff, 0xff, 0x0f, // LEB128 0xfffffffa
1, 2, 3, 4, // 4 byte section
kMaxModuleSectionCode,
0xfa,
0xff,
0xff,
0xff,
0x0f, // LEB128 0xfffffffa
1,
2,
3,
4, // 4 byte section
};
EXPECT_FAILURE(data);
}
TEST_F(WasmModuleVerifyTest, UnknownSectionSkipped) {
static const byte data[] = {
kMaxModuleSectionCode,
1, // LEB128 1
0, // one byte section
kDeclGlobals,
1,
0,
0,
0,
0, // name offset
kMemI32, // memory type
0, // exported
};
ModuleResult result = DecodeModule(data, data + arraysize(data));
EXPECT_TRUE(result.ok());
EXPECT_EQ(1, result.val->globals.size());
EXPECT_EQ(0, result.val->functions.size());
EXPECT_EQ(0, result.val->data_segments.size());
WasmGlobal* global = &result.val->globals.back();
EXPECT_EQ(0, global->name_offset);
EXPECT_EQ(MachineType::Int32(), global->type);
EXPECT_EQ(0, global->offset);
EXPECT_FALSE(global->exported);
if (result.val) delete result.val;
}
TEST_F(WasmModuleVerifyTest, ImportTable_empty) {
static const byte data[] = {kDeclSignatures, 0, kDeclImportTable, 0};
EXPECT_VERIFIES(data);
......
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