Просмотр исходного кода

Refine aot memory boundary check, add more llvm passes (#236)

Fix issue of some error info mismatch with spec cases
wenyongh 5 лет назад
Родитель
Сommit
f72e848114

+ 5 - 0
core/iwasm/compilation/aot_emit_control.c

@@ -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;
     }
 

+ 30 - 17
core/iwasm/compilation/aot_emit_memory.c

@@ -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,27 +155,37 @@ 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);
+        /* 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;
-    }
+        /* 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);
 
-    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;
+        }
+    }
 
     /* maddr = mem_base_addr + offset1 */
     if (!(maddr = LLVMBuildInBoundsGEP(comp_ctx->builder, mem_base_addr,

+ 7 - 0
core/iwasm/compilation/aot_emit_variable.c

@@ -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:

+ 83 - 1
core/iwasm/compilation/aot_llvm.c

@@ -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;
+}
+

+ 24 - 0
core/iwasm/compilation/aot_llvm.h

@@ -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

+ 66 - 20
core/iwasm/interpreter/wasm_loader.c

@@ -419,7 +419,7 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
             read_leb_uint32(p, p_end, result_count);
             if (result_count > 1) {
                 set_error_buf(error_buf, error_buf_size,
-                              "Load type section failed: invalid result count.");
+                              "Load type section failed: invalid result arity.");
                 return false;
             }
             CHECK_BUF(p, p_end, result_count);
@@ -485,6 +485,36 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end,
 unsigned
 wasm_runtime_memory_pool_size();
 
+static bool
+check_memory_init_size(uint32 init_size,
+                       char *error_buf, uint32 error_buf_size)
+{
+    if (init_size > 65536) {
+        set_error_buf(error_buf, error_buf_size,
+                      "memory size must be at most 65536 pages (4GiB)");
+        return false;
+    }
+    return true;
+}
+
+static bool
+check_memory_max_size(uint32 init_size, uint32 max_size,
+                      char *error_buf, uint32 error_buf_size)
+{
+    if (max_size < init_size) {
+        set_error_buf(error_buf, error_buf_size,
+                      "size minimum must not be greater than maximum");
+        return false;
+    }
+
+    if (max_size > 65536) {
+        set_error_buf(error_buf, error_buf_size,
+                      "memory size must be at most 65536 pages (4GiB)");
+        return false;
+    }
+    return true;
+}
+
 static bool
 load_memory_import(const uint8 **p_buf, const uint8 *buf_end,
                    WASMMemoryImport *memory,
@@ -501,8 +531,16 @@ load_memory_import(const uint8 **p_buf, const uint8 *buf_end,
 
     read_leb_uint32(p, p_end, memory->flags);
     read_leb_uint32(p, p_end, memory->init_page_count);
+    if (!check_memory_init_size(memory->init_page_count,
+                                error_buf, error_buf_size))
+        return false;
+
     if (memory->flags & 1) {
         read_leb_uint32(p, p_end, memory->max_page_count);
+        if (!check_memory_max_size(memory->init_page_count,
+                                   memory->max_page_count,
+                                   error_buf, error_buf_size))
+                return false;
         if (memory->max_page_count > max_page_count)
             memory->max_page_count = max_page_count;
     }
@@ -552,8 +590,16 @@ load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory,
 
     read_leb_uint32(p, p_end, memory->flags);
     read_leb_uint32(p, p_end, memory->init_page_count);
+    if (!check_memory_init_size(memory->init_page_count,
+                                error_buf, error_buf_size))
+        return false;
+
     if (memory->flags & 1) {
         read_leb_uint32(p, p_end, memory->max_page_count);
+        if (!check_memory_max_size(memory->init_page_count,
+                                   memory->max_page_count,
+                                   error_buf, error_buf_size))
+                return false;
         if (memory->max_page_count > max_page_count)
             memory->max_page_count = max_page_count;
     }
@@ -715,7 +761,7 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
                     if (type_index >= module->type_count) {
                         set_error_buf(error_buf, error_buf_size,
                                       "Load import section failed: "
-                                      "function type index out of range.");
+                                      "unknown type.");
                         return false;
                     }
                     import->u.function.func_type = module->types[type_index];
@@ -898,7 +944,7 @@ load_function_section(const uint8 *buf, const uint8 *buf_end,
             if (type_index >= module->type_count) {
                 set_error_buf(error_buf, error_buf_size,
                               "Load function section failed: "
-                              "function type index out of range.");
+                              "unknown type.");
                 return false;
             }
 
@@ -1017,7 +1063,7 @@ load_table_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
     if (table_count) {
         if (table_count > 1) {
             set_error_buf(error_buf, error_buf_size,
-                          "Load table section failed: multiple memories");
+                          "Load table section failed: multiple tables");
             return false;
         }
         module->table_count = table_count;
@@ -1194,7 +1240,7 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
                     if (index >= module->function_count + module->import_function_count) {
                         set_error_buf(error_buf, error_buf_size,
                                       "Load export section failed: "
-                                      "function index out of range.");
+                                      "unknown function.");
                         return false;
                     }
                     break;
@@ -1203,7 +1249,7 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
                     if (index >= module->table_count + module->import_table_count) {
                         set_error_buf(error_buf, error_buf_size,
                                       "Load export section failed: "
-                                      "table index out of range.");
+                                      "unknown table.");
                         return false;
                     }
                     break;
@@ -1212,7 +1258,7 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
                     if (index >= module->memory_count + module->import_memory_count) {
                         set_error_buf(error_buf, error_buf_size,
                                       "Load export section failed: "
-                                      "memory index out of range.");
+                                      "unknown memory.");
                         return false;
                     }
                     break;
@@ -1221,7 +1267,7 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
                     if (index >= module->global_count + module->import_global_count) {
                         set_error_buf(error_buf, error_buf_size,
                                       "Load export section failed: "
-                                      "global index out of range.");
+                                      "unknown global.");
                         return false;
                     }
                     break;
@@ -1273,7 +1319,7 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, WASMModule *m
             if (p >= p_end) {
                 set_error_buf(error_buf, error_buf_size,
                               "Load table segment section failed: "
-                              "invalid value type");
+                              "unexpected end");
                 return false;
             }
             read_leb_uint32(p, p_end, table_index);
@@ -1417,7 +1463,7 @@ load_start_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
         if (start_function >= module->function_count + module->import_function_count) {
             set_error_buf(error_buf, error_buf_size,
                           "Load start section failed: "
-                          "function index out of range.");
+                          "unknown function.");
             return false;
         }
         module->start_function = start_function;
@@ -2703,7 +2749,7 @@ wasm_loader_check_br(WASMLoaderContext *ctx, uint32 depth,
 {
     if (ctx->csp_num < depth + 1) {
       set_error_buf(error_buf, error_buf_size,
-                    "WASM module load failed: type mismatch: "
+                    "WASM module load failed: unknown label, "
                     "unexpected end of section or function");
       return false;
     }
@@ -3405,7 +3451,7 @@ fail:
     if (local_idx >= param_count + local_count) {   \
       set_error_buf(error_buf, error_buf_size,      \
                     "WASM module load failed: "     \
-                    "local index out of range");    \
+                    "unknown local.");              \
       goto fail;                                    \
     }                                               \
     local_type = local_idx < param_count            \
@@ -3427,8 +3473,7 @@ check_memory(WASMModule *module,
     if (module->memory_count == 0
         && module->import_memory_count == 0) {
         set_error_buf(error_buf, error_buf_size,
-                      "WASM module load failed: "
-                      "load or store in module without default memory");
+                      "WASM module load failed: unknown memory");
         return false;
     }
     return true;
@@ -3848,7 +3893,7 @@ handle_next_reachable_block:
                 if (func_idx >= module->import_function_count + module->function_count) {
                     set_error_buf(error_buf, error_buf_size,
                                   "WASM loader prepare bytecode failed: "
-                                  "function index out of range");
+                                  "unknown function.");
                     goto fail;
                 }
 
@@ -3888,7 +3933,7 @@ handle_next_reachable_block:
                     && module->import_table_count == 0) {
                     set_error_buf(error_buf, error_buf_size,
                                   "WASM loader prepare bytecode failed: "
-                                  "call indirect without default table");
+                                  "call indirect with unknown table");
                     goto fail;
                 }
 
@@ -3911,7 +3956,7 @@ handle_next_reachable_block:
                 if (type_idx >= module->type_count) {
                     set_error_buf(error_buf, error_buf_size,
                                   "WASM loader prepare bytecode failed: "
-                                  "function index out of range");
+                                  "unknown type");
                     goto fail;
                 }
 
@@ -3992,7 +4037,8 @@ handle_next_reachable_block:
                 if (loader_ctx->stack_cell_num <= 0) {
                     set_error_buf(error_buf, error_buf_size,
                                   "WASM loader prepare bytecode failed: "
-                                  "opcode select was found but stack was empty");
+                                  "type mismatch, opcode select was found "
+                                  "but stack was empty");
                     goto fail;
                 }
 
@@ -4175,7 +4221,7 @@ handle_next_reachable_block:
                 if (global_idx >= global_count) {
                     set_error_buf(error_buf, error_buf_size,
                                   "WASM loader prepare bytecode failed: "
-                                  "global index out of range");
+                                  "unknown global.");
                     goto fail;
                 }
 
@@ -4197,7 +4243,7 @@ handle_next_reachable_block:
                 if (global_idx >= global_count) {
                     set_error_buf(error_buf, error_buf_size,
                                   "WASM loader prepare bytecode failed: "
-                                  "global index out of range");
+                                  "unknown global.");
                     goto fail;
                 }
 

+ 1 - 1
core/iwasm/interpreter/wasm_runtime.c

@@ -753,7 +753,7 @@ wasm_instantiate(WASMModule *module,
                 for (j = 0; j < length; j++) {
                     if (table_seg->func_indexes[j] >= module_inst->function_count) {
                         set_error_buf(error_buf, error_buf_size,
-                                      "function index is overflow");
+                                      "WASM instantiate failed: unknown function");
                         wasm_deinstantiate(module_inst);
                         return NULL;
                     }