Add Component Model binary parser + validation

This commit is contained in:
Mihai Dimoiu 2026-03-25 14:53:51 +02:00
parent fcec30e933
commit 81cbeb2fd7
59 changed files with 12190 additions and 129 deletions

View File

@ -4,6 +4,12 @@
# Here is an explanation for why some of the checks are disabled: # Here is an explanation for why some of the checks are disabled:
# #
# -misc-include-cleaner: too noisy with platform abstraction headers
# -bugprone-easily-swappable-parameters: most C APIs have consecutive same-type params
# -bugprone-macro-parentheses: WAMR macros intentionally use unparenthesized args
# -misc-no-recursion: interpreter/validator use intentional recursion
# -readability-magic-numbers: wasm spec constants (opcodes, limits) are ubiquitous
#
Checks: > Checks: >
-*, -*,
@ -11,6 +17,9 @@ Checks: >
cert-*, cert-*,
clang-analyzer-*, clang-analyzer-*,
concurrency-*, concurrency-*,
cppcoreguidelines-init-variables,
cppcoreguidelines-narrowing-conversions,
cppcoreguidelines-pro-type-cstyle-cast,
misc-*, misc-*,
modernize-*, modernize-*,
performance-*, performance-*,
@ -18,6 +27,7 @@ Checks: >
readability-*, readability-*,
-bugprone-easily-swappable-parameters, -bugprone-easily-swappable-parameters,
-bugprone-macro-parentheses, -bugprone-macro-parentheses,
-misc-include-cleaner,
-misc-no-recursion, -misc-no-recursion,
-misc-unused-parameters, -misc-unused-parameters,
-readability-braces-around-statements, -readability-braces-around-statements,

1
.gitignore vendored
View File

@ -13,6 +13,7 @@
*.so *.so
.clangd .clangd
.DS_Store .DS_Store
code_analysis_report.log
*.o *.o
.aider* .aider*

View File

@ -79,6 +79,11 @@ if (NOT DEFINED WAMR_BUILD_LIBC_WASI)
set (WAMR_BUILD_LIBC_WASI 1) set (WAMR_BUILD_LIBC_WASI 1)
endif () endif ()
if (NOT DEFINED WAMR_BUILD_COMPONENT_MODEL)
# Enable Component Model by default
set (WAMR_BUILD_COMPONENT_MODEL 1)
endif ()
if (NOT DEFINED WAMR_BUILD_FAST_INTERP) if (NOT DEFINED WAMR_BUILD_FAST_INTERP)
# Enable fast interpreter # Enable fast interpreter
set (WAMR_BUILD_FAST_INTERP 1) set (WAMR_BUILD_FAST_INTERP 1)

View File

@ -779,7 +779,13 @@ if (WAMR_BUILD_BRANCH_HINTS EQUAL 1)
message (" Branch hints enabled") message (" Branch hints enabled")
add_definitions(-DWASM_ENABLE_BRANCH_HINTS=1) add_definitions(-DWASM_ENABLE_BRANCH_HINTS=1)
endif () endif ()
if (WAMR_BUILD_COMPONENT_MODEL EQUAL 1)
message (" Component Model enabled")
add_definitions(-DWASM_ENABLE_COMPONENT_MODEL=1)
else()
message (" Component Model disabled")
add_definitions(-DWASM_ENABLE_COMPONENT_MODEL=0)
endif ()
######################################## ########################################
# Show Phase4 Wasm proposals status. # Show Phase4 Wasm proposals status.
######################################## ########################################

View File

@ -87,6 +87,10 @@ if (WAMR_BUILD_GC EQUAL 1)
set (WAMR_BUILD_REF_TYPES 1) set (WAMR_BUILD_REF_TYPES 1)
endif () endif ()
if (WAMR_BUILD_COMPONENT_MODEL EQUAL 1)
include (${IWASM_DIR}/common/component-model/iwasm_component.cmake)
endif ()
if (WAMR_BUILD_LIBC_BUILTIN EQUAL 1) if (WAMR_BUILD_LIBC_BUILTIN EQUAL 1)
include (${IWASM_DIR}/libraries/libc-builtin/libc_builtin.cmake) include (${IWASM_DIR}/libraries/libc-builtin/libc_builtin.cmake)
endif () endif ()
@ -219,6 +223,7 @@ set (source_all
${IWASM_COMPL_SOURCE} ${IWASM_COMPL_SOURCE}
${IWASM_FAST_JIT_SOURCE} ${IWASM_FAST_JIT_SOURCE}
${IWASM_GC_SOURCE} ${IWASM_GC_SOURCE}
${IWASM_COMPONENT_SOURCE}
${LIB_WASI_THREADS_SOURCE} ${LIB_WASI_THREADS_SOURCE}
${LIB_PTHREAD_SOURCE} ${LIB_PTHREAD_SOURCE}
${THREAD_MGR_SOURCE} ${THREAD_MGR_SOURCE}

60
code_analysis.sh Executable file
View File

@ -0,0 +1,60 @@
#!/bin/sh
# Copyright (C) 2026 Airbus Defence and Space Romania SRL. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
# Prerequisites: clang-tidy and cppcheck (First time install: sudo apt-get update && sudo apt-get install -y clang-tidy cppcheck)
# Prerequisite for clang-tidy: CMAKE_EXPORT_COMPILE_COMMANDS=ON
rm -rf product-mini/platforms/linux/build && mkdir -p product-mini/platforms/linux/build
cd product-mini/platforms/linux/build
cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=ON && make -j8
cd ../../../../
# Define the target folders
TARGET_DIRS="core/iwasm/interpreter \
core/iwasm/common/component-model \
tests/unit/component*"
# Define the log report file
REPORT_FILE="code_analysis_report.log"
echo "--- Running code analysis for: $TARGET_DIRS"
echo "--- The analysis report will be written into $REPORT_FILE"
: > "$REPORT_FILE"
exec > "$REPORT_FILE" 2>&1
echo "--- Running Cppcheck ---"
cppcheck -q --force --enable=warning,performance,style,portability $TARGET_DIRS
echo "--- Running Clang-Tidy ---"
FILES=$(find $TARGET_DIRS -name "*.c")
HEADERS=$(find $TARGET_DIRS -name "*.h")
$(command -v /opt/wasi-sdk/bin/clang-tidy || echo clang-tidy) -p product-mini/platforms/linux/build --quiet $HEADERS $FILES
TOTAL=$(grep -c ': error:' "$REPORT_FILE" 2>/dev/null || echo 0)
printf "Total errors: $TOTAL"
for CHECK in \
bugprone-narrowing-conversions \
bugprone-multi-level-implicit-pointer-conversion \
bugprone-null-dereference \
bugprone-use-after-move \
bugprone-sizeof-expression \
clang-analyzer-core \
clang-analyzer-security \
clang-analyzer-deadcode \
cppcoreguidelines-init-variables \
cppcoreguidelines-narrowing-conversions \
performance-no-int-to-ptr \
readability-math-missing-parentheses \
concurrency-mt-unsafe \
cert-msc30-c \
cert-err34-c \
readability-redundant-casting; do
COUNT=$(grep -c "$CHECK" "$REPORT_FILE" 2>/dev/null || echo 0)
if [ "$COUNT" -gt 0 ]; then
printf ' %-56s %d\n' "$CHECK:" "$COUNT" | tee -a "$REPORT_FILE"
fi
done
echo "--- Analysis complete. Check $REPORT_FILE ---"

View File

@ -137,6 +137,10 @@
#define WASM_ENABLE_WAMR_COMPILER 0 #define WASM_ENABLE_WAMR_COMPILER 0
#endif #endif
#ifndef WASM_ENABLE_COMPONENT_MODEL
#define WASM_ENABLE_COMPONENT_MODEL 0
#endif
#ifndef WASM_ENABLE_LIBC_BUILTIN #ifndef WASM_ENABLE_LIBC_BUILTIN
#define WASM_ENABLE_LIBC_BUILTIN 0 #define WASM_ENABLE_LIBC_BUILTIN 0
#endif #endif

View File

@ -51,7 +51,11 @@ bh_static_assert(offsetof(AOTModuleInstance, cur_exception)
bh_static_assert(offsetof(AOTModuleInstance, c_api_func_imports) bh_static_assert(offsetof(AOTModuleInstance, c_api_func_imports)
== 13 * sizeof(uint64) + 128 + 7 * sizeof(uint64)); == 13 * sizeof(uint64) + 128 + 7 * sizeof(uint64));
bh_static_assert(offsetof(AOTModuleInstance, global_table_data) bh_static_assert(offsetof(AOTModuleInstance, global_table_data)
== 13 * sizeof(uint64) + 128 + 14 * sizeof(uint64)); == 13 * sizeof(uint64) + 128 + 14 * sizeof(uint64)
#if WASM_ENABLE_COMPONENT_MODEL != 0
+ sizeof(void *) + sizeof(uint64)
#endif
);
bh_static_assert(sizeof(AOTMemoryInstance) == 120); bh_static_assert(sizeof(AOTMemoryInstance) == 120);
bh_static_assert(offsetof(AOTTableInstance, elems) == 24); bh_static_assert(offsetof(AOTTableInstance, elems) == 24);

View File

@ -0,0 +1,12 @@
# Copyright (C) 2026 Airbus Defence and Space Romania SRL. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
set (IWASM_COMPONENT_DIR ${CMAKE_CURRENT_LIST_DIR})
add_definitions (-DWASM_ENABLE_COMPONENT_MODEL=1)
include_directories (${IWASM_COMPONENT_DIR})
file (GLOB source_all ${IWASM_COMPONENT_DIR}/*.c)
set (IWASM_COMPONENT_SOURCE ${source_all})

View File

@ -0,0 +1,486 @@
/*
* 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;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,183 @@
/*
* 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 <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>
bool parse_single_alias(const uint8_t **payload, const uint8_t *end, WASMComponentAliasDefinition *out, char *error_buf, uint32_t error_buf_size) {
const uint8_t *p = *payload;
out->sort = wasm_runtime_malloc(sizeof(WASMComponentSort));
if (!out->sort) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to allocate memory for alias sort");
return false;
}
// Parse the sort using the reusable parse_sort method
if (!parse_sort(&p, end, out->sort, error_buf, error_buf_size, false)) {
return false;
}
// Read tag
uint8_t tag = *p++;
// Parse alias target using switch
switch (tag) {
case WASM_COMP_ALIAS_TARGET_EXPORT: {
uint64_t instance_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &instance_idx, error_buf, error_buf_size)) {
return false;
}
WASMComponentCoreName *name = NULL;
if (!parse_core_name(&p, end, &name, error_buf, error_buf_size)) {
return false;
}
out->alias_target_type = WASM_COMP_ALIAS_TARGET_EXPORT;
out->target.exported.instance_idx = (uint32_t)instance_idx;
out->target.exported.name = name;
break;
}
case WASM_COMP_ALIAS_TARGET_CORE_EXPORT: {
uint64_t core_instance_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &core_instance_idx, error_buf, error_buf_size)) {
return false;
}
WASMComponentCoreName *core_name = NULL;
if (!parse_core_name(&p, end, &core_name, error_buf, error_buf_size)) {
return false;
}
out->alias_target_type = WASM_COMP_ALIAS_TARGET_CORE_EXPORT;
out->target.core_exported.instance_idx = (uint32_t)core_instance_idx;
out->target.core_exported.name = core_name;
break;
}
case WASM_COMP_ALIAS_TARGET_OUTER: {
uint64_t outer_ct = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &outer_ct, error_buf, error_buf_size)) {
return false;
}
uint64_t outer_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &outer_idx, error_buf, error_buf_size)) {
return false;
}
out->alias_target_type = WASM_COMP_ALIAS_TARGET_OUTER;
out->target.outer.ct = (uint32_t)outer_ct;
out->target.outer.idx = (uint32_t)outer_idx;
bool valid_outer_sort =
(out->sort->sort == WASM_COMP_SORT_TYPE)
|| (out->sort->sort == WASM_COMP_SORT_COMPONENT)
|| (out->sort->sort == WASM_COMP_SORT_CORE_SORT
&& out->sort->core_sort == WASM_COMP_CORE_SORT_MODULE);
if (!valid_outer_sort) {
set_error_buf_ex(error_buf, error_buf_size, "Outer alias sort must be type, component, or core module");
return false;
}
break;
}
default:
snprintf(error_buf, error_buf_size, "Unknown alias target type: 0x%02X", tag);
return false;
}
*payload = p;
return true;
}
// Section 6: alias section
bool wasm_component_parse_alias_section(const uint8_t **payload, uint32_t payload_len, WASMComponentAliasSection *out, char *error_buf, uint32_t error_buf_size, uint32_t *consumed_len) {
if (!payload || !*payload || payload_len == 0 || !out) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid payload or output pointer");
if (consumed_len) *consumed_len = 0;
return false;
}
const uint8_t *p = *payload;
const uint8_t *end = *payload + payload_len;
uint32_t alias_count = 0;
// Read alias count
uint64_t alias_count_leb = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &alias_count_leb, error_buf, error_buf_size)) {
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
alias_count = (uint32_t)alias_count_leb;
out->count = alias_count;
if (alias_count > 0) {
out->aliases = wasm_runtime_malloc(sizeof(WASMComponentAliasDefinition) * alias_count);
if (!out->aliases) {
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
// Zero-initialize the aliases array
memset(out->aliases, 0, sizeof(WASMComponentAliasDefinition) * alias_count);
for (uint32_t i = 0; i < alias_count; ++i) {
// Allocate memory for the sort field
if (!parse_single_alias(&p, end, &out->aliases[i], error_buf, error_buf_size)) {
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
set_error_buf_ex(error_buf, error_buf_size, "Failed to parse alias %d", i);
return false;
}
}
}
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
// If binaries use alias ids, this parser will need to be extended.
return true;
}
// Individual section free functions
void wasm_component_free_alias_section(WASMComponentSection *section) {
if (!section || !section->parsed.alias_section) return;
WASMComponentAliasSection *alias_sec = section->parsed.alias_section;
if (alias_sec->aliases) {
for (uint32_t j = 0; j < alias_sec->count; ++j) {
WASMComponentAliasDefinition *alias = &alias_sec->aliases[j];
// Free sort
if (alias->sort) {
wasm_runtime_free(alias->sort);
alias->sort = NULL;
}
// Free target-specific data
switch (alias->alias_target_type) {
case WASM_COMP_ALIAS_TARGET_EXPORT:
if (alias->target.exported.name) {
free_core_name(alias->target.exported.name);
wasm_runtime_free(alias->target.exported.name);
alias->target.exported.name = NULL;
}
break;
case WASM_COMP_ALIAS_TARGET_CORE_EXPORT:
if (alias->target.core_exported.name) {
free_core_name(alias->target.core_exported.name);
wasm_runtime_free(alias->target.core_exported.name);
alias->target.core_exported.name = NULL;
}
break;
case WASM_COMP_ALIAS_TARGET_OUTER:
// No dynamic allocations for outer aliases
break;
}
}
wasm_runtime_free(alias_sec->aliases);
alias_sec->aliases = NULL;
}
wasm_runtime_free(alias_sec);
section->parsed.alias_section = NULL;
}

View File

@ -0,0 +1,850 @@
/*
* 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 <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>
// Local helpers to free nested allocations safely
static void free_canon_opts_struct(WASMComponentCanonOpts *opts) {
if (!opts) return;
if (opts->canon_opts) {
wasm_runtime_free(opts->canon_opts);
opts->canon_opts = NULL;
opts->canon_opts_count = 0;
}
wasm_runtime_free(opts);
}
static void free_result_list_struct(WASMComponentResultList *rl) {
if (!rl) return;
if (rl->tag == WASM_COMP_RESULT_LIST_WITH_TYPE && rl->results) {
wasm_runtime_free(rl->results);
rl->results = NULL;
}
wasm_runtime_free(rl);
}
static void free_single_canon_allocs(WASMComponentCanon *canon) {
if (!canon) return;
switch (canon->tag) {
case WASM_COMP_CANON_LIFT:
if (canon->canon_data.lift.canon_opts) {
free_canon_opts_struct(canon->canon_data.lift.canon_opts);
canon->canon_data.lift.canon_opts = NULL;
}
break;
case WASM_COMP_CANON_LOWER:
if (canon->canon_data.lower.canon_opts) {
free_canon_opts_struct(canon->canon_data.lower.canon_opts);
canon->canon_data.lower.canon_opts = NULL;
}
break;
case WASM_COMP_CANON_TASK_RETURN:
if (canon->canon_data.task_return.result_list) {
free_result_list_struct(canon->canon_data.task_return.result_list);
canon->canon_data.task_return.result_list = NULL;
}
if (canon->canon_data.task_return.canon_opts) {
free_canon_opts_struct(canon->canon_data.task_return.canon_opts);
canon->canon_data.task_return.canon_opts = NULL;
}
break;
case WASM_COMP_CANON_STREAM_READ:
case WASM_COMP_CANON_STREAM_WRITE:
if (canon->canon_data.stream_read_write.canon_opts) {
free_canon_opts_struct(canon->canon_data.stream_read_write.canon_opts);
canon->canon_data.stream_read_write.canon_opts = NULL;
}
break;
case WASM_COMP_CANON_FUTURE_READ:
case WASM_COMP_CANON_FUTURE_WRITE:
if (canon->canon_data.future_read_write.canon_opts) {
free_canon_opts_struct(canon->canon_data.future_read_write.canon_opts);
canon->canon_data.future_read_write.canon_opts = NULL;
}
break;
case WASM_COMP_CANON_ERROR_CONTEXT_NEW:
case WASM_COMP_CANON_ERROR_CONTEXT_DEBUG:
if (canon->canon_data.error_context_new_debug.canon_opts) {
free_canon_opts_struct(canon->canon_data.error_context_new_debug.canon_opts);
canon->canon_data.error_context_new_debug.canon_opts = NULL;
}
break;
default:
break;
}
}
// Parse single canon option
static bool parse_canon_opt(const uint8_t **payload, const uint8_t *end, WASMComponentCanonOpt *out, char *error_buf, uint32_t error_buf_size) {
const uint8_t *p = *payload;
uint8_t tag = *p++;
out->tag = tag;
switch (tag) {
case WASM_COMP_CANON_OPT_STRING_UTF8: // string-encoding=utf8 - 0x00
case WASM_COMP_CANON_OPT_STRING_UTF16: // string-encoding=utf16 - 0x01
case WASM_COMP_CANON_OPT_STRING_LATIN1_UTF16: // string-encoding=latin1+utf16 - 0x02
break;
case WASM_COMP_CANON_OPT_MEMORY: { // (memory m) - 0x03
uint64_t core_mem_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &core_mem_idx, error_buf, error_buf_size)) {
return false;
}
out->payload.memory.mem_idx = (uint32_t)core_mem_idx;
break;
}
case WASM_COMP_CANON_OPT_REALLOC: { // (realloc f) - 0x04
uint64_t core_func_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &core_func_idx, error_buf, error_buf_size)) {
return false;
}
out->payload.realloc_opt.func_idx = (uint32_t)core_func_idx;
break;
}
case WASM_COMP_CANON_OPT_POST_RETURN: { // (post-return f) - 0x05
uint64_t core_func_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &core_func_idx, error_buf, error_buf_size)) {
return false;
}
out->payload.post_return.func_idx = (uint32_t)core_func_idx;
break;
}
case WASM_COMP_CANON_OPT_ASYNC: { // async - 0x06
break;
}
case WASM_COMP_CANON_OPT_CALLBACK: { // (callback f) - 0x07
uint64_t core_func_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &core_func_idx, error_buf, error_buf_size)) {
return false;
}
out->payload.callback.func_idx = (uint32_t)core_func_idx;
break;
}
default: {
set_error_buf_ex(error_buf, error_buf_size, "Invalid canon opt tag: %02x", tag);
return false;
}
}
*payload = p;
return true;
}
// Parsing canon options
static bool parse_canon_opts(const uint8_t **payload, const uint8_t *end, WASMComponentCanonOpts **out, char *error_buf, uint32_t error_buf_size) {
if (!payload || !*payload || !out || !end) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid payload or output pointer");
return false;
}
const uint8_t *p = *payload;
*out = wasm_runtime_malloc(sizeof(WASMComponentCanonOpts));
if (!*out) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to allocate memory for canon opts");
return false;
}
uint64_t canon_opts_count = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &canon_opts_count, error_buf, error_buf_size)) {
free_canon_opts_struct(*out);
*out = NULL;
return false;
}
(*out)->canon_opts_count = (uint32_t)canon_opts_count;
if (canon_opts_count > 0) {
(*out)->canon_opts = wasm_runtime_malloc(sizeof(WASMComponentCanonOpt) * canon_opts_count);
if (!(*out)->canon_opts) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to allocate memory for canon opts");
free_canon_opts_struct(*out);
*out = NULL;
return false;
}
for (uint64_t i = 0; i < canon_opts_count; i++) {
if (!parse_canon_opt(&p, end, &(*out)->canon_opts[i], error_buf, error_buf_size)) {
free_canon_opts_struct(*out);
*out = NULL;
return false;
}
}
} else {
(*out)->canon_opts = NULL;
}
bool has_string_encoding = false;
uint8_t seen_bits = 0; /* bits 0..4 for tags 0x03..0x07 */
for (uint32_t i = 0; i < (uint32_t)canon_opts_count; i++) {
uint8_t t = (*out)->canon_opts[i].tag;
if (t == WASM_COMP_CANON_OPT_STRING_UTF8
|| t == WASM_COMP_CANON_OPT_STRING_UTF16
|| t == WASM_COMP_CANON_OPT_STRING_LATIN1_UTF16) {
if (has_string_encoding) {
set_error_buf_ex(error_buf, error_buf_size, "Conflicting or duplicate string-encoding canonopt");
free_canon_opts_struct(*out);
*out = NULL;
return false;
}
has_string_encoding = true;
} else {
uint8_t bit = (uint8_t)(1u << (t - WASM_COMP_CANON_OPT_MEMORY));
if (seen_bits & bit) {
set_error_buf_ex(error_buf, error_buf_size, "Duplicate canonopt: 0x%02x", t);
free_canon_opts_struct(*out);
*out = NULL;
return false;
}
seen_bits |= bit;
}
}
*payload = p;
return true;
}
// Parsing single canon
static bool parse_single_canon(const uint8_t **payload, const uint8_t *end, WASMComponentCanon *out, char *error_buf, uint32_t error_buf_size) {
const uint8_t *p = *payload;
uint8_t tag = *p++;
out->tag = tag;
switch (tag) {
case WASM_COMP_CANON_LIFT: { // 0x00 0x00 f:<core:funcidx> opts:<opts> ft:<typeidx>
if (*p != 0x00) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid canon tag: %02x", tag);
return false;
}
p++;
// Read core:funcidx
uint64_t core_func_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &core_func_idx, error_buf, error_buf_size)) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to read core func idx");
return false;
}
out->canon_data.lift.core_func_idx = (uint32_t)core_func_idx;
// Read canon opts
if (!parse_canon_opts(&p, end, &out->canon_data.lift.canon_opts, error_buf, error_buf_size)) {
return false;
}
// Read typeidx
uint64_t type_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &type_idx, error_buf, error_buf_size)) {
// cleanup previously allocated opts
if (out->canon_data.lift.canon_opts) {
free_canon_opts_struct(out->canon_data.lift.canon_opts);
out->canon_data.lift.canon_opts = NULL;
}
return false;
}
out->canon_data.lift.type_idx = (uint32_t)type_idx;
break;
}
case WASM_COMP_CANON_LOWER: { // 0x01 0x00 f:<funcidx> opts:<opts>
if (*p != 0x00) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid canon tag: %02x", tag);
return false;
}
p++;
// Read funcidx
uint64_t func_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &func_idx, error_buf, error_buf_size)) {
return false;
}
out->canon_data.lower.func_idx = (uint32_t)func_idx;
// Read canon opts
if (!parse_canon_opts(&p, end, &out->canon_data.lower.canon_opts, error_buf, error_buf_size)) {
return false;
}
break;
}
case WASM_COMP_CANON_RESOURCE_NEW: { // 0x02 rt:<typeidx>
uint64_t type_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &type_idx, error_buf, error_buf_size)) {
return false;
}
out->canon_data.resource_new.resource_type_idx = (uint32_t)type_idx;
break;
}
case WASM_COMP_CANON_RESOURCE_DROP: { // 0x03 rt:<typeidx>
uint64_t type_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &type_idx, error_buf, error_buf_size)) {
return false;
}
out->canon_data.resource_drop.resource_type_idx = (uint32_t)type_idx;
out->canon_data.resource_drop.async = false;
break;
}
case WASM_COMP_CANON_RESOURCE_DROP_ASYNC: { //0x07 rt:<typeidx>
uint64_t type_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &type_idx, error_buf, error_buf_size)) {
return false;
}
out->canon_data.resource_drop.resource_type_idx = (uint32_t)type_idx;
out->canon_data.resource_drop.async = true;
break;
}
case WASM_COMP_CANON_RESOURCE_REP: { // 0x04 rt:<typeidx>
uint64_t type_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &type_idx, error_buf, error_buf_size)) {
return false;
}
out->canon_data.resource_rep.resource_type_idx = (uint32_t)type_idx;
break;
}
case WASM_COMP_CANON_BACKPRESSURE_SET: { //0x08
break;
}
case WASM_COMP_CANON_TASK_RETURN: { // 0x09 rs:<result_list> opts:<opts>
if (!parse_result_list(&p, end, &out->canon_data.task_return.result_list, error_buf, error_buf_size)) {
// Best-effort cleanup if result_list was set
if (out->canon_data.task_return.result_list) {
free_result_list_struct(out->canon_data.task_return.result_list);
out->canon_data.task_return.result_list = NULL;
}
return false;
}
if (!parse_canon_opts(&p, end, &out->canon_data.task_return.canon_opts, error_buf, error_buf_size)) {
// cleanup result_list allocated above before failing
if (out->canon_data.task_return.result_list) {
free_result_list_struct(out->canon_data.task_return.result_list);
out->canon_data.task_return.result_list = NULL;
}
return false;
}
break;
}
case WASM_COMP_CANON_TASK_CANCEL: { // 0x05 (no parameters)
break;
}
case WASM_COMP_CANON_CONTEXT_GET: { // 0x0a 0x7f i:<u32>
if (*p != 0x7f) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid canon tag: %02x", tag);
return false;
}
p++;
uint64_t i = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &i, error_buf, error_buf_size)) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to read context idx");
return false;
}
out->canon_data.context_get_set.context_idx = (uint32_t)i;
break;
}
case WASM_COMP_CANON_CONTEXT_SET: { // 0x0b 0x7f i:<u32>
if (*p != 0x7f) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid canon tag: %02x", tag);
return false;
}
p++;
uint64_t i = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &i, error_buf, error_buf_size)) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to read context idx");
return false;
}
out->canon_data.context_get_set.context_idx = (uint32_t)i;
break;
}
case WASM_COMP_CANON_YIELD: { // 0x0c cancel?:<cancel?>
uint8_t b = *p++;
if (b == WASM_COMP_OPTIONAL_TRUE) {
out->canon_data.yield.cancellable = true;
} else if (b == WASM_COMP_OPTIONAL_FALSE) {
out->canon_data.yield.cancellable = false;
} else {
set_error_buf_ex(error_buf, error_buf_size, "Invalid cancel? tag: %02x", b);
return false;
}
break;
}
case WASM_COMP_CANON_SUBTASK_CANCEL: { // 0x06 async?:<async?>
uint8_t b = *p++;
if (b == WASM_COMP_OPTIONAL_TRUE) {
out->canon_data.subtask_cancel.async = true;
} else if (b == WASM_COMP_OPTIONAL_FALSE) {
out->canon_data.subtask_cancel.async = false;
} else {
set_error_buf_ex(error_buf, error_buf_size, "Invalid async? tag: %02x", b);
return false;
}
break;
}
case WASM_COMP_CANON_SUBTASK_DROP: { // 0x0d
break;
}
case WASM_COMP_CANON_STREAM_NEW: { // 0x0e t:<typeidx>
uint64_t type_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &type_idx, error_buf, error_buf_size)) {
return false;
}
out->canon_data.stream_new.stream_type_idx = (uint32_t)type_idx;
break;
}
case WASM_COMP_CANON_STREAM_READ: { // 0x0f t:<typeidx> opts:<opts>
// Read stream type idx
uint64_t type_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &type_idx, error_buf, error_buf_size)) {
return false;
}
out->canon_data.stream_read_write.stream_type_idx = (uint32_t)type_idx;
// Read canon opts
if (!parse_canon_opts(&p, end, &out->canon_data.stream_read_write.canon_opts, error_buf, error_buf_size)) {
return false;
}
break;
}
case WASM_COMP_CANON_STREAM_WRITE: { // 0x10 t:<typeidx> opts:<opts>
// Read stream type idx
uint64_t type_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &type_idx, error_buf, error_buf_size)) {
return false;
}
out->canon_data.stream_read_write.stream_type_idx = (uint32_t)type_idx;
// Read canon opts
if (!parse_canon_opts(&p, end, &out->canon_data.stream_read_write.canon_opts, error_buf, error_buf_size)) {
return false;
}
break;
}
case WASM_COMP_CANON_STREAM_CANCEL_READ: { // 0x11 t:<typeidx> async?:<async?>
uint64_t type_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &type_idx, error_buf, error_buf_size)) {
return false;
}
out->canon_data.stream_cancel_read_write.stream_type_idx = (uint32_t)type_idx;
uint8_t b = *p++;
if (b == WASM_COMP_OPTIONAL_TRUE) {
out->canon_data.stream_cancel_read_write.async = true;
} else if (b == WASM_COMP_OPTIONAL_FALSE) {
out->canon_data.stream_cancel_read_write.async = false;
} else {
set_error_buf_ex(error_buf, error_buf_size, "Invalid async? tag: %02x", b);
return false;
}
break;
}
case WASM_COMP_CANON_STREAM_CANCEL_WRITE: { // 0x12 t:<typeidx> async?:<async?>
uint64_t type_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &type_idx, error_buf, error_buf_size)) {
return false;
}
out->canon_data.stream_cancel_read_write.stream_type_idx = (uint32_t)type_idx;
uint8_t b = *p++;
if (b == WASM_COMP_OPTIONAL_TRUE) {
out->canon_data.stream_cancel_read_write.async = true;
} else if (b == WASM_COMP_OPTIONAL_FALSE) {
out->canon_data.stream_cancel_read_write.async = false;
} else {
set_error_buf_ex(error_buf, error_buf_size, "Invalid async? tag: %02x", b);
return false;
}
break;
}
case WASM_COMP_CANON_STREAM_DROP_READABLE: { // 0x13 t:<typeidx>
uint64_t type_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &type_idx, error_buf, error_buf_size)) {
return false;
}
out->canon_data.stream_drop_readable_writable.stream_type_idx = (uint32_t)type_idx;
break;
}
case WASM_COMP_CANON_STREAM_DROP_WRITABLE: { // 0x14 t:<typeidx>
uint64_t type_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &type_idx, error_buf, error_buf_size)) {
return false;
}
out->canon_data.stream_drop_readable_writable.stream_type_idx = (uint32_t)type_idx;
break;
}
case WASM_COMP_CANON_FUTURE_NEW: { // 0x15 t:<typeidx>
uint64_t type_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &type_idx, error_buf, error_buf_size)) {
return false;
}
out->canon_data.future_new.future_type_idx = (uint32_t)type_idx;
break;
}
case WASM_COMP_CANON_FUTURE_READ: { // 0x16 t:<typeidx> opts:<opts>
uint64_t type_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &type_idx, error_buf, error_buf_size)) {
return false;
}
out->canon_data.future_read_write.future_type_idx = (uint32_t)type_idx;
if (!parse_canon_opts(&p, end, &out->canon_data.future_read_write.canon_opts, error_buf, error_buf_size)) {
return false;
}
break;
}
case WASM_COMP_CANON_FUTURE_WRITE: { // 0x17 t:<typeidx> opts:<opts>
uint64_t type_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &type_idx, error_buf, error_buf_size)) {
return false;
}
out->canon_data.future_read_write.future_type_idx = (uint32_t)type_idx;
if (!parse_canon_opts(&p, end, &out->canon_data.future_read_write.canon_opts, error_buf, error_buf_size)) {
return false;
}
break;
}
case WASM_COMP_CANON_FUTURE_CANCEL_READ: { // 0x18 t:<typeidx> async?:<async?>
uint64_t type_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &type_idx, error_buf, error_buf_size)) {
return false;
}
out->canon_data.future_cancel_read_write.future_type_idx = (uint32_t)type_idx;
uint8_t b = *p++;
if (b == WASM_COMP_OPTIONAL_TRUE) {
out->canon_data.future_cancel_read_write.async = true;
} else if (b == WASM_COMP_OPTIONAL_FALSE) {
out->canon_data.future_cancel_read_write.async = false;
} else {
set_error_buf_ex(error_buf, error_buf_size, "Invalid async? tag: %02x", b);
return false;
}
break;
}
case WASM_COMP_CANON_FUTURE_CANCEL_WRITE: { // 0x19 t:<typeidx> async?:<async?>
uint64_t type_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &type_idx, error_buf, error_buf_size)) {
return false;
}
out->canon_data.future_cancel_read_write.future_type_idx = (uint32_t)type_idx;
uint8_t b = *p++;
if (b == WASM_COMP_OPTIONAL_TRUE) {
out->canon_data.future_cancel_read_write.async = true;
} else if (b == WASM_COMP_OPTIONAL_FALSE) {
out->canon_data.future_cancel_read_write.async = false;
} else {
set_error_buf_ex(error_buf, error_buf_size, "Invalid async? tag: %02x", b);
return false;
}
break;
}
case WASM_COMP_CANON_FUTURE_DROP_READABLE: { // 0x1a t:<typeidx>
uint64_t type_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &type_idx, error_buf, error_buf_size)) {
return false;
}
out->canon_data.future_drop_readable_writable.future_type_idx = (uint32_t)type_idx;
break;
}
case WASM_COMP_CANON_FUTURE_DROP_WRITABLE: { // 0x1b t:<typeidx>
uint64_t type_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &type_idx, error_buf, error_buf_size)) {
return false;
}
out->canon_data.future_drop_readable_writable.future_type_idx = (uint32_t)type_idx;
break;
}
case WASM_COMP_CANON_ERROR_CONTEXT_NEW: // 0x1c opts:<opts>
case WASM_COMP_CANON_ERROR_CONTEXT_DEBUG: { // 0x1d opts:<opts>
if (!parse_canon_opts(&p, end, &out->canon_data.error_context_new_debug.canon_opts, error_buf, error_buf_size)) {
return false;
}
break;
}
case WASM_COMP_CANON_ERROR_CONTEXT_DROP: // 0x1e (no parameters)
case WASM_COMP_CANON_WAITABLE_SET_NEW: { // 0x1f (no parameters)
break;
}
case WASM_COMP_CANON_WAITABLE_SET_WAIT: { // 0x20 cancel?:<cancel?> m:<core:memidx>
uint8_t b = *p++;
if (b == WASM_COMP_OPTIONAL_TRUE) {
out->canon_data.waitable_set_wait_poll.cancellable = true;
} else if (b == WASM_COMP_OPTIONAL_FALSE) {
out->canon_data.waitable_set_wait_poll.cancellable = false;
} else {
set_error_buf_ex(error_buf, error_buf_size, "Invalid cancel? tag: %02x", b);
return false;
}
uint64_t core_mem_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &core_mem_idx, error_buf, error_buf_size)) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to read core mem idx");
return false;
}
out->canon_data.waitable_set_wait_poll.mem_idx = (uint32_t)core_mem_idx;
break;
}
case WASM_COMP_CANON_WAITABLE_SET_POLL: { //0x21 cancel?:<cancel?> m:<core:memidx>
uint8_t b = *p++;
if (b == WASM_COMP_OPTIONAL_TRUE) {
out->canon_data.waitable_set_wait_poll.cancellable = true;
} else if (b == WASM_COMP_OPTIONAL_FALSE) {
out->canon_data.waitable_set_wait_poll.cancellable = false;
} else {
set_error_buf_ex(error_buf, error_buf_size, "Invalid cancel? tag: %02x", b);
return false;
}
uint64_t core_mem_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &core_mem_idx, error_buf, error_buf_size)) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to read core mem idx");
return false;
}
out->canon_data.waitable_set_wait_poll.mem_idx = (uint32_t)core_mem_idx;
break;
}
case WASM_COMP_CANON_WAITABLE_SET_DROP: // 0x22 (no parameters)
case WASM_COMP_CANON_WAITABLE_JOIN: { // 0x23 (no parameters)
break;
}
case WASM_COMP_CANON_THREAD_SPAWN_REF: { // 0x40 ft:<typeidx>
uint64_t func_type_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &func_type_idx, error_buf, error_buf_size)) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to read func type idx");
return false;
}
out->canon_data.thread_spawn_ref.func_type_idx = (uint32_t)func_type_idx;
break;
}
case WASM_COMP_CANON_THREAD_SPAWN_INDIRECT: { //0x41 ft:<typeidx> tbl:<core:tableidx>
uint64_t func_type_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &func_type_idx, error_buf, error_buf_size)) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to read func type idx");
return false;
}
out->canon_data.thread_spawn_indirect.func_type_idx = (uint32_t)func_type_idx;
uint64_t core_table_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &core_table_idx, error_buf, error_buf_size)) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to read core table idx");
return false;
}
out->canon_data.thread_spawn_indirect.table_idx = (uint32_t)core_table_idx;
break;
}
case WASM_COMP_CANON_THREAD_AVAILABLE_PAR: { // 0x42 (no parameters)
break;
}
default: {
set_error_buf_ex(error_buf, error_buf_size, "Invalid canon tag: %02x", tag);
return false;
}
}
*payload = p;
return true;
}
// Section 8: canons (canonical function definitions) section
bool wasm_component_parse_canons_section(const uint8_t **payload, uint32_t payload_len, WASMComponentCanonSection *out, char *error_buf, uint32_t error_buf_size, uint32_t *consumed_len) {
if (!payload || !*payload || payload_len == 0 || !out) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid payload or output pointer");
if (consumed_len) *consumed_len = 0;
return false;
}
const uint8_t *p = *payload;
const uint8_t *end = *payload + payload_len;
uint64_t canon_count = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &canon_count, error_buf, error_buf_size)) {
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
out->count = (uint32_t)canon_count;
if (canon_count > 0) {
out->canons = wasm_runtime_malloc(sizeof(WASMComponentCanon) * canon_count);
if (!out->canons) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to allocate memory for canons");
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
// Initialize all canons to zero to avoid garbage data
memset(out->canons, 0, sizeof(WASMComponentCanon) * canon_count);
for (uint32_t i = 0; i < canon_count; ++i) {
// Check bounds before reading tag
if (p >= end) {
set_error_buf_ex(error_buf, error_buf_size, "Buffer overflow when reading canon tag");
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
if (!parse_single_canon(&p, end, &out->canons[i], error_buf, error_buf_size)) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to parse canon");
// Free previously parsed canons to avoid leaks
for (uint32_t j = 0; j < i; ++j) {
free_single_canon_allocs(&out->canons[j]);
}
wasm_runtime_free(out->canons);
out->canons = NULL;
out->count = 0;
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
}
}
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return true;
}
// Individual section free functions
void wasm_component_free_canons_section(WASMComponentSection *section) {
if (!section || !section->parsed.canon_section || !section->parsed.canon_section->canons) {
return;
}
WASMComponentCanonSection *canons_section = section->parsed.canon_section;
for (uint32_t i = 0; i < canons_section->count; i++) {
WASMComponentCanon *canon = &canons_section->canons[i];
// Free canon options for each canon that has them
switch (canon->tag) {
case WASM_COMP_CANON_LIFT:
if (canon->canon_data.lift.canon_opts) {
if (canon->canon_data.lift.canon_opts->canon_opts) {
wasm_runtime_free(canon->canon_data.lift.canon_opts->canon_opts);
}
wasm_runtime_free(canon->canon_data.lift.canon_opts);
}
break;
case WASM_COMP_CANON_LOWER:
if (canon->canon_data.lower.canon_opts) {
if (canon->canon_data.lower.canon_opts->canon_opts) {
wasm_runtime_free(canon->canon_data.lower.canon_opts->canon_opts);
}
wasm_runtime_free(canon->canon_data.lower.canon_opts);
}
break;
case WASM_COMP_CANON_TASK_RETURN:
if (canon->canon_data.task_return.result_list) {
if (canon->canon_data.task_return.result_list->results) {
wasm_runtime_free(canon->canon_data.task_return.result_list->results);
}
wasm_runtime_free(canon->canon_data.task_return.result_list);
}
if (canon->canon_data.task_return.canon_opts) {
if (canon->canon_data.task_return.canon_opts->canon_opts) {
wasm_runtime_free(canon->canon_data.task_return.canon_opts->canon_opts);
}
wasm_runtime_free(canon->canon_data.task_return.canon_opts);
}
break;
case WASM_COMP_CANON_STREAM_READ:
case WASM_COMP_CANON_STREAM_WRITE:
if (canon->canon_data.stream_read_write.canon_opts) {
if (canon->canon_data.stream_read_write.canon_opts->canon_opts) {
wasm_runtime_free(canon->canon_data.stream_read_write.canon_opts->canon_opts);
}
wasm_runtime_free(canon->canon_data.stream_read_write.canon_opts);
}
break;
case WASM_COMP_CANON_FUTURE_READ:
case WASM_COMP_CANON_FUTURE_WRITE:
if (canon->canon_data.future_read_write.canon_opts) {
if (canon->canon_data.future_read_write.canon_opts->canon_opts) {
wasm_runtime_free(canon->canon_data.future_read_write.canon_opts->canon_opts);
}
wasm_runtime_free(canon->canon_data.future_read_write.canon_opts);
}
break;
case WASM_COMP_CANON_ERROR_CONTEXT_NEW:
case WASM_COMP_CANON_ERROR_CONTEXT_DEBUG:
if (canon->canon_data.error_context_new_debug.canon_opts) {
if (canon->canon_data.error_context_new_debug.canon_opts->canon_opts) {
wasm_runtime_free(canon->canon_data.error_context_new_debug.canon_opts->canon_opts);
}
wasm_runtime_free(canon->canon_data.error_context_new_debug.canon_opts);
}
break;
default:
// Other canon types don't have nested allocations
break;
}
}
// Free the canons array itself
wasm_runtime_free(canons_section->canons);
canons_section->canons = NULL;
canons_section->count = 0;
// Free the section struct and null the pointer for consistency with other sections
wasm_runtime_free(canons_section);
section->parsed.canon_section = NULL;
}

View File

@ -0,0 +1,51 @@
/*
* 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 <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>
// Section 4: component section
bool wasm_component_parse_component_section(const uint8_t **payload, uint32_t payload_len, WASMComponent *out, char *error_buf, uint32_t error_buf_size, LoadArgs *args, unsigned int depth, uint32_t *consumed_len) {
if (consumed_len) *consumed_len = 0;
if (!payload || !*payload || payload_len == 0 || !out) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid payload or output pointer");
return false;
}
// Check depth limit BEFORE recursive call
if (depth >= MAX_DEPTH_RECURSION) {
set_error_buf_ex(error_buf, error_buf_size, "Max depth of recursion for parsing component reached: %d", depth);
return false;
}
// Increment depth BEFORE recursive call
unsigned int new_depth = depth + 1;
// Parse the nested component with incremented depth
bool status = wasm_component_parse_sections(*payload, payload_len, out, args, new_depth);
if (!status) {
set_error_buf_ex(error_buf, error_buf_size, "Could not parse sub component with depth: %d", new_depth);
return false;
}
if (consumed_len) *consumed_len = payload_len;
return true;
}
// Individual section free functions
void wasm_component_free_component_section(WASMComponentSection *section) {
if (!section || !section->parsed.component) return;
// Recursively free nested components
wasm_component_free(section->parsed.component);
wasm_runtime_free(section->parsed.component);
section->parsed.component = NULL;
}

View File

@ -0,0 +1,100 @@
/*
* 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 <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include "wasm_loader_common.h"
#include "wasm_runtime_common.h"
#include "../interpreter/wasm_runtime.h"
#include "wasm_export.h"
#include <stdio.h>
// Section 0: custom section
bool wasm_component_parse_core_custom_section(const uint8_t **payload, uint32_t payload_len, WASMComponentCoreCustomSection *out, char *error_buf, uint32_t error_buf_size, uint32_t *consumed_len) {
if (out) {
// Zero-initialize the output struct
memset(out, 0, sizeof(WASMComponentCoreCustomSection));
}
if (consumed_len) *consumed_len = 0;
if (!payload || !*payload || payload_len == 0 || !out) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid payload or output pointer");
return false;
}
const uint8_t *p = *payload;
const uint8_t *end = *payload + payload_len;
uint32_t name_len = 0;
// Check bounds
if (p >= end) {
set_error_buf_ex(error_buf, error_buf_size, "unexpected end");
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
// Read name length, validate, and copy name
uint64_t name_len_leb = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &name_len_leb, error_buf, error_buf_size)) {
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
name_len = (uint32_t)name_len_leb;
// Validate name length bounds
if (name_len == 0) {
set_error_buf_ex(error_buf, error_buf_size, "Custom section name cannot be empty");
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
if (p + name_len > end) {
set_error_buf_ex(error_buf, error_buf_size, "unexpected end");
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
// UTF-8 validation (reuse the same logic as load_user_section)
if (!wasm_check_utf8_str(p, name_len)) {
set_error_buf_ex(error_buf, error_buf_size, "invalid UTF-8 encoding");
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
// Allocate and copy the section name
out->name = (char *)wasm_runtime_malloc(name_len + 1);
if (!out->name) {
set_error_buf_ex(error_buf, error_buf_size, "Memory allocation failed for custom section name");
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
memcpy(out->name, p, name_len);
out->name[name_len] = '\0';
p += name_len;
// Set the data pointer and length
out->data = p;
out->data_len = (uint32_t)(end - p);
// Calculate consumed length
if (consumed_len) {
*consumed_len = (uint32_t)(p - *payload) + out->data_len;
}
return true;
}
// Individual section free functions
void wasm_component_free_core_custom_section(WASMComponentSection *section) {
if (!section || !section->parsed.core_custom) return;
if (section->parsed.core_custom->name) {
wasm_runtime_free(section->parsed.core_custom->name);
section->parsed.core_custom->name = NULL;
}
wasm_runtime_free(section->parsed.core_custom);
section->parsed.core_custom = NULL;
}

View File

@ -0,0 +1,286 @@
/*
* 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 <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>
// Section 2: core:instance ::= ie:<core:instanceexpr> => (instance ie)
// core:instanceexpr ::= 0x00 m:<moduleidx> arg*:vec(<core:instantiatearg>) => (instantiate m arg*)
// core:instantiatearg ::= n:<core:name> 0x12 i:<instanceidx> => (with n (instance i))
bool wasm_component_parse_core_instance_section(const uint8_t **payload, uint32_t payload_len, WASMComponentCoreInstSection *out, char *error_buf, uint32_t error_buf_size, uint32_t *consumed_len) {
if (!payload || !*payload || payload_len == 0 || !out) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid payload or output pointer");
if (consumed_len) *consumed_len = 0;
return false;
}
const uint8_t *p = *payload;
const uint8_t *end = *payload + payload_len;
uint64_t instance_count = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &instance_count, error_buf, error_buf_size)) {
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
out->count = (uint32_t)instance_count;
if (instance_count > 0) {
out->instances = wasm_runtime_malloc(sizeof(WASMComponentCoreInst) * instance_count);
if (!out->instances) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to allocate memory for core instances");
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
// Initialize all instances to zero to avoid garbage data
memset(out->instances, 0, sizeof(WASMComponentCoreInst) * instance_count);
for (uint32_t i = 0; i < instance_count; ++i) {
// Check bounds before reading tag
if (p >= end) {
set_error_buf_ex(error_buf, error_buf_size, "Buffer overflow when reading instance tag");
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
uint8_t tag = *p++;
out->instances[i].instance_expression_tag = tag;
switch (tag) {
case WASM_COMP_INSTANCE_EXPRESSION_WITH_ARGS: {
// 0x00 m:<moduleidx> arg*:vec(<core:instantiatearg>)
uint64_t module_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &module_idx, error_buf, error_buf_size)) {
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
out->instances[i].expression.with_args.idx = (uint32_t)module_idx;
uint64_t arg_len = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &arg_len, error_buf, error_buf_size)) {
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
out->instances[i].expression.with_args.arg_len = (uint32_t)arg_len;
if (arg_len > 0) {
out->instances[i].expression.with_args.args = wasm_runtime_malloc(sizeof(WASMComponentInstArg) * arg_len);
if (!out->instances[i].expression.with_args.args) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to allocate memory for core instantiate args");
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
// Initialize args to zero
memset(out->instances[i].expression.with_args.args, 0, sizeof(WASMComponentInstArg) * arg_len);
for (uint32_t j = 0; j < arg_len; ++j) {
// core:instantiatearg ::= n:<core:name> 0x12 i:<instanceidx>
// Parse core:name (LEB128 length + UTF-8 bytes)
// Check bounds before parsing name
if (p >= end) {
set_error_buf_ex(error_buf, error_buf_size, "Buffer overflow when parsing core name");
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
WASMComponentCoreName *core_name = NULL;
if (!parse_core_name(&p, end, &core_name, error_buf, error_buf_size)) {
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
// Store the name in the instantiate arg structure
out->instances[i].expression.with_args.args[j].name = core_name;
// Check bounds before reading 0x12
if (p >= end) {
set_error_buf_ex(error_buf, error_buf_size, "Buffer overflow when reading 0x12 flag");
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
// Verify 0x12 for core:instantiatearg
if(*p++ != 0x12){
set_error_buf_ex(error_buf, error_buf_size, "Failed to read 0x12 flag identifier for core instantiatearg field");
free_core_name(core_name);
wasm_runtime_free(core_name);
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
// i:<instanceidx> - this is a core instance index
uint64_t instance_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &instance_idx, error_buf, error_buf_size)) {
free_core_name(core_name);
wasm_runtime_free(core_name);
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
out->instances[i].expression.with_args.args[j].idx.instance_idx = (uint32_t)instance_idx;
}
} else {
out->instances[i].expression.with_args.args = NULL;
}
break;
}
case WASM_COMP_INSTANCE_EXPRESSION_WITHOUT_ARGS: {
// 0x01 e*:vec(<core:inlineexport>) => e*
uint64_t inline_expr_len = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &inline_expr_len, error_buf, error_buf_size)) {
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
out->instances[i].expression.without_args.inline_expr_len = (uint32_t)inline_expr_len;
if (inline_expr_len > 0) {
out->instances[i].expression.without_args.inline_expr = wasm_runtime_malloc(sizeof(WASMComponentInlineExport) * inline_expr_len);
if (!out->instances[i].expression.without_args.inline_expr) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to allocate memory for core inline exports");
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
// Initialize inline exports to zero
memset(out->instances[i].expression.without_args.inline_expr, 0, sizeof(WASMComponentInlineExport) * inline_expr_len);
for (uint32_t j = 0; j < inline_expr_len; j++) {
// core:inlineexport ::= n:<core:name> si:<core:sortidx>
WASMComponentCoreName *name = NULL;
// Debug: Check if we're about to go out of bounds
if (p >= end) {
set_error_buf_ex(error_buf, error_buf_size, "Buffer overflow in inline exports parsing");
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
// Parse core:name using the existing parse_core_name function
bool name_parse_success = parse_core_name(&p, end, &name, error_buf, error_buf_size);
if (!name_parse_success) {
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
out->instances[i].expression.without_args.inline_expr[j].name = name;
// Check bounds before parsing sort index
if (p >= end) {
set_error_buf_ex(error_buf, error_buf_size, "Buffer overflow when parsing core sort idx");
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
// Parse core:sortidx (must use is_core=true for core instances)
WASMComponentSortIdx *sort_idx = wasm_runtime_malloc(sizeof(WASMComponentSortIdx));
if (!sort_idx) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to allocate memory for core sort idx");
free_core_name(name);
wasm_runtime_free(name);
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
// Zero-initialize sort_idx
memset(sort_idx, 0, sizeof(WASMComponentSortIdx));
bool status = parse_sort_idx(&p, end, sort_idx, error_buf, error_buf_size, true);
if (!status) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to parse core sort idx");
wasm_runtime_free(sort_idx);
free_core_name(name);
wasm_runtime_free(name);
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
out->instances[i].expression.without_args.inline_expr[j].sort_idx = sort_idx;
}
} else {
out->instances[i].expression.without_args.inline_expr = NULL;
}
break;
}
default: {
set_error_buf_ex(error_buf, error_buf_size, "Unknown core instance expression tag: 0x%02X", tag);
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
}
}
}
if (consumed_len) *consumed_len = payload_len;
return true;
}
// Individual section free functions
void wasm_component_free_core_instance_section(WASMComponentSection *section) {
if (!section || !section->parsed.core_instance_section) return;
WASMComponentCoreInstSection *core_instance_sec = section->parsed.core_instance_section;
if (core_instance_sec->instances) {
for (uint32_t j = 0; j < core_instance_sec->count; ++j) {
WASMComponentCoreInst *instance = &core_instance_sec->instances[j];
switch (instance->instance_expression_tag) {
case WASM_COMP_INSTANCE_EXPRESSION_WITH_ARGS:
if (instance->expression.with_args.args) {
for (uint32_t k = 0; k < instance->expression.with_args.arg_len; ++k) {
WASMComponentInstArg *arg = &instance->expression.with_args.args[k];
// Free core name
if (arg->name) {
free_core_name(arg->name);
wasm_runtime_free(arg->name);
arg->name = NULL;
}
}
wasm_runtime_free(instance->expression.with_args.args);
instance->expression.with_args.args = NULL;
}
break;
case WASM_COMP_INSTANCE_EXPRESSION_WITHOUT_ARGS:
if (instance->expression.without_args.inline_expr) {
for (uint32_t k = 0; k < instance->expression.without_args.inline_expr_len; ++k) {
WASMComponentInlineExport *inline_export = &instance->expression.without_args.inline_expr[k];
// Free core export name
if (inline_export->name) {
free_core_name(inline_export->name);
wasm_runtime_free(inline_export->name);
inline_export->name = NULL;
}
// Free core sort index
if (inline_export->sort_idx) {
if (inline_export->sort_idx->sort) {
wasm_runtime_free(inline_export->sort_idx->sort);
inline_export->sort_idx->sort = NULL;
}
wasm_runtime_free(inline_export->sort_idx);
inline_export->sort_idx = NULL;
}
}
wasm_runtime_free(instance->expression.without_args.inline_expr);
instance->expression.without_args.inline_expr = NULL;
}
break;
}
}
wasm_runtime_free(core_instance_sec->instances);
core_instance_sec->instances = NULL;
}
wasm_runtime_free(core_instance_sec);
section->parsed.core_instance_section = NULL;
}

View File

@ -0,0 +1,102 @@
/*
* 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 <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>
// Section 1: module section
bool wasm_component_parse_core_module_section(const uint8_t **payload, uint32_t payload_len, WASMComponentCoreModuleWrapper *out, LoadArgs *args, char *error_buf, uint32_t error_buf_size, uint32_t *consumed_len) {
if (consumed_len) *consumed_len = 0;
if (!payload || !*payload || payload_len == 0 || !out) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid payload or output pointer");
return false;
}
LOG_DEBUG(" Module section: embedded Core WebAssembly module\n");
// Use the core wasm loader to parse the module
wasm_module_t mod = wasm_runtime_load_ex((uint8 *)*payload, payload_len, args, error_buf, error_buf_size);
if (!mod) {
LOG_DEBUG(" Failed to load embedded core wasm module: %s\n", error_buf);
return false;
}
// Print some basic info about the embedded module
LOG_DEBUG(" Types: %u function types\n", wasm_runtime_get_import_count(mod));
LOG_DEBUG(" Exports: %u exports\n", wasm_runtime_get_export_count(mod));
#if WASM_ENABLE_INTERP != 0
LOG_DEBUG(" Functions: %u functions\n", wasm_runtime_get_function_count(mod));
LOG_DEBUG(" Tables: %u tables\n", wasm_runtime_get_table_count(mod));
LOG_DEBUG(" Memories: %u memories\n", wasm_runtime_get_memories_count(mod));
LOG_DEBUG(" Globals: %u globals\n", wasm_runtime_get_globals_count(mod));
#endif
// Check if the module has imports
int32_t import_count = wasm_runtime_get_import_count(mod);
if (import_count > 0) {
LOG_DEBUG(" Imports: %u imports\n", import_count);
for (int32_t i = 0; i < import_count; i++) {
wasm_import_t import;
wasm_runtime_get_import_type(mod, i, &import);
LOG_DEBUG(" Import %u: module=\"%s\", name=\"%s\", kind=%u\n",
i,
import.module_name ? import.module_name : "<null>",
import.name ? import.name : "<null>",
import.kind);
// Print more details about the import
if (import.module_name && strlen(import.module_name) == 0) {
LOG_DEBUG(" WARNING: Empty module name - this will cause 'unknown import' error\n");
}
if (import.name && strlen(import.name) == 0) {
LOG_DEBUG(" WARNING: Empty field name - this will cause 'unknown import' error\n");
}
}
}
// Check if the module has exports
int32_t export_count = wasm_runtime_get_export_count(mod);
if (export_count > 0) {
LOG_DEBUG(" Exports: %u exports\n", export_count);
for (int32_t i = 0; i < export_count; i++) {
wasm_export_t export;
wasm_runtime_get_export_type(mod, i, &export);
LOG_DEBUG(" Export %u: name=\"%s\", kind= %u\n",
i,
export.name ? export.name : "<null>",
export.kind);
// Print more details about the export
if (export.name && strlen(export.name) == 0) {
LOG_DEBUG(" WARNING: Empty field name - this will cause 'unknown export' error\n");
}
}
}
// Store the module pointer directly instead of copying
out->module_handle = (void*)mod;
out->module = NULL; // We don't need the actual module structure for now
if (consumed_len) *consumed_len = payload_len;
return true;
}
// Individual section free functions
void wasm_component_free_core_module_section(WASMComponentSection *section) {
if (!section || !section->parsed.core_module) return;
// Use the proper wasm_runtime_unload function to free the module
if (section->parsed.core_module->module_handle) {
wasm_runtime_unload((wasm_module_t)section->parsed.core_module->module_handle);
section->parsed.core_module->module_handle = NULL;
}
wasm_runtime_free(section->parsed.core_module);
section->parsed.core_module = NULL;
}

View File

@ -0,0 +1,822 @@
/*
* 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 <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>
bool parse_core_limits(const uint8_t **payload, const uint8_t *end, WASMComponentCoreLimits *out, char *error_buf, uint32_t error_buf_size) {
const uint8_t *p = *payload;
uint8_t tag = *p++;
switch (tag) {
case WASM_CORE_LIMITS_MIN: {
uint64_t min = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &min, error_buf, error_buf_size)) {
return false;
}
out->tag = WASM_CORE_LIMITS_MIN;
out->lim.limits.min = (uint32_t)min;
break;
}
case WASM_CORE_LIMITS_MAX: {
uint64_t min = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &min, error_buf, error_buf_size)) {
return false;
}
uint64_t max = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &max, error_buf, error_buf_size)) {
return false;
}
out->tag = WASM_CORE_LIMITS_MAX;
out->lim.limits_max.min = (uint32_t)min;
out->lim.limits_max.max = (uint32_t)max;
break;
}
default: {
set_error_buf_ex(error_buf, error_buf_size, "Invalid limits tag: %02x", tag);
return false;
}
}
*payload = p;
return true;
}
static bool parse_core_heaptype(const uint8_t **payload, const uint8_t *end, WASMComponentCoreHeapType *out, char *error_buf, uint32_t error_buf_size)
{
const uint8_t *p = *payload;
if (p >= end) {
set_error_buf_ex(error_buf, error_buf_size, "Unexpected end while parsing heaptype");
return false;
}
uint8_t first = *p;
// absheaptype short-form: 0x6A..0x73
if (is_core_absheaptype(first)) {
out->tag = WASM_CORE_HEAP_TYPE_ABSTRACT;
out->heap_type.abstract_type = (WASMCoreAbsHeapTypeTag)first;
p++;
*payload = p;
return true;
}
// Otherwise, parse as (positive) s33 index; we store as u32
uint64_t idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &idx, error_buf, error_buf_size)) {
return false;
}
if (!is_valid_core_heap_type_index(idx)) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid heaptype index: %llu", (unsigned long long)idx);
return false;
}
out->tag = WASM_CORE_HEAP_TYPE_CONCRETE;
out->heap_type.concrete_index = (uint32_t)idx;
*payload = p;
return true;
}
bool parse_core_valtype(const uint8_t **payload, const uint8_t *end, WASMComponentCoreValType *out, char *error_buf, uint32_t error_buf_size) {
const uint8_t *p = *payload;
uint8_t tag = *p++;
// numtype ::= 0x7F (i32) | 0x7E (i64) | 0x7D (f32) | 0x7C (f64)
if (tag >= WASM_CORE_NUM_TYPE_F64 && tag <= WASM_CORE_NUM_TYPE_I32) {
out->tag = WASM_CORE_VALTYPE_NUM;
out->type.num_type = (WASMCoreNumTypeTag)tag;
*payload = p;
return true;
}
// vectype ::= 0x7B (v128)
if (tag == WASM_CORE_VECTOR_TYPE_V128) {
out->tag = WASM_CORE_VALTYPE_VECTOR;
out->type.vector_type = WASM_CORE_VECTOR_TYPE_V128;
*payload = p;
return true;
}
// reftype encodings (Preview 1 + GC):
// - 0x63 ht:heaptype => (ref null ht)
// - 0x64 ht:heaptype => (ref ht)
// - ht:absheaptype (0x6A..0x73) => short-form (ref null ht)
if (tag == 0x63 || tag == 0x64) {
WASMComponentCoreHeapType heap_type;
if (!parse_core_heaptype(&p, end, &heap_type, error_buf, error_buf_size)) {
return false;
}
if (heap_type.tag == WASM_CORE_HEAP_TYPE_ABSTRACT) {
if (heap_type.heap_type.abstract_type == WASM_CORE_ABS_HEAP_TYPE_FUNC) {
out->tag = WASM_CORE_VALTYPE_REF;
out->type.ref_type = WASM_CORE_REFTYPE_FUNC_REF;
*payload = p;
return true;
}
if (heap_type.heap_type.abstract_type == WASM_CORE_ABS_HEAP_TYPE_EXTERN) {
out->tag = WASM_CORE_VALTYPE_REF;
out->type.ref_type = WASM_CORE_REFTYPE_EXTERN_REF;
*payload = p;
return true;
}
}
set_error_buf_ex(error_buf, error_buf_size, "Unsupported reftype heaptype for core valtype");
return false;
}
// Short-form absheaptype for (ref null ht)
if (tag >= WASM_CORE_ABS_HEAP_TYPE_ARRAY && tag <= WASM_CORE_ABS_HEAP_TYPE_NOFUNC) {
if (tag == WASM_CORE_ABS_HEAP_TYPE_FUNC) {
out->tag = WASM_CORE_VALTYPE_REF;
out->type.ref_type = WASM_CORE_REFTYPE_FUNC_REF;
*payload = p;
return true;
}
if (tag == WASM_CORE_ABS_HEAP_TYPE_EXTERN) {
out->tag = WASM_CORE_VALTYPE_REF;
out->type.ref_type = WASM_CORE_REFTYPE_EXTERN_REF;
*payload = p;
return true;
}
set_error_buf_ex(error_buf, error_buf_size, "Unsupported short-form absheaptype %02x for core valtype", tag);
return false;
}
set_error_buf_ex(error_buf, error_buf_size, "Invalid core valtype tag: %02x", tag);
return false;
}
bool parse_core_import_desc(const uint8_t **payload, const uint8_t *end, WASMComponentCoreImportDesc *out, char *error_buf, uint32_t error_buf_size) {
const uint8_t *p = *payload;
uint8_t tag = *p++;
switch (tag) {
case WASM_CORE_IMPORTDESC_FUNC: {
uint64_t func_type_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &func_type_idx, error_buf, error_buf_size)) {
return false;
}
out->type = WASM_CORE_IMPORTDESC_FUNC;
out->desc.func_type_idx = (uint32_t)func_type_idx;
break;
}
case WASM_CORE_IMPORTDESC_TABLE: {
uint8_t ref_type_tag = *p++;
if (ref_type_tag == WASM_CORE_REFTYPE_FUNC_REF) {
out->type = WASM_CORE_IMPORTDESC_TABLE;
out->desc.table_type.ref_type = WASM_CORE_REFTYPE_FUNC_REF;
} else if (ref_type_tag == WASM_CORE_REFTYPE_EXTERN_REF) {
out->type = WASM_CORE_IMPORTDESC_TABLE;
out->desc.table_type.ref_type = WASM_CORE_REFTYPE_EXTERN_REF;
} else {
set_error_buf_ex(error_buf, error_buf_size, "Invalid reference type tag: %02x", ref_type_tag);
return false;
}
WASMComponentCoreLimits *limits = wasm_runtime_malloc(sizeof(WASMComponentCoreLimits));
if (!limits) {
set_error_buf_ex(error_buf, error_buf_size, "OOM allocating table limits");
return false;
}
if (!parse_core_limits(&p, end, limits, error_buf, error_buf_size)) {
wasm_runtime_free(limits);
return false;
}
out->type = WASM_CORE_IMPORTDESC_TABLE;
out->desc.table_type.limits = limits;
break;
}
case WASM_CORE_IMPORTDESC_MEMORY: {
WASMComponentCoreLimits *limits = wasm_runtime_malloc(sizeof(WASMComponentCoreLimits));
if (!limits) {
set_error_buf_ex(error_buf, error_buf_size, "OOM allocating memory limits");
return false;
}
if (!parse_core_limits(&p, end, limits, error_buf, error_buf_size)) {
wasm_runtime_free(limits);
return false;
}
out->type = WASM_CORE_IMPORTDESC_MEMORY;
out->desc.memory_type.limits = limits;
break;
}
case WASM_CORE_IMPORTDESC_GLOBAL: {
if (!parse_core_valtype(&p, end, &out->desc.global_type.val_type, error_buf, error_buf_size)) {
return false;
}
// mut ::= 0x00 => const, 0x01 => var (spec)
uint8_t mutable_tag = *p++;
if (mutable_tag == WASM_CORE_GLOBAL_MUTABLE) {
out->desc.global_type.is_mutable = true;
} else if (mutable_tag == WASM_CORE_GLOBAL_IMMUTABLE) {
out->desc.global_type.is_mutable = false;
} else {
set_error_buf_ex(error_buf, error_buf_size, "Invalid mutable tag: %02x", mutable_tag);
return false;
}
break;
}
default: {
set_error_buf_ex(error_buf, error_buf_size, "Invalid import descriptor tag: %02x", tag);
return false;
}
}
*payload = p;
return true;
}
bool parse_core_import(const uint8_t **payload, const uint8_t *end, WASMComponentCoreImport *out, char *error_buf, uint32_t error_buf_size) {
const uint8_t *p = *payload;
WASMComponentCoreName *mod_name = NULL;
if (!parse_core_name(&p, end, &mod_name, error_buf, error_buf_size)) {
return false;
}
out->mod_name = mod_name;
WASMComponentCoreName *nm_name = NULL;
if (!parse_core_name(&p, end, &nm_name, error_buf, error_buf_size)) {
return false;
}
out->nm = nm_name;
WASMComponentCoreImportDesc *import_desc = wasm_runtime_malloc(sizeof(WASMComponentCoreImportDesc));
if (!import_desc) {
set_error_buf_ex(error_buf, error_buf_size, "OOM allocating import desc");
return false;
}
if (!parse_core_import_desc(&p, end, import_desc, error_buf, error_buf_size)) {
wasm_runtime_free(import_desc);
return false;
}
out->import_desc = import_desc;
*payload = p;
return true;
}
bool parse_alias_target(const uint8_t **payload, const uint8_t *end, WASMComponentCoreAliasTarget *out, char *error_buf, uint32_t error_buf_size) {
const uint8_t *p = *payload;
uint8_t tag = *p++;
if (tag == 0x01) {
uint64_t ct_leb = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &ct_leb, error_buf, error_buf_size)) {
return false;
}
out->ct = (uint32_t)ct_leb;
uint64_t index_leb = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &index_leb, error_buf, error_buf_size)) {
return false;
}
out->index = (uint32_t)index_leb;
} else {
set_error_buf_ex(error_buf, error_buf_size, "Invalid alias target tag: %02x", tag);
return false;
}
*payload = p;
return true;
}
bool parse_core_alias(const uint8_t **payload, const uint8_t *end, WASMComponentCoreAlias *out, char *error_buf, uint32_t error_buf_size) {
const uint8_t *p = *payload;
/* no leading tag here; core:alias is parsed inside moduledecl */
if (!parse_sort(&p, end, &out->sort, error_buf, error_buf_size, true)) {
return false;
}
if (!parse_alias_target(&p, end, &out->alias_target, error_buf, error_buf_size)) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to parse alias target");
return false;
}
*payload = p;
return true;
}
bool parse_core_export_decl(const uint8_t **payload, const uint8_t *end, WASMComponentCoreExportDecl *out, char *error_buf, uint32_t error_buf_size) {
const uint8_t *p = *payload;
/* core:exportdecl ::= nm:<core:name> d:<core:exportdesc> */
WASMComponentCoreName *mod_name = NULL;
if (!parse_core_name(&p, end, &mod_name, error_buf, error_buf_size)) {
return false;
}
out->name = mod_name;
WASMComponentCoreImportDesc *export_desc = wasm_runtime_malloc(sizeof(WASMComponentCoreImportDesc));
if (!export_desc) {
set_error_buf_ex(error_buf, error_buf_size, "OOM allocating export desc");
return false;
}
if (!parse_core_import_desc(&p, end, export_desc, error_buf, error_buf_size)) {
wasm_runtime_free(export_desc);
return false;
}
out->export_desc = export_desc;
*payload = p;
return true;
}
bool parse_core_module_decl(const uint8_t **payload, const uint8_t *end, WASMComponentCoreModuleDecl *out, char *error_buf, uint32_t error_buf_size) {
const uint8_t *p = *payload;
uint8_t tag = *p++;
out->tag = tag;
switch (tag) {
case WASM_CORE_MODULEDECL_IMPORT: {
out->decl.import_decl.import = wasm_runtime_malloc(sizeof(WASMComponentCoreImport));
if (!out->decl.import_decl.import) {
set_error_buf_ex(error_buf, error_buf_size, "OOM allocating module import decl");
return false;
}
if (!parse_core_import(&p, end, out->decl.import_decl.import, error_buf, error_buf_size)) {
return false;
}
break;
}
case WASM_CORE_MODULEDECL_TYPE: {
out->decl.type_decl.type = wasm_runtime_malloc(sizeof(WASMComponentCoreType));
if (!out->decl.type_decl.type) {
set_error_buf_ex(error_buf, error_buf_size, "OOM allocating module type decl");
return false;
}
out->decl.type_decl.type->deftype = wasm_runtime_malloc(sizeof(WASMComponentCoreDefType));
if (!out->decl.type_decl.type->deftype) {
set_error_buf_ex(error_buf, error_buf_size, "OOM allocating core deftype");
return false;
}
if (!parse_single_core_type(&p, end, out->decl.type_decl.type->deftype, error_buf, error_buf_size)) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to parse type declaration");
return false;
}
break;
}
case WASM_CORE_MODULEDECL_ALIAS: {
out->decl.alias_decl.alias = wasm_runtime_malloc(sizeof(WASMComponentCoreAlias));
if (!out->decl.alias_decl.alias) {
set_error_buf_ex(error_buf, error_buf_size, "OOM allocating module alias decl");
return false;
}
if (!parse_core_alias(&p, end, out->decl.alias_decl.alias, error_buf, error_buf_size)) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to parse alias declaration");
return false;
}
break;
}
case WASM_CORE_MODULEDECL_EXPORT: {
out->decl.export_decl.export_decl = wasm_runtime_malloc(sizeof(WASMComponentCoreExportDecl));
if (!out->decl.export_decl.export_decl) {
set_error_buf_ex(error_buf, error_buf_size, "OOM allocating module export decl");
return false;
}
if (!parse_core_export_decl(&p, end, out->decl.export_decl.export_decl, error_buf, error_buf_size)) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to parse export declaration");
return false;
}
break;
}
default: {
set_error_buf_ex(error_buf, error_buf_size, "Invalid module declaration tag: %02x", tag);
return false;
}
}
*payload = p;
return true;
}
bool parse_core_moduletype(const uint8_t **payload, const uint8_t *end, WASMComponentCoreModuleType *out, char *error_buf, uint32_t error_buf_size) {
const uint8_t *p = *payload;
// Expect vec(moduledecl): count then that many moduledecl
uint64_t count_leb = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &count_leb, error_buf, error_buf_size)) {
return false;
}
uint32_t count = (uint32_t)count_leb;
out->decl_count = count;
if (count > 0) {
out->declarations = wasm_runtime_malloc(sizeof(WASMComponentCoreModuleDecl) * count);
if (!out->declarations) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to allocate memory for declarations");
return false;
}
// Zero-initialize declarations array
memset(out->declarations, 0, sizeof(WASMComponentCoreModuleDecl) * count);
for (uint32_t i = 0; i < count; i++) {
if (!parse_core_module_decl(&p, end, &out->declarations[i], error_buf, error_buf_size)) {
return false;
}
}
}
*payload = p;
return true;
}
bool parse_single_core_type(const uint8_t **payload, const uint8_t *end, WASMComponentCoreDefType *out, char *error_buf, uint32_t error_buf_size) {
const uint8_t *p = *payload;
if (p >= end) {
set_error_buf_ex(error_buf, error_buf_size, "Unexpected end while parsing core:deftype");
return false;
}
uint8_t b0 = *p; // peek only
// 1) moduletype ::= 0x50 md*:vec(moduledecl)
if (b0 == 0x50) {
p++; // consume 0x50
out->tag = WASM_CORE_DEFTYPE_MODULETYPE;
out->type.moduletype = wasm_runtime_malloc(sizeof(WASMComponentCoreModuleType));
if (!out->type.moduletype) {
set_error_buf_ex(error_buf, error_buf_size, "OOM allocating core moduletype");
return false;
}
if (!parse_core_moduletype(&p, end, out->type.moduletype, error_buf, error_buf_size)) {
return false;
}
*payload = p;
return true;
}
// 2) rectype (GC): 0x4E ...
if (b0 == 0x4E) {
set_error_buf_ex(error_buf, error_buf_size, "WebAssembly 3.0 core:rectype (0x4E ...) not supported");
return false;
}
// 3) subtype (GC): 0x00 followed by {0x50,0x4F,0x5E,0x5F,0x60}
if (b0 == 0x00) {
if (p + 1 >= end) {
set_error_buf_ex(error_buf, error_buf_size, "Unexpected end of data after 0x00");
return false;
}
uint8_t b1 = *(p + 1);
if (b1 == 0x50 || b1 == 0x4F || b1 == 0x5E || b1 == 0x5F || b1 == 0x60) {
set_error_buf_ex(error_buf, error_buf_size, "WebAssembly 3.0 core:subtype (0x00 0x%02x ...) not supported", b1);
return false;
}
}
// Otherwise invalid in this context
set_error_buf_ex(error_buf, error_buf_size, "Invalid core:deftype tag: %02x", b0);
return false;
}
// Section 3: type section (component model type section, not the core wasm type section)
bool wasm_component_parse_core_type_section(const uint8_t **payload, uint32_t payload_len, WASMComponentCoreTypeSection *out, char *error_buf, uint32_t error_buf_size, uint32_t *consumed_len) {
if (!payload || !*payload || payload_len == 0) {
return false;
}
if (consumed_len) *consumed_len = 0;
const uint8_t *p = *payload;
const uint8_t *end = *payload + payload_len;
uint64_t count_leb = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &count_leb, error_buf, error_buf_size)) {
return false;
}
uint32_t count = (uint32_t)count_leb;
out->count = count;
if (count > 0) {
out->types = wasm_runtime_malloc(sizeof(WASMComponentCoreType) * count);
if (!out->types) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to allocate memory for types");
return false;
}
memset(out->types, 0, sizeof(WASMComponentCoreType) * count);
for (uint32_t i = 0; i < count; i++) {
WASMComponentCoreDefType *dt = wasm_runtime_malloc(sizeof(WASMComponentCoreDefType));
if (!dt) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to allocate memory for core deftype");
return false;
}
memset(dt, 0, sizeof(WASMComponentCoreDefType));
if (!parse_single_core_type(&p, end, dt, error_buf, error_buf_size)) {
wasm_runtime_free(dt);
return false;
}
out->types[i].deftype = dt;
}
}
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return true;
}
// Individual section free functions
void wasm_component_free_core_type_section(WASMComponentSection *section) {
if (!section || !section->parsed.core_type_section) {
return;
}
WASMComponentCoreTypeSection *core_type_section = section->parsed.core_type_section;
if (core_type_section->types) {
for (uint32_t i = 0; i < core_type_section->count; i++) {
if (core_type_section->types[i].deftype) {
free_core_deftype(core_type_section->types[i].deftype);
wasm_runtime_free(core_type_section->types[i].deftype);
}
}
wasm_runtime_free(core_type_section->types);
}
wasm_runtime_free(core_type_section);
section->parsed.core_type_section = NULL;
}
// Helper functions for freeing core structures
void free_core_import_desc(WASMComponentCoreImportDesc *import_desc) {
if (!import_desc) {
return;
}
switch (import_desc->type) {
case WASM_CORE_IMPORTDESC_FUNC:
break;
case WASM_CORE_IMPORTDESC_TABLE:
if (import_desc->desc.table_type.limits) {
wasm_runtime_free(import_desc->desc.table_type.limits);
import_desc->desc.table_type.limits = NULL;
}
break;
case WASM_CORE_IMPORTDESC_MEMORY:
if (import_desc->desc.memory_type.limits) {
wasm_runtime_free(import_desc->desc.memory_type.limits);
import_desc->desc.memory_type.limits = NULL;
}
break;
case WASM_CORE_IMPORTDESC_GLOBAL:
// These are simple structures, no additional memory to free
break;
}
}
void free_core_import(WASMComponentCoreImport *import) {
if (!import) {
return;
}
if (import->mod_name) {
free_core_name(import->mod_name);
wasm_runtime_free(import->mod_name);
}
if (import->nm) {
free_core_name(import->nm);
wasm_runtime_free(import->nm);
}
if (import->import_desc) {
free_core_import_desc(import->import_desc);
wasm_runtime_free(import->import_desc);
}
}
void free_core_export_decl(WASMComponentCoreExportDecl *export_decl) {
if (!export_decl) {
return;
}
if (export_decl->name) {
free_core_name(export_decl->name);
wasm_runtime_free(export_decl->name);
}
if (export_decl->export_desc) {
free_core_import_desc(export_decl->export_desc);
wasm_runtime_free(export_decl->export_desc);
}
}
void free_core_module_decl(WASMComponentCoreModuleDecl *module_decl) {
if (!module_decl) {
return;
}
switch (module_decl->tag) {
case WASM_CORE_MODULEDECL_IMPORT:
if (module_decl->decl.import_decl.import) {
free_core_import(module_decl->decl.import_decl.import);
wasm_runtime_free(module_decl->decl.import_decl.import);
}
break;
case WASM_CORE_MODULEDECL_TYPE:
if (module_decl->decl.type_decl.type) {
free_core_type(module_decl->decl.type_decl.type);
wasm_runtime_free(module_decl->decl.type_decl.type);
}
break;
case WASM_CORE_MODULEDECL_ALIAS:
if (module_decl->decl.alias_decl.alias) {
wasm_runtime_free(module_decl->decl.alias_decl.alias);
}
break;
case WASM_CORE_MODULEDECL_EXPORT:
if (module_decl->decl.export_decl.export_decl) {
free_core_export_decl(module_decl->decl.export_decl.export_decl);
wasm_runtime_free(module_decl->decl.export_decl.export_decl);
}
break;
}
}
void free_core_moduletype(WASMComponentCoreModuleType *moduletype) {
if (!moduletype) {
return;
}
if (moduletype->declarations) {
for (uint32_t i = 0; i < moduletype->decl_count; i++) {
free_core_module_decl(&moduletype->declarations[i]);
}
wasm_runtime_free(moduletype->declarations);
}
}
void free_core_deftype(WASMComponentCoreDefType *deftype) {
if (!deftype) {
return;
}
switch (deftype->tag) {
case WASM_CORE_DEFTYPE_RECTYPE:
if (deftype->type.rectype) {
free_core_rectype(deftype->type.rectype);
wasm_runtime_free(deftype->type.rectype);
}
break;
case WASM_CORE_DEFTYPE_SUBTYPE:
if (deftype->type.subtype) {
free_core_module_subtype(deftype->type.subtype);
wasm_runtime_free(deftype->type.subtype);
}
break;
case WASM_CORE_DEFTYPE_MODULETYPE:
if (deftype->type.moduletype) {
free_core_moduletype(deftype->type.moduletype);
wasm_runtime_free(deftype->type.moduletype);
}
break;
}
}
void free_core_type(WASMComponentCoreType *type) {
if (!type) {
return;
}
if (type->deftype) {
free_core_deftype(type->deftype);
wasm_runtime_free(type->deftype);
}
}
void free_core_type_section(WASMComponentCoreTypeSection *section) {
if (!section) {
return;
}
if (section->types) {
for (uint32_t i = 0; i < section->count; i++) {
free_core_type(&section->types[i]);
}
wasm_runtime_free(section->types);
}
}
// Additional helper functions for freeing core structures
void free_core_functype(WASMComponentCoreFuncType *functype) {
if (!functype) {
return;
}
if (functype->params.val_types) {
wasm_runtime_free(functype->params.val_types);
}
if (functype->results.val_types) {
wasm_runtime_free(functype->results.val_types);
}
}
void free_core_rectype(WASMComponentCoreRecType *rectype) {
if (!rectype) {
return;
}
if (rectype->subtypes) {
for (uint32_t i = 0; i < rectype->subtype_count; i++) {
free_core_subtype(&rectype->subtypes[i]);
}
wasm_runtime_free(rectype->subtypes);
}
}
void free_core_resulttype(WASMComponentCoreResultType *resulttype) {
if (!resulttype) {
return;
}
if (resulttype->val_types) {
wasm_runtime_free(resulttype->val_types);
}
}
void free_core_structtype(WASMComponentCoreStructType *structtype) {
if (!structtype) {
return;
}
if (structtype->fields) {
wasm_runtime_free(structtype->fields);
}
}
void free_core_comptype(WASMComponentCoreCompType *comptype) {
if (!comptype) {
return;
}
switch (comptype->tag) {
case WASM_CORE_COMPTYPE_FUNC:
free_core_functype(&comptype->type.func_type);
break;
case WASM_CORE_COMPTYPE_STRUCT:
if (comptype->type.struct_type.fields) {
wasm_runtime_free(comptype->type.struct_type.fields);
}
break;
case WASM_CORE_COMPTYPE_ARRAY:
// Array type is simple, no additional memory to free
break;
}
}
void free_core_subtype(WASMComponentCoreSubType *subtype) {
if (!subtype) {
return;
}
if (subtype->supertypes) {
wasm_runtime_free(subtype->supertypes);
}
// Free the comptype
free_core_comptype(&subtype->comptype);
}
void free_core_module_subtype(WASMComponentCoreModuleSubType *module_subtype) {
if (!module_subtype) {
return;
}
if (module_subtype->supertypes) {
wasm_runtime_free(module_subtype->supertypes);
}
if (module_subtype->comptype) {
free_core_comptype(module_subtype->comptype);
wasm_runtime_free(module_subtype->comptype);
}
}

View File

@ -0,0 +1,17 @@
/*
* Copyright (C) 2026 Airbus Defence and Space Romania SRL. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "wasm_component_export.h"
#include "wasm_component.h"
static bool is_component = false;
bool is_component_runtime() {
return is_component;
}
void set_component_runtime(bool type) {
is_component = type;
}

View File

@ -0,0 +1,14 @@
/*
* Copyright (C) 2026 Airbus Defence and Space Romania SRL. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef WASM_COMPONENT_EXPORT_H
#define WASM_COMPONENT_EXPORT_H
#include "stdbool.h"
bool is_component_runtime();
void set_component_runtime(bool type);
#endif

View File

@ -0,0 +1,182 @@
/*
* 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 <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>
// Section 11: exports section
bool wasm_component_parse_exports_section(const uint8_t **payload, uint32_t payload_len,WASMComponentExportSection *out, char *error_buf, uint32_t error_buf_size, uint32_t *consumed_len){
if (!payload || !*payload || payload_len == 0 || !out) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid payload or output pointer");
if (consumed_len) *consumed_len = 0;
return false;
}
const uint8_t *p = *payload;
const uint8_t *end = *payload + payload_len;
if (p >= end) {
set_error_buf_ex(error_buf, error_buf_size, "Unexpected end of buffer when reading exports count");
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
uint64_t export_count_leb = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &export_count_leb, error_buf, error_buf_size)) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to read exports count");
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
uint32_t export_count = (uint32_t)export_count_leb;
out->count = export_count;
if (export_count > 0) {
out->exports = wasm_runtime_malloc(sizeof(WASMComponentExport) * export_count);
if (!out->exports) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to allocate memory for exports");
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
// Ensure all fields (including optional extern_desc) are initialized to NULL/0
memset(out->exports, 0, sizeof(WASMComponentExport) * export_count);
// Parsing every export
for (uint32_t i = 0; i < export_count; i++) {
// Parsing 'exportname'
if (p >= end) {
set_error_buf_ex(error_buf, error_buf_size, "Unexpected end of buffer when reading export name for export %u", i);
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
WASMComponentExportName *export_name = wasm_runtime_malloc(sizeof(WASMComponentExportName));
if (!export_name) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to allocate memory for export_name");
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
bool status = parse_component_export_name(&p, end, export_name, error_buf, error_buf_size);
if (!status) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to parse component name for export %u", i);
wasm_runtime_free(export_name);
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
out->exports[i].export_name = export_name;
// Parsing 'sortidx'
out->exports[i].sort_idx = wasm_runtime_malloc(sizeof(WASMComponentSortIdx));
if (!out->exports[i].sort_idx) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to allocate memory for sort_idx");
wasm_runtime_free(export_name);
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
status = parse_sort_idx(&p, end, out->exports[i].sort_idx, error_buf, error_buf_size, false);
if (!status) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to parse sort_idx for export %u", i);
wasm_runtime_free(out->exports[i].sort_idx);
wasm_runtime_free(export_name);
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
LOG_DEBUG("Export section: name = \"%s\", sort idx = %d\n", out->exports[i].export_name->exported.simple.name->name, out->exports[i].sort_idx->sort->sort);
// Parsing 'externdesc' (OPTIONAL)
if (p >= end) {
LOG_DEBUG("Parsing Extern desc\n");
set_error_buf_ex(error_buf, error_buf_size, "Unexpected end of buffer when reading optional extern_desc for export %u", i);
wasm_runtime_free(out->exports[i].sort_idx->sort);
wasm_runtime_free(out->exports[i].sort_idx);
wasm_runtime_free(export_name);
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
uint8_t opt_extern_desc = *p++;
if (opt_extern_desc == WASM_COMP_OPTIONAL_TRUE) {
if (p >= end) {
set_error_buf_ex(error_buf, error_buf_size, "Unexpected end of buffer when parsing extern_desc for export %u", i);
wasm_runtime_free(out->exports[i].sort_idx->sort);
wasm_runtime_free(out->exports[i].sort_idx);
wasm_runtime_free(export_name);
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
WASMComponentExternDesc *extern_desc = wasm_runtime_malloc(sizeof(WASMComponentExternDesc));
bool extern_status = parse_extern_desc(&p, end, extern_desc, error_buf, error_buf_size);
if (!extern_status) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to parse extern_desc for export %u", i);
wasm_runtime_free(extern_desc);
wasm_runtime_free(out->exports[i].sort_idx->sort);
wasm_runtime_free(out->exports[i].sort_idx);
wasm_runtime_free(export_name);
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
out->exports[i].extern_desc = extern_desc;
LOG_DEBUG("Extern desc added\n");
} else if (opt_extern_desc == WASM_COMP_OPTIONAL_FALSE) {
// Explicitly mark absence of extern_desc
out->exports[i].extern_desc = NULL;
LOG_DEBUG("Extern desc set to NULL\n");
} else {
set_error_buf_ex(error_buf, error_buf_size, "Malformed binary: invalid optional tag 0x%02x", opt_extern_desc);
return false;
}
}
}
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return true;
}
// Individual section free functions
void wasm_component_free_exports_section(WASMComponentSection *section) {
if (!section || !section->parsed.export_section) return;
WASMComponentExportSection *export_sec = section->parsed.export_section;
if (export_sec->exports) {
for (uint32_t j = 0; j < export_sec->count; ++j) {
WASMComponentExport *export = &export_sec->exports[j];
// Free export name
if (export->export_name) {
free_component_export_name(export->export_name);
wasm_runtime_free(export->export_name);
export->export_name = NULL;
}
// Free sort index
if (export->sort_idx) {
if (export->sort_idx->sort) {
wasm_runtime_free(export->sort_idx->sort);
export->sort_idx->sort = NULL;
}
wasm_runtime_free(export->sort_idx);
export->sort_idx = NULL;
}
// Free extern desc (optional)
if (export->extern_desc) {
free_extern_desc(export->extern_desc);
wasm_runtime_free(export->extern_desc);
export->extern_desc = NULL;
}
}
wasm_runtime_free(export_sec->exports);
export_sec->exports = NULL;
}
wasm_runtime_free(export_sec);
section->parsed.export_section = NULL;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,133 @@
/*
* 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 <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>
// Section 10: imports section
bool wasm_component_parse_imports_section(const uint8_t **payload, uint32_t payload_len, WASMComponentImportSection *out, char *error_buf, uint32_t error_buf_size, uint32_t *consumed_len) {
if (!payload || !*payload || payload_len == 0 || !out) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid payload or output pointer");
if (consumed_len) *consumed_len = 0;
return false;
}
const uint8_t *p = *payload;
const uint8_t *end = *payload + payload_len;
// import ::= in:<importname'> ed:<externdesc> => (import in ed)
// Read the count of imports (LEB128-encoded)
uint64_t import_count_leb = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &import_count_leb, error_buf, error_buf_size)) {
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
uint32_t import_count = (uint32_t)import_count_leb;
out->count = import_count;
if (import_count > 0) {
out->imports = wasm_runtime_malloc(sizeof(WASMComponentImport) * import_count);
if (!out->imports) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to allocate memory for imports");
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
// Initialize all imports to zero to avoid garbage data
memset(out->imports, 0, sizeof(WASMComponentImport) * import_count);
for (uint32_t i = 0; i < import_count; ++i) {
// importname' ::= 0x00 len:<u32> in:<importname> => in (if len = |in|)
// | 0x01 len:<u32> in:<importname> vs:<versionsuffix'> => in vs (if len = |in|)
// Parse import name (simple or versioned)
WASMComponentImportName *import_name = wasm_runtime_malloc(sizeof(WASMComponentImportName));
if (!import_name) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to allocate memory for import_name");
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
// Initialize the struct to zero to avoid garbage data
memset(import_name, 0, sizeof(WASMComponentImportName));
bool status = parse_component_import_name(&p, end, import_name, error_buf, error_buf_size);
if (!status) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to parse component name for import %u", i);
wasm_runtime_free(import_name);
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
// externdesc ::= 0x00 0x11 i:<core:typeidx> => (core module (type i))
// | 0x01 i:<typeidx> => (func (type i))
// | 0x02 b:<valuebound> => (value b)
// | 0x03 b:<typebound> => (type b)
// | 0x04 i:<typeidx> => (component (type i))
// | 0x05 i:<typeidx> => (instance (type i))
// Parse externdesc (core module, func, value, type, component, instance)
WASMComponentExternDesc *extern_desc = wasm_runtime_malloc(sizeof(WASMComponentExternDesc));
if (!extern_desc) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to allocate memory for extern_desc");
wasm_runtime_free(import_name);
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
// Initialize the struct to zero to avoid garbage data
memset(extern_desc, 0, sizeof(WASMComponentExternDesc));
status = parse_extern_desc(&p, end, extern_desc, error_buf, error_buf_size);
if (!status) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to parse extern_desc for import %u", i);
wasm_runtime_free(extern_desc);
wasm_runtime_free(import_name);
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
// Store the parsed import (importname' + externdesc)
out->imports[i].import_name = import_name;
out->imports[i].extern_desc = extern_desc;
}
}
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return true;
}
// Individual section free functions
void wasm_component_free_imports_section(WASMComponentSection *section) {
if (!section || !section->parsed.import_section) return;
WASMComponentImportSection *import_sec = section->parsed.import_section;
if (import_sec->imports) {
for (uint32_t j = 0; j < import_sec->count; ++j) {
WASMComponentImport *import = &import_sec->imports[j];
// Free import name
if (import->import_name) {
free_component_import_name(import->import_name);
wasm_runtime_free(import->import_name);
import->import_name = NULL;
}
// Free extern desc
if (import->extern_desc) {
free_extern_desc(import->extern_desc);
wasm_runtime_free(import->extern_desc);
import->extern_desc = NULL;
}
}
wasm_runtime_free(import_sec->imports);
import_sec->imports = NULL;
}
wasm_runtime_free(import_sec);
section->parsed.import_section = NULL;
}

View File

@ -0,0 +1,273 @@
/*
* 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 <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>
// Section 5: instances section
// Binary.md: instance ::= ie:<instanceexpr> => (instance ie)
// instanceexpr ::= 0x00 c:<componentidx> arg*:vec(<instantiatearg>) => (instantiate c arg*)
// instantiatearg ::= n:<name> si:<sortidx> => (with n si)
bool wasm_component_parse_instances_section(const uint8_t **payload, uint32_t payload_len, WASMComponentInstSection *out, char *error_buf, uint32_t error_buf_size, uint32_t *consumed_len) {
if (!payload || !*payload || payload_len == 0 || !out) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid payload or output pointer");
if (consumed_len) *consumed_len = 0;
return false;
}
const uint8_t *p = *payload;
const uint8_t *end = *payload + payload_len;
uint64_t instance_count = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &instance_count, error_buf, error_buf_size)) {
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
out->count = (uint32_t)instance_count;
if (instance_count > 0) {
out->instances = wasm_runtime_malloc(sizeof(WASMComponentInst) * instance_count);
if (!out->instances) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to allocate memory for instances");
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
// Initialize all instances to zero to avoid garbage data
memset(out->instances, 0, sizeof(WASMComponentInst) * instance_count);
for (uint32_t i = 0; i < instance_count; ++i) {
// Check bounds before reading tag
if (p >= end) {
set_error_buf_ex(error_buf, error_buf_size, "Buffer overflow when reading instance tag");
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
uint8_t tag = *p++;
out->instances[i].instance_expression_tag = tag;
switch (tag) {
case WASM_COMP_INSTANCE_EXPRESSION_WITH_ARGS: {
// 0x00 c:<componentidx> arg*:vec(<instantiatearg>)
uint64_t component_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &component_idx, error_buf, error_buf_size)) {
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
out->instances[i].expression.with_args.idx = (uint32_t)component_idx;
uint64_t arg_len = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &arg_len, error_buf, error_buf_size)) {
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
out->instances[i].expression.with_args.arg_len = (uint32_t)arg_len;
if (arg_len > 0) {
out->instances[i].expression.with_args.args = wasm_runtime_malloc(sizeof(WASMComponentInstArg) * arg_len);
if (!out->instances[i].expression.with_args.args) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to allocate memory for component instantiate args");
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
// Initialize args to zero
memset(out->instances[i].expression.with_args.args, 0, sizeof(WASMComponentInstArg) * arg_len);
for (uint32_t j = 0; j < arg_len; ++j) {
// Parse core:name (LEB128 length + UTF-8 bytes)
WASMComponentCoreName *core_name = NULL;
if (!parse_core_name(&p, end, &core_name, error_buf, error_buf_size)) {
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
// Store the name in the instantiate arg structure
out->instances[i].expression.with_args.args[j].name = core_name;
// si:<sortidx> - this is a component-level sort index (non-core)
out->instances[i].expression.with_args.args[j].idx.sort_idx = wasm_runtime_malloc(sizeof(WASMComponentSortIdx));
if (!out->instances[i].expression.with_args.args[j].idx.sort_idx) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to allocate memory for component arg sort idx");
free_core_name(core_name);
wasm_runtime_free(core_name);
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
// Zero-initialize sort_idx
memset(out->instances[i].expression.with_args.args[j].idx.sort_idx, 0, sizeof(WASMComponentSortIdx));
// Parse component sort index
bool status = parse_sort_idx(&p, end, out->instances[i].expression.with_args.args[j].idx.sort_idx, error_buf, error_buf_size, false);
if (!status) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to parse component arg sort idx");
free_core_name(core_name);
wasm_runtime_free(core_name);
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
}
} else {
out->instances[i].expression.with_args.args = NULL;
}
break;
}
case WASM_COMP_INSTANCE_EXPRESSION_WITHOUT_ARGS: {
// 0x01 e*:vec(<inlineexport>) => e*
uint64_t inline_expr_len = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &inline_expr_len, error_buf, error_buf_size)) {
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
out->instances[i].expression.without_args.inline_expr_len = (uint32_t)inline_expr_len;
if (inline_expr_len > 0) {
out->instances[i].expression.without_args.inline_expr = wasm_runtime_malloc(sizeof(WASMComponentInlineExport) * inline_expr_len);
if (!out->instances[i].expression.without_args.inline_expr) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to allocate memory for component inline exports");
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
// Initialize inline exports to zero
memset(out->instances[i].expression.without_args.inline_expr, 0, sizeof(WASMComponentInlineExport) * inline_expr_len);
for (uint32_t j = 0; j < inline_expr_len; j++) {
// inlineexport ::= n:<exportname> si:<sortidx>
WASMComponentCoreName *name = wasm_runtime_malloc(sizeof(WASMComponentCoreName));
if (!name) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to allocate memory for component export name");
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
// Parse export name (component-level name)
bool name_parse_success = parse_core_name(&p, end, &name, error_buf, error_buf_size);
if (!name_parse_success) {
free_core_name(name);
wasm_runtime_free(name);
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
out->instances[i].expression.without_args.inline_expr[j].name = name;
// Parse component sort index
WASMComponentSortIdx *sort_idx = wasm_runtime_malloc(sizeof(WASMComponentSortIdx));
if (!sort_idx) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to allocate memory for component sort idx");
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
// Zero-initialize sort_idx
memset(sort_idx, 0, sizeof(WASMComponentSortIdx));
bool status = parse_sort_idx(&p, end, sort_idx, error_buf, error_buf_size, false);
if (!status) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to parse component sort idx");
wasm_runtime_free(sort_idx);
free_core_name(name);
wasm_runtime_free(name);
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
out->instances[i].expression.without_args.inline_expr[j].sort_idx = sort_idx;
}
} else {
out->instances[i].expression.without_args.inline_expr = NULL;
}
break;
}
default: {
set_error_buf_ex(error_buf, error_buf_size, "Unknown instance expression tag: 0x%02X", tag);
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
}
}
}
if (consumed_len) *consumed_len = payload_len;
return true;
}
// Individual section free functions
void wasm_component_free_instances_section(WASMComponentSection *section) {
if (!section || !section->parsed.instance_section) return;
WASMComponentInstSection *instance_sec = section->parsed.instance_section;
if (instance_sec->instances) {
for (uint32_t j = 0; j < instance_sec->count; ++j) {
WASMComponentInst *instance = &instance_sec->instances[j];
switch (instance->instance_expression_tag) {
case WASM_COMP_INSTANCE_EXPRESSION_WITH_ARGS:
if (instance->expression.with_args.args) {
for (uint32_t k = 0; k < instance->expression.with_args.arg_len; ++k) {
WASMComponentInstArg *arg = &instance->expression.with_args.args[k];
// Free component name
if (arg->name) {
free_core_name(arg->name);
wasm_runtime_free(arg->name);
arg->name = NULL;
}
// Free component sort index
if (arg->idx.sort_idx) {
if (arg->idx.sort_idx->sort) {
wasm_runtime_free(arg->idx.sort_idx->sort);
arg->idx.sort_idx->sort = NULL;
}
wasm_runtime_free(arg->idx.sort_idx);
arg->idx.sort_idx = NULL;
}
}
wasm_runtime_free(instance->expression.with_args.args);
instance->expression.with_args.args = NULL;
}
break;
case WASM_COMP_INSTANCE_EXPRESSION_WITHOUT_ARGS:
if (instance->expression.without_args.inline_expr) {
for (uint32_t k = 0; k < instance->expression.without_args.inline_expr_len; ++k) {
WASMComponentInlineExport *inline_export = &instance->expression.without_args.inline_expr[k];
// Free component export name
if (inline_export->name) {
free_core_name(inline_export->name);
wasm_runtime_free(inline_export->name);
inline_export->name = NULL;
}
// Free component sort index
if (inline_export->sort_idx) {
if (inline_export->sort_idx->sort) {
wasm_runtime_free(inline_export->sort_idx->sort);
inline_export->sort_idx->sort = NULL;
}
wasm_runtime_free(inline_export->sort_idx);
inline_export->sort_idx = NULL;
}
}
wasm_runtime_free(instance->expression.without_args.inline_expr);
instance->expression.without_args.inline_expr = NULL;
}
break;
}
}
wasm_runtime_free(instance_sec->instances);
instance_sec->instances = NULL;
}
wasm_runtime_free(instance_sec);
section->parsed.instance_section = NULL;
}

View File

@ -0,0 +1,94 @@
/*
* 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 <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>
// Section 9: start section
bool wasm_component_parse_start_section(const uint8_t **payload, uint32_t payload_len, WASMComponentStartSection *out, char *error_buf, uint32_t error_buf_size, uint32_t *consumed_len) {
if (consumed_len) *consumed_len = 0;
if (!payload || !*payload || !out || payload_len == 0) {
return false;
}
const uint8_t *p = *payload;
const uint8_t *end = p + payload_len;
// Initialize outputs
out->func_idx = 0;
out->value_args_count = 0;
out->value_args = NULL;
out->result = 0;
uint64_t func_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &func_idx, error_buf, error_buf_size)) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to read func idx");
return false;
}
out->func_idx = (uint32_t)func_idx;
uint64_t args_count = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &args_count, error_buf, error_buf_size)) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to read args count");
return false;
}
out->value_args_count = (uint32_t)args_count;
if (args_count > 0) {
out->value_args = wasm_runtime_malloc(sizeof(uint32_t) * args_count);
if (!out->value_args) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to allocate memory for value args");
return false;
}
for (uint64_t i = 0; i < args_count; i++) {
uint64_t value_idx = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &value_idx, error_buf, error_buf_size)) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to read value idx");
// cleanup
wasm_runtime_free(out->value_args);
out->value_args = NULL;
out->value_args_count = 0;
return false;
}
out->value_args[i] = (uint32_t)value_idx;
}
}
uint64_t result_leb = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &result_leb, error_buf, error_buf_size)) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to read result count");
if (out->value_args) {
wasm_runtime_free(out->value_args);
out->value_args = NULL;
out->value_args_count = 0;
}
return false;
}
out->result = (uint32_t)result_leb;
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return true;
}
// Individual section free functions
void wasm_component_free_start_section(WASMComponentSection *section) {
if (!section || !section->parsed.start_section) {
return;
}
WASMComponentStartSection *start_section = section->parsed.start_section;
if (start_section->value_args) {
wasm_runtime_free(start_section->value_args);
}
wasm_runtime_free(start_section);
section->parsed.start_section = NULL;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,56 @@
/*
* Copyright (C) 2026 Airbus Defence and Space Romania SRL. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef WASM_COMPONENT_VALIDATE_H
#define WASM_COMPONENT_VALIDATE_H
#include "bh_hashmap.h"
#include "wasm_component.h"
typedef struct WASMComponentValidationContext {
// Index spaces
uint32_t type_count;
uint32_t func_count;
uint32_t instance_count;
uint32_t component_count;
uint32_t value_count;
uint32_t core_type_count;
uint32_t core_module_count;
uint32_t core_instance_count;
uint32_t core_table_count;
uint32_t core_memory_count; // needed for canon memory opts
uint32_t core_global_count;
uint32_t core_func_count; // needed for canon realloc/post-return checks
struct WASMComponentValidationContext *parent;
// name uniqueness
HashMap *import_names;
HashMap *export_names;
// Flat type lookup array: types[i] is the WASMComponentTypes* for type index i
// NULL for types introduced via import or alias
// type_is_local[i] is true if the type was defined in a local type section
WASMComponentTypes **types;
bool *type_is_local;
uint32_t types_capacity;
// Consumption tracking: value_consumed[i] is true once value i has been consumed exactly once
bool *value_consumed;
uint32_t value_consumed_capacity;
// Func-to-type tracking: func_type_indexes[i] is the type index for function i
// UINT32_MAX for functions whose type is unknown (e.g. aliased)
uint32_t *func_type_indexes;
uint32_t func_type_indexes_capacity;
// Resource type names: tracks import/export names that introduce resource types
// Used for [static] annotation validation
HashMap *resource_type_names;
} WASMComponentValidationContext;
bool wasm_component_validate(WASMComponent *comp, WASMComponentValidationContext *parent, char *error_buf, uint32_t error_buf_size);
#endif

View File

@ -0,0 +1,446 @@
/*
* 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 <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdint.h>
#include "wasm_loader_common.h"
#include "wasm_export.h"
#include <stdio.h>
// Helper function to parse a value
// Helper to check if f32 bytes represent canonical NaN
static bool is_canonical_f32_nan(const uint8_t *bytes) {
return bytes[0] == 0x00 && bytes[1] == 0x00 &&
bytes[2] == 0xC0 && bytes[3] == 0x7F;
}
// Helper to check if f64 bytes represent canonical NaN
static bool is_canonical_f64_nan(const uint8_t *bytes) {
return bytes[0] == 0x00 && bytes[1] == 0x00 && bytes[2] == 0x00 &&
bytes[3] == 0x00 && bytes[4] == 0x00 && bytes[5] == 0x00 &&
bytes[6] == 0xF8 && bytes[7] == 0x7F;
}
// Helper to check if f32/f64 bytes represent any NaN (for rejection)
static bool is_any_nan(const uint8_t *bytes, bool is_f64) {
if (is_f64) {
// Check f64 NaN pattern (exponent all 1s, mantissa non-zero)
uint64_t bits = 0;
memcpy(&bits, bytes, 8);
return ((bits >> 52) & 0x7FF) == 0x7FF && (bits & 0xFFFFFFFFFFFFF) != 0;
} else {
// Check f32 NaN pattern (exponent all 1s, mantissa non-zero)
uint32_t bits = 0;
memcpy(&bits, bytes, 4);
return ((bits >> 23) & 0xFF) == 0xFF && (bits & 0x7FFFFF) != 0;
}
}
// value ::= t:<valtype> len:<core:u32> v:<val(t)> => (value t v) (where len = ||v||)
static bool parse_value(const uint8_t **payload, const uint8_t *end, WASMComponentValue *out, char *error_buf, uint32_t error_buf_size) {
const uint8_t *p = *payload;
// Parse the value type
WASMComponentValueType *val_type = NULL;
val_type = wasm_runtime_malloc(sizeof(WASMComponentValueType));
if (!val_type) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to allocate memory for value type");
return false;
}
if (!parse_valtype(&p, end, val_type, error_buf, error_buf_size)) {
wasm_runtime_free(val_type);
return false;
}
out->val_type = val_type;
uint64_t core_data_len_u32_leb = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &core_data_len_u32_leb, error_buf, error_buf_size)) {
wasm_runtime_free(val_type);
return false;
}
out->core_data_len = (uint32_t)core_data_len_u32_leb;
// Now parse v:<val(t)> according to t. Advance `p` per case and ensure
// the declared len matches the actual encoding size for handled cases.
if ((uint32_t)(end - p) < out->core_data_len) {
set_error_buf_ex(error_buf, error_buf_size, "Insufficient bytes for value payload: need %u, have %zu", out->core_data_len, (size_t)(end - p));
wasm_runtime_free(val_type);
return false;
}
const uint8_t *v_start = p;
if (val_type->type == WASM_COMP_VAL_TYPE_PRIMVAL) {
switch (val_type->type_specific.primval_type) {
case WASM_COMP_PRIMVAL_BOOL: {
if (out->core_data_len != 1) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid bool length: %u (expected 1)", out->core_data_len);
wasm_runtime_free(val_type);
return false;
}
uint8_t b = *p;
if (b != 0x00 && b != 0x01) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid bool value byte: 0x%02x", b);
wasm_runtime_free(val_type);
return false;
}
p += 1;
break;
}
case WASM_COMP_PRIMVAL_U8: {
if (out->core_data_len != 1) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid u8 length: %u (expected 1)", out->core_data_len);
wasm_runtime_free(val_type);
return false;
}
p += 1;
break;
}
case WASM_COMP_PRIMVAL_S8: {
if (out->core_data_len != 1) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid s8 length: %u (expected 1)", out->core_data_len);
wasm_runtime_free(val_type);
return false;
}
p += 1;
break;
}
case WASM_COMP_PRIMVAL_S16: {
// signed LEB128 (1..3 bytes for 16-bit)
if (out->core_data_len < 1 || out->core_data_len > 3) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid s16 LEB length: %u (expected 1..3)", out->core_data_len);
wasm_runtime_free(val_type);
return false;
}
uint64_t tmp = 0;
uint8_t *q = (uint8_t *)p;
const uint8_t *before = p;
if (!read_leb(&q, end, 16, true, &tmp, error_buf, error_buf_size)) {
wasm_runtime_free(val_type);
return false;
}
if ((uint32_t)(q - before) != out->core_data_len) {
set_error_buf_ex(error_buf, error_buf_size, "s16 len mismatch: declared %u, decoded %u", out->core_data_len, (uint32_t)(q - before));
wasm_runtime_free(val_type);
return false;
}
p = (const uint8_t *)q;
break;
}
case WASM_COMP_PRIMVAL_U16: {
// unsigned LEB128 (1..3 bytes for 16-bit)
if (out->core_data_len < 1 || out->core_data_len > 3) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid u16 LEB length: %u (expected 1..3)", out->core_data_len);
wasm_runtime_free(val_type);
return false;
}
uint64_t tmp = 0;
uint8_t *q = (uint8_t *)p;
const uint8_t *before = p;
if (!read_leb(&q, end, 16, false, &tmp, error_buf, error_buf_size)) {
wasm_runtime_free(val_type);
return false;
}
if ((uint32_t)(q - before) != out->core_data_len) {
set_error_buf_ex(error_buf, error_buf_size, "u16 len mismatch: declared %u, decoded %u", out->core_data_len, (uint32_t)(q - before));
wasm_runtime_free(val_type);
return false;
}
p = (const uint8_t *)q;
break;
}
case WASM_COMP_PRIMVAL_S32: {
// signed LEB128 (1..5 bytes)
if (out->core_data_len < 1 || out->core_data_len > 5) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid s32 LEB length: %u (expected 1..5)", out->core_data_len);
wasm_runtime_free(val_type);
return false;
}
uint64_t tmp = 0;
uint8_t *q = (uint8_t *)p;
const uint8_t *before = p;
if (!read_leb(&q, end, 32, true, &tmp, error_buf, error_buf_size)) {
wasm_runtime_free(val_type);
return false;
}
if ((uint32_t)(q - before) != out->core_data_len) {
set_error_buf_ex(error_buf, error_buf_size, "s32 len mismatch: declared %u, decoded %u", out->core_data_len, (uint32_t)(q - before));
wasm_runtime_free(val_type);
return false;
}
p = (const uint8_t *)q;
break;
}
case WASM_COMP_PRIMVAL_U32: {
// unsigned LEB128 (1..5 bytes)
if (out->core_data_len < 1 || out->core_data_len > 5) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid u32 LEB length: %u (expected 1..5)", out->core_data_len);
wasm_runtime_free(val_type);
return false;
}
uint64_t tmp = 0;
uint8_t *q = (uint8_t *)p;
const uint8_t *before = p;
if (!read_leb(&q, end, 32, false, &tmp, error_buf, error_buf_size)) {
wasm_runtime_free(val_type);
return false;
}
if ((uint32_t)(q - before) != out->core_data_len) {
set_error_buf_ex(error_buf, error_buf_size, "u32 len mismatch: declared %u, decoded %u", out->core_data_len, (uint32_t)(q - before));
wasm_runtime_free(val_type);
return false;
}
p = (const uint8_t *)q;
break;
}
case WASM_COMP_PRIMVAL_S64: {
// signed LEB128 (1..10 bytes)
if (out->core_data_len < 1 || out->core_data_len > 10) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid s64 LEB length: %u (expected 1..10)", out->core_data_len);
wasm_runtime_free(val_type);
return false;
}
uint64_t tmp = 0;
uint8_t *q = (uint8_t *)p;
const uint8_t *before = p;
if (!read_leb(&q, end, 64, true, &tmp, error_buf, error_buf_size)) {
wasm_runtime_free(val_type);
return false;
}
if ((uint32_t)(q - before) != out->core_data_len) {
set_error_buf_ex(error_buf, error_buf_size, "s64 len mismatch: declared %u, decoded %u", out->core_data_len, (uint32_t)(q - before));
wasm_runtime_free(val_type);
return false;
}
p = (const uint8_t *)q;
break;
}
case WASM_COMP_PRIMVAL_U64: {
// unsigned LEB128 (1..10 bytes)
if (out->core_data_len < 1 || out->core_data_len > 10) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid u64 LEB length: %u (expected 1..10)", out->core_data_len);
wasm_runtime_free(val_type);
return false;
}
uint64_t tmp = 0;
uint8_t *q = (uint8_t *)p;
const uint8_t *before = p;
if (!read_leb(&q, end, 64, false, &tmp, error_buf, error_buf_size)) {
wasm_runtime_free(val_type);
return false;
}
if ((uint32_t)(q - before) != out->core_data_len) {
set_error_buf_ex(error_buf, error_buf_size, "u64 len mismatch: declared %u, decoded %u", out->core_data_len, (uint32_t)(q - before));
wasm_runtime_free(val_type);
return false;
}
p = (const uint8_t *)q;
break;
}
case WASM_COMP_PRIMVAL_F32: {
if (out->core_data_len != 4) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid f32 length: %u (expected 4)", out->core_data_len);
wasm_runtime_free(val_type);
return false;
}
if (is_canonical_f32_nan(p)) {
p += 4;
break;
} else if (is_any_nan(p, false)) {
// Reject non-canonical NaN
set_error_buf_ex(error_buf, error_buf_size, "Non-canonical NaN not allowed");
wasm_runtime_free(val_type);
return false;
}
p += 4;
break;
}
case WASM_COMP_PRIMVAL_F64: {
if (out->core_data_len != 8) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid f64 length: %u (expected 8)", out->core_data_len);
wasm_runtime_free(val_type);
return false;
}
if (is_canonical_f64_nan(p)) {
p += 8;
break;
} else if (is_any_nan(p, true)) {
// Reject non-canonical NaN
set_error_buf_ex(error_buf, error_buf_size, "Non-canonical NaN not allowed");
wasm_runtime_free(val_type);
return false;
}
p += 8;
break;
}
case WASM_COMP_PRIMVAL_CHAR: {
// val(char) ::= b*:<core:byte>* => c (where b* = core:utf8(c))
// Expect 1..4 bytes and ensure exactly one UTF-8 scalar
if (out->core_data_len < 1 || out->core_data_len > 4) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid char length: %u (expected 1..4)", out->core_data_len);
wasm_runtime_free(val_type);
return false;
}
if (!wasm_component_validate_single_utf8_scalar(p, out->core_data_len)) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid UTF-8 scalar for char");
wasm_runtime_free(val_type);
return false;
}
p += out->core_data_len;
break;
}
case WASM_COMP_PRIMVAL_STRING: {
// val(string) ::= v:<core:name> => v
// core:name = name_len_leb + name_bytes; require outer len == leb_len + name_len
const uint8_t *before = p;
uint8_t *q = (uint8_t *)p;
uint64_t name_len = 0;
if (!read_leb(&q, end, 32, false, &name_len, error_buf, error_buf_size)) {
wasm_runtime_free(val_type);
return false;
}
uint32_t leb_len = (uint32_t)(q - before);
if ((uint32_t)(end - q) < (uint32_t)name_len) {
set_error_buf_ex(error_buf, error_buf_size, "Insufficient bytes for string payload: need %llu, have %zu", (unsigned long long)name_len, (size_t)(end - q));
wasm_runtime_free(val_type);
return false;
}
if ((uint32_t)name_len + leb_len != out->core_data_len) {
set_error_buf_ex(error_buf, error_buf_size, "string len mismatch: declared %u, decoded %u", out->core_data_len, (uint32_t)name_len + leb_len);
wasm_runtime_free(val_type);
return false;
}
if (!wasm_component_validate_utf8(q, (uint32_t)name_len)) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid UTF-8 in string");
wasm_runtime_free(val_type);
return false;
}
p = q + name_len;
break;
}
default: {
set_error_buf_ex(error_buf, error_buf_size,
"Unknown primitive value type 0x%02x",
val_type->type_specific.primval_type);
wasm_runtime_free(val_type);
return false;
}
}
} else {
// valtype in the values section must be either primval or typeidx
if (val_type->type != WASM_COMP_VAL_TYPE_IDX) {
set_error_buf_ex(error_buf, error_buf_size,
"Unsupported valtype tag %u in values section (expected typeidx)",
(unsigned)val_type->type);
wasm_runtime_free(val_type);
return false;
}
// Minimal mode for type-indexed values:
// - core_data will be set to v_start (the start of v:<val(t)>)
// - just advance by the declared len and validate bounds
if ((uint32_t)(end - p) < out->core_data_len) {
set_error_buf_ex(error_buf, error_buf_size,
"Insufficient bytes for type-indexed value payload: need %u, have %zu",
out->core_data_len, (size_t)(end - p));
wasm_runtime_free(val_type);
return false;
}
p += out->core_data_len;
}
// Keep a borrowed pointer to the raw value bytes window
out->core_data = v_start;
*payload = p;
return true;
}
// Section 12: values section
bool wasm_component_parse_values_section(const uint8_t **payload, uint32_t payload_len, WASMComponentValueSection *out, char *error_buf, uint32_t error_buf_size, uint32_t *consumed_len) {
if (!payload || !*payload || payload_len == 0 || !out) {
set_error_buf_ex(error_buf, error_buf_size, "Invalid payload or output pointer");
if (consumed_len) *consumed_len = 0;
return false;
}
const uint8_t *p = *payload;
const uint8_t *end = *payload + payload_len;
// values ::= count:<count> value:<value> => (values count value)
// Read the count of values (LEB128-encoded)
uint64_t value_count_leb = 0;
if (!read_leb((uint8_t **)&p, end, 32, false, &value_count_leb, error_buf, error_buf_size)) {
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
uint32_t value_count = (uint32_t)value_count_leb;
out->count = value_count;
if (value_count > 0) {
out->values = wasm_runtime_malloc(sizeof(WASMComponentValue) * value_count);
if (!out->values) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to allocate memory for values");
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
// Initialize all values to zero to avoid garbage data
memset(out->values, 0, sizeof(WASMComponentValue) * value_count);
for (uint32_t i = 0; i < value_count; ++i) {
if (!parse_value(&p, end, &out->values[i], error_buf, error_buf_size)) {
set_error_buf_ex(error_buf, error_buf_size, "Failed to parse value %u", i);
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return false;
}
}
}
if (consumed_len) *consumed_len = (uint32_t)(p - *payload);
return true;
}
// Individual section free functions
void wasm_component_free_values_section(WASMComponentSection *section) {
if (!section || !section->parsed.value_section) {
return;
}
WASMComponentValueSection *value_section = section->parsed.value_section;
if (value_section->values) {
for (uint32_t i = 0; i < value_section->count; i++) {
// Free the allocated val_type structures
if (value_section->values[i].val_type) {
wasm_runtime_free(value_section->values[i].val_type);
value_section->values[i].val_type = NULL;
}
// core_data points into the original payload; do not free
}
wasm_runtime_free(value_section->values);
value_section->values = NULL;
}
wasm_runtime_free(value_section);
section->parsed.value_section = NULL;
}

View File

@ -4,6 +4,7 @@
*/ */
#include "bh_platform.h" #include "bh_platform.h"
#include "wasm_ieee754.h"
#if WASM_ENABLE_INTERP != 0 #if WASM_ENABLE_INTERP != 0
#include "../interpreter/wasm_runtime.h" #include "../interpreter/wasm_runtime.h"
#endif #endif
@ -50,13 +51,6 @@ runtime_malloc(uint64 size, WASMModuleInstanceCommon *module_inst,
return mem; return mem;
} }
static union {
int a;
char b;
} __ue = { .a = 1 };
#define is_little_endian() (__ue.b == 1) /* NOLINT */
/** /**
* Implementation of wasm_application_execute_main() * Implementation of wasm_application_execute_main()
*/ */
@ -311,47 +305,6 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, int32 argc,
* Implementation of wasm_application_execute_func() * Implementation of wasm_application_execute_func()
*/ */
union ieee754_float {
float f;
/* This is the IEEE 754 single-precision format. */
union {
struct {
unsigned int negative : 1;
unsigned int exponent : 8;
unsigned int mantissa : 23;
} ieee_big_endian;
struct {
unsigned int mantissa : 23;
unsigned int exponent : 8;
unsigned int negative : 1;
} ieee_little_endian;
} ieee;
};
union ieee754_double {
double d;
/* This is the IEEE 754 double-precision format. */
union {
struct {
unsigned int negative : 1;
unsigned int exponent : 11;
/* Together these comprise the mantissa. */
unsigned int mantissa0 : 20;
unsigned int mantissa1 : 32;
} ieee_big_endian;
struct {
/* Together these comprise the mantissa. */
unsigned int mantissa1 : 32;
unsigned int mantissa0 : 20;
unsigned int exponent : 11;
unsigned int negative : 1;
} ieee_little_endian;
} ieee;
};
static bool static bool
execute_func(WASMModuleInstanceCommon *module_inst, const char *name, execute_func(WASMModuleInstanceCommon *module_inst, const char *name,
int32 argc, char *argv[]) int32 argc, char *argv[])

View File

@ -0,0 +1,60 @@
#ifndef _WASM_IEEE754_H
#define _WASM_IEEE754_H
#ifdef __cplusplus
extern "C" {
#endif
union ieee754_float {
float f;
/* This is the IEEE 754 single-precision format. */
union {
struct {
unsigned int negative : 1;
unsigned int exponent : 8;
unsigned int mantissa : 23;
} ieee_big_endian;
struct {
unsigned int mantissa : 23;
unsigned int exponent : 8;
unsigned int negative : 1;
} ieee_little_endian;
} ieee;
};
union ieee754_double {
double d;
/* This is the IEEE 754 double-precision format. */
union {
struct {
unsigned int negative : 1;
unsigned int exponent : 11;
/* Together these comprise the mantissa. */
unsigned int mantissa0 : 20;
unsigned int mantissa1 : 32;
} ieee_big_endian;
struct {
/* Together these comprise the mantissa. */
unsigned int mantissa1 : 32;
unsigned int mantissa0 : 20;
unsigned int exponent : 11;
unsigned int negative : 1;
} ieee_little_endian;
} ieee;
};
static union {
int a;
char b;
} __ue = { .a = 1 };
#define is_little_endian() (__ue.b == 1) /* NOLINT */
#ifdef __cplusplus
}
#endif
#endif /* end of _WASM_IEEE754_H */

View File

@ -652,6 +652,41 @@ wasm_runtime_init_internal(void)
return true; return true;
} }
bool wasm_decode_header(const uint8_t *buf, uint32_t size, WASMHeader *out_header) {
if (!buf || size < 8) {
return false;
}
// WASM binary is little-endian
uint32_t magic = (uint32_t)buf[0] | ((uint32_t)buf[1] << 8) | ((uint32_t)buf[2] << 16) | ((uint32_t)buf[3] << 24);
// Decode version and layer fields
// For Preview 1 modules: version=0x0001, layer=0x0000 (combined: 0x00000001)
// For Preview 2 components: version=0x000d, layer=0x0001
uint16_t version = (uint16_t)buf[4] | ((uint16_t)buf[5] << 8);
uint16_t layer = (uint16_t)buf[6] | ((uint16_t)buf[7] << 8);
out_header->magic = magic;
out_header->version = version;
out_header->layer = layer;
return true;
}
bool is_wasm_module(WASMHeader header) {
if (header.magic != WASM_MAGIC_NUMBER) {
return false;
}
// For Preview 1 modules, the combined version+layer should equal 0x00000001
uint32_t combined_version = ((uint32_t)header.layer << 16) | (uint32_t)header.version;
if (combined_version != WASM_CURRENT_VERSION) {
return false;
}
return true;
}
bool bool
wasm_runtime_init() wasm_runtime_init()
{ {
@ -4512,6 +4547,76 @@ wasm_runtime_get_export_count(WASMModuleCommon *const module)
return -1; return -1;
} }
#if WASM_ENABLE_INTERP != 0
int32
wasm_runtime_get_function_count(WASMModuleCommon *const module)
{
if (!module) {
bh_assert(0);
return -1;
}
if (module->module_type == Wasm_Module_Bytecode) {
const WASMModule *wasm_module = (const WASMModule *)module;
return (int32)wasm_module->function_count;
}
return -1;
}
int32
wasm_runtime_get_table_count(WASMModuleCommon *const module)
{
if (!module) {
bh_assert(0);
return -1;
}
if (module->module_type == Wasm_Module_Bytecode) {
const WASMModule *wasm_module = (const WASMModule *)module;
return (int32)wasm_module->table_count;
}
return -1;
}
int32
wasm_runtime_get_memories_count(WASMModuleCommon *const module)
{
if (!module) {
bh_assert(0);
return -1;
}
if (module->module_type == Wasm_Module_Bytecode) {
const WASMModule *wasm_module = (const WASMModule *)module;
return (int32)wasm_module->memory_count;
}
return -1;
}
int32
wasm_runtime_get_globals_count(WASMModuleCommon *const module)
{
if (!module) {
bh_assert(0);
return -1;
}
if (module->module_type == Wasm_Module_Bytecode) {
const WASMModule *wasm_module = (const WASMModule *)module;
return (int32)wasm_module->global_count;
}
return -1;
}
#endif
void void
wasm_runtime_get_export_type(WASMModuleCommon *const module, int32 export_index, wasm_runtime_get_export_type(WASMModuleCommon *const module, int32 export_index,
wasm_export_t *export_type) wasm_export_t *export_type)

View File

@ -90,6 +90,13 @@ typedef struct WASMMemory WASMMemoryType;
#endif #endif
typedef WASMMemoryType *wasm_memory_type_t; typedef WASMMemoryType *wasm_memory_type_t;
// WASM Header Structure
typedef struct WASMHeader {
uint32_t magic; // Magic number (0x6d736100 for both)
uint16_t version; // Version field
uint16_t layer; // Layer field
} WASMHeader;
typedef struct wasm_import_t { typedef struct wasm_import_t {
const char *module_name; const char *module_name;
const char *name; const char *name;
@ -118,6 +125,11 @@ typedef struct wasm_export_t {
struct WASMModuleInstanceCommon; struct WASMModuleInstanceCommon;
typedef struct WASMModuleInstanceCommon *wasm_module_inst_t; typedef struct WASMModuleInstanceCommon *wasm_module_inst_t;
#if WASM_ENABLE_COMPONENT_MODEL != 0
struct WASMComponentInstance;
typedef struct WASMComponentInstance WASMComponentInstance;
#endif
/* Function instance */ /* Function instance */
typedef void WASMFunctionInstanceCommon; typedef void WASMFunctionInstanceCommon;
typedef WASMFunctionInstanceCommon *wasm_function_inst_t; typedef WASMFunctionInstanceCommon *wasm_function_inst_t;
@ -275,6 +287,9 @@ typedef struct LoadArgs {
wasm_runtime_load_ex has to be followed by a wasm_runtime_resolve_symbols wasm_runtime_load_ex has to be followed by a wasm_runtime_resolve_symbols
call */ call */
bool no_resolve; bool no_resolve;
#if WASM_ENABLE_COMPONENT_MODEL != 0
bool is_component;
#endif
/* TODO: more fields? */ /* TODO: more fields? */
} LoadArgs; } LoadArgs;
#endif /* LOAD_ARGS_OPTION_DEFINED */ #endif /* LOAD_ARGS_OPTION_DEFINED */
@ -354,6 +369,20 @@ typedef struct SharedHeapInitArgs {
void *pre_allocated_addr; void *pre_allocated_addr;
} SharedHeapInitArgs; } SharedHeapInitArgs;
/**
* Decode a WASM file header into WASMHeader structure
*
* @return true if success, false otherwise
*/
bool wasm_decode_header(const uint8_t *buf, uint32_t size, WASMHeader *out_header);
/**
* Check if header is a WASM Preview 1
*
* @return true if success, false otherwise
*/
bool is_wasm_module(WASMHeader header);
/** /**
* Initialize the WASM runtime environment, and also initialize * Initialize the WASM runtime environment, and also initialize
* the memory allocator with system allocator, which calls os_malloc * the memory allocator with system allocator, which calls os_malloc
@ -1602,6 +1631,48 @@ wasm_runtime_get_import_type(const wasm_module_t module, int32_t import_index,
WASM_RUNTIME_API_EXTERN int32_t WASM_RUNTIME_API_EXTERN int32_t
wasm_runtime_get_export_count(const wasm_module_t module); wasm_runtime_get_export_count(const wasm_module_t module);
#if WASM_ENABLE_INTERP != 0
/**
* Get the number of function count for a WASM module
*
* @param module the WASM module
*
* @return the number of functions (zero for none), or -1 for failure
*/
WASM_RUNTIME_API_EXTERN int32_t
wasm_runtime_get_function_count(const wasm_module_t module);
/**
* Get the number of table count for a WASM module
*
* @param module the WASM module
*
* @return the number of tables (zero for none), or -1 for failure
*/
WASM_RUNTIME_API_EXTERN int32_t
wasm_runtime_get_table_count(const wasm_module_t module);
/**
* Get the number of memory count for a WASM module
*
* @param module the WASM module
*
* @return the number of memories (zero for none), or -1 for failure
*/
WASM_RUNTIME_API_EXTERN int32_t
wasm_runtime_get_memories_count(const wasm_module_t module);
/**
* Get the number of global count for a WASM module
*
* @param module the WASM module
*
* @return the number of globals (zero for none), or -1 for failure
*/
WASM_RUNTIME_API_EXTERN int32_t
wasm_runtime_get_globals_count(const wasm_module_t module);
#endif
/** /**
* Get information about a specific WASM module export * Get information about a specific WASM module export
* *

View File

@ -154,6 +154,8 @@ typedef void *table_elem_type_t;
#define WASM_MAGIC_NUMBER 0x6d736100 #define WASM_MAGIC_NUMBER 0x6d736100
#define WASM_CURRENT_VERSION 1 #define WASM_CURRENT_VERSION 1
#define WASM_COMPONENT_VERSION 0x000d // 0x0d 0x00
#define WASM_COMPONENT_LAYER 0x0001 // 0x01 0x00
#define SECTION_TYPE_USER 0 #define SECTION_TYPE_USER 0
#define SECTION_TYPE_TYPE 1 #define SECTION_TYPE_TYPE 1

View File

@ -7108,7 +7108,7 @@ load(const uint8 *buf, uint32 size, WASMModule *module,
module->package_version = version; module->package_version = version;
if (!create_sections(buf, size, &section_list, error_buf, error_buf_size) if (!create_sections(buf, size, &section_list, error_buf, error_buf_size)
|| !load_from_sections(module, section_list, true, wasm_binary_freeable, || !load_from_sections(module, section_list, false, wasm_binary_freeable,
no_resolve, error_buf, error_buf_size)) { no_resolve, error_buf, error_buf_size)) {
destroy_sections(section_list); destroy_sections(section_list);
return false; return false;
@ -7130,7 +7130,10 @@ check_wasi_abi_compatibility(const WASMModule *module,
#if WASM_ENABLE_MULTI_MODULE != 0 #if WASM_ENABLE_MULTI_MODULE != 0
bool main_module, bool main_module,
#endif #endif
char *error_buf, uint32 error_buf_size) #if WASM_ENABLE_COMPONENT_MODEL != 0
bool is_component,
#endif
char *error_buf, uint32 error_buf_size)
{ {
/** /**
* be careful with: * be careful with:
@ -7215,13 +7218,14 @@ check_wasi_abi_compatibility(const WASMModule *module,
if (!module->import_wasi_api && !start && !initialize) { if (!module->import_wasi_api && !start && !initialize) {
return true; return true;
} }
#if WASM_ENABLE_COMPONENT_MODEL != 0
/* should have one at least */ /* should have one at least */
if (module->import_wasi_api && !start && !initialize) { if (module->import_wasi_api && !start && !initialize) {
if (!is_component)
LOG_WARNING("warning: a module with WASI apis should be either " LOG_WARNING("warning: a module with WASI apis should be either "
"a command or a reactor"); "a command or a reactor");
} }
#endif
/* /*
* there is at least one of `_start` and `_initialize` in below cases. * there is at least one of `_start` and `_initialize` in below cases.
* according to the assumption, they should be all wasi compatible * according to the assumption, they should be all wasi compatible
@ -7296,7 +7300,10 @@ wasm_loader_load(uint8 *buf, uint32 size,
#if WASM_ENABLE_MULTI_MODULE != 0 #if WASM_ENABLE_MULTI_MODULE != 0
main_module, main_module,
#endif #endif
error_buf, error_buf_size)) { #if WASM_ENABLE_COMPONENT_MODEL != 0
args->is_component,
#endif
error_buf, error_buf_size)) {
goto fail; goto fail;
} }
#endif #endif

View File

@ -12,6 +12,10 @@
#include "mem_alloc.h" #include "mem_alloc.h"
#include "../common/wasm_runtime_common.h" #include "../common/wasm_runtime_common.h"
#include "../common/wasm_memory.h" #include "../common/wasm_memory.h"
#if WASM_ENABLE_COMPONENT_MODEL != 0
#include "../common/component-model/wasm_component_export.h"
#include "../common/component-model/wasm_component.h"
#endif
#if WASM_ENABLE_GC != 0 #if WASM_ENABLE_GC != 0
#include "../common/gc/gc_object.h" #include "../common/gc/gc_object.h"
#endif #endif
@ -173,7 +177,11 @@ wasm_resolve_import_func(const WASMModule *module, WASMFunctionImport *function)
if (function->func_ptr_linked) { if (function->func_ptr_linked) {
return true; return true;
} }
#if WASM_ENABLE_COMPONENT_MODEL != 0
if (is_component_runtime()) {
return true;
}
#endif
#if WASM_ENABLE_MULTI_MODULE != 0 #if WASM_ENABLE_MULTI_MODULE != 0
if (!wasm_runtime_is_built_in_module(function->module_name)) { if (!wasm_runtime_is_built_in_module(function->module_name)) {
sub_module = (WASMModule *)wasm_runtime_load_depended_module( sub_module = (WASMModule *)wasm_runtime_load_depended_module(
@ -1494,6 +1502,38 @@ export_functions_instantiate(const WASMModule *module,
return export_funcs; return export_funcs;
} }
/**
* Instantiate export tables in a module.
*/
static WASMExportTabInstance *
export_tables_instantiate(const WASMModule *module,
WASMModuleInstance *module_inst,
uint32 export_table_count, char *error_buf,
uint32 error_buf_size)
{
WASMExportTabInstance *export_tables, *export_table;
WASMExport *export = module->exports;
uint32 i;
uint64 total_size =
sizeof(WASMExportTabInstance) * (uint64)export_table_count;
if (!(export_table = export_tables =
runtime_malloc(total_size, error_buf, error_buf_size))) {
return NULL;
}
for (i = 0; i < module->export_count; i++, export ++)
if (export->kind == EXPORT_KIND_TABLE) {
export_table->name = export->name;
export_table->table = module_inst->tables[export->index];
export_table++;
}
bh_assert((uint32)(export_table - export_tables) == export_table_count);
return export_tables;
}
#if WASM_ENABLE_TAGS != 0 #if WASM_ENABLE_TAGS != 0
/** /**
* Destroy export function instances. * Destroy export function instances.
@ -1540,6 +1580,13 @@ export_tags_instantiate(const WASMModule *module,
} }
#endif /* end of WASM_ENABLE_TAGS != 0 */ #endif /* end of WASM_ENABLE_TAGS != 0 */
static void
export_tables_deinstantiate(WASMExportTabInstance *tables)
{
if (tables)
wasm_runtime_free(tables);
}
#if WASM_ENABLE_MULTI_MEMORY != 0 #if WASM_ENABLE_MULTI_MEMORY != 0
static void static void
export_memories_deinstantiate(WASMExportMemInstance *memories) export_memories_deinstantiate(WASMExportMemInstance *memories)
@ -1961,6 +2008,7 @@ execute_free_function(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
return ret; return ret;
} }
#if WASM_ENABLE_COMPONENT_MODEL == 0
static bool static bool
check_linked_symbol(WASMModuleInstance *module_inst, char *error_buf, check_linked_symbol(WASMModuleInstance *module_inst, char *error_buf,
uint32 error_buf_size) uint32 error_buf_size)
@ -2045,6 +2093,7 @@ check_linked_symbol(WASMModuleInstance *module_inst, char *error_buf,
return true; return true;
} }
#endif
#if WASM_ENABLE_JIT != 0 #if WASM_ENABLE_JIT != 0
static bool static bool
@ -2623,7 +2672,7 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
module_inst->export_memory_count = module_inst->export_memory_count =
get_export_count(module, EXPORT_KIND_MEMORY); get_export_count(module, EXPORT_KIND_MEMORY);
#endif #endif
#if WASM_ENABLE_MULTI_MODULE != 0 #if WASM_ENABLE_MULTI_MODULE != 0 || WASM_ENABLE_COMPONENT_MODEL != 0
module_inst->export_table_count = module_inst->export_table_count =
get_export_count(module, EXPORT_KIND_TABLE); get_export_count(module, EXPORT_KIND_TABLE);
#if WASM_ENABLE_TAGS != 0 #if WASM_ENABLE_TAGS != 0
@ -2643,6 +2692,10 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
&& !(module_inst->tables = && !(module_inst->tables =
tables_instantiate(module, module_inst, first_table, tables_instantiate(module, module_inst, first_table,
error_buf, error_buf_size))) error_buf, error_buf_size)))
|| (module_inst->export_table_count > 0
&& !(module_inst->export_tables = export_tables_instantiate(
module, module_inst, module_inst->export_table_count,
error_buf, error_buf_size)))
|| (module_inst->e->function_count > 0 || (module_inst->e->function_count > 0
&& !(module_inst->e->functions = functions_instantiate( && !(module_inst->e->functions = functions_instantiate(
module, module_inst, error_buf, error_buf_size))) module, module_inst, error_buf, error_buf_size)))
@ -2779,11 +2832,11 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
} }
bh_assert(global_data == global_data_end); bh_assert(global_data == global_data_end);
} }
#if WASM_ENABLE_COMPONENT_MODEL == 0
if (!check_linked_symbol(module_inst, error_buf, error_buf_size)) { if (!check_linked_symbol(module_inst, error_buf, error_buf_size)) {
goto fail; goto fail;
} }
#endif
/* Initialize the memory data with data segment section */ /* Initialize the memory data with data segment section */
for (i = 0; i < module->data_seg_count; i++) { for (i = 0; i < module->data_seg_count; i++) {
WASMMemoryInstance *memory = NULL; WASMMemoryInstance *memory = NULL;
@ -3460,6 +3513,7 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
#endif #endif
globals_deinstantiate(module_inst->e->globals); globals_deinstantiate(module_inst->e->globals);
export_functions_deinstantiate(module_inst->export_functions); export_functions_deinstantiate(module_inst->export_functions);
export_tables_deinstantiate(module_inst->export_tables);
#if WASM_ENABLE_TAGS != 0 #if WASM_ENABLE_TAGS != 0
export_tags_deinstantiate(module_inst->e->export_tags); export_tags_deinstantiate(module_inst->e->export_tags);
#endif #endif

View File

@ -28,6 +28,10 @@ typedef struct WASMGlobalInstance WASMGlobalInstance;
typedef struct WASMTagInstance WASMTagInstance; typedef struct WASMTagInstance WASMTagInstance;
#endif #endif
#if WASM_ENABLE_COMPONENT_MODEL != 0
#include "../common/component-model/wasm_component.h"
#endif
/** /**
* When LLVM JIT, WAMR compiler or AOT is enabled, we should ensure that * When LLVM JIT, WAMR compiler or AOT is enabled, we should ensure that
* some offsets of the same field in the interpreter module instance and * some offsets of the same field in the interpreter module instance and
@ -204,7 +208,7 @@ struct WASMGlobalInstance {
#if WASM_ENABLE_GC != 0 #if WASM_ENABLE_GC != 0
WASMRefType *ref_type; WASMRefType *ref_type;
#endif #endif
#if WASM_ENABLE_MULTI_MODULE != 0 #if WASM_ENABLE_MULTI_MODULE != 0 || WASM_ENABLE_COMPONENT_MODEL != 0
/* just for import, keep the reference here */ /* just for import, keep the reference here */
WASMModuleInstance *import_module_inst; WASMModuleInstance *import_module_inst;
WASMGlobalInstance *import_global_inst; WASMGlobalInstance *import_global_inst;
@ -237,7 +241,7 @@ struct WASMFunctionInstance {
WASMFunctionImport *func_import; WASMFunctionImport *func_import;
WASMFunction *func; WASMFunction *func;
} u; } u;
#if WASM_ENABLE_MULTI_MODULE != 0 #if WASM_ENABLE_MULTI_MODULE != 0 || WASM_ENABLE_COMPONENT_MODEL != 0
WASMModuleInstance *import_module_inst; WASMModuleInstance *import_module_inst;
WASMFunctionInstance *import_func_inst; WASMFunctionInstance *import_func_inst;
#endif #endif
@ -249,6 +253,12 @@ struct WASMFunctionInstance {
/* children execution time */ /* children execution time */
uint64 children_exec_time; uint64 children_exec_time;
#endif #endif
#if WASM_ENABLE_COMPONENT_MODEL != 0
WASMModuleInstance *module_instance;
uint32 func_idx;
bool is_canon_func;
WASMComponentCanonType canon_type;
#endif
}; };
#if WASM_ENABLE_TAGS != 0 #if WASM_ENABLE_TAGS != 0
@ -466,6 +476,11 @@ struct WASMModuleInstance {
uint32 default_wasm_stack_size; uint32 default_wasm_stack_size;
uint32 reserved[7]; uint32 reserved[7];
#if WASM_ENABLE_COMPONENT_MODEL != 0
WASMComponentInstance *comp_instance;
uint32 core_instance_idx;
#endif
/* /*
* +------------------------------+ <-- memories * +------------------------------+ <-- memories
* | WASMMemoryInstance[mem_count], mem_count is always 1 for LLVM JIT/AOT * | WASMMemoryInstance[mem_count], mem_count is always 1 for LLVM JIT/AOT

View File

@ -2158,7 +2158,6 @@ wasi_sock_recv(wasm_exec_env_t exec_env, wasi_fd_t sock, iovec_app_t *ri_data,
*ro_data_len = 0; *ro_data_len = 0;
error = wasi_sock_recv_from(exec_env, sock, ri_data, ri_data_len, ri_flags, error = wasi_sock_recv_from(exec_env, sock, ri_data, ri_data_len, ri_flags,
NULL, ro_data_len); NULL, ro_data_len);
return error; return error;
} }

View File

@ -45,6 +45,7 @@ add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE})
| [WAMR_BUILD_AOT_STACK_FRAME](#aot-stack-frame-feature) | AoT stack frame | | [WAMR_BUILD_AOT_STACK_FRAME](#aot-stack-frame-feature) | AoT stack frame |
| [WAMR_BUILD_AOT_VALIDATOR](#aot-validator) | AoT validator | | [WAMR_BUILD_AOT_VALIDATOR](#aot-validator) | AoT validator |
| [WAMR_BUILD_BULK_MEMORY](#bulk-memory-feature) | bulk memory | | [WAMR_BUILD_BULK_MEMORY](#bulk-memory-feature) | bulk memory |
| [WAMR_BUILD_COMPONENT_MODEL](#component-model) | Component Model support |
| [WAMR_BUILD_COPY_CALL_STACK](#copy-call-stack) | copy call stack | | [WAMR_BUILD_COPY_CALL_STACK](#copy-call-stack) | copy call stack |
| [WAMR_BUILD_CUSTOM_NAME_SECTION](#name-section) | name section | | [WAMR_BUILD_CUSTOM_NAME_SECTION](#name-section) | name section |
| [WAMR_BUILD_DEBUG_AOT](#source-debugging-features) | debug AoT | | [WAMR_BUILD_DEBUG_AOT](#source-debugging-features) | debug AoT |
@ -222,6 +223,16 @@ Use fast jit as the first tier and LLVM JIT as the second tier.
- **WAMR_BUILD_BULK_MEMORY**=1/0, default to off. - **WAMR_BUILD_BULK_MEMORY**=1/0, default to off.
### **Component Model**
- **WAMR_BUILD_COMPONENT_MODEL**=1/0, default to on.
> [!NOTE]
> When enabled, the runtime can load and parse WebAssembly Component Model binaries according to the [Component Model MVP specification](https://github.com/WebAssembly/component-model/blob/main/design/mvp/Binary.md). This includes parsing all 13 section types (core custom, core module, core instance, core type, component, instances, aliases, types, canonicals, start, imports, exports, and values).
> [!WARNING]
> Gated features and WebAssembly 3.0 features (eg: rectype, subtype in core type sections) and async/callback canonical options are not yet supported.
### **memory64 feature** ### **memory64 feature**
- **WAMR_BUILD_MEMORY64**=1/0, default to off. - **WAMR_BUILD_MEMORY64**=1/0, default to off.

View File

@ -79,6 +79,11 @@ if (NOT DEFINED WAMR_BUILD_LIBC_WASI)
set (WAMR_BUILD_LIBC_WASI 1) set (WAMR_BUILD_LIBC_WASI 1)
endif () endif ()
if (NOT DEFINED WAMR_BUILD_COMPONENT_MODEL)
# Enable Component Model by default
set (WAMR_BUILD_COMPONENT_MODEL 1)
endif ()
if (NOT DEFINED WAMR_BUILD_FAST_INTERP) if (NOT DEFINED WAMR_BUILD_FAST_INTERP)
# Enable fast interpreter # Enable fast interpreter
set (WAMR_BUILD_FAST_INTERP 1) set (WAMR_BUILD_FAST_INTERP 1)

View File

@ -76,45 +76,7 @@ FetchContent_MakeAvailable(googletest)
include(GoogleTest) include(GoogleTest)
enable_testing() enable_testing()
add_subdirectory(wasm-vm) if(DEFINED UNITTEST_FOLDER AND NOT "${UNITTEST_FOLDER}" STREQUAL "")
add_subdirectory(interpreter) add_subdirectory("${UNITTEST_FOLDER}")
add_subdirectory(wasm-c-api) return()
add_subdirectory(libc-builtin)
add_subdirectory(shared-utils)
add_subdirectory(linear-memory-wasm)
add_subdirectory(linear-memory-aot)
add_subdirectory(linux-perf)
add_subdirectory(gc)
add_subdirectory(tid-allocator)
add_subdirectory(unsupported-features)
add_subdirectory(smart-tests)
add_subdirectory(exception-handling)
add_subdirectory(running-modes)
if(WAMR_BUILD_TARGET STREQUAL "X86_64")
add_subdirectory(aot-stack-frame)
# should enable 32-bit llvm when X86_32
add_subdirectory (aot)
add_subdirectory (custom-section)
add_subdirectory (compilation)
add_subdirectory (memory64)
add_subdirectory (shared-heap)
# HW_BOUND_CHECK is not supported on X86_32
add_subdirectory (runtime-common)
endif() endif()
if(WAMR_BUILD_TARGET STREQUAL "AARCH64")
add_subdirectory(aot-stack-frame)
add_subdirectory (aot)
add_subdirectory (custom-section)
add_subdirectory (compilation)
add_subdirectory (memory64)
add_subdirectory (shared-heap)
add_subdirectory (runtime-common)
endif ()

View File

@ -11,6 +11,10 @@ if (WAMR_BUILD_TARGET STREQUAL "X86_32")
set (WAMRC_OPTION ${WAMRC_OPTION} --target=i386) set (WAMRC_OPTION ${WAMRC_OPTION} --target=i386)
endif () endif ()
find_program(WAT2WASM wat2wasm
PATHS /opt/wabt/bin /usr/local/bin /usr/bin
REQUIRED)
add_custom_target( add_custom_target(
aot-stack-frame-test-wasm ALL aot-stack-frame-test-wasm ALL
@ -20,7 +24,7 @@ add_custom_target(
COMMAND cmake --build ${CMAKE_CURRENT_BINARY_DIR}/build-wamrc COMMAND cmake --build ${CMAKE_CURRENT_BINARY_DIR}/build-wamrc
# Step 2: Compile .wast to .wasm # Step 2: Compile .wast to .wasm
COMMAND /opt/wabt/bin/wat2wasm COMMAND ${WAT2WASM}
-o ${CMAKE_CURRENT_BINARY_DIR}/test.wasm ${CMAKE_CURRENT_LIST_DIR}/test.wast -o ${CMAKE_CURRENT_BINARY_DIR}/test.wasm ${CMAKE_CURRENT_LIST_DIR}/test.wast
# Step 3: Compile .wasm to .aot using wamrc # Step 3: Compile .wasm to .aot using wamrc
@ -38,4 +42,3 @@ add_custom_target(
-n test_aot -n test_aot
${CMAKE_CURRENT_BINARY_DIR}/test.aot ${CMAKE_CURRENT_BINARY_DIR}/test.aot
) )

View File

@ -71,7 +71,7 @@ class WAMRInstance
public: public:
WAMRInstance(WAMRModule &module, uint32_t stack_size = 8192, WAMRInstance(WAMRModule &module, uint32_t stack_size = 8192,
uint32_t heap_size = 8192) uint32_t heap_size = 32768)
{ {
module_inst_ = wasm_runtime_instantiate(module.get(), stack_size, module_inst_ = wasm_runtime_instantiate(module.get(), stack_size,
heap_size, NULL, 0); heap_size, NULL, 0);
@ -336,4 +336,4 @@ class AppData
app_addr_); app_addr_);
} }
uint32_t get_app_addr() const { return app_addr_; } uint32_t get_app_addr() const { return app_addr_; }
}; };

View File

@ -0,0 +1,64 @@
# Copyright (C) 2026 Airbus Defence and Space Romania SRL. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
cmake_minimum_required(VERSION 3.28)
project (test-component)
add_definitions (-DRUN_ON_LINUX)
add_definitions (-Dattr_container_malloc=malloc)
add_definitions (-Dattr_container_free=free)
set (WAMR_BUILD_INTERP 1)
set (WAMR_BUILD_LIBC_WASI 1)
set (WAMR_BUILD_COMPONENT_MODEL 1)
set (WAMR_BUILD_APP_FRAMEWORK 1)
set (WAMR_BUILD_AOT 0)
set (WAMR_BUILD_REF_TYPES 1)
set (WAMR_BUILD_MULTI_MODULE 0)
set (WAMR_BUILD_LOAD_CUSTOM_SECTION 1)
set (WAMR_BUILD_SIMD 0)
include (../unit_common.cmake)
include_directories (${CMAKE_CURRENT_SOURCE_DIR})
file (GLOB_RECURSE source_all ${CMAKE_CURRENT_SOURCE_DIR}/*.cc)
set (UNIT_SOURCE ${source_all})
aux_source_directory(. SRC_LIST)
set (unit_test_sources
${UNIT_SOURCE}
${PLATFORM_SHARED_SOURCE}
${UTILS_SHARED_SOURCE}
${MEM_ALLOC_SHARED_SOURCE}
${NATIVE_INTERFACE_SOURCE}
${LIBC_BUILTIN_SOURCE}
${LIBC_WASI_SOURCE}
${IWASM_COMMON_SOURCE}
${IWASM_COMPONENT_SOURCE}
${IWASM_INTERP_SOURCE}
${UNCOMMON_SHARED_SOURCE}
)
# Now simply link against gtest or gtest_main as needed. Eg
add_executable (component ${unit_test_sources})
target_include_directories(component PRIVATE ${LIBC_WASI_P2_INCLUDE_DIRS})
find_package(Threads REQUIRED)
target_link_libraries (component ${LLVM_AVAILABLE_LIBS} ${WAMR_TEST_OPENSSL_LIBS} gmock gtest_main Threads::Threads)
target_compile_definitions(component PRIVATE WAMR_BUILD_COMPONENT_MODEL=1)
add_custom_command(TARGET component POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/wasm-apps/*.wasm
${CMAKE_CURRENT_BINARY_DIR}/
COMMENT "Copy test wasm files to the directory of google test"
)
gtest_discover_tests(component)

View File

@ -0,0 +1,215 @@
/*
* Copyright (C) 2026 Airbus Defence and Space Romania SRL. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "helpers.h"
#include "wasm_component.h"
#include "bh_read_file.h"
#include <cstdio>
#include <cstring>
#include <fstream>
#include <sstream>
#include <algorithm>
ComponentHelper::ComponentHelper() {}
void
ComponentHelper::do_setup()
{
printf("Starting setup\n");
memset(&init_args, 0, sizeof(RuntimeInitArgs));
init_args.mem_alloc_type = Alloc_With_Pool;
init_args.mem_alloc_option.pool.heap_buf = global_heap_buf;
init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf);
if (!wasm_runtime_full_init(&init_args)) {
printf("Failed to initialize WAMR runtime.\n");
runtime_init = false;
} else {
runtime_init = true;
}
printf("Ending setup\n");
}
void
ComponentHelper::do_teardown()
{
printf("Starting teardown\n");
if (component_init) {
printf("Starting to unload component\n");
if (component) {
wasm_component_free(component);
component = NULL;
}
if (component_raw) {
BH_FREE(component_raw);
component_raw = NULL;
}
component_init = false;
}
if (runtime_init) {
printf("Starting to destroy runtime\n");
wasm_runtime_destroy();
runtime_init = false;
}
printf("Ending teardown\n");
}
bool
ComponentHelper::read_wasm_file(const char *wasm_file) {
const char *file = wasm_file;
printf("Reading wasm component\n");
component_raw =
(unsigned char *)bh_read_file_to_buffer(file, &wasm_file_size);
if (!component_raw) {
printf("Failed to read wasm component from file\n");
return false;
}
printf("Loaded wasm component size: %u\n", wasm_file_size);
return true;
}
bool
ComponentHelper::load_component()
{
printf("Loading wasm component in memory\n");
// Allocate component structure if not already allocated
if (!component) {
component = (WASMComponent *)wasm_runtime_malloc(sizeof(WASMComponent));
if (!component) {
printf("Failed to allocate component structure\n");
return false;
}
memset(component, 0, sizeof(WASMComponent));
}
// First decode the header
if (!wasm_decode_header(component_raw, wasm_file_size, &component->header)) {
printf("Not a valid WASM component file (header mismatch).\n");
BH_FREE(component_raw);
component_raw = NULL;
wasm_runtime_free(component);
component = NULL;
return false;
}
// Second check if it's a valid component
if (!is_wasm_component(component->header)) {
printf("Not a valid WASM component file (header mismatch).\n");
BH_FREE(component_raw);
component_raw = NULL;
wasm_runtime_free(component);
component = NULL;
return false;
}
// Parse the component sections
LoadArgs load_args = {0, false, false, false, false};
char name_buf[32];
std::memset(name_buf, 0, sizeof(name_buf));
std::snprintf(name_buf, sizeof(name_buf), "%s", "Test Component");
load_args.name = name_buf; // provide non-null, mutable name as required by loader
load_args.wasm_binary_freeable = false;
load_args.clone_wasm_binary = false;
load_args.no_resolve = false;
load_args.is_component = true;
if (!wasm_component_parse_sections(component_raw, wasm_file_size, component, &load_args, 0)) {
printf("Failed to parse WASM component sections.\n");
BH_FREE(component_raw);
component_raw = NULL;
wasm_runtime_free(component);
component = NULL;
return false;
}
printf("Component loaded successfully with %u sections\n", component->section_count);
component_init = true;
printf("Finished to load wasm component\n");
return true;
}
uint32_t ComponentHelper::get_section_count() const {
if (!component) {
return 0;
}
return component->section_count;
}
bool ComponentHelper::is_loaded() const {
return component_init && component && component->section_count > 0;
}
void ComponentHelper::reset_component() {
if (component) {
wasm_component_free(component);
component = NULL;
}
component_init = false;
}
std::vector<WASMComponentSection*> ComponentHelper::get_section(WASMComponentSectionType section_id) const {
if (section_id < 0) return {};
if (!component) return {};
std::vector<WASMComponentSection*> sections;
for(uint32_t i = 0; i < component->section_count; i++) {
if (component->sections[i].id == section_id) {
sections.push_back(&component->sections[i]);
}
}
return sections;
}
void ComponentHelper::load_memory_offsets(const std::string& filename){
std::ifstream file(filename);
if (!file.is_open()) {
throw std::runtime_error("Could not open layout file: " + filename);
}
std::string line;
while (std::getline(file, line)) {
line.erase(std::remove(line.begin(), line.end(), '"'), line.end());
if (line.empty()) continue;
std::stringstream ss(line);
std::string segment;
while (std::getline(ss, segment, ',')) {
size_t eqPos = segment.find('=');
if (eqPos != std::string::npos) {
std::string key = segment.substr(0, eqPos);
key.erase(0, key.find_first_not_of(" \t\n\r"));
std::string valueStr = segment.substr(eqPos + 1);
uint32_t value = std::stoul(valueStr);
// Store
offsets[key] = value;
}
}
}
}
uint32_t ComponentHelper::get_memory_offsets(const std::string& key) {
if (offsets.find(key) == offsets.end()) {
throw std::runtime_error("Key not found in layout: " + key);
}
return offsets[key];
}

View File

@ -0,0 +1,57 @@
/*
* Copyright (C) 2026 Airbus Defence and Space Romania SRL. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef HELPERS_H
#define HELPERS_H
#include "wasm_export.h"
#include "wasm_component.h"
#include "wasm_memory.h"
#include <string>
#include <unordered_map>
#include <cstring>
#include <vector>
#include <stdint.h>
#define HEAP_SIZE (100 * 1024 * 1024) // 100 MB
class ComponentHelper {
public:
RuntimeInitArgs init_args;
unsigned char *component_raw = NULL;
WASMComponent *component = NULL;
uint32_t wasm_file_size = 0;
uint32_t stack_size = 16 * 1024; // 16 KB
uint32_t heap_size = HEAP_SIZE; // 100 MB
char error_buf[128];
char global_heap_buf[HEAP_SIZE]; // 100 MB
bool runtime_init = false;
bool component_init = false;
bool component_instantiated = false;
std::unordered_map<std::string, uint32_t> offsets; // Memory offsets
ComponentHelper();
bool read_wasm_file(const char *wasm_file);
bool load_component();
// Helpers for tests
uint32_t get_section_count() const;
bool is_loaded() const;
void reset_component();
void do_setup();
void do_teardown();
std::vector<WASMComponentSection*> get_section(WASMComponentSectionType section_id) const;
void load_memory_offsets(const std::string& filename); // Loading the memory offsets from text file
uint32_t get_memory_offsets(const std::string& key); // Get memory offsets from map
};
#endif

View File

@ -0,0 +1,144 @@
/*
* Copyright (C) 2026 Airbus Defence and Space Romania SRL. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include <gtest/gtest.h>
#include "helpers.h"
#include <vector>
#include <memory>
#include <cstdio>
#include <cstring>
#include <string>
static std::vector<std::string> component_files = {
"add.wasm",
"complex_with_host.wasm",
"complex.wasm",
"logging-service.component.wasm",
"processor_and_logging_merged_wac_plug.wasm",
"processor-service.component.wasm",
"sampletypes.wasm"
};
class BinaryParserTest : public testing::Test
{
public:
std::unique_ptr<ComponentHelper> helper;
BinaryParserTest() {}
~BinaryParserTest() {}
virtual void SetUp() {
helper = std::make_unique<ComponentHelper>();
helper->do_setup();
}
virtual void TearDown() {
helper->do_teardown();
helper = nullptr;
}
};
TEST_F(BinaryParserTest, TestAllComponentsLoadAndUnload)
{
// Load and unload every listed component
for (const std::string &name : component_files) {
helper->reset_component();
std::string path = name;
printf("LoadAndUnloadComponent: %s\n", path.c_str());
bool ret = helper->read_wasm_file(path.c_str());
ASSERT_TRUE(ret);
ret = helper->load_component();
ASSERT_TRUE(ret);
ASSERT_TRUE(helper->is_loaded());
// Unload component and free raw buffer to simulate full unload
helper->reset_component();
if (helper->component_raw) {
BH_FREE(helper->component_raw);
helper->component_raw = NULL;
}
ASSERT_FALSE(helper->is_loaded());
ASSERT_EQ(helper->get_section_count(), 0u);
}
}
TEST_F(BinaryParserTest, TestLoadCorruptComponent)
{
// Corrupt header and expect load failure
helper->reset_component();
bool ret = helper->read_wasm_file((std::string("add.wasm").c_str()));
ASSERT_TRUE(ret);
ASSERT_TRUE(helper->component_raw != NULL);
helper->component_raw[0] ^= 0xFF; // corrupt
ret = helper->load_component();
ASSERT_FALSE(ret);
}
TEST_F(BinaryParserTest, TestDecodeHeaderValid)
{
helper->reset_component();
bool ret = helper->read_wasm_file("logging-service.component.wasm");
ASSERT_TRUE(ret);
ASSERT_TRUE(helper->component_raw != NULL);
WASMHeader header;
bool ok = wasm_decode_header(helper->component_raw,
helper->wasm_file_size,
&header);
ASSERT_TRUE(ok);
ASSERT_EQ(header.magic, WASM_MAGIC_NUMBER);
ASSERT_EQ(header.version, WASM_COMPONENT_VERSION);
ASSERT_EQ(header.layer, WASM_COMPONENT_LAYER);
}
TEST_F(BinaryParserTest, TestDecodeHeaderInvalid)
{
helper->reset_component();
bool ret = helper->read_wasm_file("logging-service.component.wasm");
ASSERT_TRUE(ret);
ASSERT_TRUE(helper->component_raw != NULL);
std::vector<uint8_t> corrupted(helper->component_raw,
helper->component_raw + helper->wasm_file_size);
corrupted[0] ^= 0xFF; // corrupt magic byte
WASMHeader header;
ret = wasm_decode_header(corrupted.data(),
(uint32_t)corrupted.size(),
&header);
ASSERT_TRUE(ret);
ASSERT_FALSE(is_wasm_component(header));
}
TEST_F(BinaryParserTest, TestSectionAliasIndividual)
{
helper->reset_component();
bool ret = helper->read_wasm_file((std::string("add.wasm").c_str()));
ASSERT_TRUE(ret);
ASSERT_TRUE(helper->component_raw != NULL);
ret = helper->load_component();
ASSERT_TRUE(ret);
ASSERT_TRUE(helper->is_loaded());
std::string check_against = "test:project/my-interface@0.1.0#add";
auto sections = helper->get_section(WASM_COMP_SECTION_ALIASES);
bool found = false;
for (auto section: sections) {
ASSERT_EQ(section->id, WASM_COMP_SECTION_ALIASES);
WASMComponentAliasSection *alias_section = section->parsed.alias_section;
for (uint32_t id = 0; id < alias_section->count; id++) {
WASMComponentAliasDefinition* alias_def = &alias_section->aliases[id];
if (alias_def->alias_target_type == WASM_COMP_ALIAS_TARGET_CORE_EXPORT) {
if (std::string{alias_def->target.core_exported.name->name} == check_against) {
found = true;
}
}
}
}
ASSERT_TRUE(found);
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -14,7 +14,7 @@ file_names=("mem_grow_out_of_bounds_01" "mem_grow_out_of_bounds_02"
WORKDIR="$PWD" WORKDIR="$PWD"
WAMRC_ROOT_DIR="${WORKDIR}/../../../wamr-compiler" WAMRC_ROOT_DIR="${WORKDIR}/../../../wamr-compiler"
WAMRC="${WAMRC_ROOT_DIR}/build/wamrc" WAMRC="${WAMRC_ROOT_DIR}/build/wamrc"
WAST2WASM="/opt/wabt/bin/wat2wasm" WAST2WASM="$(command -v wat2wasm)" || { echo "wat2wasm not found"; exit 1; }
# build wamrc if not exist # build wamrc if not exist
if [ ! -s "$WAMRC" ]; then if [ ! -s "$WAMRC" ]; then

View File

@ -11,7 +11,7 @@ file_names=("main")
WORKDIR="$PWD" WORKDIR="$PWD"
WAMRC_ROOT_DIR="${WORKDIR}/../../../wamr-compiler" WAMRC_ROOT_DIR="${WORKDIR}/../../../wamr-compiler"
WAMRC="${WAMRC_ROOT_DIR}/build/wamrc" WAMRC="${WAMRC_ROOT_DIR}/build/wamrc"
WAST2WASM="/opt/wabt/bin/wat2wasm" WAST2WASM="$(command -v wat2wasm)" || { echo "wat2wasm not found"; exit 1; }
# build wamrc if not exist # build wamrc if not exist
if [ ! -s "$WAMRC" ]; then if [ ! -s "$WAMRC" ]; then
@ -28,4 +28,3 @@ for file_name in "${file_names[@]}"; do
# compile wasm to aot # compile wasm to aot
$WAMRC -o "wasm-apps/${file_name}.aot" "wasm-apps/${file_name}.wasm" $WAMRC -o "wasm-apps/${file_name}.aot" "wasm-apps/${file_name}.wasm"
done done

View File

@ -71,7 +71,14 @@
char *current_dir = getcwd(NULL, 0); char *current_dir = getcwd(NULL, 0);
CWD = std::string(current_dir); CWD = std::string(current_dir);
free(current_dir); free(current_dir);
WASM_FILE = CWD + "/function_invocation_test.wasm"; const char *substr = "wasm-micro-runtime";
const char *pos = strstr(CWD.c_str(), substr);
if (pos) {
size_t prefix_len = (pos - CWD.c_str()) + strlen(substr);
WASM_FILE = CWD.substr(0, prefix_len) + "/tests/unit/smart-tests/interpreter/wasm-apps/function_invocation_test.wasm";
} else {
WASM_FILE = CWD + "/function_invocation_test.wasm";
}
memset(&init_args, 0, sizeof(RuntimeInitArgs)); memset(&init_args, 0, sizeof(RuntimeInitArgs));
init_args.mem_alloc_type = Alloc_With_System_Allocator; init_args.mem_alloc_type = Alloc_With_System_Allocator;
@ -452,3 +459,4 @@
bool success = wasm_runtime_call_wasm(exec_env, func, 2, wasm_argv); bool success = wasm_runtime_call_wasm(exec_env, func, 2, wasm_argv);
ASSERT_TRUE(success); ASSERT_TRUE(success);
} }

View File

@ -29,11 +29,13 @@ pushd ${SRC_COV_DIR} > /dev/null 2>&1
# collect all code coverage data # collect all code coverage data
# for lcov 2.x: ignore-errors mismatch,negative # for lcov 2.x: ignore-errors mismatch,negative
lcov -q -o ${SRC_TEMP_COV_FILE} -c -d . --rc lcov_branch_coverage=1 --rc geninfo_unexecuted_blocks=1 lcov -q -o ${SRC_TEMP_COV_FILE} -c -d . --rc branch_coverage=1 --rc geninfo_unexecuted_blocks=1 \
--ignore-errors mismatch,negative
# extract code coverage data of WAMR source files # extract code coverage data of WAMR source files
# for lcov 2.x: ignore-errors unused # for lcov 2.x: ignore-errors unused
lcov -q -r ${SRC_TEMP_COV_FILE} -o ${SRC_TEMP_COV_FILE} \ lcov -q -r ${SRC_TEMP_COV_FILE} -o ${SRC_TEMP_COV_FILE} \
-rc lcov_branch_coverage=1\ -rc branch_coverage=1 \
--ignore-errors unused \
"*/usr/*" "*/_deps/*" "*/deps/*" "*/tests/unit/*" \ "*/usr/*" "*/_deps/*" "*/deps/*" "*/tests/unit/*" \
"*/llvm/include/*" "*/include/llvm/*" "*/samples/*" \ "*/llvm/include/*" "*/include/llvm/*" "*/samples/*" \
"*/test-tools/*" "*/tests/standalone/*" "*/tests/*" "*/test-tools/*" "*/tests/standalone/*" "*/tests/*"
@ -41,7 +43,8 @@ lcov -q -r ${SRC_TEMP_COV_FILE} -o ${SRC_TEMP_COV_FILE} \
if [[ -s ${SRC_TEMP_COV_FILE} ]]; then if [[ -s ${SRC_TEMP_COV_FILE} ]]; then
if [[ -s ${DST_COV_FILE} ]]; then if [[ -s ${DST_COV_FILE} ]]; then
# merge code coverage data # merge code coverage data
lcov --rc lcov_branch_coverage=1 \ lcov --rc branch_coverage=1 \
--ignore-errors mismatch,negative,unused \
--add-tracefile ${SRC_TEMP_COV_FILE} \ --add-tracefile ${SRC_TEMP_COV_FILE} \
-a ${DST_COV_FILE} -o ${SRC_COV_FILE} -a ${DST_COV_FILE} -o ${SRC_COV_FILE}
# backup the original lcov file # backup the original lcov file
@ -64,7 +67,8 @@ if [[ -s ${SRC_TEMP_COV_FILE} ]]; then
# generate html output for merged code coverage data # generate html output for merged code coverage data
rm -fr ${DST_COV_DIR}/wamr-lcov rm -fr ${DST_COV_DIR}/wamr-lcov
genhtml -q -t "WAMR Code Coverage" \ genhtml -q -t "WAMR Code Coverage" \
--rc lcov_branch_coverage=1 --prefix=${prefix_full_path} \ --rc branch_coverage=1 --prefix=${prefix_full_path} \
--ignore-errors source,mismatch,unmapped \
-o ${DST_COV_DIR}/wamr-lcov \ -o ${DST_COV_DIR}/wamr-lcov \
${DST_COV_FILE} ${DST_COV_FILE}

View File

@ -22,6 +22,8 @@ function help()
echo " riscv32|riscv32_ilp32f|riscv32_ilp32d|riscv64|" echo " riscv32|riscv32_ilp32f|riscv32_ilp32d|riscv64|"
echo " riscv64_lp64f|riscv64_lp64d|aarch64|aarch64_vfp)" echo " riscv64_lp64f|riscv64_lp64d|aarch64|aarch64_vfp)"
echo "-t set compile type of iwasm(classic-interp|fast-interp|jit|aot|fast-jit|multi-tier-jit)" echo "-t set compile type of iwasm(classic-interp|fast-interp|jit|aot|fast-jit|multi-tier-jit)"
echo "-u choose unit test folder(s) to run - only available with -s flag set to 'unit'"
echo " accepts multiple folders: -u canonical-abi component-instantiation"
echo "-M enable multi module feature" echo "-M enable multi module feature"
echo "-p enable multi thread feature" echo "-p enable multi thread feature"
echo "-S enable SIMD feature" echo "-S enable SIMD feature"
@ -58,6 +60,8 @@ WABT_BINARY_RELEASE="NO"
TYPE=("classic-interp" "fast-interp" "jit" "aot" "fast-jit" "multi-tier-jit") TYPE=("classic-interp" "fast-interp" "jit" "aot" "fast-jit" "multi-tier-jit")
#default target #default target
TARGET="X86_64" TARGET="X86_64"
UNITTEST_FOUND="NO"
UNITTEST_FOLDERS=()
ENABLE_WASI_THREADS=0 ENABLE_WASI_THREADS=0
ENABLE_MULTI_MODULE=0 ENABLE_MULTI_MODULE=0
ENABLE_MULTI_THREAD=0 ENABLE_MULTI_THREAD=0
@ -93,7 +97,7 @@ REQUIREMENT_NAME=""
# Initialize an empty array for subrequirement IDs # Initialize an empty array for subrequirement IDs
SUBREQUIREMENT_IDS=() SUBREQUIREMENT_IDS=()
while getopts ":s:cabgvt:m:MCpSXexwWEPGQF:j:T:r:A:N" opt while getopts ":s:cu:abgvt:m:MCpSXexwWEPGQF:j:T:r:A:N" opt
do do
OPT_PARSED="TRUE" OPT_PARSED="TRUE"
case $opt in case $opt in
@ -110,6 +114,7 @@ do
OPTIND=$((OPTIND+1)) OPTIND=$((OPTIND+1))
eval "nxarg=\${$((OPTIND))}" eval "nxarg=\${$((OPTIND))}"
done done
UNITTEST_FOUND="YES"
echo "test following cases: ${TEST_CASE_ARR[@]}" echo "test following cases: ${TEST_CASE_ARR[@]}"
;; ;;
c) c)
@ -120,6 +125,21 @@ do
echo "cleaned all reports and temp files" echo "cleaned all reports and temp files"
fi fi
exit 0;; exit 0;;
u)
if [ ${UNITTEST_FOUND} == "YES" ]; then
UNITTEST_FOLDERS+=($OPTARG)
eval "nxarg=\${$((OPTIND))}"
while [[ "${nxarg}" != -* && ${nxarg} ]]; do
UNITTEST_FOLDERS+=(${nxarg})
OPTIND=$((OPTIND+1))
eval "nxarg=\${$((OPTIND))}"
done
echo "running unit tests: ${UNITTEST_FOLDERS[@]}"
else
echo "suite flag -s is not set to unit tests"
exit 1
fi
;;
a) a)
TEST_ALL_AOT_RUNTIME="all" TEST_ALL_AOT_RUNTIME="all"
echo "test all runtimes in sightglass_aot" echo "test all runtimes in sightglass_aot"
@ -129,11 +149,11 @@ do
echo "use a WABT binary release instead of compiling from source code" echo "use a WABT binary release instead of compiling from source code"
;; ;;
t) t)
echo "set compile type of wamr " ${OPTARG} echo "set compile type of wamr:" ${OPTARG}
if [[ ${OPTARG} != "classic-interp" && ${OPTARG} != "fast-interp" \ if [[ ${OPTARG} != "classic-interp" && ${OPTARG} != "fast-interp" \
&& ${OPTARG} != "jit" && ${OPTARG} != "aot" && ${OPTARG} != "jit" && ${OPTARG} != "aot"
&& ${OPTARG} != "fast-jit" && ${OPTARG} != "multi-tier-jit" ]]; then && ${OPTARG} != "fast-jit" && ${OPTARG} != "multi-tier-jit" ]]; then
echo "*----- please varify a type of compile when using -t! -----*" echo "*----- please verify a type of compile when using -t! -----*"
help help
exit 1 exit 1
fi fi
@ -141,7 +161,7 @@ do
TYPE=(${OPTARG}) TYPE=(${OPTARG})
;; ;;
m) m)
echo "set compile target of wamr" ${OPTARG} echo "set compile target of wamr:" ${OPTARG}
TARGET=$(echo "$OPTARG" | tr '[a-z]' '[A-Z]') # set target to uppercase if input x86_32 or x86_64 --> X86_32 and X86_64 TARGET=$(echo "$OPTARG" | tr '[a-z]' '[A-Z]') # set target to uppercase if input x86_32 or x86_64 --> X86_32 and X86_64
;; ;;
w) w)
@ -331,14 +351,118 @@ function unit_test()
echo "Now start unit tests" echo "Now start unit tests"
cd ${WORK_DIR} cd ${WORK_DIR}
rm -fr unittest-build local UNIT_DIR="${WORK_DIR}/../../unit"
local FAILED_LOG_DIR="${WORK_DIR}/unittest-failed-logs"
rm -rf "$FAILED_LOG_DIR"
echo "Build unit test"
touch ${REPORT_DIR}/unit_test_report.txt touch ${REPORT_DIR}/unit_test_report.txt
cmake -S ${WORK_DIR}/../../unit -B unittest-build \
-DCOLLECT_CODE_COVERAGE=${COLLECT_CODE_COVERAGE} local folders=()
cmake --build unittest-build if [[ ${#UNITTEST_FOLDERS[@]} -gt 0 ]]; then
ctest --test-dir unittest-build --output-on-failure | tee -a ${REPORT_DIR}/unit_test_report.txt folders=("${UNITTEST_FOLDERS[@]}")
else
folders=(
wasm-vm interpreter wasm-c-api libc-builtin shared-utils
linear-memory-wasm linear-memory-aot
linux-perf gc tid-allocator component unsupported-features smart-tests
exception-handling
)
if [[ "${TARGET}" != "X86_32" ]]; then
folders+=(
aot-stack-frame aot custom-section compilation running-modes
memory64 shared-heap runtime-common
)
fi
fi
local summaries=()
local total_passed=0
local total_failed=0
local total_tests=0
for folder in "${folders[@]}"; do
echo ""
echo "========== Unit test: $folder =========="
local build_dir="${WORK_DIR}/unittest-build-${folder}"
rm -rf "$build_dir"
mkdir -p "$build_dir"
cd "$build_dir"
local build_ok=true
cmake "${UNIT_DIR}" \
-DCOLLECT_CODE_COVERAGE=${COLLECT_CODE_COVERAGE} \
-DUNITTEST_FOLDER="${folder}" || build_ok=false
if $build_ok; then
make -j || build_ok=false
fi
if ! $build_ok; then
summaries+=("$folder: BUILD FAILED")
total_failed=$((total_failed + 1))
total_tests=$((total_tests + 1))
cd ${WORK_DIR}
continue
fi
local tmplog=$(mktemp)
set +e
script -qec "make test" /dev/null | tee "$tmplog"
local test_exit=${PIPESTATUS[0]}
set -e
local output=$(sed 's/\x1b\[[0-9;]*[a-zA-Z]//g' "$tmplog" | tr -d '\r')
rm -f "$tmplog"
local result_line=$(echo "$output" | grep -E '[0-9]+% tests passed' || true)
if [[ -n "$result_line" ]]; then
local failed=$(echo "$result_line" | sed -E 's/.* ([0-9]+) tests failed.*/\1/')
local count=$(echo "$result_line" | sed -E 's/.* out of ([0-9]+)/\1/')
local passed=$((count - failed))
total_passed=$((total_passed + passed))
total_failed=$((total_failed + failed))
total_tests=$((total_tests + count))
if [[ "$failed" -gt 0 ]]; then
mkdir -p "$FAILED_LOG_DIR"
local log_path="$FAILED_LOG_DIR/${folder}-LastTest.log"
local ctest_log="${build_dir}/Testing/Temporary/LastTest.log"
if [[ -f "$ctest_log" ]]; then
cp "$ctest_log" "$log_path"
fi
summaries+=("$folder: $passed passed, $failed failed out of $count")
summaries+=(" Log: $log_path")
local failed_names=$(echo "$output" | sed -n '/The following tests FAILED:/,/^$/p' | grep -E '^\s+[0-9]' || true)
if [[ -n "$failed_names" ]]; then
summaries+=(" FAILED:$failed_names")
fi
else
summaries+=("$folder: $passed passed, $failed failed out of $count")
fi
else
summaries+=("$folder: NO RESULT (exit code $test_exit)")
fi
cd ${WORK_DIR}
done
echo ""
echo "======================================"
echo " UNIT TEST SUMMARY"
echo "======================================"
for s in "${summaries[@]}"; do
echo " $s"
done
echo "--------------------------------------"
echo " TOTAL: $total_passed passed, $total_failed failed out of $total_tests"
echo "======================================" | tee -a ${REPORT_DIR}/unit_test_report.txt
if [[ $total_failed -gt 0 ]]; then
echo "Unit tests FAILED" | tee -a ${REPORT_DIR}/unit_test_report.txt
exit 1
fi
echo "Finish unit tests" echo "Finish unit tests"
} }
@ -411,7 +535,7 @@ function setup_wabt()
echo "wabt not exist, clone it from github" echo "wabt not exist, clone it from github"
git clone --recursive https://github.com/WebAssembly/wabt git clone --recursive https://github.com/WebAssembly/wabt
fi fi
echo "upate wabt" echo "update wabt"
cd wabt \ cd wabt \
&& git fetch origin \ && git fetch origin \
&& git reset --hard origin/main \ && git reset --hard origin/main \
@ -882,8 +1006,10 @@ function collect_coverage()
fi fi
pushd ${WORK_DIR} > /dev/null 2>&1 pushd ${WORK_DIR} > /dev/null 2>&1
echo "Collect code coverage of iwasm" if [[ $1 != "unit" && -d ${IWASM_LINUX_ROOT_DIR}/build ]]; then
./collect_coverage.sh ${CODE_COV_FILE} ${IWASM_LINUX_ROOT_DIR}/build echo "Collect code coverage of iwasm"
./collect_coverage.sh ${CODE_COV_FILE} ${IWASM_LINUX_ROOT_DIR}/build
fi
if [[ $1 == "llvm-aot" ]]; then if [[ $1 == "llvm-aot" ]]; then
echo "Collect code coverage of wamrc" echo "Collect code coverage of wamrc"
./collect_coverage.sh ${CODE_COV_FILE} ${WAMR_DIR}/wamr-compiler/build ./collect_coverage.sh ${CODE_COV_FILE} ${WAMR_DIR}/wamr-compiler/build
@ -891,7 +1017,13 @@ function collect_coverage()
for suite in "${TEST_CASE_ARR[@]}"; do for suite in "${TEST_CASE_ARR[@]}"; do
if [[ ${suite} = "unit" ]]; then if [[ ${suite} = "unit" ]]; then
echo "Collect code coverage of unit test" echo "Collect code coverage of unit test"
./collect_coverage.sh ${CODE_COV_FILE} ${WORK_DIR}/unittest-build if [[ ${#UNITTEST_FOLDERS[@]} -gt 0 ]]; then
for folder in "${UNITTEST_FOLDERS[@]}"; do
./collect_coverage.sh ${CODE_COV_FILE} ${WORK_DIR}/unittest-build-${folder}
done
else
./collect_coverage.sh ${CODE_COV_FILE} ${WORK_DIR}/unittest-build
fi
break break
fi fi
done done
@ -1092,6 +1224,10 @@ function trigger()
# if we're running the wasi certification tests. # if we're running the wasi certification tests.
if [[ $TEST_CASE_ARR ]]; then if [[ $TEST_CASE_ARR ]]; then
for test in "${TEST_CASE_ARR[@]}"; do for test in "${TEST_CASE_ARR[@]}"; do
if [[ "$test" == "unit" ]]; then
EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_LIBC_WASI=1 -DWAMR_BUILD_COMPONENT_MODEL=1"
break
fi
if [[ "$test" == "wasi_certification" ]]; then if [[ "$test" == "wasi_certification" ]]; then
EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_WASI_TEST=1" EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_WASI_TEST=1"
fi fi