Skip to content

Commit de9a35c

Browse files
authored
Merge pull request #1324 from bytecodealliance/main
Fix interp hw bound check issues (#1322)
2 parents 8c63fc1 + dd62b32 commit de9a35c

File tree

5 files changed

+84
-43
lines changed

5 files changed

+84
-43
lines changed

build-scripts/config_common.cmake

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -203,10 +203,6 @@ endif ()
203203
if (WAMR_DISABLE_HW_BOUND_CHECK EQUAL 1)
204204
add_definitions (-DWASM_DISABLE_HW_BOUND_CHECK=1)
205205
message (" Hardware boundary check disabled")
206-
elseif (NOT WAMR_BUILD_AOT EQUAL 1)
207-
# Enable memory access boundary check with hardware trap
208-
# only when AOT/JIT is enabled
209-
add_definitions (-DWASM_DISABLE_HW_BOUND_CHECK=1)
210206
else ()
211207
add_definitions (-DWASM_DISABLE_HW_BOUND_CHECK=0)
212208
endif ()

core/iwasm/common/wasm_runtime_common.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ static void
196196
runtime_signal_destroy()
197197
{
198198
#ifdef BH_PLATFORM_WINDOWS
199-
RemoveVectoredExceptionHandler(aot_exception_handler);
199+
RemoveVectoredExceptionHandler(runtime_exception_handler);
200200
#endif
201201
os_thread_signal_destroy();
202202
}

core/iwasm/interpreter/wasm_interp_classic.c

Lines changed: 43 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ typedef float64 CellType_F64;
2727

2828
#define BR_TABLE_TMP_BUF_LEN 32
2929

30-
#ifndef OS_ENABLE_HW_BOUND_CHECK
30+
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
31+
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
3132
#define CHECK_MEMORY_OVERFLOW(bytes) \
3233
do { \
3334
uint64 offset1 = (uint64)offset + (uint64)addr; \
@@ -60,7 +61,8 @@ typedef float64 CellType_F64;
6061
do { \
6162
maddr = memory->memory_data + (uint32)(start); \
6263
} while (0)
63-
#endif
64+
#endif /* !defined(OS_ENABLE_HW_BOUND_CHECK) \
65+
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 */
6466

6567
#define CHECK_ATOMIC_MEMORY_ACCESS() \
6668
do { \
@@ -1037,7 +1039,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
10371039
{
10381040
WASMMemoryInstance *memory = module->default_memory;
10391041
uint8 *global_data = module->global_data;
1040-
#ifndef OS_ENABLE_HW_BOUND_CHECK
1042+
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
1043+
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
1044+
|| WASM_ENABLE_BULK_MEMORY != 0
10411045
uint32 num_bytes_per_page = memory ? memory->num_bytes_per_page : 0;
10421046
uint32 linear_mem_size =
10431047
memory ? num_bytes_per_page * memory->cur_page_count : 0;
@@ -1904,8 +1908,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
19041908
frame_sp -= 2;
19051909
addr = POP_I32();
19061910
CHECK_MEMORY_OVERFLOW(8);
1907-
STORE_U32(maddr, frame_sp[1]);
1908-
STORE_U32(maddr + 4, frame_sp[2]);
1911+
PUT_I64_TO_ADDR((uint32 *)maddr,
1912+
GET_I64_FROM_ADDR(frame_sp + 1));
19091913
(void)flags;
19101914
HANDLE_OP_END();
19111915
}
@@ -1991,7 +1995,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
19911995
PUSH_I32(prev_page_count);
19921996
/* update memory instance ptr and memory size */
19931997
memory = module->default_memory;
1994-
#ifndef OS_ENABLE_HW_BOUND_CHECK
1998+
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
1999+
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
2000+
|| WASM_ENABLE_BULK_MEMORY != 0
19952001
linear_mem_size =
19962002
num_bytes_per_page * memory->cur_page_count;
19972003
#endif
@@ -3017,21 +3023,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
30173023
offset = (uint64)(uint32)POP_I32();
30183024
addr = (uint32)POP_I32();
30193025

3026+
#ifndef OS_ENABLE_HW_BOUND_CHECK
30203027
CHECK_BULK_MEMORY_OVERFLOW(addr, bytes, maddr);
3028+
#else
3029+
if ((uint64)(uint32)addr + bytes
3030+
> (uint64)linear_mem_size)
3031+
goto out_of_bounds;
3032+
maddr = memory->memory_data + (uint32)addr;
3033+
#endif
30213034

30223035
seg_len = (uint64)module->module->data_segments[segment]
30233036
->data_length;
30243037
data = module->module->data_segments[segment]->data;
3025-
#ifndef OS_ENABLE_HW_BOUND_CHECK
30263038
if (offset + bytes > seg_len)
30273039
goto out_of_bounds;
30283040

30293041
bh_memcpy_s(maddr, linear_mem_size - addr,
30303042
data + offset, (uint32)bytes);
3031-
#else
3032-
bh_memcpy_s(maddr, (uint32)bytes, data + offset,
3033-
(uint32)bytes);
3034-
#endif
30353043
break;
30363044
}
30373045
case WASM_OP_DATA_DROP:
@@ -3040,7 +3048,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
30403048

30413049
read_leb_uint32(frame_ip, frame_ip_end, segment);
30423050
module->module->data_segments[segment]->data_length = 0;
3043-
30443051
break;
30453052
}
30463053
case WASM_OP_MEMORY_COPY:
@@ -3054,15 +3061,21 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
30543061
src = POP_I32();
30553062
dst = POP_I32();
30563063

3064+
#ifndef OS_ENABLE_HW_BOUND_CHECK
30573065
CHECK_BULK_MEMORY_OVERFLOW(src, len, msrc);
30583066
CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst);
3067+
#else
3068+
if ((uint64)(uint32)src + len > (uint64)linear_mem_size)
3069+
goto out_of_bounds;
3070+
msrc = memory->memory_data + (uint32)src;
3071+
3072+
if ((uint64)(uint32)dst + len > (uint64)linear_mem_size)
3073+
goto out_of_bounds;
3074+
mdst = memory->memory_data + (uint32)dst;
3075+
#endif
30593076

30603077
/* allowing the destination and source to overlap */
3061-
#ifndef OS_ENABLE_HW_BOUND_CHECK
30623078
bh_memmove_s(mdst, linear_mem_size - dst, msrc, len);
3063-
#else
3064-
bh_memmove_s(mdst, len, msrc, len);
3065-
#endif
30663079
break;
30673080
}
30683081
case WASM_OP_MEMORY_FILL:
@@ -3075,10 +3088,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
30753088
fill_val = POP_I32();
30763089
dst = POP_I32();
30773090

3091+
#ifndef OS_ENABLE_HW_BOUND_CHECK
30783092
CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst);
3093+
#else
3094+
if ((uint64)(uint32)dst + len > (uint64)linear_mem_size)
3095+
goto out_of_bounds;
3096+
mdst = memory->memory_data + (uint32)dst;
3097+
#endif
30793098

30803099
memset(mdst, fill_val, len);
3081-
30823100
break;
30833101
}
30843102
#endif /* WASM_ENABLE_BULK_MEMORY */
@@ -3480,8 +3498,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
34803498
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
34813499
CHECK_ATOMIC_MEMORY_ACCESS();
34823500
os_mutex_lock(&memory->mem_lock);
3483-
STORE_U32(maddr, frame_sp[1]);
3484-
STORE_U32(maddr + 4, frame_sp[2]);
3501+
PUT_I64_TO_ADDR((uint32 *)maddr,
3502+
GET_I64_FROM_ADDR(frame_sp + 1));
34853503
os_mutex_unlock(&memory->mem_lock);
34863504
}
34873505
break;
@@ -3723,7 +3741,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
37233741

37243742
/* update memory instance ptr and memory size */
37253743
memory = module->default_memory;
3726-
#ifndef OS_ENABLE_HW_BOUND_CHECK
3744+
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
3745+
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
3746+
|| WASM_ENABLE_BULK_MEMORY != 0
37273747
if (memory)
37283748
linear_mem_size = num_bytes_per_page * memory->cur_page_count;
37293749
#endif
@@ -3803,7 +3823,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
38033823
goto got_exception;
38043824
#endif
38053825

3806-
#ifndef OS_ENABLE_HW_BOUND_CHECK
3826+
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
3827+
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
3828+
|| WASM_ENABLE_BULK_MEMORY != 0
38073829
out_of_bounds:
38083830
wasm_set_exception(module, "out of bounds memory access");
38093831
#endif

core/iwasm/interpreter/wasm_interp_fast.c

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ typedef int64 CellType_I64;
1818
typedef float32 CellType_F32;
1919
typedef float64 CellType_F64;
2020

21-
#ifndef OS_ENABLE_HW_BOUND_CHECK
21+
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
22+
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
2223
#define CHECK_MEMORY_OVERFLOW(bytes) \
2324
do { \
2425
uint64 offset1 = (uint64)offset + (uint64)addr; \
@@ -51,7 +52,8 @@ typedef float64 CellType_F64;
5152
do { \
5253
maddr = memory->memory_data + (uint32)(start); \
5354
} while (0)
54-
#endif /* end of OS_ENABLE_HW_BOUND_CHECK */
55+
#endif /* !defined(OS_ENABLE_HW_BOUND_CHECK) \
56+
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 */
5557

5658
#define CHECK_ATOMIC_MEMORY_ACCESS(align) \
5759
do { \
@@ -1093,7 +1095,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
10931095
WASMInterpFrame *prev_frame)
10941096
{
10951097
WASMMemoryInstance *memory = module->default_memory;
1096-
#ifndef OS_ENABLE_HW_BOUND_CHECK
1098+
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
1099+
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
1100+
|| WASM_ENABLE_BULK_MEMORY != 0
10971101
uint32 num_bytes_per_page = memory ? memory->num_bytes_per_page : 0;
10981102
uint32 linear_mem_size =
10991103
memory ? num_bytes_per_page * memory->cur_page_count : 0;
@@ -1812,7 +1816,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
18121816
frame_lp[addr_ret] = prev_page_count;
18131817
/* update memory instance ptr and memory size */
18141818
memory = module->default_memory;
1815-
#ifndef OS_ENABLE_HW_BOUND_CHECK
1819+
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
1820+
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
1821+
|| WASM_ENABLE_BULK_MEMORY != 0
18161822
linear_mem_size =
18171823
num_bytes_per_page * memory->cur_page_count;
18181824
#endif
@@ -2919,21 +2925,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
29192925
offset = (uint64)POP_I32();
29202926
addr = POP_I32();
29212927

2928+
#ifndef OS_ENABLE_HW_BOUND_CHECK
29222929
CHECK_BULK_MEMORY_OVERFLOW(addr, bytes, maddr);
2930+
#else
2931+
if ((uint64)(uint32)addr + bytes
2932+
> (uint64)linear_mem_size)
2933+
goto out_of_bounds;
2934+
maddr = memory->memory_data + (uint32)addr;
2935+
#endif
29232936

29242937
seg_len = (uint64)module->module->data_segments[segment]
29252938
->data_length;
29262939
data = module->module->data_segments[segment]->data;
2927-
#ifndef OS_ENABLE_HW_BOUND_CHECK
29282940
if (offset + bytes > seg_len)
29292941
goto out_of_bounds;
29302942

29312943
bh_memcpy_s(maddr, linear_mem_size - addr,
29322944
data + offset, (uint32)bytes);
2933-
#else
2934-
bh_memcpy_s(maddr, (uint32)bytes, data + offset,
2935-
(uint32)bytes);
2936-
#endif
29372945
break;
29382946
}
29392947
case WASM_OP_DATA_DROP:
@@ -2943,7 +2951,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
29432951
segment = read_uint32(frame_ip);
29442952

29452953
module->module->data_segments[segment]->data_length = 0;
2946-
29472954
break;
29482955
}
29492956
case WASM_OP_MEMORY_COPY:
@@ -2955,15 +2962,21 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
29552962
src = POP_I32();
29562963
dst = POP_I32();
29572964

2965+
#ifndef OS_ENABLE_HW_BOUND_CHECK
29582966
CHECK_BULK_MEMORY_OVERFLOW(src, len, msrc);
29592967
CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst);
2968+
#else
2969+
if ((uint64)(uint32)src + len > (uint64)linear_mem_size)
2970+
goto out_of_bounds;
2971+
msrc = memory->memory_data + (uint32)src;
2972+
2973+
if ((uint64)(uint32)dst + len > (uint64)linear_mem_size)
2974+
goto out_of_bounds;
2975+
mdst = memory->memory_data + (uint32)dst;
2976+
#endif
29602977

29612978
/* allowing the destination and source to overlap */
2962-
#ifndef OS_ENABLE_HW_BOUND_CHECK
29632979
bh_memmove_s(mdst, linear_mem_size - dst, msrc, len);
2964-
#else
2965-
bh_memmove_s(mdst, len, msrc, len);
2966-
#endif
29672980
break;
29682981
}
29692982
case WASM_OP_MEMORY_FILL:
@@ -2975,10 +2988,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
29752988
fill_val = POP_I32();
29762989
dst = POP_I32();
29772990

2991+
#ifndef OS_ENABLE_HW_BOUND_CHECK
29782992
CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst);
2993+
#else
2994+
if ((uint64)(uint32)dst + len > (uint64)linear_mem_size)
2995+
goto out_of_bounds;
2996+
mdst = memory->memory_data + (uint32)dst;
2997+
#endif
29792998

29802999
memset(mdst, fill_val, len);
2981-
29823000
break;
29833001
}
29843002
#endif /* WASM_ENABLE_BULK_MEMORY */
@@ -3719,7 +3737,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
37193737

37203738
/* update memory instance ptr and memory size */
37213739
memory = module->default_memory;
3722-
#ifndef OS_ENABLE_HW_BOUND_CHECK
3740+
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
3741+
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
3742+
|| WASM_ENABLE_BULK_MEMORY != 0
37233743
if (memory)
37243744
linear_mem_size = num_bytes_per_page * memory->cur_page_count;
37253745
#endif
@@ -3788,7 +3808,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
37883808
goto got_exception;
37893809
#endif
37903810

3791-
#ifndef OS_ENABLE_HW_BOUND_CHECK
3811+
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
3812+
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
3813+
|| WASM_ENABLE_BULK_MEMORY != 0
37923814
out_of_bounds:
37933815
wasm_set_exception(module, "out of bounds memory access");
37943816
#endif

doc/memory_tune.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Note:
1111
- **global heap**: the heap to allocate memory for runtime data structures, including wasm module, wasm module instance, exec env, wasm operand stack and so on. It is initialized by `wasm_runtime_init` or `wasm_runtime_full_init`. And for `wasm_runtime_full_init`, developer can specify the memory allocation mode with `RuntimeInitArgs *init_args`: allocate memory from a user defined byte buffer, from user defined allocation function, or from the platform's os_malloc function. Refer to [wasm_export.h](../core/iwasm/include/wasm_export.h#L98-L141) and [Embedding WAMR guideline](./embed_wamr.md#the-runtime-initialization) for more details. And developer can use `wasm_runtime_malloc/wasm_runtime_free` to allocate/free memory from/to the global heap.
1212
- **wasm operand stack**: the stack to store the operands required by wasm bytecodes as WebAssembly is based on a stack machine. If the exec_env is created by developer with `wasm_runtime_create_exec_env`, then its size is specified by `wasm_runtime_create_exec_env`, otherwise if the exec_env is created by runtime internally, e.g. by `wasm_application_execute_main` or `wasm_application_execute_func`, then the size is specified by `wasm_runtime_instantiate`.
1313
- **linear memory**: a contiguous, mutable array of raw bytes. It is created with an initial size but might be grown dynamically. For most compilers, e.g. wasi-sdk, emsdk, rustc or asc, normally it includes three parts, data area, auxiliary stack area and heap area. For wasi-sdk, the initial/max size can be specified with `-Wl,--initial-memory=n1,--max-memory=n2`, for emsdk, the initial/max size can be specified with `-s INITIAL_MEMORY=n1 -s MAXIMUM_MEMORY=n2 -s ALLOW_MEMORY_GROWTH=1` or `-s TOTAL_MEMORY=n`, and for asc, they can be specified with `--initialMemory` and `--maximumMemory` flags.
14+
- If the memory access boundary check with hardware trap feature is enabled, e.g. in Linux/MacOS/Windows x86-64 by default, the linear memory is allocated by `os_mmap` from virtual address space instead of global heap.
1415
- **aux stack**: the auxiliary stack resides in linear memory to store some temporary data when calling wasm functions, for example, calling a wasm function with complex struct arguments. For wasi-sdk, the size can be specified with `-z stack-size=n`, for emsdk, the size can be specified with `-s TOTAL_STACK=n`.
1516
- **app heap and libc heap**: the heap to allocate memory for wasm app, note that app heap is created only when the malloc/free functions (or __new/__release functions for AssemblyScript) are not exported and runtime can not detect the libc heap. To export the malloc/free functions, for wasi-sdk and emsdk, developer can use `-Wl,--export=malloc -Wl,--export=free` options, for asc, developer can use `--exportRuntime` option. For app heap, the size is specified by `wasm_runtime_instantiate`. It is recommended to export the malloc/free functions and disable app heap in single thread mode, and for multi-threading, as the libc heap isn't thread-safe, it is recommended to remove the dlmalloc.o from libc.a for wasi-sdk and use `-s MALLOC="none"` for emsdk, refer to [WAMR pthread library](./pthread_library.md) for more details. And developer can use `wasm_runtime_module_malloc/wasm_runtime_module_free` to allocate/free memory from/to app heap (or libc heap if malloc/free functions are exported).
1617
- **__data_end global and __heap_base global**: two globals exported by wasm application to indicate the end of data area and the base address of libc heap. For WAMR, it is recommended to export them as when there are no possible memory grow operations, runtime will truncate the linear memory into the size indicated by `__heap_base`, so as to reduce the footprint, or at least one page (64KB) is required by linear memory.

0 commit comments

Comments
 (0)