Fix loader parse block type and calculate dynamic offset for loop args (#3482)

Fix several issues in wasm loader:
- Parse a block's type index with leb int32 instead leb uint32
- Correct dst dynamic offset of loop block arguments for opcode br
  when copying the stack operands to the arguments of loop block
- Free each frame_csp's param_frame_offsets when destroy loader ctx
- Fix compilation error in wasm_mini_loader.c
- Add test cases of failed issues

This PR fixes issue #3467 and #3468.
This commit is contained in:
Wenyong Huang 2024-05-31 11:32:36 +08:00 committed by GitHub
parent 67638e24f4
commit 23e1d51587
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 139 additions and 32 deletions

View File

@ -1028,7 +1028,9 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
}
else {
frame_ip--;
read_leb_uint32(frame_ip, frame_ip_end, type_index);
read_leb_int32(frame_ip, frame_ip_end, type_index);
/* type index was checked in wasm loader */
bh_assert(type_index < comp_ctx->comp_data->type_count);
func_type =
(AOTFuncType *)comp_ctx->comp_data->types[type_index];
param_count = func_type->param_count;
@ -1048,7 +1050,9 @@ aot_compile_func(AOTCompContext *comp_ctx, uint32 func_index)
case EXT_OP_LOOP:
case EXT_OP_IF:
{
read_leb_uint32(frame_ip, frame_ip_end, type_index);
read_leb_int32(frame_ip, frame_ip_end, type_index);
/* type index was checked in wasm loader */
bh_assert(type_index < comp_ctx->comp_data->type_count);
func_type =
(AOTFuncType *)comp_ctx->comp_data->types[type_index];
param_count = func_type->param_count;

View File

@ -1510,7 +1510,9 @@ jit_compile_func(JitCompContext *cc)
case EXT_OP_LOOP:
case EXT_OP_IF:
{
read_leb_uint32(frame_ip, frame_ip_end, type_idx);
read_leb_int32(frame_ip, frame_ip_end, type_idx);
/* type index was checked in wasm loader */
bh_assert(type_idx < cc->cur_wasm_module->type_count);
func_type = cc->cur_wasm_module->types[type_idx];
param_count = func_type->param_count;
param_types = func_type->types;

View File

@ -7086,7 +7086,8 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache,
}
else {
p--;
skip_leb_uint32(p, p_end);
/* block type */
skip_leb_int32(p, p_end);
}
if (block_nested_depth
< sizeof(block_stack) / sizeof(BlockAddr)) {
@ -7101,7 +7102,7 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache,
case EXT_OP_LOOP:
case EXT_OP_IF:
/* block type */
skip_leb_uint32(p, p_end);
skip_leb_int32(p, p_end);
if (block_nested_depth
< sizeof(block_stack) / sizeof(BlockAddr)) {
block_stack[block_nested_depth].start_addr = p;
@ -7850,7 +7851,11 @@ typedef struct BranchBlock {
BranchBlockPatch *patch_list;
/* This is used to save params frame_offset of of if block */
int16 *param_frame_offsets;
/* This is used to recover dynamic offset for else branch */
/* This is used to recover the dynamic offset for else branch,
* and also to remember the start offset of dynamic space which
* stores the block arguments for loop block, so we can use it
* to copy the stack operands to the loop block's arguments in
* wasm_loader_emit_br_info for opcode br. */
uint16 start_dynamic_offset;
#endif
@ -8001,13 +8006,26 @@ static void
free_all_label_patch_lists(BranchBlock *frame_csp, uint32 csp_num)
{
BranchBlock *tmp_csp = frame_csp;
uint32 i;
for (uint32 i = 0; i < csp_num; i++) {
for (i = 0; i < csp_num; i++) {
free_label_patch_list(tmp_csp);
tmp_csp++;
}
}
static void
free_all_label_param_frame_offsets(BranchBlock *frame_csp, uint32 csp_num)
{
BranchBlock *tmp_csp = frame_csp;
uint32 i;
for (i = 0; i < csp_num; i++) {
if (tmp_csp->param_frame_offsets)
wasm_runtime_free(tmp_csp->param_frame_offsets);
tmp_csp++;
}
}
#endif /* end of WASM_ENABLE_FAST_INTERP */
#if WASM_ENABLE_GC != 0
@ -8126,6 +8144,8 @@ wasm_loader_ctx_destroy(WASMLoaderContext *ctx)
if (ctx->frame_csp_bottom) {
#if WASM_ENABLE_FAST_INTERP != 0
free_all_label_patch_lists(ctx->frame_csp_bottom, ctx->csp_num);
free_all_label_param_frame_offsets(ctx->frame_csp_bottom,
ctx->csp_num);
#endif
#if WASM_ENABLE_GC != 0
wasm_loader_clean_all_local_use_masks(ctx);
@ -9238,8 +9258,14 @@ wasm_loader_emit_br_info(WASMLoaderContext *ctx, BranchBlock *frame_csp,
emit_operand(ctx, *(int16 *)(frame_offset));
}
/* Part e */
dynamic_offset =
frame_csp->dynamic_offset + wasm_get_cell_num(types, arity);
if (frame_csp->label_type == LABEL_TYPE_LOOP)
/* Use start_dynamic_offset which was set in
copy_params_to_dynamic_space */
dynamic_offset = frame_csp->start_dynamic_offset
+ wasm_get_cell_num(types, arity);
else
dynamic_offset =
frame_csp->dynamic_offset + wasm_get_cell_num(types, arity);
if (is_br)
ctx->dynamic_offset = dynamic_offset;
for (i = (int32)arity - 1; i >= 0; i--) {
@ -10623,8 +10649,8 @@ fail:
* Part e: each param's dst offset
*/
static bool
copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block,
char *error_buf, uint32 error_buf_size)
copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, char *error_buf,
uint32 error_buf_size)
{
bool ret = false;
int16 *frame_offset = NULL;
@ -10638,6 +10664,7 @@ copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block,
uint32 param_count = block_type->u.type->param_count;
int16 condition_offset = 0;
bool disable_emit = false;
bool is_if_block = (block->label_type == LABEL_TYPE_IF ? true : false);
int16 operand_offset = 0;
uint64 size = (uint64)param_count * (sizeof(*cells) + sizeof(*src_offsets));
@ -10690,6 +10717,14 @@ copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block,
if (is_if_block)
emit_operand(loader_ctx, condition_offset);
/* Since the start offset to save the block's params and
* the start offset to save the block's results may be
* different, we remember the dynamic offset for loop block
* so that we can use it to copy the stack operands to the
* loop block's params in wasm_loader_emit_br_info. */
if (block->label_type == LABEL_TYPE_LOOP)
block->start_dynamic_offset = loader_ctx->dynamic_offset;
/* Part e) */
/* Push to dynamic space. The push will emit the dst offset. */
for (i = 0; i < param_count; i++)
@ -11062,12 +11097,12 @@ re_scan:
#endif /* end of WASM_ENABLE_GC != 0 */
}
else {
uint32 type_index;
int32 type_index;
/* Resolve the leb128 encoded type index as block type */
p--;
p_org = p - 1;
read_leb_uint32(p, p_end, type_index);
if (type_index >= module->type_count) {
read_leb_int32(p, p_end, type_index);
if ((uint32)type_index >= module->type_count) {
set_error_buf(error_buf, error_buf_size,
"unknown type");
goto fail;
@ -11171,8 +11206,8 @@ re_scan:
if (BLOCK_HAS_PARAM(block_type)) {
/* Make sure params are in dynamic space */
if (!copy_params_to_dynamic_space(
loader_ctx, false, error_buf, error_buf_size))
if (!copy_params_to_dynamic_space(loader_ctx, error_buf,
error_buf_size))
goto fail;
}
@ -11218,8 +11253,8 @@ re_scan:
/* skip the if label */
skip_label();
/* Emit a copy instruction */
if (!copy_params_to_dynamic_space(
loader_ctx, true, error_buf, error_buf_size))
if (!copy_params_to_dynamic_space(loader_ctx, error_buf,
error_buf_size))
goto fail;
/* Emit the if instruction */

View File

@ -3451,7 +3451,7 @@ wasm_loader_find_block_addr(WASMExecEnv *exec_env, BlockAddr *block_addr_cache,
case EXT_OP_LOOP:
case EXT_OP_IF:
/* block type */
skip_leb_uint32(p, p_end);
skip_leb_int32(p, p_end);
if (block_nested_depth
< sizeof(block_stack) / sizeof(BlockAddr)) {
block_stack[block_nested_depth].start_addr = p;
@ -3921,7 +3921,11 @@ typedef struct BranchBlock {
/* This is used to store available param num for if/else branch, so the else
* opcode can know how many parameters should be copied to the stack */
uint32 available_param_num;
/* This is used to recover dynamic offset for else branch */
/* This is used to recover the dynamic offset for else branch,
* and also to remember the start offset of dynamic space which
* stores the block arguments for loop block, so we can use it
* to copy the stack operands to the loop block's arguments in
* wasm_loader_emit_br_info for opcode br. */
uint16 start_dynamic_offset;
#endif
@ -4050,13 +4054,26 @@ static void
free_all_label_patch_lists(BranchBlock *frame_csp, uint32 csp_num)
{
BranchBlock *tmp_csp = frame_csp;
uint32 i;
for (uint32 i = 0; i < csp_num; i++) {
for (i = 0; i < csp_num; i++) {
free_label_patch_list(tmp_csp);
tmp_csp++;
}
}
static void
free_all_label_param_frame_offsets(BranchBlock *frame_csp, uint32 csp_num)
{
BranchBlock *tmp_csp = frame_csp;
uint32 i;
for (i = 0; i < csp_num; i++) {
if (tmp_csp->param_frame_offsets)
wasm_runtime_free(tmp_csp->param_frame_offsets);
tmp_csp++;
}
}
#endif
static bool
@ -4120,6 +4137,8 @@ wasm_loader_ctx_destroy(WASMLoaderContext *ctx)
if (ctx->frame_csp_bottom) {
#if WASM_ENABLE_FAST_INTERP != 0
free_all_label_patch_lists(ctx->frame_csp_bottom, ctx->csp_num);
free_all_label_param_frame_offsets(ctx->frame_csp_bottom,
ctx->csp_num);
#endif
wasm_runtime_free(ctx->frame_csp_bottom);
}
@ -4798,8 +4817,14 @@ wasm_loader_emit_br_info(WASMLoaderContext *ctx, BranchBlock *frame_csp,
emit_operand(ctx, *(int16 *)(frame_offset));
}
/* Part e */
dynamic_offset =
frame_csp->dynamic_offset + wasm_get_cell_num(types, arity);
if (frame_csp->label_type == LABEL_TYPE_LOOP)
/* Use start_dynamic_offset which was set in
copy_params_to_dynamic_space */
dynamic_offset = frame_csp->start_dynamic_offset
+ wasm_get_cell_num(types, arity);
else
dynamic_offset =
frame_csp->dynamic_offset + wasm_get_cell_num(types, arity);
if (is_br)
ctx->dynamic_offset = dynamic_offset;
for (i = (int32)arity - 1; i >= 0; i--) {
@ -5778,8 +5803,8 @@ fail:
* Part e: each param's dst offset
*/
static bool
copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block,
char *error_buf, uint32 error_buf_size)
copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, char *error_buf,
uint32 error_buf_size)
{
bool ret = false;
int16 *frame_offset = NULL;
@ -5793,6 +5818,7 @@ copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block,
uint32 param_count = block_type->u.type->param_count;
int16 condition_offset = 0;
bool disable_emit = false;
bool is_if_block = (block->label_type == LABEL_TYPE_IF ? true : false);
int16 operand_offset = 0;
uint64 size = (uint64)param_count * (sizeof(*cells) + sizeof(*src_offsets));
@ -5845,6 +5871,14 @@ copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block,
if (is_if_block)
emit_operand(loader_ctx, condition_offset);
/* Since the start offset to save the block's params and
* the start offset to save the block's results may be
* different, we remember the dynamic offset for loop block
* so that we can use it to copy the stack operands to the
* loop block's params in wasm_loader_emit_br_info. */
if (block->label_type == LABEL_TYPE_LOOP)
block->start_dynamic_offset = loader_ctx->dynamic_offset;
/* Part e) */
/* Push to dynamic space. The push will emit the dst offset. */
for (i = 0; i < param_count; i++)
@ -6043,11 +6077,11 @@ re_scan:
block_type.u.value_type.type = value_type;
}
else {
uint32 type_index;
int32 type_index;
/* Resolve the leb128 encoded type index as block type */
p--;
read_leb_uint32(p, p_end, type_index);
bh_assert(type_index < module->type_count);
read_leb_int32(p, p_end, type_index);
bh_assert((uint32)type_index < module->type_count);
block_type.is_value_type = false;
block_type.u.type = module->types[type_index];
#if WASM_ENABLE_FAST_INTERP == 0
@ -6134,8 +6168,8 @@ re_scan:
skip_label();
if (BLOCK_HAS_PARAM(block_type)) {
/* Make sure params are in dynamic space */
if (!copy_params_to_dynamic_space(
loader_ctx, false, error_buf, error_buf_size))
if (!copy_params_to_dynamic_space(loader_ctx, error_buf,
error_buf_size))
goto fail;
}
if (opcode == WASM_OP_LOOP) {
@ -6175,8 +6209,8 @@ re_scan:
/* skip the if label */
skip_label();
/* Emit a copy instruction */
if (!copy_params_to_dynamic_space(
loader_ctx, true, error_buf, error_buf_size))
if (!copy_params_to_dynamic_space(loader_ctx, error_buf,
error_buf_size))
goto fail;
/* Emit the if instruction */

View File

@ -1674,6 +1674,38 @@
"stdout content": "Hello from Kotlin via WASI\nCurrent 'realtime' timestamp is:",
"description": "no 'type mismatch: expect (ref null ht) but got other1 unknown type'"
}
},
{
"deprecated": false,
"ids": [
3467
],
"runtime": "iwasm-default-wasi-disabled",
"file": "tt_unreachable.wasm",
"mode": "fast-interp",
"options": "--heap-size=0 -f to_test",
"argument": "",
"expected return": {
"ret code": 1,
"stdout content": "Exception: unreachable",
"description": "no '-1.861157e+19:f32'"
}
},
{
"deprecated": false,
"ids": [
3468
],
"runtime": "iwasm-default-wasi-disabled",
"file": "i64.add.wasm",
"mode": "fast-interp",
"options": "--heap-size=0 -f to_test",
"argument": "",
"expected return": {
"ret code": 255,
"stdout content": "WASM module load failed: unknown type",
"description": "no '0x0:i64'"
}
}
]
}