From b554a9d05d89bb4ef28068b4ae4d0ee6c99bc9db Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Tue, 6 Jul 2021 17:05:59 +0800 Subject: [PATCH] Implement wasm-c-api frame/trap APIs for interpreter mode (#660) And enable to cache compiled AOT file buffer for wasm-c-api JIT mode Avoid checks that rely on undefined C behavior Fix issues of wasm-c-api sample trap and callback_chain Signed-off-by: Wenyong Huang --- README.md | 2 +- TSC_Charter.md | 24 +- core/iwasm/aot/aot_runtime.c | 4 +- core/iwasm/common/wasm_c_api.c | 268 ++++++++++++++++++-- core/iwasm/common/wasm_c_api_internal.h | 8 + core/iwasm/compilation/aot_compiler.c | 150 +++++++++-- core/iwasm/compilation/aot_compiler.h | 13 +- core/iwasm/include/aot_export.h | 7 + core/iwasm/interpreter/wasm_loader.c | 3 +- core/iwasm/interpreter/wasm_mini_loader.c | 6 +- core/iwasm/interpreter/wasm_runtime.c | 80 +++++- core/iwasm/interpreter/wasm_runtime.h | 13 + product-mini/platforms/linux/CMakeLists.txt | 6 + samples/wasm-c-api/CMakeLists.txt | 1 + samples/wasm-c-api/src/callback_chain.c | 57 +++-- samples/wasm-c-api/src/trap.c | 36 ++- 16 files changed, 575 insertions(+), 103 deletions(-) diff --git a/README.md b/README.md index d12b5e8b47..6ee1c6bdf3 100644 --- a/README.md +++ b/README.md @@ -132,7 +132,7 @@ The WAMR [samples](./samples) integrate the iwasm VM core, application manager a Project Technical Steering Committee ==================================== -The [WAMR PTSC Charter](./TSC_Charter.md) governs the operations of the project TSC. +The [WAMR PTSC Charter](./TSC_Charter.md) governs the operations of the project TSC. The current TSC members: - [lum1n0us](https://github.com/lum1n0us) - **Liang He**, - [qinxk-inter](https://github.com/qinxk-inter) - **Xiaokang Qin**, diff --git a/TSC_Charter.md b/TSC_Charter.md index 6cb8ddd282..56c4a024b9 100644 --- a/TSC_Charter.md +++ b/TSC_Charter.md @@ -2,23 +2,23 @@ ## Section 1. Guiding Principle -The WebAssembly Micro Runtime (WAMR) project is part of the -Bytecode Alliance (BA) which operates transparently, openly, -collaboratively, and ethically. Project proposals, timelines, and status +The WebAssembly Micro Runtime (WAMR) project is part of the +Bytecode Alliance (BA) which operates transparently, openly, +collaboratively, and ethically. Project proposals, timelines, and status must not merely be open, but also easily visible to outsiders. ## Section 2. Project Governance under Bytecode Alliance -Technical leadership for the WAMR projects within the Bytecode Alliance -is delegated to the projects through the project charter. Though the BA TSC +Technical leadership for the WAMR projects within the Bytecode Alliance +is delegated to the projects through the project charter. Though the BA TSC will not interfere with day-to-day discussions, votes or meetings of the PTSC, -the BA TSC may request additional amendments to the PTSC charter when +the BA TSC may request additional amendments to the PTSC charter when there is misalignment between the project charter and the BA mission and values. -The PTSC structure described in this document may be overhauled as part of -establishing a BA TSC in order to adhere to constraints or requirements that +The PTSC structure described in this document may be overhauled as part of +establishing a BA TSC in order to adhere to constraints or requirements that TSC will impose on project-level governance. ## Section 3. Establishment of the PTSC @@ -26,7 +26,7 @@ TSC will impose on project-level governance. PTSC memberships are not time-limited. There is no maximum size of the PTSC. The size is expected to vary in order to ensure adequate coverage of important areas of expertise, balanced with the ability to make decisions efficiently. -The PTSC must have at least four members. +The PTSC must have at least four members. There is no specific set of requirements or qualifications for PTSC membership beyond these rules. The PTSC may add additional members to the @@ -77,11 +77,11 @@ The PTSC will define WAMR project’s release vehicles. ## Section 5. WAMR Project Operations -The PTSC will establish and maintain a development process for the WAMR +The PTSC will establish and maintain a development process for the WAMR project. The development process will establish guidelines for how the developers and community will operate. It will, for example, establish appropriate timelines for PTSC review (e.g. agenda items must be -published at least a certain number of hours in advance of a PTSC +published at least a certain number of hours in advance of a PTSC meeting). The PTSC and entire technical community will follow any processes as may @@ -106,7 +106,7 @@ the candidate's election. Elections shall be done within the projects by the Collaborators active in the project. The PTSC will elect from amongst voting PTSC members a PTSC Chairperson to -work on building an agenda for PTSC meetings. The PTSC shall hold annual +work on building an agenda for PTSC meetings. The PTSC shall hold annual elections to select a PTSC Chairperson; there are no limits on the number of terms a PTSC Chairperson may serve. diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 90139788ca..f03d2a11f2 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -1896,7 +1896,7 @@ aot_validate_app_addr(AOTModuleInstance *module_inst, } /* integer overflow check */ - if(app_offset + size < app_offset) { + if(app_offset > UINT32_MAX - size) { goto fail; } @@ -1920,7 +1920,7 @@ aot_validate_native_addr(AOTModuleInstance *module_inst, } /* integer overflow check */ - if (addr + size < addr) { + if ((uintptr_t)addr > UINTPTR_MAX - size) { goto fail; } diff --git a/core/iwasm/common/wasm_c_api.c b/core/iwasm/common/wasm_c_api.c index 90d059e75d..3c44c6b9cb 100644 --- a/core/iwasm/common/wasm_c_api.c +++ b/core/iwasm/common/wasm_c_api.c @@ -189,7 +189,7 @@ failed: \ size_t i = 0; \ memset(out, 0, sizeof(Vector)); \ \ - if (!src->size) { \ + if (!src || !src->size) { \ return; \ } \ \ @@ -232,6 +232,7 @@ WASM_DEFINE_VEC_OWN(store, wasm_store_delete) WASM_DEFINE_VEC_OWN(module, wasm_module_delete_internal) WASM_DEFINE_VEC_OWN(instance, wasm_instance_delete_internal) WASM_DEFINE_VEC_OWN(extern, wasm_extern_delete) +WASM_DEFINE_VEC_OWN(frame, wasm_frame_delete) static inline bool valid_module_type(uint32 module_type) @@ -255,6 +256,21 @@ valid_module_type(uint32 module_type) return result; } +/* conflicting declaration between aot_export.h and aot.h */ +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0 +bool +aot_compile_wasm_file_init(); + +void +aot_compile_wasm_file_destroy(); + +uint8* +aot_compile_wasm_file(const uint8 *wasm_file_buf, uint32 wasm_file_size, + uint32 opt_level, uint32 size_level, + char *error_buf, uint32 error_buf_size, + uint32 *p_aot_file_size); +#endif + /* Runtime Environment */ static void wasm_engine_delete_internal(wasm_engine_t *engine) @@ -264,6 +280,10 @@ wasm_engine_delete_internal(wasm_engine_t *engine) wasm_runtime_free(engine); } +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0 + aot_compile_wasm_file_destroy(); +#endif + wasm_runtime_destroy(); } @@ -311,6 +331,12 @@ wasm_engine_new_internal(mem_alloc_type_t type, const MemAllocOption *opts) bh_log_set_verbose_level(3); #endif +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0 + if (!aot_compile_wasm_file_init()) { + goto failed; + } +#endif + /* create wasm_engine_t */ if (!(engine = malloc_internal(sizeof(wasm_engine_t)))) { goto failed; @@ -1289,10 +1315,106 @@ wasm_val_same(const wasm_val_t *v1, const wasm_val_t *v2) return false; } +static wasm_frame_t * +wasm_frame_new(wasm_instance_t *instance, + size_t module_offset, + uint32 func_index, + size_t func_offset) +{ + wasm_frame_t *frame; + + if (!(frame = malloc_internal(sizeof(wasm_frame_t)))) { + return NULL; + } + + frame->instance = instance; + frame->module_offset = module_offset; + frame->func_index = func_index; + frame->func_offset = func_offset; + return frame; +} + +own wasm_frame_t * +wasm_frame_copy(const wasm_frame_t *src) +{ + if (!src) { + return NULL; + } + + return wasm_frame_new(src->instance, src->module_offset, src->func_index, + src->func_offset); +} + +void +wasm_frame_delete(own wasm_frame_t *frame) +{ + if (!frame) { + return; + } + + wasm_runtime_free(frame); +} + +struct wasm_instance_t * +wasm_frame_instance(const wasm_frame_t *frame) +{ + return frame ? frame->instance : NULL; +} + +size_t +wasm_frame_module_offset(const wasm_frame_t *frame) +{ + return frame ? frame->module_offset : 0; +} + +uint32_t +wasm_frame_func_index(const wasm_frame_t *frame) +{ + return frame ? frame->func_index : 0; +} + +size_t +wasm_frame_func_offset(const wasm_frame_t *frame) +{ + return frame ? frame->func_offset : 0; +} + static wasm_trap_t * -wasm_trap_new_internal(const char *string) +wasm_trap_new_internal(WASMModuleInstanceCommon *inst_comm_rt, + const char *default_error_info) { wasm_trap_t *trap; + const char *error_info = NULL; + wasm_instance_vec_t *instances; + wasm_instance_t *frame_instance = NULL; + uint32 i; + + if (!singleton_engine || !singleton_engine->stores + || !singleton_engine->stores->num_elems) { + return NULL; + } + +#if WASM_ENABLE_INTERP != 0 + if (inst_comm_rt->module_type == Wasm_Module_Bytecode) { + if (!(error_info = + wasm_get_exception((WASMModuleInstance *)inst_comm_rt))) { + return NULL; + } + } +#endif + +#if WASM_ENABLE_AOT != 0 + if (inst_comm_rt->module_type == Wasm_Module_AoT) { + if (!(error_info = + aot_get_exception((AOTModuleInstance *)inst_comm_rt))) { + return NULL; + } + } +#endif + + if (!error_info && !(error_info = default_error_info)) { + return NULL; + } if (!(trap = malloc_internal(sizeof(wasm_trap_t)))) { return NULL; @@ -1302,11 +1424,39 @@ wasm_trap_new_internal(const char *string) goto failed; } - wasm_name_new_from_string(trap->message, string); - if (strlen(string) && !trap->message->data) { + wasm_name_new_from_string_nt(trap->message, error_info); + if (strlen(error_info) && !trap->message->data) { goto failed; } +#if WASM_ENABLE_DUMP_CALL_STACK != 0 +#if WASM_ENABLE_INTERP != 0 + if (inst_comm_rt->module_type == Wasm_Module_Bytecode) { + trap->frames = ((WASMModuleInstance *)inst_comm_rt)->frames; + } +#endif +#endif /* WASM_ENABLE_DUMP_CALL_STACK != 0 */ + + /* allow a NULL frames list */ + if (!trap->frames) { + return trap; + } + + if (!(instances = singleton_engine->stores->data[0]->instances)) { + goto failed; + } + + for (i = 0; i < instances->num_elems; i++) { + if (instances->data[i]->inst_comm_rt == inst_comm_rt) { + frame_instance = instances->data[i]; + break; + } + } + + for (i = 0; i < trap->frames->num_elems; i++) { + (((wasm_frame_t *)trap->frames->data) + i)->instance = frame_instance; + } + return trap; failed: wasm_trap_delete(trap); @@ -1342,6 +1492,7 @@ wasm_trap_delete(wasm_trap_t *trap) } DEINIT_VEC(trap->message, wasm_byte_vec_delete); + /* reuse frames of WASMModuleInstance, do not free it here */ wasm_runtime_free(trap); } @@ -1356,6 +1507,65 @@ wasm_trap_message(const wasm_trap_t *trap, own wasm_message_t *out) wasm_byte_vec_copy(out, trap->message); } +own wasm_frame_t * +wasm_trap_origin(const wasm_trap_t *trap) +{ + wasm_frame_t *latest_frame; + + if (!trap || !trap->frames || !trap->frames->num_elems) { + return NULL; + } + + /* first frame is the latest frame */ + latest_frame = (wasm_frame_t *)trap->frames->data; + return wasm_frame_copy(latest_frame); +} + +void +wasm_trap_trace(const wasm_trap_t *trap, own wasm_frame_vec_t *out) +{ + uint32 i; + + if (!trap || !out) { + return; + } + + if (!trap->frames || !trap->frames->num_elems) { + wasm_frame_vec_new_empty(out); + return; + } + + wasm_frame_vec_new_uninitialized(out, trap->frames->num_elems); + if (out->size && !out->data) { + return; + } + + for (i = 0; i < trap->frames->num_elems; i++) { + wasm_frame_t *frame; + + frame = ((wasm_frame_t *)trap->frames->data) + i; + + if (!(out->data[i] = + wasm_frame_new(frame->instance, frame->module_offset, + frame->func_index, frame->func_offset))) { + goto failed; + } + out->num_elems++; + } + + return; +failed: + for (i = 0; i < out->num_elems; i++) { + if (out->data[i]) { + wasm_runtime_free(out->data[i]); + } + } + + if (out->data) { + wasm_runtime_free(out->data); + } +} + struct wasm_module_ex_t { struct WASMModuleCommon *module_comm_rt; wasm_byte_vec_t *binary; @@ -1386,6 +1596,10 @@ wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary) { char error_buf[128] = { 0 }; wasm_module_ex_t *module_ex = NULL; +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0 + uint8 *aot_file_buf = NULL; + uint32 aot_file_size; +#endif bh_assert(singleton_engine); @@ -1401,12 +1615,35 @@ wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary) INIT_VEC(module_ex->binary, wasm_byte_vec_new, binary->size, binary->data); - module_ex->module_comm_rt = wasm_runtime_load( - (uint8 *)module_ex->binary->data, (uint32)module_ex->binary->size, - error_buf, (uint32)sizeof(error_buf)); - if (!(module_ex->module_comm_rt)) { - LOG_ERROR(error_buf); - goto failed; +#if WASM_ENABLE_AOT != 0 && WASM_ENABLE_JIT != 0 + if (get_package_type((uint8 *)module_ex->binary->data, + (uint32)module_ex->binary->size) + == Wasm_Module_Bytecode) { + if (!(aot_file_buf = aot_compile_wasm_file( + (uint8 *)module_ex->binary->data, + (uint32)module_ex->binary->size, 3, 3, error_buf, + (uint32)sizeof(error_buf), &aot_file_size))) { + LOG_ERROR(error_buf); + goto failed; + } + + if (!(module_ex->module_comm_rt = + wasm_runtime_load(aot_file_buf, aot_file_size, error_buf, + (uint32)sizeof(error_buf)))) { + LOG_ERROR(error_buf); + goto failed; + } + } + else +#endif + { + module_ex->module_comm_rt = wasm_runtime_load( + (uint8 *)module_ex->binary->data, (uint32)module_ex->binary->size, + error_buf, (uint32)sizeof(error_buf)); + if (!(module_ex->module_comm_rt)) { + LOG_ERROR(error_buf); + goto failed; + } } /* add it to a watching list in store */ @@ -2255,12 +2492,13 @@ wasm_func_call(const wasm_func_t *func, if (argv != argv_buf) wasm_runtime_free(argv); + /* trap -> exception -> trap */ if (wasm_runtime_get_exception(func->inst_comm_rt)) { - return wasm_trap_new_internal( - wasm_runtime_get_exception(func->inst_comm_rt)); + return wasm_trap_new_internal(func->inst_comm_rt, NULL); } else { - return wasm_trap_new_internal("wasm_func_call failed"); + return wasm_trap_new_internal(func->inst_comm_rt, + "wasm_func_call failed"); } } @@ -3446,8 +3684,8 @@ wasm_instance_new(wasm_store_t *store, own wasm_trap_t **traps) { char error_buf[128] = { 0 }; - const uint32 stack_size = 16 * 1024; - const uint32 heap_size = 16 * 1024; + const uint32 stack_size = 32 * 1024; + const uint32 heap_size = 32 * 1024; uint32 import_count = 0; wasm_instance_t *instance = NULL; uint32 i = 0; diff --git a/core/iwasm/common/wasm_c_api_internal.h b/core/iwasm/common/wasm_c_api_internal.h index 073eead867..0e413551ed 100644 --- a/core/iwasm/common/wasm_c_api_internal.h +++ b/core/iwasm/common/wasm_c_api_internal.h @@ -86,8 +86,16 @@ struct wasm_ref_t { uint32 obj; }; +struct wasm_frame_t { + wasm_instance_t *instance; + uint32 module_offset; + uint32 func_index; + uint32 func_offset; +}; + struct wasm_trap_t { wasm_byte_vec_t *message; + Vector *frames; }; struct wasm_func_t { diff --git a/core/iwasm/compilation/aot_compiler.c b/core/iwasm/compilation/aot_compiler.c index 3232448eee..58d9815e42 100644 --- a/core/iwasm/compilation/aot_compiler.c +++ b/core/iwasm/compilation/aot_compiler.c @@ -2135,19 +2135,82 @@ extern void wasm_set_ref_types_flag(bool enable); #endif +typedef struct AOTFileMap { + uint8 *wasm_file_buf; + uint32 wasm_file_size; + uint8 *aot_file_buf; + uint32 aot_file_size; + struct AOTFileMap *next; +} AOTFileMap; + +static bool aot_compile_wasm_file_inited = false; +static AOTFileMap *aot_file_maps = NULL; +static korp_mutex aot_file_map_lock; + +bool +aot_compile_wasm_file_init() +{ + if (aot_compile_wasm_file_inited) { + return true; + } + + if (BHT_OK != os_mutex_init(&aot_file_map_lock)) { + return false; + } + + aot_file_maps = NULL; + aot_compile_wasm_file_inited = true; + return true; +} + +void +aot_compile_wasm_file_destroy() +{ + AOTFileMap *file_map = aot_file_maps, *file_map_next; + + if (!aot_compile_wasm_file_inited) { + return; + } + + while (file_map) { + file_map_next = file_map->next; + + wasm_runtime_free(file_map->wasm_file_buf); + wasm_runtime_free(file_map->aot_file_buf); + wasm_runtime_free(file_map); + + file_map = file_map_next; + } + + aot_file_maps = NULL; + os_mutex_destroy(&aot_file_map_lock); + aot_compile_wasm_file_inited = false; +} + +static void +set_error_buf(char *error_buf, uint32 error_buf_size, const char *string) +{ + if (error_buf != NULL) { + snprintf(error_buf, error_buf_size, + "WASM module load failed: %s", string); + } +} + uint8* aot_compile_wasm_file(const uint8 *wasm_file_buf, uint32 wasm_file_size, uint32 opt_level, uint32 size_level, + char *error_buf, uint32 error_buf_size, uint32 *p_aot_file_size) { - WASMModuleCommon *wasm_module = NULL; + WASMModule *wasm_module = NULL; AOTCompData *comp_data = NULL; AOTCompContext *comp_ctx = NULL; RuntimeInitArgs init_args; AOTCompOption option = { 0 }; + AOTFileMap *file_map = NULL, *file_map_next; + uint8 *wasm_file_buf_cloned = NULL; uint8 *aot_file_buf = NULL; uint32 aot_file_size; - char error_buf[128]; option.is_jit_mode = false; option.opt_level = opt_level; @@ -2155,7 +2218,6 @@ aot_compile_wasm_file(const uint8 *wasm_file_buf, uint32 wasm_file_size, option.output_format = AOT_FORMAT_FILE; /* default value, enable or disable depends on the platform */ option.bounds_checks = 2; - option.enable_simd = true; option.enable_aux_stack_check = true; #if WASM_ENABLE_BULK_MEMORY != 0 option.enable_bulk_memory = true; @@ -2187,46 +2249,94 @@ aot_compile_wasm_file(const uint8 *wasm_file_buf, uint32 wasm_file_size, init_args.mem_alloc_option.allocator.realloc_func = realloc; init_args.mem_alloc_option.allocator.free_func = free; + os_mutex_lock(&aot_file_map_lock); + + /* lookup the file maps */ + file_map = aot_file_maps; + while (file_map) { + file_map_next = file_map->next; + + if (wasm_file_size == file_map->wasm_file_size + && memcmp(wasm_file_buf, file_map->wasm_file_buf, + wasm_file_size) == 0) { + os_mutex_unlock(&aot_file_map_lock); + /* found */ + *p_aot_file_size = file_map->aot_file_size; + return file_map->aot_file_buf; + } + + file_map = file_map_next; + } + + /* not found, initialize file map and clone wasm file */ + if (!(file_map = wasm_runtime_malloc(sizeof(AOTFileMap))) + || !(wasm_file_buf_cloned = wasm_runtime_malloc(wasm_file_size))) { + set_error_buf(error_buf, error_buf_size, "allocate memory failed"); + goto fail1; + } + + bh_memcpy_s(wasm_file_buf_cloned, wasm_file_size, + wasm_file_buf, wasm_file_size); + memset(file_map, 0, sizeof(AOTFileMap)); + file_map->wasm_file_buf = wasm_file_buf_cloned; + file_map->wasm_file_size = wasm_file_size; + /* load WASM module */ - if (!(wasm_module = (WASMModuleCommon*) - wasm_load(wasm_file_buf, wasm_file_size, + if (!(wasm_module = wasm_load(wasm_file_buf, wasm_file_size, error_buf, sizeof(error_buf)))) { - os_printf("%s\n", error_buf); - aot_set_last_error(error_buf); - return NULL; + goto fail1; } - if (!(comp_data = aot_create_comp_data((WASMModule*)wasm_module))) { - os_printf("%s\n", aot_get_last_error()); - goto fail1; + if (!(comp_data = aot_create_comp_data(wasm_module))) { + set_error_buf(error_buf, error_buf_size, aot_get_last_error()); + goto fail2; } if (!(comp_ctx = aot_create_comp_context(comp_data, &option))) { - os_printf("%s\n", aot_get_last_error()); - goto fail2; + set_error_buf(error_buf, error_buf_size, aot_get_last_error()); + goto fail3; } if (!aot_compile_wasm(comp_ctx)) { - os_printf("%s\n", aot_get_last_error()); - goto fail3; + set_error_buf(error_buf, error_buf_size, aot_get_last_error()); + goto fail4; } if (!(aot_file_buf = aot_emit_aot_file_buf(comp_ctx, comp_data, &aot_file_size))) { - os_printf("%s\n", aot_get_last_error()); - goto fail3; + set_error_buf(error_buf, error_buf_size, aot_get_last_error()); + goto fail4; + } + + file_map->aot_file_buf = aot_file_buf; + file_map->aot_file_size = aot_file_size; + + if (!aot_file_maps) + aot_file_maps = file_map; + else { + file_map->next = aot_file_maps; + aot_file_maps = file_map; } *p_aot_file_size = aot_file_size; -fail3: +fail4: /* Destroy compiler context */ aot_destroy_comp_context(comp_ctx); -fail2: +fail3: /* Destroy compile data */ aot_destroy_comp_data(comp_data); +fail2: + wasm_unload(wasm_module); fail1: - wasm_runtime_unload(wasm_module); + if (!aot_file_buf) { + if (wasm_file_buf_cloned) + wasm_runtime_free(wasm_file_buf_cloned); + if (file_map) + wasm_runtime_free(file_map); + } + + os_mutex_unlock(&aot_file_map_lock); return aot_file_buf; } diff --git a/core/iwasm/compilation/aot_compiler.h b/core/iwasm/compilation/aot_compiler.h index feb2eaff4b..9f6a214711 100644 --- a/core/iwasm/compilation/aot_compiler.h +++ b/core/iwasm/compilation/aot_compiler.h @@ -368,18 +368,19 @@ aot_emit_aot_file(AOTCompContext *comp_ctx, AOTCompData *comp_data, const char *file_name); -uint8_t* +uint8* aot_emit_aot_file_buf(AOTCompContext *comp_ctx, AOTCompData *comp_data, - uint32_t *p_aot_file_size); + uint32 *p_aot_file_size); bool aot_emit_object_file(AOTCompContext *comp_ctx, char *file_name); -uint8_t* -aot_compile_wasm_file(const uint8_t *wasm_file_buf, uint32_t wasm_file_size, - uint32_t opt_level, uint32_t size_level, - uint32_t *p_aot_file_size); +uint8* +aot_compile_wasm_file(const uint8 *wasm_file_buf, uint32 wasm_file_size, + uint32 opt_level, uint32 size_level, + char *error_buf, uint32 error_buf_size, + uint32 *p_aot_file_size); #ifdef __cplusplus } /* end of extern "C" */ diff --git a/core/iwasm/include/aot_export.h b/core/iwasm/include/aot_export.h index d209044cee..eb0aba05ca 100644 --- a/core/iwasm/include/aot_export.h +++ b/core/iwasm/include/aot_export.h @@ -77,11 +77,18 @@ aot_emit_aot_file(aot_comp_context_t comp_ctx, void aot_destroy_aot_file(uint8_t *aot_file); +bool +aot_compile_wasm_file_init(); + uint8_t* aot_compile_wasm_file(const uint8_t *wasm_file_buf, uint32_t wasm_file_size, uint32_t opt_level, uint32_t size_level, + char *error_buf, uint32_t error_buf_size, uint32_t *p_aot_file_size); +void +aot_compile_wasm_file_destroy(); + char* aot_get_last_error(); diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index a3db0a2d08..854911ff55 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -1950,7 +1950,8 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, local_type_index = 0; for (j = 0; j < local_set_count; j++) { read_leb_uint32(p_code, buf_code_end, sub_local_count); - if (local_type_index + sub_local_count <= local_type_index + if (!sub_local_count + || local_type_index > UINT32_MAX - sub_local_count || local_type_index + sub_local_count > local_count) { set_error_buf(error_buf, error_buf_size, "invalid local count"); diff --git a/core/iwasm/interpreter/wasm_mini_loader.c b/core/iwasm/interpreter/wasm_mini_loader.c index 9340682027..342838e4b1 100644 --- a/core/iwasm/interpreter/wasm_mini_loader.c +++ b/core/iwasm/interpreter/wasm_mini_loader.c @@ -981,8 +981,10 @@ load_function_section(const uint8 *buf, const uint8 *buf_end, local_type_index = 0; for (j = 0; j < local_set_count; j++) { read_leb_uint32(p_code, buf_code_end, sub_local_count); - bh_assert(!(local_type_index + sub_local_count <= local_type_index - || local_type_index + sub_local_count > local_count)); + bh_assert(sub_local_count + && local_type_index <= UINT32_MAX - sub_local_count + && local_type_index + sub_local_count + <= local_count); CHECK_BUF(p_code, buf_code_end, 1); /* 0x7F/0x7E/0x7D/0x7C */ diff --git a/core/iwasm/interpreter/wasm_runtime.c b/core/iwasm/interpreter/wasm_runtime.c index 0b43f18958..5d47ba7805 100644 --- a/core/iwasm/interpreter/wasm_runtime.c +++ b/core/iwasm/interpreter/wasm_runtime.c @@ -1580,6 +1580,14 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst) if (module_inst->exec_env_singleton) wasm_exec_env_destroy(module_inst->exec_env_singleton); +#if WASM_ENABLE_DUMP_CALL_STACK != 0 + if (module_inst->frames) { + bh_vector_destroy(module_inst->frames); + wasm_runtime_free(module_inst->frames); + module_inst->frames = NULL; + } +#endif + wasm_runtime_free(module_inst); } @@ -1925,7 +1933,7 @@ wasm_validate_app_addr(WASMModuleInstance *module_inst, memory_data_size = memory->num_bytes_per_page * memory->cur_page_count; /* integer overflow check */ - if (app_offset + size < app_offset) { + if (app_offset > UINT32_MAX - size) { goto fail; } @@ -1949,7 +1957,7 @@ wasm_validate_native_addr(WASMModuleInstance *module_inst, } /* integer overflow check */ - if (addr + size < addr) { + if ((uintptr_t)addr > UINTPTR_MAX - size) { goto fail; } @@ -2421,19 +2429,59 @@ void wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env) { WASMModuleInstance *module_inst = - (WASMModuleInstance *)wasm_exec_env_get_module_inst(exec_env); - WASMInterpFrame *cur_frame = - wasm_exec_env_get_cur_frame(exec_env); - WASMFunctionInstance *func_inst; - WASMExportFuncInstance *export_func; - const char *func_name = NULL; - uint32 n, i; + (WASMModuleInstance *)wasm_exec_env_get_module_inst(exec_env); + WASMInterpFrame *first_frame, + *cur_frame = wasm_exec_env_get_cur_frame(exec_env); + uint32 n = 0; + + /* release previous stack frame */ + if (module_inst->frames) { + bh_vector_destroy(module_inst->frames); + wasm_runtime_free(module_inst->frames); + module_inst->frames = NULL; + } + + /* count frames includes a function */ + first_frame = cur_frame; + while (cur_frame) { + if (cur_frame->function) { + n++; + } + cur_frame = cur_frame->prev_frame; + } + if (!(module_inst->frames = runtime_malloc( + (uint64)sizeof(Vector), module_inst->cur_exception, 128))) { + return; + } + + if (!bh_vector_init(module_inst->frames, n, sizeof(struct WASMFrame))) { + wasm_runtime_free(module_inst->frames); + module_inst->frames = NULL; + return; + } + + cur_frame = first_frame; + n = 0; os_printf("\n"); - for (n = 0; cur_frame && cur_frame->function; n++) { - func_name = NULL; - func_inst = cur_frame->function; + while (cur_frame) { + struct WASMFrame frame = { 0 }; + WASMFunctionInstance *func_inst = cur_frame->function; + const char *func_name = NULL; + if (!func_inst) { + cur_frame = cur_frame->prev_frame; + continue; + } + + /* place holder, will overwrite it in wasm_c_api */ + frame.instance = module_inst; + frame.module_offset = 0; + frame.func_index = func_inst - module_inst->functions; + frame.func_offset = + cur_frame->ip ? cur_frame->ip - func_inst->u.func->code : 0; + + /* look for the function name */ if (func_inst->is_import_func) { func_name = func_inst->u.func_import->field_name; } @@ -2444,8 +2492,10 @@ wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env) /* if custom name section is not generated, search symbols from export table */ if (!func_name) { + uint32 i; for (i = 0; i < module_inst->export_func_count; i++) { - export_func = module_inst->export_functions + i; + WASMExportFuncInstance *export_func = + module_inst->export_functions + i; if (export_func->function == func_inst) { func_name = export_func->name; break; @@ -2462,7 +2512,11 @@ wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env) os_printf("#%02d %s \n", n, func_name); } + /* keep print */ + bh_vector_append(module_inst->frames, &frame); + cur_frame = cur_frame->prev_frame; + n++; } os_printf("\n"); } diff --git a/core/iwasm/interpreter/wasm_runtime.h b/core/iwasm/interpreter/wasm_runtime.h index 55c13c282d..473407ba3d 100644 --- a/core/iwasm/interpreter/wasm_runtime.h +++ b/core/iwasm/interpreter/wasm_runtime.h @@ -150,6 +150,15 @@ typedef struct WASMExportMemInstance { } WASMExportMemInstance; #endif +#if WASM_ENABLE_DUMP_CALL_STACK != 0 +struct WASMFrame { + void *instance; + uint32 module_offset; + uint32 func_index; + uint32 func_offset; +}; +#endif + struct WASMModuleInstance { /* Module instance type, for module instance loaded from WASM bytecode binary, this field is Wasm_Module_Bytecode; @@ -209,6 +218,10 @@ struct WASMModuleInstance { /* The exception buffer of wasm interpreter for current thread. */ char cur_exception[128]; +#if WASM_ENABLE_DUMP_CALL_STACK != 0 + Vector *frames; +#endif + /* The custom data that can be set/get by * wasm_set_custom_data/wasm_get_custom_data */ void *custom_data; diff --git a/product-mini/platforms/linux/CMakeLists.txt b/product-mini/platforms/linux/CMakeLists.txt index 231bd0720e..e34d95a52e 100644 --- a/product-mini/platforms/linux/CMakeLists.txt +++ b/product-mini/platforms/linux/CMakeLists.txt @@ -94,6 +94,12 @@ if (COLLECT_CODE_COVERAGE EQUAL 1) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") endif () +# UNDEFINED BEHAVIOR +# refer to https://en.cppreference.com/w/cpp/language/ub +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=bounds-strict,undefined -fno-sanitize-recover") +endif() + set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..) include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake) diff --git a/samples/wasm-c-api/CMakeLists.txt b/samples/wasm-c-api/CMakeLists.txt index 334232e8d6..d0bfffa595 100644 --- a/samples/wasm-c-api/CMakeLists.txt +++ b/samples/wasm-c-api/CMakeLists.txt @@ -41,6 +41,7 @@ endif() set(WAMR_BUILD_LIBC_BUILTIN 1) set(WAMR_BUILD_LIBC_WASI 0) set(WAMR_BUILD_MULTI_MODULE 1) +set(WAMR_BUILD_DUMP_CALL_STACK 1) if(NOT DEFINED WAMR_BUILD_FAST_INTERP) set(WAMR_BUILD_FAST_INTERP 1) diff --git a/samples/wasm-c-api/src/callback_chain.c b/samples/wasm-c-api/src/callback_chain.c index ab15d08235..38e8ab7690 100644 --- a/samples/wasm-c-api/src/callback_chain.c +++ b/samples/wasm-c-api/src/callback_chain.c @@ -92,32 +92,6 @@ DEFINE_FUNCTION(log) return NULL; } -static inline void -create_import_function_list(wasm_store_t *store, - const wasm_extern_t *import_function_list[]) -{ -#define IMPORT_FUNCTION_VARIABLE_NAME(name, ...) \ - own wasm_func_t *function_##name = NULL; - IMPORT_FUNCTION_LIST(IMPORT_FUNCTION_VARIABLE_NAME) -#undef IMPORT_FUNCTION_VARIABLE_NAME - -#define CREATE_WASM_FUNCTION(name, index, CREATE_FUNC_TYPE) \ - { \ - own wasm_functype_t *type = CREATE_FUNC_TYPE; \ - if (!(function_##name = wasm_func_new(store, type, STUB_##name))) { \ - printf("> Error creating new function\n"); \ - } \ - wasm_functype_delete(type); \ - } - IMPORT_FUNCTION_LIST(CREATE_WASM_FUNCTION) -#undef CREATE_WASM_FUNCTION - -#define ADD_TO_FUNCTION_LIST(name, index, ...) \ - import_function_list[index] = wasm_func_as_extern(function_##name); - IMPORT_FUNCTION_LIST(ADD_TO_FUNCTION_LIST) -#undef CREATE_IMPORT_FUNCTION -} - /**********************************************************************/ // all exportted wasm functions. check with "/opt/wabt/bin/wasm-objdump -x -j Export X.wasm" // -1: memory @@ -221,11 +195,33 @@ main(int argc, const char *argv[]) // Instantiate. printf("Instantiating module...\n"); - const wasm_extern_t *imports[10] = { 0 }; // Create external functions. printf("Creating callback...\n"); - create_import_function_list(store, imports); +#define IMPORT_FUNCTION_VARIABLE_NAME(name, ...) \ + own wasm_func_t *function_##name = NULL; + IMPORT_FUNCTION_LIST(IMPORT_FUNCTION_VARIABLE_NAME) +#undef IMPORT_FUNCTION_VARIABLE_NAME + + const wasm_extern_t *imports[10] = { 0 }; + +#define CREATE_WASM_FUNCTION(name, index, CREATE_FUNC_TYPE) \ + { \ + own wasm_functype_t *type = CREATE_FUNC_TYPE; \ + if (!(function_##name = wasm_func_new(store, type, STUB_##name))) { \ + printf("> Error creating new function\n"); \ + return 1; \ + } \ + wasm_functype_delete(type); \ + } + IMPORT_FUNCTION_LIST(CREATE_WASM_FUNCTION) +#undef CREATE_WASM_FUNCTION + +#define ADD_TO_FUNCTION_LIST(name, index, ...) \ + imports[index] = wasm_func_as_extern(function_##name); + IMPORT_FUNCTION_LIST(ADD_TO_FUNCTION_LIST) +#undef CREATE_IMPORT_FUNCTION + own wasm_instance_t *instance = wasm_instance_new(store, module, imports, NULL); @@ -234,6 +230,11 @@ main(int argc, const char *argv[]) return 1; } +#define DESTROY_WASM_FUNCITON(name, index, ...) \ + wasm_func_delete(function_##name); + IMPORT_FUNCTION_LIST(DESTROY_WASM_FUNCITON) +#undef DESTROY_WASM_FUNCITON + // Extract export. printf("Extracting export...\n"); wasm_instance_exports(instance, &exports); diff --git a/samples/wasm-c-api/src/trap.c b/samples/wasm-c-api/src/trap.c index e121419036..6b42b35180 100644 --- a/samples/wasm-c-api/src/trap.c +++ b/samples/wasm-c-api/src/trap.c @@ -19,6 +19,17 @@ own wasm_trap_t* fail_callback( return trap; } + +void print_frame(wasm_frame_t* frame) { + printf("> %p @ 0x%zx = %"PRIu32".0x%zx\n", + wasm_frame_instance(frame), + wasm_frame_module_offset(frame), + wasm_frame_func_index(frame), + wasm_frame_func_offset(frame) + ); +} + + int main(int argc, const char* argv[]) { // Initialize. printf("Initializing...\n"); @@ -93,7 +104,6 @@ int main(int argc, const char* argv[]) { // Call. for (int i = 0; i < 2; ++i) { - char buf[32]; const wasm_func_t* func = wasm_extern_as_func(exports.data[i]); if (func == NULL) { printf("> Error accessing export!\n"); @@ -111,9 +121,29 @@ int main(int argc, const char* argv[]) { printf("Printing message...\n"); own wasm_name_t message; wasm_trap_message(trap, &message); - snprintf(buf, sizeof(buf), "> %%.%us\n", (unsigned)message.size); - printf(buf, message.data); + printf("> %s\n", message.data); + + printf("Printing origin...\n"); + own wasm_frame_t* frame = wasm_trap_origin(trap); + if (frame) { + print_frame(frame); + wasm_frame_delete(frame); + } else { + printf("> Empty origin.\n"); + } + + printf("Printing trace...\n"); + own wasm_frame_vec_t trace; + wasm_trap_trace(trap, &trace); + if (trace.size > 0) { + for (size_t i = 0; i < trace.size; ++i) { + print_frame(trace.data[i]); + } + } else { + printf("> Empty trace.\n"); + } + wasm_frame_vec_delete(&trace); wasm_trap_delete(trap); wasm_name_delete(&message); }