Skip to content

Commit 40e51fa

Browse files
fast-interp: Fix block with parameter in polymorphic stack issue (#3112)
The issue was reported in #3061.
1 parent 3111a86 commit 40e51fa

File tree

2 files changed

+130
-159
lines changed

2 files changed

+130
-159
lines changed

core/iwasm/interpreter/wasm_loader.c

+65-81
Original file line numberDiff line numberDiff line change
@@ -5280,9 +5280,8 @@ typedef struct BranchBlock {
52805280
BranchBlockPatch *patch_list;
52815281
/* This is used to save params frame_offset of of if block */
52825282
int16 *param_frame_offsets;
5283-
/* This is used to store available param num for if/else branch, so the else
5284-
* opcode can know how many parameters should be copied to the stack */
5285-
uint32 available_param_num;
5283+
/* This is used to recover dynamic offset for else branch */
5284+
uint16 start_dynamic_offset;
52865285
#endif
52875286

52885287
/* Indicate the operand stack is in polymorphic state.
@@ -7219,18 +7218,15 @@ check_block_stack(WASMLoaderContext *loader_ctx, BranchBlock *block,
72197218
* 1) POP original parameter out;
72207219
* 2) Push and copy original values to dynamic space.
72217220
* The copy instruction format:
7222-
* Part a: available param count
7221+
* Part a: param count
72237222
* Part b: all param total cell num
72247223
* Part c: each param's cell_num, src offset and dst offset
72257224
* Part d: each param's src offset
72267225
* Part e: each param's dst offset
7227-
* Note: if the stack is in polymorphic state, the actual copied parameters may
7228-
* be fewer than the defined number in block type
72297226
*/
72307227
static bool
72317228
copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block,
7232-
uint32 *p_available_param_count, char *error_buf,
7233-
uint32 error_buf_size)
7229+
char *error_buf, uint32 error_buf_size)
72347230
{
72357231
bool ret = false;
72367232
int16 *frame_offset = NULL;
@@ -7242,91 +7238,72 @@ copy_params_to_dynamic_space(WASMLoaderContext *loader_ctx, bool is_if_block,
72427238
BlockType *block_type = &block->block_type;
72437239
WASMType *wasm_type = block_type->u.type;
72447240
uint32 param_count = block_type->u.type->param_count;
7245-
uint32 available_param_count = 0;
72467241
int16 condition_offset = 0;
72477242
bool disable_emit = false;
72487243
int16 operand_offset = 0;
7249-
uint64 size;
7250-
7251-
if (is_if_block)
7252-
condition_offset = *loader_ctx->frame_offset;
7253-
7254-
/* POP original parameter out */
7255-
for (i = 0; i < param_count; i++) {
7256-
int32 available_stack_cell =
7257-
(int32)(loader_ctx->stack_cell_num - block->stack_cell_num);
7258-
7259-
if (available_stack_cell <= 0 && block->is_stack_polymorphic)
7260-
break;
7261-
7262-
POP_OFFSET_TYPE(wasm_type->types[param_count - i - 1]);
7263-
wasm_loader_emit_backspace(loader_ctx, sizeof(int16));
7264-
}
7265-
available_param_count = i;
72667244

7267-
size =
7268-
(uint64)available_param_count * (sizeof(*cells) + sizeof(*src_offsets));
7245+
uint64 size = (uint64)param_count * (sizeof(*cells) + sizeof(*src_offsets));
7246+
bh_assert(size > 0);
72697247

72707248
/* For if block, we also need copy the condition operand offset. */
72717249
if (is_if_block)
72727250
size += sizeof(*cells) + sizeof(*src_offsets);
72737251

72747252
/* Allocate memory for the emit data */
7275-
if ((size > 0)
7276-
&& !(emit_data = loader_malloc(size, error_buf, error_buf_size)))
7253+
if (!(emit_data = loader_malloc(size, error_buf, error_buf_size)))
72777254
return false;
72787255

72797256
cells = emit_data;
72807257
src_offsets = (int16 *)(cells + param_count);
72817258

7259+
if (is_if_block)
7260+
condition_offset = *loader_ctx->frame_offset;
7261+
7262+
/* POP original parameter out */
7263+
for (i = 0; i < param_count; i++) {
7264+
POP_OFFSET_TYPE(wasm_type->types[param_count - i - 1]);
7265+
wasm_loader_emit_backspace(loader_ctx, sizeof(int16));
7266+
}
72827267
frame_offset = loader_ctx->frame_offset;
72837268

72847269
/* Get each param's cell num and src offset */
7285-
for (i = 0; i < available_param_count; i++) {
7270+
for (i = 0; i < param_count; i++) {
72867271
cell = (uint8)wasm_value_type_cell_num(wasm_type->types[i]);
72877272
cells[i] = cell;
72887273
src_offsets[i] = *frame_offset;
72897274
frame_offset += cell;
72907275
}
7291-
72927276
/* emit copy instruction */
72937277
emit_label(EXT_OP_COPY_STACK_VALUES);
72947278
/* Part a) */
7295-
emit_uint32(loader_ctx, is_if_block ? available_param_count + 1
7296-
: available_param_count);
7279+
emit_uint32(loader_ctx, is_if_block ? param_count + 1 : param_count);
72977280
/* Part b) */
72987281
emit_uint32(loader_ctx, is_if_block ? wasm_type->param_cell_num + 1
72997282
: wasm_type->param_cell_num);
73007283
/* Part c) */
7301-
for (i = 0; i < available_param_count; i++)
7284+
for (i = 0; i < param_count; i++)
73027285
emit_byte(loader_ctx, cells[i]);
73037286
if (is_if_block)
73047287
emit_byte(loader_ctx, 1);
73057288

73067289
/* Part d) */
7307-
for (i = 0; i < available_param_count; i++)
7290+
for (i = 0; i < param_count; i++)
73087291
emit_operand(loader_ctx, src_offsets[i]);
73097292
if (is_if_block)
73107293
emit_operand(loader_ctx, condition_offset);
73117294

73127295
/* Part e) */
73137296
/* Push to dynamic space. The push will emit the dst offset. */
7314-
for (i = 0; i < available_param_count; i++)
7297+
for (i = 0; i < param_count; i++)
73157298
PUSH_OFFSET_TYPE(wasm_type->types[i]);
73167299
if (is_if_block)
73177300
PUSH_OFFSET_TYPE(VALUE_TYPE_I32);
73187301

7319-
if (p_available_param_count) {
7320-
*p_available_param_count = available_param_count;
7321-
}
7322-
73237302
ret = true;
73247303

73257304
fail:
73267305
/* Free the emit data */
7327-
if (emit_data) {
7328-
wasm_runtime_free(emit_data);
7329-
}
7306+
wasm_runtime_free(emit_data);
73307307

73317308
return ret;
73327309
}
@@ -7616,6 +7593,7 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
76167593

76177594
BranchBlock *cur_block = loader_ctx->frame_csp - 1;
76187595
#if WASM_ENABLE_FAST_INTERP != 0
7596+
uint32 cell_num;
76197597
available_params = block_type.u.type->param_count;
76207598
#endif
76217599
for (i = 0; i < block_type.u.type->param_count; i++) {
@@ -7633,6 +7611,13 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
76337611

76347612
POP_TYPE(
76357613
wasm_type->types[wasm_type->param_count - i - 1]);
7614+
#if WASM_ENABLE_FAST_INTERP != 0
7615+
/* decrease the frame_offset pointer accordingly to keep
7616+
* consistent with frame_ref stack */
7617+
cell_num = wasm_value_type_cell_num(
7618+
wasm_type->types[wasm_type->param_count - i - 1]);
7619+
loader_ctx->frame_offset -= cell_num;
7620+
#endif
76367621
}
76377622
}
76387623
PUSH_CSP(LABEL_TYPE_BLOCK + (opcode - WASM_OP_BLOCK),
@@ -7641,12 +7626,26 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
76417626
/* Pass parameters to block */
76427627
if (BLOCK_HAS_PARAM(block_type)) {
76437628
for (i = 0; i < block_type.u.type->param_count; i++) {
7644-
PUSH_TYPE(block_type.u.type->types[i]);
76457629
#if WASM_ENABLE_FAST_INTERP != 0
7630+
uint32 cell_num = wasm_value_type_cell_num(
7631+
block_type.u.type->types[i]);
76467632
if (i >= available_params) {
7647-
PUSH_OFFSET_TYPE(block_type.u.type->types[i]);
7633+
/* If there isn't enough data on stack, push a dummy
7634+
* offset to keep the stack consistent with
7635+
* frame_ref.
7636+
* Since the stack is already in polymorphic state,
7637+
* the opcode will not be executed, so the dummy
7638+
* offset won't cause any error */
7639+
*loader_ctx->frame_offset++ = 0;
7640+
if (cell_num > 1) {
7641+
*loader_ctx->frame_offset++ = 0;
7642+
}
7643+
}
7644+
else {
7645+
loader_ctx->frame_offset += cell_num;
76487646
}
76497647
#endif
7648+
PUSH_TYPE(block_type.u.type->types[i]);
76507649
}
76517650
}
76527651

@@ -7656,9 +7655,8 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
76567655

76577656
if (BLOCK_HAS_PARAM(block_type)) {
76587657
/* Make sure params are in dynamic space */
7659-
if (!copy_params_to_dynamic_space(loader_ctx, false,
7660-
NULL, error_buf,
7661-
error_buf_size))
7658+
if (!copy_params_to_dynamic_space(
7659+
loader_ctx, false, error_buf, error_buf_size))
76627660
goto fail;
76637661
}
76647662

@@ -7691,17 +7689,21 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
76917689
* recover them before entering else branch.
76927690
*
76937691
*/
7694-
if (if_condition_available && BLOCK_HAS_PARAM(block_type)) {
7692+
if (BLOCK_HAS_PARAM(block_type)) {
76957693
uint64 size;
76967694

7697-
/* skip the if condition operand offset */
7698-
wasm_loader_emit_backspace(loader_ctx, sizeof(int16));
7695+
/* In polymorphic state, there may be no if condition on
7696+
* the stack, so the offset may not emitted */
7697+
if (if_condition_available) {
7698+
/* skip the if condition operand offset */
7699+
wasm_loader_emit_backspace(loader_ctx,
7700+
sizeof(int16));
7701+
}
76997702
/* skip the if label */
77007703
skip_label();
77017704
/* Emit a copy instruction */
77027705
if (!copy_params_to_dynamic_space(
7703-
loader_ctx, true, &block->available_param_num,
7704-
error_buf, error_buf_size))
7706+
loader_ctx, true, error_buf, error_buf_size))
77057707
goto fail;
77067708

77077709
/* Emit the if instruction */
@@ -7722,9 +7724,8 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
77227724
- size / sizeof(int16),
77237725
(uint32)size);
77247726
}
7725-
else {
7726-
block->available_param_num = 0;
7727-
}
7727+
7728+
block->start_dynamic_offset = loader_ctx->dynamic_offset;
77287729

77297730
emit_empty_label_addr_and_frame_ip(PATCH_ELSE);
77307731
emit_empty_label_addr_and_frame_ip(PATCH_END);
@@ -7980,30 +7981,13 @@ wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
79807981

79817982
#if WASM_ENABLE_FAST_INTERP != 0
79827983
/* Recover top param_count values of frame_offset stack */
7983-
if (block->available_param_num) {
7984-
uint32 available_param_cell_num = 0;
7985-
7986-
/* total cell num of available parameters */
7987-
for (i = 0; i < block->available_param_num; i++) {
7988-
uint32 cell_num = wasm_value_type_cell_num(
7989-
block->block_type.u.type->types[i]);
7990-
7991-
/* recover dynamic offset */
7992-
if (block->param_frame_offsets[available_param_cell_num]
7993-
>= loader_ctx->dynamic_offset) {
7994-
loader_ctx->dynamic_offset =
7995-
block->param_frame_offsets
7996-
[available_param_cell_num]
7997-
+ cell_num;
7998-
}
7999-
8000-
available_param_cell_num += cell_num;
8001-
}
8002-
8003-
bh_memcpy_s(
8004-
loader_ctx->frame_offset, available_param_cell_num,
8005-
block->param_frame_offsets, available_param_cell_num);
8006-
loader_ctx->frame_offset += available_param_cell_num;
7984+
if (BLOCK_HAS_PARAM((block_type))) {
7985+
uint32 size;
7986+
size = sizeof(int16) * block_type.u.type->param_cell_num;
7987+
bh_memcpy_s(loader_ctx->frame_offset, size,
7988+
block->param_frame_offsets, size);
7989+
loader_ctx->frame_offset += (size / sizeof(int16));
7990+
loader_ctx->dynamic_offset = block->start_dynamic_offset;
80077991
}
80087992
#endif
80097993

0 commit comments

Comments
 (0)