Fix wasm loader handling opcode br_table (#3176)

Fix the errors reported in the sanitizer test of nightly run CI.
When the stack is in polymorphic state, the stack operands may be changed
after pop and push operations (e.g. stack is empty but pop op can succeed
in polymorphic, and the push op can push a new operand to stack), this may
impact the following checks to other target blocks of the br_table opcode.
This commit is contained in:
Wenyong Huang 2024-02-23 14:56:20 +08:00 committed by GitHub
parent 88bfbcf89e
commit 169e164815
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 251 additions and 38 deletions

View File

@ -9713,13 +9713,6 @@ fail:
GET_LOCAL_REFTYPE(); \
} while (0)
#define CHECK_BR(depth) \
do { \
if (!wasm_loader_check_br(loader_ctx, depth, error_buf, \
error_buf_size)) \
goto fail; \
} while (0)
static bool
check_memory(WASMModule *module, char *error_buf, uint32 error_buf_size)
{
@ -9920,6 +9913,27 @@ wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth,
bool is_type_multi_byte;
#endif
uint8 *frame_ref_old = loader_ctx->frame_ref;
uint8 *frame_ref_after_popped = NULL;
uint8 frame_ref_tmp[4] = { 0 };
uint8 *frame_ref_buf = frame_ref_tmp;
uint32 stack_cell_num_old = loader_ctx->stack_cell_num;
#if WASM_ENABLE_GC != 0
WASMRefTypeMap *frame_reftype_map_old = loader_ctx->frame_reftype_map;
WASMRefTypeMap *frame_reftype_map_after_popped = NULL;
WASMRefTypeMap frame_reftype_map_tmp[4] = { 0 };
WASMRefTypeMap *frame_reftype_map_buf = frame_reftype_map_tmp;
uint32 reftype_map_num_old = loader_ctx->reftype_map_num;
#endif
#if WASM_ENABLE_FAST_INTERP != 0
int16 *frame_offset_old = loader_ctx->frame_offset;
int16 *frame_offset_after_popped = NULL;
int16 frame_offset_tmp[4] = { 0 };
int16 *frame_offset_buf = frame_offset_tmp;
uint16 dynamic_offset_old = (loader_ctx->frame_csp - 1)->dynamic_offset;
#endif
bool ret = false;
bh_assert(loader_ctx->csp_num > 0);
if (loader_ctx->csp_num - 1 < depth) {
set_error_buf(error_buf, error_buf_size,
@ -9956,7 +9970,7 @@ wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth,
/* If the stack is in polymorphic state, just clear the stack
* and then re-push the values to make the stack top values
* match block type. */
if (cur_block->is_stack_polymorphic && !is_br_table) {
if (cur_block->is_stack_polymorphic) {
#if WASM_ENABLE_GC != 0
int32 j = reftype_map_count - 1;
#endif
@ -9975,6 +9989,52 @@ wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth,
#endif
POP_TYPE(types[i]);
}
/* Backup stack data since it may be changed in the below
push operations, and the stack data may be used when
checking other target blocks of opcode br_table */
if (is_br_table) {
uint64 total_size;
frame_ref_after_popped = loader_ctx->frame_ref;
total_size = (uint64)sizeof(uint8)
* (frame_ref_old - frame_ref_after_popped);
if (total_size > sizeof(frame_ref_tmp)
&& !(frame_ref_buf = loader_malloc(total_size, error_buf,
error_buf_size))) {
goto fail;
}
bh_memcpy_s(frame_ref_buf, (uint32)total_size,
frame_ref_after_popped, (uint32)total_size);
#if WASM_ENABLE_GC != 0
frame_reftype_map_after_popped = loader_ctx->frame_reftype_map;
total_size =
(uint64)sizeof(WASMRefTypeMap)
* (frame_reftype_map_old - frame_reftype_map_after_popped);
if (total_size > sizeof(frame_reftype_map_tmp)
&& !(frame_reftype_map_buf = loader_malloc(
total_size, error_buf, error_buf_size))) {
goto fail;
}
bh_memcpy_s(frame_reftype_map_buf, (uint32)total_size,
frame_reftype_map_after_popped, (uint32)total_size);
#endif
#if WASM_ENABLE_FAST_INTERP != 0
frame_offset_after_popped = loader_ctx->frame_offset;
total_size = (uint64)sizeof(int16)
* (frame_offset_old - frame_offset_after_popped);
if (total_size > sizeof(frame_offset_tmp)
&& !(frame_offset_buf = loader_malloc(total_size, error_buf,
error_buf_size))) {
goto fail;
}
bh_memcpy_s(frame_offset_buf, (uint32)total_size,
frame_offset_after_popped, (uint32)total_size);
#endif
}
#if WASM_ENABLE_GC != 0
j = 0;
#endif
@ -9995,7 +10055,55 @@ wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth,
#endif
PUSH_TYPE(types[i]);
}
return true;
#if WASM_ENABLE_FAST_INTERP != 0
emit_br_info(target_block);
#endif
/* Restore the stack data, note that frame_ref_bottom,
frame_reftype_map_bottom, frame_offset_bottom may be
re-allocated in the above push operations */
if (is_br_table) {
uint32 total_size;
/* The stack operand num should not be smaller than before
after pop and push operations */
bh_assert(loader_ctx->stack_cell_num >= stack_cell_num_old);
loader_ctx->stack_cell_num = stack_cell_num_old;
loader_ctx->frame_ref =
loader_ctx->frame_ref_bottom + stack_cell_num_old;
total_size = (uint32)sizeof(uint8)
* (frame_ref_old - frame_ref_after_popped);
bh_memcpy_s((uint8 *)loader_ctx->frame_ref - total_size, total_size,
frame_ref_buf, total_size);
#if WASM_ENABLE_GC != 0
/* The stack operand num should not be smaller than before
after pop and push operations */
bh_assert(loader_ctx->reftype_map_num >= reftype_map_num_old);
loader_ctx->reftype_map_num = reftype_map_num_old;
loader_ctx->frame_reftype_map =
loader_ctx->frame_reftype_map_bottom + reftype_map_num_old;
total_size =
(uint32)sizeof(WASMRefTypeMap)
* (frame_reftype_map_old - frame_reftype_map_after_popped);
bh_memcpy_s((uint8 *)loader_ctx->frame_reftype_map - total_size,
total_size, frame_reftype_map_buf, total_size);
#endif
#if WASM_ENABLE_FAST_INTERP != 0
loader_ctx->frame_offset =
loader_ctx->frame_offset_bottom + stack_cell_num_old;
total_size = (uint32)sizeof(int16)
* (frame_offset_old - frame_offset_after_popped);
bh_memcpy_s((uint8 *)loader_ctx->frame_offset - total_size,
total_size, frame_offset_buf, total_size);
(loader_ctx->frame_csp - 1)->dynamic_offset = dynamic_offset_old;
#endif
}
ret = true;
goto cleanup_and_return;
}
available_stack_cell =
@ -10031,7 +10139,7 @@ wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth,
ref_type,
#endif
error_buf, error_buf_size)) {
return false;
goto fail;
}
cell_num = wasm_value_type_cell_num(types[i]);
frame_ref -= cell_num;
@ -10045,10 +10153,26 @@ wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth,
#endif
}
return true;
#if WASM_ENABLE_FAST_INTERP != 0
emit_br_info(target_block);
#endif
ret = true;
cleanup_and_return:
fail:
return false;
if (frame_ref_buf && frame_ref_buf != frame_ref_tmp)
wasm_runtime_free(frame_ref_buf);
#if WASM_ENABLE_GC != 0
if (frame_reftype_map_buf && frame_reftype_map_buf != frame_reftype_map_tmp)
wasm_runtime_free(frame_reftype_map_buf);
#endif
#if WASM_ENABLE_FAST_INTERP != 0
if (frame_offset_buf && frame_offset_buf != frame_offset_tmp)
wasm_runtime_free(frame_offset_tmp);
#endif
return ret;
}
static BranchBlock *
@ -10066,9 +10190,6 @@ check_branch_block(WASMLoaderContext *loader_ctx, uint8 **p_buf, uint8 *buf_end,
}
frame_csp_tmp = loader_ctx->frame_csp - depth - 1;
#if WASM_ENABLE_FAST_INTERP != 0
emit_br_info(frame_csp_tmp);
#endif
*p_buf = p;
return frame_csp_tmp;

View File

@ -5428,13 +5428,6 @@ fail:
local_offset = local_offsets[local_idx]; \
} while (0)
#define CHECK_BR(depth) \
do { \
if (!wasm_loader_check_br(loader_ctx, depth, error_buf, \
error_buf_size)) \
goto fail; \
} while (0)
#define CHECK_MEMORY() \
do { \
bh_assert(module->import_memory_count + module->memory_count > 0); \
@ -5442,7 +5435,7 @@ fail:
static bool
wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth,
char *error_buf, uint32 error_buf_size)
bool is_br_table, char *error_buf, uint32 error_buf_size)
{
BranchBlock *target_block, *cur_block;
BlockType *target_block_type;
@ -5451,6 +5444,20 @@ wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth,
int32 i, available_stack_cell;
uint16 cell_num;
uint8 *frame_ref_old = loader_ctx->frame_ref;
uint8 *frame_ref_after_popped = NULL;
uint8 frame_ref_tmp[4] = { 0 };
uint8 *frame_ref_buf = frame_ref_tmp;
uint32 stack_cell_num_old = loader_ctx->stack_cell_num;
#if WASM_ENABLE_FAST_INTERP != 0
int16 *frame_offset_old = loader_ctx->frame_offset;
int16 *frame_offset_after_popped = NULL;
int16 frame_offset_tmp[4] = { 0 };
int16 *frame_offset_buf = frame_offset_tmp;
uint16 dynamic_offset_old = (loader_ctx->frame_csp - 1)->dynamic_offset;
#endif
bool ret = false;
bh_assert(loader_ctx->csp_num > 0);
if (loader_ctx->csp_num - 1 < depth) {
set_error_buf(error_buf, error_buf_size,
@ -5482,6 +5489,38 @@ wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth,
#endif
POP_TYPE(types[i]);
}
/* Backup stack data since it may be changed in the below
push operations, and the stack data may be used when
checking other target blocks of opcode br_table */
if (is_br_table) {
uint64 total_size;
frame_ref_after_popped = loader_ctx->frame_ref;
total_size = (uint64)sizeof(uint8)
* (frame_ref_old - frame_ref_after_popped);
if (total_size > sizeof(frame_ref_tmp)
&& !(frame_ref_buf = loader_malloc(total_size, error_buf,
error_buf_size))) {
goto fail;
}
bh_memcpy_s(frame_ref_buf, (uint32)total_size,
frame_ref_after_popped, (uint32)total_size);
#if WASM_ENABLE_FAST_INTERP != 0
frame_offset_after_popped = loader_ctx->frame_offset;
total_size = (uint64)sizeof(int16)
* (frame_offset_old - frame_offset_after_popped);
if (total_size > sizeof(frame_offset_tmp)
&& !(frame_offset_buf = loader_malloc(total_size, error_buf,
error_buf_size))) {
goto fail;
}
bh_memcpy_s(frame_offset_buf, (uint32)total_size,
frame_offset_after_popped, (uint32)total_size);
#endif
}
for (i = 0; i < (int32)arity; i++) {
#if WASM_ENABLE_FAST_INTERP != 0
bool disable_emit = true;
@ -5490,7 +5529,44 @@ wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth,
#endif
PUSH_TYPE(types[i]);
}
return true;
#if WASM_ENABLE_FAST_INTERP != 0
emit_br_info(target_block);
#endif
/* Restore the stack data, note that frame_ref_bottom,
frame_reftype_map_bottom, frame_offset_bottom may be
re-allocated in the above push operations */
if (is_br_table) {
uint32 total_size;
/* The stack operand num should not be smaller than before
after pop and push operations */
bh_assert(loader_ctx->stack_cell_num >= stack_cell_num_old);
loader_ctx->stack_cell_num = stack_cell_num_old;
loader_ctx->frame_ref =
loader_ctx->frame_ref_bottom + stack_cell_num_old;
total_size = (uint32)sizeof(uint8)
* (frame_ref_old - frame_ref_after_popped);
bh_memcpy_s((uint8 *)loader_ctx->frame_ref - total_size, total_size,
frame_ref_buf, total_size);
#if WASM_ENABLE_FAST_INTERP != 0
/* The stack operand num should not be smaller than before
after pop and push operations */
bh_assert(loader_ctx->reftype_map_num >= reftype_map_num_old);
loader_ctx->frame_offset =
loader_ctx->frame_offset_bottom + stack_cell_num_old;
total_size = (uint32)sizeof(int16)
* (frame_offset_old - frame_offset_after_popped);
bh_memcpy_s((uint8 *)loader_ctx->frame_offset - total_size,
total_size, frame_offset_buf, total_size);
(loader_ctx->frame_csp - 1)->dynamic_offset = dynamic_offset_old;
#endif
}
ret = true;
goto cleanup_and_return;
}
available_stack_cell =
@ -5499,33 +5575,47 @@ wasm_loader_check_br(WASMLoaderContext *loader_ctx, uint32 depth,
/* Check stack top values match target block type */
for (i = (int32)arity - 1; i >= 0; i--) {
if (!check_stack_top_values(frame_ref, available_stack_cell, types[i],
error_buf, error_buf_size))
return false;
error_buf, error_buf_size)) {
goto fail;
}
cell_num = wasm_value_type_cell_num(types[i]);
frame_ref -= cell_num;
available_stack_cell -= cell_num;
}
return true;
#if WASM_ENABLE_FAST_INTERP != 0
emit_br_info(target_block);
#endif
ret = true;
cleanup_and_return:
fail:
return false;
if (frame_ref_buf && frame_ref_buf != frame_ref_tmp)
wasm_runtime_free(frame_ref_buf);
#if WASM_ENABLE_FAST_INTERP != 0
if (frame_offset_buf && frame_offset_buf != frame_offset_tmp)
wasm_runtime_free(frame_offset_tmp);
#endif
return ret;
}
static BranchBlock *
check_branch_block(WASMLoaderContext *loader_ctx, uint8 **p_buf, uint8 *buf_end,
char *error_buf, uint32 error_buf_size)
bool is_br_table, char *error_buf, uint32 error_buf_size)
{
uint8 *p = *p_buf, *p_end = buf_end;
BranchBlock *frame_csp_tmp;
uint32 depth;
read_leb_uint32(p, p_end, depth);
CHECK_BR(depth);
if (!wasm_loader_check_br(loader_ctx, depth, is_br_table, error_buf,
error_buf_size)) {
goto fail;
}
frame_csp_tmp = loader_ctx->frame_csp - depth - 1;
#if WASM_ENABLE_FAST_INTERP != 0
emit_br_info(frame_csp_tmp);
#endif
*p_buf = p;
return frame_csp_tmp;
@ -6143,8 +6233,9 @@ re_scan:
case WASM_OP_BR:
{
if (!(frame_csp_tmp = check_branch_block(
loader_ctx, &p, p_end, error_buf, error_buf_size)))
if (!(frame_csp_tmp =
check_branch_block(loader_ctx, &p, p_end, false,
error_buf, error_buf_size)))
goto fail;
RESET_STACK();
@ -6156,8 +6247,9 @@ re_scan:
{
POP_I32();
if (!(frame_csp_tmp = check_branch_block(
loader_ctx, &p, p_end, error_buf, error_buf_size)))
if (!(frame_csp_tmp =
check_branch_block(loader_ctx, &p, p_end, false,
error_buf, error_buf_size)))
goto fail;
break;
@ -6186,7 +6278,7 @@ re_scan:
#endif
for (i = 0; i <= count; i++) {
if (!(frame_csp_tmp =
check_branch_block(loader_ctx, &p, p_end,
check_branch_block(loader_ctx, &p, p_end, true,
error_buf, error_buf_size)))
goto fail;