Return stack frames of crashed thread when using wasm-c-api (#2908)

When using the wasm-c-api and there's a trap, `wasm_func_call()` returns
a `wasm_trap_t *` object. No matter which thread crashes, the trap contains
the stack frames of the main thread.

With this PR, when there's an exception, the stack frames of the thread
where the exception occurs are stored into the thread cluster.
`wasm_func_call()` can then return those stack frames.
This commit is contained in:
Enrico Loparco 2024-01-11 05:13:05 +01:00 committed by GitHub
parent b21f17dd6d
commit ff25110840
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 73 additions and 8 deletions

View File

@ -1921,10 +1921,26 @@ wasm_frame_func_offset(const wasm_frame_t *frame)
return frame ? frame->func_offset : 0;
}
void
wasm_frame_vec_clone_internal(Vector *src, Vector *out)
{
bh_assert(src->num_elems != 0 && src->data);
bh_vector_destroy(out);
if (!bh_vector_init(out, src->num_elems, sizeof(WASMCApiFrame), false)) {
bh_vector_destroy(out);
return;
}
bh_memcpy_s(out->data, src->num_elems * sizeof(WASMCApiFrame), src->data,
src->num_elems * sizeof(WASMCApiFrame));
out->num_elems = src->num_elems;
}
static wasm_trap_t *
wasm_trap_new_internal(wasm_store_t *store,
WASMModuleInstanceCommon *inst_comm_rt,
const char *error_info)
const char *error_info, Vector *cluster_frames)
{
wasm_trap_t *trap;
#if WASM_ENABLE_DUMP_CALL_STACK != 0
@ -1954,7 +1970,9 @@ wasm_trap_new_internal(wasm_store_t *store,
/* fill in frames */
#if WASM_ENABLE_DUMP_CALL_STACK != 0
trap->frames = ((WASMModuleInstance *)inst_comm_rt)->frames;
trap->frames = cluster_frames
? cluster_frames
: ((WASMModuleInstance *)inst_comm_rt)->frames;
if (trap->frames) {
/* fill in instances */
@ -2065,10 +2083,7 @@ wasm_trap_trace(const wasm_trap_t *trap, own wasm_frame_vec_t *out)
}
for (i = 0; i < trap->frames->num_elems; i++) {
wasm_frame_t *frame;
frame = ((wasm_frame_t *)trap->frames->data) + i;
wasm_frame_t *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))) {
@ -3252,6 +3267,7 @@ wasm_func_call(const wasm_func_t *func, const wasm_val_vec_t *params,
WASMFunctionInstanceCommon *func_comm_rt = NULL;
WASMExecEnv *exec_env = NULL;
size_t param_count, result_count, alloc_count;
Vector *cluster_frames = NULL;
bh_assert(func && func->type);
@ -3364,9 +3380,20 @@ failed:
if (argv != argv_buf)
wasm_runtime_free(argv);
return wasm_trap_new_internal(
#if WASM_ENABLE_DUMP_CALL_STACK != 0 && WASM_ENABLE_THREAD_MGR != 0
WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env);
cluster_frames = &cluster->exception_frames;
wasm_cluster_traverse_lock(exec_env);
#endif
wasm_trap_t *trap = wasm_trap_new_internal(
func->store, func->inst_comm_rt,
wasm_runtime_get_exception(func->inst_comm_rt));
wasm_runtime_get_exception(func->inst_comm_rt), cluster_frames);
#if WASM_ENABLE_DUMP_CALL_STACK != 0 && WASM_ENABLE_THREAD_MGR != 0
wasm_cluster_traverse_unlock(exec_env);
#endif
return trap;
}
size_t

View File

@ -240,4 +240,7 @@ wasm_memory_new_internal(wasm_store_t *store, uint16 memory_idx_rt,
wasm_table_t *
wasm_table_new_internal(wasm_store_t *store, uint16 table_idx_rt,
WASMModuleInstanceCommon *inst_comm_rt);
void
wasm_frame_vec_clone_internal(Vector *src, Vector *out);
#endif /* _WASM_C_API_INTERNAL_H */

View File

@ -4,6 +4,7 @@
*/
#include "thread_manager.h"
#include "../common/wasm_c_api_internal.h"
#if WASM_ENABLE_INTERP != 0
#include "../interpreter/wasm_runtime.h"
@ -370,6 +371,10 @@ wasm_cluster_destroy(WASMCluster *cluster)
wasm_debug_instance_destroy(cluster);
#endif
#if WASM_ENABLE_DUMP_CALL_STACK != 0
bh_vector_destroy(&cluster->exception_frames);
#endif
wasm_runtime_free(cluster);
}
@ -1321,6 +1326,29 @@ wasm_cluster_set_exception(WASMExecEnv *exec_env, const char *exception)
data.exception = exception;
os_mutex_lock(&cluster->lock);
#if WASM_ENABLE_DUMP_CALL_STACK != 0
if (has_exception) {
/* Save the stack frames of the crashed thread into the cluster */
WASMModuleInstance *module_inst =
(WASMModuleInstance *)get_module_inst(exec_env);
#if WASM_ENABLE_INTERP != 0
if (module_inst->module_type == Wasm_Module_Bytecode
&& wasm_interp_create_call_stack(exec_env)) {
wasm_frame_vec_clone_internal(module_inst->frames,
&cluster->exception_frames);
}
#endif
#if WASM_ENABLE_AOT != 0
if (module_inst->module_type == Wasm_Module_AoT
&& aot_create_call_stack(exec_env)) {
wasm_frame_vec_clone_internal(module_inst->frames,
&cluster->exception_frames);
}
#endif
}
#endif /* WASM_ENABLE_DUMP_CALL_STACK != 0 */
cluster->has_exception = has_exception;
traverse_list(&cluster->exec_env_list, set_exception_visitor, &data);
os_mutex_unlock(&cluster->lock);

View File

@ -51,6 +51,13 @@ struct WASMCluster {
#if WASM_ENABLE_DEBUG_INTERP != 0
WASMDebugInstance *debug_inst;
#endif
#if WASM_ENABLE_DUMP_CALL_STACK != 0
/* When an exception occurs in a thread, the stack frames of that thread are
* saved into the cluster
*/
Vector exception_frames;
#endif
};
void