mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-14 05:22:24 +00:00
LibWasm: Ensure correct section ordering when parsing binary modules
There are (currently) no spec-tests ensuring that section ordering is enforced, but it _is_ a part of the spec. A pull request to add this to the specification testsuite has been opened at WebAssembly/spec#1775.
This commit is contained in:
parent
ea8d0304e9
commit
c58665332e
Notes:
github-actions[bot]
2024-08-10 08:40:31 +00:00
Author: https://github.com/dzfrias
Commit: c58665332e
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/1022
Reviewed-by: https://github.com/alimpfard ✅
2 changed files with 91 additions and 45 deletions
|
@ -1213,6 +1213,41 @@ ParseResult<DataCountSection> DataCountSection::parse([[maybe_unused]] Stream& s
|
|||
return DataCountSection { value };
|
||||
}
|
||||
|
||||
ParseResult<SectionId> SectionId::parse(Stream& stream)
|
||||
{
|
||||
u8 id = TRY_READ(stream, u8, ParseError::ExpectedIndex);
|
||||
switch (id) {
|
||||
case 0x00:
|
||||
return SectionId(SectionIdKind::Custom);
|
||||
case 0x01:
|
||||
return SectionId(SectionIdKind::Type);
|
||||
case 0x02:
|
||||
return SectionId(SectionIdKind::Import);
|
||||
case 0x03:
|
||||
return SectionId(SectionIdKind::Function);
|
||||
case 0x04:
|
||||
return SectionId(SectionIdKind::Table);
|
||||
case 0x05:
|
||||
return SectionId(SectionIdKind::Memory);
|
||||
case 0x06:
|
||||
return SectionId(SectionIdKind::Global);
|
||||
case 0x07:
|
||||
return SectionId(SectionIdKind::Export);
|
||||
case 0x08:
|
||||
return SectionId(SectionIdKind::Start);
|
||||
case 0x09:
|
||||
return SectionId(SectionIdKind::Element);
|
||||
case 0x0a:
|
||||
return SectionId(SectionIdKind::Code);
|
||||
case 0x0b:
|
||||
return SectionId(SectionIdKind::Data);
|
||||
case 0x0c:
|
||||
return SectionId(SectionIdKind::DataCount);
|
||||
default:
|
||||
return ParseError::InvalidIndex;
|
||||
}
|
||||
}
|
||||
|
||||
ParseResult<Module> Module::parse(Stream& stream)
|
||||
{
|
||||
ScopeLogger<WASM_BINPARSER_DEBUG> logger("Module"sv);
|
||||
|
@ -1227,61 +1262,64 @@ ParseResult<Module> Module::parse(Stream& stream)
|
|||
if (Bytes { buf, 4 } != wasm_version.span())
|
||||
return with_eof_check(stream, ParseError::InvalidModuleVersion);
|
||||
|
||||
auto last_section_id = CustomSection::section_id;
|
||||
auto last_section_id = SectionId::SectionIdKind::Custom;
|
||||
Module module;
|
||||
while (!stream.is_eof()) {
|
||||
auto section_id = TRY_READ(stream, u8, ParseError::ExpectedIndex);
|
||||
auto section_id = TRY(SectionId::parse(stream));
|
||||
size_t section_size = TRY_READ(stream, LEB128<u32>, ParseError::ExpectedSize);
|
||||
auto section_stream = ConstrainedStream { MaybeOwned<Stream>(stream), section_size };
|
||||
|
||||
if (section_id != CustomSection::section_id && section_id == last_section_id)
|
||||
if (section_id.kind() != SectionId::SectionIdKind::Custom && section_id.kind() == last_section_id)
|
||||
return ParseError::DuplicateSection;
|
||||
|
||||
switch (section_id) {
|
||||
case CustomSection::section_id:
|
||||
switch (section_id.kind()) {
|
||||
case SectionId::SectionIdKind::Custom:
|
||||
module.custom_sections().append(TRY(CustomSection::parse(section_stream)));
|
||||
break;
|
||||
case TypeSection::section_id:
|
||||
case SectionId::SectionIdKind::Type:
|
||||
module.type_section() = TRY(TypeSection::parse(section_stream));
|
||||
break;
|
||||
case ImportSection::section_id:
|
||||
case SectionId::SectionIdKind::Import:
|
||||
module.import_section() = TRY(ImportSection::parse(section_stream));
|
||||
break;
|
||||
case FunctionSection::section_id:
|
||||
case SectionId::SectionIdKind::Function:
|
||||
module.function_section() = TRY(FunctionSection::parse(section_stream));
|
||||
break;
|
||||
case TableSection::section_id:
|
||||
case SectionId::SectionIdKind::Table:
|
||||
module.table_section() = TRY(TableSection::parse(section_stream));
|
||||
break;
|
||||
case MemorySection::section_id:
|
||||
case SectionId::SectionIdKind::Memory:
|
||||
module.memory_section() = TRY(MemorySection::parse(section_stream));
|
||||
break;
|
||||
case GlobalSection::section_id:
|
||||
case SectionId::SectionIdKind::Global:
|
||||
module.global_section() = TRY(GlobalSection::parse(section_stream));
|
||||
break;
|
||||
case ExportSection::section_id:
|
||||
case SectionId::SectionIdKind::Export:
|
||||
module.export_section() = TRY(ExportSection::parse(section_stream));
|
||||
break;
|
||||
case StartSection::section_id:
|
||||
case SectionId::SectionIdKind::Start:
|
||||
module.start_section() = TRY(StartSection::parse(section_stream));
|
||||
break;
|
||||
case ElementSection::section_id:
|
||||
case SectionId::SectionIdKind::Element:
|
||||
module.element_section() = TRY(ElementSection::parse(section_stream));
|
||||
break;
|
||||
case CodeSection::section_id:
|
||||
case SectionId::SectionIdKind::Code:
|
||||
module.code_section() = TRY(CodeSection::parse(section_stream));
|
||||
break;
|
||||
case DataSection::section_id:
|
||||
case SectionId::SectionIdKind::Data:
|
||||
module.data_section() = TRY(DataSection::parse(section_stream));
|
||||
break;
|
||||
case DataCountSection::section_id:
|
||||
case SectionId::SectionIdKind::DataCount:
|
||||
module.data_count_section() = TRY(DataCountSection::parse(section_stream));
|
||||
break;
|
||||
default:
|
||||
return ParseError::InvalidIndex;
|
||||
}
|
||||
if (section_id != CustomSection::section_id)
|
||||
last_section_id = section_id;
|
||||
if (section_id.kind() != SectionId::SectionIdKind::Custom) {
|
||||
if (section_id.kind() < last_section_id)
|
||||
return ParseError::SectionOutOfOrder;
|
||||
last_section_id = section_id.kind();
|
||||
}
|
||||
if (section_stream.remaining() != 0)
|
||||
return ParseError::SectionSizeMismatch;
|
||||
}
|
||||
|
@ -1334,6 +1372,8 @@ ByteString parse_error_to_byte_string(ParseError error)
|
|||
return "A parsed instruction was not known to this parser";
|
||||
case ParseError::DuplicateSection:
|
||||
return "Two sections of the same type were encountered";
|
||||
case ParseError::SectionOutOfOrder:
|
||||
return "A section encountered was not in the correct ordering";
|
||||
}
|
||||
return "Unknown error";
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ enum class ParseError {
|
|||
SectionSizeMismatch,
|
||||
InvalidUtf8,
|
||||
DuplicateSection,
|
||||
SectionOutOfOrder,
|
||||
};
|
||||
|
||||
ByteString parse_error_to_byte_string(ParseError);
|
||||
|
@ -499,10 +500,39 @@ private:
|
|||
m_arguments;
|
||||
};
|
||||
|
||||
struct SectionId {
|
||||
public:
|
||||
enum class SectionIdKind : u8 {
|
||||
Custom,
|
||||
Type,
|
||||
Import,
|
||||
Function,
|
||||
Table,
|
||||
Memory,
|
||||
Global,
|
||||
Export,
|
||||
Start,
|
||||
Element,
|
||||
DataCount,
|
||||
Code,
|
||||
Data,
|
||||
};
|
||||
|
||||
explicit SectionId(SectionIdKind kind)
|
||||
: m_kind(kind)
|
||||
{
|
||||
}
|
||||
|
||||
SectionIdKind kind() const { return m_kind; }
|
||||
|
||||
static ParseResult<SectionId> parse(Stream& stream);
|
||||
|
||||
private:
|
||||
SectionIdKind m_kind;
|
||||
};
|
||||
|
||||
class CustomSection {
|
||||
public:
|
||||
static constexpr u8 section_id = 0;
|
||||
|
||||
CustomSection(ByteString name, ByteBuffer contents)
|
||||
: m_name(move(name))
|
||||
, m_contents(move(contents))
|
||||
|
@ -521,8 +551,6 @@ private:
|
|||
|
||||
class TypeSection {
|
||||
public:
|
||||
static constexpr u8 section_id = 1;
|
||||
|
||||
TypeSection() = default;
|
||||
|
||||
explicit TypeSection(Vector<FunctionType> types)
|
||||
|
@ -570,8 +598,6 @@ public:
|
|||
};
|
||||
|
||||
public:
|
||||
static constexpr u8 section_id = 2;
|
||||
|
||||
ImportSection() = default;
|
||||
|
||||
explicit ImportSection(Vector<Import> imports)
|
||||
|
@ -589,8 +615,6 @@ private:
|
|||
|
||||
class FunctionSection {
|
||||
public:
|
||||
static constexpr u8 section_id = 3;
|
||||
|
||||
FunctionSection() = default;
|
||||
|
||||
explicit FunctionSection(Vector<TypeIndex> types)
|
||||
|
@ -624,8 +648,6 @@ public:
|
|||
};
|
||||
|
||||
public:
|
||||
static constexpr u8 section_id = 4;
|
||||
|
||||
TableSection() = default;
|
||||
|
||||
explicit TableSection(Vector<Table> tables)
|
||||
|
@ -659,8 +681,6 @@ public:
|
|||
};
|
||||
|
||||
public:
|
||||
static constexpr u8 section_id = 5;
|
||||
|
||||
MemorySection() = default;
|
||||
|
||||
explicit MemorySection(Vector<Memory> memories)
|
||||
|
@ -712,8 +732,6 @@ public:
|
|||
};
|
||||
|
||||
public:
|
||||
static constexpr u8 section_id = 6;
|
||||
|
||||
GlobalSection() = default;
|
||||
|
||||
explicit GlobalSection(Vector<Global> entries)
|
||||
|
@ -752,8 +770,6 @@ public:
|
|||
ExportDesc m_description;
|
||||
};
|
||||
|
||||
static constexpr u8 section_id = 7;
|
||||
|
||||
ExportSection() = default;
|
||||
|
||||
explicit ExportSection(Vector<Export> entries)
|
||||
|
@ -786,8 +802,6 @@ public:
|
|||
FunctionIndex m_index;
|
||||
};
|
||||
|
||||
static constexpr u8 section_id = 8;
|
||||
|
||||
StartSection() = default;
|
||||
|
||||
explicit StartSection(Optional<StartFunction> func)
|
||||
|
@ -822,8 +836,6 @@ public:
|
|||
Variant<Active, Passive, Declarative> mode;
|
||||
};
|
||||
|
||||
static constexpr u8 section_id = 9;
|
||||
|
||||
ElementSection() = default;
|
||||
|
||||
explicit ElementSection(Vector<Element> segs)
|
||||
|
@ -896,8 +908,6 @@ public:
|
|||
Func m_func;
|
||||
};
|
||||
|
||||
static constexpr u8 section_id = 10;
|
||||
|
||||
CodeSection() = default;
|
||||
|
||||
explicit CodeSection(Vector<Code> funcs)
|
||||
|
@ -940,8 +950,6 @@ public:
|
|||
Value m_value;
|
||||
};
|
||||
|
||||
static constexpr u8 section_id = 11;
|
||||
|
||||
DataSection() = default;
|
||||
|
||||
explicit DataSection(Vector<Data> data)
|
||||
|
@ -959,8 +967,6 @@ private:
|
|||
|
||||
class DataCountSection {
|
||||
public:
|
||||
static constexpr u8 section_id = 12;
|
||||
|
||||
DataCountSection() = default;
|
||||
|
||||
explicit DataCountSection(Optional<u32> count)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue