From 833142652c2d341004afa83576da0e2e31cf5cfa Mon Sep 17 00:00:00 2001 From: wenlingyun1 Date: Wed, 26 Jun 2024 11:22:07 +0800 Subject: [PATCH 1/2] do aot bounds check by calling native Signed-off-by: wenlingyun1 --- core/iwasm/aot/aot_reloc.h | 1 + core/iwasm/aot/aot_runtime.c | 17 +++++++++ core/iwasm/aot/aot_runtime.h | 11 ++++++ core/iwasm/compilation/aot_emit_memory.c | 45 ++++++++++++++++++++++-- core/iwasm/compilation/aot_llvm.c | 6 ++++ core/iwasm/compilation/aot_llvm.h | 3 ++ core/iwasm/include/aot_comp_option.h | 1 + wamr-compiler/main.c | 4 +++ 8 files changed, 86 insertions(+), 2 deletions(-) diff --git a/core/iwasm/aot/aot_reloc.h b/core/iwasm/aot/aot_reloc.h index 8ead3cd934..2aa1a653ae 100644 --- a/core/iwasm/aot/aot_reloc.h +++ b/core/iwasm/aot/aot_reloc.h @@ -184,6 +184,7 @@ typedef struct { #define REG_COMMON_SYMBOLS \ REG_SYM(aot_set_exception_with_id), \ REG_SYM(aot_invoke_native), \ + REG_SYM(aot_bounds_check), \ REG_SYM(aot_call_indirect), \ REG_SYM(aot_enlarge_memory), \ REG_SYM(aot_set_exception), \ diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index e297833b3b..0fab75919e 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -3109,6 +3109,23 @@ aot_check_app_addr_and_convert(AOTModuleInstance *module_inst, bool is_str, return ret; } +#if WASM_ENABLE_MEMORY64 == 0 +uint64 +aot_bounds_check(AOTModuleInstance *module_inst, uint32 offset, uint32 bytes) +#else +uint64 +aot_bounds_check(AOTModuleInstance *module_inst, uint64 offset, uint32 bytes) +#endif +{ + WASMMemoryInstance *memory = aot_get_default_memory(module_inst); + uint64 linear_memory_size = memory->memory_data_size; + + if (offset + bytes <= linear_memory_size) { + return memory->memory_data + offset; + } + return NULL; +} + void * aot_memmove(void *dest, const void *src, size_t n) { diff --git a/core/iwasm/aot/aot_runtime.h b/core/iwasm/aot/aot_runtime.h index 34d1babd14..a07379eda0 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -622,6 +622,17 @@ aot_check_app_addr_and_convert(AOTModuleInstance *module_inst, bool is_str, uint64 app_buf_addr, uint64 app_buf_size, void **p_native_addr); +/** + * Check whether the memory offset is out of bounds + */ +#if WASM_ENABLE_MEMORY64 == 0 +uint64 +aot_bounds_check(AOTModuleInstance *module_inst, uint32 offset, uint32 bytes); +#else +uint64 +aot_bounds_check(AOTModuleInstance *module_inst, uint64 offset, uint32 bytes); +#endif + uint32 aot_get_plt_table_size(); diff --git a/core/iwasm/compilation/aot_emit_memory.c b/core/iwasm/compilation/aot_emit_memory.c index ff49239668..05d52bec29 100644 --- a/core/iwasm/compilation/aot_emit_memory.c +++ b/core/iwasm/compilation/aot_emit_memory.c @@ -94,6 +94,40 @@ get_memory_check_bound(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, static LLVMValueRef get_memory_curr_page_count(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx); +static LLVMValueRef +aot_call_runtime_bounds_check(AOTCompContext *comp_ctx, + AOTFuncContext *func_ctx, LLVMValueRef offset, + uint32 bytes) +{ + LLVMValueRef param_values[3], value, maddr, func; + LLVMTypeRef param_types[3], ret_type = 0, func_type = 0, func_ptr_type = 0; + uint32 argc = 3; + + param_types[0] = INT8_PTR_TYPE; +#if WASM_ENABLE_MEMORY64 == 0 + param_types[1] = I32_TYPE; +#else + param_types[1] = I64_TYPE; +#endif + param_types[2] = I32_TYPE; + ret_type = INT8_PTR_TYPE; + + param_values[0] = func_ctx->aot_inst; + param_values[1] = offset; + param_values[2] = I32_CONST(bytes); + + GET_AOT_FUNCTION(aot_bounds_check, argc); + + if (!(maddr = LLVMBuildCall2(comp_ctx->builder, func_type, func, + param_values, argc, "maddr"))) { + aot_set_last_error("llvm build call failed."); + goto fail; + } + return maddr; +fail: + return NULL; +} + LLVMValueRef aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, mem_offset_t offset, uint32 bytes, bool enable_segue, @@ -312,7 +346,6 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, goto fail; } } - if (!enable_segue) { /* maddr = mem_base_addr + offset1 */ if (!(maddr = @@ -337,9 +370,17 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, goto fail; } } + return maddr; fail: - return NULL; + if (comp_ctx->enable_bound_check && comp_ctx->enable_runtime_bound_check) { + maddr = + aot_call_runtime_bounds_check(comp_ctx, func_ctx, offset1, bytes); + return maddr; + } + else { + return NULL; + } } #define BUILD_PTR_CAST(ptr_type) \ diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index df07c3ca6c..d0b2d6eddd 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -2621,6 +2621,8 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option) #ifndef OS_ENABLE_HW_BOUND_CHECK comp_ctx->enable_bound_check = true; + comp_ctx->enable_runtime_bound_check = + option->enable_runtime_bound_check; /* Always enable stack boundary check if `bounds-checks` is enabled */ comp_ctx->enable_stack_bound_check = true; @@ -2954,6 +2956,8 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option) /* Set by user */ comp_ctx->enable_bound_check = (option->bounds_checks == 1) ? true : false; + comp_ctx->enable_runtime_bound_check = + option->enable_runtime_bound_check; } else { /* Unset by user, use default value */ @@ -2963,6 +2967,8 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option) } else { comp_ctx->enable_bound_check = true; + comp_ctx->enable_runtime_bound_check = + option->enable_runtime_bound_check; } } diff --git a/core/iwasm/compilation/aot_llvm.h b/core/iwasm/compilation/aot_llvm.h index ab5242173f..0c8660891b 100644 --- a/core/iwasm/compilation/aot_llvm.h +++ b/core/iwasm/compilation/aot_llvm.h @@ -397,6 +397,9 @@ typedef struct AOTCompContext { /* Boundary Check */ bool enable_bound_check; + /* Boundary Check by calling runtime function*/ + bool enable_runtime_bound_check; + /* Native stack boundary Check */ bool enable_stack_bound_check; diff --git a/core/iwasm/include/aot_comp_option.h b/core/iwasm/include/aot_comp_option.h index 617b68f974..41fce0fb67 100644 --- a/core/iwasm/include/aot_comp_option.h +++ b/core/iwasm/include/aot_comp_option.h @@ -29,6 +29,7 @@ typedef struct AOTCompOption { bool enable_llvm_pgo; bool enable_stack_estimation; bool quick_invoke_c_api_import; + bool enable_runtime_bound_check; char *use_prof_file; uint32_t opt_level; uint32_t size_level; diff --git a/wamr-compiler/main.c b/wamr-compiler/main.c index 1044014c0a..dc77833b39 100644 --- a/wamr-compiler/main.c +++ b/wamr-compiler/main.c @@ -139,6 +139,7 @@ print_help() printf(" if the option is set:\n"); printf(" (1) it is always enabled when `--bounds-checks` is enabled,\n"); printf(" (2) else it is enabled/disabled according to the option value\n"); + printf(" --runtime-bounds-checks Enable bounds check by call runtime function:\n"); printf(" --stack-usage= Generate a stack-usage file.\n"); printf(" Similarly to `clang -fstack-usage`.\n"); printf(" --format= Specifies the format of the output file\n"); @@ -545,6 +546,9 @@ main(int argc, char *argv[]) else if (!strcmp(argv[0], "--invoke-c-api-import")) { option.quick_invoke_c_api_import = true; } + else if (!strcmp(argv[0], "--runtime-bounds-checks")) { + option.enable_runtime_bound_check = true; + } #if WASM_ENABLE_LINUX_PERF != 0 else if (!strcmp(argv[0], "--enable-linux-perf")) { enable_linux_perf = true; From bd4dfcfb144ca164372898333aceb8cf0880ab9d Mon Sep 17 00:00:00 2001 From: wenlingyun1 Date: Thu, 4 Jul 2024 19:33:37 +0800 Subject: [PATCH 2/2] do runtime bounds check when normal check failed Signed-off-by: wenlingyun1 --- core/iwasm/aot/aot_runtime.c | 8 +--- core/iwasm/compilation/aot_emit_memory.c | 61 ++++++++++++++---------- 2 files changed, 37 insertions(+), 32 deletions(-) diff --git a/core/iwasm/aot/aot_runtime.c b/core/iwasm/aot/aot_runtime.c index 0fab75919e..6d8659ed91 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -3117,13 +3117,7 @@ uint64 aot_bounds_check(AOTModuleInstance *module_inst, uint64 offset, uint32 bytes) #endif { - WASMMemoryInstance *memory = aot_get_default_memory(module_inst); - uint64 linear_memory_size = memory->memory_data_size; - - if (offset + bytes <= linear_memory_size) { - return memory->memory_data + offset; - } - return NULL; + return offset; } void * diff --git a/core/iwasm/compilation/aot_emit_memory.c b/core/iwasm/compilation/aot_emit_memory.c index 05d52bec29..e0a1aa8230 100644 --- a/core/iwasm/compilation/aot_emit_memory.c +++ b/core/iwasm/compilation/aot_emit_memory.c @@ -99,7 +99,7 @@ aot_call_runtime_bounds_check(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, LLVMValueRef offset, uint32 bytes) { - LLVMValueRef param_values[3], value, maddr, func; + LLVMValueRef param_values[3], value, offset2, func; LLVMTypeRef param_types[3], ret_type = 0, func_type = 0, func_ptr_type = 0; uint32 argc = 3; @@ -118,12 +118,12 @@ aot_call_runtime_bounds_check(AOTCompContext *comp_ctx, GET_AOT_FUNCTION(aot_bounds_check, argc); - if (!(maddr = LLVMBuildCall2(comp_ctx->builder, func_type, func, - param_values, argc, "maddr"))) { + if (!(offset2 = LLVMBuildCall2(comp_ctx->builder, func_type, func, + param_values, argc, "offset2"))) { aot_set_last_error("llvm build call failed."); goto fail; } - return maddr; + return offset2; fail: return NULL; } @@ -135,10 +135,11 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, { LLVMValueRef offset_const = MEMORY64_COND_VALUE(I64_CONST(offset), I32_CONST(offset)); - LLVMValueRef addr, maddr, offset1, cmp1, cmp2, cmp; + LLVMValueRef addr, maddr, offset1, offset2, cmp1, cmp2, cmp; LLVMValueRef mem_base_addr, mem_check_bound; LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder); - LLVMBasicBlockRef check_succ; + LLVMBasicBlockRef check_succ, runtime_bounds_check; + LLVMValueRef phi; AOTValue *aot_value_top; uint32 local_idx_of_aot_value = 0; uint64 const_value; @@ -204,7 +205,6 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } POP_MEM_OFFSET(addr); - /* * Note: not throw the integer-overflow-exception here since it must * have been thrown when converting float to integer before @@ -330,21 +330,39 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, /* Add basic blocks */ ADD_BASIC_BLOCK(check_succ, "check_succ"); - LLVMMoveBasicBlockAfter(check_succ, block_curr); - - if (!aot_emit_exception(comp_ctx, func_ctx, - EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, true, cmp, - check_succ)) { - goto fail; - } - - SET_BUILD_POS(check_succ); - if (is_local_of_aot_value) { if (!aot_checked_addr_list_add(func_ctx, local_idx_of_aot_value, offset, bytes)) goto fail; } + if (comp_ctx->enable_runtime_bound_check) { + ADD_BASIC_BLOCK(runtime_bounds_check, "runtime_bounds_check"); + LLVMBuildCondBr(comp_ctx->builder, cmp, runtime_bounds_check, + check_succ); + SET_BUILD_POS(runtime_bounds_check); + offset2 = aot_call_runtime_bounds_check(comp_ctx, func_ctx, offset1, + bytes); + // todo: store offset2 in the local + LLVMBuildBr(comp_ctx->builder, check_succ); + } else { + if (!aot_emit_exception(comp_ctx, func_ctx, + EXCE_OUT_OF_BOUNDS_MEMORY_ACCESS, true, cmp, + check_succ)) { + goto fail; + } + } + + SET_BUILD_POS(check_succ); + + if (comp_ctx->enable_runtime_bound_check) { + phi = LLVMBuildPhi(comp_ctx->builder, + is_target_64bit ? I64_TYPE : I32_TYPE, "phi"); + LLVMValueRef incoming_values[] = { offset1, offset2 }; + LLVMBasicBlockRef incoming_blocks[] = { block_curr, + runtime_bounds_check }; + LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2); + offset1 = phi; + } } if (!enable_segue) { /* maddr = mem_base_addr + offset1 */ @@ -373,14 +391,7 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, return maddr; fail: - if (comp_ctx->enable_bound_check && comp_ctx->enable_runtime_bound_check) { - maddr = - aot_call_runtime_bounds_check(comp_ctx, func_ctx, offset1, bytes); - return maddr; - } - else { - return NULL; - } + return NULL; } #define BUILD_PTR_CAST(ptr_type) \