mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-11-27 01:50:50 +00:00
Merge 58a9bae9c6 into 418be9dfee
This commit is contained in:
commit
f090909a30
59
.github/workflows/verify_checked_apis.yml
vendored
Normal file
59
.github/workflows/verify_checked_apis.yml
vendored
Normal 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
|
||||
318
ci/generate_checked_functions.py
Normal file
318
ci/generate_checked_functions.py
Normal 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()
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
#define __AOT_COMP_OPTION_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
|
|||
42
core/iwasm/include/aot_comp_option_checked.h
Normal file
42
core/iwasm/include/aot_comp_option_checked.h
Normal 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
|
||||
334
core/iwasm/include/aot_export_checked.h
Normal file
334
core/iwasm/include/aot_export_checked.h
Normal 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
|
||||
4010
core/iwasm/include/gc_export_checked.h
Normal file
4010
core/iwasm/include/gc_export_checked.h
Normal file
File diff suppressed because it is too large
Load Diff
49
core/iwasm/include/lib_export_checked.h
Normal file
49
core/iwasm/include/lib_export_checked.h
Normal 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
|
||||
6205
core/iwasm/include/wasm_c_api_checked.h
Normal file
6205
core/iwasm/include/wasm_c_api_checked.h
Normal file
File diff suppressed because it is too large
Load Diff
2940
core/iwasm/include/wasm_export_checked.h
Normal file
2940
core/iwasm/include/wasm_export_checked.h
Normal file
File diff suppressed because it is too large
Load Diff
61
samples/checked-api/CMakeLists.txt
Normal file
61
samples/checked-api/CMakeLists.txt
Normal 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}
|
||||
)
|
||||
110
samples/checked-api/src/demo.c
Normal file
110
samples/checked-api/src/demo.c
Normal 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;
|
||||
}
|
||||
17
samples/checked-api/wasm-apps/CMakeLists.txt
Normal file
17
samples/checked-api/wasm-apps/CMakeLists.txt
Normal 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 .)
|
||||
31
samples/checked-api/wasm-apps/fib.c
Normal file
31
samples/checked-api/wasm-apps/fib.c
Normal 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;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user