From 17a89d1f4e5e5a3fb5bca9c13953bcd9f6d340b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= Date: Fri, 11 Nov 2022 08:20:17 +0100 Subject: [PATCH] deps: V8: cherry-pick 031b98b25cba MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Original commit message: [runtime] Clear array join stack when throwing uncatchable ... exception. Array#join depends array_join_stack to avoid infinite loop and ensures symmetric pushes/pops through catch blocks to correctly maintain the elements in the join stack. However, the stack does not pop the elements and leaves in an invalid state when throwing the uncatchable termination exception. And the invalid join stack state will affect subsequent Array#join calls. Because all the terminate exception will be handled by Isolate::UnwindAndFindHandler, we could clear the array join stack when unwinding the terminate exception. Bug: v8:13259 Change-Id: I23823e823c5fe0b089528c5cf654864cea78ebeb Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3878451 Reviewed-by: Jakob Linke Commit-Queue: 王澳 Cr-Commit-Position: refs/heads/main@{#83465} Refs: https://github.com/v8/v8/commit/031b98b25cbaaa4c62d8544f5f667d33ea4076c4 Closes: https://github.com/nodejs/node/issues/44417 PR-URL: https://github.com/nodejs/node/pull/45375 Fixes: https://github.com/nodejs/node/issues/44417 Reviewed-By: Jiawen Geng Reviewed-By: Rich Trott Reviewed-By: Kohei Ueno --- deps/v8/src/execution/isolate.cc | 9 + ...ode-side-effecting-array-join-expected.txt | 48 + ...ate-repl-mode-side-effecting-array-join.js | 32 + .../execution/thread-termination-unittest.cc | 1069 +++++++++++++++++ 4 files changed, 1158 insertions(+) create mode 100644 deps/v8/test/inspector/runtime/evaluate-repl-mode-side-effecting-array-join-expected.txt create mode 100644 deps/v8/test/inspector/runtime/evaluate-repl-mode-side-effecting-array-join.js create mode 100644 deps/v8/test/unittests/execution/thread-termination-unittest.cc diff --git a/deps/v8/src/execution/isolate.cc b/deps/v8/src/execution/isolate.cc index 62d9f4abc33fed..e5dba75764f6a9 100644 --- a/deps/v8/src/execution/isolate.cc +++ b/deps/v8/src/execution/isolate.cc @@ -1909,6 +1909,15 @@ Object Isolate::UnwindAndFindHandler() { // Special handling of termination exceptions, uncatchable by JavaScript and // Wasm code, we unwind the handlers until the top ENTRY handler is found. bool catchable_by_js = is_catchable_by_javascript(exception); + if (!catchable_by_js && !context().is_null()) { + // Because the array join stack will not pop the elements when throwing the + // uncatchable terminate exception, we need to clear the array join stack to + // avoid leaving the stack in an invalid state. + // See also CycleProtectedArrayJoin. + raw_native_context().set_array_join_stack( + ReadOnlyRoots(this).undefined_value()); + } + int visited_frames = 0; // Compute handler and stack unwinding information by performing a full walk diff --git a/deps/v8/test/inspector/runtime/evaluate-repl-mode-side-effecting-array-join-expected.txt b/deps/v8/test/inspector/runtime/evaluate-repl-mode-side-effecting-array-join-expected.txt new file mode 100644 index 00000000000000..19ad7f863eeba9 --- /dev/null +++ b/deps/v8/test/inspector/runtime/evaluate-repl-mode-side-effecting-array-join-expected.txt @@ -0,0 +1,48 @@ +Tests that Runtime.evaluate with REPL mode correctly handles Array.prototype.join. +{ + id : + result : { + result : { + className : Array + description : Array(1) + objectId : + subtype : array + type : object + } + } +} +{ + id : + result : { + exceptionDetails : { + columnNumber : -1 + exception : { + className : EvalError + description : EvalError: Possible side-effect in debug-evaluate + objectId : + subtype : error + type : object + } + exceptionId : + lineNumber : -1 + scriptId : + text : Uncaught + } + result : { + className : EvalError + description : EvalError: Possible side-effect in debug-evaluate + objectId : + subtype : error + type : object + } + } +} +{ + id : + result : { + result : { + type : string + value : /a/ + } + } +} diff --git a/deps/v8/test/inspector/runtime/evaluate-repl-mode-side-effecting-array-join.js b/deps/v8/test/inspector/runtime/evaluate-repl-mode-side-effecting-array-join.js new file mode 100644 index 00000000000000..05259ff24f4d95 --- /dev/null +++ b/deps/v8/test/inspector/runtime/evaluate-repl-mode-side-effecting-array-join.js @@ -0,0 +1,32 @@ +// Copyright 2022 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +let {Protocol} = InspectorTest.start( + 'Tests that Runtime.evaluate with REPL mode correctly handles \ +Array.prototype.join.'); + +Protocol.Runtime.enable(); +(async function () { + await evaluateReplWithSideEffects('a=[/a/]') + await evaluateRepl('a.toString()'); + await evaluateReplWithSideEffects('a.toString()'); + + InspectorTest.completeTest(); +})(); + +async function evaluateRepl(expression) { + InspectorTest.logMessage(await Protocol.Runtime.evaluate({ + expression: expression, + replMode: true, + throwOnSideEffect: true + })); +} + +async function evaluateReplWithSideEffects(expression) { + InspectorTest.logMessage(await Protocol.Runtime.evaluate({ + expression: expression, + replMode: true, + throwOnSideEffect: false + })); +} diff --git a/deps/v8/test/unittests/execution/thread-termination-unittest.cc b/deps/v8/test/unittests/execution/thread-termination-unittest.cc new file mode 100644 index 00000000000000..f9634b4a53d7e3 --- /dev/null +++ b/deps/v8/test/unittests/execution/thread-termination-unittest.cc @@ -0,0 +1,1069 @@ +// Copyright 2009 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "include/v8-function.h" +#include "include/v8-locker.h" +#include "src/api/api-inl.h" +#include "src/base/platform/platform.h" +#include "src/execution/isolate.h" +#include "src/init/v8.h" +#include "src/objects/objects-inl.h" +#include "test/unittests/test-utils.h" +#include "testing/gmock-support.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace v8 { + +base::Semaphore* semaphore = nullptr; + +class TerminatorThread : public base::Thread { + public: + explicit TerminatorThread(i::Isolate* isolate) + : Thread(Options("TerminatorThread")), + isolate_(reinterpret_cast(isolate)) {} + void Run() override { + semaphore->Wait(); + CHECK(!isolate_->IsExecutionTerminating()); + isolate_->TerminateExecution(); + } + + private: + Isolate* isolate_; +}; + +void Signal(const FunctionCallbackInfo& args) { semaphore->Signal(); } + +MaybeLocal CompileRun(Local context, Local source) { + Local