Fix interp hw bound check issues (#1322)

Fix build script to enable hw bound check for interpreter when
AOT is disabled, so as to enable spec cases test for interp with
hw bound check. And fix the issues found.
This commit is contained in:
Wenyong Huang 2022-07-23 20:39:01 +08:00 committed by GitHub
parent fd5030e02e
commit dd62b32b20
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 84 additions and 43 deletions

View File

@ -201,10 +201,6 @@ endif ()
if (WAMR_DISABLE_HW_BOUND_CHECK EQUAL 1)
add_definitions (-DWASM_DISABLE_HW_BOUND_CHECK=1)
message (" Hardware boundary check disabled")
elseif (NOT WAMR_BUILD_AOT EQUAL 1)
# Enable memory access boundary check with hardware trap
# only when AOT/JIT is enabled
add_definitions (-DWASM_DISABLE_HW_BOUND_CHECK=1)
else ()
add_definitions (-DWASM_DISABLE_HW_BOUND_CHECK=0)
endif ()

View File

@ -189,7 +189,7 @@ static void
runtime_signal_destroy()
{
#ifdef BH_PLATFORM_WINDOWS
RemoveVectoredExceptionHandler(aot_exception_handler);
RemoveVectoredExceptionHandler(runtime_exception_handler);
#endif
os_thread_signal_destroy();
}

View File

@ -24,7 +24,8 @@ typedef float64 CellType_F64;
#define BR_TABLE_TMP_BUF_LEN 32
#ifndef OS_ENABLE_HW_BOUND_CHECK
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
#define CHECK_MEMORY_OVERFLOW(bytes) \
do { \
uint64 offset1 = (uint64)offset + (uint64)addr; \
@ -57,7 +58,8 @@ typedef float64 CellType_F64;
do { \
maddr = memory->memory_data + (uint32)(start); \
} while (0)
#endif
#endif /* !defined(OS_ENABLE_HW_BOUND_CHECK) \
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 */
#define CHECK_ATOMIC_MEMORY_ACCESS() \
do { \
@ -1020,7 +1022,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
{
WASMMemoryInstance *memory = module->default_memory;
uint8 *global_data = module->global_data;
#ifndef OS_ENABLE_HW_BOUND_CHECK
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
|| WASM_ENABLE_BULK_MEMORY != 0
uint32 num_bytes_per_page = memory ? memory->num_bytes_per_page : 0;
uint32 linear_mem_size =
memory ? num_bytes_per_page * memory->cur_page_count : 0;
@ -1887,8 +1891,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
frame_sp -= 2;
addr = POP_I32();
CHECK_MEMORY_OVERFLOW(8);
STORE_U32(maddr, frame_sp[1]);
STORE_U32(maddr + 4, frame_sp[2]);
PUT_I64_TO_ADDR((uint32 *)maddr,
GET_I64_FROM_ADDR(frame_sp + 1));
(void)flags;
HANDLE_OP_END();
}
@ -1974,7 +1978,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
PUSH_I32(prev_page_count);
/* update memory instance ptr and memory size */
memory = module->default_memory;
#ifndef OS_ENABLE_HW_BOUND_CHECK
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
|| WASM_ENABLE_BULK_MEMORY != 0
linear_mem_size =
num_bytes_per_page * memory->cur_page_count;
#endif
@ -3000,21 +3006,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
offset = (uint64)(uint32)POP_I32();
addr = (uint32)POP_I32();
#ifndef OS_ENABLE_HW_BOUND_CHECK
CHECK_BULK_MEMORY_OVERFLOW(addr, bytes, maddr);
#else
if ((uint64)(uint32)addr + bytes
> (uint64)linear_mem_size)
goto out_of_bounds;
maddr = memory->memory_data + (uint32)addr;
#endif
seg_len = (uint64)module->module->data_segments[segment]
->data_length;
data = module->module->data_segments[segment]->data;
#ifndef OS_ENABLE_HW_BOUND_CHECK
if (offset + bytes > seg_len)
goto out_of_bounds;
bh_memcpy_s(maddr, linear_mem_size - addr,
data + offset, (uint32)bytes);
#else
bh_memcpy_s(maddr, (uint32)bytes, data + offset,
(uint32)bytes);
#endif
break;
}
case WASM_OP_DATA_DROP:
@ -3023,7 +3031,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
read_leb_uint32(frame_ip, frame_ip_end, segment);
module->module->data_segments[segment]->data_length = 0;
break;
}
case WASM_OP_MEMORY_COPY:
@ -3037,15 +3044,21 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
src = POP_I32();
dst = POP_I32();
#ifndef OS_ENABLE_HW_BOUND_CHECK
CHECK_BULK_MEMORY_OVERFLOW(src, len, msrc);
CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst);
#else
if ((uint64)(uint32)src + len > (uint64)linear_mem_size)
goto out_of_bounds;
msrc = memory->memory_data + (uint32)src;
if ((uint64)(uint32)dst + len > (uint64)linear_mem_size)
goto out_of_bounds;
mdst = memory->memory_data + (uint32)dst;
#endif
/* allowing the destination and source to overlap */
#ifndef OS_ENABLE_HW_BOUND_CHECK
bh_memmove_s(mdst, linear_mem_size - dst, msrc, len);
#else
bh_memmove_s(mdst, len, msrc, len);
#endif
break;
}
case WASM_OP_MEMORY_FILL:
@ -3058,10 +3071,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
fill_val = POP_I32();
dst = POP_I32();
#ifndef OS_ENABLE_HW_BOUND_CHECK
CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst);
#else
if ((uint64)(uint32)dst + len > (uint64)linear_mem_size)
goto out_of_bounds;
mdst = memory->memory_data + (uint32)dst;
#endif
memset(mdst, fill_val, len);
break;
}
#endif /* WASM_ENABLE_BULK_MEMORY */
@ -3463,8 +3481,8 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
CHECK_BULK_MEMORY_OVERFLOW(addr + offset, 8, maddr);
CHECK_ATOMIC_MEMORY_ACCESS();
os_mutex_lock(&memory->mem_lock);
STORE_U32(maddr, frame_sp[1]);
STORE_U32(maddr + 4, frame_sp[2]);
PUT_I64_TO_ADDR((uint32 *)maddr,
GET_I64_FROM_ADDR(frame_sp + 1));
os_mutex_unlock(&memory->mem_lock);
}
break;
@ -3706,7 +3724,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
/* update memory instance ptr and memory size */
memory = module->default_memory;
#ifndef OS_ENABLE_HW_BOUND_CHECK
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
|| WASM_ENABLE_BULK_MEMORY != 0
if (memory)
linear_mem_size = num_bytes_per_page * memory->cur_page_count;
#endif
@ -3786,7 +3806,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
goto got_exception;
#endif
#ifndef OS_ENABLE_HW_BOUND_CHECK
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
|| WASM_ENABLE_BULK_MEMORY != 0
out_of_bounds:
wasm_set_exception(module, "out of bounds memory access");
#endif

View File

@ -18,7 +18,8 @@ typedef int64 CellType_I64;
typedef float32 CellType_F32;
typedef float64 CellType_F64;
#ifndef OS_ENABLE_HW_BOUND_CHECK
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0
#define CHECK_MEMORY_OVERFLOW(bytes) \
do { \
uint64 offset1 = (uint64)offset + (uint64)addr; \
@ -51,7 +52,8 @@ typedef float64 CellType_F64;
do { \
maddr = memory->memory_data + (uint32)(start); \
} while (0)
#endif /* end of OS_ENABLE_HW_BOUND_CHECK */
#endif /* !defined(OS_ENABLE_HW_BOUND_CHECK) \
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 */
#define CHECK_ATOMIC_MEMORY_ACCESS(align) \
do { \
@ -1093,7 +1095,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
WASMInterpFrame *prev_frame)
{
WASMMemoryInstance *memory = module->default_memory;
#ifndef OS_ENABLE_HW_BOUND_CHECK
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
|| WASM_ENABLE_BULK_MEMORY != 0
uint32 num_bytes_per_page = memory ? memory->num_bytes_per_page : 0;
uint32 linear_mem_size =
memory ? num_bytes_per_page * memory->cur_page_count : 0;
@ -1812,7 +1816,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
frame_lp[addr_ret] = prev_page_count;
/* update memory instance ptr and memory size */
memory = module->default_memory;
#ifndef OS_ENABLE_HW_BOUND_CHECK
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
|| WASM_ENABLE_BULK_MEMORY != 0
linear_mem_size =
num_bytes_per_page * memory->cur_page_count;
#endif
@ -2919,21 +2925,23 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
offset = (uint64)POP_I32();
addr = POP_I32();
#ifndef OS_ENABLE_HW_BOUND_CHECK
CHECK_BULK_MEMORY_OVERFLOW(addr, bytes, maddr);
#else
if ((uint64)(uint32)addr + bytes
> (uint64)linear_mem_size)
goto out_of_bounds;
maddr = memory->memory_data + (uint32)addr;
#endif
seg_len = (uint64)module->module->data_segments[segment]
->data_length;
data = module->module->data_segments[segment]->data;
#ifndef OS_ENABLE_HW_BOUND_CHECK
if (offset + bytes > seg_len)
goto out_of_bounds;
bh_memcpy_s(maddr, linear_mem_size - addr,
data + offset, (uint32)bytes);
#else
bh_memcpy_s(maddr, (uint32)bytes, data + offset,
(uint32)bytes);
#endif
break;
}
case WASM_OP_DATA_DROP:
@ -2943,7 +2951,6 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
segment = read_uint32(frame_ip);
module->module->data_segments[segment]->data_length = 0;
break;
}
case WASM_OP_MEMORY_COPY:
@ -2955,15 +2962,21 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
src = POP_I32();
dst = POP_I32();
#ifndef OS_ENABLE_HW_BOUND_CHECK
CHECK_BULK_MEMORY_OVERFLOW(src, len, msrc);
CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst);
#else
if ((uint64)(uint32)src + len > (uint64)linear_mem_size)
goto out_of_bounds;
msrc = memory->memory_data + (uint32)src;
if ((uint64)(uint32)dst + len > (uint64)linear_mem_size)
goto out_of_bounds;
mdst = memory->memory_data + (uint32)dst;
#endif
/* allowing the destination and source to overlap */
#ifndef OS_ENABLE_HW_BOUND_CHECK
bh_memmove_s(mdst, linear_mem_size - dst, msrc, len);
#else
bh_memmove_s(mdst, len, msrc, len);
#endif
break;
}
case WASM_OP_MEMORY_FILL:
@ -2975,10 +2988,15 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
fill_val = POP_I32();
dst = POP_I32();
#ifndef OS_ENABLE_HW_BOUND_CHECK
CHECK_BULK_MEMORY_OVERFLOW(dst, len, mdst);
#else
if ((uint64)(uint32)dst + len > (uint64)linear_mem_size)
goto out_of_bounds;
mdst = memory->memory_data + (uint32)dst;
#endif
memset(mdst, fill_val, len);
break;
}
#endif /* WASM_ENABLE_BULK_MEMORY */
@ -3719,7 +3737,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
/* update memory instance ptr and memory size */
memory = module->default_memory;
#ifndef OS_ENABLE_HW_BOUND_CHECK
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
|| WASM_ENABLE_BULK_MEMORY != 0
if (memory)
linear_mem_size = num_bytes_per_page * memory->cur_page_count;
#endif
@ -3788,7 +3808,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
goto got_exception;
#endif
#ifndef OS_ENABLE_HW_BOUND_CHECK
#if !defined(OS_ENABLE_HW_BOUND_CHECK) \
|| WASM_CPU_SUPPORTS_UNALIGNED_ADDR_ACCESS == 0 \
|| WASM_ENABLE_BULK_MEMORY != 0
out_of_bounds:
wasm_set_exception(module, "out of bounds memory access");
#endif

View File

@ -11,6 +11,7 @@ Note:
- **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.
- **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`.
- **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.
- 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.
- **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`.
- **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).
- **__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.