Refactor app heap and memory boundary check, and fix os_printf compilation error (#356)

Insert app heap before __heap_base, or before new page
Fix os_printf compilation error in some platforms
This commit is contained in:
Wenyong Huang
2020-08-20 12:43:12 +08:00
committed by GitHub
parent 6b5f376e79
commit 89d2937cde
28 changed files with 1311 additions and 648 deletions

View File

@ -52,14 +52,14 @@ check_buf1(const uint8 *buf, const uint8 *buf_end, uint32 length,
#define CHECK_BUF(buf, buf_end, length) do { \
if (!check_buf(buf, buf_end, length, \
error_buf, error_buf_size)) { \
return false; \
goto fail; \
} \
} while (0)
#define CHECK_BUF1(buf, buf_end, length) do { \
if (!check_buf1(buf, buf_end, length, \
error_buf, error_buf_size)) { \
return false; \
goto fail; \
} \
} while (0)
@ -90,6 +90,8 @@ skip_leb(const uint8 **p_buf, const uint8 *buf_end, uint32 maxbits,
*p_buf += offset;
return true;
fail:
return false;
}
#define skip_leb_int64(p, p_end) do { \
@ -184,6 +186,7 @@ read_leb(uint8 **p_buf, const uint8 *buf_end,
fail_integer_too_large:
set_error_buf(error_buf, error_buf_size,
"WASM module load failed: integer too large");
fail:
return false;
}
@ -195,7 +198,7 @@ fail_integer_too_large:
uint64 res64; \
if (!read_leb((uint8**)&p, p_end, 64, true, &res64,\
error_buf, error_buf_size)) \
return false; \
goto fail; \
res = (int64)res64; \
} while (0)
@ -203,7 +206,7 @@ fail_integer_too_large:
uint64 res64; \
if (!read_leb((uint8**)&p, p_end, 32, false, &res64,\
error_buf, error_buf_size)) \
return false; \
goto fail; \
res = (uint32)res64; \
} while (0)
@ -211,7 +214,7 @@ fail_integer_too_large:
uint64 res64; \
if (!read_leb((uint8**)&p, p_end, 32, true, &res64,\
error_buf, error_buf_size)) \
return false; \
goto fail; \
res = (int32)res64; \
} while (0)
@ -335,19 +338,19 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end,
/* i32.const */
case INIT_EXPR_TYPE_I32_CONST:
if (type != VALUE_TYPE_I32)
goto fail;
goto fail_type_mismatch;
read_leb_int32(p, p_end, init_expr->u.i32);
break;
/* i64.const */
case INIT_EXPR_TYPE_I64_CONST:
if (type != VALUE_TYPE_I64)
goto fail;
goto fail_type_mismatch;
read_leb_int64(p, p_end, init_expr->u.i64);
break;
/* f32.const */
case INIT_EXPR_TYPE_F32_CONST:
if (type != VALUE_TYPE_F32)
goto fail;
goto fail_type_mismatch;
CHECK_BUF(p, p_end, 4);
p_float = (uint8*)&init_expr->u.f32;
for (i = 0; i < sizeof(float32); i++)
@ -356,7 +359,7 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end,
/* f64.const */
case INIT_EXPR_TYPE_F64_CONST:
if (type != VALUE_TYPE_F64)
goto fail;
goto fail_type_mismatch;
CHECK_BUF(p, p_end, 8);
p_float = (uint8*)&init_expr->u.f64;
for (i = 0; i < sizeof(float64); i++)
@ -367,19 +370,20 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end,
read_leb_uint32(p, p_end, init_expr->u.global_index);
break;
default:
goto fail;
goto fail_type_mismatch;
}
CHECK_BUF(p, p_end, 1);
end_byte = read_uint8(p);
if (end_byte != 0x0b)
goto fail;
goto fail_type_mismatch;
*p_buf = p;
return true;
fail:
fail_type_mismatch:
set_error_buf(error_buf, error_buf_size,
"WASM module load failed: type mismatch or "
"constant expression required.");
fail:
return false;
}
@ -472,6 +476,8 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
LOG_VERBOSE("Load type section success.\n");
return true;
fail:
return false;
}
#if WASM_ENABLE_MULTI_MODULE != 0
@ -804,6 +810,8 @@ load_function_import(const WASMModule *parent_module, WASMModule *sub_module,
function->import_func_linked = is_built_in_module ? NULL : linked_func;
#endif
return true;
fail:
return false;
}
static bool
@ -905,6 +913,8 @@ load_table_import(WASMModule *sub_module, const char *sub_module_name,
table->flags = declare_max_size_flag;
table->max_size = declare_max_size;
return true;
fail:
return false;
}
unsigned
@ -1034,6 +1044,8 @@ load_memory_import(WASMModule *sub_module, const char *sub_module_name,
*p_buf = p;
return true;
fail:
return false;
}
static bool
@ -1107,13 +1119,15 @@ load_global_import(const WASMModule *parent_module,
global->type = declare_type;
global->is_mutable = is_mutable;
return true;
fail:
return false;
}
static bool
load_table(const uint8 **p_buf, const uint8 *buf_end, WASMTable *table,
char *error_buf, uint32 error_buf_size)
{
const uint8 *p = *p_buf, *p_end = buf_end;
const uint8 *p = *p_buf, *p_end = buf_end, *p_org;
CHECK_BUF(p, p_end, 1);
/* 0x70 */
@ -1123,32 +1137,40 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMTable *table,
return false;
}
p_org = p;
read_leb_uint32(p, p_end, table->flags);
if (p - p_org > 1) {
set_error_buf(error_buf, error_buf_size,
"integer representation too long");
return false;
}
if (table->flags > 1) {
set_error_buf(error_buf, error_buf_size, "integer too large");
return false;
}
read_leb_uint32(p, p_end, table->init_size);
if (table->flags & 1) {
if (table->flags == 0) {
table->max_size = 0x10000;
}
else if (table->flags == 1) {
read_leb_uint32(p, p_end, table->max_size);
if (!check_table_max_size(table->init_size, table->max_size,
error_buf, error_buf_size))
return false;
}
else
table->max_size = 0x10000;
if ((table->flags & 1) && table->init_size > table->max_size) {
set_error_buf(error_buf, error_buf_size,
"size minimum must not be greater than maximum");
return false;
}
*p_buf = p;
return true;
fail:
return false;
}
static bool
load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory,
char *error_buf, uint32 error_buf_size)
{
const uint8 *p = *p_buf, *p_end = buf_end;
const uint8 *p = *p_buf, *p_end = buf_end, *p_org;
uint32 pool_size = wasm_runtime_memory_pool_size();
#if WASM_ENABLE_APP_FRAMEWORK != 0
uint32 max_page_count = pool_size * APP_MEMORY_MAX_GLOBAL_HEAP_PERCENT
@ -1157,7 +1179,25 @@ load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory,
uint32 max_page_count = pool_size / DEFAULT_NUM_BYTES_PER_PAGE;
#endif
p_org = p;
read_leb_uint32(p, p_end, memory->flags);
if (p - p_org > 1) {
set_error_buf(error_buf, error_buf_size,
"integer representation too long");
return false;
}
#if WASM_ENABLE_SHARED_MEMORY == 0
if (memory->flags > 1) {
set_error_buf(error_buf, error_buf_size, "integer too large");
return false;
}
#else
if (memory->flags > 3 || memory->flags == 2) {
set_error_buf(error_buf, error_buf_size, "integer too large");
return false;
}
#endif
read_leb_uint32(p, p_end, memory->init_page_count);
if (!check_memory_init_size(memory->init_page_count,
error_buf, error_buf_size))
@ -1172,14 +1212,17 @@ load_memory(const uint8 **p_buf, const uint8 *buf_end, WASMMemory *memory,
if (memory->max_page_count > max_page_count)
memory->max_page_count = max_page_count;
}
else
else {
/* Limit the maximum memory size to max_page_count */
memory->max_page_count = max_page_count;
}
memory->num_bytes_per_page = DEFAULT_NUM_BYTES_PER_PAGE;
*p_buf = p;
return true;
fail:
return false;
}
#if WASM_ENABLE_MULTI_MODULE != 0
@ -1434,7 +1477,7 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
default:
set_error_buf(error_buf, error_buf_size,
"Load import section failed: invalid import type.");
"Load import section failed: invalid import kind");
return false;
}
}
@ -1454,7 +1497,7 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
p = p_old;
// TODO: move it out of the loop
/* TODO: move it out of the loop */
/* insert "env", "wasi_unstable" and "wasi_snapshot_preview1" to const str list */
if (!const_str_list_insert((uint8*)"env", 3, module, error_buf, error_buf_size)
|| !const_str_list_insert((uint8*)"wasi_unstable", 13, module,
@ -1566,7 +1609,7 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
default:
set_error_buf(error_buf, error_buf_size,
"Load import section failed: "
"invalid import type.");
"invalid import kind");
return false;
}
import->kind = kind;
@ -1598,6 +1641,8 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
(void)u32;
(void)type_index;
return true;
fail:
return false;
}
static bool
@ -1779,6 +1824,8 @@ load_function_section(const uint8 *buf, const uint8 *buf_end,
LOG_VERBOSE("Load function section success.\n");
return true;
fail:
return false;
}
static bool
@ -1820,6 +1867,8 @@ load_table_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
LOG_VERBOSE("Load table section success.\n");
return true;
fail:
return false;
}
static bool
@ -1861,6 +1910,8 @@ load_memory_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
LOG_VERBOSE("Load memory section success.\n");
return true;
fail:
return false;
}
static bool
@ -1926,6 +1977,8 @@ load_global_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
LOG_VERBOSE("Load global section success.\n");
return true;
fail:
return false;
}
static bool
@ -2029,6 +2082,8 @@ load_export_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
LOG_VERBOSE("Load export section success.\n");
return true;
fail:
return false;
}
static bool
@ -2102,6 +2157,8 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end, WASMModule *m
LOG_VERBOSE("Load table segment section success.\n");
return true;
fail:
return false;
}
static bool
@ -2217,6 +2274,8 @@ check_mem_index:
LOG_VERBOSE("Load data segment section success.\n");
return true;
fail:
return false;
}
#if WASM_ENABLE_BULK_MEMORY != 0
@ -2238,6 +2297,8 @@ load_datacount_section(const uint8 *buf, const uint8 *buf_end, WASMModule *modul
LOG_VERBOSE("Load datacount section success.\n");
return true;
fail:
return false;
}
#endif
@ -2268,6 +2329,8 @@ load_code_section(const uint8 *buf, const uint8 *buf_end,
LOG_VERBOSE("Load code segment section success.\n");
return true;
fail:
return false;
}
static bool
@ -2311,6 +2374,8 @@ load_start_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
LOG_VERBOSE("Load start section success.\n");
return true;
fail:
return false;
}
static bool
@ -2344,6 +2409,8 @@ load_user_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
LOG_VERBOSE("Load custom section success.\n");
return true;
fail:
return false;
}
@ -2367,12 +2434,14 @@ load_from_sections(WASMModule *module, WASMSection *sections,
WASMSection *section = sections;
const uint8 *buf, *buf_end, *buf_code = NULL, *buf_code_end = NULL,
*buf_func = NULL, *buf_func_end = NULL;
WASMGlobal *llvm_data_end_global = NULL, *llvm_heap_base_global = NULL;
WASMGlobal *llvm_stack_top_global = NULL, *global;
uint32 llvm_data_end = UINT32_MAX, llvm_heap_base = UINT32_MAX;
uint32 llvm_stack_top = UINT32_MAX, global_index, i;
uint32 stack_top_global_index = UINT32_MAX;
WASMGlobal *aux_data_end_global = NULL, *aux_heap_base_global = NULL;
WASMGlobal *aux_stack_top_global = NULL, *global;
uint32 aux_data_end = (uint32)-1, aux_heap_base = (uint32)-1;
uint32 aux_stack_top = (uint32)-1, global_index, func_index, i;
uint32 aux_data_end_global_index = (uint32)-1;
uint32 aux_heap_base_global_index = (uint32)-1;
BlockAddr *block_addr_cache;
WASMType *func_type;
uint64 total_size;
/* Find code and function sections if have */
@ -2481,7 +2550,11 @@ load_from_sections(WASMModule *module, WASMSection *sections,
}
wasm_runtime_free(block_addr_cache);
/* Resolve llvm auxiliary data/stack/heap info and reset memory info */
module->aux_data_end_global_index = (uint32)-1;
module->aux_heap_base_global_index = (uint32)-1;
module->aux_stack_top_global_index = (uint32)-1;
/* Resolve auxiliary data/stack/heap info and reset memory info */
export = module->exports;
for (i = 0; i < module->export_count; i++, export++) {
if (export->kind == EXPORT_KIND_GLOBAL) {
@ -2492,10 +2565,11 @@ load_from_sections(WASMModule *module, WASMSection *sections,
&& !global->is_mutable
&& global->init_expr.init_expr_type ==
INIT_EXPR_TYPE_I32_CONST) {
llvm_heap_base_global = global;
llvm_heap_base = global->init_expr.u.i32;
LOG_VERBOSE("found llvm __heap_base global, value: %d\n",
llvm_heap_base);
aux_heap_base_global = global;
aux_heap_base = global->init_expr.u.i32;
aux_heap_base_global_index = export->index;
LOG_VERBOSE("Found aux __heap_base global, value: %d",
aux_heap_base);
}
}
else if (!strcmp(export->name, "__data_end")) {
@ -2505,12 +2579,13 @@ load_from_sections(WASMModule *module, WASMSection *sections,
&& !global->is_mutable
&& global->init_expr.init_expr_type ==
INIT_EXPR_TYPE_I32_CONST) {
llvm_data_end_global = global;
llvm_data_end = global->init_expr.u.i32;
LOG_VERBOSE("found llvm __data_end global, value: %d\n",
llvm_data_end);
aux_data_end_global = global;
aux_data_end = global->init_expr.u.i32;
aux_data_end_global_index = export->index;
LOG_VERBOSE("Found aux __data_end global, value: %d",
aux_data_end);
llvm_data_end = align_uint(llvm_data_end, 16);
aux_data_end = align_uint(aux_data_end, 16);
}
}
@ -2530,64 +2605,97 @@ load_from_sections(WASMModule *module, WASMSection *sections,
[3] heap_base <-- 3
[4] dso_handle
*/
if (llvm_data_end_global && llvm_heap_base_global) {
if (aux_data_end_global && aux_heap_base_global
&& aux_data_end <= aux_heap_base) {
module->aux_data_end_global_index = aux_data_end_global_index;
module->aux_data_end = aux_data_end;
module->aux_heap_base_global_index = aux_heap_base_global_index;
module->aux_heap_base = aux_heap_base;
/* Resolve aux stack top global */
for (global_index = 0; global_index < module->global_count; global_index++) {
for (global_index = 0; global_index < module->global_count;
global_index++) {
global = module->globals + global_index;
if (global != llvm_data_end_global
&& global != llvm_heap_base_global
if (global->is_mutable /* heap_base and data_end is
not mutable */
&& global->type == VALUE_TYPE_I32
&& global->is_mutable
&& global->init_expr.init_expr_type ==
INIT_EXPR_TYPE_I32_CONST
&& (global->init_expr.u.i32 <=
llvm_heap_base_global->init_expr.u.i32
&& llvm_data_end_global->init_expr.u.i32 <=
llvm_heap_base_global->init_expr.u.i32)) {
llvm_stack_top_global = global;
llvm_stack_top = global->init_expr.u.i32;
stack_top_global_index = global_index;
LOG_VERBOSE("found llvm stack top global, "
"value: %d, global index: %d\n",
llvm_stack_top, global_index);
&& (uint32)global->init_expr.u.i32 <= aux_heap_base) {
aux_stack_top_global = global;
aux_stack_top = (uint32)global->init_expr.u.i32;
module->aux_stack_top_global_index =
module->import_global_count + global_index;
module->aux_stack_bottom = aux_stack_top;
module->aux_stack_size = aux_stack_top > aux_data_end
? aux_stack_top - aux_data_end
: aux_stack_top;
LOG_VERBOSE("Found aux stack top global, value: %d, "
"global index: %d, stack size: %d",
aux_stack_top, global_index,
module->aux_stack_size);
break;
}
}
module->llvm_aux_data_end = llvm_data_end;
module->llvm_aux_stack_bottom = llvm_stack_top;
module->llvm_aux_stack_size = llvm_stack_top > llvm_data_end
? llvm_stack_top - llvm_data_end
: llvm_stack_top;
module->llvm_aux_stack_global_index = stack_top_global_index;
LOG_VERBOSE("aux stack bottom: %d, size: %d\n",
module->llvm_aux_stack_bottom,
module->llvm_aux_stack_size);
break;
}
}
}
module->malloc_function = (uint32)-1;
module->free_function = (uint32)-1;
/* Resolve auxiliary data/stack/heap info and reset memory info */
export = module->exports;
for (i = 0; i < module->export_count; i++, export++) {
if (export->kind == EXPORT_KIND_FUNC) {
if (!strcmp(export->name, "malloc")
&& export->index >= module->import_function_count) {
func_index = export->index - module->import_function_count;
func_type = module->functions[func_index]->func_type;
if (func_type->param_count == 1
&& func_type->result_count == 1
&& func_type->types[0] == VALUE_TYPE_I32
&& func_type->types[1] == VALUE_TYPE_I32) {
module->malloc_function = export->index;
LOG_VERBOSE("Found malloc function, index: %u",
export->index);
}
}
else if (!strcmp(export->name, "free")
&& export->index >= module->import_function_count) {
func_index = export->index - module->import_function_count;
func_type = module->functions[func_index]->func_type;
if (func_type->param_count == 1
&& func_type->result_count == 0
&& func_type->types[0] == VALUE_TYPE_I32) {
module->free_function = export->index;
LOG_VERBOSE("Found free function, index: %u",
export->index);
}
}
}
}
if (!module->possible_memory_grow) {
if (llvm_data_end_global
&& llvm_heap_base_global
&& llvm_stack_top_global
&& llvm_stack_top <= llvm_heap_base) {
WASMMemoryImport *memory_import;
WASMMemory *memory;
WASMMemoryImport *memory_import;
WASMMemory *memory;
if (aux_data_end_global
&& aux_heap_base_global
&& aux_stack_top_global) {
uint64 init_memory_size;
uint32 shrunk_memory_size = llvm_heap_base > llvm_data_end
? llvm_heap_base : llvm_data_end;
uint32 shrunk_memory_size = align_uint(aux_heap_base, 8);
if (module->import_memory_count) {
memory_import = &module->import_memories[0].u.memory;
init_memory_size = (uint64)memory_import->num_bytes_per_page *
memory_import->init_page_count;
if (llvm_heap_base <= init_memory_size
&& llvm_data_end <= init_memory_size) {
if (shrunk_memory_size <= init_memory_size) {
/* Reset memory info to decrease memory usage */
memory_import->num_bytes_per_page = shrunk_memory_size;
memory_import->init_page_count = 1;
LOG_VERBOSE("reset import memory size to %d\n",
LOG_VERBOSE("Shrink import memory size to %d",
shrunk_memory_size);
}
}
@ -2595,15 +2703,31 @@ load_from_sections(WASMModule *module, WASMSection *sections,
memory = &module->memories[0];
init_memory_size = (uint64)memory->num_bytes_per_page *
memory->init_page_count;
if (llvm_heap_base <= init_memory_size
&& llvm_data_end <= init_memory_size) {
if (shrunk_memory_size <= init_memory_size) {
/* Reset memory info to decrease memory usage */
memory->num_bytes_per_page = shrunk_memory_size;
memory->init_page_count = 1;
LOG_VERBOSE("reset memory size to %d\n", shrunk_memory_size);
LOG_VERBOSE("Shrink memory size to %d", shrunk_memory_size);
}
}
}
#if WASM_ENABLE_MULTI_MODULE == 0
if (module->import_memory_count) {
memory_import = &module->import_memories[0].u.memory;
/* Memory init page count cannot be larger than 65536, we don't
check integer overflow again. */
memory_import->num_bytes_per_page *= memory_import->init_page_count;
memory_import->init_page_count = memory_import->max_page_count = 1;
}
if (module->memory_count) {
/* Memory init page count cannot be larger than 65536, we don't
check integer overflow again. */
memory = &module->memories[0];
memory->num_bytes_per_page *= memory->init_page_count;
memory->init_page_count = memory->max_page_count = 1;
}
#endif
}
return true;
@ -2759,6 +2883,8 @@ create_sections(const uint8 *buf, uint32 size,
}
return true;
fail:
return false;
}
static void
@ -2819,6 +2945,8 @@ load(const uint8 *buf, uint32 size, WASMModule *module,
destroy_sections(section_list);
return true;
fail:
return false;
}
WASMModule*
@ -2834,7 +2962,7 @@ wasm_loader_load(const uint8 *buf, uint32 size, char *error_buf, uint32 error_bu
goto fail;
}
LOG_VERBOSE("Load module success");
LOG_VERBOSE("Load module success.\n");
return module;
fail:
@ -3275,8 +3403,11 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache,
break;
case WASM_OP_MISC_PREFIX:
{
opcode = read_uint8(p);
switch (opcode) {
uint32 opcode1;
read_leb_uint32(p, p_end, opcode1);
switch (opcode1) {
case WASM_OP_I32_TRUNC_SAT_S_F32:
case WASM_OP_I32_TRUNC_SAT_U_F32:
case WASM_OP_I32_TRUNC_SAT_S_F64:
@ -3340,6 +3471,8 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache,
(void)u8;
return false;
fail:
return false;
}
#define REF_I32 VALUE_TYPE_I32
@ -6032,8 +6165,8 @@ handle_op_block_and_loop:
|| global_type == VALUE_TYPE_F64) {
*p_org = WASM_OP_SET_GLOBAL_64;
}
else if (module->llvm_aux_stack_size > 0
&& global_idx == module->llvm_aux_stack_global_index) {
else if (module->aux_stack_size > 0
&& global_idx == module->aux_stack_top_global_index) {
*p_org = WASM_OP_SET_GLOBAL_AUX_STACK;
}
#endif
@ -6043,8 +6176,8 @@ handle_op_block_and_loop:
skip_label();
emit_label(WASM_OP_SET_GLOBAL_64);
}
else if (module->llvm_aux_stack_size > 0
&& global_idx == module->llvm_aux_stack_global_index) {
else if (module->aux_stack_size > 0
&& global_idx == module->aux_stack_top_global_index) {
skip_label();
emit_label(WASM_OP_SET_GLOBAL_AUX_STACK);
}
@ -6462,11 +6595,13 @@ handle_op_block_and_loop:
case WASM_OP_MISC_PREFIX:
{
opcode = read_uint8(p);
uint32 opcode1;
read_leb_uint32(p, p_end, opcode1);
#if WASM_ENABLE_FAST_INTERP != 0
emit_byte(loader_ctx, opcode);
emit_byte(loader_ctx, ((uint8)opcode1));
#endif
switch (opcode)
switch (opcode1)
{
case WASM_OP_I32_TRUNC_SAT_S_F32:
case WASM_OP_I32_TRUNC_SAT_U_F32:
@ -6574,7 +6709,7 @@ fail_data_cnt_sec_require:
if (error_buf != NULL)
snprintf(error_buf, error_buf_size,
"WASM module load failed: "
"invalid opcode 0xfc %02x.", opcode);
"invalid opcode 0xfc %02x.", opcode1);
goto fail;
break;
}