Refine aot memory boundary check, add more llvm passes (#236)
Fix issue of some error info mismatch with spec cases
This commit is contained in:
@ -127,6 +127,8 @@ handle_next_reachable_block(AOTCompContext *comp_ctx,
|
||||
AOTBlock *block_prev;
|
||||
uint8 *frame_ip;
|
||||
|
||||
aot_checked_addr_list_destroy(func_ctx);
|
||||
|
||||
if (block->block_type == BLOCK_TYPE_IF
|
||||
&& block->llvm_else_block
|
||||
&& !block->skip_wasm_code_else
|
||||
@ -233,6 +235,8 @@ aot_compile_op_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
/* Start to translate the block */
|
||||
SET_BUILDER_POS(block->llvm_entry_block);
|
||||
aot_block_stack_push(&func_ctx->block_stack, block);
|
||||
if (block_type == BLOCK_TYPE_LOOP)
|
||||
aot_checked_addr_list_destroy(func_ctx);
|
||||
}
|
||||
else if (block_type == BLOCK_TYPE_IF) {
|
||||
POP_COND(value);
|
||||
@ -373,6 +377,7 @@ aot_compile_op_else(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
/* Clear value stack and start to translate else branch */
|
||||
aot_value_stack_destroy(&block->value_stack);
|
||||
SET_BUILDER_POS(block->llvm_else_block);
|
||||
aot_checked_addr_list_destroy(func_ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -82,6 +82,7 @@ check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
LLVMValueRef mem_base_addr, mem_check_bound, total_mem_size;
|
||||
LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder);
|
||||
LLVMBasicBlockRef check_succ, check_mem_space;
|
||||
AOTValue *aot_value;
|
||||
|
||||
CHECK_LLVM_CONST(offset_const);
|
||||
CHECK_LLVM_CONST(bytes_const);
|
||||
@ -100,6 +101,8 @@ check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
}
|
||||
}
|
||||
|
||||
aot_value = func_ctx->block_stack.block_list_end->value_stack.value_list_end;
|
||||
|
||||
POP_I32(addr);
|
||||
/* offset1 = offset + addr; */
|
||||
BUILD_OP(Add, offset_const, addr, offset1, "offset1");
|
||||
@ -152,28 +155,38 @@ check_memory_overflow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
SET_BUILD_POS(check_mem_space);
|
||||
}
|
||||
|
||||
/* offset2 = offset1 - heap_base_offset; */
|
||||
BUILD_OP(Sub, offset1, heap_base_offset, offset2, "offset2");
|
||||
if (!(aot_value->is_local
|
||||
&& aot_checked_addr_list_find(func_ctx, aot_value->local_idx,
|
||||
offset, bytes))) {
|
||||
/* offset2 = offset1 - heap_base_offset; */
|
||||
BUILD_OP(Sub, offset1, heap_base_offset, offset2, "offset2");
|
||||
|
||||
if (!(mem_check_bound =
|
||||
get_memory_check_bound(comp_ctx, func_ctx, bytes))) {
|
||||
goto fail;
|
||||
if (!(mem_check_bound =
|
||||
get_memory_check_bound(comp_ctx, func_ctx, bytes))) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Add basic blocks */
|
||||
ADD_BASIC_BLOCK(check_succ, "check_succ");
|
||||
LLVMMoveBasicBlockAfter(check_succ, block_curr);
|
||||
|
||||
/* offset2 > bound ? */
|
||||
BUILD_ICMP(LLVMIntUGT, offset2, mem_check_bound, cmp, "cmp");
|
||||
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 (aot_value->is_local) {
|
||||
if (!aot_checked_addr_list_add(func_ctx, aot_value->local_idx,
|
||||
offset, bytes))
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add basic blocks */
|
||||
ADD_BASIC_BLOCK(check_succ, "check_succ");
|
||||
LLVMMoveBasicBlockAfter(check_succ, block_curr);
|
||||
|
||||
/* offset2 > bound ? */
|
||||
BUILD_ICMP(LLVMIntUGT, offset2, mem_check_bound, cmp, "cmp");
|
||||
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);
|
||||
|
||||
/* maddr = mem_base_addr + offset1 */
|
||||
if (!(maddr = LLVMBuildInBoundsGEP(comp_ctx->builder, mem_base_addr,
|
||||
&offset1, 1, "maddr"))) {
|
||||
|
||||
@ -30,6 +30,7 @@ aot_compile_op_get_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
{
|
||||
char name[32];
|
||||
LLVMValueRef value;
|
||||
AOTValue *aot_value;
|
||||
|
||||
CHECK_LOCAL(local_idx);
|
||||
|
||||
@ -42,6 +43,10 @@ aot_compile_op_get_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
}
|
||||
|
||||
PUSH(value, get_local_type(func_ctx, local_idx));
|
||||
|
||||
aot_value = func_ctx->block_stack.block_list_end->value_stack.value_list_end;
|
||||
aot_value->is_local = true;
|
||||
aot_value->local_idx = local_idx;
|
||||
return true;
|
||||
|
||||
fail:
|
||||
@ -65,6 +70,7 @@ aot_compile_op_set_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
return false;
|
||||
}
|
||||
|
||||
aot_checked_addr_list_del(func_ctx, local_idx);
|
||||
return true;
|
||||
|
||||
fail:
|
||||
@ -92,6 +98,7 @@ aot_compile_op_tee_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
||||
}
|
||||
|
||||
PUSH(value, type);
|
||||
aot_checked_addr_list_del(func_ctx, local_idx);
|
||||
return true;
|
||||
|
||||
fail:
|
||||
|
||||
@ -629,6 +629,7 @@ aot_destroy_func_contexts(AOTFuncContext **func_ctxes, uint32 count)
|
||||
if (func_ctxes[i]->exception_blocks)
|
||||
wasm_runtime_free(func_ctxes[i]->exception_blocks);
|
||||
aot_block_stack_destroy(&func_ctxes[i]->block_stack);
|
||||
aot_checked_addr_list_destroy(func_ctxes[i]);
|
||||
wasm_runtime_free(func_ctxes[i]);
|
||||
}
|
||||
wasm_runtime_free(func_ctxes);
|
||||
@ -1119,11 +1120,15 @@ aot_create_comp_context(AOTCompData *comp_data,
|
||||
aot_set_last_error("create LLVM pass manager failed.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
LLVMAddBasicAliasAnalysisPass(comp_ctx->pass_mgr);
|
||||
LLVMAddPromoteMemoryToRegisterPass(comp_ctx->pass_mgr);
|
||||
LLVMAddInstructionCombiningPass(comp_ctx->pass_mgr);
|
||||
LLVMAddCFGSimplificationPass(comp_ctx->pass_mgr);
|
||||
LLVMAddJumpThreadingPass(comp_ctx->pass_mgr);
|
||||
LLVMAddConstantPropagationPass(comp_ctx->pass_mgr);
|
||||
LLVMAddReassociatePass(comp_ctx->pass_mgr);
|
||||
LLVMAddGVNPass(comp_ctx->pass_mgr);
|
||||
LLVMAddCFGSimplificationPass(comp_ctx->pass_mgr);
|
||||
|
||||
/* Create metadata for llvm float experimental constrained intrinsics */
|
||||
if (!(comp_ctx->fp_rounding_mode =
|
||||
@ -1298,3 +1303,80 @@ aot_block_destroy(AOTBlock *block)
|
||||
aot_value_stack_destroy(&block->value_stack);
|
||||
wasm_runtime_free(block);
|
||||
}
|
||||
|
||||
bool
|
||||
aot_checked_addr_list_add(AOTFuncContext *func_ctx,
|
||||
uint32 local_idx, uint32 offset, uint32 bytes)
|
||||
{
|
||||
AOTCheckedAddr *node = func_ctx->checked_addr_list;
|
||||
|
||||
if (!(node = wasm_runtime_malloc(sizeof(AOTCheckedAddr)))) {
|
||||
aot_set_last_error("allocate memory failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
node->local_idx = local_idx;
|
||||
node->offset = offset;
|
||||
node->bytes = bytes;
|
||||
|
||||
node->next = func_ctx->checked_addr_list;
|
||||
func_ctx->checked_addr_list = node;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
aot_checked_addr_list_del(AOTFuncContext *func_ctx, uint32 local_idx)
|
||||
{
|
||||
AOTCheckedAddr *node = func_ctx->checked_addr_list;
|
||||
AOTCheckedAddr *node_prev = NULL, *node_next;
|
||||
|
||||
while (node) {
|
||||
node_next = node->next;
|
||||
|
||||
if (node->local_idx == local_idx) {
|
||||
if (!node_prev)
|
||||
func_ctx->checked_addr_list = node_next;
|
||||
else
|
||||
node_prev->next = node_next;
|
||||
wasm_runtime_free(node);
|
||||
}
|
||||
else {
|
||||
node_prev = node;
|
||||
}
|
||||
|
||||
node = node_next;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
aot_checked_addr_list_find(AOTFuncContext *func_ctx,
|
||||
uint32 local_idx, uint32 offset, uint32 bytes)
|
||||
{
|
||||
AOTCheckedAddr *node = func_ctx->checked_addr_list;
|
||||
|
||||
while (node) {
|
||||
if (node->local_idx == local_idx
|
||||
&& node->offset == offset
|
||||
&& node->bytes >= bytes) {
|
||||
return true;
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
aot_checked_addr_list_destroy(AOTFuncContext *func_ctx)
|
||||
{
|
||||
AOTCheckedAddr *node = func_ctx->checked_addr_list, *node_next;
|
||||
|
||||
while (node) {
|
||||
node_next = node->next;
|
||||
wasm_runtime_free(node);
|
||||
node = node_next;
|
||||
}
|
||||
|
||||
func_ctx->checked_addr_list = NULL;
|
||||
}
|
||||
|
||||
|
||||
@ -30,6 +30,8 @@ typedef struct AOTValue {
|
||||
LLVMValueRef value;
|
||||
/* VALUE_TYPE_I32/I64/F32/F64/VOID */
|
||||
uint8 type;
|
||||
bool is_local;
|
||||
uint32 local_idx;
|
||||
} AOTValue;
|
||||
|
||||
/**
|
||||
@ -84,6 +86,13 @@ typedef struct AOTBlockStack {
|
||||
uint32 block_index[3];
|
||||
} AOTBlockStack;
|
||||
|
||||
typedef struct AOTCheckedAddr {
|
||||
struct AOTCheckedAddr *next;
|
||||
uint32 local_idx;
|
||||
uint32 offset;
|
||||
uint32 bytes;
|
||||
} AOTCheckedAddr, *AOTCheckedAddrList;
|
||||
|
||||
typedef struct AOTFuncContext {
|
||||
AOTFunc *aot_func;
|
||||
LLVMValueRef func;
|
||||
@ -105,6 +114,7 @@ typedef struct AOTFuncContext {
|
||||
LLVMValueRef cur_exception;
|
||||
|
||||
bool mem_space_unchanged;
|
||||
AOTCheckedAddrList checked_addr_list;
|
||||
|
||||
LLVMBasicBlockRef *exception_blocks;
|
||||
LLVMBasicBlockRef got_exception_block;
|
||||
@ -258,6 +268,20 @@ aot_block_destroy(AOTBlock *block);
|
||||
LLVMTypeRef
|
||||
wasm_type_to_llvm_type(AOTLLVMTypes *llvm_types, uint8 wasm_type);
|
||||
|
||||
bool
|
||||
aot_checked_addr_list_add(AOTFuncContext *func_ctx,
|
||||
uint32 local_idx, uint32 offset, uint32 bytes);
|
||||
|
||||
void
|
||||
aot_checked_addr_list_del(AOTFuncContext *func_ctx, uint32 local_idx);
|
||||
|
||||
bool
|
||||
aot_checked_addr_list_find(AOTFuncContext *func_ctx,
|
||||
uint32 local_idx, uint32 offset, uint32 bytes);
|
||||
|
||||
void
|
||||
aot_checked_addr_list_destroy(AOTFuncContext *func_ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user