[wasm] Enforce strict ordering of WASM module sections.
R=jfb@chromium.org,rossberg@chromium.org BUG= Review URL: https://codereview.chromium.org/1900153002 Cr-Commit-Position: refs/heads/master@{#35698}
This commit is contained in:
parent
4a6a0f5530
commit
b3cf031eb8
@ -59,16 +59,16 @@ void EmitVarInt(byte** b, size_t val) {
|
||||
// We generate a large varint which we then fixup later when the size is known.
|
||||
//
|
||||
// TODO(jfb) Not strictly necessary since sizes are calculated ahead of time.
|
||||
const size_t padded_varint = 5;
|
||||
const size_t kPaddedVarintSize = 5;
|
||||
|
||||
void FixupSection(byte* start, byte* end) {
|
||||
// Same as LEBHelper::write_u32v, but fixed-width with zeroes in the MSBs.
|
||||
size_t val = end - start - padded_varint;
|
||||
size_t val = end - start - kPaddedVarintSize;
|
||||
TRACE(" fixup %u\n", (unsigned)val);
|
||||
for (size_t pos = 0; pos != padded_varint; ++pos) {
|
||||
for (size_t pos = 0; pos != kPaddedVarintSize; ++pos) {
|
||||
size_t next = val >> 7;
|
||||
byte out = static_cast<byte>(val & 0x7f);
|
||||
if (pos != padded_varint - 1) {
|
||||
if (pos != kPaddedVarintSize - 1) {
|
||||
*(start++) = 0x80 | out;
|
||||
val = next;
|
||||
} else {
|
||||
@ -80,15 +80,18 @@ void FixupSection(byte* start, byte* end) {
|
||||
|
||||
// Returns the start of the section, where the section VarInt size is.
|
||||
byte* EmitSection(WasmSection::Code code, byte** b) {
|
||||
// Emit a placeholder for the length.
|
||||
byte* start = *b;
|
||||
const char* name = WasmSection::getName(code);
|
||||
size_t length = WasmSection::getNameLength(code);
|
||||
TRACE("emit section: %s\n", name);
|
||||
for (size_t padding = 0; padding != padded_varint; ++padding) {
|
||||
for (size_t padding = 0; padding != kPaddedVarintSize; ++padding) {
|
||||
EmitUint8(b, 0xff); // Will get fixed up later.
|
||||
}
|
||||
// Emit the section name.
|
||||
const char* name = WasmSection::getName(code);
|
||||
TRACE("emit section: %s\n", name);
|
||||
size_t length = WasmSection::getNameLength(code);
|
||||
EmitVarInt(b, length); // Section name string size.
|
||||
for (size_t i = 0; i != length; ++i) EmitUint8(b, name[i]);
|
||||
|
||||
return start;
|
||||
}
|
||||
} // namespace
|
||||
@ -548,7 +551,7 @@ struct Sizes {
|
||||
}
|
||||
|
||||
void AddSection(WasmSection::Code code, size_t other_size) {
|
||||
Add(padded_varint +
|
||||
Add(kPaddedVarintSize +
|
||||
LEBHelper::sizeof_u32v(WasmSection::getNameLength(code)) +
|
||||
WasmSection::getNameLength(code),
|
||||
0);
|
||||
@ -561,11 +564,6 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const {
|
||||
|
||||
sizes.Add(2 * sizeof(uint32_t), 0); // header
|
||||
|
||||
sizes.AddSection(WasmSection::Code::Memory, 0);
|
||||
sizes.Add(kDeclMemorySize, 0);
|
||||
TRACE("Size after memory: %u, %u\n", (unsigned)sizes.header_size,
|
||||
(unsigned)sizes.body_size);
|
||||
|
||||
if (globals_.size() > 0) {
|
||||
sizes.AddSection(WasmSection::Code::Globals, globals_.size());
|
||||
/* These globals never have names, so are always 3 bytes. */
|
||||
@ -595,6 +593,21 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const {
|
||||
(unsigned)sizes.body_size);
|
||||
}
|
||||
|
||||
if (indirect_functions_.size() > 0) {
|
||||
sizes.AddSection(WasmSection::Code::FunctionTable,
|
||||
indirect_functions_.size());
|
||||
for (auto function_index : indirect_functions_) {
|
||||
sizes.Add(LEBHelper::sizeof_u32v(function_index), 0);
|
||||
}
|
||||
TRACE("Size after indirect functions: %u, %u\n",
|
||||
(unsigned)sizes.header_size, (unsigned)sizes.body_size);
|
||||
}
|
||||
|
||||
sizes.AddSection(WasmSection::Code::Memory, 0);
|
||||
sizes.Add(kDeclMemorySize, 0);
|
||||
TRACE("Size after memory: %u, %u\n", (unsigned)sizes.header_size,
|
||||
(unsigned)sizes.body_size);
|
||||
|
||||
if (start_function_index_ >= 0) {
|
||||
sizes.AddSection(WasmSection::Code::StartFunction, 0);
|
||||
sizes.Add(LEBHelper::sizeof_u32v(start_function_index_), 0);
|
||||
@ -611,16 +624,6 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const {
|
||||
(unsigned)sizes.body_size);
|
||||
}
|
||||
|
||||
if (indirect_functions_.size() > 0) {
|
||||
sizes.AddSection(WasmSection::Code::FunctionTable,
|
||||
indirect_functions_.size());
|
||||
for (auto function_index : indirect_functions_) {
|
||||
sizes.Add(LEBHelper::sizeof_u32v(function_index), 0);
|
||||
}
|
||||
TRACE("Size after indirect functions: %u, %u\n",
|
||||
(unsigned)sizes.header_size, (unsigned)sizes.body_size);
|
||||
}
|
||||
|
||||
if (sizes.body_size > 0) {
|
||||
sizes.AddSection(WasmSection::Code::End, 0);
|
||||
TRACE("Size after end: %u, %u\n", (unsigned)sizes.header_size,
|
||||
@ -637,16 +640,6 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const {
|
||||
EmitUint32(&header, kWasmMagic);
|
||||
EmitUint32(&header, kWasmVersion);
|
||||
|
||||
// -- emit memory declaration ------------------------------------------------
|
||||
{
|
||||
byte* section = EmitSection(WasmSection::Code::Memory, &header);
|
||||
EmitVarInt(&header, 16); // min memory size
|
||||
EmitVarInt(&header, 16); // max memory size
|
||||
EmitUint8(&header, 0); // memory export
|
||||
static_assert(kDeclMemorySize == 3, "memory size must match emit above");
|
||||
FixupSection(section, header);
|
||||
}
|
||||
|
||||
// -- emit globals -----------------------------------------------------------
|
||||
if (globals_.size() > 0) {
|
||||
byte* section = EmitSection(WasmSection::Code::Globals, &header);
|
||||
@ -690,6 +683,27 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const {
|
||||
FixupSection(section, header);
|
||||
}
|
||||
|
||||
// -- emit function table ----------------------------------------------------
|
||||
if (indirect_functions_.size() > 0) {
|
||||
byte* section = EmitSection(WasmSection::Code::FunctionTable, &header);
|
||||
EmitVarInt(&header, indirect_functions_.size());
|
||||
|
||||
for (auto index : indirect_functions_) {
|
||||
EmitVarInt(&header, index);
|
||||
}
|
||||
FixupSection(section, header);
|
||||
}
|
||||
|
||||
// -- emit memory declaration ------------------------------------------------
|
||||
{
|
||||
byte* section = EmitSection(WasmSection::Code::Memory, &header);
|
||||
EmitVarInt(&header, 16); // min memory size
|
||||
EmitVarInt(&header, 16); // max memory size
|
||||
EmitUint8(&header, 0); // memory export
|
||||
static_assert(kDeclMemorySize == 3, "memory size must match emit above");
|
||||
FixupSection(section, header);
|
||||
}
|
||||
|
||||
// -- emit start function index ----------------------------------------------
|
||||
if (start_function_index_ >= 0) {
|
||||
byte* section = EmitSection(WasmSection::Code::StartFunction, &header);
|
||||
@ -708,17 +722,6 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const {
|
||||
FixupSection(section, header);
|
||||
}
|
||||
|
||||
// -- emit function table ----------------------------------------------------
|
||||
if (indirect_functions_.size() > 0) {
|
||||
byte* section = EmitSection(WasmSection::Code::FunctionTable, &header);
|
||||
EmitVarInt(&header, indirect_functions_.size());
|
||||
|
||||
for (auto index : indirect_functions_) {
|
||||
EmitVarInt(&header, index);
|
||||
}
|
||||
FixupSection(section, header);
|
||||
}
|
||||
|
||||
if (sizes.body_size > 0) {
|
||||
byte* section = EmitSection(WasmSection::Code::End, &header);
|
||||
FixupSection(section, header);
|
||||
|
@ -25,7 +25,6 @@ namespace wasm {
|
||||
#define TRACE(...)
|
||||
#endif
|
||||
|
||||
|
||||
// The main logic for decoding the bytes of a module.
|
||||
class ModuleDecoder : public Decoder {
|
||||
public:
|
||||
@ -79,9 +78,8 @@ class ModuleDecoder : public Decoder {
|
||||
module->mem_external = false;
|
||||
module->origin = origin_;
|
||||
|
||||
bool sections[(size_t)WasmSection::Code::Max] = {false};
|
||||
|
||||
const byte* pos = pc_;
|
||||
int current_order = 0;
|
||||
uint32_t magic_word = consume_u32("wasm magic");
|
||||
#define BYTES(x) (x & 0xff), (x >> 8) & 0xff, (x >> 16) & 0xff, (x >> 24) & 0xff
|
||||
if (magic_word != kWasmMagic) {
|
||||
@ -109,33 +107,37 @@ class ModuleDecoder : public Decoder {
|
||||
TRACE("DecodeSection\n");
|
||||
pos = pc_;
|
||||
|
||||
int length;
|
||||
uint32_t section_length = consume_u32v(&length, "section size");
|
||||
|
||||
int section_string_leb_length = 0;
|
||||
uint32_t section_string_length = 0;
|
||||
WasmSection::Code section = consume_section_name(
|
||||
§ion_string_leb_length, §ion_string_length);
|
||||
uint32_t string_and_leb_length =
|
||||
section_string_leb_length + section_string_length;
|
||||
if (string_and_leb_length > section_length) {
|
||||
error(pos, pos,
|
||||
"section string of size %u longer than total section bytes %u",
|
||||
string_and_leb_length, section_length);
|
||||
// Read and check the section size.
|
||||
int section_leb_length = 0;
|
||||
uint32_t section_length =
|
||||
consume_u32v(§ion_leb_length, "section length");
|
||||
if (!checkAvailable(section_length)) {
|
||||
// The section would extend beyond the end of the module.
|
||||
break;
|
||||
}
|
||||
const byte* section_start = pc_;
|
||||
const byte* expected_section_end = pc_ + section_length;
|
||||
|
||||
if (section == WasmSection::Code::Max) {
|
||||
// Skip unknown section.
|
||||
uint32_t skip = section_length - string_and_leb_length;
|
||||
TRACE("skipping %u bytes from unknown section\n", skip);
|
||||
consume_bytes(skip);
|
||||
continue;
|
||||
// Read the section name.
|
||||
int string_leb_length = 0;
|
||||
uint32_t string_length =
|
||||
consume_u32v(&string_leb_length, "section name length");
|
||||
const byte* section_name_start = pc_;
|
||||
consume_bytes(string_length);
|
||||
if (failed()) {
|
||||
TRACE("Section name of length %u couldn't be read\n", string_length);
|
||||
break;
|
||||
}
|
||||
if (pc_ > expected_section_end) {
|
||||
error(section_name_start, pc_,
|
||||
"section name string %u longer than total section bytes %u",
|
||||
string_length, section_length);
|
||||
}
|
||||
|
||||
// Each section should appear at most once.
|
||||
CheckForPreviousSection(sections, section, false);
|
||||
sections[(size_t)section] = true;
|
||||
WasmSection::Code section =
|
||||
WasmSection::lookup(section_name_start, string_length);
|
||||
|
||||
current_order = CheckSectionOrder(current_order, section);
|
||||
|
||||
switch (section) {
|
||||
case WasmSection::Code::End:
|
||||
@ -163,9 +165,6 @@ class ModuleDecoder : public Decoder {
|
||||
break;
|
||||
}
|
||||
case WasmSection::Code::FunctionSignatures: {
|
||||
// Functions require a signature table first.
|
||||
CheckForPreviousSection(sections, WasmSection::Code::Signatures,
|
||||
true);
|
||||
int length;
|
||||
uint32_t functions_count = consume_u32v(&length, "functions count");
|
||||
module->functions.reserve(SafeReserve(functions_count));
|
||||
@ -178,9 +177,6 @@ class ModuleDecoder : public Decoder {
|
||||
break;
|
||||
}
|
||||
case WasmSection::Code::FunctionBodies: {
|
||||
// Function bodies should follow signatures.
|
||||
CheckForPreviousSection(sections,
|
||||
WasmSection::Code::FunctionSignatures, true);
|
||||
int length;
|
||||
const byte* pos = pc_;
|
||||
uint32_t functions_count = consume_u32v(&length, "functions count");
|
||||
@ -207,9 +203,6 @@ class ModuleDecoder : public Decoder {
|
||||
break;
|
||||
}
|
||||
case WasmSection::Code::Functions: {
|
||||
// Functions require a signature table first.
|
||||
CheckForPreviousSection(sections, WasmSection::Code::Signatures,
|
||||
true);
|
||||
int length;
|
||||
uint32_t functions_count = consume_u32v(&length, "functions count");
|
||||
module->functions.reserve(SafeReserve(functions_count));
|
||||
@ -243,9 +236,6 @@ class ModuleDecoder : public Decoder {
|
||||
break;
|
||||
}
|
||||
case WasmSection::Code::Names: {
|
||||
// Names correspond to functions.
|
||||
CheckForPreviousSection(sections,
|
||||
WasmSection::Code::FunctionSignatures, true);
|
||||
int length;
|
||||
const byte* pos = pc_;
|
||||
uint32_t functions_count = consume_u32v(&length, "functions count");
|
||||
@ -341,9 +331,6 @@ class ModuleDecoder : public Decoder {
|
||||
break;
|
||||
}
|
||||
case WasmSection::Code::ImportTable: {
|
||||
// Declares an import table.
|
||||
CheckForPreviousSection(sections, WasmSection::Code::Signatures,
|
||||
true);
|
||||
int length;
|
||||
uint32_t import_table_count =
|
||||
consume_u32v(&length, "import table count");
|
||||
@ -392,7 +379,25 @@ class ModuleDecoder : public Decoder {
|
||||
break;
|
||||
}
|
||||
case WasmSection::Code::Max:
|
||||
UNREACHABLE(); // Already skipped unknown sections.
|
||||
// Skip unknown sections.
|
||||
TRACE("Unknown section: '");
|
||||
for (uint32_t i = 0; i != string_length; ++i) {
|
||||
TRACE("%c", *(section_name_start + i));
|
||||
}
|
||||
TRACE("'\n");
|
||||
consume_bytes(section_length - string_length - string_leb_length);
|
||||
break;
|
||||
}
|
||||
|
||||
if (pc_ != expected_section_end) {
|
||||
const char* diff = pc_ < expected_section_end ? "shorter" : "longer";
|
||||
size_t expected_length = static_cast<size_t>(section_length);
|
||||
size_t actual_length = static_cast<size_t>(pc_ - section_start);
|
||||
error(pc_, pc_,
|
||||
"section \"%s\" %s (%zu bytes) than specified (%zu bytes)",
|
||||
WasmSection::getName(section), diff, actual_length,
|
||||
expected_length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -417,17 +422,18 @@ class ModuleDecoder : public Decoder {
|
||||
}
|
||||
}
|
||||
|
||||
void CheckForPreviousSection(bool* sections, WasmSection::Code section,
|
||||
bool present) {
|
||||
if (section >= WasmSection::Code::Max) return;
|
||||
if (sections[(size_t)section] == present) return;
|
||||
if (present) {
|
||||
error(pc_ - 1, nullptr, "required %s section missing",
|
||||
WasmSection::getName(section));
|
||||
} else {
|
||||
error(pc_ - 1, nullptr, "%s section already present",
|
||||
int CheckSectionOrder(int current_order, WasmSection::Code section) {
|
||||
int next_order = WasmSection::getOrder(section);
|
||||
if (next_order == 0) return current_order;
|
||||
if (next_order == current_order) {
|
||||
error(pc_, pc_, "section \"%s\" already defined",
|
||||
WasmSection::getName(section));
|
||||
}
|
||||
if (next_order < current_order) {
|
||||
error(pc_, pc_, "section \"%s\" out of order",
|
||||
WasmSection::getName(section));
|
||||
}
|
||||
return next_order;
|
||||
}
|
||||
|
||||
// Decodes a single anonymous function starting at {start_}.
|
||||
@ -643,30 +649,6 @@ class ModuleDecoder : public Decoder {
|
||||
return func_index;
|
||||
}
|
||||
|
||||
// Reads a section name.
|
||||
WasmSection::Code consume_section_name(int* string_leb_length,
|
||||
uint32_t* string_length) {
|
||||
*string_length = consume_u32v(string_leb_length, "name length");
|
||||
const byte* start = pc_;
|
||||
consume_bytes(*string_length);
|
||||
if (failed()) {
|
||||
TRACE("Section name of length %u couldn't be read\n", *string_length);
|
||||
return WasmSection::Code::Max;
|
||||
}
|
||||
// TODO(jfb) Linear search, it may be better to do a common-prefix search.
|
||||
for (WasmSection::Code i = WasmSection::begin(); i != WasmSection::end();
|
||||
i = WasmSection::next(i)) {
|
||||
if (WasmSection::getNameLength(i) == *string_length &&
|
||||
0 == memcmp(WasmSection::getName(i), start, *string_length)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
TRACE("Unknown section: '");
|
||||
for (uint32_t i = 0; i != *string_length; ++i) TRACE("%c", *(start + i));
|
||||
TRACE("'\n");
|
||||
return WasmSection::Code::Max;
|
||||
}
|
||||
|
||||
// Reads a single 8-bit integer, interpreting it as a local type.
|
||||
LocalType consume_local_type() {
|
||||
byte val = consume_u8("local type");
|
||||
|
@ -20,19 +20,28 @@ namespace internal {
|
||||
namespace wasm {
|
||||
|
||||
static const char* wasmSections[] = {
|
||||
#define F(enumerator, string) string,
|
||||
#define F(enumerator, order, string) string,
|
||||
FOR_EACH_WASM_SECTION_TYPE(F)
|
||||
#undef F
|
||||
"<unknown>" // entry for "Max"
|
||||
};
|
||||
|
||||
static uint8_t wasmSectionsLengths[]{
|
||||
#define F(enumerator, string) sizeof(string) - 1,
|
||||
#define F(enumerator, order, string) sizeof(string) - 1,
|
||||
FOR_EACH_WASM_SECTION_TYPE(F)
|
||||
#undef F
|
||||
9 // entry for "Max"
|
||||
};
|
||||
|
||||
static uint8_t wasmSectionsOrders[]{
|
||||
#define F(enumerator, order, string) order,
|
||||
FOR_EACH_WASM_SECTION_TYPE(F)
|
||||
#undef F
|
||||
0 // entry for "Max"
|
||||
};
|
||||
|
||||
static_assert(sizeof(wasmSections) / sizeof(wasmSections[0]) ==
|
||||
(size_t)WasmSection::Code::Max,
|
||||
(size_t)WasmSection::Code::Max + 1,
|
||||
"expected enum WasmSection::Code to be monotonic from 0");
|
||||
|
||||
WasmSection::Code WasmSection::begin() { return (WasmSection::Code)0; }
|
||||
@ -49,6 +58,20 @@ size_t WasmSection::getNameLength(WasmSection::Code code) {
|
||||
return wasmSectionsLengths[(size_t)code];
|
||||
}
|
||||
|
||||
int WasmSection::getOrder(WasmSection::Code code) {
|
||||
return wasmSectionsOrders[(size_t)code];
|
||||
}
|
||||
|
||||
WasmSection::Code WasmSection::lookup(const byte* string, uint32_t length) {
|
||||
// TODO(jfb) Linear search, it may be better to do a common-prefix search.
|
||||
for (Code i = begin(); i != end(); i = next(i)) {
|
||||
if (getNameLength(i) == length && 0 == memcmp(getName(i), string, length)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return Code::Max;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const WasmModule& module) {
|
||||
os << "WASM module with ";
|
||||
os << (module.min_mem_pages * module.kPageSize) << " min mem";
|
||||
|
@ -28,21 +28,21 @@ const uint32_t kWasmVersion = 0x0a;
|
||||
// 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(Memory, "memory") \
|
||||
F(Signatures, "signatures") \
|
||||
F(Functions, "functions") \
|
||||
F(Globals, "globals") \
|
||||
F(DataSegments, "data_segments") \
|
||||
F(FunctionTable, "function_table") \
|
||||
F(End, "end") \
|
||||
F(StartFunction, "start_function") \
|
||||
F(ImportTable, "import_table") \
|
||||
F(ExportTable, "export_table") \
|
||||
F(FunctionSignatures, "function_signatures") \
|
||||
F(FunctionBodies, "function_bodies") \
|
||||
F(Names, "names")
|
||||
// Entries have the form F(enumerator, order, string).
|
||||
#define FOR_EACH_WASM_SECTION_TYPE(F) \
|
||||
F(Signatures, 1, "signatures") \
|
||||
F(ImportTable, 2, "import_table") \
|
||||
F(FunctionSignatures, 3, "function_signatures") \
|
||||
F(FunctionTable, 4, "function_table") \
|
||||
F(Memory, 5, "memory") \
|
||||
F(ExportTable, 6, "export_table") \
|
||||
F(StartFunction, 7, "start_function") \
|
||||
F(FunctionBodies, 8, "function_bodies") \
|
||||
F(DataSegments, 9, "data_segments") \
|
||||
F(Names, 10, "names") \
|
||||
F(Globals, 0, "globals") \
|
||||
F(Functions, 0, "functions") \
|
||||
F(End, 0, "end")
|
||||
|
||||
// Contants for the above section types: {LEB128 length, characters...}.
|
||||
#define WASM_SECTION_MEMORY 6, 'm', 'e', 'm', 'o', 'r', 'y'
|
||||
@ -85,7 +85,7 @@ const uint32_t kWasmVersion = 0x0a;
|
||||
|
||||
struct WasmSection {
|
||||
enum class Code : uint32_t {
|
||||
#define F(enumerator, string) enumerator,
|
||||
#define F(enumerator, order, string) enumerator,
|
||||
FOR_EACH_WASM_SECTION_TYPE(F)
|
||||
#undef F
|
||||
Max
|
||||
@ -94,7 +94,9 @@ struct WasmSection {
|
||||
static WasmSection::Code end();
|
||||
static WasmSection::Code next(WasmSection::Code code);
|
||||
static const char* getName(Code code);
|
||||
static int getOrder(Code code);
|
||||
static size_t getNameLength(Code code);
|
||||
static WasmSection::Code lookup(const byte* string, uint32_t length);
|
||||
};
|
||||
|
||||
enum WasmFunctionDeclBit {
|
||||
|
@ -149,16 +149,6 @@ WasmModuleBuilder.prototype.toArray = function(debug) {
|
||||
|
||||
var wasm = this;
|
||||
|
||||
// Add memory section
|
||||
if (wasm.memory != undefined) {
|
||||
if (debug) print("emitting memory @ " + bytes.length);
|
||||
emit_section(bytes, kDeclMemory, function(bytes) {
|
||||
emit_varint(bytes, wasm.memory.min);
|
||||
emit_varint(bytes, wasm.memory.max);
|
||||
emit_u8(bytes, wasm.memory.exp ? 1 : 0);
|
||||
});
|
||||
}
|
||||
|
||||
// Add signatures section
|
||||
if (wasm.signatures.length > 0) {
|
||||
if (debug) print("emitting signatures @ " + bytes.length);
|
||||
@ -187,7 +177,7 @@ WasmModuleBuilder.prototype.toArray = function(debug) {
|
||||
});
|
||||
}
|
||||
|
||||
// Add functions section
|
||||
// Add functions declarations
|
||||
var names = false;
|
||||
var exports = 0;
|
||||
if (wasm.functions.length > 0) {
|
||||
@ -206,6 +196,54 @@ WasmModuleBuilder.prototype.toArray = function(debug) {
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// Add function table.
|
||||
if (wasm.function_table.length > 0) {
|
||||
if (debug) print("emitting function table @ " + bytes.length);
|
||||
emit_section(bytes, kDeclFunctionTable, function(bytes) {
|
||||
emit_varint(bytes, wasm.function_table.length);
|
||||
for (index of wasm.function_table) {
|
||||
emit_varint(bytes, index);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Add memory section
|
||||
if (wasm.memory != undefined) {
|
||||
if (debug) print("emitting memory @ " + bytes.length);
|
||||
emit_section(bytes, kDeclMemory, function(bytes) {
|
||||
emit_varint(bytes, wasm.memory.min);
|
||||
emit_varint(bytes, wasm.memory.max);
|
||||
emit_u8(bytes, wasm.memory.exp ? 1 : 0);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Add export table.
|
||||
if (exports > 0) {
|
||||
if (debug) print("emitting exports @ " + bytes.length);
|
||||
emit_section(bytes, kDeclExportTable, function(bytes) {
|
||||
emit_varint(bytes, exports);
|
||||
for (func of wasm.functions) {
|
||||
for (exp of func.exports) {
|
||||
emit_varint(bytes, func.index);
|
||||
emit_string(bytes, exp);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Add start function section.
|
||||
if (wasm.start_index != undefined) {
|
||||
if (debug) print("emitting start function @ " + bytes.length);
|
||||
emit_section(bytes, kDeclStartFunction, function(bytes) {
|
||||
emit_varint(bytes, wasm.start_index);
|
||||
});
|
||||
}
|
||||
|
||||
// Add function bodies.
|
||||
if (wasm.functions.length > 0) {
|
||||
// emit function bodies
|
||||
if (debug) print("emitting function bodies @ " + bytes.length);
|
||||
emit_section(bytes, kDeclFunctionBodies, function(bytes) {
|
||||
@ -244,50 +282,7 @@ WasmModuleBuilder.prototype.toArray = function(debug) {
|
||||
});
|
||||
}
|
||||
|
||||
// emit function names
|
||||
if (has_names) {
|
||||
if (debug) print("emitting names @ " + bytes.length);
|
||||
emit_section(bytes, kDeclNames, function(bytes) {
|
||||
emit_varint(bytes, wasm.functions.length);
|
||||
for (func of wasm.functions) {
|
||||
var name = func.name == undefined ? "" : func.name;
|
||||
emit_string(bytes, name);
|
||||
emit_u8(bytes, 0); // local names count == 0
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Add start function section.
|
||||
if (wasm.start_index != undefined) {
|
||||
if (debug) print("emitting start function @ " + bytes.length);
|
||||
emit_section(bytes, kDeclStartFunction, function(bytes) {
|
||||
emit_varint(bytes, wasm.start_index);
|
||||
});
|
||||
}
|
||||
|
||||
if (wasm.function_table.length > 0) {
|
||||
if (debug) print("emitting function table @ " + bytes.length);
|
||||
emit_section(bytes, kDeclFunctionTable, function(bytes) {
|
||||
emit_varint(bytes, wasm.function_table.length);
|
||||
for (index of wasm.function_table) {
|
||||
emit_varint(bytes, index);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (exports > 0) {
|
||||
if (debug) print("emitting exports @ " + bytes.length);
|
||||
emit_section(bytes, kDeclExportTable, function(bytes) {
|
||||
emit_varint(bytes, exports);
|
||||
for (func of wasm.functions) {
|
||||
for (exp of func.exports) {
|
||||
emit_varint(bytes, func.index);
|
||||
emit_string(bytes, exp);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Add data segments.
|
||||
if (wasm.data_segments.length > 0) {
|
||||
if (debug) print("emitting data segments @ " + bytes.length);
|
||||
emit_section(bytes, kDeclDataSegments, function(bytes) {
|
||||
@ -300,12 +295,25 @@ WasmModuleBuilder.prototype.toArray = function(debug) {
|
||||
});
|
||||
}
|
||||
|
||||
// Emit any explicitly added sections
|
||||
// Add any explicitly added sections
|
||||
for (exp of wasm.explicit) {
|
||||
if (debug) print("emitting explicit @ " + bytes.length);
|
||||
emit_bytes(bytes, exp);
|
||||
}
|
||||
|
||||
// Add function names.
|
||||
if (has_names) {
|
||||
if (debug) print("emitting names @ " + bytes.length);
|
||||
emit_section(bytes, kDeclNames, function(bytes) {
|
||||
emit_varint(bytes, wasm.functions.length);
|
||||
for (func of wasm.functions) {
|
||||
var name = func.name == undefined ? "" : func.name;
|
||||
emit_string(bytes, name);
|
||||
emit_u8(bytes, 0); // local names count == 0
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// End the module.
|
||||
if (debug) print("emitting end @ " + bytes.length);
|
||||
emit_section(bytes, kDeclEnd, function(bytes) {});
|
||||
|
@ -23,6 +23,7 @@ namespace wasm {
|
||||
#define INT_INT_SIG 1, kLocalI32, kLocalI32
|
||||
#define INT_INT_SIG_SIZE ((size_t)3)
|
||||
|
||||
// TODO(titzer): tricky size logic! Remove -1.
|
||||
#define SECTION(NAME, EXTRA_SIZE) \
|
||||
U32V_1(WASM_SECTION_##NAME##_SIZE + (EXTRA_SIZE)), WASM_SECTION_##NAME
|
||||
|
||||
@ -49,6 +50,15 @@ namespace wasm {
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define EXPECT_OK(result) \
|
||||
do { \
|
||||
EXPECT_TRUE(result.ok()); \
|
||||
if (!result.ok()) { \
|
||||
if (result.val) delete result.val; \
|
||||
return; \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
static size_t SizeOfVarInt(size_t value) {
|
||||
size_t size = 0;
|
||||
do {
|
||||
@ -115,7 +125,7 @@ TEST_F(WasmModuleVerifyTest, DecodeEmpty) {
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, OneGlobal) {
|
||||
static const byte data[] = {
|
||||
SECTION(GLOBALS, 7), // --
|
||||
SECTION(GLOBALS, 5), // --
|
||||
1,
|
||||
NAME_LENGTH(1),
|
||||
'g', // name
|
||||
@ -126,7 +136,7 @@ TEST_F(WasmModuleVerifyTest, OneGlobal) {
|
||||
{
|
||||
// Should decode to exactly one global.
|
||||
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
||||
EXPECT_TRUE(result.ok());
|
||||
EXPECT_OK(result);
|
||||
EXPECT_EQ(1, result.val->globals.size());
|
||||
EXPECT_EQ(0, result.val->functions.size());
|
||||
EXPECT_EQ(0, result.val->data_segments.size());
|
||||
@ -151,7 +161,7 @@ TEST_F(WasmModuleVerifyTest, ZeroGlobals) {
|
||||
0, // declare 0 globals
|
||||
};
|
||||
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
||||
EXPECT_TRUE(result.ok());
|
||||
EXPECT_OK(result);
|
||||
if (result.val) delete result.val;
|
||||
}
|
||||
|
||||
@ -192,7 +202,7 @@ TEST_F(WasmModuleVerifyTest, NGlobals) {
|
||||
}
|
||||
|
||||
ModuleResult result = DecodeModule(&buffer[0], &buffer[0] + buffer.size());
|
||||
EXPECT_TRUE(result.ok());
|
||||
EXPECT_OK(result);
|
||||
if (result.val) delete result.val;
|
||||
}
|
||||
}
|
||||
@ -224,7 +234,7 @@ TEST_F(WasmModuleVerifyTest, GlobalWithInvalidMemoryType) {
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, TwoGlobals) {
|
||||
static const byte data[] = {
|
||||
SECTION(GLOBALS, 13),
|
||||
SECTION(GLOBALS, 7),
|
||||
2,
|
||||
NO_NAME, // #0: name length
|
||||
kMemF32, // memory type
|
||||
@ -237,7 +247,7 @@ TEST_F(WasmModuleVerifyTest, TwoGlobals) {
|
||||
{
|
||||
// Should decode to exactly two globals.
|
||||
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
||||
EXPECT_TRUE(result.ok());
|
||||
EXPECT_OK(result);
|
||||
EXPECT_EQ(2, result.val->globals.size());
|
||||
EXPECT_EQ(0, result.val->functions.size());
|
||||
EXPECT_EQ(0, result.val->data_segments.size());
|
||||
@ -293,7 +303,7 @@ TEST_F(WasmModuleVerifyTest, MultipleSignatures) {
|
||||
};
|
||||
|
||||
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
||||
EXPECT_TRUE(result.ok());
|
||||
EXPECT_OK(result);
|
||||
EXPECT_EQ(3, result.val->signatures.size());
|
||||
if (result.val->signatures.size() == 3) {
|
||||
EXPECT_EQ(0, result.val->signatures[0]->return_count());
|
||||
@ -341,7 +351,7 @@ TEST_F(WasmModuleVerifyTest, OneEmptyVoidVoidFunction) {
|
||||
// sig#0 -------------------------------------------------------
|
||||
VOID_VOID_SIG,
|
||||
// func#0 ------------------------------------------------------
|
||||
SECTION(FUNCTIONS, 19), 1,
|
||||
SECTION(FUNCTIONS, 18), 1,
|
||||
kDeclFunctionLocals | kDeclFunctionExport | kDeclFunctionName,
|
||||
SIG_INDEX(0), // signature index
|
||||
NAME_LENGTH(2), 'h', 'i', // name
|
||||
@ -356,7 +366,7 @@ TEST_F(WasmModuleVerifyTest, OneEmptyVoidVoidFunction) {
|
||||
{
|
||||
// Should decode to exactly one function.
|
||||
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
||||
EXPECT_TRUE(result.ok());
|
||||
EXPECT_OK(result);
|
||||
EXPECT_EQ(0, result.val->globals.size());
|
||||
EXPECT_EQ(1, result.val->signatures.size());
|
||||
EXPECT_EQ(1, result.val->functions.size());
|
||||
@ -387,16 +397,19 @@ TEST_F(WasmModuleVerifyTest, OneEmptyVoidVoidFunction) {
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, OneFunctionImported) {
|
||||
static const byte data[] = {
|
||||
SECTION(SIGNATURES, VOID_VOID_SIG_SIZE), 1,
|
||||
// signatures
|
||||
SECTION(SIGNATURES, 1 + VOID_VOID_SIG_SIZE), 1,
|
||||
// sig#0 -------------------------------------------------------
|
||||
VOID_VOID_SIG, SECTION(FUNCTIONS, 6), 1,
|
||||
VOID_VOID_SIG,
|
||||
// functions
|
||||
SECTION(FUNCTIONS, 4), 1,
|
||||
// func#0 ------------------------------------------------------
|
||||
kDeclFunctionImport, // no name, no locals, imported
|
||||
SIG_INDEX(0),
|
||||
};
|
||||
|
||||
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
||||
EXPECT_TRUE(result.ok());
|
||||
EXPECT_OK(result);
|
||||
EXPECT_EQ(1, result.val->functions.size());
|
||||
WasmFunction* function = &result.val->functions.back();
|
||||
|
||||
@ -432,7 +445,7 @@ TEST_F(WasmModuleVerifyTest, OneFunctionWithNopBody) {
|
||||
};
|
||||
|
||||
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
||||
EXPECT_TRUE(result.ok());
|
||||
EXPECT_OK(result);
|
||||
EXPECT_EQ(1, result.val->functions.size());
|
||||
WasmFunction* function = &result.val->functions.back();
|
||||
|
||||
@ -472,7 +485,7 @@ TEST_F(WasmModuleVerifyTest, OneFunctionWithNopBody_WithLocals) {
|
||||
};
|
||||
|
||||
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
||||
EXPECT_TRUE(result.ok());
|
||||
EXPECT_OK(result);
|
||||
EXPECT_EQ(1, result.val->functions.size());
|
||||
WasmFunction* function = &result.val->functions.back();
|
||||
|
||||
@ -493,33 +506,35 @@ TEST_F(WasmModuleVerifyTest, OneFunctionWithNopBody_WithLocals) {
|
||||
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, OneGlobalOneFunctionWithNopBodyOneDataSegment) {
|
||||
static const byte kCodeStartOffset = 75;
|
||||
static const byte kCodeStartOffset = 64;
|
||||
static const byte kCodeEndOffset = kCodeStartOffset + 3;
|
||||
static const byte kDataSegmentSourceOffset = kCodeEndOffset + 20;
|
||||
static const byte kDataSegmentSourceOffset = kCodeEndOffset + 31;
|
||||
|
||||
static const byte data[] = {
|
||||
SECTION(MEMORY, 3), 28, 28, 1,
|
||||
// global#0 --------------------------------------------------
|
||||
SECTION(GLOBALS, 7), 1,
|
||||
SECTION(GLOBALS, 4), 1,
|
||||
0, // name length
|
||||
kMemU8, // memory type
|
||||
0, // exported
|
||||
// sig#0 -----------------------------------------------------
|
||||
SECTION(SIGNATURES, 3), 1, 0, 0, // void -> void
|
||||
// func#0 ----------------------------------------------------
|
||||
SECTION(FUNCTIONS, 20), 1, kDeclFunctionLocals | kDeclFunctionName, 0,
|
||||
0, // signature index
|
||||
2, 'h', 'i', // name
|
||||
1, 2, // local int32 count
|
||||
3, 4, // local int64 count
|
||||
5, 6, // local float32 count
|
||||
7, 8, // local float64 count
|
||||
3, 0, // body size
|
||||
kExprNop, // func#0 body
|
||||
kExprNop, // func#0 body
|
||||
kExprNop, // func#0 body
|
||||
SECTION(FUNCTIONS, 20), 1,
|
||||
kDeclFunctionLocals | kDeclFunctionName, // --
|
||||
SIG_INDEX(0), // signature index
|
||||
2, 'h', 'i', // name
|
||||
1, 2, // local int32 count
|
||||
3, 4, // local int64 count
|
||||
5, 6, // local float32 count
|
||||
7, 8, // local float64 count
|
||||
3, 0, // body size
|
||||
kExprNop, // func#0 body
|
||||
kExprNop, // func#0 body
|
||||
kExprNop, // func#0 body
|
||||
// memory section --------------------------------------------
|
||||
SECTION(MEMORY, 3), 28, 28, 1,
|
||||
// segment#0 -------------------------------------------------
|
||||
SECTION(DATA_SEGMENTS, 14), 1,
|
||||
SECTION(DATA_SEGMENTS, 10), 1,
|
||||
U32V_3(0x8b3ae), // dest addr
|
||||
U32V_1(5), // source size
|
||||
0, 1, 2, 3, 4, // data bytes
|
||||
@ -529,7 +544,7 @@ TEST_F(WasmModuleVerifyTest, OneGlobalOneFunctionWithNopBodyOneDataSegment) {
|
||||
|
||||
{
|
||||
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
||||
EXPECT_TRUE(result.ok());
|
||||
EXPECT_OK(result);
|
||||
EXPECT_EQ(1, result.val->globals.size());
|
||||
EXPECT_EQ(1, result.val->functions.size());
|
||||
EXPECT_EQ(1, result.val->data_segments.size());
|
||||
@ -543,7 +558,7 @@ TEST_F(WasmModuleVerifyTest, OneGlobalOneFunctionWithNopBodyOneDataSegment) {
|
||||
|
||||
WasmFunction* function = &result.val->functions.back();
|
||||
|
||||
EXPECT_EQ(63, function->name_offset);
|
||||
EXPECT_EQ(52, function->name_offset);
|
||||
EXPECT_EQ(2, function->name_length);
|
||||
EXPECT_EQ(kCodeStartOffset, function->code_start_offset);
|
||||
EXPECT_EQ(kCodeEndOffset, function->code_end_offset);
|
||||
@ -582,7 +597,7 @@ TEST_F(WasmModuleVerifyTest, OneDataSegment) {
|
||||
{
|
||||
EXPECT_VERIFIES(data);
|
||||
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
||||
EXPECT_TRUE(result.ok());
|
||||
EXPECT_OK(result);
|
||||
EXPECT_EQ(0, result.val->globals.size());
|
||||
EXPECT_EQ(0, result.val->functions.size());
|
||||
EXPECT_EQ(1, result.val->data_segments.size());
|
||||
@ -610,7 +625,7 @@ TEST_F(WasmModuleVerifyTest, TwoDataSegments) {
|
||||
28,
|
||||
28,
|
||||
1,
|
||||
SECTION(DATA_SEGMENTS, 31),
|
||||
SECTION(DATA_SEGMENTS, 23),
|
||||
2, // segment count
|
||||
U32V_3(0x7ffee), // #0: dest addr
|
||||
U32V_1(4), // source size
|
||||
@ -634,7 +649,7 @@ TEST_F(WasmModuleVerifyTest, TwoDataSegments) {
|
||||
|
||||
{
|
||||
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
||||
EXPECT_TRUE(result.ok());
|
||||
EXPECT_OK(result);
|
||||
EXPECT_EQ(0, result.val->globals.size());
|
||||
EXPECT_EQ(0, result.val->functions.size());
|
||||
EXPECT_EQ(2, result.val->data_segments.size());
|
||||
@ -670,7 +685,7 @@ TEST_F(WasmModuleVerifyTest, DataSegmentWithInvalidDest) {
|
||||
mem_pages,
|
||||
mem_pages,
|
||||
1,
|
||||
SECTION(DATA_SEGMENTS, 14),
|
||||
SECTION(DATA_SEGMENTS, 8),
|
||||
1,
|
||||
U32V_3(dest_addr),
|
||||
U32V_1(source_size),
|
||||
@ -701,7 +716,7 @@ TEST_F(WasmModuleVerifyTest, OneIndirectFunction) {
|
||||
SECTION(FUNCTION_TABLE, 2), 1, U32V_1(0)};
|
||||
|
||||
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
||||
EXPECT_TRUE(result.ok());
|
||||
EXPECT_OK(result);
|
||||
if (result.ok()) {
|
||||
EXPECT_EQ(1, result.val->signatures.size());
|
||||
EXPECT_EQ(1, result.val->functions.size());
|
||||
@ -735,7 +750,7 @@ TEST_F(WasmModuleVerifyTest, MultipleIndirectFunctions) {
|
||||
};
|
||||
|
||||
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
||||
EXPECT_TRUE(result.ok());
|
||||
EXPECT_OK(result);
|
||||
if (result.ok()) {
|
||||
EXPECT_EQ(2, result.val->signatures.size());
|
||||
EXPECT_EQ(4, result.val->functions.size());
|
||||
@ -916,7 +931,7 @@ TEST_F(WasmFunctionVerifyTest, Ok_v_v_empty) {
|
||||
|
||||
FunctionResult result = DecodeWasmFunction(isolate(), zone(), nullptr, data,
|
||||
data + arraysize(data));
|
||||
EXPECT_TRUE(result.ok());
|
||||
EXPECT_OK(result);
|
||||
|
||||
if (result.val && result.ok()) {
|
||||
WasmFunction* function = result.val;
|
||||
@ -1031,14 +1046,14 @@ TEST_F(WasmModuleVerifyTest, UnknownSectionSkipped) {
|
||||
1,
|
||||
'\0', // Section name: LEB128 1, string '\0'
|
||||
0, // one byte section
|
||||
SECTION(GLOBALS, 7),
|
||||
SECTION(GLOBALS, 4),
|
||||
1,
|
||||
0, // name length
|
||||
kMemI32, // memory type
|
||||
0, // exported
|
||||
};
|
||||
ModuleResult result = DecodeModule(data, data + arraysize(data));
|
||||
EXPECT_TRUE(result.ok());
|
||||
EXPECT_OK(result);
|
||||
|
||||
EXPECT_EQ(1, result.val->globals.size());
|
||||
EXPECT_EQ(0, result.val->functions.size());
|
||||
@ -1060,8 +1075,18 @@ TEST_F(WasmModuleVerifyTest, ImportTable_empty) {
|
||||
EXPECT_VERIFIES(data);
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, ImportTable_nosigs) {
|
||||
TEST_F(WasmModuleVerifyTest, ImportTable_nosigs1) {
|
||||
static const byte data[] = {SECTION(IMPORT_TABLE, 1), 0};
|
||||
EXPECT_VERIFIES(data);
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, ImportTable_nosigs2) {
|
||||
static const byte data[] = {
|
||||
SECTION(IMPORT_TABLE, 6), 1, // sig table
|
||||
IMPORT_SIG_INDEX(0), // sig index
|
||||
NAME_LENGTH(1), 'm', // module name
|
||||
NAME_LENGTH(1), 'f', // function name
|
||||
};
|
||||
EXPECT_FAILURE(data);
|
||||
}
|
||||
|
||||
@ -1162,7 +1187,7 @@ TEST_F(WasmModuleVerifyTest, ExportTableOne) {
|
||||
SECTION(FUNCTIONS, 1 + EMPTY_FUNCTION_SIZE),
|
||||
1, // functions
|
||||
EMPTY_FUNCTION(0), // --
|
||||
SECTION(EXPORT_TABLE, 7),
|
||||
SECTION(EXPORT_TABLE, 3),
|
||||
1, // exports
|
||||
FUNC_INDEX(0), // --
|
||||
NO_NAME // --
|
||||
@ -1269,7 +1294,7 @@ TEST_F(WasmModuleVerifyTest, ExportTableOne_off_end) {
|
||||
}
|
||||
|
||||
#define SIGNATURES_SECTION(count, ...) \
|
||||
SECTION(SIGNATURES, 1 + 3 * (count)), U32V_1(count), __VA_ARGS__
|
||||
SECTION(SIGNATURES, 1 + 2 * (count)), U32V_1(count), __VA_ARGS__
|
||||
#define FUNCTION_SIGNATURES_SECTION(count, ...) \
|
||||
SECTION(FUNCTION_SIGNATURES, 1 + (count)), U32V_1(count), __VA_ARGS__
|
||||
|
||||
@ -1282,53 +1307,67 @@ TEST_F(WasmModuleVerifyTest, ExportTableOne_off_end) {
|
||||
#define EMPTY_NAMES_SECTION SECTION(NAMES, 1), 0
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, FunctionSignatures_empty) {
|
||||
static const byte data[] = {SECTION(SIGNATURES, 1), 0,
|
||||
SECTION(FUNCTION_SIGNATURES, 1), 0};
|
||||
static const byte data[] = {
|
||||
SECTION(SIGNATURES, 1), 0, // --
|
||||
SECTION(FUNCTION_SIGNATURES, 1), 0 // --
|
||||
}; // --
|
||||
EXPECT_VERIFIES(data);
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, FunctionSignatures_one) {
|
||||
static const byte data[] = {SIGNATURES_SECTION(1, VOID_VOID_SIG),
|
||||
FUNCTION_SIGNATURES_SECTION(1, 0)};
|
||||
static const byte data[] = {
|
||||
SIGNATURES_SECTION(1, VOID_VOID_SIG), // --
|
||||
FUNCTION_SIGNATURES_SECTION(1, 0) // --
|
||||
};
|
||||
EXPECT_VERIFIES(data);
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, FunctionBodies_empty) {
|
||||
static const byte data[] = {EMPTY_SIGNATURES_SECTION,
|
||||
EMPTY_FUNCTION_SIGNATURES_SECTION,
|
||||
EMPTY_FUNCTION_BODIES_SECTION};
|
||||
static const byte data[] = {
|
||||
EMPTY_SIGNATURES_SECTION, // --
|
||||
EMPTY_FUNCTION_SIGNATURES_SECTION, // --
|
||||
EMPTY_FUNCTION_BODIES_SECTION // --
|
||||
};
|
||||
EXPECT_VERIFIES(data);
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, FunctionBodies_one_empty) {
|
||||
static const byte data[] = {
|
||||
SIGNATURES_SECTION(1, VOID_VOID_SIG), FUNCTION_SIGNATURES_SECTION(1, 0),
|
||||
SECTION(FUNCTION_BODIES, 1 + EMPTY_BODY_SIZE), 1, EMPTY_BODY};
|
||||
SIGNATURES_SECTION(1, VOID_VOID_SIG), // --
|
||||
FUNCTION_SIGNATURES_SECTION(1, 0), // --
|
||||
SECTION(FUNCTION_BODIES, 1 + EMPTY_BODY_SIZE), 1, EMPTY_BODY // --
|
||||
};
|
||||
EXPECT_VERIFIES(data);
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, FunctionBodies_one_nop) {
|
||||
static const byte data[] = {
|
||||
SIGNATURES_SECTION(1, VOID_VOID_SIG), FUNCTION_SIGNATURES_SECTION(1, 0),
|
||||
SECTION(FUNCTION_BODIES, 1 + NOP_BODY_SIZE), 1, NOP_BODY};
|
||||
SIGNATURES_SECTION(1, VOID_VOID_SIG), // --
|
||||
FUNCTION_SIGNATURES_SECTION(1, 0), // --
|
||||
SECTION(FUNCTION_BODIES, 1 + NOP_BODY_SIZE), 1, NOP_BODY // --
|
||||
};
|
||||
EXPECT_VERIFIES(data);
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, FunctionBodies_count_mismatch1) {
|
||||
static const byte data[] = {SIGNATURES_SECTION(1, VOID_VOID_SIG),
|
||||
FUNCTION_SIGNATURES_SECTION(2, 0, 0),
|
||||
SECTION(FUNCTION_BODIES, 1 + EMPTY_BODY_SIZE), 1,
|
||||
EMPTY_BODY};
|
||||
static const byte data[] = {
|
||||
SIGNATURES_SECTION(1, VOID_VOID_SIG), // --
|
||||
FUNCTION_SIGNATURES_SECTION(2, 0, 0), // --
|
||||
SECTION(FUNCTION_BODIES, 1 + EMPTY_BODY_SIZE), 1, // --
|
||||
EMPTY_BODY // --
|
||||
};
|
||||
EXPECT_FAILURE(data);
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, FunctionBodies_count_mismatch2) {
|
||||
static const byte data[] = {SIGNATURES_SECTION(1, VOID_VOID_SIG),
|
||||
FUNCTION_SIGNATURES_SECTION(1, 0),
|
||||
SECTION(FUNCTION_BODIES, 1 + 2 * NOP_BODY_SIZE),
|
||||
2,
|
||||
NOP_BODY,
|
||||
NOP_BODY};
|
||||
static const byte data[] = {
|
||||
SIGNATURES_SECTION(1, VOID_VOID_SIG), // --
|
||||
FUNCTION_SIGNATURES_SECTION(1, 0), // --
|
||||
SECTION(FUNCTION_BODIES, 1 + 2 * NOP_BODY_SIZE), // --
|
||||
2, // --
|
||||
NOP_BODY, // --
|
||||
NOP_BODY // --
|
||||
};
|
||||
EXPECT_FAILURE(data);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user