diff --git a/core/iwasm/interpreter/wasm_loader.c b/core/iwasm/interpreter/wasm_loader.c index 1453f1bfa..7280201fb 100644 --- a/core/iwasm/interpreter/wasm_loader.c +++ b/core/iwasm/interpreter/wasm_loader.c @@ -9720,6 +9720,16 @@ preserve_local_for_block(WASMLoaderContext *loader_ctx, uint8 opcode, /* preserve locals before blocks to ensure that "tee/set_local" inside blocks will not influence the value of these locals */ + uint32 frame_offset_cell = + (uint32)(loader_ctx->frame_offset - loader_ctx->frame_offset_bottom); + uint32 frame_ref_cell = + (uint32)(loader_ctx->frame_ref - loader_ctx->frame_ref_bottom); + if (frame_offset_cell < loader_ctx->stack_cell_num + || frame_ref_cell < loader_ctx->stack_cell_num) { + set_error_buf(error_buf, error_buf_size, "stack cell num error"); + return false; + } + while (i < loader_ctx->stack_cell_num) { int16 cur_offset = loader_ctx->frame_offset_bottom[i]; uint8 cur_type = loader_ctx->frame_ref_bottom[i]; @@ -12106,13 +12116,19 @@ re_scan: } #endif + uint8 *frame_ref_before_pop = loader_ctx->frame_ref; POP_TYPE( wasm_type->types[wasm_type->param_count - i - 1]); #if WASM_ENABLE_FAST_INTERP != 0 /* decrease the frame_offset pointer accordingly to keep - * consistent with frame_ref stack */ - cell_num = wasm_value_type_cell_num( - wasm_type->types[wasm_type->param_count - i - 1]); + * consistent with frame_ref stack. Use the actual + * popped cell count instead of + * wasm_value_type_cell_num() because when the stack top + * is VALUE_TYPE_ANY, wasm_loader_pop_frame_ref always + * pops exactly 1 cell regardless of the expected type + */ + cell_num = (uint32)(frame_ref_before_pop + - loader_ctx->frame_ref); loader_ctx->frame_offset -= cell_num; if (loader_ctx->frame_offset diff --git a/tests/regression/ba-issues/issues/issue-980000/frame_offset_overflow.wasm b/tests/regression/ba-issues/issues/issue-980000/frame_offset_overflow.wasm new file mode 100644 index 000000000..f0b8029ec Binary files /dev/null and b/tests/regression/ba-issues/issues/issue-980000/frame_offset_overflow.wasm differ diff --git a/tests/regression/ba-issues/issues/issue-980000/frame_offset_overflow.wat b/tests/regression/ba-issues/issues/issue-980000/frame_offset_overflow.wat new file mode 100644 index 000000000..1bbe783d0 --- /dev/null +++ b/tests/regression/ba-issues/issues/issue-980000/frame_offset_overflow.wat @@ -0,0 +1,70 @@ +(module + (global $g0 (mut i32) (i32.const 0)) + (global $g1 (mut i32) (i32.const 0)) + (global $g2 (mut i32) (i32.const 0)) + (global $g3 (mut i32) (i32.const 0)) + (global $g4 (mut i32) (i32.const 0)) + (global $g5 (mut i32) (i32.const 0)) + (global $g6 (mut i32) (i32.const 0)) + (global $g7 (mut i32) (i32.const 0)) + + (export "test" (func $0)) + (func $0 + (local i32) + + global.get $g0 + global.get $g1 + global.get $g2 + global.get $g3 + global.get $g4 + global.get $g5 + global.get $g6 + global.get $g7 + global.get $g0 + global.get $g1 + global.get $g2 + global.get $g3 + global.get $g4 + global.get $g5 + global.get $g6 + global.get $g7 + global.get $g0 + global.get $g1 + global.get $g2 + global.get $g3 + global.get $g4 + global.get $g4 + global.get $g4 + global.get $g4 + global.get $g4 + global.get $g4 + global.get $g4 + global.get $g4 + global.get $g4 + global.get $g0 + + ;; has consumed 30 elements, left 2 elements on stack + block + block + f64.const 3.14 + ;; RESET current block stack and mark polymorphic + unreachable + ;; PUSH ANY + select + + loop (param i64) (result i32) + ;; NOW, unmatched stacks. Enlarge frame_ref stack. Keep frame_offset stack unchanged. + global.get $g0 + i32.eqz + ;; OUT-OF-BOUNDS + if + unreachable + end + i32.wrap_i64 + end + local.set 0 + end + end + unreachable + ) +) diff --git a/tests/regression/ba-issues/running_config.json b/tests/regression/ba-issues/running_config.json index bc62c5491..61665f2fc 100644 --- a/tests/regression/ba-issues/running_config.json +++ b/tests/regression/ba-issues/running_config.json @@ -1786,6 +1786,22 @@ "stdout content": "", "description": "load successfully" } + }, + { + "deprecated": false, + "ids": [ + 980000 + ], + "runtime": "iwasm-default", + "file": "frame_offset_overflow.wasm", + "mode": "fast-interp", + "options": "-f test", + "argument": "", + "expected return": { + "ret code": 1, + "stdout content": "Exception: unreachable", + "description": "no 'frame offset overflow'" + } } ] }