From a14f4215a0af7176a80502ca2922aeaa17e2e1a2 Mon Sep 17 00:00:00 2001 From: Manos Koukoutos Date: Wed, 9 Jun 2021 11:56:05 +0000 Subject: [PATCH] [wasm] Fix a bug in unreachable code Loop fallthroughs should leave values according to their out-type on the stack, even when the stack is polymorphic. Bug: chromium:1217470 Change-Id: I0a7e0569fa24fc16fcac76569a5ba14b6c7b0a9f Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2949090 Reviewed-by: Andreas Haas Commit-Queue: Manos Koukoutos Cr-Commit-Position: refs/heads/master@{#75043} --- src/wasm/function-body-decoder-impl.h | 10 ++++++++-- test/mjsunit/wasm/unreachable-validation.js | 3 +++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/wasm/function-body-decoder-impl.h b/src/wasm/function-body-decoder-impl.h index 2b808f344a..64e4775384 100644 --- a/src/wasm/function-body-decoder-impl.h +++ b/src/wasm/function-body-decoder-impl.h @@ -3623,8 +3623,14 @@ class WasmFullDecoder : public WasmDecoder { CALL_INTERFACE_IF_OK_AND_PARENT_REACHABLE(PopControl, c); - // A loop just leaves the values on the stack. - if (!c->is_loop()) PushMergeValues(c, &c->end_merge); + // - In non-unreachable code, a loop just leaves the values on the stack. + // - In unreachable code, it is not guaranteed that we have Values of the + // correct types on the stack, so we have to make sure we do. Their values + // do not matter, so we might as well push the (uninitialized) values of + // the loop's end merge. + if (!c->is_loop() || c->unreachable()) { + PushMergeValues(c, &c->end_merge); + } bool parent_reached = c->reachable() || c->end_merge.reached || c->is_onearmed_if(); diff --git a/test/mjsunit/wasm/unreachable-validation.js b/test/mjsunit/wasm/unreachable-validation.js index dd1b734320..1e9f1b5cbc 100644 --- a/test/mjsunit/wasm/unreachable-validation.js +++ b/test/mjsunit/wasm/unreachable-validation.js @@ -57,6 +57,8 @@ let if_unr = [kExprIf, kWasmVoid, kExprUnreachable, kExprEnd]; let if_else_unr = [kExprIf, kWasmVoid, kExprUnreachable, kExprElse, kExprUnreachable, kExprEnd]; let block_unr = [kExprBlock, kWasmVoid, kExprUnreachable, kExprEnd]; let loop_unr = [kExprLoop, kWasmVoid, kExprUnreachable, kExprEnd]; +// An i32-typed loop returning a polymorphic stack. +let iloop_poly = [kExprLoop, kWasmI32, kExprUnreachable, kExprI32Const, 0, kExprSelect, kExprEnd]; let block_block_unr = [kExprBlock, kWasmVoid, kExprBlock, kWasmVoid, kExprUnreachable, kExprEnd, kExprEnd]; let block = [kExprBlock, kWasmVoid] let iblock = [kExprBlock, kWasmI32] @@ -100,6 +102,7 @@ run(I, '0 0 ret iadd', [...zero, ...zero, ret, iadd]); run(I, '(block U) iadd drop', [...block_unr, iadd, drop]); run(I, '(block (block U)) iadd drop', [...block_block_unr, iadd, drop]); run(I, '(loop U) iadd drop', [...loop_unr, iadd]); +run(V, '(iloop (iloop U 0 select)) drop', [kExprLoop, kWasmI32, ...iloop_poly, kExprEnd, drop]); run(I, '(if 0 U U) iadd drop', [...zero, ...if_else_unr, iadd, drop]); run(I, 'U (i_iblock leqz)', [unr, ...i_iblock, leqz, end, drop]); run(V, 'U (i_iblock ieqz)', [unr, ...i_iblock, ieqz, end, drop]);