This commit is contained in:
liang.he 2025-11-27 04:15:44 +03:00 committed by GitHub
commit f090909a30
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 14177 additions and 0 deletions

View File

@ -0,0 +1,59 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
name: Verify core/iwasm/include checked APIs to see if they are up to date
on:
# will be triggered on PR events
pull_request:
types:
- opened
- synchronize
paths:
- "core/iwasm/include/**"
- ".github/workflows/verify_checked_apis.yml"
- "ci/generate_checked_functions.py"
push:
paths:
- "core/iwasm/include/**"
- ".github/workflows/verify_checked_apis.yml"
- "ci/generate_checked_functions.py"
# Cancel any in-flight jobs for the same PR/branch so there's only one active
# at a time
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
verify_checked_apis:
name: Verify checked APIs
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.x"
- name: Install dependencies
run: |
pip install pycparser
sudo apt-get update
sudo apt-get install -y clang-format-14
- name: Generate checked APIs
id: generate_checked_apis
run: |
python3 ci/generate_checked_functions.py
- name: Check for differences
run: |
#it exits with 1 if there were differences and 0 means no differences
git diff --exit-code

View File

@ -0,0 +1,318 @@
"""
This script generates "checked" versions of functions from the specified header files.
Usage:
python3 generate_checked_functions.py --headers <header1.h> <header2.h> ...
Arguments:
--headers: A list of header file paths to process. Each header file will be parsed, and a corresponding
"_checked.h" file will be generated with additional null pointer checks and error handling.
If not provided, a default list of headers under "core/iwasm/include/" will be used.
Example:
python3 generate_checked_functions.py
# OR
python3 generate_checked_functions.py --headers core/iwasm/include/wasm_export.h
Description:
The script parses the provided header files using `pycparser` to extract function declarations and typedefs.
For each function, it generates a "checked" version that includes:
- Null pointer checks for pointer parameters.
- Error handling using a `Result` struct.
- Support for variadic arguments (e.g., ...).
The generated "_checked.h" files include the original header file and define the `Result` struct, which
encapsulates the return value and error codes. The `Result` struct is dynamically generated based on the
return types of the functions in the header file.
Dependencies:
- pycparser: Install it using `pip install pycparser`.
- clang-format-14: Ensure it is installed for formatting the generated files.
Output:
For each input header file, a corresponding "_checked.h" file is created in the same directory.
The generated files are automatically formatted using clang-format-14.
"""
import argparse
from pathlib import Path
from pycparser import c_ast, parse_file
import subprocess
# Constants for repeated strings
CPP_ARGS = [
"-E",
"-D__attribute__(x)=",
"-D__asm__(x)=",
"-D__asm(x)=",
"-D__builtin_va_list=int",
"-D__extension__=",
"-D__inline__=",
"-D__restrict=",
"-D__restrict__=",
"-D_Static_assert(x, y)=",
"-D__signed=",
"-D__volatile__(x)=",
"-Dstatic_assert(x, y)=",
]
RESULT_STRUCT_TEMPLATE = """
typedef struct {
int error_code; // Error code (0 for success, non-zero for errors)
union {
// Add other types as needed
} value;
} Result;
"""
COPYRIGHT = """
/*
* Copyright (C) 2025 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
"""
INCLUDE_HEADERS = ["<stdbool.h>", "<stdint.h>", "<stdlib.h>"]
def extract_typedefs(ast):
"""Extract all typedefs from the AST."""
return {node.name: node.type for node in ast.ext if isinstance(node, c_ast.Typedef)}
def generate_result_struct(return_types):
"""Generate the Result struct based on return types."""
result_struct = RESULT_STRUCT_TEMPLATE
for return_type in return_types:
if return_type == "void":
continue
result_struct = result_struct.replace(
"// Add other types as needed",
f" {return_type} {return_type}_value;\n // Add other types as needed",
)
return result_struct
def write_checked_header(output_path, result_struct, functions, typedefs):
"""Write the checked header file."""
with open(output_path, "w") as f:
# copyright
f.write(COPYRIGHT)
f.write("\n")
f.write("/*\n")
f.write(" * THIS FILE IS GENERATED AUTOMATICALLY, DO NOT EDIT!\n")
f.write(" */\n")
# include guard
f.write(
f"#ifndef {output_path.stem.upper()}_H\n#define {output_path.stem.upper()}_H\n\n"
)
for header in INCLUDE_HEADERS:
f.write(f"#include {header}\n")
f.write("\n")
# include original header
original_header = output_path.stem.replace("_checked", "") + ".h"
f.write(f'#include "{original_header}"\n')
f.write("\n")
f.write(result_struct + "\n")
for func in functions:
new_func = generate_checked_function(func, typedefs)
f.write(new_func + "\n\n")
f.write(f"#endif // {output_path.stem.upper()}_H\n")
def generate_checked_function(func, typedefs):
"""Generate a checked version of the given function."""
func_name = func.name # Access the name directly from Decl
new_func_name = f"{func_name}_checked"
# Extract parameters
params = func.type.args.params if func.type.args else []
# Determine the return type
return_pointer = False
return_type = "void" # Default to void if no return type is specified
if isinstance(func.type.type, c_ast.TypeDecl):
return_type = " ".join(func.type.type.type.names)
resolved_type = typedefs.get(return_type, return_type)
if isinstance(resolved_type, c_ast.PtrDecl):
return_pointer = True
# Start building the new function
new_func = [f"static inline Result {new_func_name}("]
param_list = []
for param in params:
if isinstance(param, c_ast.EllipsisParam):
# Handle variadic arguments (e.g., ...)
param_list.append("...")
new_func.append(" ...,")
continue
param_name = param.name if param.name else ""
param_list.append(param_name)
param_type = (
" ".join(param.type.type.names)
if isinstance(param.type, c_ast.TypeDecl)
else "void*"
)
new_func.append(f" {param_type} {param_name},")
if param_list:
new_func[-1] = new_func[-1].rstrip(",") # Remove trailing comma
new_func.append(") {")
# Add null checks for pointer parameters
new_func.append(f" Result res;")
has_variadic = False
for param in params:
if isinstance(param, c_ast.EllipsisParam):
# Restructure to use va_list
new_func.append(" va_list args;")
has_variadic = True
elif isinstance(param.type, c_ast.PtrDecl):
new_func.append(f" // Check for null pointer parameter: {param.name}")
new_func.append(f" if ({param.name} == NULL) {{")
new_func.append(f" res.error_code = -1;")
new_func.append(f" return res;")
new_func.append(f" }}")
# Call the original function
new_func.append(f" // Execute the original function")
if return_type == "void":
new_func.append(f" {func_name}({', '.join(param_list)});")
elif has_variadic:
new_func.append(" va_start(args, " + param_list[-2] + ");")
new_func.append(
f" {return_type} original_result = {func_name}({', '.join(param_list[:-1])}, args);"
)
new_func.append(" va_end(args);")
else:
new_func.append(
f" {return_type} original_result = {func_name}({', '.join(param_list)});"
)
# Handle returned values
new_func.append(f" // Assign return value and error code")
if return_type == "void":
new_func.append(f" res.error_code = 0;")
elif return_type == "_Bool":
new_func.append(f" res.error_code = original_result ? 0 : -2;")
new_func.append(f" res.value._Bool_value = original_result;")
# if return type is a pointer or typedef from pointer
elif return_pointer:
new_func.append(f" if (original_result != NULL) {{")
new_func.append(f" res.error_code = 0;")
new_func.append(f" res.value.{return_type}_value = original_result;")
new_func.append(f" }} else {{")
new_func.append(f" res.error_code = -2;")
new_func.append(f" }}")
else:
new_func.append(f" if (original_result == 0) {{")
new_func.append(f" res.error_code = 0;")
new_func.append(f" res.value.{return_type}_value = original_result;")
new_func.append(f" }} else {{")
new_func.append(f" res.error_code = -2;")
new_func.append(f" }}")
new_func.append(f" return res;")
new_func.append(f"}}")
return "\n".join(new_func)
def parse_arguments():
"""Parse command-line arguments."""
parser = argparse.ArgumentParser(
description="Generate checked functions from header files."
)
parser.add_argument(
"--headers",
nargs="+",
required=False,
help="List of header file paths to process. Relative to the project root.",
default=[
"core/iwasm/include/aot_comp_option.h",
"core/iwasm/include/aot_export.h",
"core/iwasm/include/gc_export.h",
"core/iwasm/include/lib_export.h",
"core/iwasm/include/wasm_c_api.h",
"core/iwasm/include/wasm_export.h",
],
)
return parser.parse_args()
def generate_checked_headers(header_paths):
"""Process each header file and generate checked versions."""
output_header = []
for input_header in header_paths:
input_path = Path(input_header)
output_path = input_path.with_name(input_path.stem + "_checked.h")
ast = parse_file(
str(input_path),
use_cpp=True,
cpp_path="gcc",
cpp_args=CPP_ARGS,
)
typedefs = extract_typedefs(ast)
functions = [
node
for node in ast.ext
if isinstance(node, c_ast.Decl) and isinstance(node.type, c_ast.FuncDecl)
]
# remove std headers functions
functions = [
f
for f in functions
if f.name
not in (
"__mempcpy",
"__stpcpy",
"memmem",
"memmove",
"mempcpy",
"memset",
"strcasestr",
"strcat",
"strchrnul",
"strcmp",
"strlcat",
"strlcpy",
"strlen",
)
]
functions = sorted(functions, key=lambda f: f.name)
return_types = {
" ".join(func.type.type.type.names)
for func in functions
if isinstance(func.type.type, c_ast.TypeDecl)
}
return_types = sorted(return_types)
result_struct = generate_result_struct(return_types)
write_checked_header(output_path, result_struct, functions, typedefs)
output_header.append(output_path)
return output_header
def main():
args = parse_arguments()
generated_headers = generate_checked_headers(args.headers)
# format the generated files using clang-format-14
for header in generated_headers:
subprocess.run(["clang-format-14", "--style=file", "-i", str(header)])
if __name__ == "__main__":
main()

View File

@ -7,6 +7,7 @@
#define __AOT_COMP_OPTION_H__
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {

View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2025 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
/*
* THIS FILE IS GENERATED AUTOMATICALLY, DO NOT EDIT!
*/
#ifndef AOT_COMP_OPTION_CHECKED_H
#define AOT_COMP_OPTION_CHECKED_H
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include "aot_comp_option.h"
typedef struct {
int error_code; // Error code (0 for success, non-zero for errors)
union {
// Add other types as needed
} value;
} Result;
static inline Result
aot_call_stack_features_init_default_checked(void *features)
{
Result res;
// Check for null pointer parameter: features
if (features == NULL) {
res.error_code = -1;
return res;
}
// Execute the original function
aot_call_stack_features_init_default(features);
// Assign return value and error code
res.error_code = 0;
return res;
}
#endif // AOT_COMP_OPTION_CHECKED_H

View File

@ -0,0 +1,334 @@
/*
* Copyright (C) 2025 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
/*
* THIS FILE IS GENERATED AUTOMATICALLY, DO NOT EDIT!
*/
#ifndef AOT_EXPORT_CHECKED_H
#define AOT_EXPORT_CHECKED_H
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include "aot_export.h"
typedef struct {
int error_code; // Error code (0 for success, non-zero for errors)
union {
_Bool _Bool_value;
aot_comp_context_t aot_comp_context_t_value;
aot_comp_data_t aot_comp_data_t_value;
aot_obj_data_t aot_obj_data_t_value;
uint32_t uint32_t_value;
// Add other types as needed
} value;
} Result;
static inline Result
aot_call_stack_features_init_default_checked(void *features)
{
Result res;
// Check for null pointer parameter: features
if (features == NULL) {
res.error_code = -1;
return res;
}
// Execute the original function
aot_call_stack_features_init_default(features);
// Assign return value and error code
res.error_code = 0;
return res;
}
static inline Result
aot_compile_wasm_checked(aot_comp_context_t comp_ctx)
{
Result res;
// Execute the original function
_Bool original_result = aot_compile_wasm(comp_ctx);
// Assign return value and error code
res.error_code = original_result ? 0 : -2;
res.value._Bool_value = original_result;
return res;
}
static inline Result
aot_compiler_destroy_checked(void)
{
Result res;
// Execute the original function
aot_compiler_destroy();
// Assign return value and error code
res.error_code = 0;
return res;
}
static inline Result
aot_compiler_init_checked(void)
{
Result res;
// Execute the original function
_Bool original_result = aot_compiler_init();
// Assign return value and error code
res.error_code = original_result ? 0 : -2;
res.value._Bool_value = original_result;
return res;
}
static inline Result
aot_create_comp_context_checked(aot_comp_data_t comp_data,
aot_comp_option_t option)
{
Result res;
// Execute the original function
aot_comp_context_t original_result =
aot_create_comp_context(comp_data, option);
// Assign return value and error code
if (original_result != NULL) {
res.error_code = 0;
res.value.aot_comp_context_t_value = original_result;
}
else {
res.error_code = -2;
}
return res;
}
static inline Result
aot_create_comp_data_checked(void *wasm_module, void *target_arch,
_Bool gc_enabled)
{
Result res;
// Check for null pointer parameter: wasm_module
if (wasm_module == NULL) {
res.error_code = -1;
return res;
}
// Check for null pointer parameter: target_arch
if (target_arch == NULL) {
res.error_code = -1;
return res;
}
// Execute the original function
aot_comp_data_t original_result =
aot_create_comp_data(wasm_module, target_arch, gc_enabled);
// Assign return value and error code
if (original_result != NULL) {
res.error_code = 0;
res.value.aot_comp_data_t_value = original_result;
}
else {
res.error_code = -2;
}
return res;
}
static inline Result
aot_destroy_aot_file_checked(void *aot_file)
{
Result res;
// Check for null pointer parameter: aot_file
if (aot_file == NULL) {
res.error_code = -1;
return res;
}
// Execute the original function
aot_destroy_aot_file(aot_file);
// Assign return value and error code
res.error_code = 0;
return res;
}
static inline Result
aot_destroy_comp_context_checked(aot_comp_context_t comp_ctx)
{
Result res;
// Execute the original function
aot_destroy_comp_context(comp_ctx);
// Assign return value and error code
res.error_code = 0;
return res;
}
static inline Result
aot_destroy_comp_data_checked(aot_comp_data_t comp_data)
{
Result res;
// Execute the original function
aot_destroy_comp_data(comp_data);
// Assign return value and error code
res.error_code = 0;
return res;
}
static inline Result
aot_emit_aot_file_checked(aot_comp_context_t comp_ctx,
aot_comp_data_t comp_data, void *file_name)
{
Result res;
// Check for null pointer parameter: file_name
if (file_name == NULL) {
res.error_code = -1;
return res;
}
// Execute the original function
_Bool original_result = aot_emit_aot_file(comp_ctx, comp_data, file_name);
// Assign return value and error code
res.error_code = original_result ? 0 : -2;
res.value._Bool_value = original_result;
return res;
}
static inline Result
aot_emit_aot_file_buf_checked(aot_comp_context_t comp_ctx,
aot_comp_data_t comp_data, void *p_aot_file_size)
{
Result res;
// Check for null pointer parameter: p_aot_file_size
if (p_aot_file_size == NULL) {
res.error_code = -1;
return res;
}
// Execute the original function
aot_emit_aot_file_buf(comp_ctx, comp_data, p_aot_file_size);
// Assign return value and error code
res.error_code = 0;
return res;
}
static inline Result
aot_emit_aot_file_buf_ex_checked(aot_comp_context_t comp_ctx,
aot_comp_data_t comp_data,
aot_obj_data_t obj_data, void *aot_file_buf,
uint32_t aot_file_size)
{
Result res;
// Check for null pointer parameter: aot_file_buf
if (aot_file_buf == NULL) {
res.error_code = -1;
return res;
}
// Execute the original function
_Bool original_result = aot_emit_aot_file_buf_ex(
comp_ctx, comp_data, obj_data, aot_file_buf, aot_file_size);
// Assign return value and error code
res.error_code = original_result ? 0 : -2;
res.value._Bool_value = original_result;
return res;
}
static inline Result
aot_emit_llvm_file_checked(aot_comp_context_t comp_ctx, void *file_name)
{
Result res;
// Check for null pointer parameter: file_name
if (file_name == NULL) {
res.error_code = -1;
return res;
}
// Execute the original function
_Bool original_result = aot_emit_llvm_file(comp_ctx, file_name);
// Assign return value and error code
res.error_code = original_result ? 0 : -2;
res.value._Bool_value = original_result;
return res;
}
static inline Result
aot_emit_object_file_checked(aot_comp_context_t comp_ctx, void *file_name)
{
Result res;
// Check for null pointer parameter: file_name
if (file_name == NULL) {
res.error_code = -1;
return res;
}
// Execute the original function
_Bool original_result = aot_emit_object_file(comp_ctx, file_name);
// Assign return value and error code
res.error_code = original_result ? 0 : -2;
res.value._Bool_value = original_result;
return res;
}
static inline Result
aot_get_aot_file_size_checked(aot_comp_context_t comp_ctx,
aot_comp_data_t comp_data,
aot_obj_data_t obj_data)
{
Result res;
// Execute the original function
uint32_t original_result =
aot_get_aot_file_size(comp_ctx, comp_data, obj_data);
// Assign return value and error code
if (original_result == 0) {
res.error_code = 0;
res.value.uint32_t_value = original_result;
}
else {
res.error_code = -2;
}
return res;
}
static inline Result
aot_get_last_error_checked(void)
{
Result res;
// Execute the original function
aot_get_last_error();
// Assign return value and error code
res.error_code = 0;
return res;
}
static inline Result
aot_get_plt_table_size_checked(void)
{
Result res;
// Execute the original function
uint32_t original_result = aot_get_plt_table_size();
// Assign return value and error code
if (original_result == 0) {
res.error_code = 0;
res.value.uint32_t_value = original_result;
}
else {
res.error_code = -2;
}
return res;
}
static inline Result
aot_obj_data_create_checked(aot_comp_context_t comp_ctx)
{
Result res;
// Execute the original function
aot_obj_data_t original_result = aot_obj_data_create(comp_ctx);
// Assign return value and error code
if (original_result != NULL) {
res.error_code = 0;
res.value.aot_obj_data_t_value = original_result;
}
else {
res.error_code = -2;
}
return res;
}
static inline Result
aot_obj_data_destroy_checked(aot_obj_data_t obj_data)
{
Result res;
// Execute the original function
aot_obj_data_destroy(obj_data);
// Assign return value and error code
res.error_code = 0;
return res;
}
#endif // AOT_EXPORT_CHECKED_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 2025 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
/*
* THIS FILE IS GENERATED AUTOMATICALLY, DO NOT EDIT!
*/
#ifndef LIB_EXPORT_CHECKED_H
#define LIB_EXPORT_CHECKED_H
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include "lib_export.h"
typedef struct {
int error_code; // Error code (0 for success, non-zero for errors)
union {
uint32_t uint32_t_value;
// Add other types as needed
} value;
} Result;
static inline Result
get_base_lib_export_apis_checked(void *p_base_lib_apis)
{
Result res;
// Check for null pointer parameter: p_base_lib_apis
if (p_base_lib_apis == NULL) {
res.error_code = -1;
return res;
}
// Execute the original function
uint32_t original_result = get_base_lib_export_apis(p_base_lib_apis);
// Assign return value and error code
if (original_result == 0) {
res.error_code = 0;
res.value.uint32_t_value = original_result;
}
else {
res.error_code = -2;
}
return res;
}
#endif // LIB_EXPORT_CHECKED_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,61 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
cmake_minimum_required (VERSION 3.14)
project(checked_api_sample)
# assertion required
set(CMAKE_BUILD_TYPE Debug)
set(CMAKE_C_STANDARD 23)
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../cmake)
find_package(WASISDK REQUIRED)
################ runtime settings ################
string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM)
include(CheckPIESupported)
# aot and interp by default
set(WAMR_BUILD_AOT 1)
set(WAMR_BUILD_INTERP 1)
set(WAMR_BUILD_JIT 0)
# wasm32-wasi
set(WAMR_BUILD_LIBC_BUILTIN 0)
set(WAMR_BUILD_LIBC_WASI 1)
# mvp
set(WAMR_BUILD_BULK_MEMORY 1)
set(WAMR_BUILD_REF_TYPES 1)
set(WAMR_BUILD_SIMD 1)
set(WAMR_BUILD_TAIL_CALL 1)
# trap information
set(WAMR_BUILD_DUMP_CALL_STACK 1)
# vmlib
set(WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..)
include(${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
add_library(vmlib SHARED ${WAMR_RUNTIME_LIB_SOURCE})
target_include_directories(vmlib INTERFACE ${WAMR_ROOT_DIR}/core/iwasm/include)
target_link_libraries (vmlib ${LLVM_AVAILABLE_LIBS} -lm -ldl)
################ host ################
include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake)
add_executable(${PROJECT_NAME} src/demo.c ${UNCOMMON_SHARED_SOURCE})
target_link_libraries(${PROJECT_NAME} vmlib)
################ aot + wasm ################
include(ExternalProject)
ExternalProject_Add(wasm
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/wasm-apps"
CONFIGURE_COMMAND ${CMAKE_COMMAND} -S ${CMAKE_CURRENT_SOURCE_DIR}/wasm-apps -B build
-DCMAKE_TOOLCHAIN_FILE=${WASISDK_TOOLCHAIN}
BUILD_COMMAND ${CMAKE_COMMAND} --build build
INSTALL_COMMAND ${CMAKE_COMMAND} --install build --prefix ${CMAKE_CURRENT_BINARY_DIR}
)
enable_testing()
add_test(NAME checked_api_sample_test
COMMAND ${PROJECT_NAME}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)

View File

@ -0,0 +1,110 @@
#include <stdio.h>
#include <stdlib.h>
#include "bh_platform.h"
#include "bh_read_file.h"
#include "wasm_export_checked.h"
#define VERIFY_API_RESULT(callee, result, fail_label) \
do { \
if (result.error_code != 0) { \
printf("%s failed with error code: %d\n", #callee, \
result.error_code); \
goto fail_label; \
} \
} while (0)
int
main(int argc, char *argv_main[])
{
Result api_result;
wasm_module_t module = NULL;
uint32 buf_size, stack_size = 8092, heap_size = 8092;
wasm_module_inst_t module_inst = NULL;
wasm_function_inst_t func = NULL;
wasm_exec_env_t exec_env = NULL;
int ret = EXIT_FAILURE;
RuntimeInitArgs init_args;
// 512Kb
static char global_heap_buf[512 * 1024];
char *wasm_path = "fib.wasm";
char *buffer;
char error_buf[128];
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);
api_result = wasm_runtime_full_init_checked(&init_args);
VERIFY_API_RESULT(wasm_runtime_full_init_checked, api_result, fail);
api_result = wasm_runtime_set_log_level_checked(WASM_LOG_LEVEL_VERBOSE);
VERIFY_API_RESULT(wasm_runtime_set_log_level_checked, api_result,
release_runtime);
buffer = bh_read_file_to_buffer(wasm_path, &buf_size);
if (buffer == NULL) {
printf("Open wasm app file [%s] failed.\n", wasm_path);
goto release_runtime;
}
api_result = wasm_runtime_load_checked((uint8 *)buffer, buf_size, error_buf,
sizeof(error_buf));
VERIFY_API_RESULT(wasm_runtime_load_checked, api_result, release_file);
module = api_result.value.wasm_module_t_value;
api_result = wasm_runtime_instantiate_checked(module, stack_size, heap_size,
error_buf, sizeof(error_buf));
VERIFY_API_RESULT(wasm_runtime_instantiate_checked, api_result,
release_module);
module_inst = api_result.value.wasm_module_inst_t_value;
api_result = wasm_runtime_create_exec_env_checked(module_inst, stack_size);
VERIFY_API_RESULT(wasm_runtime_create_exec_env_checked, api_result,
release_instance);
exec_env = api_result.value.wasm_exec_env_t_value;
api_result = wasm_runtime_lookup_function_checked(module_inst, "fib");
VERIFY_API_RESULT(wasm_runtime_lookup_function_checked, api_result,
release_exec_env);
func = api_result.value.wasm_function_inst_t_value;
wasm_val_t result[1] = { { .kind = WASM_I32 } };
wasm_val_t arguments[1] = {
{ .kind = WASM_I32, .of.i32 = 6 },
};
api_result = wasm_runtime_call_wasm_a_checked(exec_env, func, 1, result, 1,
arguments);
VERIFY_API_RESULT(wasm_runtime_call_wasm_a_checked, api_result,
release_runtime);
printf("Native finished calling wasm function: fib(%d), returned: %d\n",
arguments[0].of.i32, result[0].of.i32);
bh_assert(result[0].of.i32 == 8);
arguments[0].of.i32 = 2;
api_result = wasm_runtime_call_wasm_a_checked(exec_env, func, 1, result, 1,
arguments);
VERIFY_API_RESULT(wasm_runtime_call_wasm_a_checked, api_result,
release_runtime);
printf("Native finished calling wasm function: fib(%d), returned: %d\n",
arguments[0].of.i32, result[0].of.i32);
bh_assert(result[0].of.i32 == 1);
ret = EXIT_SUCCESS;
release_exec_env:
wasm_runtime_destroy_exec_env_checked(exec_env);
release_instance:
wasm_runtime_deinstantiate_checked(module_inst);
release_module:
wasm_runtime_unload_checked(module);
release_file:
wasm_runtime_free(buffer);
release_runtime:
wasm_runtime_destroy_checked();
fail:
return ret;
}

View File

@ -0,0 +1,17 @@
# Copyright (C) 2019 Intel Corporation. All rights reserved.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
cmake_minimum_required (VERSION 3.14)
project(checked_api_wasm_apps)
include(CMakePrintHelpers)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
################ wasm ################
add_executable(fib fib.c)
set_target_properties(fib PROPERTIES SUFFIX .wasm)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/fib.wasm DESTINATION .)

View File

@ -0,0 +1,31 @@
#include <stdio.h>
#include <stdlib.h>
int
fibonacci(int n)
{
if (n <= 0)
return 0;
if (n == 1)
return 1;
return fibonacci(n - 1) + fibonacci(n - 2);
}
__attribute__((export_name("fib"))) int
fib(int n)
{
int result = fibonacci(n);
return result;
}
int
main(int argc, char **argv)
{
int n = atoi(argv[1]);
printf("fibonacci(%d)=%d\n", n, fibonacci(n));
return 0;
}