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>
This commit is contained in:
Wenyong Huang 2021-07-06 17:05:59 +08:00 committed by GitHub
parent d91047cc37
commit b554a9d05d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 576 additions and 104 deletions

View File

@ -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>

View File

@ -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 projects 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.

View File

@ -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;
}

View File

@ -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;

View File

@ -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 {

View File

@ -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;
/* load WASM module */
if (!(wasm_module = (WASMModuleCommon*)
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;
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;
}
if (!(comp_data = aot_create_comp_data((WASMModule*)wasm_module))) {
os_printf("%s\n", aot_get_last_error());
/* 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;
}
if (!(comp_ctx = aot_create_comp_context(comp_data, &option))) {
os_printf("%s\n", aot_get_last_error());
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 = wasm_load(wasm_file_buf, wasm_file_size,
error_buf, sizeof(error_buf)))) {
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 (!aot_compile_wasm(comp_ctx)) {
os_printf("%s\n", aot_get_last_error());
if (!(comp_ctx = aot_create_comp_context(comp_data, &option))) {
set_error_buf(error_buf, error_buf_size, aot_get_last_error());
goto fail3;
}
if (!aot_compile_wasm(comp_ctx)) {
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;
}

View File

@ -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" */

View File

@ -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();

View File

@ -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");

View File

@ -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 */

View File

@ -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");
}

View File

@ -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;

View File

@ -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)

View File

@ -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)

View File

@ -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);

View File

@ -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);
}