فهرست منبع

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 <wenyong.huang@intel.com>
Wenyong Huang 4 سال پیش
والد
کامیت
b554a9d05d

+ 1 - 1
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**, <liang.he@intel.com>
 - [qinxk-inter](https://github.com/qinxk-inter) - **Xiaokang Qin**, <xiaokang.qxk@antgroup.com>

+ 12 - 12
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.

+ 2 - 2
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;
     }
 

+ 253 - 15
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 @@ failed:
     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;

+ 8 - 0
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 {

+ 130 - 20
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;
 }

+ 7 - 6
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" */

+ 7 - 0
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();
 

+ 2 - 1
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");

+ 4 - 2
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 */

+ 67 - 13
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");
 }

+ 13 - 0
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;

+ 6 - 0
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)

+ 1 - 0
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)

+ 29 - 28
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);

+ 33 - 3
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);
   }