deps: V8: backport b36cf9f6ccd2

Original commit message:

    [api] Prepare DisallowJavascriptExecution scope around api callbacks

    In `v8::Isolate::RequestInterrupt` the API contract says:

         API interrupt callbacks are forbidden from executing JavaScript
         on the interrupted Isolate.

    This CL prepares the infrastructure to enforce this contract.

    Bug: 540137721, 40067940

    TAG=agy
    CONV=78573798-a951-4bd3-9c6f-3e3b6775da4b

    Change-Id: I43cc83c3cc3ebd34052a927dde55bbf4d49d2d29
    Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/8173727
    Auto-Submit: Olivier Flückiger <olivf@chromium.org>
    Reviewed-by: Simon Zünd <szuend@chromium.org>
    Commit-Queue: Olivier Flückiger <olivf@chromium.org>
    Cr-Commit-Position: refs/heads/main@{#109086}

Refs: https://github.com/v8/v8/commit/b36cf9f6ccd2931d1d0bde6a9f366d30667e4b75
Signed-off-by: deepak1556 <hop2deep@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/65397
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Reviewed-By: Juan José Arboleda <soyjuanarbol@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Shelley Vohr <shelley.vohr@gmail.com>
This commit is contained in:
Olivier Flückiger authored and Node.js GitHub Bot committed 2026-09-04 16:56:56 +00:00
1 parent 49e2608492
commit ccd648eb0c
11 files changed
+93 -2

No files matched your search

+6
View File
@@ -148,6 +148,11 @@ v8_flag(name = "v8_enable_trace_maps")
v8_flag(name = "v8_enable_v8_checks")
v8_flag(
name = "v8_disallow_js_in_api_interrupts_is_checked",
default = True,
)
v8_flag(name = "v8_enable_verify_csa")
v8_flag(name = "v8_enable_verify_heap")
@@ -496,6 +501,7 @@ v8_config(
"v8_android_log_stdout": "V8_ANDROID_LOG_STDOUT",
"v8_code_comments": "V8_CODE_COMMENTS",
"v8_deprecation_warnings": "V8_DEPRECATION_WARNINGS",
"v8_disallow_js_in_api_interrupts_is_checked": "V8_DISALLOW_JS_IN_API_INTERRUPTS_IS_CHECKED",
"v8_imminent_deprecation_warnings": "V8_IMMINENT_DEPRECATION_WARNINGS",
"v8_enable_debug_code": "V8_ENABLE_DEBUG_CODE",
"v8_enable_disassembler": "ENABLE_DISASSEMBLER",
+11
View File
@@ -59,6 +59,10 @@ declare_args() {
# Enable compiler warnings when using V8_DEPRECATED apis.
v8_deprecation_warnings = true
# Check that executing JavaScript inside API interrupt callbacks is
# disallowed.
v8_disallow_js_in_api_interrupts_is_checked = true
# Enable compiler warnings when using V8_DEPRECATE_SOON apis.
v8_imminent_deprecation_warnings = true
@@ -999,6 +1003,7 @@ external_v8_defines = [
"V8_COMPRESS_ZONES",
"V8_ENABLE_SANDBOX",
"V8_DEPRECATION_WARNINGS",
"V8_DISALLOW_JS_IN_API_INTERRUPTS_IS_CHECKED",
"V8_IMMINENT_DEPRECATION_WARNINGS",
"V8_USE_PERFETTO",
"V8_USE_PERFETTO_JSON_EXPORT",
@@ -1047,6 +1052,10 @@ if (v8_enable_sandbox) {
if (v8_deprecation_warnings) {
enabled_external_v8_defines += [ "V8_DEPRECATION_WARNINGS" ]
}
if (v8_disallow_js_in_api_interrupts_is_checked) {
enabled_external_v8_defines +=
[ "V8_DISALLOW_JS_IN_API_INTERRUPTS_IS_CHECKED" ]
}
if (v8_imminent_deprecation_warnings) {
enabled_external_v8_defines += [ "V8_IMMINENT_DEPRECATION_WARNINGS" ]
}
@@ -3093,6 +3102,8 @@ generated_file("v8_generate_features_json") {
output_conversion = "json"
contents = {
v8_deprecation_warnings = v8_deprecation_warnings
v8_disallow_js_in_api_interrupts_is_checked =
v8_disallow_js_in_api_interrupts_is_checked
v8_enable_31bit_smis_on_64bit_arch = v8_enable_31bit_smis_on_64bit_arch
v8_enable_direct_handle = v8_enable_direct_handle
v8_enable_extensible_ro_snapshot = v8_enable_extensible_ro_snapshot
+1 -1
View File
@@ -110,7 +110,7 @@ class V8_NODISCARD PerThreadAssertScope
ScopeType& operator=(const ScopeType&) = delete; \
V8_EXPORT_PRIVATE ~ScopeType(); \
\
static bool IsAllowed(Isolate* isolate); \
V8_EXPORT_PRIVATE static bool IsAllowed(Isolate* isolate); \
\
V8_EXPORT_PRIVATE static void Open(Isolate* isolate, \
bool* was_execution_allowed); \
+7
View File
@@ -2245,6 +2245,13 @@ void Isolate::InvokeApiInterruptCallbacks() {
}
VMState<EXTERNAL> state(this);
HandleScope handle_scope(this);
// API interrupt callbacks are forbidden from executing JavaScript on the
// interrupted Isolate (see v8::Isolate::RequestInterrupt contract in
// v8-isolate.h: "Registered |callback| must not reenter interrupted
// Isolate.").
#ifdef V8_DISALLOW_JS_IN_API_INTERRUPTS_IS_CHECKED
DisallowJavascriptExecution no_js(this);
#endif // V8_DISALLOW_JS_IN_API_INTERRUPTS_IS_CHECKED
entry.first(reinterpret_cast<v8::Isolate*>(this), entry.second);
}
}
+1
View File
@@ -532,6 +532,7 @@ void V8Debugger::handleProgramBreak(
}
});
{
v8::Isolate::AllowJavascriptExecutionScope allow_script(m_isolate);
v8::Context::Scope scope(pausedContext);
m_inspector->forEachSession(
+1
View File
@@ -96,6 +96,7 @@ int V8InspectorImpl::resolveUniqueContextId(
v8::MaybeLocal<v8::Value> V8InspectorImpl::compileAndRunInternalScript(
v8::Local<v8::Context> context, v8::Local<v8::String> source) {
v8::Isolate::AllowJavascriptExecutionScope allow_script(m_isolate);
v8::Local<v8::UnboundScript> unboundScript;
if (!v8::debug::CompileInspectorScript(m_isolate, source)
.ToLocal(&unboundScript))
+2
View File
@@ -355,6 +355,8 @@ void V8InspectorSessionImpl::reportAllContexts(V8RuntimeAgentImpl* agent) {
}
void V8InspectorSessionImpl::dispatchProtocolMessage(StringView message) {
v8::Isolate::AllowJavascriptExecutionScope allow_script(
m_inspector->isolate());
KeepSessionAliveScope keepAlive(*this);
using v8_crdtp::span;
+2
View File
@@ -38,6 +38,7 @@ V8Regex::V8Regex(V8InspectorImpl* inspector, const String16& pattern,
v8::Local<v8::RegExp> regex;
// Protect against reentrant debugger calls via interrupts.
v8::debug::PostponeInterruptsScope no_interrupts(m_inspector->isolate());
v8::Isolate::AllowJavascriptExecutionScope allow_js(m_inspector->isolate());
if (v8::RegExp::New(context, toV8String(isolate, pattern),
static_cast<v8::RegExp::Flags>(flags))
.ToLocal(&regex))
@@ -69,6 +70,7 @@ int V8Regex::match(const String16& string, int startFrom,
v8::MicrotasksScope::kDoNotRunMicrotasks);
// Protect against reentrant debugger calls via interrupts.
v8::debug::PostponeInterruptsScope no_interrupts(m_inspector->isolate());
v8::Isolate::AllowJavascriptExecutionScope allow_js(m_inspector->isolate());
v8::TryCatch tryCatch(isolate);
v8::Local<v8::RegExp> regex = m_regex.Get(isolate);
+20
View File
@@ -22306,6 +22306,26 @@ TEST(RequestInterruptSmallScripts) {
CHECK(interrupt_was_called);
}
#ifdef V8_DISALLOW_JS_IN_API_INTERRUPTS_IS_CHECKED
static bool interrupt_check_no_js = false;
void DisallowJsInterruptCallback(v8::Isolate* isolate, void* data) {
CHECK(!i::AllowJavascriptExecution::IsAllowed(
reinterpret_cast<i::Isolate*>(isolate)));
interrupt_check_no_js = true;
}
TEST(RequestInterruptDisallowsJavascript) {
LocalContext env;
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope scope(isolate);
interrupt_check_no_js = false;
isolate->RequestInterrupt(&DisallowJsInterruptCallback, nullptr);
CompileRun("(function(x){return x;})(1);");
CHECK(interrupt_check_no_js);
}
#endif // V8_DISALLOW_JS_IN_API_INTERRUPTS_IS_CHECKED
static v8::Global<Value> function_new_expected_env_global;
static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
v8::Isolate* isolate = info.GetIsolate();
+7 -1
View File
@@ -124,7 +124,13 @@ class InterruptTest {
CHECK(string->ContainsOnlyOneByte());
// Internalize the subject by using it as a computed property name in an
// object.
CompileRun("o = { [subject_string]: 'foo' }");
{
// This test is technically wrong for running JS in a C++ interrupt.
// However we know that the interuptee here is the regexp engine, which
// does not care.
Isolate::AllowJavascriptExecutionScope allow_script(isolate);
CompileRun("o = { [subject_string]: 'foo' }");
}
CHECK(string->IsOneByte());
}
+35
View File
@@ -0,0 +1,35 @@
// Copyright 2026 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.
// Flags: --allow-natives-syntax
var Debug = debug.Debug;
var exception = null;
Debug.setListener(function (event, exec_state, event_data, data) {
if (event == Debug.DebugEvent.Break) {
try {
var sab2 = new SharedArrayBuffer(4);
var i32a2 = new Int32Array(sab2);
Atomics.wait(i32a2, 0, 0, 10);
} catch (e) {
exception = e;
}
}
});
let sab = new SharedArrayBuffer(4);
let i32a = new Int32Array(sab);
let timeout = {
valueOf: function() {
%ScheduleBreak();
return 10;
}
};
Atomics.wait(i32a, 0, 0, timeout);
assertNotNull(exception);
assertTrue(exception.message.includes("cannot be called in this context"));