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..77e9b706d7 100644 --- a/core/iwasm/aot/aot_runtime.c +++ b/core/iwasm/aot/aot_runtime.c @@ -3109,6 +3109,21 @@ aot_check_app_addr_and_convert(AOTModuleInstance *module_inst, bool is_str, return ret; } +uint64 +aot_bounds_check(AOTModuleInstance *module_inst, uint64 offset, + uint32 bytes) +{ + 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; + } + // execption + 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..04966a22cb 100644 --- a/core/iwasm/aot/aot_runtime.h +++ b/core/iwasm/aot/aot_runtime.h @@ -622,6 +622,13 @@ 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 inside the linear memory + */ +uint64 +aot_bounds_check(AOTModuleInstance *module_inst, uint64 offset, + uint32 bytes); + 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..0588aaa0ee 100644 --- a/core/iwasm/compilation/aot_emit_memory.c +++ b/core/iwasm/compilation/aot_emit_memory.c @@ -94,6 +94,37 @@ 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; + param_types[1] = I64_TYPE; + 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, @@ -257,18 +288,57 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, && !(is_local_of_aot_value && aot_checked_addr_list_find(func_ctx, local_idx_of_aot_value, offset, bytes))) { - uint32 init_page_count = - comp_ctx->comp_data->memories[0].init_page_count; - if (init_page_count == 0) { - LLVMValueRef mem_size; + if (comp_ctx->enable_runtime_bound_check) { + + if (!(maddr = aot_call_runtime_bounds_check(comp_ctx, func_ctx, offset1, bytes))) + { + goto fail; + } + } + else { + uint32 init_page_count = + comp_ctx->comp_data->memories[0].init_page_count; + if (init_page_count == 0) { + LLVMValueRef mem_size; + + if (!(mem_size = + get_memory_curr_page_count(comp_ctx, func_ctx))) { + goto fail; + } + BUILD_ICMP(LLVMIntEQ, mem_size, + MEMORY64_COND_VALUE(I64_ZERO, I32_ZERO), cmp, + "is_zero"); + ADD_BASIC_BLOCK(check_succ, "check_mem_size_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; + } - if (!(mem_size = get_memory_curr_page_count(comp_ctx, func_ctx))) { + SET_BUILD_POS(check_succ); + block_curr = check_succ; + } + + if (!(mem_check_bound = + get_memory_check_bound(comp_ctx, func_ctx, bytes))) { goto fail; } - BUILD_ICMP(LLVMIntEQ, mem_size, - MEMORY64_COND_VALUE(I64_ZERO, I32_ZERO), cmp, "is_zero"); - ADD_BASIC_BLOCK(check_succ, "check_mem_size_succ"); + + if (is_target_64bit) { + BUILD_ICMP(LLVMIntUGT, offset1, mem_check_bound, cmp, "cmp"); + } + else { + /* Check integer overflow */ + BUILD_ICMP(LLVMIntULT, offset1, addr, cmp1, "cmp1"); + BUILD_ICMP(LLVMIntUGT, offset1, mem_check_bound, cmp2, "cmp2"); + BUILD_OP(Or, cmp1, cmp2, cmp, "cmp"); + } + + /* 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)) { @@ -276,40 +346,12 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, } SET_BUILD_POS(check_succ); - block_curr = check_succ; - } - - if (!(mem_check_bound = - get_memory_check_bound(comp_ctx, func_ctx, bytes))) { - goto fail; - } - - if (is_target_64bit) { - BUILD_ICMP(LLVMIntUGT, offset1, mem_check_bound, cmp, "cmp"); - } - else { - /* Check integer overflow */ - BUILD_ICMP(LLVMIntULT, offset1, addr, cmp1, "cmp1"); - BUILD_ICMP(LLVMIntUGT, offset1, mem_check_bound, cmp2, "cmp2"); - BUILD_OP(Or, cmp1, cmp2, cmp, "cmp"); - } - - /* 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 (is_local_of_aot_value) { + if (!aot_checked_addr_list_add(func_ctx, local_idx_of_aot_value, + offset, bytes)) + goto fail; + } } } @@ -321,6 +363,7 @@ aot_check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx, aot_set_last_error("llvm build add failed."); goto fail; } + } else { LLVMValueRef maddr_base; diff --git a/core/iwasm/compilation/aot_llvm.c b/core/iwasm/compilation/aot_llvm.c index df07c3ca6c..5d5ea0d8d1 100644 --- a/core/iwasm/compilation/aot_llvm.c +++ b/core/iwasm/compilation/aot_llvm.c @@ -2621,6 +2621,7 @@ 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 +2955,7 @@ 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 +2965,7 @@ 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;