mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2026-04-18 10:17:38 +00:00
Merge 70a7bbb03f into fcec30e933
This commit is contained in:
commit
ffb26bff67
10
.clang-tidy
10
.clang-tidy
|
|
@ -4,6 +4,12 @@
|
|||
|
||||
# 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: >
|
||||
-*,
|
||||
|
|
@ -11,6 +17,9 @@ Checks: >
|
|||
cert-*,
|
||||
clang-analyzer-*,
|
||||
concurrency-*,
|
||||
cppcoreguidelines-init-variables,
|
||||
cppcoreguidelines-narrowing-conversions,
|
||||
cppcoreguidelines-pro-type-cstyle-cast,
|
||||
misc-*,
|
||||
modernize-*,
|
||||
performance-*,
|
||||
|
|
@ -18,6 +27,7 @@ Checks: >
|
|||
readability-*,
|
||||
-bugprone-easily-swappable-parameters,
|
||||
-bugprone-macro-parentheses,
|
||||
-misc-include-cleaner,
|
||||
-misc-no-recursion,
|
||||
-misc-unused-parameters,
|
||||
-readability-braces-around-statements,
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ jobs:
|
|||
- name: Build wamrc
|
||||
run: |
|
||||
mkdir build && cd build
|
||||
cmake .. -DCMAKE_C_FLAGS="-Werror"
|
||||
cmake .. -DCMAKE_C_FLAGS="-Werror" -DWAMR_BUILD_COMPONENT_MODEL=0
|
||||
cmake --build . --config Release --parallel 4
|
||||
working-directory: wamr-compiler
|
||||
|
||||
|
|
@ -295,7 +295,7 @@ jobs:
|
|||
if: matrix.platform == 'linux'
|
||||
run: |
|
||||
mkdir build && cd build
|
||||
cmake .. -DCMAKE_C_FLAGS="-Werror" ${{ matrix.make_options_run_mode }} ${{ matrix.make_options_feature }} ${{ matrix.extra_options}}
|
||||
cmake .. -DCMAKE_C_FLAGS="-Werror" -DWAMR_BUILD_COMPONENT_MODEL=0 ${{ matrix.make_options_run_mode }} ${{ matrix.make_options_feature }} ${{ matrix.extra_options}}
|
||||
cmake --build . --config Release --parallel 4
|
||||
working-directory: product-mini/platforms/${{ matrix.platform }}
|
||||
|
||||
|
|
@ -303,7 +303,7 @@ jobs:
|
|||
if: matrix.platform == 'android'
|
||||
run: |
|
||||
mkdir build && cd build
|
||||
cmake .. -DCMAKE_C_FLAGS="-Werror" ${{ matrix.make_options_run_mode }} ${{ matrix.make_options_feature }} \
|
||||
cmake .. -DCMAKE_C_FLAGS="-Werror" -DWAMR_BUILD_COMPONENT_MODEL=0 ${{ matrix.make_options_run_mode }} ${{ matrix.make_options_feature }} \
|
||||
-DWAMR_BUILD_TARGET=X86_64
|
||||
cmake --build . --config Release --parallel 4
|
||||
working-directory: product-mini/platforms/${{ matrix.platform }}
|
||||
|
|
@ -348,7 +348,7 @@ jobs:
|
|||
- name: Build wamrc
|
||||
run: |
|
||||
mkdir build && cd build
|
||||
cmake ..
|
||||
cmake .. -DWAMR_BUILD_COMPONENT_MODEL=0
|
||||
cmake --build . --config Release --parallel 4
|
||||
working-directory: wamr-compiler
|
||||
|
||||
|
|
@ -472,7 +472,7 @@ jobs:
|
|||
if: (!endsWith(matrix.make_options, '_INTERP_BUILD_OPTIONS'))
|
||||
run: |
|
||||
mkdir build && cd build
|
||||
cmake ..
|
||||
cmake .. -DWAMR_BUILD_COMPONENT_MODEL=0
|
||||
cmake --build . --config Release --parallel 4
|
||||
working-directory: wamr-compiler
|
||||
|
||||
|
|
@ -523,7 +523,7 @@ jobs:
|
|||
- name: Build wamrc
|
||||
run: |
|
||||
mkdir build && cd build
|
||||
cmake ..
|
||||
cmake .. -DWAMR_BUILD_COMPONENT_MODEL=0
|
||||
cmake --build . --config Release --parallel 4
|
||||
working-directory: wamr-compiler
|
||||
|
||||
|
|
|
|||
4
.github/workflows/compilation_on_windows.yml
vendored
4
.github/workflows/compilation_on_windows.yml
vendored
|
|
@ -95,7 +95,7 @@ jobs:
|
|||
run: |
|
||||
cd product-mini/platforms/windows
|
||||
mkdir build && cd build
|
||||
cmake .. ${{ matrix.build_options }}
|
||||
cmake .. -DWAMR_BUILD_COMPONENT_MODEL=0 ${{ matrix.build_options }}
|
||||
cmake --build . --config Release --parallel 4
|
||||
|
||||
build_wamrc:
|
||||
|
|
@ -130,7 +130,7 @@ jobs:
|
|||
|
||||
- name: Build wamrc
|
||||
run: |
|
||||
cmake -S . -B build
|
||||
cmake -S . -B build -DWAMR_BUILD_COMPONENT_MODEL=0
|
||||
cmake --build build --config Release --parallel 4
|
||||
working-directory: wamr-compiler
|
||||
|
||||
|
|
|
|||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -13,6 +13,7 @@
|
|||
*.so
|
||||
.clangd
|
||||
.DS_Store
|
||||
code_analysis_report.log
|
||||
*.o
|
||||
.aider*
|
||||
|
||||
|
|
|
|||
|
|
@ -79,6 +79,11 @@ if (NOT DEFINED WAMR_BUILD_LIBC_WASI)
|
|||
set (WAMR_BUILD_LIBC_WASI 1)
|
||||
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)
|
||||
# Enable fast interpreter
|
||||
set (WAMR_BUILD_FAST_INTERP 1)
|
||||
|
|
|
|||
|
|
@ -779,7 +779,13 @@ if (WAMR_BUILD_BRANCH_HINTS EQUAL 1)
|
|||
message (" Branch hints enabled")
|
||||
add_definitions(-DWASM_ENABLE_BRANCH_HINTS=1)
|
||||
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.
|
||||
########################################
|
||||
|
|
|
|||
|
|
@ -87,6 +87,10 @@ if (WAMR_BUILD_GC EQUAL 1)
|
|||
set (WAMR_BUILD_REF_TYPES 1)
|
||||
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)
|
||||
include (${IWASM_DIR}/libraries/libc-builtin/libc_builtin.cmake)
|
||||
endif ()
|
||||
|
|
@ -219,6 +223,7 @@ set (source_all
|
|||
${IWASM_COMPL_SOURCE}
|
||||
${IWASM_FAST_JIT_SOURCE}
|
||||
${IWASM_GC_SOURCE}
|
||||
${IWASM_COMPONENT_SOURCE}
|
||||
${LIB_WASI_THREADS_SOURCE}
|
||||
${LIB_PTHREAD_SOURCE}
|
||||
${THREAD_MGR_SOURCE}
|
||||
|
|
|
|||
60
code_analysis.sh
Executable file
60
code_analysis.sh
Executable 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 ---"
|
||||
|
|
@ -137,6 +137,10 @@
|
|||
#define WASM_ENABLE_WAMR_COMPILER 0
|
||||
#endif
|
||||
|
||||
#ifndef WASM_ENABLE_COMPONENT_MODEL
|
||||
#define WASM_ENABLE_COMPONENT_MODEL 0
|
||||
#endif
|
||||
|
||||
#ifndef WASM_ENABLE_LIBC_BUILTIN
|
||||
#define WASM_ENABLE_LIBC_BUILTIN 0
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -50,8 +50,14 @@ bh_static_assert(offsetof(AOTModuleInstance, cur_exception)
|
|||
== 13 * sizeof(uint64));
|
||||
bh_static_assert(offsetof(AOTModuleInstance, c_api_func_imports)
|
||||
== 13 * sizeof(uint64) + 128 + 7 * sizeof(uint64));
|
||||
#if WASM_ENABLE_COMPONENT_MODEL != 0
|
||||
bh_static_assert(offsetof(AOTModuleInstance, global_table_data)
|
||||
== 13 * sizeof(uint64) + 128 + 14 * sizeof(uint64)
|
||||
+ sizeof(void *) + sizeof(uint64));
|
||||
#else
|
||||
bh_static_assert(offsetof(AOTModuleInstance, global_table_data)
|
||||
== 13 * sizeof(uint64) + 128 + 14 * sizeof(uint64));
|
||||
#endif
|
||||
|
||||
bh_static_assert(sizeof(AOTMemoryInstance) == 120);
|
||||
bh_static_assert(offsetof(AOTTableInstance, elems) == 24);
|
||||
|
|
|
|||
12
core/iwasm/common/component-model/iwasm_component.cmake
Normal file
12
core/iwasm/common/component-model/iwasm_component.cmake
Normal 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})
|
||||
637
core/iwasm/common/component-model/wasm_component.c
Normal file
637
core/iwasm/common/component-model/wasm_component.c
Normal file
|
|
@ -0,0 +1,637 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
2002
core/iwasm/common/component-model/wasm_component.h
Normal file
2002
core/iwasm/common/component-model/wasm_component.h
Normal file
File diff suppressed because it is too large
Load Diff
220
core/iwasm/common/component-model/wasm_component_alias_section.c
Normal file
220
core/iwasm/common/component-model/wasm_component_alias_section.c
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
1077
core/iwasm/common/component-model/wasm_component_canons_section.c
Normal file
1077
core/iwasm/common/component-model/wasm_component_canons_section.c
Normal file
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
|
|
@ -0,0 +1,398 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
1005
core/iwasm/common/component-model/wasm_component_core_type_section.c
Normal file
1005
core/iwasm/common/component-model/wasm_component_core_type_section.c
Normal file
File diff suppressed because it is too large
Load Diff
21
core/iwasm/common/component-model/wasm_component_export.c
Normal file
21
core/iwasm/common/component-model/wasm_component_export.c
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
16
core/iwasm/common/component-model/wasm_component_export.h
Normal file
16
core/iwasm/common/component-model/wasm_component_export.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* 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
|
||||
|
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
1323
core/iwasm/common/component-model/wasm_component_helpers.c
Normal file
1323
core/iwasm/common/component-model/wasm_component_helpers.c
Normal file
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
|
|
@ -0,0 +1,381 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
112
core/iwasm/common/component-model/wasm_component_start_section.c
Normal file
112
core/iwasm/common/component-model/wasm_component_start_section.c
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
2402
core/iwasm/common/component-model/wasm_component_types_section.c
Normal file
2402
core/iwasm/common/component-model/wasm_component_types_section.c
Normal file
File diff suppressed because it is too large
Load Diff
3012
core/iwasm/common/component-model/wasm_component_validate.c
Normal file
3012
core/iwasm/common/component-model/wasm_component_validate.c
Normal file
File diff suppressed because it is too large
Load Diff
60
core/iwasm/common/component-model/wasm_component_validate.h
Normal file
60
core/iwasm/common/component-model/wasm_component_validate.h
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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
|
||||
|
|
@ -0,0 +1,569 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
*/
|
||||
|
||||
#include "bh_platform.h"
|
||||
#include "wasm_ieee754.h"
|
||||
#if WASM_ENABLE_INTERP != 0
|
||||
#include "../interpreter/wasm_runtime.h"
|
||||
#endif
|
||||
|
|
@ -50,13 +51,6 @@ runtime_malloc(uint64 size, WASMModuleInstanceCommon *module_inst,
|
|||
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()
|
||||
*/
|
||||
|
|
@ -311,47 +305,6 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst, int32 argc,
|
|||
* 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
|
||||
execute_func(WASMModuleInstanceCommon *module_inst, const char *name,
|
||||
int32 argc, char *argv[])
|
||||
|
|
|
|||
60
core/iwasm/common/wasm_ieee754.h
Normal file
60
core/iwasm/common/wasm_ieee754.h
Normal 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 */
|
||||
|
|
@ -652,6 +652,47 @@ wasm_runtime_init_internal(void)
|
|||
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
|
||||
wasm_runtime_init()
|
||||
{
|
||||
|
|
@ -4512,6 +4553,72 @@ wasm_runtime_get_export_count(WASMModuleCommon *const module)
|
|||
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
|
||||
wasm_runtime_get_export_type(WASMModuleCommon *const module, int32 export_index,
|
||||
wasm_export_t *export_type)
|
||||
|
|
|
|||
|
|
@ -90,6 +90,13 @@ typedef struct WASMMemory WASMMemoryType;
|
|||
#endif
|
||||
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 {
|
||||
const char *module_name;
|
||||
const char *name;
|
||||
|
|
@ -118,6 +125,11 @@ typedef struct wasm_export_t {
|
|||
struct WASMModuleInstanceCommon;
|
||||
typedef struct WASMModuleInstanceCommon *wasm_module_inst_t;
|
||||
|
||||
#if WASM_ENABLE_COMPONENT_MODEL != 0
|
||||
struct WASMComponentInstance;
|
||||
typedef struct WASMComponentInstance WASMComponentInstance;
|
||||
#endif
|
||||
|
||||
/* Function instance */
|
||||
typedef void WASMFunctionInstanceCommon;
|
||||
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
|
||||
call */
|
||||
bool no_resolve;
|
||||
#if WASM_ENABLE_COMPONENT_MODEL != 0
|
||||
bool is_component;
|
||||
#endif
|
||||
/* TODO: more fields? */
|
||||
} LoadArgs;
|
||||
#endif /* LOAD_ARGS_OPTION_DEFINED */
|
||||
|
|
@ -354,6 +369,22 @@ typedef struct SharedHeapInitArgs {
|
|||
void *pre_allocated_addr;
|
||||
} 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
|
||||
* the memory allocator with system allocator, which calls os_malloc
|
||||
|
|
@ -1602,6 +1633,48 @@ wasm_runtime_get_import_type(const wasm_module_t module, int32_t import_index,
|
|||
WASM_RUNTIME_API_EXTERN int32_t
|
||||
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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -154,6 +154,8 @@ typedef void *table_elem_type_t;
|
|||
|
||||
#define WASM_MAGIC_NUMBER 0x6d736100
|
||||
#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_TYPE 1
|
||||
|
|
|
|||
|
|
@ -7108,8 +7108,9 @@ load(const uint8 *buf, uint32 size, WASMModule *module,
|
|||
module->package_version = version;
|
||||
|
||||
if (!create_sections(buf, size, §ion_list, error_buf, error_buf_size)
|
||||
|| !load_from_sections(module, section_list, true, wasm_binary_freeable,
|
||||
no_resolve, error_buf, error_buf_size)) {
|
||||
|| !load_from_sections(module, section_list, false,
|
||||
wasm_binary_freeable, no_resolve, error_buf,
|
||||
error_buf_size)) {
|
||||
destroy_sections(section_list);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -7129,6 +7130,9 @@ static bool
|
|||
check_wasi_abi_compatibility(const WASMModule *module,
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
bool main_module,
|
||||
#endif
|
||||
#if WASM_ENABLE_COMPONENT_MODEL != 0
|
||||
bool is_component,
|
||||
#endif
|
||||
char *error_buf, uint32 error_buf_size)
|
||||
{
|
||||
|
|
@ -7215,13 +7219,14 @@ check_wasi_abi_compatibility(const WASMModule *module,
|
|||
if (!module->import_wasi_api && !start && !initialize) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_COMPONENT_MODEL != 0
|
||||
/* should have one at least */
|
||||
if (module->import_wasi_api && !start && !initialize) {
|
||||
LOG_WARNING("warning: a module with WASI apis should be either "
|
||||
"a command or a reactor");
|
||||
if (!is_component)
|
||||
LOG_WARNING("warning: a module with WASI apis should be either "
|
||||
"a command or a reactor");
|
||||
}
|
||||
|
||||
#endif
|
||||
/*
|
||||
* there is at least one of `_start` and `_initialize` in below cases.
|
||||
* according to the assumption, they should be all wasi compatible
|
||||
|
|
@ -7295,6 +7300,9 @@ wasm_loader_load(uint8 *buf, uint32 size,
|
|||
if (!check_wasi_abi_compatibility(module,
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
main_module,
|
||||
#endif
|
||||
#if WASM_ENABLE_COMPONENT_MODEL != 0
|
||||
args->is_component,
|
||||
#endif
|
||||
error_buf, error_buf_size)) {
|
||||
goto fail;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,10 @@
|
|||
#include "mem_alloc.h"
|
||||
#include "../common/wasm_runtime_common.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
|
||||
#include "../common/gc/gc_object.h"
|
||||
#endif
|
||||
|
|
@ -173,7 +177,11 @@ wasm_resolve_import_func(const WASMModule *module, WASMFunctionImport *function)
|
|||
if (function->func_ptr_linked) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_COMPONENT_MODEL != 0
|
||||
if (is_component_runtime()) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
if (!wasm_runtime_is_built_in_module(function->module_name)) {
|
||||
sub_module = (WASMModule *)wasm_runtime_load_depended_module(
|
||||
|
|
@ -1494,6 +1502,37 @@ export_functions_instantiate(const WASMModule *module,
|
|||
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
|
||||
/**
|
||||
* Destroy export function instances.
|
||||
|
|
@ -1540,6 +1579,13 @@ export_tags_instantiate(const WASMModule *module,
|
|||
}
|
||||
#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
|
||||
static void
|
||||
export_memories_deinstantiate(WASMExportMemInstance *memories)
|
||||
|
|
@ -1961,6 +2007,7 @@ execute_free_function(WASMModuleInstance *module_inst, WASMExecEnv *exec_env,
|
|||
return ret;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_COMPONENT_MODEL == 0
|
||||
static bool
|
||||
check_linked_symbol(WASMModuleInstance *module_inst, char *error_buf,
|
||||
uint32 error_buf_size)
|
||||
|
|
@ -2045,6 +2092,7 @@ check_linked_symbol(WASMModuleInstance *module_inst, char *error_buf,
|
|||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_JIT != 0
|
||||
static bool
|
||||
|
|
@ -2623,7 +2671,7 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
|
|||
module_inst->export_memory_count =
|
||||
get_export_count(module, EXPORT_KIND_MEMORY);
|
||||
#endif
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0 || WASM_ENABLE_COMPONENT_MODEL != 0
|
||||
module_inst->export_table_count =
|
||||
get_export_count(module, EXPORT_KIND_TABLE);
|
||||
#if WASM_ENABLE_TAGS != 0
|
||||
|
|
@ -2643,6 +2691,10 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
|
|||
&& !(module_inst->tables =
|
||||
tables_instantiate(module, module_inst, first_table,
|
||||
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->functions = functions_instantiate(
|
||||
module, module_inst, error_buf, error_buf_size)))
|
||||
|
|
@ -2779,11 +2831,11 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
|
|||
}
|
||||
bh_assert(global_data == global_data_end);
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_COMPONENT_MODEL == 0
|
||||
if (!check_linked_symbol(module_inst, error_buf, error_buf_size)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#endif
|
||||
/* Initialize the memory data with data segment section */
|
||||
for (i = 0; i < module->data_seg_count; i++) {
|
||||
WASMMemoryInstance *memory = NULL;
|
||||
|
|
@ -3460,6 +3512,7 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
|
|||
#endif
|
||||
globals_deinstantiate(module_inst->e->globals);
|
||||
export_functions_deinstantiate(module_inst->export_functions);
|
||||
export_tables_deinstantiate(module_inst->export_tables);
|
||||
#if WASM_ENABLE_TAGS != 0
|
||||
export_tags_deinstantiate(module_inst->e->export_tags);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -28,6 +28,10 @@ typedef struct WASMGlobalInstance WASMGlobalInstance;
|
|||
typedef struct WASMTagInstance WASMTagInstance;
|
||||
#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
|
||||
* some offsets of the same field in the interpreter module instance and
|
||||
|
|
@ -204,7 +208,7 @@ struct WASMGlobalInstance {
|
|||
#if WASM_ENABLE_GC != 0
|
||||
WASMRefType *ref_type;
|
||||
#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 */
|
||||
WASMModuleInstance *import_module_inst;
|
||||
WASMGlobalInstance *import_global_inst;
|
||||
|
|
@ -237,7 +241,7 @@ struct WASMFunctionInstance {
|
|||
WASMFunctionImport *func_import;
|
||||
WASMFunction *func;
|
||||
} u;
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0
|
||||
#if WASM_ENABLE_MULTI_MODULE != 0 || WASM_ENABLE_COMPONENT_MODEL != 0
|
||||
WASMModuleInstance *import_module_inst;
|
||||
WASMFunctionInstance *import_func_inst;
|
||||
#endif
|
||||
|
|
@ -249,6 +253,12 @@ struct WASMFunctionInstance {
|
|||
/* children execution time */
|
||||
uint64 children_exec_time;
|
||||
#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
|
||||
|
|
@ -466,6 +476,11 @@ struct WASMModuleInstance {
|
|||
uint32 default_wasm_stack_size;
|
||||
uint32 reserved[7];
|
||||
|
||||
#if WASM_ENABLE_COMPONENT_MODEL != 0
|
||||
WASMComponentInstance *comp_instance;
|
||||
uint32 core_instance_idx;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* +------------------------------+ <-- memories
|
||||
* | WASMMemoryInstance[mem_count], mem_count is always 1 for LLVM JIT/AOT
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
error = wasi_sock_recv_from(exec_env, sock, ri_data, ri_data_len, ri_flags,
|
||||
NULL, ro_data_len);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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_VALIDATOR](#aot-validator) | AoT validator |
|
||||
| [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_CUSTOM_NAME_SECTION](#name-section) | name section |
|
||||
| [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.
|
||||
|
||||
### **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**
|
||||
|
||||
- **WAMR_BUILD_MEMORY64**=1/0, default to off.
|
||||
|
|
|
|||
114
doc/component_model.md
Normal file
114
doc/component_model.md
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
# WAMR Component Model support
|
||||
|
||||
## Introduction
|
||||
|
||||
A WebAssembly (Wasm) component is an abstraction layer built over [standard WebAssembly](https://webassembly.github.io/spec/core/index.html) (often called WebAssembly Core). It is designed to enrich the exposed type system and improve interoperability across different programming languages and libraries. More details can be found [here](https://component-model.bytecodealliance.org/).
|
||||
|
||||
To distinguish between the two layers, the Component Model specification refers to standard WebAssembly entities by prefixing them with the word "core" (e.g., core modules, core functions, core types).
|
||||
|
||||
In short, a Wasm component uses WIT—an [Interface Definition Language](https://en.wikipedia.org/wiki/Interface_description_language) (IDL)—to define its public-facing interfaces. It then bundles one or more Wasm core modules to implement the underlying logic behind those interfaces.
|
||||
|
||||
WAMR implements binary parsing for the WebAssembly [Component Model](https://github.com/WebAssembly/component-model) proposal. The parser handles the component binary format as defined in the [Binary.md](https://github.com/WebAssembly/component-model/blob/main/design/mvp/Binary.md) specification, covering all 13 section types with validation and error reporting.
|
||||
|
||||
References:
|
||||
- [Component Model design repository](https://github.com/WebAssembly/component-model)
|
||||
- [Component Model binary format specification](https://github.com/WebAssembly/component-model/blob/main/design/mvp/Binary.md)
|
||||
- [Canonical ABI specification](https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md)
|
||||
- [Build WAMR vmcore](./build_wamr.md) for build flag reference
|
||||
|
||||
## Build
|
||||
|
||||
Enable the feature by setting the CMake flag `WAMR_BUILD_COMPONENT_MODEL` (enabled by default). This defines the C preprocessor macro `WASM_ENABLE_COMPONENT_MODEL=1`.
|
||||
|
||||
```cmake
|
||||
set (WAMR_BUILD_COMPONENT_MODEL 1)
|
||||
include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
|
||||
add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE})
|
||||
```
|
||||
|
||||
Or pass it on the cmake command line:
|
||||
|
||||
```bash
|
||||
cmake -DWAMR_BUILD_COMPONENT_MODEL=1 ..
|
||||
```
|
||||
|
||||
## Component vs core module
|
||||
|
||||
A component binary shares the same magic number (`\0asm`) as a core WebAssembly module but is distinguished by its header fields:
|
||||
|
||||
| | Core module | Component |
|
||||
|---------------|---------------|---------------|
|
||||
| magic | `\0asm` | `\0asm` |
|
||||
| version | `0x0001` | `0x000d` |
|
||||
| layer | `0x0000` | `0x0001` |
|
||||
|
||||
WAMR uses `wasm_decode_header()` to read the 8-byte header and `is_wasm_component()` to determine whether a binary is a component or a core module.
|
||||
|
||||
## Binary parsing overview
|
||||
|
||||
The binary parser takes a raw component binary buffer and produces a `WASMComponent` structure that holds the decoded header and an array of parsed sections. The diagram below illustrates the high-level parsing flow:
|
||||
|
||||
<center><img src="./pics/binary_parser_hld.png" width="85%" height="85%"></img></center>
|
||||
|
||||
The parsing proceeds as follows:
|
||||
|
||||
1. **Header decode** -- `wasm_decode_header()` reads the 8-byte header (magic, version, layer) and populates a `WASMHeader` struct.
|
||||
2. **Section loop** -- the parser iterates over the binary, reading a 1-byte section ID and a LEB128-encoded payload length for each section.
|
||||
3. **Section dispatch** -- based on the section ID, the parser delegates to a dedicated per-section parser. Each parser decodes the section payload into a typed struct, validates its contents (UTF-8 names, index bounds, canonical options), and reports how many bytes were consumed.
|
||||
4. **Core module delegation** -- when a Core Module section (0x01) is encountered, the parser delegates to the existing WAMR core module loader (`wasm_runtime_load_ex()`) to parse the embedded module.
|
||||
5. **Recursive nesting** -- when a Component section (0x04) is encountered, the parser calls itself recursively with an incremented depth counter. Recursion depth is capped at 100.
|
||||
6. **Result** -- on success, the `WASMComponent` struct holds the header and a dynamically-sized array of `WASMComponentSection` entries, each containing the raw payload pointer and a typed union with the parsed result.
|
||||
|
||||
### Section types
|
||||
|
||||
The component binary format defines 13 section types:
|
||||
|
||||
| ID | Section | Spec reference |
|
||||
|------|------------------|-----------------------------------|
|
||||
| 0x00 | Core Custom | custom section (name + data) |
|
||||
| 0x01 | Core Module | embedded core wasm module |
|
||||
| 0x02 | Core Instance | core module instantiation |
|
||||
| 0x03 | Core Type | core func types, module types |
|
||||
| 0x04 | Component | nested component (recursive) |
|
||||
| 0x05 | Instance | component instance definitions |
|
||||
| 0x06 | Alias | export, core export, outer aliases|
|
||||
| 0x07 | Type | component type definitions |
|
||||
| 0x08 | Canon | canonical lift/lower/resource ops |
|
||||
| 0x09 | Start | component start function |
|
||||
| 0x0A | Import | component imports |
|
||||
| 0x0B | Export | component exports |
|
||||
| 0x0C | Value | value definitions |
|
||||
|
||||
### Current limitations
|
||||
|
||||
- **Core Type (0x03)**: only `moduletype` is supported; WebAssembly GC types (`rectype`, `subtype`) are rejected.
|
||||
- **Canon (0x08)**: `async` and `callback` canonical options are rejected; all other canonical operations are supported.
|
||||
|
||||
## Source layout
|
||||
|
||||
All component model sources reside in `core/iwasm/common/component-model/`:
|
||||
|
||||
```
|
||||
component-model/
|
||||
iwasm_component.cmake # CMake build configuration
|
||||
wasm_component.h # type definitions, enums, struct declarations
|
||||
wasm_component.c # entry point: section dispatch and free
|
||||
wasm_component_helpers.c # shared utilities: LEB128, names, value types
|
||||
wasm_component_validate.c # validation: UTF-8, index bounds, canon options
|
||||
wasm_component_validate.h # validation declarations
|
||||
wasm_component_core_custom_section.c # section 0x00
|
||||
wasm_component_core_module_section.c # section 0x01
|
||||
wasm_component_core_instance_section.c # section 0x02
|
||||
wasm_component_core_type_section.c # section 0x03
|
||||
wasm_component_component_section.c # section 0x04
|
||||
wasm_component_instances_section.c # section 0x05
|
||||
wasm_component_alias_section.c # section 0x06
|
||||
wasm_component_types_section.c # section 0x07
|
||||
wasm_component_canons_section.c # section 0x08
|
||||
wasm_component_start_section.c # section 0x09
|
||||
wasm_component_imports_section.c # section 0x0A
|
||||
wasm_component_exports_section.c # section 0x0B
|
||||
wasm_component_values_section.c # section 0x0C
|
||||
wasm_component_export.c # export runtime helpers
|
||||
wasm_component_export.h # export declarations
|
||||
```
|
||||
BIN
doc/pics/binary_parser_hld.png
Normal file
BIN
doc/pics/binary_parser_hld.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 470 KiB |
|
|
@ -79,6 +79,11 @@ if (NOT DEFINED WAMR_BUILD_LIBC_WASI)
|
|||
set (WAMR_BUILD_LIBC_WASI 1)
|
||||
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)
|
||||
# Enable fast interpreter
|
||||
set (WAMR_BUILD_FAST_INTERP 1)
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@ function build_iwasm() {
|
|||
if [ -d build-iwasm-$2 ]; then rm -rf build-iwasm-$2; else mkdir build-iwasm-$2; fi &&
|
||||
cd build-iwasm-$2 &&
|
||||
cmake ${WAMR_DIR}/product-mini/platforms/${PLATFORM} $1 \
|
||||
-DCMAKE_BUILD_TYPE=Debug -DWAMR_BUILD_SANITIZER=asan &&
|
||||
-DCMAKE_BUILD_TYPE=Debug -DWAMR_BUILD_SANITIZER=asan \
|
||||
-DWAMR_BUILD_COMPONENT_MODEL=0 &&
|
||||
make -j 4
|
||||
if [ "$?" != 0 ]; then
|
||||
echo -e "build iwasm failed"
|
||||
|
|
|
|||
|
|
@ -76,45 +76,7 @@ FetchContent_MakeAvailable(googletest)
|
|||
include(GoogleTest)
|
||||
enable_testing()
|
||||
|
||||
add_subdirectory(wasm-vm)
|
||||
add_subdirectory(interpreter)
|
||||
add_subdirectory(wasm-c-api)
|
||||
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)
|
||||
if(DEFINED UNITTEST_FOLDER AND NOT "${UNITTEST_FOLDER}" STREQUAL "")
|
||||
add_subdirectory("${UNITTEST_FOLDER}")
|
||||
return()
|
||||
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 ()
|
||||
|
|
|
|||
|
|
@ -11,6 +11,10 @@ if (WAMR_BUILD_TARGET STREQUAL "X86_32")
|
|||
set (WAMRC_OPTION ${WAMRC_OPTION} --target=i386)
|
||||
endif ()
|
||||
|
||||
find_program(WAT2WASM wat2wasm
|
||||
PATHS /opt/wabt/bin /usr/local/bin /usr/bin
|
||||
REQUIRED)
|
||||
|
||||
add_custom_target(
|
||||
aot-stack-frame-test-wasm ALL
|
||||
|
||||
|
|
@ -20,7 +24,7 @@ add_custom_target(
|
|||
COMMAND cmake --build ${CMAKE_CURRENT_BINARY_DIR}/build-wamrc
|
||||
|
||||
# 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
|
||||
|
||||
# Step 3: Compile .wasm to .aot using wamrc
|
||||
|
|
@ -38,4 +42,3 @@ add_custom_target(
|
|||
-n test_aot
|
||||
${CMAKE_CURRENT_BINARY_DIR}/test.aot
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ class WAMRInstance
|
|||
|
||||
public:
|
||||
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,
|
||||
heap_size, NULL, 0);
|
||||
|
|
@ -336,4 +336,4 @@ class AppData
|
|||
app_addr_);
|
||||
}
|
||||
uint32_t get_app_addr() const { return app_addr_; }
|
||||
};
|
||||
};
|
||||
|
|
|
|||
64
tests/unit/component/CMakeLists.txt
Normal file
64
tests/unit/component/CMakeLists.txt
Normal 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)
|
||||
215
tests/unit/component/helpers.cc
Normal file
215
tests/unit/component/helpers.cc
Normal 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];
|
||||
}
|
||||
62
tests/unit/component/helpers.h
Normal file
62
tests/unit/component/helpers.h
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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
|
||||
144
tests/unit/component/test_binary_parser.cc
Normal file
144
tests/unit/component/test_binary_parser.cc
Normal 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);
|
||||
}
|
||||
BIN
tests/unit/component/wasm-apps/add.wasm
Normal file
BIN
tests/unit/component/wasm-apps/add.wasm
Normal file
Binary file not shown.
BIN
tests/unit/component/wasm-apps/complex.wasm
Normal file
BIN
tests/unit/component/wasm-apps/complex.wasm
Normal file
Binary file not shown.
BIN
tests/unit/component/wasm-apps/complex_with_host.wasm
Normal file
BIN
tests/unit/component/wasm-apps/complex_with_host.wasm
Normal file
Binary file not shown.
BIN
tests/unit/component/wasm-apps/logging_service.component.wasm
Normal file
BIN
tests/unit/component/wasm-apps/logging_service.component.wasm
Normal file
Binary file not shown.
Binary file not shown.
BIN
tests/unit/component/wasm-apps/processor_service.component.wasm
Normal file
BIN
tests/unit/component/wasm-apps/processor_service.component.wasm
Normal file
Binary file not shown.
BIN
tests/unit/component/wasm-apps/sampletypes.wasm
Normal file
BIN
tests/unit/component/wasm-apps/sampletypes.wasm
Normal file
Binary file not shown.
|
|
@ -14,7 +14,7 @@ file_names=("mem_grow_out_of_bounds_01" "mem_grow_out_of_bounds_02"
|
|||
WORKDIR="$PWD"
|
||||
WAMRC_ROOT_DIR="${WORKDIR}/../../../wamr-compiler"
|
||||
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
|
||||
if [ ! -s "$WAMRC" ]; then
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ file_names=("main")
|
|||
WORKDIR="$PWD"
|
||||
WAMRC_ROOT_DIR="${WORKDIR}/../../../wamr-compiler"
|
||||
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
|
||||
if [ ! -s "$WAMRC" ]; then
|
||||
|
|
@ -28,4 +28,3 @@ for file_name in "${file_names[@]}"; do
|
|||
# compile wasm to aot
|
||||
$WAMRC -o "wasm-apps/${file_name}.aot" "wasm-apps/${file_name}.wasm"
|
||||
done
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,14 @@
|
|||
char *current_dir = getcwd(NULL, 0);
|
||||
CWD = std::string(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));
|
||||
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);
|
||||
ASSERT_TRUE(success);
|
||||
}
|
||||
|
||||
|
|
@ -29,11 +29,13 @@ pushd ${SRC_COV_DIR} > /dev/null 2>&1
|
|||
|
||||
# collect all code coverage data
|
||||
# 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
|
||||
# for lcov 2.x: ignore-errors unused
|
||||
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/*" \
|
||||
"*/llvm/include/*" "*/include/llvm/*" "*/samples/*" \
|
||||
"*/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 ${DST_COV_FILE} ]]; then
|
||||
# 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} \
|
||||
-a ${DST_COV_FILE} -o ${SRC_COV_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
|
||||
rm -fr ${DST_COV_DIR}/wamr-lcov
|
||||
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 \
|
||||
${DST_COV_FILE}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ function help()
|
|||
echo " riscv32|riscv32_ilp32f|riscv32_ilp32d|riscv64|"
|
||||
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 "-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 "-p enable multi thread 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")
|
||||
#default target
|
||||
TARGET="X86_64"
|
||||
UNITTEST_FOUND="NO"
|
||||
UNITTEST_FOLDERS=()
|
||||
ENABLE_WASI_THREADS=0
|
||||
ENABLE_MULTI_MODULE=0
|
||||
ENABLE_MULTI_THREAD=0
|
||||
|
|
@ -93,7 +97,7 @@ REQUIREMENT_NAME=""
|
|||
# Initialize an empty array for 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
|
||||
OPT_PARSED="TRUE"
|
||||
case $opt in
|
||||
|
|
@ -110,6 +114,7 @@ do
|
|||
OPTIND=$((OPTIND+1))
|
||||
eval "nxarg=\${$((OPTIND))}"
|
||||
done
|
||||
UNITTEST_FOUND="YES"
|
||||
echo "test following cases: ${TEST_CASE_ARR[@]}"
|
||||
;;
|
||||
c)
|
||||
|
|
@ -120,6 +125,21 @@ do
|
|||
echo "cleaned all reports and temp files"
|
||||
fi
|
||||
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)
|
||||
TEST_ALL_AOT_RUNTIME="all"
|
||||
echo "test all runtimes in sightglass_aot"
|
||||
|
|
@ -129,11 +149,11 @@ do
|
|||
echo "use a WABT binary release instead of compiling from source code"
|
||||
;;
|
||||
t)
|
||||
echo "set compile type of wamr " ${OPTARG}
|
||||
echo "set compile type of wamr:" ${OPTARG}
|
||||
if [[ ${OPTARG} != "classic-interp" && ${OPTARG} != "fast-interp" \
|
||||
&& ${OPTARG} != "jit" && ${OPTARG} != "aot"
|
||||
&& ${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
|
||||
exit 1
|
||||
fi
|
||||
|
|
@ -141,7 +161,7 @@ do
|
|||
TYPE=(${OPTARG})
|
||||
;;
|
||||
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
|
||||
;;
|
||||
w)
|
||||
|
|
@ -331,14 +351,118 @@ function unit_test()
|
|||
echo "Now start unit tests"
|
||||
|
||||
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
|
||||
cmake -S ${WORK_DIR}/../../unit -B unittest-build \
|
||||
-DCOLLECT_CODE_COVERAGE=${COLLECT_CODE_COVERAGE}
|
||||
cmake --build unittest-build
|
||||
ctest --test-dir unittest-build --output-on-failure | tee -a ${REPORT_DIR}/unit_test_report.txt
|
||||
|
||||
local folders=()
|
||||
if [[ ${#UNITTEST_FOLDERS[@]} -gt 0 ]]; then
|
||||
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"
|
||||
}
|
||||
|
|
@ -411,7 +535,7 @@ function setup_wabt()
|
|||
echo "wabt not exist, clone it from github"
|
||||
git clone --recursive https://github.com/WebAssembly/wabt
|
||||
fi
|
||||
echo "upate wabt"
|
||||
echo "update wabt"
|
||||
cd wabt \
|
||||
&& git fetch origin \
|
||||
&& git reset --hard origin/main \
|
||||
|
|
@ -882,8 +1006,10 @@ function collect_coverage()
|
|||
fi
|
||||
|
||||
pushd ${WORK_DIR} > /dev/null 2>&1
|
||||
echo "Collect code coverage of iwasm"
|
||||
./collect_coverage.sh ${CODE_COV_FILE} ${IWASM_LINUX_ROOT_DIR}/build
|
||||
if [[ $1 != "unit" && -d ${IWASM_LINUX_ROOT_DIR}/build ]]; then
|
||||
echo "Collect code coverage of iwasm"
|
||||
./collect_coverage.sh ${CODE_COV_FILE} ${IWASM_LINUX_ROOT_DIR}/build
|
||||
fi
|
||||
if [[ $1 == "llvm-aot" ]]; then
|
||||
echo "Collect code coverage of wamrc"
|
||||
./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
|
||||
if [[ ${suite} = "unit" ]]; then
|
||||
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
|
||||
fi
|
||||
done
|
||||
|
|
@ -1027,6 +1159,7 @@ function trigger()
|
|||
EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_BULK_MEMORY=1"
|
||||
EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_REF_TYPES=1"
|
||||
EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_LIBC_WASI=0"
|
||||
EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_COMPONENT_MODEL=0"
|
||||
|
||||
if [[ ${ENABLE_MULTI_MODULE} == 1 ]];then
|
||||
EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_MULTI_MODULE=1"
|
||||
|
|
@ -1092,6 +1225,10 @@ function trigger()
|
|||
# if we're running the wasi certification tests.
|
||||
if [[ $TEST_CASE_ARR ]]; then
|
||||
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
|
||||
EXTRA_COMPILE_FLAGS+=" -DWAMR_BUILD_WASI_TEST=1"
|
||||
fi
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user