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:
YAMAMOTO Takashi
2023-11-18 09:50:16 +09:00
committed by GitHub
parent 08c0ec74c4
commit 562a5dd1b6
26 changed files with 745 additions and 72 deletions

View File

@ -650,6 +650,7 @@ wasm_init_memory(WASMModuleInstance *inst, uint32 mem_idx, uint32 seg_idx,
WASMDataSeg *data_segment;
uint32 mem_size;
uint8 *mem_addr, *data_addr;
uint32 seg_len;
/* if d + n > the length of mem.data */
mem_inst = inst->memories[mem_idx];
@ -659,13 +660,19 @@ wasm_init_memory(WASMModuleInstance *inst, uint32 mem_idx, uint32 seg_idx,
/* if s + n > the length of data.data */
bh_assert(seg_idx < inst->module->data_seg_count);
data_segment = inst->module->data_segments[seg_idx];
if (data_segment->data_length < data_offset
|| data_segment->data_length - data_offset < len)
if (bh_bitmap_get_bit(inst->e->common.data_dropped, seg_idx)) {
seg_len = 0;
data_addr = NULL;
}
else {
data_segment = inst->module->data_segments[seg_idx];
seg_len = data_segment->data_length;
data_addr = data_segment->data + data_offset;
}
if (seg_len < data_offset || seg_len - data_offset < len)
goto out_of_bounds;
mem_addr = mem_inst->memory_data + mem_offset;
data_addr = data_segment->data + data_offset;
bh_memcpy_s(mem_addr, mem_size - mem_offset, data_addr, len);
return 0;
@ -706,21 +713,22 @@ fail:
return false;
}
static void
wasm_data_drop(WASMModuleInstance *inst, uint32 seg_idx)
{
bh_bitmap_set_bit(inst->e->common.data_dropped, seg_idx);
}
bool
jit_compile_op_data_drop(JitCompContext *cc, uint32 seg_idx)
{
JitReg module = get_module_reg(cc->jit_frame);
JitReg data_segments = jit_cc_new_reg_ptr(cc);
JitReg data_segment = jit_cc_new_reg_ptr(cc);
JitReg args[2] = { 0 };
GEN_INSN(LDPTR, data_segments, module,
NEW_CONST(I32, offsetof(WASMModule, data_segments)));
GEN_INSN(LDPTR, data_segment, data_segments,
NEW_CONST(I32, seg_idx * sizeof(WASMDataSeg *)));
GEN_INSN(STI32, NEW_CONST(I32, 0), data_segment,
NEW_CONST(I32, offsetof(WASMDataSeg, data_length)));
args[0] = get_module_inst_reg(cc->jit_frame);
args[1] = NEW_CONST(I32, seg_idx);
return true;
return jit_emit_callnative(cc, wasm_data_drop, 0, args,
sizeof(args) / sizeof(args[0]));
}
static int

View File

@ -10,21 +10,22 @@
#include "../jit_frontend.h"
#if WASM_ENABLE_REF_TYPES != 0
static void
wasm_elem_drop(WASMModuleInstance *inst, uint32 tbl_seg_idx)
{
bh_bitmap_set_bit(inst->e->common.elem_dropped, tbl_seg_idx);
}
bool
jit_compile_op_elem_drop(JitCompContext *cc, uint32 tbl_seg_idx)
{
JitReg module, tbl_segs;
JitReg args[2] = { 0 };
module = get_module_reg(cc->jit_frame);
args[0] = get_module_inst_reg(cc->jit_frame);
args[1] = NEW_CONST(I32, tbl_seg_idx);
tbl_segs = jit_cc_new_reg_ptr(cc);
GEN_INSN(LDPTR, tbl_segs, module,
NEW_CONST(I32, offsetof(WASMModule, table_segments)));
GEN_INSN(STI32, NEW_CONST(I32, true), tbl_segs,
NEW_CONST(I32, tbl_seg_idx * sizeof(WASMTableSeg)
+ offsetof(WASMTableSeg, is_dropped)));
return true;
return jit_emit_callnative(cc, wasm_elem_drop, 0, args,
sizeof(args) / sizeof(args[0]));
}
bool
@ -105,6 +106,12 @@ wasm_init_table(WASMModuleInstance *inst, uint32 tbl_idx, uint32 elem_idx,
if (offset_len_out_of_bounds(dst_offset, len, tbl_sz))
goto out_of_bounds;
if (!len)
return 0;
if (bh_bitmap_get_bit(inst->e->common.elem_dropped, elem_idx))
goto out_of_bounds;
bh_memcpy_s((uint8 *)tbl + offsetof(WASMTableInstance, elems)
+ dst_offset * sizeof(uint32),
(uint32)((tbl_sz - dst_offset) * sizeof(uint32)),