Fix data/elem drop (#2747)
Currently, `data.drop` instruction is implemented by directly modifying the underlying module. It breaks use cases where you have multiple instances sharing a single loaded module. `elem.drop` has the same problem too. This PR fixes the issue by keeping track of which data/elem segments have been dropped by using bitmaps for each module instances separately, and add a sample to demonstrate the issue and make the CI run it. Also add a missing check of dropped elements to the fast-jit `table.init`. Fixes: https://github.com/bytecodealliance/wasm-micro-runtime/issues/2735 Fixes: https://github.com/bytecodealliance/wasm-micro-runtime/issues/2772
This commit is contained in:
@ -311,7 +311,6 @@ typedef struct WASMTableSeg {
|
||||
uint32 mode;
|
||||
/* funcref or externref, elemkind will be considered as funcref */
|
||||
uint32 elem_type;
|
||||
bool is_dropped;
|
||||
/* optional, only for active */
|
||||
uint32 table_index;
|
||||
InitializerExpression base_offset;
|
||||
|
||||
@ -3160,9 +3160,17 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
maddr = memory->memory_data + (uint32)addr;
|
||||
#endif
|
||||
|
||||
seg_len = (uint64)module->module->data_segments[segment]
|
||||
->data_length;
|
||||
data = module->module->data_segments[segment]->data;
|
||||
if (bh_bitmap_get_bit(module->e->common.data_dropped,
|
||||
segment)) {
|
||||
seg_len = 0;
|
||||
data = NULL;
|
||||
}
|
||||
else {
|
||||
seg_len =
|
||||
(uint64)module->module->data_segments[segment]
|
||||
->data_length;
|
||||
data = module->module->data_segments[segment]->data;
|
||||
}
|
||||
if (offset + bytes > seg_len)
|
||||
goto out_of_bounds;
|
||||
|
||||
@ -3175,7 +3183,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
uint32 segment;
|
||||
|
||||
read_leb_uint32(frame_ip, frame_ip_end, segment);
|
||||
module->module->data_segments[segment]->data_length = 0;
|
||||
bh_bitmap_set_bit(module->e->common.data_dropped,
|
||||
segment);
|
||||
break;
|
||||
}
|
||||
case WASM_OP_MEMORY_COPY:
|
||||
@ -3270,8 +3279,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
break;
|
||||
}
|
||||
|
||||
if (module->module->table_segments[elem_idx]
|
||||
.is_dropped) {
|
||||
if (bh_bitmap_get_bit(module->e->common.elem_dropped,
|
||||
elem_idx)) {
|
||||
wasm_set_exception(module,
|
||||
"out of bounds table access");
|
||||
goto got_exception;
|
||||
@ -3303,8 +3312,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
read_leb_uint32(frame_ip, frame_ip_end, elem_idx);
|
||||
bh_assert(elem_idx < module->module->table_seg_count);
|
||||
|
||||
module->module->table_segments[elem_idx].is_dropped =
|
||||
true;
|
||||
bh_bitmap_set_bit(module->e->common.elem_dropped,
|
||||
elem_idx);
|
||||
break;
|
||||
}
|
||||
case WASM_OP_TABLE_COPY:
|
||||
|
||||
@ -3005,10 +3005,18 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
goto out_of_bounds;
|
||||
maddr = memory->memory_data + (uint32)addr;
|
||||
#endif
|
||||
if (bh_bitmap_get_bit(module->e->common.data_dropped,
|
||||
segment)) {
|
||||
seg_len = 0;
|
||||
data = NULL;
|
||||
}
|
||||
else {
|
||||
|
||||
seg_len = (uint64)module->module->data_segments[segment]
|
||||
->data_length;
|
||||
data = module->module->data_segments[segment]->data;
|
||||
seg_len =
|
||||
(uint64)module->module->data_segments[segment]
|
||||
->data_length;
|
||||
data = module->module->data_segments[segment]->data;
|
||||
}
|
||||
if (offset + bytes > seg_len)
|
||||
goto out_of_bounds;
|
||||
|
||||
@ -3021,8 +3029,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
uint32 segment;
|
||||
|
||||
segment = read_uint32(frame_ip);
|
||||
|
||||
module->module->data_segments[segment]->data_length = 0;
|
||||
bh_bitmap_set_bit(module->e->common.data_dropped,
|
||||
segment);
|
||||
break;
|
||||
}
|
||||
case WASM_OP_MEMORY_COPY:
|
||||
@ -3114,8 +3122,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
break;
|
||||
}
|
||||
|
||||
if (module->module->table_segments[elem_idx]
|
||||
.is_dropped) {
|
||||
if (bh_bitmap_get_bit(module->e->common.elem_dropped,
|
||||
elem_idx)) {
|
||||
wasm_set_exception(module,
|
||||
"out of bounds table access");
|
||||
goto got_exception;
|
||||
@ -3144,9 +3152,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
|
||||
{
|
||||
uint32 elem_idx = read_uint32(frame_ip);
|
||||
bh_assert(elem_idx < module->module->table_seg_count);
|
||||
|
||||
module->module->table_segments[elem_idx].is_dropped =
|
||||
true;
|
||||
bh_bitmap_set_bit(module->e->common.elem_dropped,
|
||||
elem_idx);
|
||||
break;
|
||||
}
|
||||
case WASM_OP_TABLE_COPY:
|
||||
|
||||
@ -1666,6 +1666,31 @@ wasm_instantiate(WASMModule *module, WASMModuleInstance *parent,
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
if (module->data_seg_count > 0) {
|
||||
module_inst->e->common.data_dropped =
|
||||
bh_bitmap_new(0, module->data_seg_count);
|
||||
if (module_inst->e->common.data_dropped == NULL) {
|
||||
LOG_DEBUG("failed to allocate bitmaps");
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"failed to allocate bitmaps");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if WASM_ENABLE_REF_TYPES != 0
|
||||
if (module->table_seg_count > 0) {
|
||||
module_inst->e->common.elem_dropped =
|
||||
bh_bitmap_new(0, module->table_seg_count);
|
||||
if (module_inst->e->common.elem_dropped == NULL) {
|
||||
LOG_DEBUG("failed to allocate bitmaps");
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"failed to allocate bitmaps");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_DUMP_CALL_STACK != 0
|
||||
if (!(module_inst->frames = runtime_malloc((uint64)sizeof(Vector),
|
||||
error_buf, error_buf_size))) {
|
||||
@ -2189,6 +2214,13 @@ wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst)
|
||||
wasm_native_call_context_dtors((WASMModuleInstanceCommon *)module_inst);
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
bh_bitmap_delete(module_inst->e->common.data_dropped);
|
||||
#endif
|
||||
#if WASM_ENABLE_REF_TYPES != 0
|
||||
bh_bitmap_delete(module_inst->e->common.elem_dropped);
|
||||
#endif
|
||||
|
||||
wasm_runtime_free(module_inst);
|
||||
}
|
||||
|
||||
@ -3148,16 +3180,23 @@ llvm_jit_memory_init(WASMModuleInstance *module_inst, uint32 seg_index,
|
||||
{
|
||||
WASMMemoryInstance *memory_inst;
|
||||
WASMModule *module;
|
||||
uint8 *data = NULL;
|
||||
uint8 *data;
|
||||
uint8 *maddr;
|
||||
uint64 seg_len = 0;
|
||||
uint64 seg_len;
|
||||
|
||||
bh_assert(module_inst->module_type == Wasm_Module_Bytecode);
|
||||
|
||||
memory_inst = wasm_get_default_memory(module_inst);
|
||||
module = module_inst->module;
|
||||
seg_len = module->data_segments[seg_index]->data_length;
|
||||
data = module->data_segments[seg_index]->data;
|
||||
|
||||
if (bh_bitmap_get_bit(module_inst->e->common.data_dropped, seg_index)) {
|
||||
seg_len = 0;
|
||||
data = NULL;
|
||||
}
|
||||
else {
|
||||
module = module_inst->module;
|
||||
seg_len = module->data_segments[seg_index]->data_length;
|
||||
data = module->data_segments[seg_index]->data;
|
||||
}
|
||||
|
||||
if (!wasm_runtime_validate_app_addr((WASMModuleInstanceCommon *)module_inst,
|
||||
dst, len))
|
||||
@ -3182,7 +3221,7 @@ llvm_jit_data_drop(WASMModuleInstance *module_inst, uint32 seg_index)
|
||||
{
|
||||
bh_assert(module_inst->module_type == Wasm_Module_Bytecode);
|
||||
|
||||
module_inst->module->data_segments[seg_index]->data_length = 0;
|
||||
bh_bitmap_set_bit(module_inst->e->common.data_dropped, seg_index);
|
||||
/* Currently we can't free the dropped data segment
|
||||
as they are stored in wasm bytecode */
|
||||
return true;
|
||||
@ -3193,12 +3232,8 @@ llvm_jit_data_drop(WASMModuleInstance *module_inst, uint32 seg_index)
|
||||
void
|
||||
llvm_jit_drop_table_seg(WASMModuleInstance *module_inst, uint32 tbl_seg_idx)
|
||||
{
|
||||
WASMTableSeg *tbl_segs;
|
||||
|
||||
bh_assert(module_inst->module_type == Wasm_Module_Bytecode);
|
||||
|
||||
tbl_segs = module_inst->module->table_segments;
|
||||
tbl_segs[tbl_seg_idx].is_dropped = true;
|
||||
bh_bitmap_set_bit(module_inst->e->common.elem_dropped, tbl_seg_idx);
|
||||
}
|
||||
|
||||
void
|
||||
@ -3227,7 +3262,7 @@ llvm_jit_table_init(WASMModuleInstance *module_inst, uint32 tbl_idx,
|
||||
return;
|
||||
}
|
||||
|
||||
if (tbl_seg->is_dropped) {
|
||||
if (bh_bitmap_get_bit(module_inst->e->common.elem_dropped, tbl_seg_idx)) {
|
||||
jit_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
|
||||
#include "wasm.h"
|
||||
#include "bh_atomic.h"
|
||||
#include "bh_bitmap.h"
|
||||
#include "bh_hashmap.h"
|
||||
#include "../common/wasm_runtime_common.h"
|
||||
#include "../common/wasm_exec_env.h"
|
||||
@ -223,6 +224,12 @@ typedef struct WASMModuleInstanceExtraCommon {
|
||||
/* Disable bounds checks or not */
|
||||
bool disable_bounds_checks;
|
||||
#endif
|
||||
#if WASM_ENABLE_BULK_MEMORY != 0
|
||||
bh_bitmap *data_dropped;
|
||||
#endif
|
||||
#if WASM_ENABLE_REF_TYPES != 0
|
||||
bh_bitmap *elem_dropped;
|
||||
#endif
|
||||
} WASMModuleInstanceExtraCommon;
|
||||
|
||||
/* Extra info of WASM module instance for interpreter/jit mode */
|
||||
|
||||
Reference in New Issue
Block a user