mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2026-04-18 18:18:44 +00:00
637 lines
26 KiB
C
637 lines
26 KiB
C
/*
|
|
* Copyright (C) 2026 Airbus Defence and Space Romania SRL. All rights reserved.
|
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
*/
|
|
|
|
#include "wasm_component.h"
|
|
#include "../interpreter/wasm.h"
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include "wasm_loader_common.h"
|
|
#include "wasm_runtime_common.h"
|
|
#include "wasm_export.h"
|
|
#include <stdio.h>
|
|
|
|
// Parse all sections in a WASM component binary
|
|
// Each section is dispatched to its own parser and stored in the output
|
|
// structure
|
|
bool
|
|
wasm_component_parse_sections(const uint8_t *buf, uint32_t size,
|
|
WASMComponent *out_component, LoadArgs *args,
|
|
unsigned int depth)
|
|
{
|
|
if (!buf || size < 8 || !out_component) {
|
|
return false;
|
|
}
|
|
|
|
// Decode the header first
|
|
if (!wasm_decode_header(buf, size, &out_component->header)) {
|
|
return false;
|
|
}
|
|
|
|
// const uint8_t *begin = buf;
|
|
const uint8_t *p = buf + 8;
|
|
const uint8_t *end = buf + size;
|
|
uint32_t section_capacity = 8;
|
|
|
|
WASMComponentSection *sections =
|
|
wasm_runtime_malloc(section_capacity * sizeof(WASMComponentSection));
|
|
if (!sections) {
|
|
return false;
|
|
}
|
|
|
|
uint32_t section_count = 0;
|
|
while (p < end) {
|
|
// Read section id (1 byte) and payload length (LEB128)
|
|
uint8_t section_id = *p++;
|
|
char error_buf[128] = { 0 };
|
|
|
|
// Read payload length
|
|
uint64 payload_len = 0;
|
|
if (!read_leb((uint8_t **)&p, end, 32, false, &payload_len, error_buf,
|
|
sizeof(error_buf))) {
|
|
wasm_runtime_free(sections);
|
|
return false; // Error handling
|
|
}
|
|
|
|
if ((uint32_t)(end - p) < payload_len) {
|
|
wasm_runtime_free(sections);
|
|
return false;
|
|
}
|
|
|
|
// Store section info
|
|
if (section_count == section_capacity) {
|
|
section_capacity *= 2;
|
|
WASMComponentSection *new_sections = wasm_runtime_realloc(
|
|
sections, section_capacity * sizeof(WASMComponentSection));
|
|
if (!new_sections) {
|
|
wasm_runtime_free(sections);
|
|
return false;
|
|
}
|
|
sections = new_sections;
|
|
}
|
|
|
|
const uint8_t *payload_start = p;
|
|
uint32_t current_section_index = section_count;
|
|
sections[current_section_index].payload = payload_start;
|
|
sections[current_section_index].payload_len = (uint32_t)payload_len;
|
|
sections[current_section_index].id = section_id;
|
|
sections[current_section_index].parsed.any =
|
|
NULL; // Initialize parsed union to NULL
|
|
section_count++;
|
|
|
|
uint32_t consumed_len = 0;
|
|
bool parse_success = false;
|
|
|
|
// LOG_DEBUG("Parsing section: %d | Section size: %d | payload_start:
|
|
// %d\n", section_id, payload_len, payload_start-begin);
|
|
switch (section_id) {
|
|
// Section 0: custom section
|
|
case WASM_COMP_SECTION_CORE_CUSTOM:
|
|
{
|
|
// Parse custom section (name + data)
|
|
WASMComponentCoreCustomSection *custom =
|
|
wasm_runtime_malloc(sizeof(WASMComponentCoreCustomSection));
|
|
if (custom)
|
|
memset(custom, 0, sizeof(WASMComponentCoreCustomSection));
|
|
|
|
parse_success = wasm_component_parse_core_custom_section(
|
|
&p, (uint32_t)payload_len, custom, error_buf,
|
|
sizeof(error_buf), &consumed_len);
|
|
if (!parse_success || consumed_len != payload_len) {
|
|
if (custom) {
|
|
wasm_runtime_free(custom);
|
|
}
|
|
if (error_buf[0]) {
|
|
LOG_DEBUG("Error parsing custom section: %s\n",
|
|
error_buf);
|
|
}
|
|
if (consumed_len != payload_len) {
|
|
LOG_DEBUG("FATAL ERROR: Custom section consumed %u "
|
|
"bytes but expected %lu\n",
|
|
consumed_len, payload_len);
|
|
wasm_runtime_free(sections);
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
sections[current_section_index].parsed.core_custom = custom;
|
|
}
|
|
break;
|
|
}
|
|
// Section 1: module section
|
|
case WASM_COMP_SECTION_CORE_MODULE:
|
|
{
|
|
// Parse and load the embedded core wasm module
|
|
WASMComponentCoreModuleWrapper *module =
|
|
wasm_runtime_malloc(sizeof(WASMComponentCoreModuleWrapper));
|
|
if (module)
|
|
memset(module, 0, sizeof(WASMComponentCoreModuleWrapper));
|
|
parse_success = wasm_component_parse_core_module_section(
|
|
&payload_start, (uint32_t)payload_len, module, args,
|
|
error_buf, sizeof(error_buf), &consumed_len);
|
|
if (!parse_success || consumed_len != payload_len) {
|
|
if (module) {
|
|
wasm_runtime_free(module);
|
|
}
|
|
if (error_buf[0]) {
|
|
LOG_DEBUG("Error parsing module section: %s\n",
|
|
error_buf);
|
|
}
|
|
if (consumed_len != payload_len) {
|
|
LOG_DEBUG("FATAL ERROR: Module section consumed %u "
|
|
"bytes but expected %lu\n",
|
|
consumed_len, payload_len);
|
|
wasm_runtime_free(sections);
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
sections[current_section_index].parsed.core_module = module;
|
|
}
|
|
break;
|
|
}
|
|
// Section 2: instance section
|
|
case WASM_COMP_SECTION_CORE_INSTANCE:
|
|
{
|
|
WASMComponentCoreInstSection *core_instance_section =
|
|
wasm_runtime_malloc(sizeof(WASMComponentCoreInstSection));
|
|
if (core_instance_section)
|
|
memset(core_instance_section, 0,
|
|
sizeof(WASMComponentCoreInstSection));
|
|
parse_success = wasm_component_parse_core_instance_section(
|
|
&payload_start, (uint32_t)payload_len,
|
|
core_instance_section, error_buf, sizeof(error_buf),
|
|
&consumed_len);
|
|
if (parse_success && consumed_len == payload_len) {
|
|
sections[current_section_index]
|
|
.parsed.core_instance_section = core_instance_section;
|
|
}
|
|
else {
|
|
if (core_instance_section) {
|
|
wasm_runtime_free(core_instance_section);
|
|
}
|
|
if (error_buf[0]) {
|
|
LOG_DEBUG("Error parsing core instances section: %s\n",
|
|
error_buf);
|
|
}
|
|
if (consumed_len != payload_len) {
|
|
LOG_DEBUG("FATAL ERROR: Core Instances section "
|
|
"consumed %u bytes but expected %lu\n",
|
|
consumed_len, payload_len);
|
|
wasm_runtime_free(sections);
|
|
return false;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
// Section 3: core types section
|
|
case WASM_COMP_SECTION_CORE_TYPE:
|
|
{
|
|
WASMComponentCoreTypeSection *core_type_section =
|
|
wasm_runtime_malloc(sizeof(WASMComponentCoreTypeSection));
|
|
if (core_type_section)
|
|
memset(core_type_section, 0,
|
|
sizeof(WASMComponentCoreTypeSection));
|
|
parse_success = wasm_component_parse_core_type_section(
|
|
&payload_start, (uint32_t)payload_len, core_type_section,
|
|
error_buf, sizeof(error_buf), &consumed_len);
|
|
if (parse_success && consumed_len == payload_len) {
|
|
sections[current_section_index].parsed.core_type_section =
|
|
core_type_section;
|
|
}
|
|
else {
|
|
if (core_type_section) {
|
|
wasm_runtime_free(core_type_section);
|
|
}
|
|
if (error_buf[0]) {
|
|
LOG_DEBUG("Error parsing core types section: %s\n",
|
|
error_buf);
|
|
}
|
|
if (consumed_len != payload_len) {
|
|
LOG_DEBUG("FATAL ERROR: Core types section consumed %u "
|
|
"bytes but expected %lu\n",
|
|
consumed_len, payload_len);
|
|
wasm_runtime_free(sections);
|
|
return false;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
// Section 4: component section
|
|
case WASM_COMP_SECTION_COMPONENT:
|
|
{
|
|
// Parse and load the embedded component
|
|
WASMComponent *component =
|
|
wasm_runtime_malloc(sizeof(WASMComponent));
|
|
if (!component) {
|
|
LOG_DEBUG(
|
|
"Failed to allocate memory for nested component\n");
|
|
wasm_runtime_free(sections);
|
|
return false;
|
|
}
|
|
// Initialize the component structure to avoid garbage data
|
|
memset(component, 0, sizeof(WASMComponent));
|
|
|
|
// Parse the nested component sections directly from the payload
|
|
parse_success = wasm_component_parse_sections(
|
|
payload_start, (uint32_t)payload_len, component, args,
|
|
depth + 1);
|
|
consumed_len = payload_len; // The entire payload is consumed
|
|
|
|
if (!parse_success) {
|
|
LOG_DEBUG(" Failed to parse nested component, freeing "
|
|
"component at %p\n",
|
|
component);
|
|
wasm_runtime_free(component);
|
|
LOG_DEBUG("Error parsing sub component section\n");
|
|
wasm_runtime_free(sections);
|
|
return false;
|
|
}
|
|
else {
|
|
LOG_DEBUG(
|
|
" Successfully parsed nested component at %p\n",
|
|
component);
|
|
sections[current_section_index].parsed.component =
|
|
component;
|
|
}
|
|
break;
|
|
}
|
|
// Section 5: instances section
|
|
case WASM_COMP_SECTION_INSTANCES:
|
|
{
|
|
WASMComponentInstSection *instance_section =
|
|
wasm_runtime_malloc(sizeof(WASMComponentInstSection));
|
|
if (instance_section)
|
|
memset(instance_section, 0,
|
|
sizeof(WASMComponentInstSection));
|
|
parse_success = wasm_component_parse_instances_section(
|
|
&payload_start, (uint32_t)payload_len, instance_section,
|
|
error_buf, sizeof(error_buf), &consumed_len);
|
|
if (parse_success && consumed_len == payload_len) {
|
|
sections[current_section_index].parsed.instance_section =
|
|
instance_section;
|
|
}
|
|
else {
|
|
if (instance_section) {
|
|
wasm_runtime_free(instance_section);
|
|
}
|
|
if (error_buf[0]) {
|
|
LOG_DEBUG("Error parsing instances section: %s\n",
|
|
error_buf);
|
|
}
|
|
if (consumed_len != payload_len) {
|
|
LOG_DEBUG("FATAL ERROR: Instances section consumed %u "
|
|
"bytes but expected %lu\n",
|
|
consumed_len, payload_len);
|
|
wasm_runtime_free(sections);
|
|
return false;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
// Section 6: aliases section for imports/exports
|
|
case WASM_COMP_SECTION_ALIASES:
|
|
{
|
|
// Parse alias definitions for imports/exports
|
|
WASMComponentAliasSection *alias_section =
|
|
wasm_runtime_malloc(sizeof(WASMComponentAliasSection));
|
|
if (alias_section)
|
|
memset(alias_section, 0, sizeof(WASMComponentAliasSection));
|
|
parse_success = wasm_component_parse_alias_section(
|
|
&payload_start, (uint32_t)payload_len, alias_section,
|
|
error_buf, sizeof(error_buf), &consumed_len);
|
|
if (parse_success && consumed_len == payload_len) {
|
|
sections[current_section_index].parsed.alias_section =
|
|
alias_section;
|
|
}
|
|
else {
|
|
if (alias_section) {
|
|
wasm_runtime_free(alias_section);
|
|
}
|
|
if (error_buf[0]) {
|
|
LOG_DEBUG("Error parsing alias section: %s\n",
|
|
error_buf);
|
|
}
|
|
if (consumed_len != payload_len) {
|
|
LOG_DEBUG("FATAL ERROR: Alias section consumed %u "
|
|
"bytes but expected %lu\n",
|
|
consumed_len, payload_len);
|
|
wasm_runtime_free(sections);
|
|
return false;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
// Section 7: types section
|
|
case WASM_COMP_SECTION_TYPE:
|
|
{
|
|
WASMComponentTypeSection *type_section =
|
|
wasm_runtime_malloc(sizeof(WASMComponentTypeSection));
|
|
if (type_section)
|
|
memset(type_section, 0, sizeof(WASMComponentTypeSection));
|
|
parse_success = wasm_component_parse_types_section(
|
|
&payload_start, (uint32_t)payload_len, type_section,
|
|
error_buf, sizeof(error_buf), &consumed_len);
|
|
if (parse_success && consumed_len == payload_len) {
|
|
sections[current_section_index].parsed.type_section =
|
|
type_section;
|
|
}
|
|
else {
|
|
if (type_section) {
|
|
wasm_runtime_free(type_section);
|
|
}
|
|
if (error_buf[0]) {
|
|
LOG_DEBUG("Error parsing types section: %s\n",
|
|
error_buf);
|
|
}
|
|
if (consumed_len != payload_len) {
|
|
LOG_DEBUG("FATAL ERROR: Types section consumed %u "
|
|
"bytes but expected %lu\n",
|
|
consumed_len, payload_len);
|
|
wasm_runtime_free(sections);
|
|
return false;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
// Section 8: canons section
|
|
case WASM_COMP_SECTION_CANONS:
|
|
{
|
|
WASMComponentCanonSection *canon_section =
|
|
wasm_runtime_malloc(sizeof(WASMComponentCanonSection));
|
|
if (canon_section)
|
|
memset(canon_section, 0, sizeof(WASMComponentCanonSection));
|
|
parse_success = wasm_component_parse_canons_section(
|
|
&payload_start, (uint32_t)payload_len, canon_section,
|
|
error_buf, sizeof(error_buf), &consumed_len);
|
|
if (parse_success && consumed_len == payload_len) {
|
|
sections[current_section_index].parsed.canon_section =
|
|
canon_section;
|
|
}
|
|
else {
|
|
if (canon_section) {
|
|
wasm_runtime_free(canon_section);
|
|
}
|
|
if (error_buf[0]) {
|
|
LOG_DEBUG("Error parsing canons section: %s\n",
|
|
error_buf);
|
|
}
|
|
if (consumed_len != payload_len) {
|
|
LOG_DEBUG("FATAL ERROR: Canons section consumed %u "
|
|
"bytes but expected %lu\n",
|
|
consumed_len, payload_len);
|
|
wasm_runtime_free(sections);
|
|
return false;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
// Section 9: start section
|
|
case WASM_COMP_SECTION_START:
|
|
{
|
|
WASMComponentStartSection *start_section =
|
|
wasm_runtime_malloc(sizeof(WASMComponentStartSection));
|
|
if (start_section)
|
|
memset(start_section, 0, sizeof(WASMComponentStartSection));
|
|
parse_success = wasm_component_parse_start_section(
|
|
&payload_start, (uint32_t)payload_len, start_section,
|
|
error_buf, sizeof(error_buf), &consumed_len);
|
|
if (parse_success && consumed_len == payload_len) {
|
|
sections[current_section_index].parsed.start_section =
|
|
start_section;
|
|
}
|
|
else {
|
|
if (start_section) {
|
|
wasm_runtime_free(start_section);
|
|
}
|
|
if (error_buf[0]) {
|
|
LOG_DEBUG("Error parsing start section: %s\n",
|
|
error_buf);
|
|
}
|
|
if (consumed_len != payload_len) {
|
|
LOG_DEBUG("FATAL ERROR: Start section consumed %u "
|
|
"bytes but expected %lu\n",
|
|
consumed_len, payload_len);
|
|
wasm_runtime_free(sections);
|
|
return false;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
// Section 10: imports section (component model imports)
|
|
case WASM_COMP_SECTION_IMPORTS:
|
|
{
|
|
// Parse all imports: name (simple/versioned) and externdesc
|
|
// (all 6 types)
|
|
WASMComponentImportSection *import_section =
|
|
wasm_runtime_malloc(sizeof(WASMComponentImportSection));
|
|
if (import_section)
|
|
memset(import_section, 0,
|
|
sizeof(WASMComponentImportSection));
|
|
parse_success = wasm_component_parse_imports_section(
|
|
&payload_start, (uint32_t)payload_len, import_section,
|
|
error_buf, sizeof(error_buf), &consumed_len);
|
|
if (parse_success && consumed_len == payload_len) {
|
|
sections[current_section_index].parsed.import_section =
|
|
import_section;
|
|
}
|
|
else {
|
|
if (import_section) {
|
|
wasm_runtime_free(import_section);
|
|
}
|
|
if (error_buf[0]) {
|
|
LOG_DEBUG("Error parsing imports section: %s\n",
|
|
error_buf);
|
|
}
|
|
if (consumed_len != payload_len) {
|
|
LOG_DEBUG("FATAL ERROR: Imports section consumed %u "
|
|
"bytes but expected %lu\n",
|
|
consumed_len, payload_len);
|
|
wasm_runtime_free(sections);
|
|
return false;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
// Section 11: exports section
|
|
case WASM_COMP_SECTION_EXPORTS:
|
|
{
|
|
WASMComponentExportSection *export_section =
|
|
wasm_runtime_malloc(sizeof(WASMComponentExportSection));
|
|
if (export_section)
|
|
memset(export_section, 0,
|
|
sizeof(WASMComponentExportSection));
|
|
parse_success = wasm_component_parse_exports_section(
|
|
&payload_start, (uint32_t)payload_len, export_section,
|
|
error_buf, sizeof(error_buf), &consumed_len);
|
|
if (parse_success && consumed_len == payload_len) {
|
|
sections[current_section_index].parsed.export_section =
|
|
export_section;
|
|
}
|
|
else {
|
|
if (export_section) {
|
|
wasm_runtime_free(export_section);
|
|
}
|
|
if (error_buf[0]) {
|
|
LOG_DEBUG("Error parsing export section: %s\n",
|
|
error_buf);
|
|
}
|
|
if (consumed_len != payload_len) {
|
|
LOG_DEBUG("FATAL ERROR: Exports section consumed %u "
|
|
"bytes but expected %lu\n",
|
|
consumed_len, payload_len);
|
|
wasm_runtime_free(sections);
|
|
return false;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
// Section 12: values section
|
|
case WASM_COMP_SECTION_VALUES:
|
|
{
|
|
WASMComponentValueSection *value_section =
|
|
wasm_runtime_malloc(sizeof(WASMComponentValueSection));
|
|
if (value_section)
|
|
memset(value_section, 0, sizeof(WASMComponentValueSection));
|
|
parse_success = wasm_component_parse_values_section(
|
|
&payload_start, (uint32_t)payload_len, value_section,
|
|
error_buf, sizeof(error_buf), &consumed_len);
|
|
if (parse_success && consumed_len == payload_len) {
|
|
sections[current_section_index].parsed.value_section =
|
|
value_section;
|
|
}
|
|
else {
|
|
if (value_section) {
|
|
wasm_runtime_free(value_section);
|
|
}
|
|
if (error_buf[0]) {
|
|
LOG_DEBUG("Error parsing values section: %s\n",
|
|
error_buf);
|
|
}
|
|
if (consumed_len != payload_len) {
|
|
LOG_DEBUG("FATAL ERROR: Values section consumed %u "
|
|
"bytes but expected %lu\n",
|
|
consumed_len, payload_len);
|
|
wasm_runtime_free(sections);
|
|
return false;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
// Unknown/unsupported section id
|
|
LOG_DEBUG("FATAL ERROR: Unknown/unsupported section (id=%u, "
|
|
"size=%lu)\n",
|
|
section_id, payload_len);
|
|
wasm_runtime_free(sections);
|
|
return false;
|
|
}
|
|
|
|
// Advance the main parser by the consumed amount
|
|
p = payload_start + consumed_len;
|
|
|
|
// Safety check to ensure we don't go past the end
|
|
if (p > end) {
|
|
wasm_runtime_free(sections);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
out_component->sections = sections;
|
|
out_component->section_count = section_count;
|
|
return true;
|
|
}
|
|
|
|
// Check if Header is Component
|
|
bool
|
|
is_wasm_component(WASMHeader header)
|
|
{
|
|
if (header.magic != WASM_MAGIC_NUMBER
|
|
|| header.version != WASM_COMPONENT_VERSION
|
|
|| header.layer != WASM_COMPONENT_LAYER) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Main component free function
|
|
void
|
|
wasm_component_free(WASMComponent *component)
|
|
{
|
|
if (!component || !component->sections)
|
|
return;
|
|
|
|
for (uint32_t i = 0; i < component->section_count; ++i) {
|
|
WASMComponentSection *sec = &component->sections[i];
|
|
|
|
switch (sec->id) {
|
|
case WASM_COMP_SECTION_CORE_CUSTOM: // Section 0
|
|
wasm_component_free_core_custom_section(sec);
|
|
break;
|
|
|
|
case WASM_COMP_SECTION_CORE_MODULE: // Section 1
|
|
wasm_component_free_core_module_section(sec);
|
|
break;
|
|
|
|
case WASM_COMP_SECTION_CORE_INSTANCE: // Section 2
|
|
wasm_component_free_core_instance_section(sec);
|
|
break;
|
|
|
|
case WASM_COMP_SECTION_CORE_TYPE: // Section 3
|
|
wasm_component_free_core_type_section(sec);
|
|
break;
|
|
|
|
case WASM_COMP_SECTION_COMPONENT: // Section 4
|
|
wasm_component_free_component_section(sec);
|
|
break;
|
|
|
|
case WASM_COMP_SECTION_INSTANCES: // Section 5
|
|
wasm_component_free_instances_section(sec);
|
|
break;
|
|
|
|
case WASM_COMP_SECTION_ALIASES: // Section 6
|
|
wasm_component_free_alias_section(sec);
|
|
break;
|
|
|
|
case WASM_COMP_SECTION_TYPE: // Section 7
|
|
wasm_component_free_types_section(sec);
|
|
break;
|
|
|
|
case WASM_COMP_SECTION_CANONS: // Section 8
|
|
wasm_component_free_canons_section(sec);
|
|
break;
|
|
|
|
case WASM_COMP_SECTION_START: // Section 9
|
|
wasm_component_free_start_section(sec);
|
|
break;
|
|
|
|
case WASM_COMP_SECTION_IMPORTS: // Section 10
|
|
wasm_component_free_imports_section(sec);
|
|
break;
|
|
|
|
case WASM_COMP_SECTION_EXPORTS: // Section 11
|
|
wasm_component_free_exports_section(sec);
|
|
break;
|
|
|
|
case WASM_COMP_SECTION_VALUES: // Section 12
|
|
wasm_component_free_values_section(sec);
|
|
break;
|
|
|
|
default:
|
|
// For other sections that don't have parsed data or are stubs
|
|
// Just free the any pointer if it exists
|
|
if (sec->parsed.any) {
|
|
wasm_runtime_free(sec->parsed.any);
|
|
sec->parsed.any = NULL;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
wasm_runtime_free(component->sections);
|
|
component->sections = NULL;
|
|
component->section_count = 0;
|
|
} |