Repository navigation
src: fix null pointer call when running without a startup snapshot - #65820
Merged
nodejs-github-bot merged 1 commit intoSep 7, 2026
Merged
nodejs-github-bot merged 1 commit into
nodejs-github-bot merged 1 commit into
Conversation
Collaborator
|
Review requested:
|
Collaborator
Without a startup snapshot (`--no-node-snapshot`, a `--without-node-snapshot` build, or an embedder Environment that was bootstrapped from scratch) starting a Worker made a member call through a null `SnapshotData*`, and so did `NodeMainInstance` while setting itself up. It only worked because the function called does not touch `this`; UBSan reports it for every such Worker. The call existed because `IsolateData::CreateIsolateData()` took an `EmbedderSnapshotData*` and unwrapped it straight away, so the two internal callers wrapped their possibly-null `SnapshotData*` with `AsEmbedderWrapper()` only for it to be unwrapped again. Let the internal function take the `SnapshotData*` itself, unwrap in the public `CreateIsolateData()` only, and drop `AsEmbedderWrapper()`, which has no other users. Refs: nodejs#47731 Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com>
codebytere
force-pushed
the
fix/embedder-worker-null-snapshot-ub
branch
from
September 5, 2026 17:56
a6a8713 to
c55177f
Compare
Collaborator
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #65820 +/- ##
==========================================
- Coverage 90.19% 90.17% -0.03%
==========================================
Files 770 770
Lines 264410 264410
Branches 50243 50232 -11
==========================================
- Hits 238490 238437 -53
- Misses 16924 16979 +55
+ Partials 8996 8994 -2
🚀 New features to boost your workflow:
|
Collaborator
jasnell
approved these changes
Sep 6, 2026
legendecas
approved these changes
Sep 7, 2026
Collaborator
|
Landed in 1e0ebef |
aduh95
pushed a commit
that referenced
this pull request
Sep 16, 2026
Without a startup snapshot (`--no-node-snapshot`, a `--without-node-snapshot` build, or an embedder Environment that was bootstrapped from scratch) starting a Worker made a member call through a null `SnapshotData*`, and so did `NodeMainInstance` while setting itself up. It only worked because the function called does not touch `this`; UBSan reports it for every such Worker. The call existed because `IsolateData::CreateIsolateData()` took an `EmbedderSnapshotData*` and unwrapped it straight away, so the two internal callers wrapped their possibly-null `SnapshotData*` with `AsEmbedderWrapper()` only for it to be unwrapped again. Let the internal function take the `SnapshotData*` itself, unwrap in the public `CreateIsolateData()` only, and drop `AsEmbedderWrapper()`, which has no other users. Refs: #47731 Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com> PR-URL: #65820 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95
pushed a commit
that referenced
this pull request
Sep 22, 2026
Without a startup snapshot (`--no-node-snapshot`, a `--without-node-snapshot` build, or an embedder Environment that was bootstrapped from scratch) starting a Worker made a member call through a null `SnapshotData*`, and so did `NodeMainInstance` while setting itself up. It only worked because the function called does not touch `this`; UBSan reports it for every such Worker. The call existed because `IsolateData::CreateIsolateData()` took an `EmbedderSnapshotData*` and unwrapped it straight away, so the two internal callers wrapped their possibly-null `SnapshotData*` with `AsEmbedderWrapper()` only for it to be unwrapped again. Let the internal function take the `SnapshotData*` itself, unwrap in the public `CreateIsolateData()` only, and drop `AsEmbedderWrapper()`, which has no other users. Refs: #47731 Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com> PR-URL: #65820 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
MarshallOfSound
added a commit
to electron/electron
that referenced
this pull request
Oct 15, 2026
… snapshot SnapshotData::AsEmbedderWrapper() was removed. Both call sites wrap the embedded snapshot, so use EmbedderSnapshotData::BuiltinSnapshotData(). Ref: nodejs/node#65820
MarshallOfSound
added a commit
to electron/electron
that referenced
this pull request
Oct 15, 2026
… snapshot SnapshotData::AsEmbedderWrapper() was removed. Both call sites wrap the embedded snapshot, so use EmbedderSnapshotData::BuiltinSnapshotData(). Ref: nodejs/node#65820
MarshallOfSound
added a commit
to electron/electron
that referenced
this pull request
Oct 15, 2026
… snapshot SnapshotData::AsEmbedderWrapper() was removed. Both call sites wrap the embedded snapshot, so use EmbedderSnapshotData::BuiltinSnapshotData(). Ref: nodejs/node#65820
MarshallOfSound
added a commit
to electron/electron
that referenced
this pull request
Oct 15, 2026
… snapshot SnapshotData::AsEmbedderWrapper() was removed. Both call sites wrap the embedded snapshot, so use EmbedderSnapshotData::BuiltinSnapshotData(). Ref: nodejs/node#65820
MarshallOfSound
added a commit
to electron/electron
that referenced
this pull request
Oct 15, 2026
… snapshot SnapshotData::AsEmbedderWrapper() was removed. Both call sites wrap the embedded snapshot, so use EmbedderSnapshotData::BuiltinSnapshotData(). Ref: nodejs/node#65820
MarshallOfSound
added a commit
to electron/electron
that referenced
this pull request
Oct 15, 2026
… snapshot SnapshotData::AsEmbedderWrapper() was removed. Both call sites wrap the embedded snapshot, so use EmbedderSnapshotData::BuiltinSnapshotData(). Ref: nodejs/node#65820
MarshallOfSound
added a commit
to electron/electron
that referenced
this pull request
Oct 15, 2026
… snapshot SnapshotData::AsEmbedderWrapper() was removed. Both call sites wrap the embedded snapshot, so use EmbedderSnapshotData::BuiltinSnapshotData(). Ref: nodejs/node#65820
MarshallOfSound
added a commit
to electron/electron
that referenced
this pull request
Oct 15, 2026
… snapshot SnapshotData::AsEmbedderWrapper() was removed. Both call sites wrap the embedded snapshot, so use EmbedderSnapshotData::BuiltinSnapshotData(). Ref: nodejs/node#65820
MarshallOfSound
added a commit
to electron/electron
that referenced
this pull request
Oct 15, 2026
… snapshot SnapshotData::AsEmbedderWrapper() was removed. Both call sites wrap the embedded snapshot, so use EmbedderSnapshotData::BuiltinSnapshotData(). Ref: nodejs/node#65820
MarshallOfSound
added a commit
to electron/electron
that referenced
this pull request
Oct 15, 2026
* 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: nodejs/node#62237 Ref: nodejs/node#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: nodejs/node#65966 Ref: nodejs/node#66108 Ref: nodejs/node#65484 * fix(patch): skip RSA-PSS keygen deprecation tests with BoringSSL The skip is now upstream. Ref: nodejs/node#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: nodejs/node#65778 * fix(patch): gate jspi flag on V8_ENABLE_WEBASSEMBLY Ref: nodejs/node#66082 * chore: remove upstreamed patches - nodejs/node#63985 - nodejs/node#65630 - nodejs/node#64453 - nodejs/node#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: nodejs/node#65484 * fix(patch): read the peer certificate chain without consuming it sk_X509_num() returns size_t in BoringSSL. Ref: nodejs/node#65602 * fix(patch): fix shared buffer growability validation Ref: nodejs/node#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: nodejs/node#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: nodejs/node#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: nodejs/node#65845 Ref: https://chromium-review.googlesource.com/c/v8/v8/+/7708297 * chore: remove obsolete TLS external-memory accounting patch Upstream moved the SecureContext external-memory Increase() into Init() and guards the Decrease() on ctx_, so the leak this patch fixed is gone. The patch's removal of that guard now double-decrements when v24.22.0's TLSSocket closes a single-use context before the wrapper is destroyed, tripping V8's ExternalMemoryAccounter DCHECK in every TLS test. Already dropped on main in #53524. * 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: nodejs/node#64453 --------- Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com> Co-authored-by: Sam Attard <sattard@anthropic.com>
MarshallOfSound
added a commit
to electron/electron
that referenced
this pull request
Oct 15, 2026
* 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: nodejs/node#62237 Ref: nodejs/node#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: nodejs/node#65966 Ref: nodejs/node#66108 Ref: nodejs/node#65484 * fix(patch): skip RSA-PSS keygen deprecation tests with BoringSSL The skip is now upstream. Ref: nodejs/node#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: nodejs/node#65778 * fix(patch): gate jspi flag on V8_ENABLE_WEBASSEMBLY Ref: nodejs/node#66082 * chore: remove upstreamed patches - nodejs/node#63985 - nodejs/node#65630 - nodejs/node#64453 - nodejs/node#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: nodejs/node#65484 * fix(patch): read the peer certificate chain without consuming it sk_X509_num() returns size_t in BoringSSL. Ref: nodejs/node#65602 * fix(patch): fix shared buffer growability validation Ref: nodejs/node#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: nodejs/node#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: nodejs/node#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: nodejs/node#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: nodejs/node#64453 --------- Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com> Co-authored-by: Sam Attard <sattard@anthropic.com>
MarshallOfSound
added a commit
to electron/electron
that referenced
this pull request
Oct 15, 2026
* 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: nodejs/node#62237 Ref: nodejs/node#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: nodejs/node#65966 Ref: nodejs/node#66108 Ref: nodejs/node#65484 * fix(patch): skip RSA-PSS keygen deprecation tests with BoringSSL The skip is now upstream. Ref: nodejs/node#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: nodejs/node#65778 * fix(patch): gate jspi flag on V8_ENABLE_WEBASSEMBLY Ref: nodejs/node#66082 * chore: remove upstreamed patches - nodejs/node#63985 - nodejs/node#65630 - nodejs/node#64453 - nodejs/node#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: nodejs/node#65484 * fix(patch): read the peer certificate chain without consuming it sk_X509_num() returns size_t in BoringSSL. Ref: nodejs/node#65602 * 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: nodejs/node#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: nodejs/node#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: nodejs/node#65845 Ref: https://chromium-review.googlesource.com/c/v8/v8/+/7708297 * chore: remove obsolete TLS external-memory accounting patch Upstream moved the SecureContext external-memory Increase() into Init() and guards the Decrease() on ctx_, so the leak this patch fixed is gone. The patch's removal of that guard now double-decrements when v24.22.0's TLSSocket closes a single-use context before the wrapper is destroyed, tripping V8's ExternalMemoryAccounter DCHECK in every TLS test. Already dropped on main in #53524. * 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: nodejs/node#64453 --------- Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com> Co-authored-by: Sam Attard <sattard@anthropic.com>
MarshallOfSound
added a commit
to electron/electron
that referenced
this pull request
Oct 15, 2026
* 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: nodejs/node#62237 Ref: nodejs/node#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: nodejs/node#65966 Ref: nodejs/node#66108 Ref: nodejs/node#65484 * fix(patch): skip RSA-PSS keygen deprecation tests with BoringSSL The skip is now upstream. Ref: nodejs/node#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: nodejs/node#65778 * fix(patch): gate jspi flag on V8_ENABLE_WEBASSEMBLY Ref: nodejs/node#66082 * chore: remove upstreamed patches - nodejs/node#63985 - nodejs/node#65630 - nodejs/node#64453 - nodejs/node#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: nodejs/node#65484 * fix(patch): read the peer certificate chain without consuming it sk_X509_num() returns size_t in BoringSSL. Ref: nodejs/node#65602 * fix(patch): fix shared buffer growability validation Ref: nodejs/node#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: nodejs/node#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: nodejs/node#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: nodejs/node#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: nodejs/node#64453 --------- Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com> Co-authored-by: Sam Attard <sattard@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Without a startup snapshot (
--no-node-snapshot, a--without-node-snapshotbuild, or an embedder Environment bootstrapped from scratch), starting a Worker and setting up the main instance both make a member call through a nullSnapshotData*; it only works because the callee does not touchthis, and UBSan reports it for every such Worker. The call existed becauseIsolateData::CreateIsolateData()took anEmbedderSnapshotData*that its internal callers had to wrap their possibly-nullSnapshotData*into.The internal function now takes the
SnapshotData*itself and only the publicCreateIsolateData()unwraps the embedder type;AsEmbedderWrapper()had no other users and is removed.Tests:
EnvironmentTest.WorkerInEnvironmentWithoutSnapshot(UBSan before);node --no-node-snapshotwith a Worker and the worker/snapshot suites pass.Refs: #47731
Disclosure: the code, test and this description were written by Claude Code, directed and reviewed by @codebytere.