From 23cfee22058880f8251d9627e7f6640d466c37a9 Mon Sep 17 00:00:00 2001 From: Diego Frias Date: Mon, 29 Jul 2024 19:56:00 -0700 Subject: [PATCH] LibWasm: Clean up module sections API Remove `for_each_section_of_type` in favor of making the module's sections defined as distinct fields. This means it is no longer possible to have two of the same section (which is invalid in WebAssembly, for anything other than custom sections). --- .../AbstractMachine/AbstractMachine.cpp | 594 ++++++++---------- .../LibWasm/AbstractMachine/Validator.cpp | 214 +++---- Userland/Libraries/LibWasm/Parser/Parser.cpp | 38 +- .../Libraries/LibWasm/Printer/Printer.cpp | 42 +- Userland/Libraries/LibWasm/Types.h | 118 ++-- .../LibWeb/WebAssembly/WebAssembly.cpp | 2 +- Userland/Utilities/wasm.cpp | 2 +- 7 files changed, 469 insertions(+), 541 deletions(-) diff --git a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp index 4e4a712c61a..e450332a6de 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp +++ b/Userland/Libraries/LibWasm/AbstractMachine/AbstractMachine.cpp @@ -146,75 +146,67 @@ InstantiationResult AbstractMachine::instantiate(Module const& module, Vector(); auto& main_module_instance = *main_module_instance_pointer; - Optional instantiation_result; - module.for_each_section_of_type([&](TypeSection const& section) { - main_module_instance.types() = section.types(); - }); + main_module_instance.types() = module.type_section().types(); Vector global_values; Vector> elements; ModuleInstance auxiliary_instance; - module.for_each_section_of_type([&](ImportSection const& section) { - for (auto [i, import_] : enumerate(section.imports())) { - auto extern_ = externs.at(i); - auto invalid = import_.description().visit( - [&](MemoryType const& mem_type) -> Optional { - if (!extern_.has()) - return "Expected memory import"sv; - auto other_mem_type = m_store.get(extern_.get())->type(); - if (other_mem_type.limits().is_subset_of(mem_type.limits())) - return {}; - return ByteString::formatted("Memory import and extern do not match: {}-{} vs {}-{}", mem_type.limits().min(), mem_type.limits().max(), other_mem_type.limits().min(), other_mem_type.limits().max()); - }, - [&](TableType const& table_type) -> Optional { - if (!extern_.has()) - return "Expected table import"sv; - auto other_table_type = m_store.get(extern_.get())->type(); - if (table_type.element_type() == other_table_type.element_type() - && other_table_type.limits().is_subset_of(table_type.limits())) - return {}; - - return ByteString::formatted("Table import and extern do not match: {}-{} vs {}-{}", table_type.limits().min(), table_type.limits().max(), other_table_type.limits().min(), other_table_type.limits().max()); - }, - [&](GlobalType const& global_type) -> Optional { - if (!extern_.has()) - return "Expected global import"sv; - auto other_global_type = m_store.get(extern_.get())->type(); - if (global_type.type() == other_global_type.type() - && global_type.is_mutable() == other_global_type.is_mutable()) - return {}; - return "Global import and extern do not match"sv; - }, - [&](FunctionType const& type) -> Optional { - if (!extern_.has()) - return "Expected function import"sv; - auto other_type = m_store.get(extern_.get())->visit([&](WasmFunction const& wasm_func) { return wasm_func.type(); }, [&](HostFunction const& host_func) { return host_func.type(); }); - if (type.results() != other_type.results()) - return ByteString::formatted("Function import and extern do not match, results: {} vs {}", type.results(), other_type.results()); - if (type.parameters() != other_type.parameters()) - return ByteString::formatted("Function import and extern do not match, parameters: {} vs {}", type.parameters(), other_type.parameters()); + for (auto [i, import_] : enumerate(module.import_section().imports())) { + auto extern_ = externs.at(i); + auto invalid = import_.description().visit( + [&](MemoryType const& mem_type) -> Optional { + if (!extern_.has()) + return "Expected memory import"sv; + auto other_mem_type = m_store.get(extern_.get())->type(); + if (other_mem_type.limits().is_subset_of(mem_type.limits())) return {}; - }, - [&](TypeIndex type_index) -> Optional { - if (!extern_.has()) - return "Expected function import"sv; - auto other_type = m_store.get(extern_.get())->visit([&](WasmFunction const& wasm_func) { return wasm_func.type(); }, [&](HostFunction const& host_func) { return host_func.type(); }); - auto& type = module.type(type_index); - if (type.results() != other_type.results()) - return ByteString::formatted("Function import and extern do not match, results: {} vs {}", type.results(), other_type.results()); - if (type.parameters() != other_type.parameters()) - return ByteString::formatted("Function import and extern do not match, parameters: {} vs {}", type.parameters(), other_type.parameters()); + return ByteString::formatted("Memory import and extern do not match: {}-{} vs {}-{}", mem_type.limits().min(), mem_type.limits().max(), other_mem_type.limits().min(), other_mem_type.limits().max()); + }, + [&](TableType const& table_type) -> Optional { + if (!extern_.has()) + return "Expected table import"sv; + auto other_table_type = m_store.get(extern_.get())->type(); + if (table_type.element_type() == other_table_type.element_type() + && other_table_type.limits().is_subset_of(table_type.limits())) return {}; - }); - if (invalid.has_value()) - instantiation_result = InstantiationError { ByteString::formatted("{}::{}: {}", import_.module(), import_.name(), invalid.release_value()) }; - } - }); - if (instantiation_result.has_value()) - return instantiation_result.release_value(); + return ByteString::formatted("Table import and extern do not match: {}-{} vs {}-{}", table_type.limits().min(), table_type.limits().max(), other_table_type.limits().min(), other_table_type.limits().max()); + }, + [&](GlobalType const& global_type) -> Optional { + if (!extern_.has()) + return "Expected global import"sv; + auto other_global_type = m_store.get(extern_.get())->type(); + if (global_type.type() == other_global_type.type() + && global_type.is_mutable() == other_global_type.is_mutable()) + return {}; + return "Global import and extern do not match"sv; + }, + [&](FunctionType const& type) -> Optional { + if (!extern_.has()) + return "Expected function import"sv; + auto other_type = m_store.get(extern_.get())->visit([&](WasmFunction const& wasm_func) { return wasm_func.type(); }, [&](HostFunction const& host_func) { return host_func.type(); }); + if (type.results() != other_type.results()) + return ByteString::formatted("Function import and extern do not match, results: {} vs {}", type.results(), other_type.results()); + if (type.parameters() != other_type.parameters()) + return ByteString::formatted("Function import and extern do not match, parameters: {} vs {}", type.parameters(), other_type.parameters()); + return {}; + }, + [&](TypeIndex type_index) -> Optional { + if (!extern_.has()) + return "Expected function import"sv; + auto other_type = m_store.get(extern_.get())->visit([&](WasmFunction const& wasm_func) { return wasm_func.type(); }, [&](HostFunction const& host_func) { return host_func.type(); }); + auto& type = module.type_section().types()[type_index.value()]; + if (type.results() != other_type.results()) + return ByteString::formatted("Function import and extern do not match, results: {} vs {}", type.results(), other_type.results()); + if (type.parameters() != other_type.parameters()) + return ByteString::formatted("Function import and extern do not match, parameters: {} vs {}", type.parameters(), other_type.parameters()); + return {}; + }); + if (invalid.has_value()) + return InstantiationError { ByteString::formatted("{}::{}: {}", import_.module(), import_.name(), invalid.release_value()) }; + } for (auto& entry : externs) { if (auto* ptr = entry.get_pointer()) @@ -223,239 +215,179 @@ InstantiationResult AbstractMachine::instantiate(Module const& module, Vector([&](FunctionSection const& section) { function_section = §ion; }); - Vector module_functions; - if (function_section) - module_functions.ensure_capacity(function_section->types().size()); + module_functions.ensure_capacity(module.function_section().types().size()); - module.for_each_section_of_type([&](auto& code_section) { - size_t i = 0; - for (auto& code : code_section.functions()) { - auto type_index = function_section->types()[i]; - auto address = m_store.allocate(main_module_instance, code, type_index); - VERIFY(address.has_value()); - auxiliary_instance.functions().append(*address); - module_functions.append(*address); - ++i; - } - }); + size_t i = 0; + for (auto& code : module.code_section().functions()) { + auto type_index = module.function_section().types()[i]; + auto address = m_store.allocate(main_module_instance, code, type_index); + VERIFY(address.has_value()); + auxiliary_instance.functions().append(*address); + module_functions.append(*address); + ++i; + } BytecodeInterpreter interpreter(m_stack_info); - module.for_each_section_of_type([&](auto& global_section) { - for (auto& entry : global_section.entries()) { + for (auto& entry : module.global_section().entries()) { + Configuration config { m_store }; + if (m_should_limit_instruction_count) + config.enable_instruction_count_limit(); + config.set_frame(Frame { + auxiliary_instance, + Vector {}, + entry.expression(), + 1, + }); + auto result = config.execute(interpreter).assert_wasm_result(); + if (result.is_trap()) + return InstantiationError { ByteString::formatted("Global value construction trapped: {}", result.trap().reason) }; + global_values.append(result.values().first()); + } + + if (auto result = allocate_all_initial_phase(module, main_module_instance, externs, global_values, module_functions); result.has_value()) + return result.release_value(); + + for (auto& segment : module.element_section().segments()) { + Vector references; + for (auto& entry : segment.init) { Configuration config { m_store }; if (m_should_limit_instruction_count) config.enable_instruction_count_limit(); config.set_frame(Frame { auxiliary_instance, Vector {}, - entry.expression(), - 1, + entry, + entry.instructions().size(), }); auto result = config.execute(interpreter).assert_wasm_result(); if (result.is_trap()) - instantiation_result = InstantiationError { ByteString::formatted("Global value construction trapped: {}", result.trap().reason) }; - else - global_values.append(result.values().first()); + return InstantiationError { ByteString::formatted("Element construction trapped: {}", result.trap().reason) }; + + for (auto& value : result.values()) { + auto reference = value.to(); + references.append(reference.release_value()); + } } - }); + elements.append(move(references)); + } - if (instantiation_result.has_value()) - return instantiation_result.release_value(); - - if (auto result = allocate_all_initial_phase(module, main_module_instance, externs, global_values, module_functions); result.has_value()) + if (auto result = allocate_all_final_phase(module, main_module_instance, elements); result.has_value()) return result.release_value(); - module.for_each_section_of_type([&](ElementSection const& section) { - for (auto& segment : section.segments()) { - Vector references; - for (auto& entry : segment.init) { + size_t index = 0; + for (auto& segment : module.element_section().segments()) { + auto current_index = index; + ++index; + auto active_ptr = segment.mode.get_pointer(); + auto elem_instance = m_store.get(main_module_instance.elements()[current_index]); + if (!active_ptr) { + if (segment.mode.has()) + *elem_instance = ElementInstance(elem_instance->type(), {}); + continue; + } + Configuration config { m_store }; + if (m_should_limit_instruction_count) + config.enable_instruction_count_limit(); + config.set_frame(Frame { + auxiliary_instance, + Vector {}, + active_ptr->expression, + 1, + }); + auto result = config.execute(interpreter).assert_wasm_result(); + if (result.is_trap()) + return InstantiationError { ByteString::formatted("Element section initialisation trapped: {}", result.trap().reason) }; + auto d = result.values().first().to(); + if (!d.has_value()) + return InstantiationError { "Element section initialisation returned invalid table initial offset" }; + auto table_instance = m_store.get(main_module_instance.tables()[active_ptr->index.value()]); + if (current_index >= main_module_instance.elements().size()) + return InstantiationError { "Invalid element referenced by active element segment" }; + if (!table_instance || !elem_instance) + return InstantiationError { "Invalid element referenced by active element segment" }; + + Checked total_size = elem_instance->references().size(); + total_size.saturating_add(d.value()); + + if (total_size.value() > table_instance->elements().size()) + return InstantiationError { "Table instantiation out of bounds" }; + + size_t i = 0; + for (auto it = elem_instance->references().begin(); it < elem_instance->references().end(); ++i, ++it) + table_instance->elements()[i + d.value()] = *it; + // Drop element + *m_store.get(main_module_instance.elements()[current_index]) = ElementInstance(elem_instance->type(), {}); + } + + for (auto& segment : module.data_section().data()) { + Optional result = segment.value().visit( + [&](DataSection::Data::Active const& data) -> Optional { Configuration config { m_store }; if (m_should_limit_instruction_count) config.enable_instruction_count_limit(); config.set_frame(Frame { auxiliary_instance, Vector {}, - entry, - entry.instructions().size(), + data.offset, + 1, }); auto result = config.execute(interpreter).assert_wasm_result(); - if (result.is_trap()) { - instantiation_result = InstantiationError { ByteString::formatted("Element construction trapped: {}", result.trap().reason) }; - return IterationDecision::Continue; + if (result.is_trap()) + return InstantiationError { ByteString::formatted("Data section initialisation trapped: {}", result.trap().reason) }; + size_t offset = TRY(result.values().first().value().visit( + [&](auto const& value) { return ErrorOr { value }; }, + [&](u128 const&) { return ErrorOr { InstantiationError { "Data segment offset returned a vector type"sv } }; }, + [&](Reference const&) { return ErrorOr { InstantiationError { "Data segment offset returned a reference type"sv } }; })); + if (main_module_instance.memories().size() <= data.index.value()) { + return InstantiationError { + ByteString::formatted("Data segment referenced out-of-bounds memory ({}) of max {} entries", + data.index.value(), main_module_instance.memories().size()) + }; } - - for (auto& value : result.values()) { - if (!value.type().is_reference()) { - instantiation_result = InstantiationError { "Evaluated element entry is not a reference" }; - return IterationDecision::Continue; - } - auto reference = value.to(); - if (!reference.has_value()) { - instantiation_result = InstantiationError { "Evaluated element entry does not contain a reference" }; - return IterationDecision::Continue; - } - // FIXME: type-check the reference. - references.append(reference.release_value()); + auto maybe_data_address = m_store.allocate_data(data.init); + if (!maybe_data_address.has_value()) { + return InstantiationError { "Failed to allocate a data instance for an active data segment"sv }; } - } - elements.append(move(references)); - } + main_module_instance.datas().append(*maybe_data_address); - return IterationDecision::Continue; - }); - - if (instantiation_result.has_value()) - return instantiation_result.release_value(); - - if (auto result = allocate_all_final_phase(module, main_module_instance, elements); result.has_value()) - return result.release_value(); - - module.for_each_section_of_type([&](ElementSection const& section) { - size_t index = 0; - for (auto& segment : section.segments()) { - auto current_index = index; - ++index; - auto active_ptr = segment.mode.get_pointer(); - auto elem_instance = m_store.get(main_module_instance.elements()[current_index]); - if (!active_ptr) { - if (segment.mode.has()) - *elem_instance = ElementInstance(elem_instance->type(), {}); - continue; - } - Configuration config { m_store }; - if (m_should_limit_instruction_count) - config.enable_instruction_count_limit(); - config.set_frame(Frame { - auxiliary_instance, - Vector {}, - active_ptr->expression, - 1, - }); - auto result = config.execute(interpreter).assert_wasm_result(); - if (result.is_trap()) { - instantiation_result = InstantiationError { ByteString::formatted("Element section initialisation trapped: {}", result.trap().reason) }; - return IterationDecision::Break; - } - auto d = result.values().first().to(); - if (!d.has_value()) { - instantiation_result = InstantiationError { "Element section initialisation returned invalid table initial offset" }; - return IterationDecision::Break; - } - auto table_instance = m_store.get(main_module_instance.tables()[active_ptr->index.value()]); - if (current_index >= main_module_instance.elements().size()) { - instantiation_result = InstantiationError { "Invalid element referenced by active element segment" }; - return IterationDecision::Break; - } - if (!table_instance || !elem_instance) { - instantiation_result = InstantiationError { "Invalid element referenced by active element segment" }; - return IterationDecision::Break; - } - - Checked total_size = elem_instance->references().size(); - total_size.saturating_add(d.value()); - - if (total_size.value() > table_instance->elements().size()) { - instantiation_result = InstantiationError { "Table instantiation out of bounds" }; - return IterationDecision::Break; - } - - size_t i = 0; - for (auto it = elem_instance->references().begin(); it < elem_instance->references().end(); ++i, ++it) { - table_instance->elements()[i + d.value()] = *it; - } - // Drop element - *m_store.get(main_module_instance.elements()[current_index]) = ElementInstance(elem_instance->type(), {}); - } - - return IterationDecision::Continue; - }); - - if (instantiation_result.has_value()) - return instantiation_result.release_value(); - - module.for_each_section_of_type([&](DataSection const& data_section) { - for (auto& segment : data_section.data()) { - segment.value().visit( - [&](DataSection::Data::Active const& data) { - Configuration config { m_store }; - if (m_should_limit_instruction_count) - config.enable_instruction_count_limit(); - config.set_frame(Frame { - auxiliary_instance, - Vector {}, - data.offset, - 1, - }); - auto result = config.execute(interpreter).assert_wasm_result(); - if (result.is_trap()) { - instantiation_result = InstantiationError { ByteString::formatted("Data section initialisation trapped: {}", result.trap().reason) }; - return; - } - size_t offset = 0; - result.values().first().value().visit( - [&](auto const& value) { offset = value; }, - [&](u128 const&) { instantiation_result = InstantiationError { "Data segment offset returned a vector type"sv }; }, - [&](Reference const&) { instantiation_result = InstantiationError { "Data segment offset returned a reference"sv }; }); - if (instantiation_result.has_value() && instantiation_result->is_error()) - return; - if (main_module_instance.memories().size() <= data.index.value()) { - instantiation_result = InstantiationError { - ByteString::formatted("Data segment referenced out-of-bounds memory ({}) of max {} entries", - data.index.value(), main_module_instance.memories().size()) - }; - return; - } - auto maybe_data_address = m_store.allocate_data(data.init); - if (!maybe_data_address.has_value()) { - instantiation_result = InstantiationError { "Failed to allocate a data instance for an active data segment"sv }; - return; - } - main_module_instance.datas().append(*maybe_data_address); - - auto address = main_module_instance.memories()[data.index.value()]; - auto instance = m_store.get(address); - Checked checked_offset = data.init.size(); - checked_offset += offset; - if (checked_offset.has_overflow() || checked_offset > instance->size()) { - instantiation_result = InstantiationError { - ByteString::formatted("Data segment attempted to write to out-of-bounds memory ({}) in memory of size {}", - offset, instance->size()) - }; - return; - } - if (data.init.is_empty()) - return; + auto address = main_module_instance.memories()[data.index.value()]; + auto instance = m_store.get(address); + Checked checked_offset = data.init.size(); + checked_offset += offset; + if (checked_offset.has_overflow() || checked_offset > instance->size()) { + return InstantiationError { + ByteString::formatted("Data segment attempted to write to out-of-bounds memory ({}) in memory of size {}", + offset, instance->size()) + }; + } + if (!data.init.is_empty()) instance->data().overwrite(offset, data.init.data(), data.init.size()); - }, - [&](DataSection::Data::Passive const& passive) { - auto maybe_data_address = m_store.allocate_data(passive.init); - if (!maybe_data_address.has_value()) { - instantiation_result = InstantiationError { "Failed to allocate a data instance for a passive data segment"sv }; - return; - } - main_module_instance.datas().append(*maybe_data_address); - }); - } - }); + return {}; + }, + [&](DataSection::Data::Passive const& passive) -> Optional { + auto maybe_data_address = m_store.allocate_data(passive.init); + if (!maybe_data_address.has_value()) { + return InstantiationError { "Failed to allocate a data instance for a passive data segment"sv }; + } + main_module_instance.datas().append(*maybe_data_address); + return {}; + }); + if (result.has_value()) + return result.release_value(); + } - module.for_each_section_of_type([&](StartSection const& section) { + if (module.start_section().function().has_value()) { auto& functions = main_module_instance.functions(); - auto index = section.function().index(); + auto index = module.start_section().function()->index(); if (functions.size() <= index.value()) { - instantiation_result = InstantiationError { ByteString::formatted("Start section function referenced invalid index {} of max {} entries", index.value(), functions.size()) }; - return; + return InstantiationError { ByteString::formatted("Start section function referenced invalid index {} of max {} entries", index.value(), functions.size()) }; } auto result = invoke(functions[index.value()], {}); if (result.is_trap()) - instantiation_result = InstantiationError { ByteString::formatted("Start function trapped: {}", result.trap().reason) }; - }); - - if (instantiation_result.has_value()) - return instantiation_result.release_value(); + return InstantiationError { ByteString::formatted("Start function trapped: {}", result.trap().reason) }; + } return InstantiationResult { move(main_module_instance_pointer) }; } @@ -476,86 +408,77 @@ Optional AbstractMachine::allocate_all_initial_phase(Module // FIXME: What if this fails? - module.for_each_section_of_type([&](TableSection const& section) { - for (auto& table : section.tables()) { - auto table_address = m_store.allocate(table.type()); - VERIFY(table_address.has_value()); - module_instance.tables().append(*table_address); - } - }); + for (auto& table : module.table_section().tables()) { + auto table_address = m_store.allocate(table.type()); + VERIFY(table_address.has_value()); + module_instance.tables().append(*table_address); + } - module.for_each_section_of_type([&](MemorySection const& section) { - for (auto& memory : section.memories()) { - auto memory_address = m_store.allocate(memory.type()); - VERIFY(memory_address.has_value()); - module_instance.memories().append(*memory_address); - } - }); + for (auto& memory : module.memory_section().memories()) { + auto memory_address = m_store.allocate(memory.type()); + VERIFY(memory_address.has_value()); + module_instance.memories().append(*memory_address); + } - module.for_each_section_of_type([&](GlobalSection const& section) { - size_t index = 0; - for (auto& entry : section.entries()) { - auto address = m_store.allocate(entry.type(), move(global_values[index])); - VERIFY(address.has_value()); - module_instance.globals().append(*address); - index++; - } - }); - module.for_each_section_of_type([&](ExportSection const& section) { - for (auto& entry : section.entries()) { - Variant address {}; - entry.description().visit( - [&](FunctionIndex const& index) { - if (module_instance.functions().size() > index.value()) - address = FunctionAddress { module_instance.functions()[index.value()] }; - else - dbgln("Failed to export '{}', the exported address ({}) was out of bounds (min: 0, max: {})", entry.name(), index.value(), module_instance.functions().size()); - }, - [&](TableIndex const& index) { - if (module_instance.tables().size() > index.value()) - address = TableAddress { module_instance.tables()[index.value()] }; - else - dbgln("Failed to export '{}', the exported address ({}) was out of bounds (min: 0, max: {})", entry.name(), index.value(), module_instance.tables().size()); - }, - [&](MemoryIndex const& index) { - if (module_instance.memories().size() > index.value()) - address = MemoryAddress { module_instance.memories()[index.value()] }; - else - dbgln("Failed to export '{}', the exported address ({}) was out of bounds (min: 0, max: {})", entry.name(), index.value(), module_instance.memories().size()); - }, - [&](GlobalIndex const& index) { - if (module_instance.globals().size() > index.value()) - address = GlobalAddress { module_instance.globals()[index.value()] }; - else - dbgln("Failed to export '{}', the exported address ({}) was out of bounds (min: 0, max: {})", entry.name(), index.value(), module_instance.globals().size()); - }); + size_t index = 0; + for (auto& entry : module.global_section().entries()) { + auto address = m_store.allocate(entry.type(), move(global_values[index])); + VERIFY(address.has_value()); + module_instance.globals().append(*address); + index++; + } - if (address.has()) { - result = InstantiationError { "An export could not be resolved" }; - continue; - } - - module_instance.exports().append(ExportInstance { - entry.name(), - move(address).downcast(), + for (auto& entry : module.export_section().entries()) { + Variant address {}; + entry.description().visit( + [&](FunctionIndex const& index) { + if (module_instance.functions().size() > index.value()) + address = FunctionAddress { module_instance.functions()[index.value()] }; + else + dbgln("Failed to export '{}', the exported address ({}) was out of bounds (min: 0, max: {})", entry.name(), index.value(), module_instance.functions().size()); + }, + [&](TableIndex const& index) { + if (module_instance.tables().size() > index.value()) + address = TableAddress { module_instance.tables()[index.value()] }; + else + dbgln("Failed to export '{}', the exported address ({}) was out of bounds (min: 0, max: {})", entry.name(), index.value(), module_instance.tables().size()); + }, + [&](MemoryIndex const& index) { + if (module_instance.memories().size() > index.value()) + address = MemoryAddress { module_instance.memories()[index.value()] }; + else + dbgln("Failed to export '{}', the exported address ({}) was out of bounds (min: 0, max: {})", entry.name(), index.value(), module_instance.memories().size()); + }, + [&](GlobalIndex const& index) { + if (module_instance.globals().size() > index.value()) + address = GlobalAddress { module_instance.globals()[index.value()] }; + else + dbgln("Failed to export '{}', the exported address ({}) was out of bounds (min: 0, max: {})", entry.name(), index.value(), module_instance.globals().size()); }); + + if (address.has()) { + result = InstantiationError { "An export could not be resolved" }; + continue; } - }); + + module_instance.exports().append(ExportInstance { + entry.name(), + move(address).downcast(), + }); + } return result; } Optional AbstractMachine::allocate_all_final_phase(Module const& module, ModuleInstance& module_instance, Vector>& elements) { - module.for_each_section_of_type([&](ElementSection const& section) { - size_t index = 0; - for (auto& segment : section.segments()) { - auto address = m_store.allocate(segment.type, move(elements[index])); - VERIFY(address.has_value()); - module_instance.elements().append(*address); - index++; - } - }); + size_t index = 0; + for (auto& segment : module.element_section().segments()) { + auto address = m_store.allocate(segment.type, move(elements[index])); + VERIFY(address.has_value()); + module_instance.elements().append(*address); + index++; + } return {}; } @@ -642,21 +565,10 @@ void Linker::populate() if (!m_ordered_imports.is_empty()) return; - // There better be at most one import section! - bool already_seen_an_import_section = false; - m_module.for_each_section_of_type([&](ImportSection const& section) { - if (already_seen_an_import_section) { - if (!m_error.has_value()) - m_error = LinkError {}; - m_error->other_errors.append(LinkError::InvalidImportedModule); - return; - } - already_seen_an_import_section = true; - for (auto& import_ : section.imports()) { - m_ordered_imports.append({ import_.module(), import_.name(), import_.description() }); - m_unresolved_imports.set(m_ordered_imports.last()); - } - }); + for (auto& import_ : m_module.import_section().imports()) { + m_ordered_imports.append({ import_.module(), import_.name(), import_.description() }); + m_unresolved_imports.set(m_ordered_imports.last()); + } } } diff --git a/Userland/Libraries/LibWasm/AbstractMachine/Validator.cpp b/Userland/Libraries/LibWasm/AbstractMachine/Validator.cpp index 57ac2476f4c..a727998ba90 100644 --- a/Userland/Libraries/LibWasm/AbstractMachine/Validator.cpp +++ b/Userland/Libraries/LibWasm/AbstractMachine/Validator.cpp @@ -16,111 +16,79 @@ namespace Wasm { ErrorOr Validator::validate(Module& module) { - ErrorOr result {}; + // Pre-emptively make invalid. The module will be set to `Valid` at the end + // of validation. + module.set_validation_status(Module::ValidationStatus::Invalid, {}); // Note: The spec performs this after populating the context, but there's no real reason to do so, // as this has no dependency. HashTable seen_export_names; - module.for_each_section_of_type([&result, &seen_export_names](ExportSection const& section) { - if (result.is_error()) - return; - for (auto& export_ : section.entries()) { - if (seen_export_names.try_set(export_.name()).release_value_but_fixme_should_propagate_errors() != AK::HashSetResult::InsertedNewEntry) { - result = Errors::duplicate_export_name(export_.name()); - return; - } - } - }); - if (result.is_error()) { - module.set_validation_status(Module::ValidationStatus::Invalid, {}); - return result; - } + for (auto& export_ : module.export_section().entries()) + if (seen_export_names.try_set(export_.name()).release_value_but_fixme_should_propagate_errors() != AK::HashSetResult::InsertedNewEntry) + return Errors::duplicate_export_name(export_.name()); m_context = {}; - module.for_each_section_of_type([this](TypeSection const& section) { - m_context.types.extend(section.types()); - }); + m_context.types.extend(module.type_section().types()); + m_context.data_count = module.data_count_section().count(); - module.for_each_section_of_type([this](DataCountSection const& section) { - m_context.data_count = section.count(); - }); - - module.for_each_section_of_type([&](ImportSection const& section) { - for (auto& import_ : section.imports()) { - import_.description().visit( - [this, &result](TypeIndex const& index) { - if (m_context.types.size() > index.value()) - m_context.functions.append(m_context.types[index.value()]); - else - result = Errors::invalid("TypeIndex"sv); - m_context.imported_function_count++; - }, - [this](FunctionType const& type) { - m_context.functions.append(type); - m_context.imported_function_count++; - }, - [this](TableType const& type) { m_context.tables.append(type); }, - [this](MemoryType const& type) { m_context.memories.append(type); }, - [this](GlobalType const& type) { - m_globals_without_internal_globals.append(type); - m_context.globals.append(type); - }); - } - }); - - if (result.is_error()) { - module.set_validation_status(Module::ValidationStatus::Invalid, {}); - return result; + for (auto& import_ : module.import_section().imports()) { + TRY(import_.description().visit( + [&](TypeIndex const& index) -> ErrorOr { + if (m_context.types.size() > index.value()) + m_context.functions.append(m_context.types[index.value()]); + else + return Errors::invalid("TypeIndex"sv); + m_context.imported_function_count++; + return {}; + }, + [&](FunctionType const& type) -> ErrorOr { + m_context.functions.append(type); + m_context.imported_function_count++; + return {}; + }, + [&](TableType const& type) -> ErrorOr { + m_context.tables.append(type); + return {}; + }, + [&](MemoryType const& type) -> ErrorOr { + m_context.memories.append(type); + return {}; + }, + [&](GlobalType const& type) -> ErrorOr { + m_globals_without_internal_globals.append(type); + m_context.globals.append(type); + return {}; + })); } - CodeSection const* code_section { nullptr }; - module.for_each_section_of_type([&](auto& section) { code_section = §ion; }); - module.for_each_section_of_type([&](FunctionSection const& section) { - if ((!code_section && !section.types().is_empty()) || (code_section && code_section->functions().size() != section.types().size())) { - result = Errors::invalid("FunctionSection"sv); - return; - } - m_context.functions.ensure_capacity(section.types().size() + m_context.functions.size()); - for (auto& index : section.types()) { - if (m_context.types.size() > index.value()) { - m_context.functions.append(m_context.types[index.value()]); - } else { - result = Errors::invalid("TypeIndex"sv); - break; - } - } - }); - if (result.is_error()) { - module.set_validation_status(Module::ValidationStatus::Invalid, {}); - return result; - } + if (module.code_section().functions().size() != module.function_section().types().size()) + return Errors::invalid("FunctionSection"sv); - module.for_each_section_of_type([this](TableSection const& section) { - m_context.tables.ensure_capacity(m_context.tables.size() + section.tables().size()); - for (auto& table : section.tables()) - m_context.tables.append(table.type()); - }); + m_context.functions.ensure_capacity(module.function_section().types().size() + m_context.functions.size()); + for (auto& index : module.function_section().types()) + if (m_context.types.size() > index.value()) + m_context.functions.append(m_context.types[index.value()]); + else + return Errors::invalid("TypeIndex"sv); - module.for_each_section_of_type([this](MemorySection const& section) { - m_context.memories.ensure_capacity(m_context.memories.size() + section.memories().size()); - for (auto& memory : section.memories()) - m_context.memories.append(memory.type()); - }); + m_context.tables.ensure_capacity(m_context.tables.size() + module.table_section().tables().size()); + for (auto& table : module.table_section().tables()) + m_context.tables.append(table.type()); - module.for_each_section_of_type([this](GlobalSection const& section) { - m_context.globals.ensure_capacity(m_context.globals.size() + section.entries().size()); - for (auto& global : section.entries()) - m_context.globals.append(global.type()); - }); - module.for_each_section_of_type([this](ElementSection const& section) { - m_context.elements.ensure_capacity(section.segments().size()); - for (auto& segment : section.segments()) - m_context.elements.append(segment.type); - }); - module.for_each_section_of_type([this](DataSection const& section) { - m_context.datas.resize(section.data().size()); - }); + m_context.memories.ensure_capacity(m_context.memories.size() + module.memory_section().memories().size()); + for (auto& memory : module.memory_section().memories()) + m_context.memories.append(memory.type()); + + m_context.globals.ensure_capacity(m_context.globals.size() + module.global_section().entries().size()); + for (auto& global : module.global_section().entries()) + m_context.globals.append(global.type()); + + m_context.elements.ensure_capacity(module.element_section().segments().size()); + for (auto& segment : module.element_section().segments()) + m_context.elements.append(segment.type); + + m_context.datas.resize(module.data_section().data().size()); // We need to build the set of declared functions to check that `ref.func` uses a specific set of predetermined functions, found in: // - Element initializer expressions @@ -134,44 +102,28 @@ ErrorOr Validator::validate(Module& module) } } }; - module.for_each_section_of_type([&](ExportSection const& section) { - for (auto& export_ : section.entries()) { - if (!export_.description().has()) - continue; - auto index = export_.description().get(); - m_context.references->tree.insert(index.value(), index); - } - }); - module.for_each_section_of_type([&](ElementSection const& section) { - for (auto& segment : section.segments()) { - for (auto& expression : segment.init) - scan_expression_for_function_indices(expression); - } - }); - module.for_each_section_of_type([&](GlobalSection const& section) { - for (auto& segment : section.entries()) - scan_expression_for_function_indices(segment.expression()); - }); - bool seen_start_section = false; - module.for_each_section_of_type([&](StartSection const&) { - if (seen_start_section) - result = Errors::multiple_start_sections(); - seen_start_section = true; - }); - if (result.is_error()) { - module.set_validation_status(Module::ValidationStatus::Invalid, {}); - return result; + for (auto& export_ : module.export_section().entries()) { + if (!export_.description().has()) + continue; + auto index = export_.description().get(); + m_context.references->tree.insert(index.value(), index); } + for (auto& segment : module.element_section().segments()) { + for (auto& expression : segment.init) + scan_expression_for_function_indices(expression); + } + for (auto& segment : module.global_section().entries()) + scan_expression_for_function_indices(segment.expression()); - for (auto& section : module.sections()) { - section.visit([this, &result](auto& section) { - result = validate(section); - }); - if (result.is_error()) { - module.set_validation_status(Module::ValidationStatus::Invalid, {}); - return result; - } - } + TRY(validate(module.import_section())); + TRY(validate(module.export_section())); + TRY(validate(module.start_section())); + TRY(validate(module.data_section())); + TRY(validate(module.element_section())); + TRY(validate(module.global_section())); + TRY(validate(module.memory_section())); + TRY(validate(module.table_section())); + TRY(validate(module.code_section())); module.set_validation_status(Module::ValidationStatus::Valid, {}); return {}; @@ -193,8 +145,10 @@ ErrorOr Validator::validate(ExportSection const& section) ErrorOr Validator::validate(StartSection const& section) { - TRY(validate(section.function().index())); - FunctionType const& type = m_context.functions[section.function().index().value()]; + if (!section.function().has_value()) + return {}; + TRY(validate(section.function()->index())); + FunctionType const& type = m_context.functions[section.function()->index().value()]; if (!type.parameters().is_empty() || !type.results().is_empty()) return Errors::invalid("start function signature"sv); return {}; diff --git a/Userland/Libraries/LibWasm/Parser/Parser.cpp b/Userland/Libraries/LibWasm/Parser/Parser.cpp index 28d29a3f905..80b2b6712ef 100644 --- a/Userland/Libraries/LibWasm/Parser/Parser.cpp +++ b/Userland/Libraries/LibWasm/Parser/Parser.cpp @@ -1227,60 +1227,66 @@ ParseResult Module::parse(Stream& stream) if (Bytes { buf, 4 } != wasm_version.span()) return with_eof_check(stream, ParseError::InvalidModuleVersion); - Vector sections; + auto last_section_id = CustomSection::section_id; + Module module; while (!stream.is_eof()) { auto section_id = TRY_READ(stream, u8, ParseError::ExpectedIndex); size_t section_size = TRY_READ(stream, LEB128, ParseError::ExpectedSize); auto section_stream = ConstrainedStream { MaybeOwned(stream), section_size }; + if (section_id != CustomSection::section_id && section_id == last_section_id) + return ParseError::DuplicateSection; + switch (section_id) { case CustomSection::section_id: - sections.append(TRY(CustomSection::parse(section_stream))); + module.custom_sections().append(TRY(CustomSection::parse(section_stream))); break; case TypeSection::section_id: - sections.append(TRY(TypeSection::parse(section_stream))); + module.type_section() = TRY(TypeSection::parse(section_stream)); break; case ImportSection::section_id: - sections.append(TRY(ImportSection::parse(section_stream))); + module.import_section() = TRY(ImportSection::parse(section_stream)); break; case FunctionSection::section_id: - sections.append(TRY(FunctionSection::parse(section_stream))); + module.function_section() = TRY(FunctionSection::parse(section_stream)); break; case TableSection::section_id: - sections.append(TRY(TableSection::parse(section_stream))); + module.table_section() = TRY(TableSection::parse(section_stream)); break; case MemorySection::section_id: - sections.append(TRY(MemorySection::parse(section_stream))); + module.memory_section() = TRY(MemorySection::parse(section_stream)); break; case GlobalSection::section_id: - sections.append(TRY(GlobalSection::parse(section_stream))); + module.global_section() = TRY(GlobalSection::parse(section_stream)); break; case ExportSection::section_id: - sections.append(TRY(ExportSection::parse(section_stream))); + module.export_section() = TRY(ExportSection::parse(section_stream)); break; case StartSection::section_id: - sections.append(TRY(StartSection::parse(section_stream))); + module.start_section() = TRY(StartSection::parse(section_stream)); break; case ElementSection::section_id: - sections.append(TRY(ElementSection::parse(section_stream))); + module.element_section() = TRY(ElementSection::parse(section_stream)); break; case CodeSection::section_id: - sections.append(TRY(CodeSection::parse(section_stream))); + module.code_section() = TRY(CodeSection::parse(section_stream)); break; case DataSection::section_id: - sections.append(TRY(DataSection::parse(section_stream))); + module.data_section() = TRY(DataSection::parse(section_stream)); break; case DataCountSection::section_id: - sections.append(TRY(DataCountSection::parse(section_stream))); + 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_stream.remaining() != 0) return ParseError::SectionSizeMismatch; } - return Module { move(sections) }; + return module; } ByteString parse_error_to_byte_string(ParseError error) @@ -1326,6 +1332,8 @@ ByteString parse_error_to_byte_string(ParseError error) return "A parsed string was not valid UTF-8"; case ParseError::UnknownInstruction: return "A parsed instruction was not known to this parser"; + case ParseError::DuplicateSection: + return "Two sections of the same type were encountered"; } return "Unknown error"; } diff --git a/Userland/Libraries/LibWasm/Printer/Printer.cpp b/Userland/Libraries/LibWasm/Printer/Printer.cpp index 3584fa6368f..b7dfee0065a 100644 --- a/Userland/Libraries/LibWasm/Printer/Printer.cpp +++ b/Userland/Libraries/LibWasm/Printer/Printer.cpp @@ -64,6 +64,8 @@ void Printer::print(Wasm::BlockType const& type) void Printer::print(Wasm::CodeSection const& section) { + if (section.functions().is_empty()) + return; print_indent(); print("(section code\n"); { @@ -97,6 +99,8 @@ void Printer::print(Wasm::CustomSection const& section) void Printer::print(Wasm::DataCountSection const& section) { + if (!section.count().has_value()) + return; print_indent(); print("(section data count\n"); if (section.count().has_value()) { @@ -110,6 +114,8 @@ void Printer::print(Wasm::DataCountSection const& section) void Printer::print(Wasm::DataSection const& section) { + if (section.data().is_empty()) + return; print_indent(); print("(section data\n"); { @@ -163,6 +169,8 @@ void Printer::print(Wasm::DataSection::Data const& data) void Printer::print(Wasm::ElementSection const& section) { + if (section.segments().is_empty()) + return; print_indent(); print("(section element\n"); { @@ -218,6 +226,8 @@ void Printer::print(Wasm::ElementSection::Element const& element) void Printer::print(Wasm::ExportSection const& section) { + if (section.entries().is_empty()) + return; print_indent(); print("(section export\n"); { @@ -282,6 +292,8 @@ void Printer::print(Wasm::CodeSection::Func const& func) void Printer::print(Wasm::FunctionSection const& section) { + if (section.types().is_empty()) + return; print_indent(); print("(section function\n"); { @@ -329,6 +341,8 @@ void Printer::print(Wasm::FunctionType const& type) void Printer::print(Wasm::GlobalSection const& section) { + if (section.entries().is_empty()) + return; print_indent(); print("(section global\n"); { @@ -384,6 +398,8 @@ void Printer::print(Wasm::GlobalType const& type) void Printer::print(Wasm::ImportSection const& section) { + if (section.imports().is_empty()) + return; print_indent(); print("(section import\n"); { @@ -493,6 +509,8 @@ void Printer::print(Wasm::Locals const& local) void Printer::print(Wasm::MemorySection const& section) { + if (section.memories().is_empty()) + return; print_indent(); print("(section memory\n"); { @@ -534,8 +552,20 @@ void Printer::print(Wasm::Module const& module) { TemporaryChange change { m_indent, m_indent + 1 }; print("(module\n"); - for (auto& section : module.sections()) - section.visit([this](auto const& value) { print(value); }); + for (auto& custom_section : module.custom_sections()) + print(custom_section); + print(module.type_section()); + print(module.import_section()); + print(module.function_section()); + print(module.table_section()); + print(module.memory_section()); + print(module.global_section()); + print(module.export_section()); + print(module.start_section()); + print(module.element_section()); + print(module.code_section()); + print(module.data_section()); + print(module.data_count_section()); } print_indent(); print(")\n"); @@ -543,11 +573,13 @@ void Printer::print(Wasm::Module const& module) void Printer::print(Wasm::StartSection const& section) { + if (!section.function().has_value()) + return; print_indent(); print("(section start\n"); { TemporaryChange change { m_indent, m_indent + 1 }; - print(section.function()); + print(*section.function()); } print_indent(); print(")\n"); @@ -561,6 +593,8 @@ void Printer::print(Wasm::StartSection::StartFunction const& function) void Printer::print(Wasm::TableSection const& section) { + if (section.tables().is_empty()) + return; print_indent(); print("(section table\n"); { @@ -601,6 +635,8 @@ void Printer::print(Wasm::TableType const& type) void Printer::print(Wasm::TypeSection const& section) { + if (section.types().is_empty()) + return; print_indent(); print("(section type\n"); { diff --git a/Userland/Libraries/LibWasm/Types.h b/Userland/Libraries/LibWasm/Types.h index e3ddf49dac2..753afcc043f 100644 --- a/Userland/Libraries/LibWasm/Types.h +++ b/Userland/Libraries/LibWasm/Types.h @@ -56,6 +56,7 @@ enum class ParseError { OutOfMemory, SectionSizeMismatch, InvalidUtf8, + DuplicateSection, }; ByteString parse_error_to_byte_string(ParseError); @@ -522,6 +523,8 @@ class TypeSection { public: static constexpr u8 section_id = 1; + TypeSection() = default; + explicit TypeSection(Vector types) : m_types(move(types)) { @@ -569,6 +572,8 @@ public: public: static constexpr u8 section_id = 2; + ImportSection() = default; + explicit ImportSection(Vector imports) : m_imports(move(imports)) { @@ -586,6 +591,8 @@ class FunctionSection { public: static constexpr u8 section_id = 3; + FunctionSection() = default; + explicit FunctionSection(Vector types) : m_types(move(types)) { @@ -619,6 +626,8 @@ public: public: static constexpr u8 section_id = 4; + TableSection() = default; + explicit TableSection(Vector tables) : m_tables(move(tables)) { @@ -652,6 +661,8 @@ public: public: static constexpr u8 section_id = 5; + MemorySection() = default; + explicit MemorySection(Vector memories) : m_memories(move(memories)) { @@ -703,6 +714,8 @@ public: public: static constexpr u8 section_id = 6; + GlobalSection() = default; + explicit GlobalSection(Vector entries) : m_entries(move(entries)) { @@ -741,6 +754,8 @@ public: static constexpr u8 section_id = 7; + ExportSection() = default; + explicit ExportSection(Vector entries) : m_entries(move(entries)) { @@ -773,7 +788,9 @@ public: static constexpr u8 section_id = 8; - explicit StartSection(StartFunction func) + StartSection() = default; + + explicit StartSection(Optional func) : m_function(move(func)) { } @@ -783,7 +800,7 @@ public: static ParseResult parse(Stream& stream); private: - StartFunction m_function; + Optional m_function; }; class ElementSection { @@ -807,6 +824,8 @@ public: static constexpr u8 section_id = 9; + ElementSection() = default; + explicit ElementSection(Vector segs) : m_segments(move(segs)) { @@ -879,6 +898,8 @@ public: static constexpr u8 section_id = 10; + CodeSection() = default; + explicit CodeSection(Vector funcs) : m_functions(move(funcs)) { @@ -921,6 +942,8 @@ public: static constexpr u8 section_id = 11; + DataSection() = default; + explicit DataSection(Vector data) : m_data(move(data)) { @@ -938,6 +961,8 @@ class DataCountSection { public: static constexpr u8 section_id = 12; + DataCountSection() = default; + explicit DataCountSection(Optional count) : m_count(move(count)) { @@ -959,57 +984,37 @@ public: Valid, }; - using AnySection = Variant< - CustomSection, - TypeSection, - ImportSection, - FunctionSection, - TableSection, - MemorySection, - GlobalSection, - ExportSection, - StartSection, - ElementSection, - CodeSection, - DataSection, - DataCountSection>; - static constexpr Array wasm_magic { 0, 'a', 's', 'm' }; static constexpr Array wasm_version { 1, 0, 0, 0 }; - explicit Module(Vector sections) - : m_sections(move(sections)) - { - } + Module() = default; - auto& sections() const { return m_sections; } - auto& type(TypeIndex index) const - { - FunctionType const* type = nullptr; - for_each_section_of_type([&](TypeSection const& section) { - type = §ion.types().at(index.value()); - }); - - VERIFY(type != nullptr); - return *type; - } - - template - void for_each_section_of_type(Callback&& callback) const - { - for (auto& section : m_sections) { - if (auto ptr = section.get_pointer()) - callback(*ptr); - } - } - template - void for_each_section_of_type(Callback&& callback) - { - for (auto& section : m_sections) { - if (auto ptr = section.get_pointer()) - callback(*ptr); - } - } + auto& custom_sections() { return m_custom_sections; } + auto& custom_sections() const { return m_custom_sections; } + auto& type_section() const { return m_type_section; } + auto& type_section() { return m_type_section; } + auto& import_section() const { return m_import_section; } + auto& import_section() { return m_import_section; } + auto& function_section() { return m_function_section; } + auto& function_section() const { return m_function_section; } + auto& table_section() { return m_table_section; } + auto& table_section() const { return m_table_section; } + auto& memory_section() { return m_memory_section; } + auto& memory_section() const { return m_memory_section; } + auto& global_section() { return m_global_section; } + auto& global_section() const { return m_global_section; } + auto& export_section() { return m_export_section; } + auto& export_section() const { return m_export_section; } + auto& start_section() { return m_start_section; } + auto& start_section() const { return m_start_section; } + auto& element_section() { return m_element_section; } + auto& element_section() const { return m_element_section; } + auto& code_section() { return m_code_section; } + auto& code_section() const { return m_code_section; } + auto& data_section() { return m_data_section; } + auto& data_section() const { return m_data_section; } + auto& data_count_section() { return m_data_count_section; } + auto& data_count_section() const { return m_data_count_section; } void set_validation_status(ValidationStatus status, Badge) { set_validation_status(status); } ValidationStatus validation_status() const { return m_validation_status; } @@ -1021,7 +1026,20 @@ public: private: void set_validation_status(ValidationStatus status) { m_validation_status = status; } - Vector m_sections; + Vector m_custom_sections; + TypeSection m_type_section; + ImportSection m_import_section; + FunctionSection m_function_section; + TableSection m_table_section; + MemorySection m_memory_section; + GlobalSection m_global_section; + ExportSection m_export_section; + StartSection m_start_section; + ElementSection m_element_section; + CodeSection m_code_section; + DataSection m_data_section; + DataCountSection m_data_count_section; + ValidationStatus m_validation_status { ValidationStatus::Unchecked }; Optional m_validation_error; }; diff --git a/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp b/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp index ca0e969011d..b243a2f3089 100644 --- a/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp +++ b/Userland/Libraries/LibWeb/WebAssembly/WebAssembly.cpp @@ -182,7 +182,7 @@ JS::ThrowCompletionOr> instantiate_module(JS TRY(import_name.type.visit( [&](Wasm::TypeIndex index) -> JS::ThrowCompletionOr { dbgln("Trying to resolve a function {}::{}, type index {}", import_name.module, import_name.name, index.value()); - auto& type = module.type(index); + auto& type = module.type_section().types()[index.value()]; // FIXME: IsCallable() if (!import_.is_function()) return {}; diff --git a/Userland/Utilities/wasm.cpp b/Userland/Utilities/wasm.cpp index 7568ba0f563..56e6b7dcc8c 100644 --- a/Userland/Utilities/wasm.cpp +++ b/Userland/Utilities/wasm.cpp @@ -672,7 +672,7 @@ ErrorOr serenity_main(Main::Arguments arguments) for (auto& entry : linker.unresolved_imports()) { if (!entry.type.has()) continue; - auto type = parse_result.value().type(entry.type.get()); + auto type = parse_result.value().type_section().types()[entry.type.get().value()]; auto address = machine.store().allocate(Wasm::HostFunction( [name = entry.name, type = type](auto&, auto& arguments) -> Wasm::Result { StringBuilder argument_builder;