chore: bump node to v24.22.0 (main) (#55006)

* chore: bump node in DEPS to v24.22.0

* fix(patch): enable the V8 sandbox in shared-cage builds

Upstream now enables the V8 sandbox only for shared-cage builds. Keep
Electron's behaviour of enabling it whenever pointer compression is on,
matching Chromium's V8. The unofficial.gni x86 hunk landed upstream.

Ref: https://github.com/nodejs/node/pull/62237
Ref: https://github.com/nodejs/node/pull/65491

* fix(patch): use names for asymmetric key algorithms

Upstream dropped the BoringSSL guard in DhKeyGenTraits::Setup(), removed
ReadASN1Element() from ncrypto, and no longer includes <openssl/evp.h>
from env.h, so those hunks are no longer needed.

Ref: https://github.com/nodejs/node/pull/65966
Ref: https://github.com/nodejs/node/pull/66108
Ref: https://github.com/nodejs/node/pull/65484

* fix(patch): skip RSA-PSS keygen deprecation tests with BoringSSL

The skip is now upstream.

Ref: https://github.com/nodejs/node/pull/65808

* fix(patch): detach cppgc wrappers from their Realm before it is freed

Upstream's CppgcWrapperList::Cleanup() now pops nodes itself and the
wrapper owns and frees its list node, so the local PopFront/delete hunk
is dropped.

Ref: https://github.com/nodejs/node/pull/65778

* fix(patch): gate jspi flag on V8_ENABLE_WEBASSEMBLY

Ref: https://github.com/nodejs/node/pull/66082

* chore: remove upstreamed patches

- https://github.com/nodejs/node/pull/63985
- https://github.com/nodejs/node/pull/65630
- https://github.com/nodejs/node/pull/64453
- https://github.com/nodejs/node/pull/65778

* chore: update patches (trivial only)

* chore: update filenames.auto.gni

* fix(patch): discover hashes from OpenSSL providers

ncrypto's DigestCache::aliases() now has a function-local static, so
ncrypto needs the no_exit_time_destructors config too.

Ref: https://github.com/nodejs/node/pull/65484

* fix(patch): read the peer certificate chain without consuming it

sk_X509_num() returns size_t in BoringSSL.

Ref: https://github.com/nodejs/node/pull/65602

* fix(patch): fix shared buffer growability validation

Ref: https://github.com/nodejs/node/pull/65845

* chore: update patches (trivial only)

* node#65820: src: fix null pointer call when running without a startup snapshot

SnapshotData::AsEmbedderWrapper() was removed. Both call sites wrap the
embedded snapshot, so use EmbedderSnapshotData::BuiltinSnapshotData().

Ref: https://github.com/nodejs/node/pull/65820

* node#65407: src: apply IsolateSettings when using a snapshot

node::CreateEnvironment() no longer installs the per-isolate message
listener when it builds the environment from a snapshot, so stop
compensating for that and let SetIsolateUpForNode() add it.

Ref: https://github.com/nodejs/node/pull/65407

* test: drop removed wasm rab integration flag from webidl buffer source test

Chromium's V8 removed --experimental-wasm-rab-integration after shipping
it; the new test-internal-webidl-buffer-source.js passes it.

Ref: https://github.com/nodejs/node/pull/65845
Ref: https://chromium-review.googlesource.com/c/v8/v8/+/7708297

* test: skip new rmSync permission error test when the Node suite runs as root

test-fs-rmSync-special-char-additional-error.js is new in v24.22.0 and
relies on a read-only directory blocking removal, which root bypasses;
the Linux Node.js test job runs as root.

Ref: https://github.com/nodejs/node/pull/64453

---------

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: Sam Attard <sattard@anthropic.com>
This commit is contained in:
electron-roller[bot]andSam Attard authored and GitHub committed 2026-10-15 23:11:35 +00:00
1 parent 2766ef64b6
commit 1f3d86bcf8
40 files changed
+328 -1218

No files matched your search

+1 -1
View File
@@ -4,7 +4,7 @@ vars = {
'chromium_version':
'158.0.8105.0',
'node_version':
'v24.21.0',
'v24.22.0',
'nan_version':
'a1b4ba8f4bf2f46d2f270dbbb7bc0af482dc3e32',
'squirrel.mac_version':
+2 -2
View File
@@ -227,8 +227,6 @@ auto_filenames = {
"../third_party/electron_node/src/crypto/crypto_bio.h",
"../third_party/electron_node/src/crypto/crypto_chacha20_poly1305.h",
"../third_party/electron_node/src/crypto/crypto_cipher.h",
"../third_party/electron_node/src/crypto/crypto_clienthello-inl.h",
"../third_party/electron_node/src/crypto/crypto_clienthello.h",
"../third_party/electron_node/src/crypto/crypto_common.h",
"../third_party/electron_node/src/crypto/crypto_context.h",
"../third_party/electron_node/src/crypto/crypto_dh.h",
@@ -241,7 +239,9 @@ auto_filenames = {
"../third_party/electron_node/src/crypto/crypto_keygen.h",
"../third_party/electron_node/src/crypto/crypto_keys.h",
"../third_party/electron_node/src/crypto/crypto_kmac.h",
"../third_party/electron_node/src/crypto/crypto_mac.h",
"../third_party/electron_node/src/crypto/crypto_pbkdf2.h",
"../third_party/electron_node/src/crypto/crypto_pkcs12.h",
"../third_party/electron_node/src/crypto/crypto_pqc.h",
"../third_party/electron_node/src/crypto/crypto_random.h",
"../third_party/electron_node/src/crypto/crypto_rsa.h",
+2 -4
View File
@@ -46,10 +46,8 @@ test_account_for_libc_rm_error_on_electron_linux.patch
fix_use_embedder_perfetto_client_when_available.patch
src_fix_external_reference_registration_for_new_cfunction_lifetime.patch
fix_do_not_pass_removed_jspi_v8_flag.patch
src_keep_global_list_of_addon-provided_cleanup_hooks.patch
src_fix_use-after-free_in_cleanuphookthunkrun.patch
fix_allow_electron_s_linked_bindings_under_the_permission_model.patch
fs_support_removing_read-only_files_in_rmsync_on_windows.patch
src_detach_cppgc_wrappers_from_their_realm_before_it_is_freed.patch
add_missing_includes_of_standard_library_headers_1292.patch
deps_add_missing_standard_library_includes_to_simdjson.patch
test_drop_removed_wasm_rab_integration_flag.patch
test_skip_rmsync_permission_error_test_when_running_as_root.patch
@@ -6,7 +6,7 @@ Subject: Delete deprecated fields on v8::Isolate
https://chromium-review.googlesource.com/c/v8/v8/+/7081397
diff --git a/src/api/environment.cc b/src/api/environment.cc
index ea8ba25085c12f6180c879f19e543a8151e3792d..90d40720a4faad865cf6584bee73e5739d534f36 100644
index 51b7607854b77ceeb3f9e977ce15594cdb4eaeca..6313d5ce1839fafb175c0e0c74eb39445baed467 100644
--- a/src/api/environment.cc
+++ b/src/api/environment.cc
@@ -219,8 +219,6 @@ void SetIsolateCreateParamsForNode(Isolate::CreateParams* params) {
@@ -72,10 +72,10 @@ index 5f04e7085f4246b673f8ea629d03cc8b02e93f2a..60d61aef3f8db2e1d43096de580c5127
inline Environment* Environment::GetCurrent(
diff --git a/src/env.cc b/src/env.cc
index 3f655793d1353619699d42b09b227c729946075f..5389d6e699f32dacfd4d5710258f04f1cb9f9d12 100644
index efda30eb1fb1c18bafd64eed46a6fc72e806a02b..beb700dbe9fabcfe7c154a4c9e0f3dd8c95bc52e 100644
--- a/src/env.cc
+++ b/src/env.cc
@@ -703,13 +703,16 @@ void TrackingTraceStateObserver::UpdateTraceCategoryState() {
@@ -704,13 +704,16 @@ void TrackingTraceStateObserver::UpdateTraceCategoryState() {
void Environment::AssignToContext(Local<v8::Context> context,
Realm* realm,
const ContextInfo& info) {
@@ -96,7 +96,7 @@ index 3f655793d1353619699d42b09b227c729946075f..5389d6e699f32dacfd4d5710258f04f1
// This must not be done before other context fields are initialized.
ContextEmbedderTag::TagNodeContext(context);
@@ -724,12 +727,16 @@ void Environment::AssignToContext(Local<v8::Context> context,
@@ -725,12 +728,16 @@ void Environment::AssignToContext(Local<v8::Context> context,
void Environment::UnassignFromContext(Local<v8::Context> context) {
if (!context.IsEmpty()) {
@@ -119,10 +119,10 @@ index 3f655793d1353619699d42b09b227c729946075f..5389d6e699f32dacfd4d5710258f04f1
UntrackContext(context);
}
diff --git a/src/histogram.cc b/src/histogram.cc
index 7127bb80cc8fa3ecf3d618358bfd7d53dc8b591e..41c3528529b970a319f9c2baab51eb0b801a7fc0 100644
index 30a095b3c43c015d8569f65362b6b3b619290f7f..2e649644acf7aff3be059cd8ec1c96235d2d44e6 100644
--- a/src/histogram.cc
+++ b/src/histogram.cc
@@ -755,7 +755,8 @@ HistogramBase::HistogramBase(
@@ -1873,7 +1873,8 @@ HistogramBase::HistogramBase(Environment* env,
MakeWeak();
wrap->SetAlignedPointerInInternalField(
HistogramImpl::InternalFields::kImplField,
@@ -131,8 +131,8 @@ index 7127bb80cc8fa3ecf3d618358bfd7d53dc8b591e..41c3528529b970a319f9c2baab51eb0b
+ v8::kEmbedderDataTypeTagDefault);
}
HistogramBase::HistogramBase(
@@ -767,7 +768,8 @@ HistogramBase::HistogramBase(
HistogramBase::HistogramBase(Environment* env,
@@ -1883,7 +1884,8 @@ HistogramBase::HistogramBase(Environment* env,
MakeWeak();
wrap->SetAlignedPointerInInternalField(
HistogramImpl::InternalFields::kImplField,
@@ -142,7 +142,7 @@ index 7127bb80cc8fa3ecf3d618358bfd7d53dc8b591e..41c3528529b970a319f9c2baab51eb0b
}
void HistogramBase::MemoryInfo(MemoryTracker* tracker) const {
@@ -1022,7 +1024,8 @@ IntervalHistogram::IntervalHistogram(Environment* env,
@@ -2387,7 +2389,8 @@ IntervalHistogram::IntervalHistogram(Environment* env,
MakeWeak();
wrap->SetAlignedPointerInInternalField(
HistogramImpl::InternalFields::kImplField,
@@ -152,7 +152,7 @@ index 7127bb80cc8fa3ecf3d618358bfd7d53dc8b591e..41c3528529b970a319f9c2baab51eb0b
uv_timer_init(env->event_loop(), &timer_);
}
@@ -1114,7 +1117,8 @@ IterationHistogram::IterationHistogram(Environment* env,
@@ -2479,7 +2482,8 @@ IterationHistogram::IterationHistogram(Environment* env,
MakeWeak();
wrap->SetAlignedPointerInInternalField(
HistogramImpl::InternalFields::kImplField,
@@ -162,7 +162,7 @@ index 7127bb80cc8fa3ecf3d618358bfd7d53dc8b591e..41c3528529b970a319f9c2baab51eb0b
uv_check_init(env->event_loop(), &check_handle_);
uv_prepare_init(env->event_loop(), &prepare_handle_);
uv_unref(reinterpret_cast<uv_handle_t*>(&check_handle_));
@@ -1595,7 +1599,8 @@ HistogramImpl* HistogramImpl::FromJSObject(Local<Value> value) {
@@ -3056,7 +3060,8 @@ HistogramImpl* HistogramImpl::FromJSObject(Local<Value> value) {
auto obj = value.As<Object>();
DCHECK_GE(obj->InternalFieldCount(), HistogramImpl::kInternalFieldCount);
return static_cast<HistogramImpl*>(
@@ -279,7 +279,7 @@ index d4dd93d084d5e58f0c18ef82a51d25be4643ba7a..2709cdb31869d9e030c654d975b07967
void BindingData::MemoryInfo(MemoryTracker* tracker) const {
diff --git a/src/node_realm-inl.h b/src/node_realm-inl.h
index 0af487a9abc9ee1783367ac86b0016ab89e02006..c01cef477aaba52f9894943acede7fb22ed17dcb 100644
index d527a4d4c620a30377ce2c0cdb0ff0cb6a11ec66..97756edfce15b2f3647646146683727b36c0eec3 100644
--- a/src/node_realm-inl.h
+++ b/src/node_realm-inl.h
@@ -22,7 +22,8 @@ inline Realm* Realm::GetCurrent(v8::Local<v8::Context> context) {
@@ -293,7 +293,7 @@ index 0af487a9abc9ee1783367ac86b0016ab89e02006..c01cef477aaba52f9894943acede7fb2
inline Realm* Realm::GetCurrent(
diff --git a/src/node_snapshotable.cc b/src/node_snapshotable.cc
index c3e995adf437413fe956e45c2ccc704d8737de59..ae0613fdf35efcdb4b5917b9ecb3ad12d7bf4976 100644
index e773fb1ed4e777667fa677b402b20d676e9af4a2..643cc0bb244c89178a499082f0532d887e18c24c 100644
--- a/src/node_snapshotable.cc
+++ b/src/node_snapshotable.cc
@@ -1370,7 +1370,8 @@ StartupData SerializeNodeContextData(Local<Context> holder,
@@ -6,10 +6,10 @@ Subject: Remove deprecated `GetIsolate`
https://chromium-review.googlesource.com/c/v8/v8/+/6905244
diff --git a/src/api/environment.cc b/src/api/environment.cc
index 4dea08fafee4379066a7d8af66fb07c7e7a3490c..ea8ba25085c12f6180c879f19e543a8151e3792d 100644
index 312a857537867e408fe2bd1b1a0d1061c41ccf3b..51b7607854b77ceeb3f9e977ce15594cdb4eaeca 100644
--- a/src/api/environment.cc
+++ b/src/api/environment.cc
@@ -792,7 +792,7 @@ std::unique_ptr<MultiIsolatePlatform> MultiIsolatePlatform::Create(
@@ -810,7 +810,7 @@ std::unique_ptr<MultiIsolatePlatform> MultiIsolatePlatform::Create(
MaybeLocal<Object> GetPerContextExports(Local<Context> context,
IsolateData* isolate_data) {
@@ -18,7 +18,7 @@ index 4dea08fafee4379066a7d8af66fb07c7e7a3490c..ea8ba25085c12f6180c879f19e543a81
EscapableHandleScope handle_scope(isolate);
Local<Object> global = context->Global();
@@ -838,7 +838,7 @@ void ProtoThrower(const FunctionCallbackInfo<Value>& info) {
@@ -856,7 +856,7 @@ void ProtoThrower(const FunctionCallbackInfo<Value>& info) {
// This runs at runtime, regardless of whether the context
// is created from a snapshot.
Maybe<void> InitializeContextRuntime(Local<Context> context) {
@@ -27,7 +27,7 @@ index 4dea08fafee4379066a7d8af66fb07c7e7a3490c..ea8ba25085c12f6180c879f19e543a81
HandleScope handle_scope(isolate);
// When `IsCodeGenerationFromStringsAllowed` is true, V8 takes the fast path
@@ -917,7 +917,7 @@ Maybe<void> InitializeContextRuntime(Local<Context> context) {
@@ -935,7 +935,7 @@ Maybe<void> InitializeContextRuntime(Local<Context> context) {
}
Maybe<void> InitializeBaseContextForSnapshot(Local<Context> context) {
@@ -36,7 +36,7 @@ index 4dea08fafee4379066a7d8af66fb07c7e7a3490c..ea8ba25085c12f6180c879f19e543a81
HandleScope handle_scope(isolate);
// Delete `Intl.v8BreakIterator`
@@ -942,7 +942,7 @@ Maybe<void> InitializeBaseContextForSnapshot(Local<Context> context) {
@@ -960,7 +960,7 @@ Maybe<void> InitializeBaseContextForSnapshot(Local<Context> context) {
}
Maybe<void> InitializeMainContextForSnapshot(Local<Context> context) {
@@ -45,7 +45,7 @@ index 4dea08fafee4379066a7d8af66fb07c7e7a3490c..ea8ba25085c12f6180c879f19e543a81
HandleScope handle_scope(isolate);
// Initialize the default values.
@@ -960,7 +960,7 @@ Maybe<void> InitializeMainContextForSnapshot(Local<Context> context) {
@@ -978,7 +978,7 @@ Maybe<void> InitializeMainContextForSnapshot(Local<Context> context) {
MaybeLocal<Object> InitializePrivateSymbols(Local<Context> context,
IsolateData* isolate_data) {
CHECK(isolate_data);
@@ -54,7 +54,7 @@ index 4dea08fafee4379066a7d8af66fb07c7e7a3490c..ea8ba25085c12f6180c879f19e543a81
EscapableHandleScope scope(isolate);
Context::Scope context_scope(context);
@@ -984,7 +984,7 @@ MaybeLocal<Object> InitializePrivateSymbols(Local<Context> context,
@@ -1002,7 +1002,7 @@ MaybeLocal<Object> InitializePrivateSymbols(Local<Context> context,
MaybeLocal<Object> InitializePerIsolateSymbols(Local<Context> context,
IsolateData* isolate_data) {
CHECK(isolate_data);
@@ -63,7 +63,7 @@ index 4dea08fafee4379066a7d8af66fb07c7e7a3490c..ea8ba25085c12f6180c879f19e543a81
EscapableHandleScope scope(isolate);
Context::Scope context_scope(context);
@@ -1010,7 +1010,7 @@ MaybeLocal<Object> InitializePerIsolateSymbols(Local<Context> context,
@@ -1028,7 +1028,7 @@ MaybeLocal<Object> InitializePerIsolateSymbols(Local<Context> context,
Maybe<void> InitializePrimordials(Local<Context> context,
IsolateData* isolate_data) {
// Run per-context JS files.
@@ -85,10 +85,10 @@ index cc60ddddb037e0279615bbe24821eb20fd8da677..37d83e41b618a07aca98118260abe961
return handle;
diff --git a/src/crypto/crypto_context.cc b/src/crypto/crypto_context.cc
index 176c69dfe7a7d1f6dfe33fcc7ffc470e50df50d2..9fbca1812491c8a181ab791eeb33a18f906af66f 100644
index 114b0c920882dd267f057c6414563c57e91eb236..ec217aadc4a34ce09742c3b9490634727f387c1d 100644
--- a/src/crypto/crypto_context.cc
+++ b/src/crypto/crypto_context.cc
@@ -1173,7 +1173,7 @@ bool ArrayOfStringsToX509s(Local<Context> context,
@@ -1174,7 +1174,7 @@ bool ArrayOfStringsToX509s(Local<Context> context,
Local<Array> cert_array,
std::vector<X509*>* certs) {
ClearErrorOnReturn clear_error_on_return;
@@ -98,7 +98,7 @@ index 176c69dfe7a7d1f6dfe33fcc7ffc470e50df50d2..9fbca1812491c8a181ab791eeb33a18f
uint32_t array_length = cert_array->Length();
diff --git a/src/crypto/crypto_x509.cc b/src/crypto/crypto_x509.cc
index 82da68d8eef06c57aae76f2b54eeb09db5b41ecf..9d3fddd63d1e333674633752b2b5243c8d9954c7 100644
index 1bf003f830812664ad903dbdfe30366835767c0b..337cd5899f9ced88e9d2eda61ba194b7f70b910a 100644
--- a/src/crypto/crypto_x509.cc
+++ b/src/crypto/crypto_x509.cc
@@ -109,7 +109,7 @@ MaybeLocal<Value> ToV8Value(Local<Context> context, BIOPointer&& bio) {
@@ -133,10 +133,10 @@ index 31277621e92b4d3583a67140f4ab8a74a9c6df3b..caa109871b71926f3355491767b8064b
// Recreate the buffer in the constructor.
InternalFieldInfo* casted_info = static_cast<InternalFieldInfo*>(info);
diff --git a/src/env.cc b/src/env.cc
index c68bb8e4854a301b6899d2f7183b77dd9ff98c31..3f655793d1353619699d42b09b227c729946075f 100644
index 7674b06f7018020f87c32316a66eebc04720ab5e..efda30eb1fb1c18bafd64eed46a6fc72e806a02b 100644
--- a/src/env.cc
+++ b/src/env.cc
@@ -1818,10 +1818,10 @@ void AsyncHooks::Deserialize(Local<Context> context) {
@@ -1935,10 +1935,10 @@ void AsyncHooks::Deserialize(Local<Context> context) {
context->GetDataFromSnapshotOnce<Array>(
info_->js_execution_async_resources).ToLocalChecked();
} else {
@@ -149,7 +149,7 @@ index c68bb8e4854a301b6899d2f7183b77dd9ff98c31..3f655793d1353619699d42b09b227c72
// The native_execution_async_resources_ field requires v8::Local<> instances
// for async calls whose resources were on the stack as JS objects when they
@@ -1861,7 +1861,7 @@ AsyncHooks::SerializeInfo AsyncHooks::Serialize(Local<Context> context,
@@ -1978,7 +1978,7 @@ AsyncHooks::SerializeInfo AsyncHooks::Serialize(Local<Context> context,
info.async_id_fields = async_id_fields_.Serialize(context, creator);
if (!js_execution_async_resources_.IsEmpty()) {
info.js_execution_async_resources = creator->AddData(
@@ -283,10 +283,10 @@ index fbcf8f0f99ccaac583040e1ecebcbf65bd03cfa6..6934e3ca3751091e6ebc7802dabf8b50
CHECK(!env->temporary_required_module_facade_original.IsEmpty());
return env->temporary_required_module_facade_original.Get(isolate);
diff --git a/src/node.h b/src/node.h
index 952d51946d9412c376dfe305a2c5fd564b60998c..b0ba5d00ff170a61ee85d4959b879f1515e28484 100644
index 564ba432f023ea0575bba72e1a17816faf4d830c..ff11c2ef06a720df01bbdd784746066a7c23ee5b 100644
--- a/src/node.h
+++ b/src/node.h
@@ -1160,7 +1160,7 @@ NODE_DEPRECATED("Use v8::Date::ValueOf() directly",
@@ -1168,7 +1168,7 @@ NODE_DEPRECATED("Use v8::Date::ValueOf() directly",
#define NODE_DEFINE_CONSTANT(target, constant) \
do { \
@@ -295,7 +295,7 @@ index 952d51946d9412c376dfe305a2c5fd564b60998c..b0ba5d00ff170a61ee85d4959b879f15
v8::Local<v8::Context> context = isolate->GetCurrentContext(); \
v8::Local<v8::String> constant_name = v8::String::NewFromUtf8Literal( \
isolate, #constant, v8::NewStringType::kInternalized); \
@@ -1176,7 +1176,7 @@ NODE_DEPRECATED("Use v8::Date::ValueOf() directly",
@@ -1184,7 +1184,7 @@ NODE_DEPRECATED("Use v8::Date::ValueOf() directly",
#define NODE_DEFINE_HIDDEN_CONSTANT(target, constant) \
do { \
@@ -305,10 +305,10 @@ index 952d51946d9412c376dfe305a2c5fd564b60998c..b0ba5d00ff170a61ee85d4959b879f15
v8::Local<v8::String> constant_name = v8::String::NewFromUtf8Literal( \
isolate, #constant, v8::NewStringType::kInternalized); \
diff --git a/src/node_blob.cc b/src/node_blob.cc
index d05a693120f2643dc01395493d51db3d3f95f9b7..57d35358fbfd71bc0ef01f8c83f5f00f0b02b8cf 100644
index ef148203713880ed3f56698613f9cd9c78ff1fb0..a04bc2be0ef5ab65ac39062de0549bb3e4b168c1 100644
--- a/src/node_blob.cc
+++ b/src/node_blob.cc
@@ -580,7 +580,7 @@ void BlobBindingData::Deserialize(Local<Context> context,
@@ -579,7 +579,7 @@ void BlobBindingData::Deserialize(Local<Context> context,
int index,
InternalFieldInfoBase* info) {
DCHECK_IS_SNAPSHOT_SLOT(index);
@@ -432,10 +432,10 @@ index 5550a4bee3ce9ec8759d216335a9b2b96e20c96e..b38c2f75a92f2d6c1b9c6e7b7aca9246
Local<Array> keys;
if (!entries->GetOwnPropertyNames(context).ToLocal(&keys))
diff --git a/src/node_errors.cc b/src/node_errors.cc
index d79d8d0a1ed63731147007f264541545d724980e..7b29370686a9e4d408f81d7b8bd16c3d533bf33b 100644
index 9a7c89b22fe358808fbd9570c7239b4e040ab450..026ee86b455c327fbd5be3472cd504097bf0258b 100644
--- a/src/node_errors.cc
+++ b/src/node_errors.cc
@@ -651,7 +651,7 @@ v8::ModifyCodeGenerationFromStringsResult ModifyCodeGenerationFromStrings(
@@ -654,7 +654,7 @@ v8::ModifyCodeGenerationFromStringsResult ModifyCodeGenerationFromStrings(
v8::Local<v8::Context> context,
v8::Local<v8::Value> source,
bool is_code_like) {
@@ -444,7 +444,7 @@ index d79d8d0a1ed63731147007f264541545d724980e..7b29370686a9e4d408f81d7b8bd16c3d
if (context->GetNumberOfEmbedderDataFields() <=
ContextEmbedderIndex::kAllowCodeGenerationFromStrings) {
@@ -1073,7 +1073,7 @@ const char* errno_string(int errorno) {
@@ -1076,7 +1076,7 @@ const char* errno_string(int errorno) {
}
void PerIsolateMessageListener(Local<Message> message, Local<Value> error) {
@@ -453,7 +453,7 @@ index d79d8d0a1ed63731147007f264541545d724980e..7b29370686a9e4d408f81d7b8bd16c3d
switch (message->ErrorLevel()) {
case Isolate::MessageErrorLevel::kMessageWarning: {
Environment* env = Environment::GetCurrent(isolate);
@@ -1238,7 +1238,7 @@ void Initialize(Local<Object> target,
@@ -1241,7 +1241,7 @@ void Initialize(Local<Object> target,
SetMethod(
context, target, "getErrorSourcePositions", GetErrorSourcePositions);
@@ -463,10 +463,10 @@ index d79d8d0a1ed63731147007f264541545d724980e..7b29370686a9e4d408f81d7b8bd16c3d
READONLY_PROPERTY(target, "exitCodes", exit_codes);
diff --git a/src/node_file.cc b/src/node_file.cc
index c2bc9dfaa6a0d10624362d217fe591d8465a6c3a..15a433fc2c1fde03d1e875a88c238bc36fcc6c93 100644
index 78d98080323698dc619ebdffda7cb3849d4414bc..fb5aaa3ab08923bf9c1c4e767bad2881510633e8 100644
--- a/src/node_file.cc
+++ b/src/node_file.cc
@@ -4194,7 +4194,7 @@ void BindingData::Deserialize(Local<Context> context,
@@ -4272,7 +4272,7 @@ void BindingData::Deserialize(Local<Context> context,
int index,
InternalFieldInfoBase* info) {
DCHECK_IS_SNAPSHOT_SLOT(index);
@@ -551,10 +551,10 @@ index a33748d360c96368fa623b31ef0711eaaa04267f..d4dd93d084d5e58f0c18ef82a51d25be
// Recreate the buffer in the constructor.
InternalFieldInfo* casted_info = static_cast<InternalFieldInfo*>(info);
diff --git a/src/node_realm.cc b/src/node_realm.cc
index 6d2e4eb641a8ffaacf4aebd3522008a285387a30..47bd7d9f19077ac7a558c73db5f51bdf8da291e7 100644
index 05c37067124898c306ae4eadb986cf038284730c..4444b7d6c52dff2d5ea4c5509df7d932789c8e3a 100644
--- a/src/node_realm.cc
+++ b/src/node_realm.cc
@@ -22,7 +22,7 @@ using v8::String;
@@ -20,7 +20,7 @@ using v8::TryCatch;
using v8::Value;
Realm::Realm(Environment* env, v8::Local<v8::Context> context, Kind kind)
@@ -562,7 +562,7 @@ index 6d2e4eb641a8ffaacf4aebd3522008a285387a30..47bd7d9f19077ac7a558c73db5f51bdf
+ : env_(env), isolate_(v8::Isolate::GetCurrent()), kind_(kind) {
context_.Reset(isolate_, context);
env->AssignToContext(context, this, ContextInfo(""));
// The environment can also purge empty wrappers in the check callback,
}
diff --git a/src/node_report.cc b/src/node_report.cc
index 04c5d415c3c67ef9eba962bc15e738f0df6a005a..b8bb41e88888e426689298a611fc87cb3d8e0caf 100644
--- a/src/node_report.cc
@@ -577,7 +577,7 @@ index 04c5d415c3c67ef9eba962bc15e738f0df6a005a..b8bb41e88888e426689298a611fc87cb
if (!error_obj->GetOwnPropertyNames(context).ToLocal(&keys)) {
return writer->json_objectend(); // the end of 'errorProperties'
diff --git a/src/node_snapshotable.cc b/src/node_snapshotable.cc
index 41b0773f4c37a016cfa55aff6bb03baf50905b32..c3e995adf437413fe956e45c2ccc704d8737de59 100644
index 1d0702ba59be0653b417afc8729306b307ca6272..e773fb1ed4e777667fa677b402b20d676e9af4a2 100644
--- a/src/node_snapshotable.cc
+++ b/src/node_snapshotable.cc
@@ -1675,7 +1675,7 @@ void BindingData::Deserialize(Local<Context> context,
@@ -590,10 +590,10 @@ index 41b0773f4c37a016cfa55aff6bb03baf50905b32..c3e995adf437413fe956e45c2ccc704d
// Recreate the buffer in the constructor.
InternalFieldInfo* casted_info = static_cast<InternalFieldInfo*>(info);
diff --git a/src/node_sqlite.cc b/src/node_sqlite.cc
index ee6a2ece542610cb6e262cca29f9884da6bb2ae5..91ae8c9d31f5c8984c25c1030238fbe0db5c95a2 100644
index a0a13c3537e7ae95ae1bf535ec9b50b2469e78a5..f21c7deea5edd85198bb4c015af0d38b42e7d8c9 100644
--- a/src/node_sqlite.cc
+++ b/src/node_sqlite.cc
@@ -2676,7 +2676,7 @@ bool StatementSync::BindParams(const FunctionCallbackInfo<Value>& args) {
@@ -2886,7 +2886,7 @@ bool StatementSync::BindParams(const FunctionCallbackInfo<Value>& args) {
if (args[0]->IsObject() && !args[0]->IsArrayBufferView() &&
!args[0]->IsArrayBuffer() && !args[0]->IsSharedArrayBuffer()) {
Local<Object> obj = args[0].As<Object>();
@@ -688,10 +688,10 @@ index 9bebd4fb1b86b97df59aa2a04106c1916ca658bc..afd17511610cc0977874190aeca9e5e6
Storage* storage;
ASSIGN_OR_RETURN_UNWRAP(&storage, info.This());
diff --git a/src/node_worker.cc b/src/node_worker.cc
index ed3aa30caac3f47691c4a7262e671589c3bace7b..3d6e0bdaaec133e89e947971b37cf0d8bdc08e38 100644
index b45ee62d0e13d24c013102ca2b463a2517d92907..91949db98400298ae7a770a76c387fcf2b388571 100644
--- a/src/node_worker.cc
+++ b/src/node_worker.cc
@@ -1466,8 +1466,6 @@ void GetEnvMessagePort(const FunctionCallbackInfo<Value>& args) {
@@ -1459,8 +1459,6 @@ void GetEnvMessagePort(const FunctionCallbackInfo<Value>& args) {
Local<Object> port = env->message_port();
CHECK_IMPLIES(!env->is_main_thread(), !port.IsEmpty());
if (!port.IsEmpty()) {
+12 -21
View File
@@ -15,20 +15,20 @@ was missing gypi_values.node_pdl_files from its inputs, causing Ninja to skip
regeneration when PDL domain files changed. Should be upstreamed.
diff --git a/configure.py b/configure.py
index 3c3b5a34925b5e578aa4b507674e15b88c4035c7..65da589f59e1eb7fc82c08dc05429fb19a1772eb 100755
index b826e24e3f474f4ec89bafd0a6db3081fadfbef8..1b35f195f7ee7547544cc954baf95c725afa8d0b 100755
--- a/configure.py
+++ b/configure.py
@@ -1987,7 +1987,7 @@ def configure_v8(o, configs):
# Until we manage to get rid of all those, v8_enable_sandbox cannot be used.
# Note that enabling pointer compression without enabling sandbox is unsupported by V8,
# so this can be broken at any time.
- o['variables']['v8_enable_sandbox'] = 0
@@ -1955,7 +1955,7 @@ def configure_v8(o, configs):
# Like V8's own default, the sandbox goes with the shared pointer compression
# cage. Multi-cage builds give every IsolateGroup its own sandbox, which the
# array buffer allocator does not know about yet.
- o['variables']['v8_enable_sandbox'] = 1 if options.pointer_compression_shared_cage else 0
+ o['variables']['v8_enable_sandbox'] = 1 if options.enable_pointer_compression else 0
# We set v8_enable_pointer_compression_shared_cage to 0 always, even when
# pointer compression is enabled so that we don't accidentally enable shared
# cage mode when pointer compression is on.
o['variables']['v8_enable_pointer_compression_shared_cage'] = 1 if options.pointer_compression_shared_cage else 0
o['variables']['v8_enable_external_code_space'] = 1 if options.enable_pointer_compression else 0
o['variables']['v8_enable_31bit_smis_on_64bit_arch'] = 1 if options.enable_pointer_compression else 0
diff --git a/node.gni b/node.gni
index 41f200189a34e150e4c8f25da2a72c2108259720..156fee33b3813fe4d94a1c9585f217a99dbfbd5f 100644
index 28ef444b72c139eb9253122dfaf8b14c8108eac6..0d0438ba8f478a08949ea07cad6c349d15060be9 100644
--- a/node.gni
+++ b/node.gni
@@ -5,10 +5,10 @@
@@ -70,7 +70,7 @@ index 41f200189a34e150e4c8f25da2a72c2108259720..156fee33b3813fe4d94a1c9585f217a9
+ use_system_histogram = false
}
assert(!node_enable_inspector || node_use_openssl,
# Link against shared copies of the bundled dependencies instead of building
diff --git a/src/node_builtins.cc b/src/node_builtins.cc
index bf1276f82412b7321732995cfc2f93d9cce961a2..cfd8c8c9c7d8911be7b3a66f4695e54f1022a678 100644
--- a/src/node_builtins.cc
@@ -309,18 +309,9 @@ index 856878c33681a73d41016729dabe48b0a6a80589..91a11852d206b65485fe90fd037a0bd1
if sys.platform == 'win32':
files = [ x.replace('\\', '/') for x in files ]
diff --git a/unofficial.gni b/unofficial.gni
index aa78f9ce60c0439536eaf6e23880e30ebef0e1a9..7265e09bf7601afe76463f528ffb385db796e093 100644
index aa35cd4664e9ed43b46e1ad62eaabcf1cfe40135..7265e09bf7601afe76463f528ffb385db796e093 100644
--- a/unofficial.gni
+++ b/unofficial.gni
@@ -94,7 +94,7 @@ template("node_gn_build") {
"-Wno-unused-function",
]
- if (current_cpu == "x86") {
+ if (target_cpu == "x86") {
node_arch = "ia32"
} else {
node_arch = target_cpu
@@ -147,32 +147,42 @@ template("node_gn_build") {
public_configs = [
":node_external_config",
@@ -7,10 +7,10 @@ Subject: build: ensure native module compilation fails if not using a new
This should not be upstreamed, it is a quality-of-life patch for downstream module builders.
diff --git a/common.gypi b/common.gypi
index 83e0691d4a2d86bed83a3caf24d795f14af464bd..7e67f7575c866c7628c980c77d131a4766caf58f 100644
index bc690955d3da82216abfe73c92d5ec9c2dbaa784..00b5cea77e949befd234a474a7f109ba47d24d8b 100644
--- a/common.gypi
+++ b/common.gypi
@@ -93,6 +93,8 @@
@@ -96,6 +96,8 @@
'v8_use_perfetto': 0,
'tsan%': 0,
@@ -19,7 +19,7 @@ index 83e0691d4a2d86bed83a3caf24d795f14af464bd..7e67f7575c866c7628c980c77d131a47
##### end V8 defaults #####
'conditions': [
@@ -344,7 +346,8 @@
@@ -347,7 +349,8 @@
'_GLIBCXX_USE_CXX11_ABI=1',
# This help forks when building Node.js on a 32-bit arch as
# libuv is always compiled with _FILE_OFFSET_BITS=64
@@ -29,7 +29,7 @@ index 83e0691d4a2d86bed83a3caf24d795f14af464bd..7e67f7575c866c7628c980c77d131a47
],
# Forcibly disable -Werror. We support a wide range of compilers, it's
@@ -501,6 +504,11 @@
@@ -504,6 +507,11 @@
}],
],
}],
@@ -42,10 +42,10 @@ index 83e0691d4a2d86bed83a3caf24d795f14af464bd..7e67f7575c866c7628c980c77d131a47
# list in v8/BUILD.gn.
['node_enable_experimentals == "true"', {
diff --git a/configure.py b/configure.py
index 65da589f59e1eb7fc82c08dc05429fb19a1772eb..443818802df9bf62c17aa783617ec5b932cedf81 100755
index 1b35f195f7ee7547544cc954baf95c725afa8d0b..172aef2c5194574eb298462588ecf76ae2a2e366 100755
--- a/configure.py
+++ b/configure.py
@@ -1959,6 +1959,7 @@ def configure_library(lib, output, pkgname=None):
@@ -1930,6 +1930,7 @@ def configure_library(lib, output, pkgname=None):
def configure_v8(o, configs):
set_configuration_variable(configs, 'v8_enable_v8_checks', release=0, debug=1)
@@ -54,7 +54,7 @@ index 65da589f59e1eb7fc82c08dc05429fb19a1772eb..443818802df9bf62c17aa783617ec5b9
o['variables']['v8_enable_javascript_promise_hooks'] = 1
o['variables']['v8_enable_lite_mode'] = 1 if options.v8_lite_mode else 0
diff --git a/src/node.h b/src/node.h
index d922352b19414cc6aac1ddd4cf4c6001afc2aa76..3bd4849bb93340569c0067fedd37fefeebff4eb5 100644
index 9f9ba48eb8e2ffcac85dd2147fe631204f2a604e..cba83119bfaf88b360b2f1220611a0c642ec7364 100644
--- a/src/node.h
+++ b/src/node.h
@@ -22,6 +22,12 @@
@@ -14,7 +14,7 @@ and
This patch can be removed once this is fixed upstream in simdjson.
diff --git a/deps/simdjson/simdjson.h b/deps/simdjson/simdjson.h
index afcca85ad6bf7835f8f914d9d417f8347ad3db5c..a836ca8cfdb2fa7348ef7c2cf9c21f18ade5707b 100644
index 43fe09631c0135af616f9df082c82ba87c434b72..91b0fc22e5965ddb3378887867b5c5c951ae7226 100644
--- a/deps/simdjson/simdjson.h
+++ b/deps/simdjson/simdjson.h
@@ -4408,12 +4408,17 @@ private:
@@ -35,7 +35,7 @@ index afcca85ad6bf7835f8f914d9d417f8347ad3db5c..a836ca8cfdb2fa7348ef7c2cf9c21f18
namespace simdjson {
namespace internal {
@@ -5115,6 +5120,9 @@ simdjson_inline bool padded_memory_map::is_valid() const noexcept {
@@ -5116,6 +5121,9 @@ simdjson_inline bool padded_memory_map::is_valid() const noexcept {
} // namespace simdjson
@@ -45,7 +45,7 @@ index afcca85ad6bf7835f8f914d9d417f8347ad3db5c..a836ca8cfdb2fa7348ef7c2cf9c21f18
inline simdjson::padded_string operator ""_padded(const char *str, size_t len) {
return simdjson::padded_string(str, len);
}
@@ -5123,6 +5131,8 @@ inline simdjson::padded_string operator ""_padded(const char8_t *str, size_t len
@@ -5124,6 +5132,8 @@ inline simdjson::padded_string operator ""_padded(const char8_t *str, size_t len
return simdjson::padded_string(reinterpret_cast<const char *>(str), len);
}
#endif
@@ -54,7 +54,7 @@ index afcca85ad6bf7835f8f914d9d417f8347ad3db5c..a836ca8cfdb2fa7348ef7c2cf9c21f18
#endif // SIMDJSON_PADDED_STRING_INL_H
/* end file simdjson/padded_string-inl.h */
@@ -72764,12 +72774,16 @@ simdjson_inline simdjson_warn_unused std::unique_ptr<ondemand::parser>& parser::
@@ -72847,12 +72857,16 @@ simdjson_inline simdjson_warn_unused std::unique_ptr<ondemand::parser>& parser::
return parser_instance;
}
@@ -71,7 +71,7 @@ index afcca85ad6bf7835f8f914d9d417f8347ad3db5c..a836ca8cfdb2fa7348ef7c2cf9c21f18
} // namespace ondemand
} // namespace arm64
@@ -86146,12 +86160,16 @@ simdjson_inline simdjson_warn_unused std::unique_ptr<ondemand::parser>& parser::
@@ -86238,12 +86252,16 @@ simdjson_inline simdjson_warn_unused std::unique_ptr<ondemand::parser>& parser::
return parser_instance;
}
@@ -19,6 +19,18 @@ index ab7dc27de3e304f6d912d5834da47e3b4eb25495..b6c0fd4ceee989dac55c7d54e52fef18
sources = gypi_values.ada_sources
}
}
diff --git a/deps/ncrypto/unofficial.gni b/deps/ncrypto/unofficial.gni
index dad4fbbf16f060a76bc7842135506f30aed7ffc0..d874d4b1e4079b392ba7652ea6bfc7de5e920626 100644
--- a/deps/ncrypto/unofficial.gni
+++ b/deps/ncrypto/unofficial.gni
@@ -26,6 +26,7 @@ template("ncrypto_gn_build") {
source_set(target_name) {
forward_variables_from(invoker, "*")
public_configs = [ ":ncrypto_config" ]
+ configs += [ "//build/config/compiler:no_exit_time_destructors" ]
defines = [
"NCRYPTO_ENGINE_COMPAT=1",
"OPENSSL_SUPPRESS_DEPRECATED",
diff --git a/unofficial.gni b/unofficial.gni
index ca6fab3f2fa162c5292687e4218f7ea2c8bd4b46..1ccb4f3274b50f74e4ea5c309db155d7e0027560 100644
--- a/unofficial.gni
@@ -19,7 +19,7 @@ We're still exploring ways to upstream this. This patch can be removed
once Node.js vendors a simdjson release that includes these headers.
diff --git a/deps/simdjson/simdjson.cpp b/deps/simdjson/simdjson.cpp
index 7b8b0c44f05767da92f631d7d117936c556f0db8..975b59f6f3a0d30bdbb62ac292fd95635fab7a04 100644
index 71f443b3d2bb4394009600cde34935ec25eff30b..505dc6406f6e14858124a823170f9fbd2fb7c7d8 100644
--- a/deps/simdjson/simdjson.cpp
+++ b/deps/simdjson/simdjson.cpp
@@ -3,6 +3,12 @@
@@ -36,7 +36,7 @@ index 7b8b0c44f05767da92f631d7d117936c556f0db8..975b59f6f3a0d30bdbb62ac292fd9563
/* begin file base.h */
#ifndef SIMDJSON_SRC_BASE_H
diff --git a/deps/simdjson/simdjson.h b/deps/simdjson/simdjson.h
index a836ca8cfdb2fa7348ef7c2cf9c21f18ade5707b..91047857bb250b5d2c2903f153ff59297b526988 100644
index 91b0fc22e5965ddb3378887867b5c5c951ae7226..919e9532f00092997710882a8b223e7b8c1f1096 100644
--- a/deps/simdjson/simdjson.h
+++ b/deps/simdjson/simdjson.h
@@ -4,6 +4,14 @@
@@ -62,7 +62,7 @@ eliminating the Node bootstrap recompile.
config following https://chromium-review.googlesource.com/c/v8/v8/+/7808546.
diff --git a/node.gni b/node.gni
index 156fee33b3813fe4d94a1c9585f217a99dbfbd5f..a443ff52ca1dda5cb2cfdfe5241076836a33b8fc 100644
index 0d0438ba8f478a08949ea07cad6c349d15060be9..55f35c4c376e66be291631cff8b1acf266ff41a3 100644
--- a/node.gni
+++ b/node.gni
@@ -31,6 +31,13 @@ declare_args() {
@@ -110,12 +110,12 @@ index 156fee33b3813fe4d94a1c9585f217a99dbfbd5f..a443ff52ca1dda5cb2cfdfe524107683
# Build with Amaro (TypeScript utils).
node_use_amaro = true
diff --git a/src/api/embed_helpers.cc b/src/api/embed_helpers.cc
index c1bcb3948c4cf68b36dbb1ea985bfb02267ad724..b9ddc1e2139c1a3b869a27f088e6e64688efa0f0 100644
index 051110c9c6e96b91fa966f9dc8cd3a161db6d0b2..7b78ed07d020c6553c9fdf449fa057e5daef54a3 100644
--- a/src/api/embed_helpers.cc
+++ b/src/api/embed_helpers.cc
@@ -131,6 +131,15 @@ CommonEnvironmentSetup::CommonEnvironmentSetup(
isolate = impl_->isolate = Isolate::Allocate(GetOrCreateIsolateGroup());
platform->RegisterIsolate(isolate, loop);
params.cpp_heap =
v8::CppHeap::Create(platform, v8::CppHeapCreateParams{{}}).release();
+ // Electron: extend an existing V8 startup snapshot rather than build the
+ // heap from scratch (Electron's V8 has external startup data / the
@@ -238,7 +238,7 @@ index 664f878c0671db76cbf68116d224606243ddf501..4ed6d6ecf12ea92129f4d7b7fdb59bcb
return nullptr;
}
diff --git a/src/node_snapshotable.cc b/src/node_snapshotable.cc
index ae0613fdf35efcdb4b5917b9ecb3ad12d7bf4976..bc48096932b0a1004aec4317dc0c265bd6f1c045 100644
index 643cc0bb244c89178a499082f0532d887e18c24c..2568e857f299f058c15e41b7990412c51064767e 100644
--- a/src/node_snapshotable.cc
+++ b/src/node_snapshotable.cc
@@ -866,6 +866,19 @@ const std::vector<intptr_t>& SnapshotBuilder::CollectExternalReferences() {
@@ -8,10 +8,10 @@ an ExternalPointerTypeTag parameter. Use kExternalPointerTypeTagDefault
for all existing call sites.
diff --git a/src/crypto/crypto_context.cc b/src/crypto/crypto_context.cc
index 9fbca1812491c8a181ab791eeb33a18f906af66f..03a3b93f0cf60a6eab4128a8e58a240169ed2d06 100644
index ec217aadc4a34ce09742c3b9490634727f387c1d..e857de97428bde0bcd76f486fe29f1befa076e2c 100644
--- a/src/crypto/crypto_context.cc
+++ b/src/crypto/crypto_context.cc
@@ -2625,7 +2625,7 @@ int SecureContext::TicketCompatibilityCallback(SSL* ssl,
@@ -2622,7 +2622,7 @@ int SecureContext::TicketCompatibilityCallback(SSL* ssl,
void SecureContext::CtxGetter(const FunctionCallbackInfo<Value>& info) {
SecureContext* sc;
ASSIGN_OR_RETURN_UNWRAP(&sc, info.This());
@@ -21,7 +21,7 @@ index 9fbca1812491c8a181ab791eeb33a18f906af66f..03a3b93f0cf60a6eab4128a8e58a2401
}
diff --git a/src/js_native_api_v8.cc b/src/js_native_api_v8.cc
index 75ce4c921b5acf5d612aeb5a7720b5874b6066ac..6c87611f7cbaf8a0b4c04f812f65381ede112056 100644
index 5c4a7b611888664ad70e48fb240be7320bac032b..29e2e1808a3f42a35d9478f2f8949037b0011880 100644
--- a/src/js_native_api_v8.cc
+++ b/src/js_native_api_v8.cc
@@ -356,7 +356,7 @@ inline napi_status Unwrap(napi_env env,
@@ -100,10 +100,10 @@ index 757d39558f7853d39ee0d574152bb3810cfa3ca5..51c097e69388a516aa7a9239053367fa
env->compile_cache_handler()->MaybeSave(cache_entry, utf8.ToStringView());
}
diff --git a/src/node_util.cc b/src/node_util.cc
index ce381c00888b032c281938a7bab334058e075ec8..6d3373caae6c5cc22e16fc32e7ea007178aa1a20 100644
index c3a6fbed06efc92e3cc0ac59ab51c8b802033c81..39523bd256c8bf22597ba79dd06ea451025ffabb 100644
--- a/src/node_util.cc
+++ b/src/node_util.cc
@@ -93,7 +93,7 @@ static void GetExternalValue(
@@ -96,7 +96,7 @@ static void GetExternalValue(
Isolate* isolate = args.GetIsolate();
Local<External> external = args[0].As<External>();
@@ -113,10 +113,10 @@ index ce381c00888b032c281938a7bab334058e075ec8..6d3373caae6c5cc22e16fc32e7ea0071
Local<BigInt> ret = BigInt::NewFromUnsigned(isolate, value);
args.GetReturnValue().Set(ret);
diff --git a/src/stream_base.cc b/src/stream_base.cc
index f57f75e5f2750a8f56258c043717c15adad1cf2a..287a41b3af00ea937ca0267a230b94c9c6566f00 100644
index ad9affc538732fcc88ef839598b9cbf7e22fd79d..74717fbae8776bdba7c288308c5c1cc7fc8393ef 100644
--- a/src/stream_base.cc
+++ b/src/stream_base.cc
@@ -649,7 +649,7 @@ void StreamBase::GetExternal(const FunctionCallbackInfo<Value>& args) {
@@ -685,7 +685,7 @@ void StreamBase::GetExternal(const FunctionCallbackInfo<Value>& args) {
StreamBase* wrap = StreamBase::FromObject(args.This().As<Object>());
if (wrap == nullptr) return;
@@ -50,10 +50,10 @@ index e7311af43237c9459263d15c6b10749b92a5b7d3..66f71c3845361cc380d89ec50472658b
const maybeMain = resolvedOption <= legacyMainResolveExtensionsIndexes.kResolvedByMainIndexNode ?
packageConfig.main || './' : '';
diff --git a/src/node_file.cc b/src/node_file.cc
index a576b4a9d4ebbee73cd3ea038ab2d84210fcc21b..c2bc9dfaa6a0d10624362d217fe591d8465a6c3a 100644
index acb9e9d669835a5433a47a531b79c3609070d9a0..78d98080323698dc619ebdffda7cb3849d4414bc 100644
--- a/src/node_file.cc
+++ b/src/node_file.cc
@@ -3943,13 +3943,25 @@ static void CpSyncCopyDir(const FunctionCallbackInfo<Value>& args) {
@@ -4021,13 +4021,25 @@ static void CpSyncCopyDir(const FunctionCallbackInfo<Value>& args) {
}
BindingData::FilePathIsFileReturnType BindingData::FilePathIsFile(
@@ -80,7 +80,7 @@ index a576b4a9d4ebbee73cd3ea038ab2d84210fcc21b..c2bc9dfaa6a0d10624362d217fe591d8
uv_fs_t req;
int rc = uv_fs_stat(env->event_loop(), &req, file_path.c_str(), nullptr);
@@ -4007,6 +4019,11 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
@@ -4085,6 +4097,11 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
std::optional<std::string> initial_file_path;
std::string file_path;
@@ -92,7 +92,7 @@ index a576b4a9d4ebbee73cd3ea038ab2d84210fcc21b..c2bc9dfaa6a0d10624362d217fe591d8
if (args.Length() >= 2 && args[1]->IsString()) {
auto package_config_main = Utf8Value(isolate, args[1]).ToString();
@@ -4027,7 +4044,7 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
@@ -4105,7 +4122,7 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
BufferValue buff_file_path(isolate, local_file_path);
ToNamespacedPath(env, &buff_file_path);
@@ -101,7 +101,7 @@ index a576b4a9d4ebbee73cd3ea038ab2d84210fcc21b..c2bc9dfaa6a0d10624362d217fe591d8
case BindingData::FilePathIsFileReturnType::kIsFile:
return args.GetReturnValue().Set(i);
case BindingData::FilePathIsFileReturnType::kIsNotFile:
@@ -4064,7 +4081,7 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
@@ -4142,7 +4159,7 @@ void BindingData::LegacyMainResolve(const FunctionCallbackInfo<Value>& args) {
BufferValue buff_file_path(isolate, local_file_path);
ToNamespacedPath(env, &buff_file_path);
@@ -10,23 +10,8 @@ This should be upstreamed in some form, though it may need to be tweaked
before it's acceptable to upstream, as this patch comments out a couple
of tests that upstream probably cares about.
diff --git a/test/parallel/test-crypto-keygen-deprecation.js b/test/parallel/test-crypto-keygen-deprecation.js
index 926dfbbc4ae987217ab404ec25a3ca0a2ef2edcf..df0b379c1b1e982b96ea97c9814f38991d734ce4 100644
--- a/test/parallel/test-crypto-keygen-deprecation.js
+++ b/test/parallel/test-crypto-keygen-deprecation.js
@@ -4,6 +4,10 @@ const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
+if (process.features.openssl_is_boringssl) {
+ common.skip('Skipping unsupported RSA-PSS key tests');
+}
+
const DeprecationWarning = [];
DeprecationWarning.push([
'"options.hash" is deprecated, use "options.hashAlgorithm" instead.',
diff --git a/test/parallel/test-crypto-pqc-key-objects-ml-dsa.js b/test/parallel/test-crypto-pqc-key-objects-ml-dsa.js
index 883c2b7123844ede9c729809c2ac11e2c7288d72..54e7ff13547955ee7891fc493765e96aac39ba82 100644
index 715b313849dfaed0bae244ae971b8e9cb74a5d76..f42e34900f212399099efd68c9bb2249b1d0157a 100644
--- a/test/parallel/test-crypto-pqc-key-objects-ml-dsa.js
+++ b/test/parallel/test-crypto-pqc-key-objects-ml-dsa.js
@@ -4,6 +4,10 @@ const common = require('../common');
@@ -37,7 +22,7 @@ index 883c2b7123844ede9c729809c2ac11e2c7288d72..54e7ff13547955ee7891fc493765e96a
+ common.skip('Skipping unsupported ML-DSA key tests');
+}
+
const { hasOpenSSL } = require('../common/crypto');
const { hasOpenSSL, isBoringSSL } = require('../common/crypto');
const assert = require('assert');
diff --git a/test/parallel/test-openssl-unreadable-config.js b/test/parallel/test-openssl-unreadable-config.js
@@ -13,15 +13,17 @@ Refs: https://github.com/nodejs/node/pull/59941
Refs: https://chromium-review.googlesource.com/c/v8/v8/+/6937664
diff --git a/src/node.cc b/src/node.cc
index c977e31ab87158a527bf76d0e1f7283e6eeb40eb..f303b0c694c4c32863b15cbcabd315b4f435cd5e 100644
index d7fa3d8fdf23610917723b0bb808e19adc002f76..eb8835d5e66c67d6727ef75636770c7cd7c27930 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -790,9 +790,6 @@ static ExitCode ProcessGlobalArgsInternal(std::vector<std::string>* args,
@@ -790,11 +790,6 @@ static ExitCode ProcessGlobalArgsInternal(std::vector<std::string>* args,
v8_args.emplace_back("--js-source-phase-imports");
}
-#if V8_ENABLE_WEBASSEMBLY
- // WebAssembly JS Promise Integration
- v8_args.emplace_back("--experimental-wasm-jspi");
-#endif // V8_ENABLE_WEBASSEMBLY
-
#ifdef __POSIX__
// Block SIGPROF signals when sleeping in epoll_wait/kevent/etc. Avoids the
@@ -26,7 +26,7 @@ TaskQueue<T> without a priority member since the queue became a
priority_queue.
diff --git a/src/node_platform.cc b/src/node_platform.cc
index 7f4004b4cb94b813be693818d3c4d96923442eea..c13d363cde2cf028ba3f364db489bb5d6bedf7a6 100644
index 0598f17eeb4a15b01297eb8d26d0798ab4a4441a..6893935e7cf7bc5cc92479f553a1e4827820b71d 100644
--- a/src/node_platform.cc
+++ b/src/node_platform.cc
@@ -139,6 +139,7 @@ class WorkerThreadsTaskRunner::DelayedTaskScheduler {
@@ -8,10 +8,10 @@ an API override to replace the native `ReadFileSync` in the `modules`
binding.
diff --git a/src/env_properties.h b/src/env_properties.h
index 36e1f920979377ae191347b70958850a58607c1d..f85e0892133c5f97c676276751063c872e9f06b3 100644
index 564d3fa3c7a24ccabb0dda2ca4e1d07ec9c34502..34eac82fd87afd00695f1e482dda7c8d83ff4268 100644
--- a/src/env_properties.h
+++ b/src/env_properties.h
@@ -517,6 +517,7 @@
@@ -498,6 +498,7 @@
V(maybe_cache_generated_source_map, v8::Function) \
V(messaging_deserialize_create_object, v8::Function) \
V(message_port, v8::Object) \
@@ -16,28 +16,8 @@ Upstreams:
- https://github.com/nodejs/node/pull/39138
- https://github.com/nodejs/node/pull/39136
diff --git a/deps/ncrypto/ncrypto.cc b/deps/ncrypto/ncrypto.cc
index b7bbaccfc3a568b7ccfed97f01f2bc37a56b70dd..8c34bb9434284f4d25b4a472cb5496d22d47ce3e 100644
--- a/deps/ncrypto/ncrypto.cc
+++ b/deps/ncrypto/ncrypto.cc
@@ -3347,6 +3347,7 @@ constexpr bool IsASN1Sequence(const unsigned char* data,
return true;
}
+#if NCRYPTO_USE_OPENSSL3_PROVIDER
constexpr bool ReadASN1Element(const unsigned char* data,
size_t size,
unsigned char tag,
@@ -3374,6 +3375,7 @@ constexpr bool ReadASN1Element(const unsigned char* data,
*total_size = offset + length;
return true;
}
+#endif // NCRYPTO_USE_OPENSSL3_PROVIDER
constexpr bool IsEncryptedPrivateKeyInfo(
const Buffer<const unsigned char>& buffer) {
diff --git a/src/crypto/crypto_common.cc b/src/crypto/crypto_common.cc
index fde12953860cd0a40d04e6342b91337045bc784e..08f567bc4bf22840756b81b8a7c8cdf7dd53326f 100644
index ea0747511a107c96befd2dae1d7bd56759dd95b6..14dccb316ae600e55b2321e185e6d5833ba54575 100644
--- a/src/crypto/crypto_common.cc
+++ b/src/crypto/crypto_common.cc
@@ -90,7 +90,7 @@ StackOfX509 CloneSSLCerts(X509Pointer&& cert,
@@ -59,10 +39,10 @@ index fde12953860cd0a40d04e6342b91337045bc784e..08f567bc4bf22840756b81b8a7c8cdf7
X509View ca(sk_X509_value(peer_certs.get(), i));
if (!cert->view().isIssuedBy(ca)) continue;
diff --git a/src/crypto/crypto_context.cc b/src/crypto/crypto_context.cc
index af8d52fbe699a1b8721f09ea53503edaa91ce60a..176c69dfe7a7d1f6dfe33fcc7ffc470e50df50d2 100644
index 74ea622dad505586a9437097d36e84b7c11f0aa5..114b0c920882dd267f057c6414563c57e91eb236 100644
--- a/src/crypto/crypto_context.cc
+++ b/src/crypto/crypto_context.cc
@@ -169,7 +169,7 @@ int SSL_CTX_use_certificate_chain(SSL_CTX* ctx,
@@ -170,7 +170,7 @@ int SSL_CTX_use_certificate_chain(SSL_CTX* ctx,
// the CA certificates.
SSL_CTX_clear_extra_chain_certs(ctx);
@@ -71,7 +51,7 @@ index af8d52fbe699a1b8721f09ea53503edaa91ce60a..176c69dfe7a7d1f6dfe33fcc7ffc470e
X509* ca = sk_X509_value(extra_certs, i);
// NOTE: Increments reference count on `ca`
@@ -2345,7 +2345,7 @@ void SecureContext::LoadPKCS12(const FunctionCallbackInfo<Value>& args) {
@@ -2360,7 +2360,7 @@ void SecureContext::LoadPKCS12(const FunctionCallbackInfo<Value>& args) {
}
// Add CA certs too
@@ -80,31 +60,11 @@ index af8d52fbe699a1b8721f09ea53503edaa91ce60a..176c69dfe7a7d1f6dfe33fcc7ffc470e
X509* ca = sk_X509_value(extra_certs.get(), i);
X509_STORE_add_cert(sc->GetCertStoreOwnedByThisSecureContext(), ca);
diff --git a/src/crypto/crypto_dh.cc b/src/crypto/crypto_dh.cc
index 6418283e7e4ef06a4cacb973255dd42ccbe246ab..678ae4ebde6e0f12e09a3e9c01f8b9a560186c1e 100644
--- a/src/crypto/crypto_dh.cc
+++ b/src/crypto/crypto_dh.cc
@@ -458,11 +458,12 @@ EVPKeyCtxPointer DhKeyGenTraits::Setup(DhKeyPairGenConfig* params) {
if (!dh) return {};
key_params = EVPKeyPointer::NewDH(std::move(dh));
- } else if (int* prime_size = std::get_if<int>(&params->params.prime)) {
- auto param_ctx = EVPKeyCtxPointer::NewFromID(EVP_PKEY_DH);
+ } else if (std::holds_alternative<int>(params->params.prime)) {
#ifndef OPENSSL_IS_BORINGSSL
+ auto param_ctx = EVPKeyCtxPointer::NewFromID(EVP_PKEY_DH);
if (!param_ctx.initForParamgen() ||
- !param_ctx.setDhParameters(*prime_size, params->params.generator)) {
+ !param_ctx.setDhParameters(std::get<int>(params->params.prime),
+ params->params.generator)) {
return {};
}
diff --git a/src/crypto/crypto_hash.cc b/src/crypto/crypto_hash.cc
index f1a7bab16967b0b6e94e859d9a0af65ad65fd008..d250ee36017449b5081890a3af686e4ad45a1e42 100644
index 2cf971347b9ea98bf76a8d277a46d7a6842efda6..326120e21d38ad0c78a92658353c8252db49ff28 100644
--- a/src/crypto/crypto_hash.cc
+++ b/src/crypto/crypto_hash.cc
@@ -282,7 +282,7 @@ void Hash::OneShotDigest(const FunctionCallbackInfo<Value>& args) {
@@ -380,7 +380,7 @@ void OneShotDigestWithMD(Environment* env,
enum encoding output_enc = ParseEncoding(isolate, args[4], args[5], HEX);
bool is_xof = (EVP_MD_flags(md) & EVP_MD_FLAG_XOF) != 0;
@@ -113,19 +73,19 @@ index f1a7bab16967b0b6e94e859d9a0af65ad65fd008..d250ee36017449b5081890a3af686e4a
// This is to cause hash() to fail when an incorrect
// outputLength option was passed for a non-XOF hash function.
diff --git a/src/env.h b/src/env.h
index c5501cd7914a7369c2b93f2b66127e6901852692..499dcb86728d83656b9283ef004b519f46cb2b24 100644
--- a/src/env.h
+++ b/src/env.h
@@ -53,7 +53,7 @@
#include "v8-profiler.h"
#include "v8.h"
-#if HAVE_OPENSSL
+#if HAVE_OPENSSL && OPENSSL_VERSION_MAJOR >= 3
#include <openssl/evp.h>
#endif
diff --git a/src/crypto/crypto_x509.cc b/src/crypto/crypto_x509.cc
index 0050e5591e2ae0afb517500934ddfb223078bd76..944802925def832be06a05f05a9ff535b5e0d97c 100644
--- a/src/crypto/crypto_x509.cc
+++ b/src/crypto/crypto_x509.cc
@@ -946,7 +946,7 @@ MaybeLocal<Object> X509Certificate::NewWithIssuers(
}
Local<Object> issuer;
- if (issuer_chain != nullptr && start < sk_X509_num(issuer_chain)) {
+ if (issuer_chain != nullptr && start < static_cast<int>(sk_X509_num(issuer_chain))) {
X509Pointer issuer_cert =
X509View(sk_X509_value(issuer_chain, start)).clone();
if (!issuer_cert) [[unlikely]] {
diff --git a/src/node_metadata.h b/src/node_metadata.h
index 8703e4315a999df505ff322aea05a268e017831e..18ddb44400f90f2fbea4ffad09cc1a8f986bf997 100644
--- a/src/node_metadata.h
@@ -140,7 +100,7 @@ index 8703e4315a999df505ff322aea05a268e017831e..18ddb44400f90f2fbea4ffad09cc1a8f
#include <quic/guard.h>
#ifndef OPENSSL_NO_QUIC
diff --git a/src/node_options.h b/src/node_options.h
index 870a6babc770b35c93ac5528ab765bae81b1f40b..4ffcdb8c1f9e1d866960c419569f3410f8e50934 100644
index b55fae0a32175fdff7a0c3ecb479297bd035eb7e..04eaa705e8023dab7104ac4d55f9d4179b7f30d4 100644
--- a/src/node_options.h
+++ b/src/node_options.h
@@ -11,7 +11,7 @@
@@ -39,10 +39,10 @@ Three classes of fixes, all of which give the affected symbols strong
Observed on macOS arm64 official builds; latent on Linux/Windows.
diff --git a/src/env.cc b/src/env.cc
index 5389d6e699f32dacfd4d5710258f04f1cb9f9d12..c665e08b6d4eb3f1f772451e6bed1ae746f0d2f3 100644
index beb700dbe9fabcfe7c154a4c9e0f3dd8c95bc52e..f86232b125d9967f3021348cf88f132c391b2e0e 100644
--- a/src/env.cc
+++ b/src/env.cc
@@ -2328,4 +2328,8 @@ v8::CpuProfile* Environment::StopCpuProfile(v8::ProfilerId profile_id) {
@@ -2445,4 +2445,8 @@ v8::CpuProfile* Environment::StopCpuProfile(v8::ProfilerId profile_id) {
return profile;
}
@@ -74,7 +74,7 @@ index 72c1a73aa6c06f55f655cabd0416a709c31e2722..bb7519e4b984ef9915f72bdfb08414f0
public:
explicit JSGraph(Isolate* isolate) : isolate_(isolate) {}
diff --git a/src/js_native_api.h b/src/js_native_api.h
index d2375ecd32483ff57840d30f804100372f2e12db..396f7848952e941b3e667b47424c51664cac72ef 100644
index 2a36c4e3ddf397f8df6d535bdd61e8a1fb720ebb..4d97fe40c8935f0e23a42e8e7034bcb9155600fb 100644
--- a/src/js_native_api.h
+++ b/src/js_native_api.h
@@ -17,7 +17,7 @@
@@ -126,10 +126,10 @@ index f4094b05b0122377c826828457a842cde0acb2e8..a6a0ffb0ed272b9b05acc9cb32aa7951
NODE_BINDING_PER_ISOLATE_INIT(
diff --git a/src/node_http2.cc b/src/node_http2.cc
index b6bbb1a4edc33da3b77806c095213e0d663ad1a6..426d25d13c28d0282d217a54d66549324ff875ed 100644
index 010109791f0b3727dcf8cbad484341ae654a56f1..4ad6f6d25c8c4e326d9bcbebb43b4b663974ccb0 100644
--- a/src/node_http2.cc
+++ b/src/node_http2.cc
@@ -3795,6 +3795,13 @@ void Http2Session::MaybeNotifyGracefulCloseComplete() {
@@ -3749,6 +3749,13 @@ void Http2Session::MaybeNotifyGracefulCloseComplete() {
return;
}
} // namespace http2
@@ -144,7 +144,7 @@ index b6bbb1a4edc33da3b77806c095213e0d663ad1a6..426d25d13c28d0282d217a54d6654932
NODE_BINDING_CONTEXT_AWARE_INTERNAL(http2, node::http2::Initialize)
diff --git a/src/node_http2.h b/src/node_http2.h
index f321bf0c16018fa134202784a8e1c30e017d2de8..df19438171dbf2164e735d576036b8ea462065be 100644
index 94e77cbc6fa62af386beb4da5de0eb93a7788174..793bc3e27eccb1037518ad0d70f748b032fb6b55 100644
--- a/src/node_http2.h
+++ b/src/node_http2.h
@@ -146,6 +146,96 @@ struct Http2RcBufferPointerTraits {
@@ -20,10 +20,10 @@ tag ranges used by Blink and gin, which share isolates with Node.js in
renderer processes.
diff --git a/src/cppgc_helpers-inl.h b/src/cppgc_helpers-inl.h
index 0e52bf5a6f4837d0f4bfed83987c6903796fda55..68c70153b96cc3e62db1b5dc74ac4026fa306271 100644
index 745f2c0526fafc1079b94be875a9e5a519d3a794..f81b087ad21a28ec2385cd0cfae3177a470a2850 100644
--- a/src/cppgc_helpers-inl.h
+++ b/src/cppgc_helpers-inl.h
@@ -16,7 +16,7 @@ void CppgcMixin::Wrap(T* ptr, Realm* realm, v8::Local<v8::Object> obj) {
@@ -15,7 +15,7 @@ void CppgcMixin::Wrap(T* ptr, Realm* realm, v8::Local<v8::Object> obj) {
ptr->traced_reference_ = v8::TracedReference<v8::Object>(isolate, obj);
// Note that ptr must be of concrete type T in Wrap.
auto* wrappable = static_cast<v8::Object::Wrappable*>(ptr);
@@ -33,7 +33,7 @@ index 0e52bf5a6f4837d0f4bfed83987c6903796fda55..68c70153b96cc3e62db1b5dc74ac4026
obj->SetAlignedPointerInInternalField(
kEmbedderType, realm->isolate_data()->embedder_id_for_cppgc(), 0);
diff --git a/src/cppgc_helpers.h b/src/cppgc_helpers.h
index fe6300a5d5d2d6602a84cbd33736c2133041d1b0..b9153306b6cbc34d076c0eb5b32ecce3c5de98de 100644
index f1363d5da78f7a3603fb4502489ecf2ee3483fdb..7baf7b11a68c2cbb83bd67a152be74a8533ecdb0 100644
--- a/src/cppgc_helpers.h
+++ b/src/cppgc_helpers.h
@@ -19,6 +19,25 @@ class Environment;
@@ -63,10 +63,10 @@ index fe6300a5d5d2d6602a84cbd33736c2133041d1b0..b9153306b6cbc34d076c0eb5b32ecce3
* This is a helper mixin with a BaseObject-like interface to help
* implementing wrapper objects managed by V8's cppgc (Oilpan) library.
diff --git a/src/env.cc b/src/env.cc
index c665e08b6d4eb3f1f772451e6bed1ae746f0d2f3..ea0ff5b84f4a54a3f8efdfadb9f22e1120a9519e 100644
index f86232b125d9967f3021348cf88f132c391b2e0e..f72aafe07c039c6d63b74c80cd252f830930d121 100644
--- a/src/env.cc
+++ b/src/env.cc
@@ -643,8 +643,7 @@ IsolateData::~IsolateData() {}
@@ -644,8 +644,7 @@ IsolateData::~IsolateData() {}
void SetCppgcReference(Isolate* isolate,
Local<Object> object,
v8::Object::Wrappable* wrappable) {
@@ -20,7 +20,7 @@ allowing contentTracing to remain the sole owner of category filtering,
recording sessions, output, and lifecycle.
diff --git a/node.gni b/node.gni
index a443ff52ca1dda5cb2cfdfe5241076836a33b8fc..7d764d56c5e6318f8faf085b029c994d29ad37ce 100644
index 55f35c4c376e66be291631cff8b1acf266ff41a3..102e27726b7bd7f4adb290c43ceadc1559b27e54 100644
--- a/node.gni
+++ b/node.gni
@@ -57,6 +57,10 @@ declare_args() {
@@ -49,10 +49,10 @@ index b7d0041d0737f7e0315216748e3a5908428c7d1c..b48efd7e1a611dddb5724d65d623c8a2
get_trigger_async_id());
TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(TRACING_CATEGORY_NODE1(async_hooks),
diff --git a/src/env.cc b/src/env.cc
index ea0ff5b84f4a54a3f8efdfadb9f22e1120a9519e..d5f6d6b07a95dcca1fa00e899e5ad416b4fa626a 100644
index f72aafe07c039c6d63b74c80cd252f830930d121..65df49c367c6a378ffe1931bf8afa6315388a446 100644
--- a/src/env.cc
+++ b/src/env.cc
@@ -685,8 +685,8 @@ void TrackingTraceStateObserver::UpdateTraceCategoryState() {
@@ -686,8 +686,8 @@ void TrackingTraceStateObserver::UpdateTraceCategoryState() {
return;
}
@@ -63,7 +63,7 @@ index ea0ff5b84f4a54a3f8efdfadb9f22e1120a9519e..d5f6d6b07a95dcca1fa00e899e5ad416
Isolate* isolate = env_->isolate();
HandleScope handle_scope(isolate);
@@ -945,8 +945,7 @@ Environment::Environment(IsolateData* isolate_data,
@@ -1053,8 +1053,7 @@ Environment::Environment(IsolateData* isolate_data,
time_origin_timestamp_,
MAYBE_FIELD_PTR(env_info, performance_state));
@@ -74,7 +74,7 @@ index ea0ff5b84f4a54a3f8efdfadb9f22e1120a9519e..d5f6d6b07a95dcca1fa00e899e5ad416
TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(TRACING_CATEGORY_NODE1(environment),
"Environment",
diff --git a/src/node.cc b/src/node.cc
index 838106acff8fda886a11a28e9f23f47588a2e8d4..c977e31ab87158a527bf76d0e1f7283e6eeb40eb 100644
index 92c5fd8cb66f063e7cb4084b98500f28c60ec29a..d7fa3d8fdf23610917723b0bb808e19adc002f76 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -47,6 +47,10 @@
@@ -88,7 +88,7 @@ index 838106acff8fda886a11a28e9f23f47588a2e8d4..c977e31ab87158a527bf76d0e1f7283e
#if HAVE_OPENSSL
#include "ncrypto.h"
#include "node_crypto.h"
@@ -1135,6 +1139,14 @@ InitializeOncePerProcessInternal(const std::vector<std::string>& args,
@@ -1137,6 +1141,14 @@ InitializeOncePerProcessInternal(const std::vector<std::string>& args,
}
}
@@ -132,7 +132,7 @@ index 952161d9e2cf1c92c3600fc2da0af594cc3f53bd..17976d01e4f4f2bf87a38a4fdb36fc70
if (GET_TRACE_ENABLED) { \
TRACE_EVENT0(TRACING_CATEGORY_NODE2(fs_dir, sync), TRACE_NAME(syscall)); \
diff --git a/src/node_file.cc b/src/node_file.cc
index 06bafaea64e7fbb2b5f32e92fd7dc79be875ac68..d995103234649e9ac2c4dd9fbcc7869a483cc855 100644
index b6e2d325e338aedcab3e7fa2038e773930f56fcd..b74809f65c60e7c9f5c13b39f7d11a8c49b59fd0 100644
--- a/src/node_file.cc
+++ b/src/node_file.cc
@@ -147,8 +147,7 @@ static const char* get_fs_func_name_by_type(uv_fs_type req_type) {
@@ -146,7 +146,7 @@ index 06bafaea64e7fbb2b5f32e92fd7dc79be875ac68..d995103234649e9ac2c4dd9fbcc7869a
if (GET_TRACE_ENABLED) \
TRACE_EVENT_BEGIN( \
diff --git a/src/node_internals.h b/src/node_internals.h
index 24c5dbe405d69ceb0e515aeaa6b26233bb2943a9..3504c170e0c335274166a5666695b49d4a06c957 100644
index 39e8312ddd7167ee235927e1772f6d4dff98a5ad..7b6a516eab2239428368357aec177ea7d9b50ded 100644
--- a/src/node_internals.h
+++ b/src/node_internals.h
@@ -315,7 +315,14 @@ class ThreadPoolWork {
@@ -177,7 +177,7 @@ index 24c5dbe405d69ceb0e515aeaa6b26233bb2943a9..3504c170e0c335274166a5666695b49d
// Functions defined in node.cc that are exposed via the bootstrapper object
diff --git a/src/node_trace_events.cc b/src/node_trace_events.cc
index 412b5b67b35dfd192af04485e9c858f9862e9e0a..2fc6f4d338ffcbdb57236af5d121279e61156299 100644
index c8f2a58734ee6d2ab440cd2439574cbd09d6fc00..ca49f05085161c6ffa9661d5da7c80a28bfe1412 100644
--- a/src/node_trace_events.cc
+++ b/src/node_trace_events.cc
@@ -75,7 +75,6 @@ void NodeCategorySet::New(const FunctionCallbackInfo<Value>& args) {
@@ -219,7 +219,7 @@ index 412b5b67b35dfd192af04485e9c858f9862e9e0a..2fc6f4d338ffcbdb57236af5d121279e
category_set->enabled_ = true;
}
}
@@ -107,16 +109,19 @@ void NodeCategorySet::Disable(const FunctionCallbackInfo<Value>& args) {
@@ -107,8 +109,10 @@ void NodeCategorySet::Disable(const FunctionCallbackInfo<Value>& args) {
const auto& categories = category_set->GetCategories();
if (category_set->enabled_ && !categories.empty()) {
auto* agent = tracing::Agent::GetInstance();
@@ -232,6 +232,7 @@ index 412b5b67b35dfd192af04485e9c858f9862e9e0a..2fc6f4d338ffcbdb57236af5d121279e
category_set->enabled_ = false;
}
}
@@ -119,8 +123,9 @@ static void HasAgent(const FunctionCallbackInfo<Value>& args) {
void GetEnabledCategories(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
@@ -242,7 +243,7 @@ index 412b5b67b35dfd192af04485e9c858f9862e9e0a..2fc6f4d338ffcbdb57236af5d121279e
Local<Value> ret;
if (!categories.empty() &&
ToV8Value(env->context(), categories, env->isolate()).ToLocal(&ret)) {
@@ -137,8 +142,12 @@ static void GetCategoryEnabledBuffer(const FunctionCallbackInfo<Value>& args) {
@@ -141,8 +146,12 @@ static void GetCategoryEnabledBuffer(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
node::Utf8Value category_name(isolate, args[0]);
@@ -1,139 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: "Sparsh :)" <76697238+SparshGarg999@users.noreply.github.com>
Date: Tue, 8 Sep 2026 10:23:09 +0530
Subject: fs: support removing read-only files in rmSync on Windows
On Windows, libc++ std::filesystem::remove and remove_all do not
automatically clear the read-only attribute before deleting a file
(unlike MSVC STL). This causes fs.rmSync to fail with EPERM when
trying to remove read-only files in environments where Node.js is
built using clang libc++ (such as Electron).
This commit introduces a Windows-specific helper
ClearReadOnlyAttributeW which clears the FILE_ATTRIBUTE_READONLY
attribute recursively (or for a single file) when
operation_not_permitted is returned, allowing rmSync to
successfully delete read-only files/folders.
Fixes: https://github.com/nodejs/node/issues/64374
Signed-off-by: SparshGarg999 <sparshgarg999@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/64453
Fixes: https://github.com/nodejs/node/issues/64374
Reviewed-By: Stefan Stojanovic <stefan.stojanovic@janeasystems.com>
(cherry picked from commit 2987a5965f1f5c6d9f0023406389c57002e63629)
diff --git a/src/node_file.cc b/src/node_file.cc
index d995103234649e9ac2c4dd9fbcc7869a483cc855..e6b22eebaf07589ab0ad17a49067e65078fe9376 100644
--- a/src/node_file.cc
+++ b/src/node_file.cc
@@ -1750,6 +1750,41 @@ static void RMDir(const FunctionCallbackInfo<Value>& args) {
}
}
+#ifdef _WIN32
+static void ClearReadOnlyAttributeWHelper(const wchar_t* path) {
+ DWORD attrs = GetFileAttributesW(path);
+ if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_READONLY)) {
+ SetFileAttributesW(path, attrs & ~FILE_ATTRIBUTE_READONLY);
+ }
+}
+
+static void ClearReadOnlyAttributeW(const std::filesystem::path& path,
+ bool recursive) {
+ std::error_code ec;
+ auto file_status = std::filesystem::symlink_status(path, ec);
+ if (ec) return;
+
+ if (recursive &&
+ file_status.type() == std::filesystem::file_type::directory) {
+ for (const auto& entry : std::filesystem::recursive_directory_iterator(
+ path,
+ std::filesystem::directory_options::skip_permission_denied,
+ ec)) {
+ std::error_code entry_ec;
+ auto entry_status = entry.symlink_status(entry_ec);
+ if (entry_ec) continue;
+ if (entry_status.type() != std::filesystem::file_type::symlink) {
+ ClearReadOnlyAttributeWHelper(entry.path().c_str());
+ }
+ }
+ }
+
+ if (file_status.type() != std::filesystem::file_type::symlink) {
+ ClearReadOnlyAttributeWHelper(path.c_str());
+ }
+}
+#endif
+
static void RmSync(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
Isolate* isolate = env->isolate();
@@ -1797,6 +1832,9 @@ static void RmSync(const FunctionCallbackInfo<Value>& args) {
};
int i = 1;
+#ifdef _WIN32
+ bool cleared_readonly = false;
+#endif
while (maxRetries >= 0) {
if (recursive) {
@@ -1805,6 +1843,22 @@ static void RmSync(const FunctionCallbackInfo<Value>& args) {
std::filesystem::remove(file_path, error);
}
+#ifdef _WIN32
+ // On Windows, libc++ does not clear the read-only attribute before
+ // removing a file (unlike MSVC STL which does). Attempt to clear it
+ // manually when we get EPERM (operation_not_permitted) so that read-only
+ // files can be deleted, matching the behavior of official Node.js builds.
+ if (error == std::errc::operation_not_permitted && !cleared_readonly) {
+ cleared_readonly = true;
+ ClearReadOnlyAttributeW(file_path, recursive);
+ if (recursive) {
+ std::filesystem::remove_all(file_path, error);
+ } else {
+ std::filesystem::remove(file_path, error);
+ }
+ }
+#endif // _WIN32
+
if (!error || error == std::errc::no_such_file_or_directory) {
return;
} else if (!can_omit_error(error)) {
diff --git a/test/parallel/test-fs-rm.js b/test/parallel/test-fs-rm.js
index b15118fc9aa0d63688cdac07e8004f452d86d08e..6a2607ad57ece1e9a0b82dded7bf46bb722e18d9 100644
--- a/test/parallel/test-fs-rm.js
+++ b/test/parallel/test-fs-rm.js
@@ -632,3 +632,30 @@ if (isGitPresent) {
}
}
}
+
+{
+ // Test that rmSync can delete read-only files (and directories containing read-only files recursively)
+ const dirname = nextDirPath();
+ const filePath = path.join(dirname, 'readonly-file.txt');
+ const recursiveDir = path.join(dirname, 'subdir');
+ const recursiveFilePath = path.join(recursiveDir, 'readonly-nested.txt');
+
+ fs.mkdirSync(recursiveDir, { recursive: true });
+ fs.writeFileSync(filePath, 'hello');
+ fs.writeFileSync(recursiveFilePath, 'world');
+
+ // Make files read-only
+ fs.chmodSync(filePath, 0o444);
+ fs.chmodSync(recursiveFilePath, 0o444);
+
+ // rmSync without recursive option on a file
+ fs.rmSync(filePath);
+ assert.strictEqual(fs.existsSync(filePath), false);
+
+ // rmSync with recursive option on a directory containing a read-only file
+ fs.rmSync(recursiveDir, { recursive: true });
+ assert.strictEqual(fs.existsSync(recursiveDir), false);
+
+ // Clean up parent directory
+ fs.rmSync(dirname, { recursive: true, force: true });
+}
@@ -13,10 +13,10 @@ FallThrough method was also removed upstream; drop it here too.
Ref: https://chromium-review.googlesource.com/c/chromium/src/+/7885632
diff --git a/src/inspector_agent.cc b/src/inspector_agent.cc
index 1f86e4bfc2652c7526af1582ac05b8b7a224a47a..55fe49c1e3058c366ede37a7698aefae82ea3f75 100644
index 31277a74d1f3d3c8b733bfe0a21b25b2d19a4bc4..351033ebc10879a440f99667eddd4cc1cfe604a5 100644
--- a/src/inspector_agent.cc
+++ b/src/inspector_agent.cc
@@ -321,21 +321,16 @@ class ChannelImpl final : public v8_inspector::V8Inspector::Channel,
@@ -328,21 +328,16 @@ class ChannelImpl final : public v8_inspector::V8Inspector::Channel,
std::vector<uint8_t> cbor_buffer;
ConvertJSONToCBOR(crdtp::SpanFrom(raw_message), &cbor_buffer);
@@ -42,7 +42,7 @@ index 1f86e4bfc2652c7526af1582ac05b8b7a224a47a..55fe49c1e3058c366ede37a7698aefae
}
void schedulePauseOnNextStatement(const std::string& reason) {
@@ -428,13 +423,6 @@ class ChannelImpl final : public v8_inspector::V8Inspector::Channel,
@@ -435,13 +430,6 @@ class ChannelImpl final : public v8_inspector::V8Inspector::Channel,
sendMessageToFrontend(json);
}
@@ -16,7 +16,7 @@ call into JS from an interrupt.
Upstreamed at https://github.com/nodejs/node/pull/65397.
diff --git a/src/inspector_agent.cc b/src/inspector_agent.cc
index 55fe49c1e3058c366ede37a7698aefae82ea3f75..7329990ebf6a0bcb64b18069b67a61d45b56c60b 100644
index 351033ebc10879a440f99667eddd4cc1cfe604a5..c22d6fc36b9cef4c15fe579bc3f9acf979528e8e 100644
--- a/src/inspector_agent.cc
+++ b/src/inspector_agent.cc
@@ -54,6 +54,7 @@ using crdtp::UberDispatcher;
@@ -27,9 +27,9 @@ index 55fe49c1e3058c366ede37a7698aefae82ea3f75..7329990ebf6a0bcb64b18069b67a61d4
using v8::Function;
using v8::HandleScope;
using v8::Isolate;
@@ -77,6 +78,53 @@ static std::atomic_bool start_io_thread_async_initialized { false };
// Protects the Agent* stored in start_io_thread_async.data.
static Mutex start_io_thread_async_mutex;
@@ -77,6 +78,53 @@ static Mutex start_io_thread_agents_mutex;
static std::vector<Agent*> start_io_thread_agents;
static bool debug_signal_handler_started = false;
+template <typename Defer, typename OnFailure>
+void SyncJavaScriptHookState(Environment* env,
@@ -78,10 +78,10 @@ index 55fe49c1e3058c366ede37a7698aefae82ea3f75..7329990ebf6a0bcb64b18069b67a61d4
+ }
+}
+
// Called on the main thread.
void StartIoThreadAsyncCallback(uv_async_t* handle) {
static_cast<Agent*>(handle->data)->StartIoThread();
@@ -455,6 +503,15 @@ class SameThreadInspectorSession : public InspectorSession {
static void RequestIoThreadStartOnAgents() {
Mutex::ScopedLock lock(start_io_thread_agents_mutex);
for (Agent* agent : start_io_thread_agents) agent->RequestIoThreadStart();
@@ -462,6 +510,15 @@ class SameThreadInspectorSession : public InspectorSession {
void NotifyClusterWorkersDebugEnabled(Environment* env) {
Isolate* isolate = env->isolate();
@@ -97,7 +97,7 @@ index 55fe49c1e3058c366ede37a7698aefae82ea3f75..7329990ebf6a0bcb64b18069b67a61d4
HandleScope handle_scope(isolate);
// Send message to enable debug in cluster workers
@@ -959,54 +1016,40 @@ void Agent::SetupNetworkTracking(Local<Function> enable_function,
@@ -974,54 +1031,40 @@ void Agent::SetupNetworkTracking(Local<Function> enable_function,
Local<Function> disable_function) {
parent_env_->set_inspector_enable_network_tracking(enable_function);
parent_env_->set_inspector_disable_network_tracking(disable_function);
@@ -177,7 +177,7 @@ index 55fe49c1e3058c366ede37a7698aefae82ea3f75..7329990ebf6a0bcb64b18069b67a61d4
}
void Agent::WaitForDisconnect() {
@@ -1057,7 +1100,7 @@ void Agent::RegisterAsyncHook(Isolate* isolate,
@@ -1072,7 +1115,7 @@ void Agent::RegisterAsyncHook(Isolate* isolate,
}
void Agent::SetAsyncHookTrackingEnabled(bool enabled) {
@@ -186,7 +186,7 @@ index 55fe49c1e3058c366ede37a7698aefae82ea3f75..7329990ebf6a0bcb64b18069b67a61d4
SyncAsyncHookState();
}
@@ -1071,52 +1114,25 @@ void Agent::SetAsyncHookTrackingEnabled(bool enabled) {
@@ -1086,52 +1129,25 @@ void Agent::SetAsyncHookTrackingEnabled(bool enabled) {
// When it's not safe to call into JS, this is a no-op and we'll try again in
// RegisterAsyncHook() (for 1) or from a scheduled immediate (for 2).
void Agent::SyncAsyncHookState() {
@@ -257,10 +257,10 @@ index 55fe49c1e3058c366ede37a7698aefae82ea3f75..7329990ebf6a0bcb64b18069b67a61d4
void Agent::AsyncTaskScheduled(const StringView& task_name, void* task,
diff --git a/src/inspector_agent.h b/src/inspector_agent.h
index 932e4e8dce899101a17d978dfc5065de5eb06758..6e1a622aa6d95be198165f521f82513c8552606e 100644
index 5a1d1de26547bb437f4f86c2e1825d6eaf709e9d..bf76578e8c06a062b991937a2cca02b62d3f4c5a 100644
--- a/src/inspector_agent.h
+++ b/src/inspector_agent.h
@@ -28,6 +28,12 @@ class ParentInspectorHandle;
@@ -29,6 +29,12 @@ class ParentInspectorHandle;
class NodeInspectorClient;
class WorkerManager;
@@ -273,7 +273,7 @@ index 932e4e8dce899101a17d978dfc5065de5eb06758..6e1a622aa6d95be198165f521f82513c
class InspectorSession {
public:
virtual ~InspectorSession() = default;
@@ -132,7 +138,7 @@ class Agent {
@@ -134,7 +140,7 @@ class Agent {
private:
void SyncAsyncHookState();
@@ -282,7 +282,7 @@ index 932e4e8dce899101a17d978dfc5065de5eb06758..6e1a622aa6d95be198165f521f82513c
node::Environment* parent_env_;
// Encapsulates majority of the Inspector functionality
@@ -152,13 +158,11 @@ class Agent {
@@ -154,9 +160,7 @@ class Agent {
// The state of the async hook used for async stack traces that the protocol
// last requested, and the state JS currently has. SyncAsyncHookState()
// reconciles the two when it is possible and safe to call into JS.
@@ -291,6 +291,12 @@ index 932e4e8dce899101a17d978dfc5065de5eb06758..6e1a622aa6d95be198165f521f82513c
- bool syncing_async_hook_state_ = false;
+ JavaScriptHookState async_hook_state_;
// Woken by the SIGUSR1 watchdog; closed by the cleanup hook or ~Agent(),
// whichever runs first, and freed by its close callback.
@@ -164,9 +168,9 @@ class Agent {
void StopAcceptingIoThreadStarts();
static void StopAcceptingIoThreadStartsHook(void* agent);
- bool network_tracking_enabled_ = false;
- bool pending_enable_network_tracking = false;
- bool pending_disable_network_tracking = false;
@@ -18,10 +18,10 @@ This can be removed when Node.js upgrades to a version of V8 containing CLs
from the above issue.
diff --git a/src/api/environment.cc b/src/api/environment.cc
index 4969c908c487a96fd6da80741d70d11b10dea131..4dea08fafee4379066a7d8af66fb07c7e7a3490c 100644
index 4debed160e1abf8d3d4ecdd3d5e7d11f0a091cc1..312a857537867e408fe2bd1b1a0d1061c41ccf3b 100644
--- a/src/api/environment.cc
+++ b/src/api/environment.cc
@@ -320,6 +320,10 @@ Isolate* NewIsolate(Isolate::CreateParams* params,
@@ -349,6 +349,10 @@ Isolate* NewIsolate(Isolate::CreateParams* params,
MultiIsolatePlatform* platform,
const SnapshotData* snapshot_data,
const IsolateSettings& settings) {
@@ -32,7 +32,7 @@ index 4969c908c487a96fd6da80741d70d11b10dea131..4dea08fafee4379066a7d8af66fb07c7
IsolateGroup group = GetOrCreateIsolateGroup();
Isolate* isolate = Isolate::Allocate(group);
if (isolate == nullptr) return nullptr;
@@ -370,9 +374,12 @@ Isolate* NewIsolate(ArrayBufferAllocator* allocator,
@@ -382,9 +386,12 @@ Isolate* NewIsolate(ArrayBufferAllocator* allocator,
uv_loop_t* event_loop,
MultiIsolatePlatform* platform,
const EmbedderSnapshotData* snapshot_data,
@@ -47,10 +47,10 @@ index 4969c908c487a96fd6da80741d70d11b10dea131..4dea08fafee4379066a7d8af66fb07c7
event_loop,
platform,
diff --git a/src/cppgc_helpers-inl.h b/src/cppgc_helpers-inl.h
index 745ecab746f7c7540733d31a94f52809dcddd5be..0e52bf5a6f4837d0f4bfed83987c6903796fda55 100644
index f81dfb9bf60d52b225479c3a7a00b93225a9d10f..745f2c0526fafc1079b94be875a9e5a519d3a794 100644
--- a/src/cppgc_helpers-inl.h
+++ b/src/cppgc_helpers-inl.h
@@ -15,11 +15,12 @@ void CppgcMixin::Wrap(T* ptr, Realm* realm, v8::Local<v8::Object> obj) {
@@ -14,11 +14,12 @@ void CppgcMixin::Wrap(T* ptr, Realm* realm, v8::Local<v8::Object> obj) {
v8::Isolate* isolate = realm->isolate();
ptr->traced_reference_ = v8::TracedReference<v8::Object>(isolate, obj);
// Note that ptr must be of concrete type T in Wrap.
@@ -63,10 +63,10 @@ index 745ecab746f7c7540733d31a94f52809dcddd5be..0e52bf5a6f4837d0f4bfed83987c6903
- obj->SetAlignedPointerInInternalField(kSlot, ptr);
+ kEmbedderType, realm->isolate_data()->embedder_id_for_cppgc(), 0);
+ obj->SetAlignedPointerInInternalField(kSlot, ptr, 0);
realm->TrackCppgcWrapper(ptr);
ptr->list_node_ = realm->TrackCppgcWrapper(ptr);
}
@@ -40,7 +41,7 @@ T* CppgcMixin::Unwrap(v8::Local<v8::Object> obj) {
@@ -39,7 +40,7 @@ T* CppgcMixin::Unwrap(v8::Local<v8::Object> obj) {
if (obj->InternalFieldCount() != T::kInternalFieldCount) {
return nullptr;
}
@@ -75,29 +75,11 @@ index 745ecab746f7c7540733d31a94f52809dcddd5be..0e52bf5a6f4837d0f4bfed83987c6903
return ptr;
}
diff --git a/src/cppgc_helpers.cc b/src/cppgc_helpers.cc
index 7c557a822d2028aa88adbdca63677a44afd1a120..ae7e45fbc26317a53207c267865ea4db553f5a8a 100644
--- a/src/cppgc_helpers.cc
+++ b/src/cppgc_helpers.cc
@@ -4,11 +4,12 @@
namespace node {
void CppgcWrapperList::Cleanup() {
- for (auto node : *this) {
+ while (CppgcWrapperListNode* node = PopFront()) {
CppgcMixin* ptr = node->persistent.Get();
if (ptr != nullptr) {
ptr->Finalize();
}
+ delete node;
}
}
diff --git a/src/cppgc_helpers.h b/src/cppgc_helpers.h
index fb2af584a4ae777022c9ef8c20ada1edcbbbefdc..fe6300a5d5d2d6602a84cbd33736c2133041d1b0 100644
index df6b4836c676d468a97371f804ffe53606e7d171..f1363d5da78f7a3603fb4502489ecf2ee3483fdb 100644
--- a/src/cppgc_helpers.h
+++ b/src/cppgc_helpers.h
@@ -155,7 +155,7 @@ class CppgcMixin : public cppgc::GarbageCollectedMixin, public MemoryRetainer {
@@ -149,7 +149,7 @@ class CppgcMixin : public cppgc::GarbageCollectedMixin, public MemoryRetainer {
*/
#define CPPGC_MIXIN(Klass) \
public /* NOLINT(whitespace/indent) */ \
@@ -107,10 +89,10 @@ index fb2af584a4ae777022c9ef8c20ada1edcbbbefdc..fe6300a5d5d2d6602a84cbd33736c213
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
diff --git a/src/env.cc b/src/env.cc
index 84957de5cb0149e518c92ca0608f6e16faf5e5e6..c68bb8e4854a301b6899d2f7183b77dd9ff98c31 100644
index 3495479752fb8957ea4d89ca76f2c2dcddecf100..7674b06f7018020f87c32316a66eebc04720ab5e 100644
--- a/src/env.cc
+++ b/src/env.cc
@@ -642,7 +642,7 @@ IsolateData::~IsolateData() {}
@@ -643,7 +643,7 @@ IsolateData::~IsolateData() {}
// Deprecated API, embedders should use v8::Object::Wrap() directly instead.
void SetCppgcReference(Isolate* isolate,
Local<Object> object,
@@ -120,7 +102,7 @@ index 84957de5cb0149e518c92ca0608f6e16faf5e5e6..c68bb8e4854a301b6899d2f7183b77dd
isolate, object, wrappable);
}
diff --git a/src/node.h b/src/node.h
index 3bd4849bb93340569c0067fedd37fefeebff4eb5..952d51946d9412c376dfe305a2c5fd564b60998c 100644
index cba83119bfaf88b360b2f1220611a0c642ec7364..564ba432f023ea0575bba72e1a17816faf4d830c 100644
--- a/src/node.h
+++ b/src/node.h
@@ -78,6 +78,7 @@
@@ -131,7 +113,7 @@ index 3bd4849bb93340569c0067fedd37fefeebff4eb5..952d51946d9412c376dfe305a2c5fd56
#include "v8-platform.h" // NOLINT(build/include_order)
#include "node_version.h" // NODE_MODULE_VERSION
@@ -597,7 +598,8 @@ NODE_EXTERN v8::Isolate* NewIsolate(
@@ -599,7 +600,8 @@ NODE_EXTERN v8::Isolate* NewIsolate(
struct uv_loop_s* event_loop,
MultiIsolatePlatform* platform,
const EmbedderSnapshotData* snapshot_data = nullptr,
@@ -141,7 +123,7 @@ index 3bd4849bb93340569c0067fedd37fefeebff4eb5..952d51946d9412c376dfe305a2c5fd56
NODE_EXTERN v8::Isolate* NewIsolate(
std::shared_ptr<ArrayBufferAllocator> allocator,
struct uv_loop_s* event_loop,
@@ -1720,9 +1722,10 @@ void RegisterSignalHandler(int signal,
@@ -1728,9 +1730,10 @@ void RegisterSignalHandler(int signal,
// work with only Node.js versions with v8::Object::Wrap() should use that
// instead.
NODE_DEPRECATED("Use v8::Object::Wrap()",
@@ -156,7 +138,7 @@ index 3bd4849bb93340569c0067fedd37fefeebff4eb5..952d51946d9412c376dfe305a2c5fd56
namespace crypto {
diff --git a/src/node_main_instance.cc b/src/node_main_instance.cc
index 6f674df3ed0dc1b4e5cd3a249fb787a9fc98361d..90f9eb84b6835c36a91ce23d77722812ce173c0f 100644
index bc07d6aaf42678d935c28659c8b1d7adc6475194..6faf7569f7323fa1c85b19ba6e2f7583cd63b848 100644
--- a/src/node_main_instance.cc
+++ b/src/node_main_instance.cc
@@ -44,6 +44,8 @@ NodeMainInstance::NodeMainInstance(const SnapshotData* snapshot_data,
@@ -169,7 +151,7 @@ index 6f674df3ed0dc1b4e5cd3a249fb787a9fc98361d..90f9eb84b6835c36a91ce23d77722812
isolate_ =
NewIsolate(isolate_params_.get(), event_loop, platform, snapshot_data);
diff --git a/src/node_worker.cc b/src/node_worker.cc
index e743cb45359a2e1e3151f17dc80ada639a9db3e0..ed3aa30caac3f47691c4a7262e671589c3bace7b 100644
index fd6a0d90afaa7195564b09b81a24cb155aca81ae..b45ee62d0e13d24c013102ca2b463a2517d92907 100644
--- a/src/node_worker.cc
+++ b/src/node_worker.cc
@@ -182,6 +182,9 @@ class WorkerThreadData {
@@ -41,10 +41,10 @@ index f308232804352a72f81aa75dc42487b7a0697a47..077b8bff2c29cf35291e30b1bbfc8bdb
bench.end(n);
}
diff --git a/common.gypi b/common.gypi
index 7e67f7575c866c7628c980c77d131a4766caf58f..b1802a5fa1742f1896bcdfaca644245051cf7841 100644
index 00b5cea77e949befd234a474a7f109ba47d24d8b..49771334b41b2c6488a64ca17bbd46f62ccab45a 100644
--- a/common.gypi
+++ b/common.gypi
@@ -90,7 +90,7 @@
@@ -93,7 +93,7 @@
'v8_enable_sandbox%': 0,
'v8_enable_v8_checks%': 0,
'v8_enable_zone_compression%': 0,
@@ -54,10 +54,10 @@ index 7e67f7575c866c7628c980c77d131a4766caf58f..b1802a5fa1742f1896bcdfaca6442450
'using_electron_config_gypi%': 0,
diff --git a/configure.py b/configure.py
index 443818802df9bf62c17aa783617ec5b932cedf81..be0707fa1781201959fa0f4b3712021657dbfee8 100755
index 172aef2c5194574eb298462588ecf76ae2a2e366..80d5362e0037664aa98c02ff5568682bf5d3143b 100755
--- a/configure.py
+++ b/configure.py
@@ -1031,6 +1031,12 @@ parser.add_argument('--without-inspector',
@@ -1004,6 +1004,12 @@ parser.add_argument('--without-inspector',
default=None,
help='disable the V8 inspector protocol')
@@ -70,7 +70,7 @@ index 443818802df9bf62c17aa783617ec5b932cedf81..be0707fa1781201959fa0f4b37120216
parser.add_argument('--shared',
action='store_true',
dest='shared',
@@ -1997,6 +2003,7 @@ def configure_v8(o, configs):
@@ -1962,6 +1968,7 @@ def configure_v8(o, configs):
o['variables']['v8_enable_31bit_smis_on_64bit_arch'] = 1 if options.enable_pointer_compression else 0
o['variables']['v8_enable_extensible_ro_snapshot'] = 0
o['variables']['v8_trace_maps'] = 1 if options.trace_maps else 0
@@ -402,7 +402,7 @@ index 06a4f8a239855571dcc67cd81e7da7a255a9ebfd..1cb3ba4df520e782037d63bf1aeaef8b
let debugLogCategoryEnabled = false;
let timerFlags = kNone;
diff --git a/node.gyp b/node.gyp
index 5df80c48e7c747a49bd2e86ea7706de757fff32e..8aa3652277db2aef5e9ac5f0febdd08a44853fa0 100644
index 14f14c79630f19bbf7d319b669614123ef94b148..e9a73b3b5cf580d559d1cac60082c1022fcdc3ac 100644
--- a/node.gyp
+++ b/node.gyp
@@ -193,10 +193,9 @@
@@ -432,7 +432,7 @@ index 5df80c48e7c747a49bd2e86ea7706de757fff32e..8aa3652277db2aef5e9ac5f0febdd08a
'src/tracing/traced_value.h',
'src/timer_wrap.h',
'src/timer_wrap-inl.h',
@@ -1387,6 +1384,14 @@
@@ -1339,6 +1336,14 @@
}, {
'sources!': [ '<@(node_cctest_quic_sources)' ],
}],
@@ -447,7 +447,7 @@ index 5df80c48e7c747a49bd2e86ea7706de757fff32e..8aa3652277db2aef5e9ac5f0febdd08a
['v8_enable_inspector==1', {
'defines': [
'HAVE_INSPECTOR=1',
@@ -1709,6 +1714,14 @@
@@ -1661,6 +1666,14 @@
'NODE_USE_NODE_CODE_CACHE=1',
],
}],
@@ -463,10 +463,10 @@ index 5df80c48e7c747a49bd2e86ea7706de757fff32e..8aa3652277db2aef5e9ac5f0febdd08a
'defines': [
'HAVE_INSPECTOR=1',
diff --git a/src/api/environment.cc b/src/api/environment.cc
index c81ef82c5a23d30ec7430b8726bd28e1be2f225e..75fc97a581b79c87a51adcbe999b937262b422db 100644
index 4126d4b9f6caf6cbddba403189858c7f0ec60abb..885b9d9e6f9cc4497f27492f5eabcdbbe7f1e902 100644
--- a/src/api/environment.cc
+++ b/src/api/environment.cc
@@ -759,14 +759,6 @@ MultiIsolatePlatform* GetMultiIsolatePlatform(IsolateData* env) {
@@ -777,14 +777,6 @@ MultiIsolatePlatform* GetMultiIsolatePlatform(IsolateData* env) {
return env->platform();
}
@@ -530,7 +530,7 @@ index a493f59465d207b4b89d8941807d4ff6acff82ac..88e8a2f401cac75810e3b0fdb776b41e
+ ],
}
diff --git a/src/inspector_agent.cc b/src/inspector_agent.cc
index 7329990ebf6a0bcb64b18069b67a61d45b56c60b..37c86da997097240e381c79dbfd00b17937167af 100644
index c22d6fc36b9cef4c15fe579bc3f9acf979528e8e..8ef5de4b47bf8d98a4fbbb8aa91ed639b3ae0e27 100644
--- a/src/inspector_agent.cc
+++ b/src/inspector_agent.cc
@@ -14,7 +14,9 @@
@@ -543,7 +543,7 @@ index 7329990ebf6a0bcb64b18069b67a61d45b56c60b..37c86da997097240e381c79dbfd00b17
#include "inspector/worker_agent.h"
#include "inspector/worker_inspector.h"
#include "inspector_io.h"
@@ -286,9 +288,11 @@ class ChannelImpl final : public v8_inspector::V8Inspector::Channel,
@@ -293,9 +295,11 @@ class ChannelImpl final : public v8_inspector::V8Inspector::Channel,
StringView(),
V8Inspector::ClientTrustLevel::kFullyTrusted);
node_dispatcher_ = std::make_unique<UberDispatcher>(this);
@@ -555,7 +555,7 @@ index 7329990ebf6a0bcb64b18069b67a61d45b56c60b..37c86da997097240e381c79dbfd00b17
if (worker_manager) {
worker_agent_ = std::make_unique<protocol::WorkerAgent>(worker_manager);
worker_agent_->Wire(node_dispatcher_.get());
@@ -322,8 +326,10 @@ class ChannelImpl final : public v8_inspector::V8Inspector::Channel,
@@ -329,8 +333,10 @@ class ChannelImpl final : public v8_inspector::V8Inspector::Channel,
}
~ChannelImpl() override {
@@ -566,7 +566,7 @@ index 7329990ebf6a0bcb64b18069b67a61d45b56c60b..37c86da997097240e381c79dbfd00b17
if (worker_agent_) {
worker_agent_->disable();
worker_agent_.reset(); // Dispose before the dispatchers
@@ -472,7 +478,9 @@ class ChannelImpl final : public v8_inspector::V8Inspector::Channel,
@@ -479,7 +485,9 @@ class ChannelImpl final : public v8_inspector::V8Inspector::Channel,
}
std::unique_ptr<protocol::RuntimeAgent> runtime_agent_;
@@ -691,7 +691,7 @@ index c9173d404c79a69743fc75ddb6bba0ac9579c1ef..952161d9e2cf1c92c3600fc2da0af594
return env->ThrowUVException(err, "opendir");
}
diff --git a/src/node_file.cc b/src/node_file.cc
index 15a433fc2c1fde03d1e875a88c238bc36fcc6c93..06bafaea64e7fbb2b5f32e92fd7dc79be875ac68 100644
index fb5aaa3ab08923bf9c1c4e767bad2881510633e8..b6e2d325e338aedcab3e7fa2038e773930f56fcd 100644
--- a/src/node_file.cc
+++ b/src/node_file.cc
@@ -153,10 +153,16 @@ static const char* get_fs_func_name_by_type(uv_fs_type req_type) {
@@ -712,7 +712,7 @@ index 15a433fc2c1fde03d1e875a88c238bc36fcc6c93..06bafaea64e7fbb2b5f32e92fd7dc79b
#define FS_ASYNC_TRACE_BEGIN0(fs_type, id) \
TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(TRACING_CATEGORY_NODE2(fs, async), \
diff --git a/src/node_internals.h b/src/node_internals.h
index 8e930a6fecd6589b858293d91b2454ea14ae7c73..24c5dbe405d69ceb0e515aeaa6b26233bb2943a9 100644
index dc228f8e1e245d9f4fca8f2f948619304bfed5d5..39e8312ddd7167ee235927e1772f6d4dff98a5ad 100644
--- a/src/node_internals.h
+++ b/src/node_internals.h
@@ -315,6 +315,7 @@ class ThreadPoolWork {
@@ -732,7 +732,7 @@ index 8e930a6fecd6589b858293d91b2454ea14ae7c73..24c5dbe405d69ceb0e515aeaa6b26233
// Functions defined in node.cc that are exposed via the bootstrapper object
diff --git a/src/node_options.h b/src/node_options.h
index 4ffcdb8c1f9e1d866960c419569f3410f8e50934..04ca2785b9da5cd4083c6dee200cfaeb6e06bfc6 100644
index 04eaa705e8023dab7104ac4d55f9d4179b7f30d4..575f4b23b58d9d2ea863d3209e3b9abaa6cfce7c 100644
--- a/src/node_options.h
+++ b/src/node_options.h
@@ -333,7 +333,11 @@ class PerProcessOptions : public Options {
@@ -748,7 +748,7 @@ index 4ffcdb8c1f9e1d866960c419569f3410f8e50934..04ca2785b9da5cd4083c6dee200cfaeb
bool zero_fill_all_buffers = false;
bool debug_arraybuffer_allocations = false;
diff --git a/src/node_platform.cc b/src/node_platform.cc
index c13d363cde2cf028ba3f364db489bb5d6bedf7a6..1f235cdd171ed4d00bdfd3ed25acbbfdfd172d2f 100644
index 6893935e7cf7bc5cc92479f553a1e4827820b71d..bf2dac8f5d9e11f52603c562ff049cabc67eb91e 100644
--- a/src/node_platform.cc
+++ b/src/node_platform.cc
@@ -477,7 +477,8 @@ NodePlatform::NodePlatform(int thread_pool_size,
@@ -784,7 +784,7 @@ index f47e2a46b66b84938bcbf5b34ffc4a4a4a39af3f..665d2a467e08084837217482f65bb626
v8::PageAllocator* page_allocator_;
std::shared_ptr<WorkerThreadsTaskRunner> worker_thread_task_runner_;
diff --git a/src/node_trace_events.cc b/src/node_trace_events.cc
index 49c457cae2b3da603a548874f63dbdf9f50580d9..412b5b67b35dfd192af04485e9c858f9862e9e0a 100644
index f2d766b8b192dfbbd40af1f8ffaee624b747bb1d..c8f2a58734ee6d2ab440cd2439574cbd09d6fc00 100644
--- a/src/node_trace_events.cc
+++ b/src/node_trace_events.cc
@@ -7,7 +7,7 @@
@@ -811,7 +811,7 @@ index 49c457cae2b3da603a548874f63dbdf9f50580d9..412b5b67b35dfd192af04485e9c858f9
// Starts the Tracing Agent if it wasn't started already (e.g. through
// a command line flag.)
auto* agent = tracing::Agent::GetInstance();
@@ -205,6 +204,14 @@ void NodeCategorySet::Initialize(Local<Object> target,
@@ -210,6 +209,14 @@ void NodeCategorySet::Initialize(Local<Object> target,
.Check();
target->Set(context, trace,
binding->Get(context, trace).ToLocalChecked()).Check();
@@ -1747,7 +1747,7 @@ index 0bc9df81d87562243817a6618641a49b602654e3..e04ffff48efbc55cc2221c22be7fd2e0
// Do not use this class directly. Define a custom structured class to provide
diff --git a/test/common/index.js b/test/common/index.js
index 9d15b57bf6b85bb006496069149f41110a2664b5..309c7301f2bbf842aad00c31f57c8a455e6b2228 100755
index 0f2d695bbc5a6476d0e87bc79eb94485398e6e6b..15f3c1fa796f3ce11b62b8437469a5ae83c9c389 100755
--- a/test/common/index.js
+++ b/test/common/index.js
@@ -58,6 +58,7 @@ const hasCrypto = Boolean(process.versions.openssl) &&
@@ -1777,7 +1777,7 @@ index 9d15b57bf6b85bb006496069149f41110a2664b5..309c7301f2bbf842aad00c31f57c8a45
function getArrayBufferViews(buf) {
const { buffer, byteOffset, byteLength } = buf;
@@ -1006,6 +1019,8 @@ const common = {
@@ -1007,6 +1020,8 @@ const common = {
skipIfEslintMissing,
skipIfInspectorDisabled,
skipIfSQLiteMissing,
@@ -2231,10 +2231,10 @@ index 844b3769ce201c615b2daaaaa85c8dd01a13c8f1..2e6c20255ce75f94c83e9238bc90a50b
const CODE = 'const { Worker } = require(\'worker_threads\'); ' +
`new Worker(${JSON.stringify(__filename)})`;
diff --git a/tools/v8_gypfiles/features.gypi b/tools/v8_gypfiles/features.gypi
index 53886830721c46b3ea1df7aaf7180ed19c3288eb..56f2ec123d22250ac1c7bcf368c4ea640114eb09 100644
index 373448fccfb22ca2ec16df321a387fc710319cc4..d911d9f01b0c02e154358ccd812f324850655b56 100644
--- a/tools/v8_gypfiles/features.gypi
+++ b/tools/v8_gypfiles/features.gypi
@@ -205,8 +205,7 @@
@@ -208,8 +208,7 @@
# Enable seeded array index hash.
'v8_enable_seeded_array_index_hash%': 1,
@@ -2244,7 +2244,7 @@ index 53886830721c46b3ea1df7aaf7180ed19c3288eb..56f2ec123d22250ac1c7bcf368c4ea64
'v8_use_perfetto%': 0,
# Enable map packing & unpacking (sets -dV8_MAP_PACKING).
@@ -465,7 +464,10 @@
@@ -484,7 +483,10 @@
'defines': ['ENABLE_VERIFY_CSA',],
}],
['v8_use_perfetto==1', {
@@ -2257,7 +2257,7 @@ index 53886830721c46b3ea1df7aaf7180ed19c3288eb..56f2ec123d22250ac1c7bcf368c4ea64
['v8_enable_map_packing==1', {
'defines': ['V8_MAP_PACKING',],
diff --git a/tools/v8_gypfiles/v8.gyp b/tools/v8_gypfiles/v8.gyp
index f90a29d102ac0246a9261e223f0b5f69ec6d328b..71a7c40efa061afa954874ac97820be97e50463c 100644
index 370001847ee8b43c0e83e516f65856c85eff3f41..60d630702b95d786d9634c0ffda40ba7f8374a1d 100644
--- a/tools/v8_gypfiles/v8.gyp
+++ b/tools/v8_gypfiles/v8.gyp
@@ -33,6 +33,7 @@
@@ -1,465 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shelley Vohr <shelley.vohr@gmail.com>
Date: Thu, 3 Sep 2026 04:13:45 +0000
Subject: src: detach cppgc wrappers from their Realm before it is freed
`Realm::RunCleanup()` finalizes the cppgc-managed wrappers it tracks
so that none of them touches the Realm once it is gone, but it reaches
them through weak persistents, and the GC clears those as soon as it
finds a wrapper dead. With lazy and concurrent sweeping the destructor
can run much later, so a wrapper collected shortly before
`FreeEnvironment()` and swept after it was skipped by the cleanup and
kept its `realm_`: `~CppgcMixin()` then wrote
`should_purge_empty_cppgc_wrappers_` into the freed Realm, and a
subclass destructor calling `Finalize()` as documented would have
called `Clean()` with a dangling Realm. A Worker that compiles a few
`vm.Script`s, gets a full GC from external memory pressure and calls
`process.exit()` is enough to hit the first case.
Move the Realm pointer into the list node, which the wrapper now owns
and deletes in its destructor. `CppgcWrapperList::Cleanup()` unlinks
every node, finalizing the wrappers that are still alive and clearing
the Realm pointer for the collected ones, which only their own
destructor may still touch. `Realm::PendingCleanup()` accounts for the
list so it is always drained. The purge flag, its GC epilogue callback
and `PurgeEmpty()` are no longer needed, and removing them also stops
the list nodes of wrappers that are alive at `FreeEnvironment()` from
leaking.
Refs: https://github.com/nodejs/node/pull/56534
Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/65778
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Cherry-picked from upstream commit c909c63be392b4c9ffdc2108e64371b9fa83e472;
remove this patch once a Node.js release containing it is rolled in.
diff --git a/src/cppgc_helpers-inl.h b/src/cppgc_helpers-inl.h
index 68c70153b96cc3e62db1b5dc74ac4026fa306271..f81b087ad21a28ec2385cd0cfae3177a470a2850 100644
--- a/src/cppgc_helpers-inl.h
+++ b/src/cppgc_helpers-inl.h
@@ -11,7 +11,6 @@ namespace node {
template <typename T>
void CppgcMixin::Wrap(T* ptr, Realm* realm, v8::Local<v8::Object> obj) {
CHECK_GE(obj->InternalFieldCount(), T::kInternalFieldCount);
- ptr->realm_ = realm;
v8::Isolate* isolate = realm->isolate();
ptr->traced_reference_ = v8::TracedReference<v8::Object>(isolate, obj);
// Note that ptr must be of concrete type T in Wrap.
@@ -21,7 +20,7 @@ void CppgcMixin::Wrap(T* ptr, Realm* realm, v8::Local<v8::Object> obj) {
obj->SetAlignedPointerInInternalField(
kEmbedderType, realm->isolate_data()->embedder_id_for_cppgc(), 0);
obj->SetAlignedPointerInInternalField(kSlot, ptr, 0);
- realm->TrackCppgcWrapper(ptr);
+ ptr->list_node_ = realm->TrackCppgcWrapper(ptr);
}
template <typename T>
@@ -46,17 +45,26 @@ T* CppgcMixin::Unwrap(v8::Local<v8::Object> obj) {
}
v8::Local<v8::Object> CppgcMixin::object() const {
- return traced_reference_.Get(realm_->isolate());
+ return traced_reference_.Get(realm()->isolate());
}
Environment* CppgcMixin::env() const {
- return realm_->env();
+ return realm()->env();
+}
+
+Realm* CppgcMixin::realm() const {
+ return list_node_ == nullptr ? nullptr : list_node_->realm;
+}
+
+void CppgcMixin::Finalize() {
+ Realm* current_realm = realm();
+ if (current_realm == nullptr) return;
+ this->Clean(current_realm);
+ list_node_->realm = nullptr;
}
CppgcMixin::~CppgcMixin() {
- if (realm_ != nullptr) {
- realm_->set_should_purge_empty_cppgc_wrappers(true);
- }
+ delete list_node_;
}
} // namespace node
diff --git a/src/cppgc_helpers.cc b/src/cppgc_helpers.cc
index ae7e45fbc26317a53207c267865ea4db553f5a8a..9424904c0ea82d14102a47a6f4915210ef39fc76 100644
--- a/src/cppgc_helpers.cc
+++ b/src/cppgc_helpers.cc
@@ -1,15 +1,14 @@
-#include "cppgc_helpers.h"
-#include "env-inl.h"
+#include "cppgc_helpers.h" // NOLINT(build/include_inline)
+#include "cppgc_helpers-inl.h"
namespace node {
void CppgcWrapperList::Cleanup() {
- while (CppgcWrapperListNode* node = PopFront()) {
- CppgcMixin* ptr = node->persistent.Get();
- if (ptr != nullptr) {
- ptr->Finalize();
- }
- delete node;
+ while (!IsEmpty()) {
+ CppgcWrapperListNode* node = PopFront();
+ CppgcMixin* wrapper = node->persistent.Get();
+ if (wrapper != nullptr) wrapper->Finalize();
+ node->realm = nullptr;
}
}
@@ -24,18 +23,4 @@ void CppgcWrapperList::MemoryInfo(MemoryTracker* tracker) const {
}
}
}
-
-void CppgcWrapperList::PurgeEmpty() {
- for (auto weak_it = begin(); weak_it != end();) {
- CppgcWrapperListNode* node = *weak_it;
- auto next_it = ++weak_it;
- // The underlying cppgc wrapper has already been garbage collected.
- // Remove it from the list.
- if (!node->persistent) {
- node->persistent.Clear();
- delete node;
- }
- weak_it = next_it;
- }
-}
} // namespace node
diff --git a/src/cppgc_helpers.h b/src/cppgc_helpers.h
index b9153306b6cbc34d076c0eb5b32ecce3c5de98de..7baf7b11a68c2cbb83bd67a152be74a8533ecdb0 100644
--- a/src/cppgc_helpers.h
+++ b/src/cppgc_helpers.h
@@ -66,9 +66,9 @@ static_assert(
* cleanup relies on a living Node.js `Realm`, it should implement a
* pattern like this:
*
- * ~MyWrap() { this->Destroy(); }
+ * ~MyWrap() { this->Finalize(); }
* void Clean(Realm* env) override {
- * // Do cleanup that relies on a living Environemnt.
+ * // Do cleanup that relies on a living Realm.
* }
*/
class CppgcMixin : public cppgc::GarbageCollectedMixin, public MemoryRetainer {
@@ -87,7 +87,7 @@ class CppgcMixin : public cppgc::GarbageCollectedMixin, public MemoryRetainer {
inline v8::Local<v8::Object> object() const;
inline Environment* env() const;
- inline Realm* realm() const { return realm_; }
+ inline Realm* realm() const;
inline v8::Local<v8::Object> object(v8::Isolate* isolate) const {
return traced_reference_.Get(isolate);
}
@@ -114,11 +114,7 @@ class CppgcMixin : public cppgc::GarbageCollectedMixin, public MemoryRetainer {
// destructor. Outside of Finalize(), subclasses should avoid calling
// into JavaScript or perform any operation that can trigger garbage
// collection during the destruction.
- void Finalize() {
- if (realm_ == nullptr) return;
- this->Clean(realm_);
- realm_ = nullptr;
- }
+ inline void Finalize();
// The default implementation of Clean() is a no-op. If subclasses wish
// to perform cleanup that require a living Realm, they should
@@ -129,10 +125,8 @@ class CppgcMixin : public cppgc::GarbageCollectedMixin, public MemoryRetainer {
inline ~CppgcMixin();
- friend class CppgcWrapperListNode;
-
private:
- Realm* realm_ = nullptr;
+ CppgcWrapperListNode* list_node_ = nullptr;
v8::TracedReference<v8::Object> traced_reference_;
};
diff --git a/src/node_realm-inl.h b/src/node_realm-inl.h
index c01cef477aaba52f9894943acede7fb22ed17dcb..97756edfce15b2f3647646146683727b36c0eec3 100644
--- a/src/node_realm-inl.h
+++ b/src/node_realm-inl.h
@@ -136,11 +136,13 @@ void Realm::TrackBaseObject(BaseObject* bo) {
++base_object_count_;
}
-CppgcWrapperListNode::CppgcWrapperListNode(CppgcMixin* ptr) : persistent(ptr) {}
+CppgcWrapperListNode::CppgcWrapperListNode(Realm* realm, CppgcMixin* wrapper)
+ : realm(realm), persistent(wrapper) {}
-void Realm::TrackCppgcWrapper(CppgcMixin* handle) {
- DCHECK_EQ(handle->realm(), this);
- cppgc_wrapper_list_.PushFront(new CppgcWrapperListNode(handle));
+CppgcWrapperListNode* Realm::TrackCppgcWrapper(CppgcMixin* handle) {
+ CppgcWrapperListNode* node = new CppgcWrapperListNode(this, handle);
+ cppgc_wrapper_list_.PushFront(node);
+ return node;
}
void Realm::UntrackBaseObject(BaseObject* bo) {
@@ -149,7 +151,7 @@ void Realm::UntrackBaseObject(BaseObject* bo) {
}
bool Realm::PendingCleanup() const {
- return !base_object_list_.IsEmpty();
+ return !base_object_list_.IsEmpty() || !cppgc_wrapper_list_.IsEmpty();
}
} // namespace node
diff --git a/src/node_realm.cc b/src/node_realm.cc
index 47bd7d9f19077ac7a558c73db5f51bdf8da291e7..17c3dd754bda13413e7cac6fc2fb55f6a4866a66 100644
--- a/src/node_realm.cc
+++ b/src/node_realm.cc
@@ -10,8 +10,6 @@ namespace node {
using v8::Context;
using v8::EscapableHandleScope;
-using v8::GCCallbackFlags;
-using v8::GCType;
using v8::HandleScope;
using v8::Isolate;
using v8::Local;
@@ -25,26 +23,11 @@ Realm::Realm(Environment* env, v8::Local<v8::Context> context, Kind kind)
: env_(env), isolate_(v8::Isolate::GetCurrent()), kind_(kind) {
context_.Reset(isolate_, context);
env->AssignToContext(context, this, ContextInfo(""));
- // The environment can also purge empty wrappers in the check callback,
- // though that may be a bit excessive depending on usage patterns.
- // For now using the GC epilogue is adequate.
- isolate_->AddGCEpilogueCallback(PurgeEmptyCppgcWrappers, this);
}
Realm::~Realm() {
- isolate_->RemoveGCEpilogueCallback(PurgeEmptyCppgcWrappers, this);
CHECK_EQ(base_object_count_, 0);
-}
-
-void Realm::PurgeEmptyCppgcWrappers(Isolate* isolate,
- GCType type,
- GCCallbackFlags flags,
- void* data) {
- Realm* realm = static_cast<Realm*>(data);
- if (realm->should_purge_empty_cppgc_wrappers_) {
- realm->cppgc_wrapper_list_.PurgeEmpty();
- realm->should_purge_empty_cppgc_wrappers_ = false;
- }
+ CHECK(cppgc_wrapper_list_.IsEmpty());
}
void Realm::MemoryInfo(MemoryTracker* tracker) const {
diff --git a/src/node_realm.h b/src/node_realm.h
index 2ed04aa271b4c49db5be56d7a0e1969a0182cde6..4cb20d151d4dc94370eac7a17b56f8da2e6e418a 100644
--- a/src/node_realm.h
+++ b/src/node_realm.h
@@ -27,16 +27,16 @@ using BindingDataStore =
static_cast<size_t>(BindingDataType::kBindingDataTypeCount)>;
/**
- * This is a wrapper around a weak persistent of CppgcMixin, used in the
- * CppgcWrapperList to avoid accessing already garbage collected CppgcMixins.
+ * Owned by a CppgcMixin and linked into its Realm's list until the Realm
+ * cleans up and clears `realm`. The Realm only calls into wrappers the GC
+ * still considers alive (the weak persistent); a collected wrapper whose
+ * destructor runs later sees `realm == nullptr` instead of a freed Realm.
*/
class CppgcWrapperListNode {
public:
- explicit inline CppgcWrapperListNode(CppgcMixin* ptr);
- inline explicit operator bool() const { return !persistent; }
- inline CppgcMixin* operator->() const { return persistent.Get(); }
- inline CppgcMixin* operator*() const { return persistent.Get(); }
+ inline CppgcWrapperListNode(Realm* realm, CppgcMixin* wrapper);
+ Realm* realm;
cppgc::WeakPersistent<CppgcMixin> persistent;
// Used by ContainerOf in the ListNode implementation for fast manipulation of
// CppgcWrapperList.
@@ -53,7 +53,6 @@ class CppgcWrapperList
public MemoryRetainer {
public:
void Cleanup();
- void PurgeEmpty();
SET_MEMORY_INFO_NAME(CppgcWrapperList)
SET_SELF_SIZE(CppgcWrapperList)
@@ -148,7 +147,7 @@ class Realm : public MemoryRetainer {
// Base object count created after the bootstrap of the realm.
inline int64_t base_object_created_after_bootstrap() const;
- inline void TrackCppgcWrapper(CppgcMixin* handle);
+ inline CppgcWrapperListNode* TrackCppgcWrapper(CppgcMixin* handle);
inline CppgcWrapperList* cppgc_wrapper_list() { return &cppgc_wrapper_list_; }
#define V(PropertyName, TypeName) \
@@ -164,14 +163,6 @@ class Realm : public MemoryRetainer {
// it's only used for tests.
std::vector<std::string> builtins_in_snapshot;
- // This used during the destruction of cppgc wrappers to inform a GC epilogue
- // callback to clean up the weak persistents used to track cppgc wrappers if
- // the wrappers are already garbage collected to prevent holding on to
- // excessive useless persistents.
- inline void set_should_purge_empty_cppgc_wrappers(bool value) {
- should_purge_empty_cppgc_wrappers_ = value;
- }
-
protected:
~Realm();
@@ -181,17 +172,11 @@ class Realm : public MemoryRetainer {
// Shorthand for isolate pointer.
v8::Isolate* isolate_;
v8::Global<v8::Context> context_;
- bool should_purge_empty_cppgc_wrappers_ = false;
#define V(PropertyName, TypeName) v8::Global<TypeName> PropertyName##_;
PER_REALM_STRONG_PERSISTENT_VALUES(V)
#undef V
- static void PurgeEmptyCppgcWrappers(v8::Isolate* isolate,
- v8::GCType type,
- v8::GCCallbackFlags flags,
- void* data);
-
private:
void InitializeContext(v8::Local<v8::Context> context,
const RealmSerializeInfo* realm_info);
diff --git a/test/cctest/test_cppgc.cc b/test/cctest/test_cppgc.cc
index 21f981f9ab229ffeb99fa0e903ece7f973cc9b50..030f369ab45e823ae65c07d6e7ec414dfecf6f26 100644
--- a/test/cctest/test_cppgc.cc
+++ b/test/cctest/test_cppgc.cc
@@ -3,8 +3,11 @@
#include <cppgc/heap.h>
#include <node.h>
#include <v8-cppgc.h>
+#include <v8-external-memory-accounter.h>
#include <v8-sandbox.h>
#include <v8.h>
+#include "cppgc_helpers-inl.h"
+#include "node_realm-inl.h"
#include "node_test_fixture.h"
// This tests that Node.js can work with an existing CppHeap.
@@ -106,3 +109,114 @@ TEST_F(NodeZeroIsolateTestFixture, ExistingCppHeapTest) {
// heap can be reclaimed. So just check at least some of them are traced.
EXPECT_GT(CppGCed::kTraceCount, 0);
}
+
+class CppgcTest : public EnvironmentTestFixture {
+ protected:
+ // Above the external memory hard limit, so V8 runs a full GC synchronously
+ // and leaves sweeping (and cppgc destructors) for later.
+ static constexpr size_t kExternalMemoryPressure = size_t{8} << 30;
+
+ void CollectGarbageLeavingSweepingPending() {
+ v8::ExternalMemoryAccounter pressure;
+ pressure.Increase(isolate_, kExternalMemoryPressure);
+ pressure.Decrease(isolate_, kExternalMemoryPressure);
+ }
+
+ void FinishSweeping() {
+ isolate_->LowMemoryNotification();
+ platform->DrainTasks(isolate_);
+ }
+};
+
+using node::CppgcMixin;
+
+class RealmBoundWrap final : CPPGC_MIXIN(RealmBoundWrap) {
+ public:
+ SET_CPPGC_NAME(RealmBoundWrap)
+ DEFAULT_CPPGC_TRACE()
+ SET_NO_MEMORY_INFO()
+
+ static node::Realm* live_realm;
+ static int clean_count;
+ static int clean_with_dead_realm_count;
+ static int destructor_count;
+
+ RealmBoundWrap(node::Environment* env, v8::Local<v8::Object> object) {
+ CppgcMixin::Wrap(this, env, object);
+ }
+ ~RealmBoundWrap() {
+ Finalize();
+ destructor_count++;
+ }
+ void Clean(node::Realm* realm) override {
+ clean_count++;
+ if (realm != live_realm) clean_with_dead_realm_count++;
+ }
+};
+
+node::Realm* RealmBoundWrap::live_realm = nullptr;
+int RealmBoundWrap::clean_count = 0;
+int RealmBoundWrap::clean_with_dead_realm_count = 0;
+int RealmBoundWrap::destructor_count = 0;
+
+TEST_F(CppgcTest, CleanIsNotCalledWithFreedRealm) {
+ constexpr int kCount = 32;
+ {
+ const v8::HandleScope handle_scope(isolate_);
+ Env env{handle_scope, Argv()};
+ RealmBoundWrap::live_realm = (*env)->principal_realm();
+
+ v8::Local<v8::FunctionTemplate> ctor = v8::FunctionTemplate::New(isolate_);
+ ctor->InstanceTemplate()->SetInternalFieldCount(
+ node::CppgcMixin::kInternalFieldCount);
+ v8::Local<v8::Function> fn =
+ ctor->GetFunction(env.context()).ToLocalChecked();
+ {
+ v8::HandleScope inner_scope(isolate_);
+ for (int i = 0; i <= kCount; i++) {
+ v8::Local<v8::Object> obj =
+ fn->NewInstance(env.context()).ToLocalChecked();
+ cppgc::MakeGarbageCollected<RealmBoundWrap>(
+ (*env)->cppgc_allocation_handle(), *env, obj);
+ if (i < kCount) continue;
+ env.context()
+ ->Global()
+ ->Set(env.context(),
+ v8::String::NewFromUtf8Literal(isolate_, "kept"),
+ obj)
+ .Check();
+ }
+ }
+
+ CollectGarbageLeavingSweepingPending();
+ EXPECT_LT(RealmBoundWrap::destructor_count, kCount);
+ }
+ RealmBoundWrap::live_realm = nullptr;
+ FinishSweeping();
+
+ EXPECT_GE(RealmBoundWrap::clean_count, 1);
+ EXPECT_EQ(RealmBoundWrap::clean_with_dead_realm_count, 0);
+}
+
+TEST_F(CppgcTest, WrappersAliveAtFreeEnvironmentDoNotLeak) {
+ const v8::HandleScope handle_scope(isolate_);
+ Env env{handle_scope, Argv()};
+ node::LoadEnvironment(*env,
+ "globalThis.script = new (require('vm').Script)('1');"
+ "globalThis.context = require('vm').createContext();")
+ .ToLocalChecked();
+}
+
+TEST_F(CppgcTest, VmScriptCollectedBeforeFreeEnvironmentSweptAfter) {
+ {
+ const v8::HandleScope handle_scope(isolate_);
+ Env env{handle_scope, Argv()};
+ node::LoadEnvironment(*env,
+ "const { Script } = require('vm');"
+ "for (let i = 0; i < 64; i++) new Script('1');"
+ "undefined;")
+ .ToLocalChecked();
+ CollectGarbageLeavingSweepingPending();
+ }
+ FinishSweeping();
+}
@@ -1,112 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Caleb Everett <everett.caleb@gmail.com>
Date: Mon, 10 Aug 2026 10:58:05 -0400
Subject: src: fix use-after-free in CleanupHookThunkRun
CleanupHookThunkRun() read thunk->isolate/fun/arg from the
CleanupHookThunk after invoking thunk->fun(). For every
node::ObjectWrap alive at teardown, thunk->fun is
ObjectWrap::CleanupHook, which deletes the wrap; ~ObjectWrap() calls
RemoveEnvironmentCleanupHook() itself, erasing the CleanupHookThunk
from the registry and freeing the node it lives in. The subsequent
read of thunk->isolate/fun/arg to make the (now redundant) second
RemoveEnvironmentCleanupHook() call was therefore a use-after-free.
Cache the fields before running the hook so nothing is read from
`thunk` once it may have been freed, and add a cctest that registers a
cleanup hook which removes itself while the queue is drained.
Backport of nodejs/node#65630. This patch can be removed when Electron
updates to a Node.js release that contains it.
Co-authored-by: Sreehari Annam <sreehari.annam@gmail.com>
Co-authored-by: nsavoire <19255994+nsavoire@users.noreply.github.com>
Signed-off-by: Caleb Everett <everett.caleb@gmail.com>
diff --git a/src/api/hooks.cc b/src/api/hooks.cc
index 07efb145a29eecc3e701f4c7b62ca96ea4555050..3213a30a7bc734a6626d0f93d4ce2ac7ddc747f6 100644
--- a/src/api/hooks.cc
+++ b/src/api/hooks.cc
@@ -157,8 +157,15 @@ static ExclusiveAccess<CleanupHookRegistry> cleanup_hook_registry;
static void CleanupHookThunkRun(void* arg) {
const CleanupHookThunk* thunk = static_cast<CleanupHookThunk*>(arg);
- thunk->fun(thunk->arg);
- RemoveEnvironmentCleanupHook(thunk->isolate, thunk->fun, thunk->arg);
+ // `thunk->fun` may itself remove and free this CleanupHookThunk (e.g. via
+ // ~ObjectWrap(), which calls RemoveEnvironmentCleanupHook()), so cache the
+ // fields we still need before invoking it rather than reading them from
+ // `thunk` afterwards.
+ Isolate* isolate = thunk->isolate;
+ CleanupHook fun = thunk->fun;
+ void* fun_arg = thunk->arg;
+ fun(fun_arg);
+ RemoveEnvironmentCleanupHook(isolate, fun, fun_arg);
}
void AddEnvironmentCleanupHook(Isolate* isolate,
diff --git a/test/cctest/test_environment.cc b/test/cctest/test_environment.cc
index 3e846a672900807ba8df19e626837ce18be503c4..27c1556db02fac99b5f9b23427933c7a243d02c4 100644
--- a/test/cctest/test_environment.cc
+++ b/test/cctest/test_environment.cc
@@ -27,6 +27,12 @@ static void at_exit_callback_ordered2(void* arg);
static void at_exit_js(void* arg);
static std::string cb_1_arg; // NOLINT(runtime/string)
+struct SelfRemovingCleanupHookState {
+ v8::Isolate* isolate;
+ bool ran = false;
+};
+static void self_removing_cleanup_hook(void* arg);
+
class EnvironmentTest : public EnvironmentTestFixture {
private:
void TearDown() override {
@@ -309,6 +315,27 @@ TEST_F(EnvironmentTest, AtExitRunsJS) {
EXPECT_TRUE(called_at_exit_js);
}
+// A cleanup hook that removes itself while the environment cleanup queue is
+// being drained must not cause a use-after-free. This registers such a hook
+// directly rather than through node::ObjectWrap, whose destructor removes
+// its own hook and is what makes this reachable for addons since #63642.
+// The use-after-free is silent in ordinary builds; it is caught by the
+// ASan/Valgrind CI, which is also how the original assertion (#63923)
+// surfaced. Regression test for https://github.com/nodejs/node/issues/65195.
+TEST_F(EnvironmentTest, RemoveEnvironmentCleanupHookDuringCleanup) {
+ const v8::HandleScope handle_scope(isolate_);
+ const Argv argv;
+ SelfRemovingCleanupHookState state{isolate_};
+ {
+ Env env{handle_scope, argv};
+ node::AddEnvironmentCleanupHook(
+ isolate_, self_removing_cleanup_hook, &state);
+ // Destroying `env` runs FreeEnvironment() -> RunCleanup(), which drains
+ // the cleanup queue and invokes CleanupHookThunkRun() for the hook above.
+ }
+ EXPECT_TRUE(state.ran);
+}
+
TEST_F(EnvironmentTest, MultipleEnvironmentsPerIsolate) {
const v8::HandleScope handle_scope(isolate_);
const Argv argv;
@@ -392,6 +419,19 @@ static void at_exit_js(void* arg) {
called_at_exit_js = true;
}
+// Reproduces the sequence node::ObjectWrap performs since
+// https://github.com/nodejs/node/pull/63642, without using ObjectWrap
+// itself: the hook removes its own environment cleanup hook. When that runs
+// while the cleanup queue is being drained, CleanupHookThunkRun() must not
+// read the CleanupHookThunk after invoking the hook -- the hook has already
+// erased and freed it. See https://github.com/nodejs/node/issues/65195.
+static void self_removing_cleanup_hook(void* arg) {
+ auto* state = static_cast<SelfRemovingCleanupHookState*>(arg);
+ state->ran = true;
+ node::RemoveEnvironmentCleanupHook(
+ state->isolate, self_removing_cleanup_hook, state);
+}
+
TEST_F(EnvironmentTest, SetImmediateCleanup) {
int called = 0;
int called_unref = 0;
@@ -1,167 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Anna Henningsen <anna@addaleax.net>
Date: Thu, 18 Jun 2026 17:38:03 +0200
Subject: src: keep global list of addon-provided cleanup hooks
A recent change, 215027c8eded2e, introduced flakiness into our
test suite that exposed an issue with the cleanup hook API design.
Specifically, the signatures of `AddEnvironmentCleanupHook()` and
`RemoveEnvironmentCleanupHook()` are problematic. Both functions
take `Isolate*` arguments, as addons are not generally expected
to have to care about the Node.js `Environment` as a first-class
scope provider.
However, this model made the incorrect assumption that in the
situations in which `RemoveEnvironmentCleanupHook()` would be
invoked an `Environment` would always be associated with the
current `Isolate` (via the current V8 `Context`, if there is one).
This occasionally breaks down when `RemoveEnvironmentCleanupHook()`
is called during garbage collection -- which would be an expected
use case of the functionality, but one that has not been covered
through our tests before 215027c8eded2e.
Since Node.js guarantees API and ABI stability within a major version,
and this is a bug that is independent from the aforementioned change,
this commit resolves it by adding global mutable state to keep track
off cleanup hooks registered through the Node.js public API.
Obviously, this solution does not represent a desirable long-term
state, and a semver-minor follow up should add an API that does not
require modifications to these data structures, likely based on
the async cleanup hook API which already solves this issue properly.
Refs: https://github.com/nodejs/node/pull/63642
Fixes: https://github.com/nodejs/node/issues/63923
Signed-off-by: Anna Henningsen <anna@addaleax.net>
PR-URL: https://github.com/nodejs/node/pull/63985
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Backport of https://github.com/nodejs/node/pull/63985 for
https://github.com/electron/electron/issues/53387: Node.js 24.19.0 made
node::ObjectWrap register an environment cleanup hook, and removing it
from ~ObjectWrap() during GC (no current context) hit CHECK_NOT_NULL(env)
and aborted native addons. Conflict in test/addons/worker-addon/binding.cc
resolved by deriving `isolate` from the module context, since v24.x does
not carry the upstream refactor that introduced that local.
(cherry picked from commit 68321eff80918e324e9fdaf1aa8cee6db14b84f7)
diff --git a/src/api/hooks.cc b/src/api/hooks.cc
index 86132d5eec29ce1fea946e233a96c2ba9cc64471..07efb145a29eecc3e701f4c7b62ca96ea4555050 100644
--- a/src/api/hooks.cc
+++ b/src/api/hooks.cc
@@ -127,20 +127,71 @@ struct ACHHandle final {
// this.
void DeleteACHHandle::operator ()(ACHHandle* handle) const { delete handle; }
+// TODO(addaleax): Having this extra set of data structures is far from
+// ideal, but unfortunately the public synchronous cleanup hook API was
+// slightly mis-designed; in particular, RemoveEnvironmentCleanupHook() needs
+// to keep working when the Isolate either has no active context (such as
+// during GC) or that context is associated with another Node.js Environment.
+// We should align this with the asynchronous API, which handles this properly
+// through an explicit reference to the cleanup hook instead of requiring
+// lookups in internal maps.
+struct CleanupHookThunk final {
+ Isolate* isolate;
+ Environment* env;
+ CleanupHook fun;
+ void* arg;
+
+ bool operator==(const CleanupHookThunk& other) const {
+ // `env` is intentionally not part of this comparison
+ return isolate == other.isolate && fun == other.fun && arg == other.arg;
+ }
+};
+struct CleanupHookThunkHash {
+ size_t operator()(const CleanupHookThunk& thunk) const {
+ return std::hash<void*>()(thunk.arg);
+ }
+};
+using CleanupHookRegistry =
+ std::unordered_set<CleanupHookThunk, CleanupHookThunkHash>;
+static ExclusiveAccess<CleanupHookRegistry> cleanup_hook_registry;
+
+static void CleanupHookThunkRun(void* arg) {
+ const CleanupHookThunk* thunk = static_cast<CleanupHookThunk*>(arg);
+ thunk->fun(thunk->arg);
+ RemoveEnvironmentCleanupHook(thunk->isolate, thunk->fun, thunk->arg);
+}
+
void AddEnvironmentCleanupHook(Isolate* isolate,
CleanupHook fun,
void* arg) {
Environment* env = Environment::GetCurrent(isolate);
CHECK_NOT_NULL(env);
- env->AddCleanupHook(fun, arg);
+ void* wrapped_arg;
+ {
+ ExclusiveAccess<CleanupHookRegistry>::Scoped registry(
+ &cleanup_hook_registry);
+ auto result = registry->insert({isolate, env, fun, arg});
+ CHECK(result.second);
+ wrapped_arg = const_cast<CleanupHookThunk*>(&*result.first);
+ }
+ env->AddCleanupHook(CleanupHookThunkRun, wrapped_arg);
}
void RemoveEnvironmentCleanupHook(Isolate* isolate,
CleanupHook fun,
void* arg) {
- Environment* env = Environment::GetCurrent(isolate);
- CHECK_NOT_NULL(env);
- env->RemoveCleanupHook(fun, arg);
+ CleanupHookThunk thunk;
+ void* wrapped_arg;
+ {
+ ExclusiveAccess<CleanupHookRegistry>::Scoped registry(
+ &cleanup_hook_registry);
+ auto result = registry->find({isolate, nullptr, fun, arg});
+ if (result == registry->end()) return;
+ wrapped_arg = const_cast<CleanupHookThunk*>(&*result);
+ thunk = *result;
+ registry->erase(result);
+ }
+ thunk.env->RemoveCleanupHook(CleanupHookThunkRun, wrapped_arg);
}
static void FinishAsyncCleanupHook(void* arg) {
diff --git a/test/addons/worker-addon/binding.cc b/test/addons/worker-addon/binding.cc
index a5f9d8b3f835d8926d55d06b57a523617afc6e65..183cad371c3286d872f681015585cc80d57fd0b5 100644
--- a/test/addons/worker-addon/binding.cc
+++ b/test/addons/worker-addon/binding.cc
@@ -51,12 +51,26 @@ void Cleanup(void* str) {
void Initialize(Local<Object> exports,
Local<Value> module,
Local<Context> context) {
+ Isolate* isolate = context->GetIsolate();
node::AddEnvironmentCleanupHook(
- context->GetIsolate(),
- Cleanup,
- const_cast<void*>(static_cast<const void*>("cleanup")));
- node::AddEnvironmentCleanupHook(context->GetIsolate(), Dummy, nullptr);
- node::RemoveEnvironmentCleanupHook(context->GetIsolate(), Dummy, nullptr);
+ isolate, Cleanup, const_cast<void*>(static_cast<const void*>("cleanup")));
+
+ // Test that adding and removing a cleanup hook works as expected
+ {
+ node::AddEnvironmentCleanupHook(isolate, Dummy, nullptr);
+ node::RemoveEnvironmentCleanupHook(isolate, Dummy, nullptr);
+ }
+
+ // Test that adding and removing a cleanup hook also works if there
+ // is no active context during removal
+ {
+ node::AddEnvironmentCleanupHook(isolate, Dummy, nullptr);
+ {
+ context->Exit();
+ node::RemoveEnvironmentCleanupHook(isolate, Dummy, nullptr);
+ context->Enter();
+ }
+ }
if (getenv("addExtraItemToEventLoop") != nullptr) {
// Add an item to the event loop that we do not clean up in order to make
@@ -172,10 +172,10 @@ index 5f5af63486a556f00b1cc3d44ec731f414904626..3132a96abb87f9275080ca0d8b2015b1
int32_t port = value->Int32Value(env->context()).FromMaybe(0);
diff --git a/src/node_sqlite.cc b/src/node_sqlite.cc
index a44d310411b1de86f72f2d817c046fc11b558f71..fc7d4a826b4e34f684e8371f112a79cafa6e9abd 100644
index 0b32b2a8be3650da0d46f72ee344363fb341b81d..ebdc0e049dd95c388a8e9465c0132d03afcf746a 100644
--- a/src/node_sqlite.cc
+++ b/src/node_sqlite.cc
@@ -791,7 +791,7 @@ Intercepted DatabaseSyncLimits::LimitsGetter(
@@ -853,7 +853,7 @@ Intercepted DatabaseSyncLimits::LimitsGetter(
Intercepted DatabaseSyncLimits::LimitsSetter(
Local<Name> property,
Local<Value> value,
@@ -185,10 +185,10 @@ index a44d310411b1de86f72f2d817c046fc11b558f71..fc7d4a826b4e34f684e8371f112a79ca
return Intercepted::kNo;
}
diff --git a/src/node_sqlite.h b/src/node_sqlite.h
index 9c7a4380dcf55762a1a21f971075c0a5aaae85ee..d77c7fc6362343db0c0cda60b9036fe69cbc78b3 100644
index 442f291b05d65168b4fe6383adca703cb40f510d..998ac3b098752e70f00ce38ac014306346750586 100644
--- a/src/node_sqlite.h
+++ b/src/node_sqlite.h
@@ -441,7 +441,7 @@ class DatabaseSyncLimits : public BaseObject {
@@ -565,7 +565,7 @@ class DatabaseSyncLimits : public BaseObject {
static v8::Intercepted LimitsSetter(
v8::Local<v8::Name> property,
v8::Local<v8::Value> value,
@@ -11,10 +11,10 @@ which now have the V2 semantics. Rename the call sites accordingly.
https://chromium-review.googlesource.com/c/v8/v8/+/7955758
diff --git a/src/api/environment.cc b/src/api/environment.cc
index 90d40720a4faad865cf6584bee73e5739d534f36..c81ef82c5a23d30ec7430b8726bd28e1be2f225e 100644
index 6313d5ce1839fafb175c0e0c74eb39445baed467..4126d4b9f6caf6cbddba403189858c7f0ec60abb 100644
--- a/src/api/environment.cc
+++ b/src/api/environment.cc
@@ -971,7 +971,7 @@ MaybeLocal<Object> InitializePrivateSymbols(Local<Context> context,
@@ -989,7 +989,7 @@ MaybeLocal<Object> InitializePrivateSymbols(Local<Context> context,
Local<Object> private_symbols_object;
if (!private_symbols->NewInstance(context).ToLocal(&private_symbols_object) ||
@@ -23,7 +23,7 @@ index 90d40720a4faad865cf6584bee73e5739d534f36..c81ef82c5a23d30ec7430b8726bd28e1
.IsNothing()) {
return MaybeLocal<Object>();
}
@@ -997,7 +997,7 @@ MaybeLocal<Object> InitializePerIsolateSymbols(Local<Context> context,
@@ -1015,7 +1015,7 @@ MaybeLocal<Object> InitializePerIsolateSymbols(Local<Context> context,
Local<Object> per_isolate_symbols_object;
if (!per_isolate_symbols->NewInstance(context).ToLocal(
&per_isolate_symbols_object) ||
@@ -48,7 +48,7 @@ index 6a3c4e6952a8f3250bf1b57652a1622e9f63ec52..487b8b7adfd35646d20fdb15be5fd6f2
}
return false;
diff --git a/src/js_native_api_v8.cc b/src/js_native_api_v8.cc
index 6c87611f7cbaf8a0b4c04f812f65381ede112056..da2ed4bae5a552117ad808c19a2e57f884b037ae 100644
index 29e2e1808a3f42a35d9478f2f8949037b0011880..33ac5632781134d76f11143b24db1bc2db5b581a 100644
--- a/src/js_native_api_v8.cc
+++ b/src/js_native_api_v8.cc
@@ -1579,7 +1579,7 @@ napi_status NAPI_CDECL node_api_set_prototype(napi_env env,
@@ -135,10 +135,10 @@ index 51c097e69388a516aa7a9239053367faa4f7595e..d2337033fc1bf538f84c619add57bcc7
THROW_ERR_INVALID_INVOCATION(isolate);
return;
diff --git a/src/node_options.cc b/src/node_options.cc
index 5cbb2e7c593f08a18e670a49c1025a25c2511e7c..d4dffb1093f7a792b0e9cef2756b530cbc78ce88 100644
index 9ccad939f1aefe38bcd7fa1f906c0e40dfc0adfd..d78133e65c275219a38976d4cde4e81901d906e3 100644
--- a/src/node_options.cc
+++ b/src/node_options.cc
@@ -1820,7 +1820,7 @@ void GetCLIOptionsInfo(const FunctionCallbackInfo<Value>& args) {
@@ -1847,7 +1847,7 @@ void GetCLIOptionsInfo(const FunctionCallbackInfo<Value>& args) {
Local<Map> options = Map::New(isolate);
if (options
@@ -147,7 +147,7 @@ index 5cbb2e7c593f08a18e670a49c1025a25c2511e7c..d4dffb1093f7a792b0e9cef2756b530c
env->primordials_safe_map_prototype_object())
.IsNothing()) {
return;
@@ -1861,7 +1861,7 @@ void GetCLIOptionsInfo(const FunctionCallbackInfo<Value>& args) {
@@ -1888,7 +1888,7 @@ void GetCLIOptionsInfo(const FunctionCallbackInfo<Value>& args) {
if (!ToV8Value(context, _ppop_instance.aliases_).ToLocal(&aliases)) return;
if (aliases.As<Object>()
@@ -157,10 +157,10 @@ index 5cbb2e7c593f08a18e670a49c1025a25c2511e7c..d4dffb1093f7a792b0e9cef2756b530c
.IsNothing()) {
return;
diff --git a/src/node_sqlite.cc b/src/node_sqlite.cc
index a04c7b97e743d75a53e8e01f31e40f601a207572..a44d310411b1de86f72f2d817c046fc11b558f71 100644
index d1ef4d06f73bcb23686d91df2a0a3d5141e1ba70..0b32b2a8be3650da0d46f72ee344363fb341b81d 100644
--- a/src/node_sqlite.cc
+++ b/src/node_sqlite.cc
@@ -765,7 +765,7 @@ Intercepted DatabaseSyncLimits::LimitsGetter(
@@ -827,7 +827,7 @@ Intercepted DatabaseSyncLimits::LimitsGetter(
}
DatabaseSyncLimits* limits;
@@ -169,7 +169,7 @@ index a04c7b97e743d75a53e8e01f31e40f601a207572..a44d310411b1de86f72f2d817c046fc1
Environment* env = limits->env();
Isolate* isolate = env->isolate();
@@ -797,7 +797,7 @@ Intercepted DatabaseSyncLimits::LimitsSetter(
@@ -859,7 +859,7 @@ Intercepted DatabaseSyncLimits::LimitsSetter(
}
DatabaseSyncLimits* limits;
@@ -178,7 +178,7 @@ index a04c7b97e743d75a53e8e01f31e40f601a207572..a44d310411b1de86f72f2d817c046fc1
Environment* env = limits->env();
Isolate* isolate = env->isolate();
@@ -3039,9 +3039,9 @@ BaseObjectPtr<StatementSyncIterator> StatementExecutionHelper::Iterate(
@@ -3253,9 +3253,9 @@ BaseObjectPtr<StatementSyncIterator> StatementExecutionHelper::Iterate(
}
if (iter->object()
@@ -191,10 +191,10 @@ index a04c7b97e743d75a53e8e01f31e40f601a207572..a44d310411b1de86f72f2d817c046fc1
return BaseObjectPtr<StatementSyncIterator>();
}
diff --git a/src/node_util.cc b/src/node_util.cc
index 6d3373caae6c5cc22e16fc32e7ea007178aa1a20..ad979ff1c223b571486265d27b35cb617dfc82a9 100644
index 39523bd256c8bf22597ba79dd06ea451025ffabb..04217d6dce9333cf0e5a1c6de711f49b93c46663 100644
--- a/src/node_util.cc
+++ b/src/node_util.cc
@@ -366,7 +366,7 @@ static void DefineLazyPropertiesGetter(
@@ -369,7 +369,7 @@ static void DefineLazyPropertiesGetter(
// When this getter is invoked in a vm context, the `Realm::GetCurrent(info)`
// returns a nullptr and retrieve the creation context via `this` object and
// get the creation Realm.
@@ -203,6 +203,15 @@ index 6d3373caae6c5cc22e16fc32e7ea007178aa1a20..ad979ff1c223b571486265d27b35cb61
if (!receiver_val->IsObject()) {
THROW_ERR_INVALID_INVOCATION(isolate);
return;
@@ -522,7 +522,7 @@ void Initialize(Local<Object> target,
{
const Local<Object> prototype =
- SharedArrayBuffer::New(isolate, 0)->GetPrototypeV2().As<Object>();
+ SharedArrayBuffer::New(isolate, 0)->GetPrototype().As<Object>();
const Local<Object> descriptor =
prototype
->GetOwnPropertyDescriptor(
diff --git a/src/node_webstorage.cc b/src/node_webstorage.cc
index 8a058f19834134ca65b7a763b7c41fe850642980..3856e9cdaa305f4919c315060bae8d1a5f17cb80 100644
--- a/src/node_webstorage.cc
@@ -76,10 +76,10 @@ index 53d4de01666271e6bb84b04d3386b7b1cb193cdd..757d39558f7853d39ee0d574152bb381
THROW_ERR_INVALID_INVOCATION(isolate);
return;
diff --git a/src/node_sqlite.cc b/src/node_sqlite.cc
index 91ae8c9d31f5c8984c25c1030238fbe0db5c95a2..a04c7b97e743d75a53e8e01f31e40f601a207572 100644
index f21c7deea5edd85198bb4c015af0d38b42e7d8c9..d1ef4d06f73bcb23686d91df2a0a3d5141e1ba70 100644
--- a/src/node_sqlite.cc
+++ b/src/node_sqlite.cc
@@ -765,7 +765,7 @@ Intercepted DatabaseSyncLimits::LimitsGetter(
@@ -827,7 +827,7 @@ Intercepted DatabaseSyncLimits::LimitsGetter(
}
DatabaseSyncLimits* limits;
@@ -88,7 +88,7 @@ index 91ae8c9d31f5c8984c25c1030238fbe0db5c95a2..a04c7b97e743d75a53e8e01f31e40f60
Environment* env = limits->env();
Isolate* isolate = env->isolate();
@@ -797,7 +797,7 @@ Intercepted DatabaseSyncLimits::LimitsSetter(
@@ -859,7 +859,7 @@ Intercepted DatabaseSyncLimits::LimitsSetter(
}
DatabaseSyncLimits* limits;
@@ -98,10 +98,10 @@ index 91ae8c9d31f5c8984c25c1030238fbe0db5c95a2..a04c7b97e743d75a53e8e01f31e40f60
Environment* env = limits->env();
Isolate* isolate = env->isolate();
diff --git a/src/node_util.cc b/src/node_util.cc
index 027f668c21944308d021e8eb10ee3898c8b482a7..ce381c00888b032c281938a7bab334058e075ec8 100644
index 96c0c9397546afc420f3649b5d5ba9f636364bb9..c3a6fbed06efc92e3cc0ac59ab51c8b802033c81 100644
--- a/src/node_util.cc
+++ b/src/node_util.cc
@@ -366,7 +366,7 @@ static void DefineLazyPropertiesGetter(
@@ -369,7 +369,7 @@ static void DefineLazyPropertiesGetter(
// When this getter is invoked in a vm context, the `Realm::GetCurrent(info)`
// returns a nullptr and retrieve the creation context via `this` object and
// get the creation Realm.
@@ -7,7 +7,7 @@ This refactors several allocators to allocate within the V8 memory cage,
allowing them to be compatible with the V8_SANDBOXED_POINTERS feature.
diff --git a/node.gyp b/node.gyp
index 988838e85858ef1ca87662a024c278f811477179..5df80c48e7c747a49bd2e86ea7706de757fff32e 100644
index 62c748b130c7ddec9e429d48925e79d5a395bd73..14f14c79630f19bbf7d319b669614123ef94b148 100644
--- a/node.gyp
+++ b/node.gyp
@@ -152,6 +152,7 @@
@@ -19,10 +19,10 @@ index 988838e85858ef1ca87662a024c278f811477179..5df80c48e7c747a49bd2e86ea7706de7
'src/node_snapshotable.cc',
'src/node_sockaddr.cc',
diff --git a/src/crypto/crypto_util.cc b/src/crypto/crypto_util.cc
index 3f5f70bf320040bafa479279c163d7c74d3decc6..2023f913eae6661768c09d80fffa9ce58396da9d 100644
index 19a087770f7ef98b5a93429f785a45281446d3d5..70392a2e29ac85012a11f517e103e24b0a0439d0 100644
--- a/src/crypto/crypto_util.cc
+++ b/src/crypto/crypto_util.cc
@@ -403,24 +403,30 @@ std::unique_ptr<BackingStore> ByteSource::ReleaseToBackingStore(
@@ -765,24 +765,30 @@ std::unique_ptr<BackingStore> ByteSource::ReleaseToBackingStore(
// It's ok for allocated_data_ to be nullptr but
// only if size_ is zero.
CHECK_IMPLIES(size_ > 0, allocated_data_ != nullptr);
@@ -69,7 +69,7 @@ index 3f5f70bf320040bafa479279c163d7c74d3decc6..2023f913eae6661768c09d80fffa9ce5
#else
std::unique_ptr<BackingStore> ptr = ArrayBuffer::NewBackingStore(
allocated_data_,
@@ -793,19 +799,13 @@ namespace {
@@ -1155,19 +1161,13 @@ namespace {
// using OPENSSL_malloc. However, if the secure heap is
// initialized, SecureBuffer will automatically use it.
void SecureBuffer(const FunctionCallbackInfo<Value>& args) {
@@ -95,7 +95,7 @@ index 3f5f70bf320040bafa479279c163d7c74d3decc6..2023f913eae6661768c09d80fffa9ce5
auto data = DataPointer::SecureAlloc(len);
diff --git a/src/crypto/crypto_x509.cc b/src/crypto/crypto_x509.cc
index be4067df0e226636cb6d876c41aa830343069f86..82da68d8eef06c57aae76f2b54eeb09db5b41ecf 100644
index 944802925def832be06a05f05a9ff535b5e0d97c..1bf003f830812664ad903dbdfe30366835767c0b 100644
--- a/src/crypto/crypto_x509.cc
+++ b/src/crypto/crypto_x509.cc
@@ -141,19 +141,17 @@ MaybeLocal<Value> ToBuffer(Environment* env, BIOPointer* bio) {
@@ -425,10 +425,10 @@ index 0000000000000000000000000000000000000000..44bc180778a23ce611b570c91242a1b1
+
+#endif // SRC_NODE_SERDES_UTILS_H_
diff --git a/src/node_trace_events.cc b/src/node_trace_events.cc
index 5e01f64a5039235447101d0d8cfbdba3da4ddbc1..49c457cae2b3da603a548874f63dbdf9f50580d9 100644
index 08eb71c5122d749bd499d55a7cd878b50ca321a0..f2d766b8b192dfbbd40af1f8ffaee624b747bb1d 100644
--- a/src/node_trace_events.cc
+++ b/src/node_trace_events.cc
@@ -141,12 +141,28 @@ static void GetCategoryEnabledBuffer(const FunctionCallbackInfo<Value>& args) {
@@ -145,12 +145,28 @@ static void GetCategoryEnabledBuffer(const FunctionCallbackInfo<Value>& args) {
const uint8_t* enabled_pointer =
TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(category_name.out());
uint8_t* enabled_pointer_cast = const_cast<uint8_t*>(enabled_pointer);
@@ -19,7 +19,7 @@ user with ordinary permissions.
Refs: https://github.com/nodejs/node/pull/57103
diff --git a/test/parallel/test-fs-rm.js b/test/parallel/test-fs-rm.js
index e92bf8c079715fc97f491f83be09a606769eba18..b15118fc9aa0d63688cdac07e8004f452d86d08e 100644
index 1d0578e3004da463d30cdb9ff2bd28477d4318f5..6a2607ad57ece1e9a0b82dded7bf46bb722e18d9 100644
--- a/test/parallel/test-fs-rm.js
+++ b/test/parallel/test-fs-rm.js
@@ -491,7 +491,8 @@ if (isGitPresent) {
@@ -0,0 +1,26 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sam Attard <sattard@anthropic.com>
Date: Thu, 15 Oct 2026 18:02:58 +0000
Subject: test: drop removed wasm rab integration flag
Chromium's V8 shipped resizable ArrayBuffer / WebAssembly integration and
removed the --experimental-wasm-rab-integration flag, so passing it makes
the test exit with "bad option". Node.js v24.22.0 added the flag to
test-internal-webidl-buffer-source.js.
This patch can be removed once Node.js's bundled V8 no longer has the
flag and the test stops passing it.
Refs: https://github.com/nodejs/node/pull/65845
Refs: https://chromium-review.googlesource.com/c/v8/v8/+/7708297
diff --git a/test/parallel/test-internal-webidl-buffer-source.js b/test/parallel/test-internal-webidl-buffer-source.js
index b3158bd7d3481e3257fc97a1ed584cd27e8d0c9b..8e81f42a9456054d95dd60fca6c99f4ebcf21736 100644
--- a/test/parallel/test-internal-webidl-buffer-source.js
+++ b/test/parallel/test-internal-webidl-buffer-source.js
@@ -1,4 +1,4 @@
-// Flags: --expose-internals --experimental-wasm-rab-integration
+// Flags: --expose-internals
'use strict';
const common = require('../common');
@@ -0,0 +1,31 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sam Attard <sattard@anthropic.com>
Date: Thu, 15 Oct 2026 19:31:39 +0000
Subject: test: skip rmSync permission error test when running as root
test-fs-rmSync-special-char-additional-error.js (new in v24.22.0) makes
a directory read-only and expects rmSync() to fail with EACCES. Root
ignores directory permissions, so the removal succeeds and the cleanup
chmod then throws ENOENT. Electron's Linux CI runs the Node.js suite as
root; skip there like test-fs-rm.js already guards its permission block
with process.getuid() !== 0.
This should be upstreamed; remove the patch once Node.js carries the
guard.
Refs: https://github.com/nodejs/node/pull/64453
diff --git a/test/parallel/test-fs-rmSync-special-char-additional-error.js b/test/parallel/test-fs-rmSync-special-char-additional-error.js
index 9b4de3c84d626fbbc4d537bd539276dc42d5f5c4..615a6128302efb9906bfce0bea93f93020477953 100644
--- a/test/parallel/test-fs-rmSync-special-char-additional-error.js
+++ b/test/parallel/test-fs-rmSync-special-char-additional-error.js
@@ -6,6 +6,9 @@ const fs = require('node:fs');
const path = require('node:path');
const { execSync } = require('child_process');
+if (!common.isWindows && process.getuid() === 0)
+ common.skip('as this test checks permission errors, it cannot run as root');
+
tmpdir.refresh(); // Prepare a clean temporary directory
function countOccurrences(haystack, needle) {
@@ -70,10 +70,10 @@ index 1066633daf65d430b5f46e1b226ee3cf70979c33..c7c39ae8c0632695d8b22023b8e6b1d1
class ContextifyScript final : CPPGC_MIXIN(ContextifyScript) {
diff --git a/test/cctest/test_environment.cc b/test/cctest/test_environment.cc
index a219d512570136a9b1e940942b8426bf19d0d1f1..3e846a672900807ba8df19e626837ce18be503c4 100644
index 6a48db67baad3d97e3bc8a469e65fc5b07548ffd..6a0cbefdb84b26ac0f37a90742c25a10662eaf41 100644
--- a/test/cctest/test_environment.cc
+++ b/test/cctest/test_environment.cc
@@ -706,15 +706,16 @@ TEST_F(EnvironmentTest, NestedMicrotaskQueue) {
@@ -806,15 +806,16 @@ TEST_F(EnvironmentTest, NestedMicrotaskQueue) {
const v8::HandleScope handle_scope(isolate_);
const Argv argv;
+4 -10
View File
@@ -302,8 +302,9 @@ int NodeMain() {
// bootstrapped environment) from the snapshot instead of running the
// bootstrap -- the same path the browser process takes in
// NodeBindings::CreateEnvironment.
auto snapshot_wrapper = snapshot ? snapshot->AsEmbedderWrapper()
: node::EmbedderSnapshotData::Pointer{};
auto snapshot_wrapper =
snapshot ? node::EmbedderSnapshotData::BuiltinSnapshotData()
: node::EmbedderSnapshotData::Pointer{};
isolate_data = node::CreateIsolateData(isolate, loop, gin_env.platform(),
/*allocator=*/nullptr,
snapshot_wrapper.get());
@@ -323,21 +324,14 @@ int NodeMain() {
static_cast<node::EnvironmentFlags::Flags>(env_flags));
CHECK_NE(nullptr, env);
node::IsolateSettings isolate_settings;
if (snapshot) {
// The snapshot's main context was created inside CreateEnvironment and
// is not entered yet; enter it for the lifetime of the process, as
// JavascriptEnvironment does for the context it creates itself (its
// destructor exits the current context).
env->context()->Enter();
// node::CreateEnvironment already installed the per-isolate message
// listener while deserializing (SetIsolateErrorHandlers, snapshot path
// only). Listeners are additive, so don't let SetIsolateUpForNode add a
// second one -- every uncaught exception would be reported twice.
isolate_settings.flags &=
~node::IsolateSettingsFlags::MESSAGE_LISTENER_WITH_ERROR_LEVEL;
}
node::SetIsolateUpForNode(isolate, isolate_settings);
node::SetIsolateUpForNode(isolate, node::IsolateSettings{});
gin_helper::Dictionary process(isolate, env->process_object());
process.SetMethod<&ElectronBindings::Crash>("crash");
+3 -7
View File
@@ -799,9 +799,6 @@ void NodeBindings::SetUpIsolate(v8::Isolate* const isolate) {
browser_env_ == BrowserEnvironment::kUtility) {
// Node.js requires that microtask checkpoints be explicitly invoked.
is.policy = v8::MicrotasksPolicy::kExplicit;
// node::CreateEnvironment already added Node's listener if it built the
// environment from the Node snapshot; keep exactly one.
isolate->RemoveMessageListeners(node::errors::PerIsolateMessageListener);
} else {
// Blink expects the microtasks policy to be kScoped, but Node.js expects it
// to be kExplicit. In the renderer, there can be many contexts within the
@@ -871,10 +868,9 @@ std::shared_ptr<node::Environment> NodeBindings::CreateEnvironment(
// The Node startup snapshot's per-isolate data (templates, primordials)
// is fed to CreateIsolateData so the bootstrap is deserialized.
auto snapshot_wrapper = from_snapshot
? node::SnapshotBuilder::GetEmbeddedSnapshotData()
->AsEmbedderWrapper()
: node::EmbedderSnapshotData::Pointer{};
auto snapshot_wrapper =
from_snapshot ? node::EmbedderSnapshotData::BuiltinSnapshotData()
: node::EmbedderSnapshotData::Pointer{};
auto* isolate_data =
node::CreateIsolateData(isolate, uv_loop_, platform,
/*allocator=*/nullptr, snapshot_wrapper.get());