wasm loader: Fix pop invalid offset count when stack top is ANY (#3516)

In wasm_loader_pop_frame_offset, when the stack is in polymorphic state
and the stack top operand is VALUE_TYPE_ANY, if we popping I64/F64
operand, we should pop one offset but not two offsets.

The issue was reported in #3513 and #3514.
This commit is contained in:
Wenyong Huang
2024-06-14 16:22:08 +08:00
committed by GitHub
parent ad5d31b9b0
commit d3e89895be
5 changed files with 83 additions and 44 deletions

View File

@ -9370,42 +9370,41 @@ wasm_loader_pop_frame_offset(WASMLoaderContext *ctx, uint8 type,
char *error_buf, uint32 error_buf_size) char *error_buf, uint32 error_buf_size)
{ {
/* if ctx->frame_csp equals ctx->frame_csp_bottom, /* if ctx->frame_csp equals ctx->frame_csp_bottom,
then current block is the function block */ then current block is the function block */
uint32 depth = ctx->frame_csp > ctx->frame_csp_bottom ? 1 : 0; uint32 depth = ctx->frame_csp > ctx->frame_csp_bottom ? 1 : 0;
BranchBlock *cur_block = ctx->frame_csp - depth; BranchBlock *cur_block = ctx->frame_csp - depth;
int32 available_stack_cell = int32 available_stack_cell =
(int32)(ctx->stack_cell_num - cur_block->stack_cell_num); (int32)(ctx->stack_cell_num - cur_block->stack_cell_num);
uint32 cell_num_to_pop;
/* Directly return success if current block is in stack /* Directly return success if current block is in stack
* polymorphic state while stack is empty. */ polymorphic state while stack is empty. */
if (available_stack_cell <= 0 && cur_block->is_stack_polymorphic) if (available_stack_cell <= 0 && cur_block->is_stack_polymorphic)
return true; return true;
if (type == VALUE_TYPE_VOID) if (type == VALUE_TYPE_VOID)
return true; return true;
if (is_32bit_type(type)) { /* Change type to ANY when the stack top is ANY, so as to avoid
/* Check the offset stack bottom to ensure the frame offset popping unneeded offsets, e.g. if type is I64/F64, we may pop
stack will not go underflow. But we don't thrown error two offsets */
and return true here, because the error msg should be if (available_stack_cell > 0 && *(ctx->frame_ref - 1) == VALUE_TYPE_ANY)
given in wasm_loader_pop_frame_ref */ type = VALUE_TYPE_ANY;
if (!check_offset_pop(ctx, 1))
return true;
ctx->frame_offset -= 1; cell_num_to_pop = wasm_value_type_cell_num(type);
if ((*(ctx->frame_offset) > ctx->start_dynamic_offset)
&& (*(ctx->frame_offset) < ctx->max_dynamic_offset)) /* Check the offset stack bottom to ensure the frame offset
ctx->dynamic_offset -= 1; stack will not go underflow. But we don't thrown error
} and return true here, because the error msg should be
else { given in wasm_loader_pop_frame_ref */
if (!check_offset_pop(ctx, 2)) if (!check_offset_pop(ctx, cell_num_to_pop))
return true; return true;
ctx->frame_offset -= cell_num_to_pop;
if ((*(ctx->frame_offset) > ctx->start_dynamic_offset)
&& (*(ctx->frame_offset) < ctx->max_dynamic_offset))
ctx->dynamic_offset -= cell_num_to_pop;
ctx->frame_offset -= 2;
if ((*(ctx->frame_offset) > ctx->start_dynamic_offset)
&& (*(ctx->frame_offset) < ctx->max_dynamic_offset))
ctx->dynamic_offset -= 2;
}
emit_operand(ctx, *(ctx->frame_offset)); emit_operand(ctx, *(ctx->frame_offset));
(void)error_buf; (void)error_buf;
@ -10893,6 +10892,12 @@ wasm_loader_get_custom_section(WASMModule *module, const char *name,
} }
#endif #endif
#if 0
#define HANDLE_OPCODE(opcode) #opcode
DEFINE_GOTO_TABLE(const char *, op_mnemonics);
#undef HANDLE_OPCODE
#endif
static bool static bool
wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func, wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
uint32 cur_func_idx, char *error_buf, uint32 cur_func_idx, char *error_buf,

View File

@ -4924,43 +4924,45 @@ wasm_loader_pop_frame_offset(WASMLoaderContext *ctx, uint8 type,
char *error_buf, uint32 error_buf_size) char *error_buf, uint32 error_buf_size)
{ {
/* if ctx->frame_csp equals ctx->frame_csp_bottom, /* if ctx->frame_csp equals ctx->frame_csp_bottom,
then current block is the function block */ then current block is the function block */
uint32 depth = ctx->frame_csp > ctx->frame_csp_bottom ? 1 : 0; uint32 depth = ctx->frame_csp > ctx->frame_csp_bottom ? 1 : 0;
BranchBlock *cur_block = ctx->frame_csp - depth; BranchBlock *cur_block = ctx->frame_csp - depth;
int32 available_stack_cell = int32 available_stack_cell =
(int32)(ctx->stack_cell_num - cur_block->stack_cell_num); (int32)(ctx->stack_cell_num - cur_block->stack_cell_num);
uint32 cell_num_to_pop;
/* Directly return success if current block is in stack /* Directly return success if current block is in stack
* polymorphic state while stack is empty. */ polymorphic state while stack is empty. */
if (available_stack_cell <= 0 && cur_block->is_stack_polymorphic) if (available_stack_cell <= 0 && cur_block->is_stack_polymorphic)
return true; return true;
if (type == VALUE_TYPE_VOID) if (type == VALUE_TYPE_VOID)
return true; return true;
if (is_32bit_type(type)) { /* Change type to ANY when the stack top is ANY, so as to avoid
/* Check the offset stack bottom to ensure the frame offset popping unneeded offsets, e.g. if type is I64/F64, we may pop
stack will not go underflow. But we don't thrown error two offsets */
and return true here, because the error msg should be if (available_stack_cell > 0 && *(ctx->frame_ref - 1) == VALUE_TYPE_ANY)
given in wasm_loader_pop_frame_ref */ type = VALUE_TYPE_ANY;
if (!check_offset_pop(ctx, 1))
return true;
ctx->frame_offset -= 1; cell_num_to_pop = wasm_value_type_cell_num(type);
if ((*(ctx->frame_offset) > ctx->start_dynamic_offset)
&& (*(ctx->frame_offset) < ctx->max_dynamic_offset)) /* Check the offset stack bottom to ensure the frame offset
ctx->dynamic_offset -= 1; stack will not go underflow. But we don't thrown error
} and return true here, because the error msg should be
else { given in wasm_loader_pop_frame_ref */
if (!check_offset_pop(ctx, 2)) if (!check_offset_pop(ctx, cell_num_to_pop))
return true; return true;
ctx->frame_offset -= cell_num_to_pop;
if ((*(ctx->frame_offset) > ctx->start_dynamic_offset)
&& (*(ctx->frame_offset) < ctx->max_dynamic_offset))
ctx->dynamic_offset -= cell_num_to_pop;
ctx->frame_offset -= 2;
if ((*(ctx->frame_offset) > ctx->start_dynamic_offset)
&& (*(ctx->frame_offset) < ctx->max_dynamic_offset))
ctx->dynamic_offset -= 2;
}
emit_operand(ctx, *(ctx->frame_offset)); emit_operand(ctx, *(ctx->frame_offset));
(void)error_buf;
(void)error_buf_size;
return true; return true;
} }

View File

@ -1722,6 +1722,38 @@
"stdout content": "WASM module load failed: data count and data section have inconsistent lengths", "stdout content": "WASM module load failed: data count and data section have inconsistent lengths",
"description": "Check data segment count" "description": "Check data segment count"
} }
},
{
"deprecated": false,
"ids": [
3513
],
"runtime": "iwasm-default-wasi-disabled",
"file": "iwasm_poc_04.wasm",
"mode": "fast-interp",
"options": "-f main",
"argument": "",
"expected return": {
"ret code": 0,
"stdout content": "",
"description": "no sanitizer 'heap-buffer-overflow'"
}
},
{
"deprecated": false,
"ids": [
3514
],
"runtime": "iwasm-default-wasi-disabled",
"file": "iwasm_poc_05.wasm",
"mode": "fast-interp",
"options": "-f main",
"argument": "",
"expected return": {
"ret code": 0,
"stdout content": "",
"description": "no sanitizer 'heap-buffer-overflow'"
}
} }
] ]
} }