mirror of
https://github.com/nodejs/node.git
synced 2026-11-09 15:11:11 -05:00
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:
1 parent
49e2608492
commit
ccd648eb0c
11 files changed
+93
-2
No files matched your search
Vendored
+6
@@ -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",
|
||||
|
||||
Vendored
+11
@@ -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
|
||||
|
||||
Vendored
+1
-1
@@ -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); \
|
||||
|
||||
Vendored
+7
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
@@ -532,6 +532,7 @@ void V8Debugger::handleProgramBreak(
|
||||
}
|
||||
});
|
||||
{
|
||||
v8::Isolate::AllowJavascriptExecutionScope allow_script(m_isolate);
|
||||
v8::Context::Scope scope(pausedContext);
|
||||
|
||||
m_inspector->forEachSession(
|
||||
|
||||
+1
@@ -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))
|
||||
|
||||
@@ -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;
|
||||
|
||||
Vendored
+2
@@ -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(®ex))
|
||||
@@ -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);
|
||||
|
||||
Vendored
+20
@@ -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();
|
||||
|
||||
Vendored
+7
-1
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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"));
|
||||
Reference in new issue
Block a user