Просмотр исходного кода

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
YAMAMOTO Takashi 2 лет назад
Родитель
Сommit
562a5dd1b6

+ 6 - 0
.github/workflows/compilation_on_android_ubuntu.yml

@@ -444,6 +444,12 @@ jobs:
           cmake --build . --config Release --parallel 4
           ./iwasm wasm-apps/no_pthread.wasm
 
+      - name: Build Sample [shared-module]
+        run: |
+          cd samples/shared-module
+          ./build.sh
+          ./run.sh
+
   test:
     needs:
       [

+ 6 - 0
.github/workflows/compilation_on_macos.yml

@@ -327,3 +327,9 @@ jobs:
           cmake ..
           cmake --build . --config Release --parallel 4
           ./iwasm wasm-apps/no_pthread.wasm
+
+      - name: Build Sample [shared-module]
+        run: |
+          cd samples/shared-module
+          ./build.sh
+          ./run.sh

+ 6 - 0
.github/workflows/nightly_run.yml

@@ -501,6 +501,12 @@ jobs:
           cmake ..
           cmake --build . --config Release --parallel 4
           ./iwasm wasm-apps/no_pthread.wasm
+
+      - name: Build Sample [shared-module]
+        run: |
+          cd samples/shared-module
+          ./build.sh
+          ./run.sh
   test:
     needs:
       [

+ 0 - 1
core/iwasm/aot/aot_loader.c

@@ -1095,7 +1095,6 @@ load_table_init_data_list(const uint8 **p_buf, const uint8 *buf_end,
 
         data_list[i]->mode = mode;
         data_list[i]->elem_type = elem_type;
-        data_list[i]->is_dropped = false;
         data_list[i]->table_index = table_index;
         data_list[i]->offset.init_expr_type = (uint8)init_expr_type;
         data_list[i]->offset.u.i64 = (int64)init_expr_value;

+ 61 - 13
core/iwasm/aot/aot_runtime.c

@@ -1098,6 +1098,9 @@ aot_instantiate(AOTModule *module, AOTModuleInstance *parent,
                 char *error_buf, uint32 error_buf_size)
 {
     AOTModuleInstance *module_inst;
+#if WASM_ENABLE_BULK_MEMORY != 0 || WASM_ENABLE_REF_TYPES != 0
+    WASMModuleInstanceExtraCommon *common;
+#endif
     const uint32 module_inst_struct_size =
         offsetof(AOTModuleInstance, global_table_data.bytes);
     const uint64 module_inst_mem_inst_size =
@@ -1164,6 +1167,32 @@ aot_instantiate(AOTModule *module, AOTModuleInstance *parent,
     }
 #endif
 
+#if WASM_ENABLE_BULK_MEMORY != 0 || WASM_ENABLE_REF_TYPES != 0
+    common = &((AOTModuleInstanceExtra *)module_inst->e)->common;
+#endif
+#if WASM_ENABLE_BULK_MEMORY != 0
+    if (module->mem_init_data_count > 0) {
+        common->data_dropped = bh_bitmap_new(0, module->mem_init_data_count);
+        if (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_init_data_count > 0) {
+        common->elem_dropped = bh_bitmap_new(0, module->table_init_data_count);
+        if (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
+
     /* Initialize global info */
     p = (uint8 *)module_inst + module_inst_struct_size
         + module_inst_mem_inst_size;
@@ -1264,6 +1293,8 @@ fail:
 void
 aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst)
 {
+    WASMModuleInstanceExtraCommon *common =
+        &((AOTModuleInstanceExtra *)module_inst->e)->common;
     if (module_inst->exec_env_singleton) {
         /* wasm_exec_env_destroy will call
            wasm_cluster_wait_for_all_except_self to wait for other
@@ -1306,7 +1337,7 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst)
     if (module_inst->func_type_indexes)
         wasm_runtime_free(module_inst->func_type_indexes);
 
-    if (((AOTModuleInstanceExtra *)module_inst->e)->common.c_api_func_imports)
+    if (common->c_api_func_imports)
         wasm_runtime_free(((AOTModuleInstanceExtra *)module_inst->e)
                               ->common.c_api_func_imports);
 
@@ -1317,6 +1348,13 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst)
         wasm_native_call_context_dtors((WASMModuleInstanceCommon *)module_inst);
     }
 
+#if WASM_ENABLE_BULK_MEMORY != 0
+    bh_bitmap_delete(common->data_dropped);
+#endif
+#if WASM_ENABLE_REF_TYPES != 0
+    bh_bitmap_delete(common->elem_dropped);
+#endif
+
     wasm_runtime_free(module_inst);
 }
 
@@ -2302,13 +2340,21 @@ aot_memory_init(AOTModuleInstance *module_inst, uint32 seg_index, uint32 offset,
 {
     AOTMemoryInstance *memory_inst = aot_get_default_memory(module_inst);
     AOTModule *aot_module;
-    uint8 *data = NULL;
+    uint8 *data;
     uint8 *maddr;
-    uint64 seg_len = 0;
+    uint64 seg_len;
 
-    aot_module = (AOTModule *)module_inst->module;
-    seg_len = aot_module->mem_init_data_list[seg_index]->byte_count;
-    data = aot_module->mem_init_data_list[seg_index]->bytes;
+    if (bh_bitmap_get_bit(
+            ((AOTModuleInstanceExtra *)module_inst->e)->common.data_dropped,
+            seg_index)) {
+        seg_len = 0;
+        data = NULL;
+    }
+    else {
+        aot_module = (AOTModule *)module_inst->module;
+        seg_len = aot_module->mem_init_data_list[seg_index]->byte_count;
+        data = aot_module->mem_init_data_list[seg_index]->bytes;
+    }
 
     if (!wasm_runtime_validate_app_addr((WASMModuleInstanceCommon *)module_inst,
                                         dst, len))
@@ -2331,9 +2377,9 @@ aot_memory_init(AOTModuleInstance *module_inst, uint32 seg_index, uint32 offset,
 bool
 aot_data_drop(AOTModuleInstance *module_inst, uint32 seg_index)
 {
-    AOTModule *aot_module = (AOTModule *)module_inst->module;
-
-    aot_module->mem_init_data_list[seg_index]->byte_count = 0;
+    bh_bitmap_set_bit(
+        ((AOTModuleInstanceExtra *)module_inst->e)->common.data_dropped,
+        seg_index);
     /* Currently we can't free the dropped data segment
        as the mem_init_data_count is a continuous array */
     return true;
@@ -2546,9 +2592,9 @@ aot_get_module_inst_mem_consumption(const AOTModuleInstance *module_inst,
 void
 aot_drop_table_seg(AOTModuleInstance *module_inst, uint32 tbl_seg_idx)
 {
-    AOTModule *module = (AOTModule *)module_inst->module;
-    AOTTableInitData *tbl_seg = module->table_init_data_list[tbl_seg_idx];
-    tbl_seg->is_dropped = true;
+    bh_bitmap_set_bit(
+        ((AOTModuleInstanceExtra *)module_inst->e)->common.elem_dropped,
+        tbl_seg_idx);
 }
 
 void
@@ -2576,7 +2622,9 @@ aot_table_init(AOTModuleInstance *module_inst, uint32 tbl_idx,
         return;
     }
 
-    if (tbl_seg->is_dropped) {
+    if (bh_bitmap_get_bit(
+            ((AOTModuleInstanceExtra *)module_inst->e)->common.elem_dropped,
+            tbl_seg_idx)) {
         aot_set_exception_with_id(module_inst, EXCE_OUT_OF_BOUNDS_TABLE_ACCESS);
         return;
     }

+ 0 - 1
core/iwasm/compilation/aot.c

@@ -129,7 +129,6 @@ aot_create_table_init_data_list(const WASMModule *module)
         data_list[i]->mode = module->table_segments[i].mode;
         data_list[i]->elem_type = module->table_segments[i].elem_type;
         /* runtime control it */
-        data_list[i]->is_dropped = false;
         data_list[i]->table_index = module->table_segments[i].table_index;
         bh_memcpy_s(&data_list[i]->offset, sizeof(AOTInitExpr),
                     &module->table_segments[i].base_offset,

+ 0 - 1
core/iwasm/compilation/aot.h

@@ -143,7 +143,6 @@ typedef struct AOTTableInitData {
     uint32 mode;
     /* funcref or externref, elemkind will be considered as funcref */
     uint32 elem_type;
-    bool is_dropped;
     /* optional, only for active */
     uint32 table_index;
     /* Start address of init data */

+ 1 - 1
core/iwasm/compilation/aot_emit_aot_file.c

@@ -269,7 +269,7 @@ static uint32
 get_table_init_data_size(AOTTableInitData *table_init_data)
 {
     /*
-     * mode (4 bytes), elem_type (4 bytes), do not need is_dropped field
+     * mode (4 bytes), elem_type (4 bytes)
      *
      * table_index(4 bytes) + init expr type (4 bytes) + init expr value (8
      * bytes)

+ 22 - 14
core/iwasm/fast-jit/fe/jit_emit_memory.c

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

+ 17 - 10
core/iwasm/fast-jit/fe/jit_emit_table.c

@@ -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);
-
-    tbl_segs = jit_cc_new_reg_ptr(cc);
-    GEN_INSN(LDPTR, tbl_segs, module,
-             NEW_CONST(I32, offsetof(WASMModule, table_segments)));
+    args[0] = get_module_inst_reg(cc->jit_frame);
+    args[1] = NEW_CONST(I32, tbl_seg_idx);
 
-    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)),

+ 0 - 1
core/iwasm/interpreter/wasm.h

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

+ 17 - 8
core/iwasm/interpreter/wasm_interp_classic.c

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

+ 17 - 10
core/iwasm/interpreter/wasm_interp_fast.c

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

+ 47 - 12
core/iwasm/interpreter/wasm_runtime.c

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

+ 7 - 0
core/iwasm/interpreter/wasm_runtime.h

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

+ 27 - 0
core/shared/utils/bh_bitmap.c

@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2021 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include "bh_bitmap.h"
+
+bh_bitmap *
+bh_bitmap_new(uintptr_t begin_index, unsigned bitnum)
+{
+    bh_bitmap *bitmap;
+    uint32 bitmap_size = (bitnum + 7) / 8;
+    uint32 total_size = offsetof(bh_bitmap, map) + bitmap_size;
+
+    if (bitnum > UINT32_MAX - 7 || total_size < offsetof(bh_bitmap, map)
+        || (total_size - offsetof(bh_bitmap, map)) != bitmap_size) {
+        return NULL; /* integer overflow */
+    }
+
+    if ((bitmap = BH_MALLOC(total_size)) != NULL) {
+        memset(bitmap, 0, total_size);
+        bitmap->begin_index = begin_index;
+        bitmap->end_index = begin_index + bitnum;
+    }
+
+    return bitmap;
+}

+ 114 - 0
core/shared/utils/bh_bitmap.h

@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2021 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#ifndef _BH_BITMAP_H
+#define _BH_BITMAP_H
+
+#include "bh_platform.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * A simple fixed size bitmap.
+ */
+typedef struct bh_bitmap {
+    /* The first valid bit index.  */
+    uintptr_t begin_index;
+
+    /* The last valid bit index plus one.  */
+    uintptr_t end_index;
+
+    /* The bitmap.  */
+    uint8 map[1];
+} bh_bitmap;
+
+/**
+ * Create a new bitmap.
+ *
+ * @param begin_index the first valid bit index
+ * @param bitnum maximal bit number of the bitmap.
+ *
+ * @return the new bitmap if succeeds, NULL otherwise.
+ */
+bh_bitmap *
+bh_bitmap_new(uintptr_t begin_index, unsigned bitnum);
+
+/**
+ * Delete a bitmap.
+ *
+ * @param bitmap the bitmap to be deleted
+ */
+static inline void
+bh_bitmap_delete(bh_bitmap *bitmap)
+{
+    if (bitmap != NULL)
+        BH_FREE(bitmap);
+}
+
+/**
+ * Check whether the given index is in the range of the bitmap.
+ *
+ * @param bitmap the bitmap
+ * @param n the bit index
+ *
+ * @return true if the index is in range, false otherwise
+ */
+static inline bool
+bh_bitmap_is_in_range(bh_bitmap *bitmap, unsigned n)
+{
+    return n >= bitmap->begin_index && n < bitmap->end_index;
+}
+
+/**
+ * Get a bit in the bitmap
+ *
+ * @param bitmap the bitmap
+ * @param n the n-th bit to be get
+ *
+ * @return value of the bit
+ */
+static inline int
+bh_bitmap_get_bit(bh_bitmap *bitmap, unsigned n)
+{
+    unsigned idx = n - bitmap->begin_index;
+    bh_assert(n >= bitmap->begin_index && n < bitmap->end_index);
+    return (bitmap->map[idx / 8] >> (idx % 8)) & 1;
+}
+
+/**
+ * Set a bit in the bitmap.
+ *
+ * @param bitmap the bitmap
+ * @param n the n-th bit to be set
+ */
+static inline void
+bh_bitmap_set_bit(bh_bitmap *bitmap, unsigned n)
+{
+    unsigned idx = n - bitmap->begin_index;
+    bh_assert(n >= bitmap->begin_index && n < bitmap->end_index);
+    bitmap->map[idx / 8] |= 1 << (idx % 8);
+}
+
+/**
+ * Clear a bit in the bitmap.
+ *
+ * @param bitmap the bitmap
+ * @param n the n-th bit to be cleared
+ */
+static inline void
+bh_bitmap_clear_bit(bh_bitmap *bitmap, unsigned n)
+{
+    unsigned idx = n - bitmap->begin_index;
+    bh_assert(n >= bitmap->begin_index && n < bitmap->end_index);
+    bitmap->map[idx / 8] &= ~(1 << (idx % 8));
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 1 - 0
product-mini/platforms/alios-things/aos.mk

@@ -98,6 +98,7 @@ $(NAME)_SOURCES := ${SHARED_ROOT}/platform/alios/alios_platform.c \
                    ${SHARED_ROOT}/mem-alloc/ems/ems_alloc.c \
                    ${SHARED_ROOT}/mem-alloc/ems/ems_hmu.c \
                    ${SHARED_ROOT}/utils/bh_assert.c \
+                   ${SHARED_ROOT}/utils/bh_bitmap.c \
                    ${SHARED_ROOT}/utils/bh_common.c \
                    ${SHARED_ROOT}/utils/bh_hashmap.c \
                    ${SHARED_ROOT}/utils/bh_list.c \

+ 1 - 0
product-mini/platforms/nuttx/wamr.mk

@@ -371,6 +371,7 @@ CSRCS += nuttx_platform.c \
          ems_alloc.c \
          ems_hmu.c \
          bh_assert.c \
+         bh_bitmap.c \
          bh_common.c \
          bh_hashmap.c \
          bh_list.c \

+ 1 - 0
samples/shared-module/.gitignore

@@ -0,0 +1 @@
+/out/

+ 95 - 0
samples/shared-module/CMakeLists.txt

@@ -0,0 +1,95 @@
+# Copyright (C) 2019 Intel Corporation.  All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+cmake_minimum_required (VERSION 3.14)
+
+include(CheckPIESupported)
+
+project (shared-module)
+
+set (CMAKE_CXX_STANDARD 17)
+
+################  runtime settings  ################
+string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM)
+if (APPLE)
+  add_definitions(-DBH_PLATFORM_DARWIN)
+endif ()
+
+# Reset default linker flags
+set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
+set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
+
+# WAMR features switch
+
+# Set WAMR_BUILD_TARGET, currently values supported:
+# "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]",
+# "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]"
+if (NOT DEFINED WAMR_BUILD_TARGET)
+  if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)")
+    set (WAMR_BUILD_TARGET "AARCH64")
+  elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64")
+    set (WAMR_BUILD_TARGET "RISCV64")
+  elseif (CMAKE_SIZEOF_VOID_P EQUAL 8)
+    # Build as X86_64 by default in 64-bit platform
+    set (WAMR_BUILD_TARGET "X86_64")
+  elseif (CMAKE_SIZEOF_VOID_P EQUAL 4)
+    # Build as X86_32 by default in 32-bit platform
+    set (WAMR_BUILD_TARGET "X86_32")
+  else ()
+    message(SEND_ERROR "Unsupported build target platform!")
+  endif ()
+endif ()
+
+if (NOT CMAKE_BUILD_TYPE)
+  set (CMAKE_BUILD_TYPE Debug)
+endif ()
+
+set (WAMR_BUILD_INTERP 1)
+set (WAMR_BUILD_AOT 1)
+set (WAMR_BUILD_JIT 0)
+
+# fast interpreter
+# set (WAMR_BUILD_FAST_INTERP 1)
+
+# fast-jit
+# set (WAMR_BUILD_FAST_JIT 1)
+
+# llvm jit
+# set (WAMR_BUILD_JIT 1)
+# set (LLVM_DIR /usr/local/opt/llvm@14/lib/cmake/llvm)
+
+set (WAMR_BUILD_REF_TYPES 1)
+
+if (NOT MSVC)
+  # linker flags
+  if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang"))
+    set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
+  endif ()
+  set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security")
+  if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64")
+    if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang"))
+      set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mindirect-branch-register")
+    endif ()
+  endif ()
+endif ()
+
+# build out vmlib
+set (WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..)
+include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
+
+add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE})
+
+################  application related  ################
+include_directories(${CMAKE_CURRENT_LIST_DIR}/src)
+include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake)
+
+add_executable (shared-module src/main.c ${UNCOMMON_SHARED_SOURCE})
+
+check_pie_supported()
+set_target_properties (shared-module PROPERTIES POSITION_INDEPENDENT_CODE ON)
+
+if (APPLE)
+  target_link_libraries (shared-module vmlib -lm -ldl -lpthread ${LLVM_AVAILABLE_LIBS})
+else ()
+  target_link_libraries (shared-module vmlib -lm -ldl -lpthread -lrt ${LLVM_AVAILABLE_LIBS})
+endif ()

+ 5 - 0
samples/shared-module/README.md

@@ -0,0 +1,5 @@
+The "shared-module" sample project
+==================================
+
+This sample demonstrates a bug described in:
+https://github.com/bytecodealliance/wasm-micro-runtime/issues/2735.

+ 63 - 0
samples/shared-module/build.sh

@@ -0,0 +1,63 @@
+#
+# Copyright (C) 2019 Intel Corporation.  All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+#
+
+#!/bin/bash
+
+CURR_DIR=$PWD
+WAMR_DIR=${PWD}/../..
+OUT_DIR=${PWD}/out
+
+WASM_APPS=${PWD}/wasm-apps
+
+
+rm -rf ${OUT_DIR}
+mkdir ${OUT_DIR}
+mkdir ${OUT_DIR}/wasm-apps
+
+
+echo "##################### build shared-module project"
+cd ${CURR_DIR}
+mkdir -p cmake_build
+cd cmake_build
+cmake ..
+make -j ${nproc}
+if [ $? != 0 ];then
+    echo "BUILD_FAIL shared-module exit as $?\n"
+    exit 2
+fi
+
+cp -a shared-module ${OUT_DIR}
+
+printf "\n"
+
+echo "##################### build wasm apps"
+
+cd ${WASM_APPS}
+
+for i in `ls *.wat`
+do
+APP_SRC="$i"
+OUT_FILE=${i%.*}.wasm
+
+# Note: the CI installs wabt in /opt/wabt
+if type wat2wasm; then
+    WAT2WASM=${WAT2WASM:-wat2wasm}
+elif [ -x /opt/wabt/bin/wat2wasm ]; then
+    WAT2WASM=${WAT2WASM:-/opt/wabt/bin/wat2wasm}
+fi
+
+${WAT2WASM} -o ${OUT_DIR}/wasm-apps/${OUT_FILE} ${APP_SRC}
+
+# aot
+# wamrc -o ${OUT_DIR}/wasm-apps/${OUT_FILE}.aot ${OUT_DIR}/wasm-apps/${OUT_FILE}
+# mv ${OUT_DIR}/wasm-apps/${OUT_FILE}.aot ${OUT_DIR}/wasm-apps/${OUT_FILE}
+
+if [ -f ${OUT_DIR}/wasm-apps/${OUT_FILE} ]; then
+        echo "build ${OUT_FILE} success"
+else
+        echo "build ${OUT_FILE} fail"
+fi
+done
+echo "##################### build wasm apps done"

+ 3 - 0
samples/shared-module/run.sh

@@ -0,0 +1,3 @@
+#!/bin/bash
+
+out/shared-module -f out/wasm-apps/testapp.wasm

+ 206 - 0
samples/shared-module/src/main.c

@@ -0,0 +1,206 @@
+
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include "wasm_export.h"
+#include "bh_read_file.h"
+#include "bh_getopt.h"
+
+void
+print_usage(void)
+{
+    fprintf(stdout, "Options:\r\n");
+    fprintf(stdout, "  -f [path of wasm file] \n");
+}
+
+int
+main(int argc, char *argv_main[])
+{
+    int exit_code = 1;
+    static char global_heap_buf[512 * 1024];
+    char *buffer;
+    char error_buf[128];
+    int opt;
+    char *wasm_path = NULL;
+
+    const unsigned int N = 4;
+    wasm_module_t module = NULL;
+    wasm_module_inst_t module_inst[N];
+    wasm_exec_env_t exec_env[N];
+    const char *name_test_data_drop = "test_data_drop";
+    const char *name_test_elem_drop = "test_elem_drop";
+    wasm_function_inst_t func_test_data_drop[N];
+    wasm_function_inst_t func_test_elem_drop[N];
+    unsigned int i;
+    unsigned int iter;
+    uint32 buf_size, stack_size = 8092, heap_size = 8092;
+
+    for (i = 0; i < N; i++) {
+        module_inst[i] = NULL;
+        exec_env[i] = NULL;
+        func_test_data_drop[i] = NULL;
+        func_test_elem_drop[i] = NULL;
+    }
+
+    RuntimeInitArgs init_args;
+    memset(&init_args, 0, sizeof(RuntimeInitArgs));
+
+    while ((opt = getopt(argc, argv_main, "hf:")) != -1) {
+        switch (opt) {
+            case 'f':
+                wasm_path = optarg;
+                break;
+            case 'h':
+                print_usage();
+                return 0;
+            case '?':
+                print_usage();
+                return 0;
+        }
+    }
+    if (optind == 1) {
+        print_usage();
+        return 0;
+    }
+
+    memset(&init_args, 0, sizeof(init_args));
+    init_args.mem_alloc_type = Alloc_With_Pool;
+    init_args.mem_alloc_option.pool.heap_buf = global_heap_buf;
+    init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf);
+
+    if (!wasm_runtime_full_init(&init_args)) {
+        printf("Init runtime environment failed.\n");
+        return -1;
+    }
+
+    buffer = bh_read_file_to_buffer(wasm_path, &buf_size);
+
+    if (!buffer) {
+        printf("Open wasm app file [%s] failed.\n", wasm_path);
+        goto fail;
+    }
+
+    module = wasm_runtime_load((uint8 *)buffer, buf_size, error_buf,
+                               sizeof(error_buf));
+    if (!module) {
+        printf("Load wasm module failed. error: %s\n", error_buf);
+        goto fail;
+    }
+
+    for (i = 0; i < N; i++) {
+        module_inst[i] = wasm_runtime_instantiate(module, stack_size, heap_size,
+                                                  error_buf, sizeof(error_buf));
+
+        if (!module_inst[i]) {
+            printf("Instantiate wasm module failed. error: %s\n", error_buf);
+            goto fail;
+        }
+
+        exec_env[i] = wasm_runtime_create_exec_env(module_inst[i], stack_size);
+        if (!exec_env[i]) {
+            printf("Create wasm execution environment failed.\n");
+            goto fail;
+        }
+
+        func_test_data_drop[i] = wasm_runtime_lookup_function(
+            module_inst[i], name_test_data_drop, NULL);
+        if (!func_test_data_drop[i]) {
+            printf("The wasm function %s is not found.\n", name_test_data_drop);
+            goto fail;
+        }
+
+        func_test_elem_drop[i] = wasm_runtime_lookup_function(
+            module_inst[i], name_test_elem_drop, NULL);
+        if (!func_test_elem_drop[i]) {
+            printf("The wasm function %s is not found.\n", name_test_elem_drop);
+            goto fail;
+        }
+    }
+
+    for (iter = 0; iter < 2; iter++) {
+        /*
+         * as we drop data/table in the first iteration,
+         * the later iterations should trap.
+         */
+        const bool should_trap = iter > 0;
+
+        for (i = 0; i < N; i++) {
+            uint32_t argv[1] = {};
+            if (wasm_runtime_call_wasm(exec_env[i], func_test_data_drop[i], 0,
+                                       argv)) {
+                uint32_t result = argv[0];
+                printf(
+                    "Native finished calling wasm function: %s, return: %x\n",
+                    name_test_data_drop, result);
+                if (result != 0x64636261) { /* "abcd" */
+                    printf("unexpected return value\n");
+                    goto fail;
+                }
+                if (should_trap) {
+                    printf("a trap is expected\n");
+                    goto fail;
+                }
+            }
+            else if (should_trap) {
+                printf("call wasm function %s failed as expected. error: %s\n",
+                       name_test_data_drop,
+                       wasm_runtime_get_exception(module_inst[i]));
+            }
+            else {
+                printf("call wasm function %s failed. error: %s\n",
+                       name_test_data_drop,
+                       wasm_runtime_get_exception(module_inst[i]));
+                goto fail;
+            }
+        }
+
+        for (i = 0; i < N; i++) {
+            wasm_runtime_clear_exception(module_inst[i]);
+
+            uint32_t argv[1] = {};
+            if (wasm_runtime_call_wasm(exec_env[i], func_test_elem_drop[i], 0,
+                                       argv)) {
+                uint32_t result = argv[0];
+                printf(
+                    "Native finished calling wasm function: %s, return: %x\n",
+                    name_test_elem_drop, result);
+                if (result != 0) {
+                    printf("unexpected return value\n");
+                    goto fail;
+                }
+                if (should_trap) {
+                    printf("a trap is expected\n");
+                    goto fail;
+                }
+            }
+            else if (should_trap) {
+                printf("call wasm function %s failed as expected. error: %s\n",
+                       name_test_elem_drop,
+                       wasm_runtime_get_exception(module_inst[i]));
+            }
+            else {
+                printf("call wasm function %s failed. error: %s\n",
+                       name_test_elem_drop,
+                       wasm_runtime_get_exception(module_inst[i]));
+                goto fail;
+            }
+        }
+    }
+
+    exit_code = 0;
+fail:
+    for (i = 0; i < N; i++) {
+        if (exec_env[i])
+            wasm_runtime_destroy_exec_env(exec_env[i]);
+        if (module_inst[i])
+            wasm_runtime_deinstantiate(module_inst[i]);
+    }
+    if (module)
+        wasm_runtime_unload(module);
+    if (buffer)
+        BH_FREE(buffer);
+    wasm_runtime_destroy();
+    return exit_code;
+}

+ 22 - 0
samples/shared-module/wasm-apps/testapp.wat

@@ -0,0 +1,22 @@
+;; Copyright (C) 2023 Midokura Japan KK.  All rights reserved.
+;; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+(module
+  (func (export "test_data_drop") (result i32)
+    (memory.init 0 (i32.const 0) (i32.const 0) (i32.const 4))
+    data.drop 0
+    (i32.load (i32.const 0))
+  )
+  (func (export "test_elem_drop") (result i32)
+    (table.init 0 (i32.const 0) (i32.const 0) (i32.const 4))
+    elem.drop 0
+    i32.const 3
+    table.get 0
+    ref.is_null
+  )
+  (func $f)
+  (memory 1 1)
+  (table 4 4 funcref)
+  (data "abcd")
+  (elem func $f $f $f $f)
+)