Compare commits

...

74 Commits

Author SHA1 Message Date
trop[bot]
87badb84f8 test: remove split dependency (#49555)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2026-01-28 15:38:05 +01:00
trop[bot]
2f3a1ca461 fix: chrome://accessibility drift (#49559)
https://chromium-review.googlesource.com/c/chromium/src/+/6870052

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2026-01-28 15:37:39 +01:00
trop[bot]
81ae20905c ci: reapply patches if PR base branch updates them (#49533)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2026-01-27 17:40:35 -05:00
trop[bot]
da4a808af7 docs: correct type for process.noDeprecation (#49545)
* docs: correct type for process.noDeprecation

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

* docs: mark `noDeprecation` as optional instead

Co-authored-by: René <contact.9a5d6388@renegade334.me.uk>

Co-authored-by: David Sanders <dsanders11@ucsbalum.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2026-01-27 11:37:32 +01:00
trop[bot]
71579e4749 fix: second argument to shell.writeShortcutLink is optional (#49502)
fix: second argument to shell.writeShortcutLink is optional

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2026-01-23 14:31:09 -05:00
trop[bot]
06fdee87b3 fix: return early from platform_util::Beep() on Linux if there is no default GDK display (#49484)
fix: return early from beep on linux if there is no default gdk display

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Noah Gregory <noahmgregory@gmail.com>
2026-01-23 11:07:47 +01:00
trop[bot]
6ce52ad792 fix: potential devtools crash on empty (#49489)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2026-01-22 11:59:57 -05:00
electron-roller[bot]
7784d25821 chore: bump node to v22.22.0 (39-x-y) (#49389)
* chore: bump node in DEPS to v22.22.0

* chore: update patches

* chore: fixup sandboxed pointers patch

(cherry picked from commit f52fbdbe51)

* chore: fixup v8 sandbox pointers node patch

* tls: route callback exceptions through error handlers

https://github.com/nodejs-private/node-private/pull/782
(cherry picked from commit 87bc8ebd34)

* chore:remove zero-fill sandbox patch component

xref https://github.com/electron/electron/pull/49452

* fixup! chore:remove zero-fill sandbox patch component

* test: correct conditional secure heap flags test

xref:  https://github.com/nodejs/node/pull/60385

---------

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <kleinschmidtorama@gmail.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
Co-authored-by: deepak1556 <hop2deep@gmail.com>
2026-01-22 09:53:44 -05:00
trop[bot]
126a32c5d2 docs: document that shell.trashItem requires backslashes (#49479)
docs: Update shell.md: Document that shell.trashItem requires backslashes

In Windows many functions relating to files (e.g. shell.openItem, the Node fs functions, as well as native Win32 APIs) will accept either type of slash / or \ as a folder separator.

shell.trashItem does not work with / as folder separator in Windows. This documentation change explains that.

See also:
https://github.com/electron/electron/issues/28831

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: sam marshall <s.marshall@open.ac.uk>
2026-01-21 14:52:13 -05:00
trop[bot]
811b1d6326 revert: use deprecated setAllowedFileTypes in macOS dialogs (#49472)
* revert: use deprectated setAllowedFileTypes in macOS dialogs

Closes https://github.com/electron/electron/issues/48191

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

* chore: remove stray import

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2026-01-21 17:57:35 +01:00
trop[bot]
50fc493ae6 ci: detect patch needs update error with problem matcher (#49412)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2026-01-21 12:32:04 +01:00
trop[bot]
9453e8bfe1 build: roll build-image to a82b87d (#49450)
build: roll build-image to a82b87d

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2026-01-19 19:01:42 +01:00
trop[bot]
a4eb213a04 fix: restore AXDocument accessibility attribute for representedFilename on macOS (#49418)
Starting from Chromium 134.0.6989.0 (Electron 35.0.0-beta.5), the
NativeWidgetMacNSWindow class overrides accessibilityDocument to return
the web content URL from the accessibility tree, but doesn't fall back
to NSWindow's default behavior when that URL is empty.

This broke Electron's setRepresentedFilename() API - the file path was
still set on the NSWindow, but no longer exposed via the AXDocument
accessibility attribute that screen readers use.

This fix adds an accessibilityDocument override in ElectronNSWindow that
checks representedFilename first, falling back to Chromium's behavior
for web content URLs.

Fixes: https://github.com/electron/electron/issues/XXXXX

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Daniel Gräfe <Daniel.Alm@ForumD.net>
2026-01-19 15:02:51 +01:00
trop[bot]
81c08e80f6 docs: fix webContents.hostWebContents types (#49445)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Niklas Wenzel <dev@nikwen.de>
2026-01-19 10:58:28 +01:00
trop[bot]
5f630c7de7 fix: try clearing InspectableWebContents delegate earlier (#49423)
fix: try clearing InspectableWebContents delegate earlier

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2026-01-18 09:52:20 +01:00
trop[bot]
2dc82ea1f3 fix: make toplevel icon Wayland protocol work (#49415)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Alex Schwartz <alexschwartz01@gmail.com>
2026-01-16 11:04:40 -05:00
Shelley Vohr
f57d6f92b6 feat: support WebSocket authentication handling (#49065)
* feat: support WebSocket authentication handling

* chore: make linter happy

---------

Co-authored-by: Charles Kerr <charles@charleskerr.com>
2026-01-13 08:52:14 -05:00
Robo
744142fe54 fix: reduce stack memory consumption in BytecodeGenerator (#49360)
Reduce stack memory consumption in BytecodeGenerator

Backports

1) https://chromium-review.googlesource.com/c/v8/v8/+/7180480
2) https://chromium-review.googlesource.com/c/v8/v8/+/7160576
3) https://chromium-review.googlesource.com/c/v8/v8/+/7062734

2 and 3 are needed to cleanly land 1. However, most of the code
changes are noop since v8_flags.proto_assign_seq_opt is experimental
and disabled by default for feature. The reason why stack memory
consumption is improved for all scenarios can be found in
https://github.com/microsoft/vscode/issues/283403#issuecomment-3737968271
2026-01-13 19:04:51 +09:00
trop[bot]
b200b8d6c0 build: roll build-tools SHA to 4430e4a (#49367)
build: roll build-tools SHA to 4430e4a

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2026-01-12 15:44:02 -05:00
electron-roller[bot]
cdaf0e96b6 chore: bump chromium to 142.0.7444.265 (39-x-y) (#49322)
chore: bump chromium in DEPS to 142.0.7444.265

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2026-01-12 11:29:53 +01:00
trop[bot]
981df181c1 chore: improvements to script/run-clang-tidy.ts (#49341)
* chore: disable color output for clang-tidy in CI

Co-authored-by: David Sanders <dsanders11@ucsbalum.com>

* chore: small QoL improvements to run-clang-tidy.ts

Co-authored-by: David Sanders <dsanders11@ucsbalum.com>

* chore: add --fix option to script/run-clang-tidy.ts

Co-authored-by: David Sanders <dsanders11@ucsbalum.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2026-01-09 14:43:00 -06:00
John Kleinschmidt
218300e57f build: use @electron-ci/dev-root for package.json default (#49319)
* build: use @electron-ci/dev-root for package.json default (#49154)

(cherry picked from commit bab6bd3dae)

* fxiup
2026-01-07 09:48:08 -05:00
Charles Kerr
6ccee512e4 chore: remove patches/v8/cherry-pick-e0052e7af9c9 (#49309)
chore: remove patches/v8/cherry-pick-e0052e7af9c9.patch

included in latest roll of upstream w/v8 14.2.231.22
2026-01-06 12:43:37 -06:00
trop[bot]
b6e4f514d8 docs: update roundedCorners documentation (#49310)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Niklas Wenzel <dev@nikwen.de>
2026-01-06 11:00:23 -05:00
trop[bot]
ade4c00984 fix: webRequest.onBeforeSendHeaders not being able to modify reserved headers (#49242)
* fix: `webRequest.onBeforeSendHeaders` not being able to modify reserved headers

Co-authored-by: Samuel Attard <sattard@anthropic.com>

* chore: add unit test for reserved header

Co-authored-by: Samuel Attard <sattard@anthropic.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Samuel Attard <sattard@anthropic.com>
2026-01-05 16:30:50 -05:00
trop[bot]
d8687cfc9d build: fixup release notes generation (#49304)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <kleinschmidtorama@gmail.com>
2026-01-05 15:56:30 -05:00
electron-roller[bot]
2ab4489447 chore: bump chromium to 142.0.7444.243 (39-x-y) (#49228)
chore: bump chromium in DEPS to 142.0.7444.243

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2026-01-02 13:49:22 +09:00
Keeley Hammond
ab9b156113 chore: cherry-pick e0052e7af9c9 from v8 (#49287)
* chore: cherry-pick e0052e7af9c9 from v8

* chore: update patches
2025-12-31 17:02:33 +13:00
trop[bot]
35a531953b build: drop dugite as a dependency (#49205)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <kleinschmidtorama@gmail.com>
2025-12-15 16:39:41 -05:00
trop[bot]
4d18062d0f ci: disallow non-maintainer changes to Yarn files (#49192)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2025-12-11 17:14:14 -05:00
electron-roller[bot]
832ffb2330 chore: bump chromium to 142.0.7444.235 (39-x-y) (#49190)
chore: bump chromium in DEPS to 142.0.7444.235

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2025-12-11 15:25:12 -05:00
trop[bot]
03121eeaef build: upgrade yarn to 4.12.0 (#49179)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <kleinschmidtorama@gmail.com>
2025-12-10 19:20:43 -08:00
trop[bot]
8282c07a0f build: upgrade github-app-auth to 3.2.0 (#49177)
build: upgrade github-app-auth to 3.2.0 (#49152)

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2025-12-10 14:20:43 -05:00
Niklas Wenzel
f2d1cb21b0 fix: visual artifacts while resizing on Windows (#49138)
Manual backports of:

- crrev.com/c/7129658
- crrev.com/c/7210913
- crrev.com/c/7115438
2025-12-04 16:42:24 -08:00
electron-roller[bot]
ef9b4162af chore: bump chromium to 142.0.7444.226 (39-x-y) (#49137)
* chore: bump chromium in DEPS to 142.0.7444.226

* chore: update patches

---------

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: Niklas Wenzel <dev@nikwen.de>
2025-12-03 15:50:16 -05:00
trop[bot]
6e97bca80d fix: run toast creation on background thread (#49130)
* fix: run toast creation on background thread

notes: attempts to fix app freeze when triggering notifications and the COM server in WindowsShellExperienceHost hangs

Co-authored-by: Jan Hannemann <jan.hannemann@outlook.com>

* fix: comments

Co-authored-by: Jan Hannemann <jan.hannemann@outlook.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Jan Hannemann <jan.hannemann@outlook.com>
2025-12-02 20:41:24 -08:00
trop[bot]
c511fc5c3f chore: reclaim macOS disk space (#49121)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2025-12-01 15:30:07 -08:00
trop[bot]
22dfbb0822 ci: use clang problem matcher with nan spec runner (#49099)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2025-12-01 09:45:35 -05:00
trop[bot]
85913a38da fix: ensure menu-did-close is emitted for application menus (#49093)
fix: ensure menu-did-close is emitted for application menus

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2025-11-26 11:47:13 -06:00
trop[bot]
a327629ca2 ci: don't build yarn modules for linux arm (#49088)
This should fix the oom errors

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2025-11-26 10:32:30 -05:00
Niklas Wenzel
7deed2b980 fix: reduce visual artifacts while resizing on Windows (#49076) 2025-11-26 10:23:52 +01:00
trop[bot]
65fc06a9f7 chore: backport 744f40f from devtools-frontend (#49044)
* chore: backport 744f40f from devtools-frontend

Co-authored-by: deepak1556 <hop2deep@gmail.com>

* chore: update patch

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: deepak1556 <hop2deep@gmail.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2025-11-25 12:07:04 -06:00
John Kleinschmidt
245e70aedd test: fixup test failures on linux (#49059)
* test: fixup spec runner to properly fail on linux when tests fail

* test: fixup dbus tests

* test: disable context menu spellcheck tests on linux

https://github.com/electron/electron/pull/48657 broke those tests
(cherry picked from commit cc3c999148)

* test:rebuild native modules

(cherry picked from commit bb8e2a924b)

* fix: wait for devtools blur event in focus test to avoid race condition

(cherry picked from commit 6fd2575cbc)

* fix: wait for devtools blur event in focus test to avoid race condition

(cherry picked from commit ea830139af)

---------

Co-authored-by: Alice Zhao <alicelovescake@anthropic.com>
2025-11-24 17:02:14 -05:00
trop[bot]
2a8164f499 fix: exception when reading system certificates via nodejs (#49042)
* fix: exception when reading system certificates via nodejs

Co-authored-by: deepak1556 <hop2deep@gmail.com>

* fixup! fix: exception when reading system certificates via nodejs

chore: fix trop patch shear

* chore: update patches

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: deepak1556 <hop2deep@gmail.com>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
2025-11-24 14:47:53 -06:00
trop[bot]
2f7024dbcc docs: update linux build instructions (#49060)
* docs: update linux build instructions

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>

* Update docs/development/build-instructions-linux.md

Co-authored-by: Erick Zhao <ezhao@slack-corp.com>

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>

* Update docs/development/build-instructions-linux.md

Co-authored-by: Erick Zhao <ezhao@slack-corp.com>

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2025-11-24 13:50:33 -06:00
trop[bot]
d53d3bb99e docs: explain how to create transparent window using BaseWindow (#49051)
docs: clarify how to create transparent BaseWindow

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: teoyuqi <83915879+teoyuqi@users.noreply.github.com>
2025-11-24 09:41:48 +01:00
trop[bot]
c2c1d40294 fix: only call popup closecallback for top-level menu (#49045)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2025-11-23 21:35:47 +01:00
electron-roller[bot]
0e9decd459 chore: bump chromium to 142.0.7444.177 (39-x-y) (#49037)
chore: bump chromium in DEPS to 142.0.7444.177

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2025-11-21 10:21:05 -05:00
John Kleinschmidt
b2e73d28e2 build: update to yarn v4 (#48994)
* build: update to yarn v4

(cherry picked from commit 6adec744f3)

* chore: fixup types after yarn v4 migration

* chore: update nan yarn.lock patch

* build: automatically install git for dugite
2025-11-19 17:32:30 -05:00
trop[bot]
aeb5af803f fix: abort more descriptively for beforeunload (#49011)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2025-11-19 17:00:51 -05:00
trop[bot]
53819a8a2a fix: revert the parent window remained interactive after the modal window was opened (#49019)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: bill.shen <15865969+cucbin@users.noreply.github.com>
2025-11-19 16:56:33 -05:00
electron-roller[bot]
14565211f7 chore: bump chromium to 142.0.7444.175 (39-x-y) (#49003)
* chore: bump chromium in DEPS to 142.0.7444.175

* chore: update patches

---------

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2025-11-18 11:25:22 -08:00
trop[bot]
00646c9db6 fix: handle empty event scenario in ipc callbacks (#48992)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: deepak1556 <hop2deep@gmail.com>
2025-11-18 09:17:20 -05:00
trop[bot]
d9c33a951a build: add header for SetStackDumpFirstChanceCallback in renderer client (#48980)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Keeley Hammond <vertedinde@electronjs.org>
2025-11-15 10:04:28 -08:00
trop[bot]
8b02e33187 build: limit workflow gh token permissions (#48969)
* build: limit workflow gh token permissions

Co-authored-by: Samuel Attard <samuel.r.attard@gmail.com>

* feedback

Co-authored-by: Samuel Attard <sattard@anthropic.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Samuel Attard <samuel.r.attard@gmail.com>
Co-authored-by: Samuel Attard <sattard@anthropic.com>
2025-11-15 11:32:21 +01:00
trop[bot]
eecca2cb19 fix: revert enabling WASM trap handlers in all Node.js processes (#48975)
Revert "fix: enable wasm trap handlers in all Node.js processes (#48788)"

This reverts commit ca0b46b413.

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Keeley Hammond <khammond@slack-corp.com>
2025-11-14 18:56:50 -08:00
trop[bot]
08b5ef556c test: add view.getBounds|setBounds tests (#48961)
test: add view.getBounds|setBounds tests

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2025-11-14 12:12:22 -05:00
Shelley Vohr
ab85f2c2f7 chore: cherry-pick 4cf9311 from v8 (#48951) 2025-11-13 14:50:46 -08:00
Fedor Indutny
1936243ce1 fix: crash on windows when UTF-8 is in path (#48944)
In 6399527761 we changed the path strings
that `node_modules.cc` operates on from single-byte to wide strings.
Unfortunately this means that `generic_path()` that the
"fix: ensure TraverseParent bails on resource path exit" patch was
calling was no longer a safe method to call on Windows if the underlying
string has unicode characters in it.

Here we fix it by using `ConvertGenericPathToUTF8` from the Node.js
internal utilities.
2025-11-13 13:56:30 -08:00
trop[bot]
e7e052f5b1 docs: fix docs for app.isHardwareAccelerationEnabled() (#48945)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Niklas Wenzel <dev@nikwen.de>
2025-11-13 14:59:43 -05:00
trop[bot]
349a9b6398 docs: explain how to load SF Symbols with nativeImage (#48939)
* docs: explain how to load SF Symbols with `nativeImage`

Co-authored-by: Niklas Wenzel <dev@nikwen.de>

* fix: use single quotes

Co-authored-by: Niklas Wenzel <dev@nikwen.de>

* fix: use single quotes

Co-authored-by: Niklas Wenzel <dev@nikwen.de>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Niklas Wenzel <dev@nikwen.de>
2025-11-13 11:19:21 -05:00
trop[bot]
b5f19ce974 feat: add bypassCustomProtocolHandlers option to net.request (#48882)
* feat: add bypassCustomProtocolHandlers option to net.request

Co-authored-by: Kai <udbmnm@163.com>

* style: fix lint errors in api-protocol-spec

Co-authored-by: Kai <udbmnm@163.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Kai <udbmnm@163.com>
2025-11-13 10:35:06 -05:00
trop[bot]
bb930b887b feat: add app.isHardwareAccelerationEnabled() (#48680)
* feat: add app.isHardwareAccelerationEnabled()

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

* chore: address review feedback

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2025-11-13 10:32:14 -05:00
trop[bot]
e962bc3743 docs: clarify meaning of string value for menu item icon (#48938)
* docs: clarify meaning of string value for menu item icon

Co-authored-by: Niklas Wenzel <dev@nikwen.de>

* fix: format

Co-authored-by: Niklas Wenzel <dev@nikwen.de>

* fix: wording

Co-authored-by: Niklas Wenzel <dev@nikwen.de>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Niklas Wenzel <dev@nikwen.de>
2025-11-13 10:28:01 -05:00
trop[bot]
895cf006e7 fix: Windows: Calling window.setFocusable(true) will no longer cause a window to lose focus (#48928)
Make setFocusable only deactivate a window if focusable is false. Do not deactivate a window when setting focusable to true.

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: vulture <isu@vulture.fm>
2025-11-13 09:52:58 +01:00
trop[bot]
bc1ca72dc7 docs: fix v40 stable release date (#48920)
* docs(timelines): Correct v40.0.0 stable release date

On the Electron Timelines tutorial page (/docs/latest/tutorial/electron-timelines), there is a clear typo in the release schedule for v40.0.0.

The table currently lists the dates as:
* Alpha: 2025-Oct-30
* Beta: 2025-Dec-03
* **Stable: 2025-Oct-28**

This is logically incorrect, as the 'Stable' release date (Oct 28) is listed *before* both the 'Alpha' (Oct 30) and 'Beta' (Dec 03) dates for the same version.

This appears to be a copy-paste error, as the 'Stable' date (2025-Oct-28) is identical to the 'Stable' date for the v39.0.0 release in the preceding row.

This commit updates the 'Stable' date for v40.0.0 to its correct value, ensuring the timeline is accurate and logical.

Co-authored-by: 정승규 <43807509+jsk41755@users.noreply.github.com>

* docs: Update v40.0.0 stable date to 2026-Jan-13 based on Chromium schedule

Co-authored-by: 정승규 <43807509+jsk41755@users.noreply.github.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: 정승규 <43807509+jsk41755@users.noreply.github.com>
2025-11-12 15:44:22 +01:00
electron-roller[bot]
a9a4c77353 chore: bump chromium to 142.0.7444.162 (39-x-y) (#48899)
* chore: bump chromium in DEPS to 142.0.7444.162

* chore: update patches

---------

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2025-11-12 11:24:14 +01:00
trop[bot]
0f613246d9 fix: restore window's canHide property on macOS (#48901)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: bill.shen <15865969+cucbin@users.noreply.github.com>
2025-11-12 09:42:37 +01:00
trop[bot]
a77b92adf2 ci: exclude top-level docs files from full CI (#48895)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2025-11-11 21:06:23 +01:00
trop[bot]
d62c324567 fix: enable wasm trap handlers in all Node.js processes (#48837)
* fix: enable wasm trap handlers in all Node.js processes

Co-authored-by: deepak1556 <hop2deep@gmail.com>

* fix: separate registrations to account for featurelist init

Co-authored-by: deepak1556 <hop2deep@gmail.com>

* build: add missing header for SetStackDumpFirstChanceCallback

* fix: pdf spec

delay load pdfjs-dist which compiles wasm on load, trap handlers
will be initialized once the user script starts but before app#ready.

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: deepak1556 <hop2deep@gmail.com>
2025-11-11 18:45:57 +09:00
trop[bot]
108a26a0f9 docs: remove electronegativity (#48887)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Erick Zhao <ezhao@slack-corp.com>
2025-11-11 09:59:08 +01:00
Shelley Vohr
331f8cca47 feat: enable resetting accent color (#48852) 2025-11-10 16:44:20 -05:00
trop[bot]
215128715a feat: Focus DevTools when breakpoint is triggered (#48702)
`bringToFront` DevTools message is sent when breakpoint is triggered
or inspect is called and Chromium upon this message activates DevTools
via `DevToolsUIBindings::Delegate::ActivateWindow`:
```
void DevToolsWindow::ActivateWindow() {
  if (life_stage_ != kLoadCompleted)
    return;
\#if BUILDFLAG(IS_ANDROID)
  NOTIMPLEMENTED();
\#else
  if (is_docked_ && GetInspectedBrowserWindow())
    main_web_contents_->Focus();
  else if (!is_docked_ && browser_ && !browser_->window()->IsActive())
    browser_->window()->Activate();
\#endif
}
```
which implements: `DevToolsUIBindings::Delegate::ActivateWindow`.

Electron also implements this interface in:
`electron::InspectableWebContents`. However it was only setting
a zoom level, therefore this commit extends it with activation
of the DevTools.

Only supported for DevTools manged by `electron::InspectableWebContents`.

Closes: #37388

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Michał Pichliński <michal.pichlinski@here.io>
2025-11-10 16:42:40 -05:00
trop[bot]
efcab52714 feat: add SF Symbol support to NativeImage::CreateFromNamedImage (#48773)
* feat: add SF Symbol support to NativeImage::CreateFromNamedImage

Co-authored-by: TheCommieAxolotl <87679354+TheCommieAxolotl@users.noreply.github.com>

* use obj-c name in NSImage constructor

Co-authored-by: TheCommieAxolotl <87679354+TheCommieAxolotl@users.noreply.github.com>

* add test for named symbol image

Co-authored-by: TheCommieAxolotl <87679354+TheCommieAxolotl@users.noreply.github.com>

* apply suggested simplification

Co-authored-by: TheCommieAxolotl <87679354+TheCommieAxolotl@users.noreply.github.com>

* fix: support NX cocoa prefix

Co-authored-by: TheCommieAxolotl <87679354+TheCommieAxolotl@users.noreply.github.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: TheCommieAxolotl <87679354+TheCommieAxolotl@users.noreply.github.com>
2025-11-10 21:18:45 +01:00
171 changed files with 21980 additions and 11833 deletions

View File

@@ -2,7 +2,7 @@ version: '3'
services:
buildtools:
image: ghcr.io/electron/devcontainer:933c7d6ff6802706875270bec2e3c891cf8add3f
image: ghcr.io/electron/devcontainer:a82b87d7a4f5ff0cab61405f8151ac4cf4942aeb
volumes:
- ..:/workspaces/gclient/src/electron:cached

View File

@@ -184,7 +184,7 @@ runs:
shell: bash
run: |
cd src/electron
node script/yarn create-typescript-definitions
node script/yarn.js create-typescript-definitions
- name: Publish Electron Dist ${{ inputs.step-suffix }}
if: ${{ inputs.is-release == 'true' }}
shell: bash

View File

@@ -143,16 +143,17 @@ runs:
echo "No changes to patches detected"
fi
fi
- name: Remove patch conflict problem matcher
- name: Remove patch conflict problem matchers
shell: bash
run: |
echo "::remove-matcher owner=merge-conflict::"
echo "::remove-matcher owner=patch-conflict::"
echo "::remove-matcher owner=patch-needs-update::"
- name: Upload patches stats
if: ${{ inputs.target-platform == 'linux' && github.ref == 'refs/heads/main' }}
shell: bash
run: |
npx node src/electron/script/patches-stats.mjs --upload-stats || true
node src/electron/script/patches-stats.mjs --upload-stats || true
# delete all .git directories under src/ except for
# third_party/angle/ and third_party/dawn/ because of build time generation of files
# gen/angle/commit.h depends on third_party/angle/.git/HEAD

View File

@@ -64,15 +64,24 @@ runs:
sudo rm -rf /Applications/Xcode_16.1.app
sudo rm -rf /Applications/Xcode_16.2.app
sudo rm -rf /Applications/Xcode_16.3.app
sudo rm -rf /Applications/Xcode_26*
sudo rm -rf /Applications/Google Chrome.app
sudo rm -rf /Applications/Google Chrome for Testing.app
sudo rm -rf /Applications/Firefox.app
sudo rm -rf /Applications/Firefox.app
sudo rm -rf /Applications/Microsoft Edge.app
sudo rm -rf ~/project/src/third_party/catapult/tracing/test_data
sudo rm -rf ~/project/src/third_party/angle/third_party/VK-GL-CTS
sudo rm -rf /Users/runner/Library/Android
sudo rm -rf $JAVA_HOME_11_arm64
sudo rm -rf $JAVA_HOME_17_arm64
sudo rm -rf $JAVA_HOME_21_arm64
sudo rm -rf $JAVA_HOME_25_arm64
sudo rm -rf /Users/runner/.dotnet/
sudo rm -rf /Users/runner/.rustup
# remove homebrew packages we don't need
brew uninstall -f --zap aws-sam-cli session-manager-plugin gcc gcc@13 gcc@14 llvm@18 gradle maven ant azure-cli
brew autoremove
# lipo off some huge binaries arm64 versions to save space
strip_universal_deep $(xcode-select -p)/../SharedFrameworks

View File

@@ -13,12 +13,16 @@ runs:
- name: Generating Types for SHA in ${{ inputs.sha-file }}
shell: bash
run: |
git checkout $(cat ${{ inputs.sha-file }})
rm -rf node_modules
yarn install --frozen-lockfile --ignore-scripts
export ELECTRON_DIR=$(pwd)
if [ "${{ inputs.sha-file }}" == ".dig-old" ]; then
cd /tmp
git clone https://github.com/electron/electron.git
cd electron
fi
git checkout $(cat $ELECTRON_DIR/${{ inputs.sha-file }})
node script/yarn.js install --immutable
echo "#!/usr/bin/env node\nglobal.x=1" > node_modules/typescript/bin/tsc
node node_modules/.bin/electron-docs-parser --dir=./ --outDir=./ --moduleVersion=0.0.0-development
node node_modules/.bin/electron-typescript-definitions --api=electron-api.json --outDir=artifacts
mv artifacts/electron.d.ts artifacts/${{ inputs.filename }}
git checkout .
mv artifacts/electron.d.ts $ELECTRON_DIR/artifacts/${{ inputs.filename }}
working-directory: ./electron

View File

@@ -15,7 +15,7 @@ runs:
git config --global core.preloadindex true
git config --global core.longpaths true
fi
export BUILD_TOOLS_SHA=a5d9f9052dcc36ee88bef5c8b13acbefd87b7d8d
export BUILD_TOOLS_SHA=4430e4a505e0f4fa2a41b707a10a36f780bbdd26
npm i -g @electron/build-tools
# Update depot_tools to ensure python
e d update_depot_tools

View File

@@ -6,7 +6,7 @@ runs:
- name: Get yarn cache directory path
shell: bash
id: yarn-cache-dir-path
run: echo "dir=$(node src/electron/script/yarn cache dir)" >> $GITHUB_OUTPUT
run: echo "dir=$(node src/electron/script/yarn.js config get cacheFolder)" >> $GITHUB_OUTPUT
- uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
id: yarn-cache
with:
@@ -18,4 +18,14 @@ runs:
shell: bash
run: |
cd src/electron
node script/yarn install --frozen-lockfile --prefer-offline
if [ "$TARGET_ARCH" = "x86" ]; then
export npm_config_arch="ia32"
fi
# if running on linux arm skip yarn Builds
ARCH=$(uname -m)
if [ "$ARCH" = "armv7l" ]; then
echo "Skipping yarn build on linux arm"
node script/yarn.js install --immutable --mode=skip-build
else
node script/yarn.js install --immutable
fi

View File

@@ -19,6 +19,16 @@
"line": 3
}
]
},
{
"owner": "patch-needs-update",
"pattern": [
{
"regexp": "^((patches\/.*): needs update)$",
"message": 1,
"file": 2
}
]
}
]
}

View File

@@ -3,10 +3,14 @@ name: Archaeologist
on:
pull_request:
permissions: {}
jobs:
archaeologist-dig:
name: Archaeologist Dig
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout Electron
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.0.2

View File

@@ -6,11 +6,15 @@ on:
schedule:
- cron: "0 0 * * *"
permissions: {}
jobs:
build-git-cache-linux:
runs-on: electron-arc-centralus-linux-amd64-32core
permissions:
contents: read
container:
image: ghcr.io/electron/build:bc2f48b2415a670de18d13605b1cf0eb5fdbaae1
image: ghcr.io/electron/build:a82b87d7a4f5ff0cab61405f8151ac4cf4942aeb
options: --user root
volumes:
- /mnt/cross-instance-cache:/mnt/cross-instance-cache
@@ -30,8 +34,10 @@ jobs:
build-git-cache-windows:
runs-on: electron-arc-centralus-linux-amd64-32core
permissions:
contents: read
container:
image: ghcr.io/electron/build:bc2f48b2415a670de18d13605b1cf0eb5fdbaae1
image: ghcr.io/electron/build:a82b87d7a4f5ff0cab61405f8151ac4cf4942aeb
options: --user root --device /dev/fuse --cap-add SYS_ADMIN
volumes:
- /mnt/win-cache:/mnt/win-cache
@@ -52,10 +58,12 @@ jobs:
build-git-cache-macos:
runs-on: electron-arc-centralus-linux-amd64-32core
permissions:
contents: read
# This job updates the same git cache as linux, so it needs to run after the linux one.
needs: build-git-cache-linux
container:
image: ghcr.io/electron/build:bc2f48b2415a670de18d13605b1cf0eb5fdbaae1
image: ghcr.io/electron/build:a82b87d7a4f5ff0cab61405f8151ac4cf4942aeb
options: --user root
volumes:
- /mnt/cross-instance-cache:/mnt/cross-instance-cache

View File

@@ -6,7 +6,7 @@ on:
build-image-sha:
type: string
description: 'SHA for electron/build image'
default: '933c7d6ff6802706875270bec2e3c891cf8add3f'
default: 'a82b87d7a4f5ff0cab61405f8151ac4cf4942aeb'
required: true
skip-macos:
type: boolean
@@ -43,16 +43,20 @@ defaults:
run:
shell: bash
permissions: {}
jobs:
setup:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
outputs:
docs: ${{ steps.filter.outputs.docs }}
src: ${{ steps.filter.outputs.src }}
build-image-sha: ${{ steps.set-output.outputs.build-image-sha }}
docs-only: ${{ steps.set-output.outputs.docs-only }}
has-patches: ${{ steps.filter.outputs.patches }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.0.2
with:
@@ -63,13 +67,20 @@ jobs:
filters: |
docs:
- 'docs/**'
- README.md
- SECURITY.md
- CONTRIBUTING.md
- CODE_OF_CONDUCT.md
src:
- '!docs/**'
patches:
- DEPS
- 'patches/**'
- name: Set Outputs for Build Image SHA & Docs Only
id: set-output
run: |
if [ -z "${{ inputs.build-image-sha }}" ]; then
echo "build-image-sha=933c7d6ff6802706875270bec2e3c891cf8add3f" >> "$GITHUB_OUTPUT"
echo "build-image-sha=a82b87d7a4f5ff0cab61405f8151ac4cf4942aeb" >> "$GITHUB_OUTPUT"
else
echo "build-image-sha=${{ inputs.build-image-sha }}" >> "$GITHUB_OUTPUT"
fi
@@ -80,6 +91,8 @@ jobs:
needs: setup
if: ${{ !inputs.skip-lint }}
uses: ./.github/workflows/pipeline-electron-lint.yml
permissions:
contents: read
with:
container: '{"image":"ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }}","options":"--user root"}'
secrets: inherit
@@ -89,15 +102,54 @@ jobs:
needs: [setup, checkout-linux]
if: ${{ needs.setup.outputs.docs-only == 'true' }}
uses: ./.github/workflows/pipeline-electron-docs-only.yml
permissions:
contents: read
with:
container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
secrets: inherit
# Apply Patches Job
apply-patches:
needs: setup
if: ${{ needs.setup.outputs.has-patches == 'true' }}
runs-on: electron-arc-centralus-linux-amd64-32core
permissions:
contents: read
container:
image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }}
options: --user root
volumes:
- /mnt/cross-instance-cache:/mnt/cross-instance-cache
- /var/run/sas:/var/run/sas
env:
CHROMIUM_GIT_COOKIE: ${{ secrets.CHROMIUM_GIT_COOKIE }}
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True'
steps:
- name: Checkout Electron
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8
with:
path: src/electron
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
- name: Rebase onto Base Branch
working-directory: src/electron
run: |
git config user.email "electron@github.com"
git config user.name "Electron Bot"
git fetch origin ${{ github.event.pull_request.base.ref }}
git rebase origin/${{ github.event.pull_request.base.ref }}
- name: Checkout & Sync & Save
uses: ./src/electron/.github/actions/checkout
with:
target-platform: linux
# Checkout Jobs
checkout-macos:
needs: setup
if: ${{ needs.setup.outputs.src == 'true' && !inputs.skip-macos}}
runs-on: electron-arc-centralus-linux-amd64-32core
permissions:
contents: read
container:
image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }}
options: --user root
@@ -126,6 +178,8 @@ jobs:
needs: setup
if: ${{ !inputs.skip-linux}}
runs-on: electron-arc-centralus-linux-amd64-32core
permissions:
contents: read
container:
image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }}
options: --user root
@@ -155,6 +209,8 @@ jobs:
needs: setup
if: ${{ needs.setup.outputs.src == 'true' && !inputs.skip-windows }}
runs-on: electron-arc-centralus-linux-amd64-32core
permissions:
contents: read
container:
image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }}
options: --user root --device /dev/fuse --cap-add SYS_ADMIN
@@ -185,6 +241,8 @@ jobs:
# GN Check Jobs
macos-gn-check:
uses: ./.github/workflows/pipeline-segment-electron-gn-check.yml
permissions:
contents: read
needs: checkout-macos
with:
target-platform: macos
@@ -195,6 +253,8 @@ jobs:
linux-gn-check:
uses: ./.github/workflows/pipeline-segment-electron-gn-check.yml
permissions:
contents: read
needs: checkout-linux
if: ${{ needs.setup.outputs.src == 'true' }}
with:
@@ -207,6 +267,8 @@ jobs:
windows-gn-check:
uses: ./.github/workflows/pipeline-segment-electron-gn-check.yml
permissions:
contents: read
needs: checkout-windows
with:
target-platform: win
@@ -310,7 +372,7 @@ jobs:
build-runs-on: electron-arc-centralus-linux-amd64-32core
test-runs-on: electron-arc-centralus-linux-arm64-4core
build-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
test-container: '{"image":"ghcr.io/electron/test:arm32v7-${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root --privileged --init","volumes":["/home/runner/externals:/mnt/runner-externals"]}'
test-container: '{"image":"ghcr.io/electron/test:arm32v7-${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root --privileged --init --memory=12g","volumes":["/home/runner/externals:/mnt/runner-externals"]}'
target-platform: linux
target-arch: arm
is-release: false
@@ -400,6 +462,8 @@ jobs:
gha-done:
name: GitHub Actions Completed
runs-on: ubuntu-latest
permissions:
contents: read
needs: [docs-only, macos-x64, macos-arm64, linux-x64, linux-x64-asan, linux-arm, linux-arm64, windows-x64, windows-x86, windows-arm64]
if: always() && !contains(needs.*.result, 'failure')
steps:

View File

@@ -1,16 +1,20 @@
name: Clean Source Cache
description: |
This workflow cleans up the source cache on the cross-instance cache volume
to free up space. It runs daily at midnight and clears files older than 15 days.
# Description:
# This workflow cleans up the source cache on the cross-instance cache volume
# to free up space. It runs daily at midnight and clears files older than 15 days.
on:
schedule:
- cron: "0 0 * * *"
permissions: {}
jobs:
clean-src-cache:
runs-on: electron-arc-centralus-linux-amd64-32core
permissions:
contents: read
container:
image: ghcr.io/electron/build:bc2f48b2415a670de18d13605b1cf0eb5fdbaae1
options: --user root

View File

@@ -4,14 +4,15 @@ on:
issues:
types: [labeled]
permissions: # added using https://github.com/step-security/secure-workflows
contents: read
permissions: {}
jobs:
issue-labeled-with-status:
name: status/{confirmed,reviewed} label added
if: github.event.label.name == 'status/confirmed' || github.event.label.name == 'status/reviewed'
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Generate GitHub App token
uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1
@@ -31,6 +32,8 @@ jobs:
name: blocked/* label added
if: startsWith(github.event.label.name, 'blocked/')
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Generate GitHub App token
uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1

View File

@@ -11,6 +11,7 @@ jobs:
add-to-issue-triage:
if: ${{ contains(github.event.issue.labels.*.name, 'bug :beetle:') }}
runs-on: ubuntu-latest
permissions: {}
steps:
- name: Generate GitHub App token
uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1
@@ -28,6 +29,7 @@ jobs:
set-labels:
if: ${{ contains(github.event.issue.labels.*.name, 'bug :beetle:') }}
runs-on: ubuntu-latest
permissions: {}
steps:
- name: Generate GitHub App token
uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1

View File

@@ -10,6 +10,7 @@ jobs:
issue-transferred:
name: Issue Transferred
runs-on: ubuntu-latest
permissions: {}
if: ${{ !github.event.changes.new_repository.private }}
steps:
- name: Generate GitHub App token

View File

@@ -4,14 +4,15 @@ on:
issues:
types: [unlabeled]
permissions:
contents: read
permissions: {}
jobs:
issue-unlabeled-blocked:
name: All blocked/* labels removed
if: startsWith(github.event.label.name, 'blocked/') && github.event.issue.state == 'open'
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Check for any blocked labels
id: check-for-blocked-labels

View File

@@ -6,7 +6,7 @@ on:
build-image-sha:
type: string
description: 'SHA for electron/build image'
default: '933c7d6ff6802706875270bec2e3c891cf8add3f'
default: 'a82b87d7a4f5ff0cab61405f8151ac4cf4942aeb'
upload-to-storage:
description: 'Uploads to Azure storage'
required: false
@@ -17,9 +17,13 @@ on:
type: boolean
default: false
permissions: {}
jobs:
checkout-linux:
runs-on: electron-arc-centralus-linux-amd64-32core
permissions:
contents: read
container:
image: ghcr.io/electron/build:${{ inputs.build-image-sha }}
options: --user root
@@ -40,6 +44,8 @@ jobs:
publish-x64:
uses: ./.github/workflows/pipeline-segment-electron-build.yml
permissions:
contents: read
needs: checkout-linux
with:
environment: production-release
@@ -55,6 +61,8 @@ jobs:
publish-arm:
uses: ./.github/workflows/pipeline-segment-electron-build.yml
permissions:
contents: read
needs: checkout-linux
with:
environment: production-release
@@ -70,6 +78,8 @@ jobs:
publish-arm64:
uses: ./.github/workflows/pipeline-segment-electron-build.yml
permissions:
contents: read
needs: checkout-linux
with:
environment: production-release

View File

@@ -6,7 +6,7 @@ on:
build-image-sha:
type: string
description: 'SHA for electron/build image'
default: '933c7d6ff6802706875270bec2e3c891cf8add3f'
default: 'a82b87d7a4f5ff0cab61405f8151ac4cf4942aeb'
required: true
upload-to-storage:
description: 'Uploads to Azure storage'
@@ -18,9 +18,13 @@ on:
type: boolean
default: false
permissions: {}
jobs:
checkout-macos:
runs-on: electron-arc-centralus-linux-amd64-32core
permissions:
contents: read
container:
image: ghcr.io/electron/build:${{ inputs.build-image-sha }}
options: --user root
@@ -44,6 +48,8 @@ jobs:
publish-x64-darwin:
uses: ./.github/workflows/pipeline-segment-electron-build.yml
permissions:
contents: read
needs: checkout-macos
with:
environment: production-release
@@ -59,6 +65,8 @@ jobs:
publish-x64-mas:
uses: ./.github/workflows/pipeline-segment-electron-build.yml
permissions:
contents: read
needs: checkout-macos
with:
environment: production-release
@@ -74,6 +82,8 @@ jobs:
publish-arm64-darwin:
uses: ./.github/workflows/pipeline-segment-electron-build.yml
permissions:
contents: read
needs: checkout-macos
with:
environment: production-release
@@ -89,6 +99,8 @@ jobs:
publish-arm64-mas:
uses: ./.github/workflows/pipeline-segment-electron-build.yml
permissions:
contents: read
needs: checkout-macos
with:
environment: production-release

View File

@@ -7,6 +7,8 @@ on:
- 'spec/yarn.lock'
- '.github/workflows/**'
- '.github/actions/**'
- '.yarn/**'
- '.yarnrc.yml'
permissions: {}

View File

@@ -55,6 +55,8 @@ on:
type: boolean
default: false
permissions: {}
concurrency:
group: electron-build-and-test-and-nan-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref_protected == true && github.run_id || github.ref }}
cancel-in-progress: ${{ github.ref_protected != true }}
@@ -62,6 +64,8 @@ concurrency:
jobs:
build:
uses: ./.github/workflows/pipeline-segment-electron-build.yml
permissions:
contents: read
with:
build-runs-on: ${{ inputs.build-runs-on }}
build-container: ${{ inputs.build-container }}
@@ -74,6 +78,10 @@ jobs:
secrets: inherit
test:
uses: ./.github/workflows/pipeline-segment-electron-test.yml
permissions:
contents: read
issues: read
pull-requests: read
needs: build
with:
target-arch: ${{ inputs.target-arch }}
@@ -83,6 +91,8 @@ jobs:
secrets: inherit
nn-test:
uses: ./.github/workflows/pipeline-segment-node-nan-test.yml
permissions:
contents: read
needs: build
with:
target-arch: ${{ inputs.target-arch }}

View File

@@ -64,14 +64,13 @@ concurrency:
group: electron-build-and-test-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref_protected == true && github.run_id || github.ref }}
cancel-in-progress: ${{ github.ref_protected != true }}
permissions:
contents: read
issues: read
pull-requests: read
permissions: {}
jobs:
build:
uses: ./.github/workflows/pipeline-segment-electron-build.yml
permissions:
contents: read
with:
build-runs-on: ${{ inputs.build-runs-on }}
build-container: ${{ inputs.build-container }}
@@ -86,6 +85,10 @@ jobs:
secrets: inherit
test:
uses: ./.github/workflows/pipeline-segment-electron-test.yml
permissions:
contents: read
issues: read
pull-requests: read
needs: build
with:
target-arch: ${{ inputs.target-arch }}

View File

@@ -8,6 +8,8 @@ on:
description: 'Container to run the docs-only ts compile in'
type: string
permissions: {}
concurrency:
group: electron-docs-only-${{ github.ref }}
cancel-in-progress: true
@@ -19,6 +21,8 @@ jobs:
docs-only:
name: Docs Only Compile
runs-on: electron-arc-centralus-linux-amd64-4core
permissions:
contents: read
timeout-minutes: 20
container: ${{ fromJSON(inputs.container) }}
steps:
@@ -50,12 +54,12 @@ jobs:
shell: bash
run: |
cd src/electron
node script/yarn create-typescript-definitions
node script/yarn tsc -p tsconfig.default_app.json --noEmit
node script/yarn.js create-typescript-definitions
node script/yarn.js tsc -p tsconfig.default_app.json --noEmit
for f in build/webpack/*.js
do
out="${f:29}"
if [ "$out" != "base.js" ]; then
node script/yarn webpack --config $f --output-filename=$out --output-path=./.tmp --env mode=development
node script/yarn.js webpack --config $f --output-filename=$out --output-path=./.tmp --env mode=development
fi
done

View File

@@ -8,6 +8,8 @@ on:
description: 'Container to run lint in'
type: string
permissions: {}
concurrency:
group: electron-lint-${{ github.ref_protected == true && github.run_id || github.ref }}
cancel-in-progress: ${{ github.ref_protected != true }}
@@ -19,6 +21,8 @@ jobs:
lint:
name: Lint
runs-on: electron-arc-centralus-linux-amd64-4core
permissions:
contents: read
timeout-minutes: 20
container: ${{ fromJSON(inputs.container) }}
steps:
@@ -74,11 +78,11 @@ jobs:
# but then we would lint its contents (at least gn format), and it doesn't pass it.
cd src/electron
node script/yarn install --frozen-lockfile
node script/yarn lint
node script/yarn.js install --immutable
node script/yarn.js lint
- name: Run Script Typechecker
shell: bash
run: |
cd src/electron
node script/yarn tsc -p tsconfig.script.json
node script/yarn.js tsc -p tsconfig.script.json

View File

@@ -59,6 +59,8 @@ on:
type: boolean
default: false
permissions: {}
concurrency:
group: electron-build-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ inputs.target-variant }}-${{ inputs.is-asan }}-${{ github.ref_protected == true && github.run_id || github.ref }}
cancel-in-progress: ${{ github.ref_protected != true }}
@@ -81,6 +83,8 @@ jobs:
run:
shell: bash
runs-on: ${{ inputs.build-runs-on }}
permissions:
contents: read
container: ${{ fromJSON(inputs.build-container) }}
environment: ${{ inputs.environment }}
env:

View File

@@ -26,6 +26,8 @@ on:
type: string
default: testing
permissions: {}
concurrency:
group: electron-gn-check-${{ inputs.target-platform }}-${{ github.ref }}
cancel-in-progress: true
@@ -41,6 +43,8 @@ jobs:
run:
shell: bash
runs-on: ${{ inputs.check-runs-on }}
permissions:
contents: read
container: ${{ fromJSON(inputs.check-container) }}
steps:
- name: Checkout Electron

View File

@@ -35,10 +35,7 @@ concurrency:
group: electron-test-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ inputs.is-asan }}-${{ github.ref_protected == true && github.run_id || github.ref }}
cancel-in-progress: ${{ github.ref_protected != true }}
permissions:
contents: read
issues: read
pull-requests: read
permissions: {}
env:
CHROMIUM_GIT_COOKIE: ${{ secrets.CHROMIUM_GIT_COOKIE }}
@@ -53,6 +50,10 @@ jobs:
run:
shell: bash
runs-on: ${{ inputs.test-runs-on }}
permissions:
contents: read
issues: read
pull-requests: read
container: ${{ fromJSON(inputs.test-container) }}
strategy:
fail-fast: false
@@ -195,10 +196,7 @@ jobs:
# sudo security authorizationdb write com.apple.trust-settings.admin allow
# cd src/electron
# ./script/codesign/generate-identity.sh
- name: Install Datadog CLI
run: |
cd src/electron
node script/yarn global add @datadog/datadog-ci
- name: Run Electron Tests
shell: bash
env:
@@ -224,7 +222,7 @@ jobs:
export ELECTRON_FORCE_TEST_SUITE_EXIT="true"
fi
fi
node script/yarn test --runners=main --enableRerun=3 --trace-uncaught --enable-logging --files $tests_files
node script/yarn.js test --runners=main --enableRerun=3 --trace-uncaught --enable-logging --files $tests_files
else
chown :builduser .. && chmod g+w ..
chown -R :builduser . && chmod -R g+w .
@@ -241,9 +239,14 @@ jobs:
export MOCHA_TIMEOUT=180000
echo "Piping output to ASAN_SYMBOLIZE ($ASAN_SYMBOLIZE)"
cd electron
runuser -u builduser -- xvfb-run script/actions/run-tests.sh script/yarn test --runners=main --trace-uncaught --enable-logging --files $tests_files | $ASAN_SYMBOLIZE
runuser -u builduser -- xvfb-run script/actions/run-tests.sh script/yarn.js test --runners=main --trace-uncaught --enable-logging --files $tests_files | $ASAN_SYMBOLIZE
else
runuser -u builduser -- xvfb-run script/actions/run-tests.sh script/yarn test --runners=main --trace-uncaught --enable-logging --files $tests_files
if [ "${{ inputs.target-arch }}" = "arm" ]; then
runuser -u builduser -- xvfb-run script/actions/run-tests.sh script/yarn.js test --skipYarnInstall --runners=main --enableRerun=3 --trace-uncaught --enable-logging --files $tests_files
else
runuser -u builduser -- xvfb-run script/actions/run-tests.sh script/yarn.js test --runners=main --enableRerun=3 --trace-uncaught --enable-logging --files $tests_files
fi
fi
fi
- name: Upload Test results to Datadog
@@ -255,9 +258,10 @@ jobs:
DD_TAGS: "os.architecture:${{ inputs.target-arch }},os.family:${{ inputs.target-platform }},os.platform:${{ inputs.target-platform }},asan:${{ inputs.is-asan }}"
run: |
if ! [ -z $DD_API_KEY ] && [ -f src/electron/junit/test-results-main.xml ]; then
export DATADOG_PATH=`node src/electron/script/yarn global bin`
$DATADOG_PATH/datadog-ci junit upload src/electron/junit/test-results-main.xml
fi
cd src/electron
export DATADOG_PATH=`node script/yarn.js bin datadog-ci`
$DATADOG_PATH junit upload junit/test-results-main.xml
fi
if: always() && !cancelled()
- name: Upload Test Artifacts
if: always() && !cancelled()

View File

@@ -26,6 +26,8 @@ on:
type: string
default: testing
permissions: {}
concurrency:
group: electron-node-nan-test-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref_protected == true && github.run_id || github.ref }}
cancel-in-progress: ${{ github.ref_protected != true }}
@@ -39,6 +41,8 @@ jobs:
node-tests:
name: Run Node.js Tests
runs-on: electron-arc-centralus-linux-amd64-8core
permissions:
contents: read
timeout-minutes: 30
env:
TARGET_ARCH: ${{ inputs.target-arch }}
@@ -93,6 +97,8 @@ jobs:
nan-tests:
name: Run Nan Tests
runs-on: electron-arc-centralus-linux-amd64-4core
permissions:
contents: read
timeout-minutes: 30
env:
TARGET_ARCH: ${{ inputs.target-arch }}
@@ -132,10 +138,16 @@ jobs:
unzip -:o dist.zip
- name: Setup Linux for Headless Testing
run: sh -e /etc/init.d/xvfb start
- name: Add Clang problem matcher
shell: bash
run: echo "::add-matcher::src/electron/.github/problem-matchers/clang.json"
- name: Run Nan Tests
run: |
cd src
node electron/script/nan-spec-runner.js
- name: Remove Clang problem matcher
shell: bash
run: echo "::remove-matcher owner=clang::"
- name: Wait for active SSH sessions
shell: bash
if: always() && !cancelled()

View File

@@ -11,6 +11,7 @@ jobs:
name: backport/requested label added
if: github.event.label.name == 'backport/requested 🗳'
runs-on: ubuntu-latest
permissions: {}
steps:
- name: Trigger Slack workflow
uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1
@@ -28,6 +29,7 @@ jobs:
name: deprecation-review/complete label added
if: github.event.label.name == 'deprecation-review/complete ✅'
runs-on: ubuntu-latest
permissions: {}
steps:
- name: Generate GitHub App token
uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1

View File

@@ -0,0 +1,69 @@
name: Rerun PR Apply Patches
on:
push:
branches:
- main
- '[1-9][0-9]-x-y'
paths:
- 'DEPS'
- 'patches/**'
permissions: {}
jobs:
rerun-apply-patches:
runs-on: ubuntu-latest
permissions:
contents: read
actions: write
pull-requests: read
steps:
- name: Find PRs and Rerun Apply Patches
env:
GH_REPO: ${{ github.repository }}
GH_TOKEN: ${{ github.token }}
run: |
BRANCH="${GITHUB_REF#refs/heads/}"
# Find all open PRs targeting this branch
PRS=$(gh pr list --base "$BRANCH" --state open --limit 250 --json number)
echo "$PRS" | jq -c '.[]' | while read -r pr; do
PR_NUMBER=$(echo "$pr" | jq -r '.number')
echo "Processing PR #${PR_NUMBER}"
# Find the apply-patches job check for this PR
CHECK=$(gh pr checks "$PR_NUMBER" --json link,name,state,workflow --jq '[.[] | select(.workflow == "Build" and .name == "apply-patches")] | first')
if [ -z "$CHECK" ] || [ "$CHECK" = "null" ]; then
echo " No apply-patches job found for PR #${PR_NUMBER}"
continue
fi
STATE=$(echo "$CHECK" | jq -r '.state')
if [ "$STATE" = "SKIPPED" ]; then
echo " apply-patches job was skipped for PR #${PR_NUMBER} (no patches)"
continue
fi
LINK=$(echo "$CHECK" | jq -r '.link')
# Extract the run ID from the link (format: .../runs/RUN_ID/job/JOB_ID)
RUN_ID=$(echo "$LINK" | grep -oE 'runs/[0-9]+' | cut -d'/' -f2)
if [ -z "$RUN_ID" ]; then
echo " Could not extract run ID from link: ${LINK}"
continue
fi
# Get the job database ID for the apply-patches job
JOB_ID=$(gh run view "$RUN_ID" --json jobs --jq '.jobs[] | select(.name == "apply-patches") | .databaseId')
if [ -z "$JOB_ID" ]; then
echo " Could not find apply-patches job ID for run: ${RUN_ID}"
continue
fi
gh run rerun "$RUN_ID" --job "$JOB_ID"
done

View File

@@ -7,8 +7,7 @@ on:
- edited
- synchronize
permissions:
contents: read
permissions: {}
jobs:
main:

View File

@@ -11,6 +11,7 @@ jobs:
check-stable-prep-items:
name: Check Stable Prep Items
runs-on: ubuntu-latest
permissions: {}
steps:
- name: Generate GitHub App token
uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1

View File

@@ -10,6 +10,7 @@ permissions: {}
jobs:
stale:
runs-on: ubuntu-latest
permissions: {}
steps:
- name: Generate GitHub App token
uses: electron/github-app-auth-action@384fd19694fe7b6dcc9a684746c6976ad78228ae # v1.1.1
@@ -31,6 +32,7 @@ jobs:
only-pr-labels: not-a-real-label
pending-repro:
runs-on: ubuntu-latest
permissions: {}
if: ${{ always() }}
needs: stale
steps:

View File

@@ -6,7 +6,7 @@ on:
build-image-sha:
type: string
description: 'SHA for electron/build image'
default: '933c7d6ff6802706875270bec2e3c891cf8add3f'
default: 'a82b87d7a4f5ff0cab61405f8151ac4cf4942aeb'
required: true
upload-to-storage:
description: 'Uploads to Azure storage'
@@ -18,9 +18,13 @@ on:
type: boolean
default: false
permissions: {}
jobs:
checkout-windows:
runs-on: electron-arc-centralus-linux-amd64-32core
permissions:
contents: read
container:
image: ghcr.io/electron/build:${{ inputs.build-image-sha }}
options: --user root --device /dev/fuse --cap-add SYS_ADMIN
@@ -48,6 +52,8 @@ jobs:
publish-x64-win:
uses: ./.github/workflows/pipeline-segment-electron-build.yml
permissions:
contents: read
needs: checkout-windows
with:
environment: production-release
@@ -62,6 +68,8 @@ jobs:
publish-arm64-win:
uses: ./.github/workflows/pipeline-segment-electron-build.yml
permissions:
contents: read
needs: checkout-windows
with:
environment: production-release
@@ -76,6 +84,8 @@ jobs:
publish-x86-win:
uses: ./.github/workflows/pipeline-segment-electron-build.yml
permissions:
contents: read
needs: checkout-windows
with:
environment: production-release

2
.gitignore vendored
View File

@@ -53,3 +53,5 @@ ts-gen
patches/mtime-cache.json
spec/fixtures/logo.png
.yarn/install-state.gz

942
.yarn/releases/yarn-4.12.0.cjs vendored Executable file

File diff suppressed because one or more lines are too long

12
.yarnrc.yml Normal file
View File

@@ -0,0 +1,12 @@
enableScripts: false
nmHoistingLimits: workspaces
nodeLinker: node-modules
npmMinimalAgeGate: 10080
npmPreapprovedPackages:
- "@electron/*"
yarnPath: .yarn/releases/yarn-4.12.0.cjs

9
DEPS
View File

@@ -2,9 +2,9 @@ gclient_gn_args_from = 'src'
vars = {
'chromium_version':
'142.0.7444.134',
'142.0.7444.265',
'node_version':
'v22.21.1',
'v22.22.0',
'nan_version':
'e14bdcd1f72d62bca1d541b66da43130384ec213',
'squirrel.mac_version':
@@ -30,9 +30,6 @@ vars = {
# The path of the sysroots.json file.
'sysroots_json_path': 'electron/script/sysroots.json',
# KEEP IN SYNC WITH utils.js FILE
'yarn_version': '1.22.22',
# To be able to build clean Chromium from sources.
'apply_patches': True,
@@ -155,7 +152,7 @@ hooks = [
'action': [
'python3',
'-c',
'import os, subprocess; os.chdir(os.path.join("src", "electron")); subprocess.check_call(["python3", "script/lib/npx.py", "yarn@' + (Var("yarn_version")) + '", "install", "--frozen-lockfile"]);',
'import os, subprocess; os.chdir(os.path.join("src", "electron")); subprocess.check_call(["node", ".yarn/releases/yarn-4.12.0.cjs", "install", "--immutable"]);',
],
},
{

View File

@@ -1216,6 +1216,13 @@ Disables hardware acceleration for current app.
This method can only be called before app is ready.
### `app.isHardwareAccelerationEnabled()`
Returns `boolean` - whether hardware acceleration is currently enabled.
> [!NOTE]
> This information is only usable after the `gpu-info-update` event is emitted.
### `app.disableDomainBlockingFor3DAPIs()`
By default, Chromium disables 3D APIs (e.g. WebGL) until restart on a per

View File

@@ -1262,15 +1262,16 @@ Sets the properties for the window's taskbar button.
#### `win.setAccentColor(accentColor)` _Windows_
* `accentColor` boolean | string - The accent color for the window. By default, follows user preference in System Settings.
* `accentColor` boolean | string | null - The accent color for the window. By default, follows user preference in System Settings. To reset to system default, pass `null`.
Sets the system accent color and highlighting of active window border.
The `accentColor` parameter accepts the following values:
* **Color string** - Sets a custom accent color using standard CSS color formats (Hex, RGB, RGBA, HSL, HSLA, or named colors). Alpha values in RGBA/HSLA formats are ignored and the color is treated as fully opaque.
* **`true`** - Uses the system's default accent color from user preferences in System Settings.
* **`false`** - Explicitly disables accent color highlighting for the window.
* **Color string** - Like `true`, but sets a custom accent color using standard CSS color formats (Hex, RGB, RGBA, HSL, HSLA, or named colors). Alpha values in RGBA/HSLA formats are ignored and the color is treated as fully opaque.
* **`true`** - Enable accent color highlighting for the window with the system accent color regardless of whether accent colors are enabled for windows in System `Settings.`
* **`false`** - Disable accent color highlighting for the window regardless of whether accent colors are currently enabled for windows in System Settings.
* **`null`** - Reset window accent color behavior to follow behavior set in System Settings.
Examples:
@@ -1283,11 +1284,14 @@ win.setAccentColor('#ff0000')
// RGB format (alpha ignored if present).
win.setAccentColor('rgba(255,0,0,0.5)')
// Use system accent color.
// Enable accent color, using the color specified in System Settings.
win.setAccentColor(true)
// Disable accent color.
win.setAccentColor(false)
// Reset window accent color behavior to follow behavior set in System Settings.
win.setAccentColor(null)
```
#### `win.getAccentColor()` _Windows_

View File

@@ -1252,7 +1252,8 @@ Captures a snapshot of the page within `rect`. Omitting `rect` will capture the
Returns `Promise<void>` - the promise will resolve when the page has finished loading
(see [`did-finish-load`](web-contents.md#event-did-finish-load)), and rejects
if the page fails to load (see [`did-fail-load`](web-contents.md#event-did-fail-load)).
if the page fails to load (see
[`did-fail-load`](web-contents.md#event-did-fail-load)). A noop rejection handler is already attached, which avoids unhandled rejection errors. If the existing page has a beforeUnload handler, [`did-fail-load`](web-contents.md#event-did-fail-load) will be called unless [`will-prevent-unload`](web-contents.md#event-did-fail-load) is handled.
Same as [`webContents.loadURL(url[, options])`](web-contents.md#contentsloadurlurl-options).
@@ -1467,15 +1468,16 @@ Sets the properties for the window's taskbar button.
#### `win.setAccentColor(accentColor)` _Windows_
* `accentColor` boolean | string - The accent color for the window. By default, follows user preference in System Settings.
* `accentColor` boolean | string | null - The accent color for the window. By default, follows user preference in System Settings. To reset to system default, pass `null`.
Sets the system accent color and highlighting of active window border.
The `accentColor` parameter accepts the following values:
* **Color string** - Sets a custom accent color using standard CSS color formats (Hex, RGB, RGBA, HSL, HSLA, or named colors). Alpha values in RGBA/HSLA formats are ignored and the color is treated as fully opaque.
* **`true`** - Uses the system's default accent color from user preferences in System Settings.
* **`false`** - Explicitly disables accent color highlighting for the window.
* **Color string** - Like `true`, but sets a custom accent color using standard CSS color formats (Hex, RGB, RGBA, HSL, HSLA, or named colors). Alpha values in RGBA/HSLA formats are ignored and the color is treated as fully opaque.
* **`true`** - Enable accent color highlighting for the window with the system accent color regardless of whether accent colors are enabled for windows in System `Settings.`
* **`false`** - Disable accent color highlighting for the window regardless of whether accent colors are currently enabled for windows in System Settings.
* **`null`** - Reset window accent color behavior to follow behavior set in System Settings.
Examples:
@@ -1488,11 +1490,14 @@ win.setAccentColor('#ff0000')
// RGB format (alpha ignored if present).
win.setAccentColor('rgba(255,0,0,0.5)')
// Use system accent color.
// Enable accent color, using the color specified in System Settings.
win.setAccentColor(true)
// Disable accent color.
win.setAccentColor(false)
// Reset window accent color behavior to follow behavior set in System Settings.
win.setAccentColor(null)
```
#### `win.getAccentColor()` _Windows_

View File

@@ -25,6 +25,11 @@ following properties:
with which the request is associated. Defaults to the empty string. The
`session` option supersedes `partition`. Thus if a `session` is explicitly
specified, `partition` is ignored.
* `bypassCustomProtocolHandlers` boolean (optional) - When set to `true`,
custom protocol handlers registered for the request's URL scheme will not be
called. This allows forwarding an intercepted request to the built-in
handler. [webRequest](web-request.md) handlers will still be triggered
when bypassing custom protocols. Defaults to `false`.
* `credentials` string (optional) - Can be `include`, `omit` or
`same-origin`. Whether to send
[credentials](https://fetch.spec.whatwg.org/#credentials) with this

View File

@@ -34,7 +34,8 @@ See [`Menu`](menu.md) for examples.
* `sublabel` string (optional) _macOS_ - Available in macOS >= 14.4
* `toolTip` string (optional) _macOS_ - Hover text for this menu item.
* `accelerator` string (optional) - An [Accelerator](../tutorial/keyboard-shortcuts.md#accelerators) string.
* `icon` ([NativeImage](native-image.md) | string) (optional)
* `icon` ([NativeImage](native-image.md) | string) (optional) - Can be a
[NativeImage](native-image.md) or the file path of an icon.
* `enabled` boolean (optional) - If false, the menu item will be greyed out and
unclickable.
* `acceleratorWorksWhenHidden` boolean (optional) _macOS_ - default is `true`, and when `false` will prevent the accelerator from triggering the item if the item is not visible.

View File

@@ -202,8 +202,7 @@ Creates a new `NativeImage` instance from `dataUrl`, a base 64 encoded [Data URL
Returns `NativeImage`
Creates a new `NativeImage` instance from the `NSImage` that maps to the
given image name. See Apple's [`NSImageName`](https://developer.apple.com/documentation/appkit/nsimagename#2901388)
documentation for a list of possible values.
given image name. See Apple's [`NSImageName`](https://developer.apple.com/documentation/appkit/nsimagename#2901388) documentation and [SF Symbols](https://developer.apple.com/sf-symbols/) for a list of possible values.
The `hslShift` is applied to the image with the following rules:
@@ -231,6 +230,15 @@ echo -e '#import <Cocoa/Cocoa.h>\nint main() { NSLog(@"%@", SYSTEM_IMAGE_NAME);
where `SYSTEM_IMAGE_NAME` should be replaced with any value from [this list](https://developer.apple.com/documentation/appkit/nsimagename?language=objc).
For SF Symbols, usage looks as follows:
```js
const image = nativeImage.createFromNamedImage('square.and.pencil')
```
where `'square.and.pencil'` is the symbol name from the
[SF Symbols app](https://developer.apple.com/sf-symbols/).
## Class: NativeImage
> Natively wrap images such as tray, dock, and application icons.

View File

@@ -71,7 +71,7 @@ will disable the support for `asar` archives in Node's built-in modules.
### `process.noDeprecation`
A `boolean` that controls whether or not deprecation warnings are printed to `stderr`.
A `boolean` (optional) that controls whether or not deprecation warnings are printed to `stderr`.
Setting this to `true` will silence deprecation warnings. This property is used
instead of the `--no-deprecation` command line flag.

View File

@@ -58,6 +58,10 @@ Rejects if there was an error while deleting the requested item.
This moves a path to the OS-specific trash location (Trash on macOS, Recycle
Bin on Windows, and a desktop-environment-specific location on Linux).
The path must use the default path separator for the platform (backslash on
Windows). Use `path.resolve()` from the `node:path` module to ensure correct
handling on all filesystems.
### `shell.beep()`
Play the beep sound.

View File

@@ -72,6 +72,9 @@
some GTK+3 desktop environments. Default is `false`.
* `transparent` boolean (optional) - Makes the window [transparent](../../tutorial/custom-window-styles.md#transparent-windows).
Default is `false`. On Windows, does not work unless the window is frameless.
When you add a [`View`](../view.md) to a `BaseWindow`, you'll need to call
[`view.setBackgroundColor`](../view.md#viewsetbackgroundcolorcolor) with a transparent
background color on that view to make its background transparent as well.
* `type` string (optional) - The type of window, default is normal window. See more about
this below.
* `visualEffectState` string (optional) _macOS_ - Specify how the material
@@ -99,9 +102,9 @@
* `trafficLightPosition` [Point](point.md) (optional) _macOS_ -
Set a custom position for the traffic light buttons in frameless windows.
* `roundedCorners` boolean (optional) _macOS_ _Windows_ - Whether frameless window
should have rounded corners. Default is `true`. Setting this property
to `false` will prevent the window from being fullscreenable on macOS.
On Windows versions older than Windows 11 Build 22000 this property has no effect, and frameless windows will not have rounded corners.
should have rounded corners. Default is `true`. On Windows versions older than
Windows 11 Build 22000 this property has no effect, and frameless windows will
not have rounded corners.
* `thickFrame` boolean (optional) _Windows_ - Use `WS_THICKFRAME` style for
frameless windows on Windows, which adds the standard window frame. Setting it
to `false` will remove window shadow and window animations, and disable window

View File

@@ -1079,7 +1079,7 @@ Emitted when the [mainFrame](web-contents.md#contentsmainframe-readonly), an `<i
Returns `Promise<void>` - the promise will resolve when the page has finished loading
(see [`did-finish-load`](web-contents.md#event-did-finish-load)), and rejects
if the page fails to load (see
[`did-fail-load`](web-contents.md#event-did-fail-load)). A noop rejection handler is already attached, which avoids unhandled rejection errors.
[`did-fail-load`](web-contents.md#event-did-fail-load)). A noop rejection handler is already attached, which avoids unhandled rejection errors. If the existing page has a beforeUnload handler, [`did-fail-load`](web-contents.md#event-did-fail-load) will be called unless [`will-prevent-unload`](web-contents.md#event-did-fail-load) is handled.
Loads the `url` in the window. The `url` must contain the protocol prefix,
e.g. the `http://` or `file://`. If the load should bypass http cache then
@@ -2410,7 +2410,8 @@ A [`NavigationHistory`](navigation-history.md) used by this webContents.
#### `contents.hostWebContents` _Readonly_
A [`WebContents`](web-contents.md) instance that might own this `WebContents`.
A `WebContents | null` property that represents a [`WebContents`](web-contents.md)
instance that might own this `WebContents`.
#### `contents.devToolsWebContents` _Readonly_

View File

@@ -6,77 +6,17 @@ Follow the guidelines below for building **Electron itself** on Linux, for the p
## Prerequisites
* At least 25GB disk space and 8GB RAM.
* Python >= 3.9.
* [Node.js](https://nodejs.org/download/) >= 22.12.0
* [clang](https://clang.llvm.org/get_started.html) 3.4 or later.
* Development headers of GTK 3 and libnotify.
Due to Electron's dependency on Chromium, prerequisites and dependencies for Electron change over time. [Chromium's documentation on building on Linux](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/linux/build_instructions.md) has up to date information for building Chromium on Linux. This documentation can generally
be followed for building Electron on Linux as well.
On Ubuntu >= 20.04, install the following libraries:
```sh
$ sudo apt-get install build-essential clang libdbus-1-dev libgtk-3-dev \
libnotify-dev libasound2-dev libcap-dev \
libcups2-dev libxtst-dev \
libxss1 libnss3-dev gcc-multilib g++-multilib curl \
gperf bison python3-dbusmock openjdk-8-jre
```
On Ubuntu < 20.04, install the following libraries:
```sh
$ sudo apt-get install build-essential clang libdbus-1-dev libgtk-3-dev \
libnotify-dev libgnome-keyring-dev \
libasound2-dev libcap-dev libcups2-dev libxtst-dev \
libxss1 libnss3-dev gcc-multilib g++-multilib curl \
gperf bison python-dbusmock openjdk-8-jre
```
On RHEL / CentOS, install the following libraries:
```sh
$ sudo yum install clang dbus-devel gtk3-devel libnotify-devel \
libgnome-keyring-devel xorg-x11-server-utils libcap-devel \
cups-devel libXtst-devel alsa-lib-devel libXrandr-devel \
nss-devel python-dbusmock openjdk-8-jre
```
On Fedora, install the following libraries:
```sh
$ sudo dnf install clang dbus-devel gperf gtk3-devel \
libnotify-devel libgnome-keyring-devel libcap-devel \
cups-devel libXtst-devel alsa-lib-devel libXrandr-devel \
nss-devel python-dbusmock
```
On Arch Linux / Manjaro, install the following libraries:
```sh
$ sudo pacman -Syu base-devel clang libdbus gtk2 libnotify \
libgnome-keyring alsa-lib libcap libcups libxtst \
libxss nss gcc-multilib curl gperf bison \
python2 python-dbusmock jdk8-openjdk
```
Other distributions may offer similar packages for installation via package
managers such as pacman. Or one can compile from source code.
Additionally, Electron's [Linux dependency installer](https://github.com/electron/build-images/blob/main/tools/install-deps.sh) can be referenced to get the current dependencies that Electron requires in addition to what Chromium installs via [build/install-deps.sh](https://chromium.googlesource.com/chromium/src/+/HEAD/build/install-build-deps.sh).
### Cross compilation
If you want to build for an `arm` target you should also install the following
dependencies:
If you want to build for an `arm` target, you can use Electron's [Linux dependency installer](https://github.com/electron/build-images/blob/main/tools/install-deps.sh) to install the additional dependencies by passing the `--arm argument`:
```sh
$ sudo apt-get install libc6-dev-armhf-cross linux-libc-dev-armhf-cross \
g++-arm-linux-gnueabihf
```
Similarly for `arm64`, install the following:
```sh
$ sudo apt-get install libc6-dev-arm64-cross linux-libc-dev-arm64-cross \
g++-aarch64-linux-gnu
$ sudo install-deps.sh --arm
```
And to cross-compile for `arm` or targets, you should pass the

View File

@@ -9,7 +9,7 @@ check out our [Electron Versioning](./electron-versioning.md) doc.
| Electron | Alpha | Beta | Stable | EOL | Chrome | Node | Supported |
| ------- | ----- | ------- | ------ | ------ | ---- | ---- | ---- |
| 40.0.0 | 2025-Oct-30 | 2025-Dec-03 | 2025-Oct-28 | 2026-Jun-30 | M144 | TBD | ✅ |
| 40.0.0 | 2025-Oct-30 | 2025-Dec-03 | 2026-Jan-13 | 2026-Jun-30 | M144 | TBD | ✅ |
| 39.0.0 | 2025-Sep-04 | 2025-Oct-01 | 2025-Oct-28 | 2026-May-05 | M142 | v22.20 | ✅ |
| 38.0.0 | 2025-Jun-26 | 2025-Aug-06 | 2025-Sep-02 | 2026-Mar-10 | M140 | v22.18 | ✅ |
| 37.0.0 | 2025-May-01 | 2025-May-28 | 2025-Jun-24 | 2026-Jan-13 | M138 | v22.16 | ✅ |

View File

@@ -118,13 +118,6 @@ You should at least follow these steps to improve the security of your applicati
19. [Check which fuses you can change](#19-check-which-fuses-you-can-change)
20. [Do not expose Electron APIs to untrusted web content](#20-do-not-expose-electron-apis-to-untrusted-web-content)
To automate the detection of misconfigurations and insecure patterns, it is
possible to use
[Electronegativity](https://github.com/doyensec/electronegativity). For
additional details on potential weaknesses and implementation bugs when
developing applications using Electron, please refer to this
[guide for developers and auditors](https://doyensec.com/resources/us-17-Carettoni-Electronegativity-A-Study-Of-Electron-Security-wp.pdf).
### 1. Only load secure content
Any resources not included with your application should be loaded using a

View File

@@ -119,7 +119,10 @@ export function fetchWithSession (input: RequestInfo, init: (RequestInit & {bypa
p.reject(err);
});
if (!req.body?.pipeTo(Writable.toWeb(r as unknown as Writable)).then(() => r.end())) { r.end(); }
// pipeTo expects a WritableStream<Uint8Array>. Node.js' Writable.toWeb returns WritableStream<any>,
// which causes a TS structural mismatch.
const writable = Writable.toWeb(r as unknown as Writable) as unknown as WritableStream<Uint8Array>;
if (!req.body?.pipeTo(writable).then(() => r.end())) { r.end(); }
return p.promise;
}

View File

@@ -4,6 +4,8 @@ import { createReadStream } from 'fs';
import { Readable } from 'stream';
import { ReadableStream } from 'stream/web';
import type { ReadableStreamDefaultReader } from 'stream/web';
// Global protocol APIs.
const { registerSchemesAsPrivileged, getStandardSchemes, Protocol } = process._linkedBinding('electron_browser_protocol');
@@ -12,7 +14,7 @@ const ERR_UNEXPECTED = -9;
const isBuiltInScheme = (scheme: string) => ['http', 'https', 'file'].includes(scheme);
function makeStreamFromPipe (pipe: any): ReadableStream {
function makeStreamFromPipe (pipe: any): ReadableStream<Uint8Array> {
const buf = new Uint8Array(1024 * 1024 /* 1 MB */);
return new ReadableStream({
async pull (controller) {
@@ -38,21 +40,26 @@ function makeStreamFromFileInfo ({
filePath: string;
offset?: number;
length?: number;
}): ReadableStream {
}): ReadableStream<Uint8Array> {
// Node's Readable.toWeb produces a WHATWG ReadableStream whose chunks are Uint8Array.
return Readable.toWeb(createReadStream(filePath, {
start: offset,
end: length >= 0 ? offset + length : undefined
}));
})) as ReadableStream<Uint8Array>;
}
function convertToRequestBody (uploadData: ProtocolRequest['uploadData']): RequestInit['body'] {
if (!uploadData) return null;
// Optimization: skip creating a stream if the request is just a single buffer.
if (uploadData.length === 1 && (uploadData[0] as any).type === 'rawData') return uploadData[0].bytes;
if (uploadData.length === 1 && (uploadData[0] as any).type === 'rawData') {
return uploadData[0].bytes as any;
}
const chunks = [...uploadData] as any[]; // TODO: types are wrong
let current: ReadableStreamDefaultReader | null = null;
return new ReadableStream({
const chunks = [...uploadData] as any[]; // TODO: refine ProtocolRequest types
// Use Node's web stream types explicitly to avoid DOM lib vs Node lib structural mismatches.
// Generic <Uint8Array> ensures reader.read() returns value?: Uint8Array consistent with enqueue.
let current: ReadableStreamDefaultReader<Uint8Array> | null = null;
return new ReadableStream<Uint8Array>({
async pull (controller) {
if (current) {
const { done, value } = await current.read();
@@ -67,7 +74,7 @@ function convertToRequestBody (uploadData: ProtocolRequest['uploadData']): Reque
if (!chunks.length) { return controller.close(); }
const chunk = chunks.shift()!;
if (chunk.type === 'rawData') {
controller.enqueue(chunk.bytes);
controller.enqueue(chunk.bytes as Uint8Array);
} else if (chunk.type === 'file') {
current = makeStreamFromFileInfo(chunk).getReader();
return this.pull!(controller);

View File

@@ -40,7 +40,7 @@ process.on('uncaughtException', function (error) {
// Emit 'exit' event on quit.
const { app } = require('electron');
app.on('quit', (_event, exitCode) => {
app.on('quit', (_event: any, exitCode: number) => {
process.emit('exit', exitCode);
});

View File

@@ -289,7 +289,8 @@ function parseOptions (optionsIn: ClientRequestConstructorOptions | string): Nod
referrerPolicy: options.referrerPolicy,
cache: options.cache,
allowNonHttpProtocols: Object.hasOwn(options, kAllowNonHttpProtocols),
priority: options.priority
priority: options.priority,
bypassCustomProtocolHandlers: options.bypassCustomProtocolHandlers
};
if ('priorityIncremental' in options) {
urlLoaderOptions.priorityIncremental = options.priorityIncremental;

View File

@@ -11,12 +11,14 @@ const { contextIsolationEnabled } = internalContextBridge;
* 1) Use menu API to show context menu.
*/
window.onload = function () {
if (contextIsolationEnabled) {
internalContextBridge.overrideGlobalValueFromIsolatedWorld([
'InspectorFrontendHost', 'showContextMenuAtPoint'
], createMenu);
} else {
window.InspectorFrontendHost!.showContextMenuAtPoint = createMenu;
if (window.InspectorFrontendHost) {
if (contextIsolationEnabled) {
internalContextBridge.overrideGlobalValueFromIsolatedWorld([
'InspectorFrontendHost', 'showContextMenuAtPoint'
], createMenu);
} else {
window.InspectorFrontendHost.showContextMenuAtPoint = createMenu;
}
}
};

View File

@@ -1,14 +1,15 @@
{
"name": "electron",
"name": "@electron-ci/dev-root",
"version": "0.0.0-development",
"repository": "https://github.com/electron/electron",
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
"devDependencies": {
"@azure/storage-blob": "^12.28.0",
"@datadog/datadog-ci": "^4.1.2",
"@electron/asar": "^3.2.13",
"@electron/docs-parser": "^2.0.0",
"@electron/fiddle-core": "^1.3.4",
"@electron/github-app-auth": "^2.2.1",
"@electron/github-app-auth": "^3.2.0",
"@electron/lint-roller": "^3.1.2",
"@electron/typescript-definitions": "^9.1.2",
"@octokit/rest": "^20.1.2",
@@ -24,7 +25,6 @@
"buffer": "^6.0.3",
"chalk": "^4.1.0",
"check-for-leaks": "^1.2.1",
"dugite": "^2.7.1",
"eslint": "^8.57.1",
"eslint-config-standard": "^17.1.0",
"eslint-plugin-import": "^2.32.0",
@@ -40,6 +40,7 @@
"lint-staged": "^16.1.0",
"markdownlint-cli2": "^0.18.0",
"minimist": "^1.2.8",
"node-gyp": "^11.4.2",
"null-loader": "^4.0.1",
"pre-flight": "^2.0.0",
"process": "^0.11.10",
@@ -134,6 +135,18 @@
]
},
"resolutions": {
"nan": "nodejs/nan#e14bdcd1f72d62bca1d541b66da43130384ec213"
"dbus-native/xml2js": "0.5.0",
"abstract-socket": "github:deepak1556/node-abstractsocket#928cc591decd12aff7dad96449da8afc29832c19",
"minimist@npm:~0.0.1": "0.2.4"
},
"packageManager": "yarn@4.12.0",
"workspaces": [
"spec",
"spec/fixtures/native-addon/*"
],
"dependenciesMeta": {
"abstract-socket": {
"built": true
}
}
}

View File

@@ -143,3 +143,7 @@ allow_electron_to_depend_on_components_os_crypt_sync.patch
expose_referrerscriptinfo_hostdefinedoptionsindex.patch
chore_disable_protocol_handler_dcheck.patch
fix_release_mouse_buttons_on_focus_loss_on_wayland.patch
viz_fix_visual_artifacts_due_to_resizing_root_render_pass_with_dcomp.patch
viz_do_not_overallocate_surface_on_initial_render.patch
viz_create_isbufferqueuesupportedandenabled.patch
viz_fix_visual_artifacts_while_resizing_window_with_dcomp.patch

View File

@@ -46,7 +46,7 @@ index 7280ef29b85c1b16b11dd9e4d628a9eb579bb4dd..ab56e29d402a400a8c91aa97b6e82ad7
# than here in :chrome_dll.
deps += [ "//chrome:packed_resources_integrity_header" ]
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 15cfa64348e80a3507fc83c3819e9abdb238bffb..4650080f45da4e321d4b0f0dabd98f2bf097c7c2 100644
index d8978eb678048850cc0e629d0c978f23417b5be9..219c9ae3dde4f2239b5c1331b99c8f2e9a170628 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -7571,9 +7571,12 @@ test("unit_tests") {

View File

@@ -312,7 +312,7 @@ index 7e3d46902fbf736b4240eb3fcb89975a7b222197..57fdc89fc265ad70cb0bff8443cc1026
auto DrawAsSinglePath = [&]() {
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 6f47f1f484ffbc107f454fb2b23a9adda68ff7c0..10a13a986bb5d39323bf25ecba1b3935b1b0a081 100644
index 2e464ef7bbfd7e0d84df348d012e8020d4758726..b59eceacbd4143ef183bb67c39f9ccccc7582adb 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -214,6 +214,10 @@

View File

@@ -0,0 +1,93 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Niklas Wenzel <dev@nikwen.de>
Date: Wed, 3 Dec 2025 17:10:02 +0100
Subject: viz: Create IsBufferQueueSupportedAndEnabled()
Manual backport of crrev.com/c/7210913
Bug: 457463689
Change-Id: I31bbaa6b5d79697c6bb5e1fc6738f6ea5a937b4f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7210913
Reviewed-by: Michael Tang <tangm@microsoft.com>
Commit-Queue: David Sanders <dsanders11@ucsbalum.com>
Reviewed-by: Vasiliy Telezhnikov <vasilyt@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1553190}
diff --git a/components/viz/service/display/output_surface.cc b/components/viz/service/display/output_surface.cc
index ff795eb057ac64f40aa842fec8e053d12f57f538..71287614c627d39f8d019889498205ab3eff2a69 100644
--- a/components/viz/service/display/output_surface.cc
+++ b/components/viz/service/display/output_surface.cc
@@ -21,6 +21,16 @@
namespace viz {
+namespace {
+
+#if BUILDFLAG(IS_WIN)
+// Use BufferQueue for the primary plane instead of a DXGI swap chain or DComp
+// surface.
+BASE_FEATURE(kBufferQueue, base::FEATURE_DISABLED_BY_DEFAULT);
+#endif
+
+} // namespace
+
OutputSurface::Capabilities::Capabilities() = default;
OutputSurface::Capabilities::~Capabilities() = default;
OutputSurface::Capabilities::Capabilities(const Capabilities& capabilities) =
@@ -94,6 +104,12 @@ bool IsDelegatedCompositingSupportedAndEnabled(
// Ensure we check the feature flag iff the feature is supported.
return features::IsDelegatedCompositingEnabled();
}
+
+bool IsBufferQueueSupportedAndEnabled(
+ OutputSurface::DCSupportLevel support_level) {
+ return support_level >= OutputSurface::DCSupportLevel::kDCompDynamicTexture &&
+ base::FeatureList::IsEnabled(kBufferQueue);
+}
#endif
} // namespace viz
diff --git a/components/viz/service/display/output_surface.h b/components/viz/service/display/output_surface.h
index 25306ab6e18a266efdc329e4ddd81f5303033f4c..589f4c10dad9c807c9e3ce7baba63795b629435b 100644
--- a/components/viz/service/display/output_surface.h
+++ b/components/viz/service/display/output_surface.h
@@ -307,6 +307,9 @@ class VIZ_SERVICE_EXPORT OutputSurface {
// `features::IsDelegatedCompositingEnabled()`.
bool IsDelegatedCompositingSupportedAndEnabled(
OutputSurface::DCSupportLevel support_level);
+
+bool IsBufferQueueSupportedAndEnabled(
+ OutputSurface::DCSupportLevel support_level);
#endif
} // namespace viz
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc
index e34e15dda13a183568fc3e186d3b89da1e828ad4..9b9a4c02c975799fe42b04f0d5b680274d28b09e 100644
--- a/components/viz/service/display/skia_renderer.cc
+++ b/components/viz/service/display/skia_renderer.cc
@@ -121,12 +121,6 @@ namespace {
BASE_FEATURE(kDumpWithoutCrashingOnMissingRenderPassBacking,
base::FEATURE_ENABLED_BY_DEFAULT);
-#if BUILDFLAG(IS_WIN)
-// Use BufferQueue for the primary plane instead of a DXGI swap chain or DComp
-// surface.
-BASE_FEATURE(kBufferQueue, base::FEATURE_DISABLED_BY_DEFAULT);
-#endif
-
// Smallest unit that impacts anti-aliasing output. We use this to determine
// when an exterior edge (with AA) has been clipped (no AA). The specific value
// was chosen to match that used by gl_renderer.
@@ -992,10 +986,8 @@ SkiaRenderer::SkiaRenderer(const RendererSettings* settings,
// It's possible to use BufferQueue with DComp textures, so we can optionally
// enable it behind a feature flag.
- const bool want_buffer_queue =
- output_surface_->capabilities().dc_support_level >=
- OutputSurface::DCSupportLevel::kDCompDynamicTexture &&
- base::FeatureList::IsEnabled(kBufferQueue);
+ const bool want_buffer_queue = IsBufferQueueSupportedAndEnabled(
+ output_surface_->capabilities().dc_support_level);
#else
const bool want_buffer_queue = true;
#endif

View File

@@ -0,0 +1,45 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Niklas Wenzel <dev@nikwen.de>
Date: Wed, 3 Dec 2025 17:08:55 +0100
Subject: viz: Do not overallocate surface on initial render
Manual backport of crrev.com/c/7129658
Change-Id: I0baa5865dbe66efc7b0f3f793c8e89cdc6aaa0b6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7129658
Commit-Queue: Vasiliy Telezhnikov <vasilyt@chromium.org>
Reviewed-by: Vasiliy Telezhnikov <vasilyt@chromium.org>
Reviewed-by: Michael Tang <tangm@microsoft.com>
Cr-Commit-Position: refs/heads/main@{#1544293}
diff --git a/components/viz/service/display/direct_renderer.cc b/components/viz/service/display/direct_renderer.cc
index c03a4b3db61371021a94128f698126b5fef2f577..01abf5d36e2e117acf6f9cdc91307c9ac5616453 100644
--- a/components/viz/service/display/direct_renderer.cc
+++ b/components/viz/service/display/direct_renderer.cc
@@ -1081,10 +1081,13 @@ gfx::Size DirectRenderer::CalculateTextureSizeForRenderPass(
// buffer area and number of reallocations to quantify the trade-off.
gfx::Size DirectRenderer::CalculateSizeForOutputSurface(
const gfx::Size& requested_viewport_size) {
+ const gfx::Size surface_size = surface_size_for_swap_buffers();
+
// We're not able to clip back buffers if output surface does not support
- // clipping.
- if (requested_viewport_size == surface_size_for_swap_buffers() ||
+ // clipping. We don't round on the initial frame when a window is first shown.
+ if (requested_viewport_size == surface_size ||
!output_surface_->capabilities().supports_viewporter ||
+ surface_size.IsZero() ||
settings_->dont_round_texture_sizes_for_pixel_tests) {
device_viewport_size_ = requested_viewport_size;
return requested_viewport_size;
@@ -1102,8 +1105,8 @@ gfx::Size DirectRenderer::CalculateSizeForOutputSurface(
// allows backings to be more easily reused during a resize operation.
const int request_width = requested_viewport_size.width();
const int request_height = requested_viewport_size.height();
- int surface_width = surface_size_for_swap_buffers().width();
- int surface_height = surface_size_for_swap_buffers().height();
+ int surface_width = surface_size.width();
+ int surface_height = surface_size.height();
constexpr int multiple = 256;
// If |request_width| or |request_height| is already a multiple of |multiple|,

View File

@@ -0,0 +1,43 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Niklas Wenzel <dev@nikwen.de>
Date: Thu, 20 Nov 2025 11:51:44 -0800
Subject: viz: Fix visual artifacts due to resizing root render pass with DComp
Backport of crrev.com/c/7156576
Refs https://github.com/electron/electron/issues/36280#issuecomment-3560964534
Bug: 457463689
Change-Id: I7e00eadb2a1c3b44d64939d1a870d89befee158b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7156576
Reviewed-by: Vasiliy Telezhnikov <vasilyt@chromium.org>
Reviewed-by: Jonathan Ross <jonross@chromium.org>
Commit-Queue: Jonathan Ross <jonross@chromium.org>
Reviewed-by: Michael Tang <tangm@microsoft.com>
Cr-Commit-Position: refs/heads/main@{#1547987}
diff --git a/components/viz/service/display_embedder/skia_output_device_dcomp.cc b/components/viz/service/display_embedder/skia_output_device_dcomp.cc
index 81649eb59eb71ac950779af0f521a1f2a02e3add..7ac9ea1cdc4416a7af8dc2a75404cbc15be6cfad 100644
--- a/components/viz/service/display_embedder/skia_output_device_dcomp.cc
+++ b/components/viz/service/display_embedder/skia_output_device_dcomp.cc
@@ -39,6 +39,11 @@
namespace viz {
namespace {
+// With DirectComposition, resize surface based on root render pass size to
+// avoid gutter which shows stale pixels.
+BASE_FEATURE(kDirectCompositionResizeBasedOnRootSurface,
+ base::FEATURE_ENABLED_BY_DEFAULT);
+
base::TimeTicks g_last_reshape_failure = base::TimeTicks();
NOINLINE void CheckForLoopFailures() {
@@ -155,6 +160,8 @@ SkiaOutputDeviceDComp::SkiaOutputDeviceDComp(
capabilities_.renderer_allocates_images = true;
capabilities_.supports_viewporter = presenter_->SupportsViewporter();
capabilities_.supports_non_backed_solid_color_overlays = true;
+ capabilities_.resize_based_on_root_surface =
+ base::FeatureList::IsEnabled(kDirectCompositionResizeBasedOnRootSurface);
DCHECK(context_state_);
DCHECK(context_state_->gr_context() ||

View File

@@ -0,0 +1,122 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Niklas Wenzel <dev@nikwen.de>
Date: Wed, 3 Dec 2025 17:42:58 +0100
Subject: viz: Fix visual artifacts while resizing window with DComp
Manual backport of crrev.com/c/7115438
Bug: 457463689
Change-Id: I9c684effe15e0b112ae533faa243e5a035e9c875
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7115438
Commit-Queue: David Sanders <dsanders11@ucsbalum.com>
Reviewed-by: Michael Tang <tangm@microsoft.com>
Reviewed-by: Vasiliy Telezhnikov <vasilyt@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1553192}
diff --git a/components/viz/service/display/direct_renderer.cc b/components/viz/service/display/direct_renderer.cc
index 01abf5d36e2e117acf6f9cdc91307c9ac5616453..7e45d9ea46d0d4095169daf748e20c98db21969d 100644
--- a/components/viz/service/display/direct_renderer.cc
+++ b/components/viz/service/display/direct_renderer.cc
@@ -243,6 +243,31 @@ void DirectRenderer::DrawFrame(
current_frame()->device_viewport_size = device_viewport_size;
current_frame()->display_color_spaces = display_color_spaces;
+ gfx::Size surface_resource_size =
+ CalculateSizeForOutputSurface(device_viewport_size);
+
+#if BUILDFLAG(IS_WIN)
+ if (output_surface_->capabilities().clear_drawn_areas_outside_viewport &&
+ device_viewport_size != surface_resource_size) {
+ // On Windows with DirectComposition, we cannot synchronize the swap chain
+ // |Present| and the DComp |Commit| calls to take effect at the same time.
+ // (Both take effect asynchronously.) Hence, presenting a frame and changing
+ // the DComp layer clip rect can happen at different times. This can lead to
+ // ugly visual artifacts while resizing the window because it can reveal
+ // areas of the surface that are outside the viewport (crbug.com/457463689).
+ // To prevent those artifacts, we clear areas outside of the viewport with a
+ // transparent color. Transparency is expensive, so we use it only while
+ // resizing.
+ // This line gives us a transparent image format and triggers the background
+ // to be cleared in |SkiaRenderer::ClearFramebuffer|.
+ root_render_pass->has_transparent_background = true;
+ // Redraw and swap the whole surface.
+ root_render_pass->output_rect = gfx::Rect(surface_resource_size);
+ current_frame()->root_damage_rect = gfx::Rect(surface_resource_size);
+ current_frame()->device_viewport_size = surface_resource_size;
+ }
+#endif
+
output_surface_->SetNeedsMeasureNextDrawLatency();
BeginDrawingFrame();
@@ -274,8 +299,6 @@ void DirectRenderer::DrawFrame(
current_frame()->display_color_spaces.GetOutputBufferFormat(
current_frame()->root_render_pass->content_color_usage,
frame_has_alpha));
- gfx::Size surface_resource_size =
- CalculateSizeForOutputSurface(device_viewport_size);
if (overlay_processor_) {
// Display transform and viewport size are needed for overlay validator on
// Android SurfaceControl, and viewport size is need on Windows. These need
@@ -397,8 +420,10 @@ void DirectRenderer::DrawFrame(
// If we need to redraw the frame, the whole output should be considered
// damaged.
- if (needs_full_frame_redraw)
- current_frame()->root_damage_rect = gfx::Rect(device_viewport_size);
+ if (needs_full_frame_redraw) {
+ current_frame()->root_damage_rect =
+ gfx::Rect(current_frame()->device_viewport_size);
+ }
if (!skip_drawing_root_render_pass) {
DrawRenderPassAndExecuteCopyRequests(root_render_pass);
diff --git a/components/viz/service/display/output_surface.h b/components/viz/service/display/output_surface.h
index 589f4c10dad9c807c9e3ce7baba63795b629435b..641bbfc732c88141ddd929a4c334360462259ee4 100644
--- a/components/viz/service/display/output_surface.h
+++ b/components/viz/service/display/output_surface.h
@@ -106,6 +106,11 @@ class VIZ_SERVICE_EXPORT OutputSurface {
#if BUILDFLAG(IS_WIN)
// Whether this OutputSurface supports direct composition layers.
DCSupportLevel dc_support_level = DCSupportLevel::kNone;
+ // Whether to 1) clear all drawn areas outside the viewport with a
+ // transparent background color when drawing a frame and 2) swap them. This
+ // is necessary if the surface clip rect can get out of sync with the
+ // viewport size (e.g., due to a race condition).
+ bool clear_drawn_areas_outside_viewport = false;
#endif
// Whether this OutputSurface should skip DrawAndSwap(). This is true for
// the unified display on Chrome OS. All drawing is handled by the physical
diff --git a/components/viz/service/display_embedder/skia_output_device_dcomp.cc b/components/viz/service/display_embedder/skia_output_device_dcomp.cc
index 7ac9ea1cdc4416a7af8dc2a75404cbc15be6cfad..8e027d1382c5d639c1e114b8e25b6cea3af3445d 100644
--- a/components/viz/service/display_embedder/skia_output_device_dcomp.cc
+++ b/components/viz/service/display_embedder/skia_output_device_dcomp.cc
@@ -39,10 +39,8 @@
namespace viz {
namespace {
-// With DirectComposition, resize surface based on root render pass size to
-// avoid gutter which shows stale pixels.
-BASE_FEATURE(kDirectCompositionResizeBasedOnRootSurface,
- base::FEATURE_ENABLED_BY_DEFAULT);
+// Apply fixes for crbug.com/457463689.
+BASE_FEATURE(kDirectCompositionResizeFixes, base::FEATURE_ENABLED_BY_DEFAULT);
base::TimeTicks g_last_reshape_failure = base::TimeTicks();
@@ -161,7 +159,14 @@ SkiaOutputDeviceDComp::SkiaOutputDeviceDComp(
capabilities_.supports_viewporter = presenter_->SupportsViewporter();
capabilities_.supports_non_backed_solid_color_overlays = true;
capabilities_.resize_based_on_root_surface =
- base::FeatureList::IsEnabled(kDirectCompositionResizeBasedOnRootSurface);
+ base::FeatureList::IsEnabled(kDirectCompositionResizeFixes);
+ // With delegated compositing or a buffer queue, |Present| and |Commit| are
+ // synchronized and the clear is not needed.
+ capabilities_.clear_drawn_areas_outside_viewport =
+ base::FeatureList::IsEnabled(kDirectCompositionResizeFixes) &&
+ !IsDelegatedCompositingSupportedAndEnabled(
+ capabilities_.dc_support_level) &&
+ !IsBufferQueueSupportedAndEnabled(capabilities_.dc_support_level);
DCHECK(context_state_);
DCHECK(context_state_->gr_context() ||

View File

@@ -1 +1,2 @@
chore_expose_ui_to_allow_electron_to_set_dock_side.patch
fix_element_tree_flickering_with_node_inspection.patch

View File

@@ -0,0 +1,107 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alex Rudenko <alexrudenko@chromium.org>
Date: Thu, 20 Nov 2025 11:18:30 +0100
Subject: Fix element tree flickering with node inspection
Regressed in https://crrev.com/c/6888910. The highlighting in the tree
outline emits the INSPECT_MODE_WILL_BE_TOGGLED on the overlay model
causing the tree to clear the highlight immediately. This CL
recovers the logic missed in the https://crrev.com/c/6888910
to prevent re-entrancy during highlighting.
Fixed: 462120622
Change-Id: I08af098f7a142085c2fb16511031855623e07c4b
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/7170551
Reviewed-by: Philip Pfaffe <pfaffe@chromium.org>
Commit-Queue: Philip Pfaffe <pfaffe@chromium.org>
Auto-Submit: Alex Rudenko <alexrudenko@chromium.org>
diff --git a/front_end/panels/elements/DOMTreeWidget.test.ts b/front_end/panels/elements/DOMTreeWidget.test.ts
index 43ae133087a61c47c84349c7550485bd52b23847..d83fddd7afc1871b8064631d63c1b6b1e5357b70 100644
--- a/front_end/panels/elements/DOMTreeWidget.test.ts
+++ b/front_end/panels/elements/DOMTreeWidget.test.ts
@@ -24,6 +24,7 @@ describeWithMockConnection('DOMTreeWidget', () => {
elementsTreeOutline,
alreadyExpandedParentTreeElement: null,
highlightedTreeElement: null,
+ isUpdatingHighlights: false,
});
const domTree = new Elements.ElementsTreeOutline.DOMTreeWidget(undefined, view);
domTree.performUpdate();
diff --git a/front_end/panels/elements/ElementsTreeOutline.ts b/front_end/panels/elements/ElementsTreeOutline.ts
index bd8093e1c0961648e782234ed5826273d6ace6d9..c6c8d9d29a84f872126ca0b7c847dffe08c285ad 100644
--- a/front_end/panels/elements/ElementsTreeOutline.ts
+++ b/front_end/panels/elements/ElementsTreeOutline.ts
@@ -105,6 +105,7 @@ interface ViewInput {
interface ViewOutput {
elementsTreeOutline?: ElementsTreeOutline;
highlightedTreeElement: ElementsTreeElement|null;
+ isUpdatingHighlights: boolean;
alreadyExpandedParentTreeElement: ElementsTreeElement|null;
}
@@ -136,6 +137,7 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
// Node highlighting logic. FIXME: express as a lit template.
const previousHighlightedNode = output.highlightedTreeElement?.node() ?? null;
if (previousHighlightedNode !== input.currentHighlightedNode) {
+ output.isUpdatingHighlights = true;
let treeElement: ElementsTreeElement|null = null;
if (output.highlightedTreeElement) {
@@ -173,6 +175,7 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
output.highlightedTreeElement = treeElement;
output.elementsTreeOutline.setHoverEffect(treeElement);
treeElement?.reveal(true);
+ output.isUpdatingHighlights = false;
}
};
@@ -225,6 +228,7 @@ export class DOMTreeWidget extends UI.Widget.Widget {
#viewOutput: ViewOutput = {
highlightedTreeElement: null,
alreadyExpandedParentTreeElement: null,
+ isUpdatingHighlights: false,
};
#highlightThrottler = new Common.Throttler.Throttler(100);
@@ -239,8 +243,8 @@ export class DOMTreeWidget extends UI.Widget.Widget {
SDK.OverlayModel.OverlayModel, SDK.OverlayModel.Events.HIGHLIGHT_NODE_REQUESTED, this.#highlightNode, this,
{scoped: true});
SDK.TargetManager.TargetManager.instance().addModelListener(
- SDK.OverlayModel.OverlayModel, SDK.OverlayModel.Events.INSPECT_MODE_WILL_BE_TOGGLED, this.#clearState, this,
- {scoped: true});
+ SDK.OverlayModel.OverlayModel, SDK.OverlayModel.Events.INSPECT_MODE_WILL_BE_TOGGLED,
+ this.#clearHighlightedNode, this, {scoped: true});
}
}
@@ -251,7 +255,13 @@ export class DOMTreeWidget extends UI.Widget.Widget {
});
}
- #clearState(): void {
+ #clearHighlightedNode(): void {
+ // Highlighting an element via tree outline will emit the
+ // INSPECT_MODE_WILL_BE_TOGGLED event, therefore, we skip it if the view
+ // informed us that it is updating the element.
+ if (this.#viewOutput.isUpdatingHighlights) {
+ return;
+ }
this.#currentHighlightedNode = null;
this.requestUpdate();
}
@@ -305,11 +315,11 @@ export class DOMTreeWidget extends UI.Widget.Widget {
currentHighlightedNode: this.#currentHighlightedNode,
onElementsTreeUpdated: this.onElementsTreeUpdated.bind(this),
onSelectedNodeChanged: event => {
- this.#clearState();
+ this.#clearHighlightedNode();
this.onSelectedNodeChanged(event);
},
- onElementCollapsed: this.#clearState.bind(this),
- onElementExpanded: this.#clearState.bind(this),
+ onElementCollapsed: this.#clearHighlightedNode.bind(this),
+ onElementExpanded: this.#clearHighlightedNode.bind(this),
},
this.#viewOutput, this.contentElement);
}

View File

@@ -7,3 +7,4 @@ fix_support_new_variant_of_namedpropertyhandlerconfiguration_and.patch
fix_correct_usages_of_v8_returnvalue_void_set_nonempty_for_new.patch
chore_remove_deprecated_functioncallbackinfo_holder.patch
fix_replace_deprecated_get_setprototype.patch
chore_add_yarnrc_yml_and_yarn_lock_file_to_use_yarn_v4.patch

File diff suppressed because it is too large Load Diff

View File

@@ -39,7 +39,6 @@ build_change_crdtp_protocoltypetraits_signatures_to_avoid_conflict.patch
fix_adjust_wpt_and_webidl_tests_for_enabled_float16array.patch
chore_add_createexternalizabletwobytestring_to_globals.patch
refactor_attach_cppgc_heap_on_v8_isolate_creation.patch
fix_ensure_traverseparent_bails_on_resource_path_exit.patch
cli_move_--trace-atomics-wait_to_eol.patch
fix_cppgc_initializing_twice.patch
fix_task_starvation_in_inspector_context_test.patch
@@ -53,3 +52,8 @@ src_switch_from_get_setprototype_to_get_setprototypev2.patch
fix_replace_deprecated_setprototype.patch
fix_redefined_macos_sdk_header_symbols.patch
src_use_cp_utf8_for_wide_file_names_on_win32.patch
fix_ensure_traverseparent_bails_on_resource_path_exit.patch
src_handle_der_decoding_errors_from_system_certificates.patch
remove_obsolete_noarraybufferzerofillscope.patch
src_prepare_for_v8_sandboxing.patch
test_correct_conditional_secure_heap_flags_test.patch

View File

@@ -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 8e227ddd1be50c046a8cf2895a31d607eb7d31de..82f53bba29613de212f64be440ca20d7c630fddf 100644
index ceac508418f489a8077c1bc85a2feaf85bf60480..33827edce63c9fe08b52aea59571391a83853443 100644
--- a/src/api/environment.cc
+++ b/src/api/environment.cc
@@ -654,7 +654,7 @@ std::unique_ptr<MultiIsolatePlatform> MultiIsolatePlatform::Create(
@@ -646,7 +646,7 @@ std::unique_ptr<MultiIsolatePlatform> MultiIsolatePlatform::Create(
MaybeLocal<Object> GetPerContextExports(Local<Context> context,
IsolateData* isolate_data) {
@@ -18,7 +18,7 @@ index 8e227ddd1be50c046a8cf2895a31d607eb7d31de..82f53bba29613de212f64be440ca20d7
EscapableHandleScope handle_scope(isolate);
Local<Object> global = context->Global();
@@ -700,7 +700,7 @@ void ProtoThrower(const FunctionCallbackInfo<Value>& info) {
@@ -692,7 +692,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 8e227ddd1be50c046a8cf2895a31d607eb7d31de..82f53bba29613de212f64be440ca20d7
HandleScope handle_scope(isolate);
// When `IsCodeGenerationFromStringsAllowed` is true, V8 takes the fast path
@@ -779,7 +779,7 @@ Maybe<void> InitializeContextRuntime(Local<Context> context) {
@@ -771,7 +771,7 @@ Maybe<void> InitializeContextRuntime(Local<Context> context) {
}
Maybe<void> InitializeBaseContextForSnapshot(Local<Context> context) {
@@ -36,7 +36,7 @@ index 8e227ddd1be50c046a8cf2895a31d607eb7d31de..82f53bba29613de212f64be440ca20d7
HandleScope handle_scope(isolate);
// Delete `Intl.v8BreakIterator`
@@ -804,7 +804,7 @@ Maybe<void> InitializeBaseContextForSnapshot(Local<Context> context) {
@@ -796,7 +796,7 @@ Maybe<void> InitializeBaseContextForSnapshot(Local<Context> context) {
}
Maybe<void> InitializeMainContextForSnapshot(Local<Context> context) {
@@ -45,7 +45,7 @@ index 8e227ddd1be50c046a8cf2895a31d607eb7d31de..82f53bba29613de212f64be440ca20d7
HandleScope handle_scope(isolate);
// Initialize the default values.
@@ -822,7 +822,7 @@ Maybe<void> InitializeMainContextForSnapshot(Local<Context> context) {
@@ -814,7 +814,7 @@ Maybe<void> InitializeMainContextForSnapshot(Local<Context> context) {
MaybeLocal<Object> InitializePrivateSymbols(Local<Context> context,
IsolateData* isolate_data) {
CHECK(isolate_data);
@@ -54,7 +54,7 @@ index 8e227ddd1be50c046a8cf2895a31d607eb7d31de..82f53bba29613de212f64be440ca20d7
EscapableHandleScope scope(isolate);
Context::Scope context_scope(context);
@@ -846,7 +846,7 @@ MaybeLocal<Object> InitializePrivateSymbols(Local<Context> context,
@@ -838,7 +838,7 @@ MaybeLocal<Object> InitializePrivateSymbols(Local<Context> context,
MaybeLocal<Object> InitializePerIsolateSymbols(Local<Context> context,
IsolateData* isolate_data) {
CHECK(isolate_data);
@@ -63,7 +63,7 @@ index 8e227ddd1be50c046a8cf2895a31d607eb7d31de..82f53bba29613de212f64be440ca20d7
EscapableHandleScope scope(isolate);
Context::Scope context_scope(context);
@@ -872,7 +872,7 @@ MaybeLocal<Object> InitializePerIsolateSymbols(Local<Context> context,
@@ -864,7 +864,7 @@ MaybeLocal<Object> InitializePerIsolateSymbols(Local<Context> context,
Maybe<void> InitializePrimordials(Local<Context> context,
IsolateData* isolate_data) {
// Run per-context JS files.
@@ -508,10 +508,10 @@ index 492d5f455f45a5c8a957ecdabed38709a633f640..48f9917113555c7ed87e37750c45d152
Local<Array> keys;
if (!entries->GetOwnPropertyNames(context).ToLocal(&keys))
diff --git a/src/node_errors.cc b/src/node_errors.cc
index 4386a1bc5678e351ce084cd2c47202561619b164..8d51201ad24999ed8f54e16c7878432d41841cf2 100644
index 36a21b9523351fe2f225ffe7fca184d737640b62..c6e9e2c00064348c435ae10871a4013cb49376e6 100644
--- a/src/node_errors.cc
+++ b/src/node_errors.cc
@@ -633,7 +633,7 @@ v8::ModifyCodeGenerationFromStringsResult ModifyCodeGenerationFromStrings(
@@ -631,7 +631,7 @@ v8::ModifyCodeGenerationFromStringsResult ModifyCodeGenerationFromStrings(
v8::Local<v8::Context> context,
v8::Local<v8::Value> source,
bool is_code_like) {
@@ -520,7 +520,7 @@ index 4386a1bc5678e351ce084cd2c47202561619b164..8d51201ad24999ed8f54e16c7878432d
if (context->GetNumberOfEmbedderDataFields() <=
ContextEmbedderIndex::kAllowCodeGenerationFromStrings) {
@@ -1000,7 +1000,7 @@ const char* errno_string(int errorno) {
@@ -1037,7 +1037,7 @@ const char* errno_string(int errorno) {
}
void PerIsolateMessageListener(Local<Message> message, Local<Value> error) {
@@ -529,7 +529,7 @@ index 4386a1bc5678e351ce084cd2c47202561619b164..8d51201ad24999ed8f54e16c7878432d
switch (message->ErrorLevel()) {
case Isolate::MessageErrorLevel::kMessageWarning: {
Environment* env = Environment::GetCurrent(isolate);
@@ -1161,7 +1161,7 @@ void Initialize(Local<Object> target,
@@ -1198,7 +1198,7 @@ void Initialize(Local<Object> target,
SetMethod(
context, target, "getErrorSourcePositions", GetErrorSourcePositions);
@@ -592,7 +592,7 @@ index 3c5f38ba4f492749c9d7d82179d2a6563787602b..6e83da3ee975dea431e21209bba9227e
data_.Reset();
return ret;
diff --git a/src/node_modules.cc b/src/node_modules.cc
index ed22da844a61b14b8580cd3d6bb3a233b8559b38..14f2a35f87e8c2fa17898147d7247cc00c066f35 100644
index 62050791174563f88b8629d576eed8959b3c2e20..fa04b4a8cdd02a2cad1eaf2e5a848b951d1b1150 100644
--- a/src/node_modules.cc
+++ b/src/node_modules.cc
@@ -64,7 +64,7 @@ void BindingData::Deserialize(v8::Local<v8::Context> context,
@@ -604,7 +604,7 @@ index ed22da844a61b14b8580cd3d6bb3a233b8559b38..14f2a35f87e8c2fa17898147d7247cc0
Realm* realm = Realm::GetCurrent(context);
BindingData* binding = realm->AddBindingData<BindingData>(holder);
CHECK_NOT_NULL(binding);
@@ -656,7 +656,7 @@ void BindingData::CreatePerContextProperties(Local<Object> target,
@@ -617,7 +617,7 @@ void BindingData::CreatePerContextProperties(Local<Object> target,
Realm* realm = Realm::GetCurrent(context);
realm->AddBindingData<BindingData>(target);
@@ -640,7 +640,7 @@ index 66a8ee48fc68b22eaf6c9d9209cc5cb2439e55ff..b31e244f8af7d37c35319853a478776c
env->AssignToContext(context, this, ContextInfo(""));
}
diff --git a/src/node_report.cc b/src/node_report.cc
index 8ff711f12e19f73e50daac2b9c0fd26773d32758..6966710e8f0be542364850776ddf76f9223a02e7 100644
index e1f4e30417d17f85d2294f3a01e6d90f0a443948..12a59307b452b0d67ebe909cae0458b8a0ca085b 100644
--- a/src/node_report.cc
+++ b/src/node_report.cc
@@ -399,7 +399,7 @@ static void PrintJavaScriptErrorProperties(JSONWriter* writer,

View File

@@ -8,10 +8,10 @@ they use themselves as the entry point. We should try to upstream some form
of this.
diff --git a/lib/internal/process/pre_execution.js b/lib/internal/process/pre_execution.js
index d12d21905c4823f45cffeea4423e99e81b1008f5..4987cd3f6c9eefb440bca3f58113df6cd5b410ac 100644
index 15443a710ccf53fae333da3b1fbb52a970c658d5..464b34829c1a566836bfca6bbc2b87fcf5e50016 100644
--- a/lib/internal/process/pre_execution.js
+++ b/lib/internal/process/pre_execution.js
@@ -267,12 +267,14 @@ function patchProcessObject(expandArgv1) {
@@ -265,12 +265,14 @@ function patchProcessObject(expandArgv1) {
// the entry point.
if (expandArgv1 && process.argv[1] && process.argv[1][0] !== '-') {
// Expand process.argv[1] into a full path.

View File

@@ -8,10 +8,10 @@ resource path. This commit ensures that the TraverseParent function
bails out if the parent path is outside of the resource path.
diff --git a/src/node_modules.cc b/src/node_modules.cc
index 60b03b1563b230f78d8a9bdd8480da4d2ae90a27..35bfada261258407982d9e24cf7b3e820235c941 100644
index 947513d5b91e8c13478b25d80a1157edbcd64b64..4e46df6afe6ca57f6df9a64d3fc572450baf7d5c 100644
--- a/src/node_modules.cc
+++ b/src/node_modules.cc
@@ -279,8 +279,41 @@ const BindingData::PackageConfig* BindingData::TraverseParent(
@@ -315,8 +315,41 @@ const BindingData::PackageConfig* BindingData::TraverseParent(
Realm* realm, const std::filesystem::path& check_path) {
std::filesystem::path current_path = check_path;
auto env = realm->env();
@@ -47,22 +47,22 @@ index 60b03b1563b230f78d8a9bdd8480da4d2ae90a27..35bfada261258407982d9e24cf7b3e82
+ });
+ };
+
+ bool did_original_path_start_with_resources_path = starts_with(check_path.
+ generic_string(), resources_path);
+ bool did_original_path_start_with_resources_path = starts_with(
+ ConvertGenericPathToUTF8(check_path), resources_path);
+
do {
current_path = current_path.parent_path();
@@ -299,6 +332,12 @@ const BindingData::PackageConfig* BindingData::TraverseParent(
return nullptr;
@@ -336,6 +369,12 @@ const BindingData::PackageConfig* BindingData::TraverseParent(
}
}
+ // If current path is outside the resources path, bail.
+ if (did_original_path_start_with_resources_path &&
+ !starts_with(current_path.generic_string(), resources_path)) {
+ !starts_with(ConvertGenericPathToUTF8(current_path), resources_path)) {
+ return nullptr;
+ }
+
// Check if the path ends with `/node_modules`
if (current_path.generic_string().ends_with("/node_modules")) {
if (current_path.filename() == "node_modules") {
return nullptr;

View File

@@ -20,7 +20,7 @@ index 82225b0a53dd828750991a4e15a060b736b6ea2b..4b0d31356a2496a7fc67876a22da2453
V(performance_entry_callback, v8::Function) \
V(prepare_stack_trace_callback, v8::Function) \
diff --git a/src/node_modules.cc b/src/node_modules.cc
index 35bfada261258407982d9e24cf7b3e820235c941..ed22da844a61b14b8580cd3d6bb3a233b8559b38 100644
index 60b03b1563b230f78d8a9bdd8480da4d2ae90a27..62050791174563f88b8629d576eed8959b3c2e20 100644
--- a/src/node_modules.cc
+++ b/src/node_modules.cc
@@ -21,6 +21,7 @@ namespace modules {
@@ -90,7 +90,7 @@ index 35bfada261258407982d9e24cf7b3e820235c941..ed22da844a61b14b8580cd3d6bb3a233
void BindingData::ReadPackageJSON(const FunctionCallbackInfo<Value>& args) {
CHECK_GE(args.Length(), 1); // path, [is_esm, base, specifier]
CHECK(args[0]->IsString()); // path
@@ -597,6 +633,8 @@ void InitImportMetaPathHelpers(const FunctionCallbackInfo<Value>& args) {
@@ -558,6 +594,8 @@ void InitImportMetaPathHelpers(const FunctionCallbackInfo<Value>& args) {
void BindingData::CreatePerIsolateProperties(IsolateData* isolate_data,
Local<ObjectTemplate> target) {
Isolate* isolate = isolate_data->isolate();
@@ -99,7 +99,7 @@ index 35bfada261258407982d9e24cf7b3e820235c941..ed22da844a61b14b8580cd3d6bb3a233
SetMethod(isolate, target, "readPackageJSON", ReadPackageJSON);
SetMethod(isolate,
target,
@@ -635,6 +673,8 @@ void BindingData::CreatePerContextProperties(Local<Object> target,
@@ -596,6 +634,8 @@ void BindingData::CreatePerContextProperties(Local<Object> target,
void BindingData::RegisterExternalReferences(
ExternalReferenceRegistry* registry) {

View File

@@ -86,10 +86,10 @@ index 0ca643aa74d13f278685d2330b791182b55c15b4..cbcecfba33070b820aca0e2814982160
NODE_DEFINE_CONSTANT(target, ETIMEDOUT);
#endif
diff --git a/src/node_errors.cc b/src/node_errors.cc
index ae8553ee2022d60fea4572976b14ba9cd253aa45..4386a1bc5678e351ce084cd2c47202561619b164 100644
index 238942d45a136facec55ca5a2534e2dc407137e9..36a21b9523351fe2f225ffe7fca184d737640b62 100644
--- a/src/node_errors.cc
+++ b/src/node_errors.cc
@@ -862,10 +862,6 @@ const char* errno_string(int errorno) {
@@ -899,10 +899,6 @@ const char* errno_string(int errorno) {
ERRNO_CASE(ENOBUFS);
#endif
@@ -100,7 +100,7 @@ index ae8553ee2022d60fea4572976b14ba9cd253aa45..4386a1bc5678e351ce084cd2c4720256
#ifdef ENODEV
ERRNO_CASE(ENODEV);
#endif
@@ -904,14 +900,6 @@ const char* errno_string(int errorno) {
@@ -941,14 +937,6 @@ const char* errno_string(int errorno) {
ERRNO_CASE(ENOSPC);
#endif
@@ -115,7 +115,7 @@ index ae8553ee2022d60fea4572976b14ba9cd253aa45..4386a1bc5678e351ce084cd2c4720256
#ifdef ENOSYS
ERRNO_CASE(ENOSYS);
#endif
@@ -994,10 +982,6 @@ const char* errno_string(int errorno) {
@@ -1031,10 +1019,6 @@ const char* errno_string(int errorno) {
ERRNO_CASE(ESTALE);
#endif

View File

@@ -48,7 +48,7 @@ index fe669d40c31a29334b047b9cfee3067f64ef0a7b..9e5de7bbe574add017cd12ee091304d0
static CFunction fast_timing_safe_equal(CFunction::Make(FastTimingSafeEqual));
diff --git a/src/node_buffer.cc b/src/node_buffer.cc
index e39852c8e0392e0a9ae5d4ea58be115416e19233..c94b14741c827a81d69a6f036426a344e563ad72 100644
index b9f0c97938203b4652780a7d707c5e83319330b0..8a5b6b57321c2843a965a7e51b2ebed991a1e424 100644
--- a/src/node_buffer.cc
+++ b/src/node_buffer.cc
@@ -44,6 +44,14 @@
@@ -74,7 +74,7 @@ index e39852c8e0392e0a9ae5d4ea58be115416e19233..c94b14741c827a81d69a6f036426a344
using v8::FunctionCallbackInfo;
using v8::Global;
using v8::HandleScope;
@@ -584,19 +591,24 @@ void SlowCopy(const FunctionCallbackInfo<Value>& args) {
@@ -583,19 +590,24 @@ void SlowCopy(const FunctionCallbackInfo<Value>& args) {
// Assume caller has properly validated args.
uint32_t FastCopy(Local<Value> receiver,
@@ -107,7 +107,7 @@ index e39852c8e0392e0a9ae5d4ea58be115416e19233..c94b14741c827a81d69a6f036426a344
return to_copy;
}
@@ -865,19 +877,17 @@ void Compare(const FunctionCallbackInfo<Value> &args) {
@@ -864,19 +876,17 @@ void Compare(const FunctionCallbackInfo<Value> &args) {
}
int32_t FastCompare(v8::Local<v8::Value>,
@@ -135,7 +135,7 @@ index e39852c8e0392e0a9ae5d4ea58be115416e19233..c94b14741c827a81d69a6f036426a344
}
static v8::CFunction fast_compare(v8::CFunction::Make(FastCompare));
@@ -1149,14 +1159,13 @@ void SlowIndexOfNumber(const FunctionCallbackInfo<Value>& args) {
@@ -1148,14 +1158,13 @@ void SlowIndexOfNumber(const FunctionCallbackInfo<Value>& args) {
}
int32_t FastIndexOfNumber(v8::Local<v8::Value>,
@@ -153,7 +153,7 @@ index e39852c8e0392e0a9ae5d4ea58be115416e19233..c94b14741c827a81d69a6f036426a344
}
static v8::CFunction fast_index_of_number(
@@ -1496,21 +1505,31 @@ void SlowWriteString(const FunctionCallbackInfo<Value>& args) {
@@ -1510,21 +1519,31 @@ void SlowWriteString(const FunctionCallbackInfo<Value>& args) {
template <encoding encoding>
uint32_t FastWriteString(Local<Value> receiver,

View File

@@ -9,10 +9,10 @@ This is already applied in newer versions of Node so we can drop
this patch once we upgrade to v23.
diff --git a/src/api/environment.cc b/src/api/environment.cc
index 0a358735c331767e8eb563a80e9aaccfb544c27b..d7d18d5fcbf008ac131db189a141315af4f6410b 100644
index 79327877b0f34cbafb3efcc21617027d4011f806..8a12475857135bd3e904610b7eb887c397c8e73c 100644
--- a/src/api/environment.cc
+++ b/src/api/environment.cc
@@ -835,7 +835,7 @@ MaybeLocal<Object> InitializePrivateSymbols(Local<Context> context,
@@ -827,7 +827,7 @@ MaybeLocal<Object> InitializePrivateSymbols(Local<Context> context,
Local<Object> private_symbols_object;
if (!private_symbols->NewInstance(context).ToLocal(&private_symbols_object) ||
@@ -21,7 +21,7 @@ index 0a358735c331767e8eb563a80e9aaccfb544c27b..d7d18d5fcbf008ac131db189a141315a
.IsNothing()) {
return MaybeLocal<Object>();
}
@@ -861,7 +861,7 @@ MaybeLocal<Object> InitializePerIsolateSymbols(Local<Context> context,
@@ -853,7 +853,7 @@ MaybeLocal<Object> InitializePerIsolateSymbols(Local<Context> context,
Local<Object> per_isolate_symbols_object;
if (!per_isolate_symbols->NewInstance(context).ToLocal(
&per_isolate_symbols_object) ||

View File

@@ -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 cb37fa080fc8e8d524cfa2758c4a8c2c5652324d..8e227ddd1be50c046a8cf2895a31d607eb7d31de 100644
index fd71ceac65ccef1d2832b45b0b5612877cee22c1..ceac508418f489a8077c1bc85a2feaf85bf60480 100644
--- a/src/api/environment.cc
+++ b/src/api/environment.cc
@@ -316,6 +316,10 @@ Isolate* NewIsolate(Isolate::CreateParams* params,
@@ -308,6 +308,10 @@ Isolate* NewIsolate(Isolate::CreateParams* params,
MultiIsolatePlatform* platform,
const SnapshotData* snapshot_data,
const IsolateSettings& settings) {
@@ -32,7 +32,7 @@ index cb37fa080fc8e8d524cfa2758c4a8c2c5652324d..8e227ddd1be50c046a8cf2895a31d607
Isolate* isolate = Isolate::Allocate();
if (isolate == nullptr) return nullptr;
@@ -359,9 +363,12 @@ Isolate* NewIsolate(ArrayBufferAllocator* allocator,
@@ -351,9 +355,12 @@ Isolate* NewIsolate(ArrayBufferAllocator* allocator,
uv_loop_t* event_loop,
MultiIsolatePlatform* platform,
const EmbedderSnapshotData* snapshot_data,

View File

@@ -0,0 +1,653 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Robo <hop2deep@gmail.com>
Date: Wed, 21 Jan 2026 09:53:15 +0000
Subject: remove obsolete NoArrayBufferZeroFillScope
Replace the scope in favor of the V8 api added in
https://chromium-review.googlesource.com/c/v8/v8/+/5679067
Ports changes from
1) https://github.com/nodejs/node/commit/869ea331f3a8215229290e2e6038956874c382a6
2) https://github.com/nodejs/node/commit/ef9dc0857a73610f5de5dc9f37afd0a927c4c17f
3) partially from https://github.com/nodejs/node/commit/e0a71517fef4ca83f2d40d2d1600022bc82a7f9f
This is needed to remove dependency on the zero_fill_field_
that is exposed to JS
Refs https://github.com/nodejs/node/commit/3cdb1cd437f63dd256ae2ab3b7e9016257326cb4
diff --git a/src/api/environment.cc b/src/api/environment.cc
index 8a12475857135bd3e904610b7eb887c397c8e73c..3702672f4e2c3b1bff9f9f5c66ca251af447826a 100644
--- a/src/api/environment.cc
+++ b/src/api/environment.cc
@@ -107,11 +107,7 @@ MaybeLocal<Value> PrepareStackTraceCallback(Local<Context> context,
}
void* NodeArrayBufferAllocator::Allocate(size_t size) {
- void* ret;
- if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
- ret = allocator_->Allocate(size);
- else
- ret = allocator_->AllocateUninitialized(size);
+ void* ret = allocator_->Allocate(size);
if (ret != nullptr) [[likely]] {
total_mem_usage_.fetch_add(size, std::memory_order_relaxed);
}
diff --git a/src/crypto/crypto_cipher.cc b/src/crypto/crypto_cipher.cc
index c00d3616e08b00b1e0a3a29b2dbb5278e1e14fcc..8939c5e5085d00b098f66074b9ee033f5be55d08 100644
--- a/src/crypto/crypto_cipher.cc
+++ b/src/crypto/crypto_cipher.cc
@@ -20,6 +20,7 @@ using ncrypto::SSLPointer;
using v8::Array;
using v8::ArrayBuffer;
using v8::BackingStore;
+using v8::BackingStoreInitializationMode;
using v8::Context;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
@@ -774,10 +775,10 @@ CipherBase::UpdateResult CipherBase::Update(
return kErrorState;
}
- {
- NoArrayBufferZeroFillScope no_zero_fill_scope(env()->isolate_data());
- *out = ArrayBuffer::NewBackingStore(env()->isolate(), buf_len);
- }
+ *out = ArrayBuffer::NewBackingStore(
+ env()->isolate(),
+ buf_len,
+ BackingStoreInitializationMode::kUninitialized);
buffer = {
.data = reinterpret_cast<const unsigned char*>(data),
@@ -852,11 +853,10 @@ bool CipherBase::Final(std::unique_ptr<BackingStore>* out) {
const int mode = ctx_.getMode();
- {
- NoArrayBufferZeroFillScope no_zero_fill_scope(env()->isolate_data());
- *out = ArrayBuffer::NewBackingStore(
- env()->isolate(), static_cast<size_t>(ctx_.getBlockSize()));
- }
+ *out = ArrayBuffer::NewBackingStore(
+ env()->isolate(),
+ static_cast<size_t>(ctx_.getBlockSize()),
+ BackingStoreInitializationMode::kUninitialized);
if (kind_ == kDecipher &&
Cipher::FromCtx(ctx_).isSupportedAuthenticatedMode()) {
@@ -972,10 +972,10 @@ bool PublicKeyCipher::Cipher(
return false;
}
- {
- NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
- *out = ArrayBuffer::NewBackingStore(env->isolate(), out_len);
- }
+ *out = ArrayBuffer::NewBackingStore(
+ env->isolate(),
+ out_len,
+ BackingStoreInitializationMode::kUninitialized);
if (EVP_PKEY_cipher(
ctx.get(),
diff --git a/src/crypto/crypto_common.cc b/src/crypto/crypto_common.cc
index b81b9005365272217c77e2b9289bd9f877c0e77c..185b1d8fe657b5db64dc92497ca742d69f7a2764 100644
--- a/src/crypto/crypto_common.cc
+++ b/src/crypto/crypto_common.cc
@@ -37,6 +37,7 @@ using ncrypto::X509Pointer;
using ncrypto::X509View;
using v8::ArrayBuffer;
using v8::BackingStore;
+using v8::BackingStoreInitializationMode;
using v8::Context;
using v8::EscapableHandleScope;
using v8::Integer;
@@ -307,11 +308,10 @@ MaybeLocal<Object> ECPointToBuffer(Environment* env,
return MaybeLocal<Object>();
}
- std::unique_ptr<BackingStore> bs;
- {
- NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
- bs = ArrayBuffer::NewBackingStore(env->isolate(), len);
- }
+ std::unique_ptr<BackingStore> bs = ArrayBuffer::NewBackingStore(
+ env->isolate(),
+ len,
+ BackingStoreInitializationMode::kUninitialized);
len = EC_POINT_point2oct(group,
point,
diff --git a/src/crypto/crypto_ec.cc b/src/crypto/crypto_ec.cc
index 2a3107dbbf5c0dfe70c2e105338d186e5620ddbf..f36c84a77313bd57d0a7a902d1a2529636ca1422 100644
--- a/src/crypto/crypto_ec.cc
+++ b/src/crypto/crypto_ec.cc
@@ -29,6 +29,7 @@ using ncrypto::MarkPopErrorOnReturn;
using v8::Array;
using v8::ArrayBuffer;
using v8::BackingStore;
+using v8::BackingStoreInitializationMode;
using v8::Context;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
@@ -201,14 +202,10 @@ void ECDH::ComputeSecret(const FunctionCallbackInfo<Value>& args) {
return;
}
- std::unique_ptr<BackingStore> bs;
- {
- NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
- // NOTE: field_size is in bits
- int field_size = EC_GROUP_get_degree(ecdh->group_);
- size_t out_len = (field_size + 7) / 8;
- bs = ArrayBuffer::NewBackingStore(env->isolate(), out_len);
- }
+ int field_size = EC_GROUP_get_degree(ecdh->group_);
+ size_t out_len = (field_size + 7) / 8;
+ auto bs = ArrayBuffer::NewBackingStore(
+ env->isolate(), out_len, BackingStoreInitializationMode::kUninitialized);
if (!ECDH_compute_key(
bs->Data(), bs->ByteLength(), pub, ecdh->key_.get(), nullptr))
@@ -257,12 +254,10 @@ void ECDH::GetPrivateKey(const FunctionCallbackInfo<Value>& args) {
return THROW_ERR_CRYPTO_OPERATION_FAILED(env,
"Failed to get ECDH private key");
- std::unique_ptr<BackingStore> bs;
- {
- NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
- bs = ArrayBuffer::NewBackingStore(env->isolate(),
- BignumPointer::GetByteCount(b));
- }
+ auto bs = ArrayBuffer::NewBackingStore(
+ env->isolate(),
+ BignumPointer::GetByteCount(b),
+ BackingStoreInitializationMode::kUninitialized);
CHECK_EQ(bs->ByteLength(),
BignumPointer::EncodePaddedInto(
b, static_cast<unsigned char*>(bs->Data()), bs->ByteLength()));
diff --git a/src/crypto/crypto_rsa.cc b/src/crypto/crypto_rsa.cc
index 1f2fccce6ed8f14525557644e0bdd130eedf3337..1099a8f89bb53083f01942ee14fff453d8cdc0af 100644
--- a/src/crypto/crypto_rsa.cc
+++ b/src/crypto/crypto_rsa.cc
@@ -20,6 +20,7 @@ using ncrypto::EVPKeyPointer;
using ncrypto::RSAPointer;
using v8::ArrayBuffer;
using v8::BackingStore;
+using v8::BackingStoreInitializationMode;
using v8::FunctionCallbackInfo;
using v8::Int32;
using v8::JustVoid;
@@ -535,12 +536,10 @@ Maybe<void> GetRsaKeyDetail(Environment* env,
return Nothing<void>();
}
- std::unique_ptr<BackingStore> public_exponent;
- {
- NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
- public_exponent = ArrayBuffer::NewBackingStore(
- env->isolate(), BignumPointer::GetByteCount(e));
- }
+ auto public_exponent = ArrayBuffer::NewBackingStore(
+ env->isolate(),
+ BignumPointer::GetByteCount(e),
+ BackingStoreInitializationMode::kUninitialized);
CHECK_EQ(BignumPointer::EncodePaddedInto(
e,
static_cast<unsigned char*>(public_exponent->Data()),
diff --git a/src/crypto/crypto_sig.cc b/src/crypto/crypto_sig.cc
index 2f6e683e3497d4315259773d09443e5215bff28f..c33e93c34ef32c18e6de6bc03698ed6b851b4aa3 100644
--- a/src/crypto/crypto_sig.cc
+++ b/src/crypto/crypto_sig.cc
@@ -21,6 +21,7 @@ using ncrypto::EVPKeyPointer;
using ncrypto::EVPMDCtxPointer;
using v8::ArrayBuffer;
using v8::BackingStore;
+using v8::BackingStoreInitializationMode;
using v8::Boolean;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
@@ -92,11 +93,8 @@ std::unique_ptr<BackingStore> Node_SignFinal(Environment* env,
return nullptr;
size_t sig_len = pkey.size();
- std::unique_ptr<BackingStore> sig;
- {
- NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
- sig = ArrayBuffer::NewBackingStore(env->isolate(), sig_len);
- }
+ auto sig = ArrayBuffer::NewBackingStore(
+ env->isolate(), sig_len, BackingStoreInitializationMode::kUninitialized);
EVPKeyCtxPointer pkctx = pkey.newCtx();
if (pkctx && EVP_PKEY_sign_init(pkctx.get()) > 0 &&
ApplyRSAOptions(pkey, pkctx.get(), padding, pss_salt_len) &&
@@ -168,11 +166,9 @@ std::unique_ptr<BackingStore> ConvertSignatureToP1363(
if (n == kNoDsaSignature)
return std::move(signature);
- std::unique_ptr<BackingStore> buf;
- {
- NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
- buf = ArrayBuffer::NewBackingStore(env->isolate(), 2 * n);
- }
+ auto buf = ArrayBuffer::NewBackingStore(
+ env->isolate(), 2 * n, BackingStoreInitializationMode::kUninitialized);
+
if (!ExtractP1363(static_cast<unsigned char*>(signature->Data()),
static_cast<unsigned char*>(buf->Data()),
signature->ByteLength(), n))
diff --git a/src/crypto/crypto_tls.cc b/src/crypto/crypto_tls.cc
index a80685790bd29102d99929ff81f866e0aee370f1..24336b86f6f25533a7b668e9f9806a5635e3a398 100644
--- a/src/crypto/crypto_tls.cc
+++ b/src/crypto/crypto_tls.cc
@@ -46,6 +46,7 @@ using v8::Array;
using v8::ArrayBuffer;
using v8::ArrayBufferView;
using v8::BackingStore;
+using v8::BackingStoreInitializationMode;
using v8::Boolean;
using v8::Context;
using v8::DontDelete;
@@ -1087,10 +1088,10 @@ int TLSWrap::DoWrite(WriteWrap* w,
// and copying it when it could just be used.
if (nonempty_count != 1) {
- {
- NoArrayBufferZeroFillScope no_zero_fill_scope(env()->isolate_data());
- bs = ArrayBuffer::NewBackingStore(env()->isolate(), length);
- }
+ bs = ArrayBuffer::NewBackingStore(
+ env()->isolate(),
+ length,
+ BackingStoreInitializationMode::kUninitialized);
size_t offset = 0;
for (i = 0; i < count; i++) {
memcpy(static_cast<char*>(bs->Data()) + offset,
@@ -1107,8 +1108,10 @@ int TLSWrap::DoWrite(WriteWrap* w,
written = SSL_write(ssl_.get(), buf->base, buf->len);
if (written == -1) {
- NoArrayBufferZeroFillScope no_zero_fill_scope(env()->isolate_data());
- bs = ArrayBuffer::NewBackingStore(env()->isolate(), length);
+ bs = ArrayBuffer::NewBackingStore(
+ env()->isolate(),
+ length,
+ BackingStoreInitializationMode::kUninitialized);
memcpy(bs->Data(), buf->base, buf->len);
}
}
@@ -1746,11 +1749,8 @@ void TLSWrap::GetFinished(const FunctionCallbackInfo<Value>& args) {
if (len == 0)
return;
- std::unique_ptr<BackingStore> bs;
- {
- NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
- bs = ArrayBuffer::NewBackingStore(env->isolate(), len);
- }
+ auto bs = ArrayBuffer::NewBackingStore(
+ env->isolate(), len, BackingStoreInitializationMode::kUninitialized);
CHECK_EQ(bs->ByteLength(),
SSL_get_finished(w->ssl_.get(), bs->Data(), bs->ByteLength()));
@@ -1777,11 +1777,8 @@ void TLSWrap::GetPeerFinished(const FunctionCallbackInfo<Value>& args) {
if (len == 0)
return;
- std::unique_ptr<BackingStore> bs;
- {
- NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
- bs = ArrayBuffer::NewBackingStore(env->isolate(), len);
- }
+ auto bs = ArrayBuffer::NewBackingStore(
+ env->isolate(), len, BackingStoreInitializationMode::kUninitialized);
CHECK_EQ(bs->ByteLength(),
SSL_get_peer_finished(w->ssl_.get(), bs->Data(), bs->ByteLength()));
@@ -1806,11 +1803,8 @@ void TLSWrap::GetSession(const FunctionCallbackInfo<Value>& args) {
if (slen <= 0)
return; // Invalid or malformed session.
- std::unique_ptr<BackingStore> bs;
- {
- NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
- bs = ArrayBuffer::NewBackingStore(env->isolate(), slen);
- }
+ auto bs = ArrayBuffer::NewBackingStore(
+ env->isolate(), slen, BackingStoreInitializationMode::kUninitialized);
unsigned char* p = static_cast<unsigned char*>(bs->Data());
CHECK_LT(0, i2d_SSL_SESSION(sess, &p));
@@ -1993,11 +1987,8 @@ void TLSWrap::ExportKeyingMaterial(const FunctionCallbackInfo<Value>& args) {
uint32_t olen = args[0].As<Uint32>()->Value();
Utf8Value label(env->isolate(), args[1]);
- std::unique_ptr<BackingStore> bs;
- {
- NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
- bs = ArrayBuffer::NewBackingStore(env->isolate(), olen);
- }
+ auto bs = ArrayBuffer::NewBackingStore(
+ env->isolate(), olen, BackingStoreInitializationMode::kUninitialized);
ByteSource context;
bool use_context = !args[2]->IsUndefined();
diff --git a/src/crypto/crypto_x509.cc b/src/crypto/crypto_x509.cc
index fd29d17de195017970856ce30d7a9c5785b0b8ee..7fe3d09851d4476fa3f77ea0a0b49e8af13fae4f 100644
--- a/src/crypto/crypto_x509.cc
+++ b/src/crypto/crypto_x509.cc
@@ -28,6 +28,7 @@ using v8::Array;
using v8::ArrayBuffer;
using v8::ArrayBufferView;
using v8::BackingStore;
+using v8::BackingStoreInitializationMode;
using v8::Boolean;
using v8::Context;
using v8::Date;
@@ -683,11 +684,8 @@ MaybeLocal<Object> GetPubKey(Environment* env, OSSL3_CONST RSA* rsa) {
int size = i2d_RSA_PUBKEY(rsa, nullptr);
CHECK_GE(size, 0);
- std::unique_ptr<BackingStore> bs;
- {
- NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
- bs = ArrayBuffer::NewBackingStore(env->isolate(), size);
- }
+ auto bs = ArrayBuffer::NewBackingStore(
+ env->isolate(), size, BackingStoreInitializationMode::kUninitialized);
unsigned char* serialized = reinterpret_cast<unsigned char*>(bs->Data());
CHECK_GE(i2d_RSA_PUBKEY(rsa, &serialized), 0);
diff --git a/src/encoding_binding.cc b/src/encoding_binding.cc
index 5ace688bb7ffc86eedf5aff11ab0ab487ad9440e..31058543a164bb45ba989e8c433994e0857a98b9 100644
--- a/src/encoding_binding.cc
+++ b/src/encoding_binding.cc
@@ -15,6 +15,7 @@ namespace encoding_binding {
using v8::ArrayBuffer;
using v8::BackingStore;
+using v8::BackingStoreInitializationMode;
using v8::Context;
using v8::FunctionCallbackInfo;
using v8::Isolate;
@@ -123,9 +124,8 @@ void BindingData::EncodeUtf8String(const FunctionCallbackInfo<Value>& args) {
Local<ArrayBuffer> ab;
{
- NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
- std::unique_ptr<BackingStore> bs =
- ArrayBuffer::NewBackingStore(isolate, length);
+ std::unique_ptr<BackingStore> bs = ArrayBuffer::NewBackingStore(
+ isolate, length, BackingStoreInitializationMode::kUninitialized);
CHECK(bs);
diff --git a/src/env-inl.h b/src/env-inl.h
index 98e1e1e75bae94038bba0049447ab48b0acfb8cc..fe395bf89f9c1e5bb2dabc8fceda7b9b2b877415 100644
--- a/src/env-inl.h
+++ b/src/env-inl.h
@@ -44,16 +44,6 @@
namespace node {
-NoArrayBufferZeroFillScope::NoArrayBufferZeroFillScope(
- IsolateData* isolate_data)
- : node_allocator_(isolate_data->node_allocator()) {
- if (node_allocator_ != nullptr) node_allocator_->zero_fill_field()[0] = 0;
-}
-
-NoArrayBufferZeroFillScope::~NoArrayBufferZeroFillScope() {
- if (node_allocator_ != nullptr) node_allocator_->zero_fill_field()[0] = 1;
-}
-
inline v8::Isolate* IsolateData::isolate() const {
return isolate_;
}
diff --git a/src/env.cc b/src/env.cc
index 161d577e0ea6a251c83ba1903b1ec9a582a5317c..52713421465c23c959afac1955168294b2048341 100644
--- a/src/env.cc
+++ b/src/env.cc
@@ -39,6 +39,9 @@ namespace node {
using errors::TryCatchScope;
using v8::Array;
+using v8::ArrayBuffer;
+using v8::BackingStore;
+using v8::BackingStoreInitializationMode;
using v8::Boolean;
using v8::Context;
using v8::CppHeap;
@@ -724,9 +727,10 @@ void Environment::add_refs(int64_t diff) {
}
uv_buf_t Environment::allocate_managed_buffer(const size_t suggested_size) {
- NoArrayBufferZeroFillScope no_zero_fill_scope(isolate_data());
- std::unique_ptr<v8::BackingStore> bs =
- v8::ArrayBuffer::NewBackingStore(isolate(), suggested_size);
+ std::unique_ptr<BackingStore> bs = ArrayBuffer::NewBackingStore(
+ isolate(),
+ suggested_size,
+ BackingStoreInitializationMode::kUninitialized);
uv_buf_t buf = uv_buf_init(static_cast<char*>(bs->Data()), bs->ByteLength());
released_allocated_buffers_.emplace(buf.base, std::move(bs));
return buf;
diff --git a/src/env.h b/src/env.h
index c346e3a9c827993036438685d758a734f9ce8c05..28c8df87c8e2f06e2ed8c554260bfdedb860bb4a 100644
--- a/src/env.h
+++ b/src/env.h
@@ -114,19 +114,6 @@ class ModuleWrap;
class Environment;
class Realm;
-// Disables zero-filling for ArrayBuffer allocations in this scope. This is
-// similar to how we implement Buffer.allocUnsafe() in JS land.
-class NoArrayBufferZeroFillScope {
- public:
- inline explicit NoArrayBufferZeroFillScope(IsolateData* isolate_data);
- inline ~NoArrayBufferZeroFillScope();
-
- private:
- NodeArrayBufferAllocator* node_allocator_;
-
- friend class Environment;
-};
-
struct IsolateDataSerializeInfo {
std::vector<SnapshotIndex> primitive_values;
std::vector<PropInfo> template_values;
diff --git a/src/node_buffer.cc b/src/node_buffer.cc
index e844fe6cb33acefd075516e675075421ad5c3cff..06c84eb6ec097e3cb39502116135a7802aed13ce 100644
--- a/src/node_buffer.cc
+++ b/src/node_buffer.cc
@@ -66,6 +66,7 @@ namespace Buffer {
using v8::ArrayBuffer;
using v8::ArrayBufferView;
using v8::BackingStore;
+using v8::BackingStoreInitializationMode;
using v8::Context;
using v8::EscapableHandleScope;
using v8::FunctionCallbackInfo;
@@ -376,9 +377,8 @@ MaybeLocal<Object> New(Environment* env, size_t length) {
Local<ArrayBuffer> ab;
{
- NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
- std::unique_ptr<BackingStore> bs =
- ArrayBuffer::NewBackingStore(isolate, length);
+ std::unique_ptr<BackingStore> bs = ArrayBuffer::NewBackingStore(
+ isolate, length, BackingStoreInitializationMode::kUninitialized);
CHECK(bs);
@@ -417,18 +417,14 @@ MaybeLocal<Object> Copy(Environment* env, const char* data, size_t length) {
return Local<Object>();
}
- Local<ArrayBuffer> ab;
- {
- NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
- std::unique_ptr<BackingStore> bs =
- ArrayBuffer::NewBackingStore(isolate, length);
+ std::unique_ptr<BackingStore> bs = ArrayBuffer::NewBackingStore(
+ isolate, length, BackingStoreInitializationMode::kUninitialized);
- CHECK(bs);
+ CHECK(bs);
- memcpy(bs->Data(), data, length);
+ memcpy(bs->Data(), data, length);
- ab = ArrayBuffer::New(isolate, std::move(bs));
- }
+ Local<ArrayBuffer> ab = ArrayBuffer::New(isolate, std::move(bs));
MaybeLocal<Object> obj =
New(env, ab, 0, ab->ByteLength())
@@ -1440,14 +1436,16 @@ void CreateUnsafeArrayBuffer(const FunctionCallbackInfo<Value>& args) {
Local<ArrayBuffer> buf;
- NodeArrayBufferAllocator* allocator = env->isolate_data()->node_allocator();
// 0-length, or zero-fill flag is set, or building snapshot
if (size == 0 || per_process::cli_options->zero_fill_all_buffers ||
- allocator == nullptr) {
+ env->isolate_data()->is_building_snapshot()) {
buf = ArrayBuffer::New(isolate, size);
} else {
- std::unique_ptr<BackingStore> store =
- ArrayBuffer::NewBackingStore(isolate, size);
+ std::unique_ptr<BackingStore> store = ArrayBuffer::NewBackingStore(
+ isolate,
+ size,
+ BackingStoreInitializationMode::kUninitialized,
+ v8::BackingStoreOnFailureMode::kReturnNull);
if (!store) {
return env->ThrowRangeError("Array buffer allocation failed");
}
diff --git a/src/node_http2.cc b/src/node_http2.cc
index 8237c9b7d325dd925ae8798d7795fcd94eeb13d0..a22cf6c4e33e5cf2d3168ce03dc35af8a9584af7 100644
--- a/src/node_http2.cc
+++ b/src/node_http2.cc
@@ -27,6 +27,7 @@ using v8::Array;
using v8::ArrayBuffer;
using v8::ArrayBufferView;
using v8::BackingStore;
+using v8::BackingStoreInitializationMode;
using v8::Boolean;
using v8::Context;
using v8::EscapableHandleScope;
@@ -298,11 +299,10 @@ Local<Value> Http2Settings::Pack(
size_t count,
const nghttp2_settings_entry* entries) {
EscapableHandleScope scope(env->isolate());
- std::unique_ptr<BackingStore> bs;
- {
- NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
- bs = ArrayBuffer::NewBackingStore(env->isolate(), count * 6);
- }
+ std::unique_ptr<BackingStore> bs = ArrayBuffer::NewBackingStore(
+ env->isolate(),
+ count * 6,
+ BackingStoreInitializationMode::kUninitialized);
if (nghttp2_pack_settings_payload(static_cast<uint8_t*>(bs->Data()),
bs->ByteLength(),
entries,
@@ -468,13 +468,11 @@ Origins::Origins(
return;
}
- {
- NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
- bs_ = ArrayBuffer::NewBackingStore(env->isolate(),
- alignof(nghttp2_origin_entry) - 1 +
- count_ * sizeof(nghttp2_origin_entry) +
- origin_string_len);
- }
+ bs_ = ArrayBuffer::NewBackingStore(
+ env->isolate(),
+ alignof(nghttp2_origin_entry) - 1 +
+ count_ * sizeof(nghttp2_origin_entry) + origin_string_len,
+ BackingStoreInitializationMode::kUninitialized);
// Make sure the start address is aligned appropriately for an nghttp2_nv*.
char* start = nbytes::AlignUp(static_cast<char*>(bs_->Data()),
@@ -2120,12 +2118,10 @@ void Http2Session::OnStreamRead(ssize_t nread, const uv_buf_t& buf_) {
// happen, we concatenate the data we received with the already-stored
// pending input data, slicing off the already processed part.
size_t pending_len = stream_buf_.len - stream_buf_offset_;
- std::unique_ptr<BackingStore> new_bs;
- {
- NoArrayBufferZeroFillScope no_zero_fill_scope(env()->isolate_data());
- new_bs = ArrayBuffer::NewBackingStore(env()->isolate(),
- pending_len + nread);
- }
+ std::unique_ptr<BackingStore> new_bs = ArrayBuffer::NewBackingStore(
+ env()->isolate(),
+ pending_len + nread,
+ BackingStoreInitializationMode::kUninitialized);
memcpy(static_cast<char*>(new_bs->Data()),
stream_buf_.base + stream_buf_offset_,
pending_len);
diff --git a/src/node_internals.h b/src/node_internals.h
index 12ea72b61b0a5e194207bb369dfed4b8667107cb..18844e18a32d6b07e62481138fa2342765643484 100644
--- a/src/node_internals.h
+++ b/src/node_internals.h
@@ -121,8 +121,6 @@ v8::MaybeLocal<v8::Object> InitializePrivateSymbols(
class NodeArrayBufferAllocator : public ArrayBufferAllocator {
public:
- inline uint32_t* zero_fill_field() { return &zero_fill_field_; }
-
void* Allocate(size_t size) override; // Defined in src/node.cc
void* AllocateUninitialized(size_t size) override;
void Free(void* data, size_t size) override;
@@ -139,7 +137,6 @@ class NodeArrayBufferAllocator : public ArrayBufferAllocator {
}
private:
- uint32_t zero_fill_field_ = 1; // Boolean but exposed as uint32 to JS land.
std::atomic<size_t> total_mem_usage_ {0};
// Delegate to V8's allocator for compatibility with the V8 memory cage.
diff --git a/src/stream_base.cc b/src/stream_base.cc
index fc81108120f0066f2d5dabedc74e22cb6c84d8e4..0bf2642599ee91e2d2aa20d6d066c80b3026ecc5 100644
--- a/src/stream_base.cc
+++ b/src/stream_base.cc
@@ -19,6 +19,7 @@ namespace node {
using v8::Array;
using v8::ArrayBuffer;
using v8::BackingStore;
+using v8::BackingStoreInitializationMode;
using v8::ConstructorBehavior;
using v8::Context;
using v8::DontDelete;
@@ -243,8 +244,8 @@ int StreamBase::Writev(const FunctionCallbackInfo<Value>& args) {
std::unique_ptr<BackingStore> bs;
if (storage_size > 0) {
- NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
- bs = ArrayBuffer::NewBackingStore(isolate, storage_size);
+ bs = ArrayBuffer::NewBackingStore(
+ isolate, storage_size, BackingStoreInitializationMode::kUninitialized);
}
offset = 0;
@@ -398,14 +399,14 @@ int StreamBase::WriteString(const FunctionCallbackInfo<Value>& args) {
if (try_write) {
// Copy partial data
- NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
- bs = ArrayBuffer::NewBackingStore(isolate, buf.len);
+ bs = ArrayBuffer::NewBackingStore(
+ isolate, buf.len, BackingStoreInitializationMode::kUninitialized);
memcpy(bs->Data(), buf.base, buf.len);
data_size = buf.len;
} else {
// Write it
- NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
- bs = ArrayBuffer::NewBackingStore(isolate, storage_size);
+ bs = ArrayBuffer::NewBackingStore(
+ isolate, storage_size, BackingStoreInitializationMode::kUninitialized);
data_size = StringBytes::Write(isolate,
static_cast<char*>(bs->Data()),
storage_size,

View File

@@ -0,0 +1,74 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Joyee Cheung <joyeec9h3@gmail.com>
Date: Thu, 20 Nov 2025 13:50:28 +0900
Subject: src: handle DER decoding errors from system certificates
When decoding certificates from the system store, it's not actually
guaranteed to succeed. In case the system returns a certificate
that cannot be decoded (might be related to SSL implementation issues),
skip them.
diff --git a/src/crypto/crypto_context.cc b/src/crypto/crypto_context.cc
index 0c6b12f8e17b4a7e86ebc836a4e1cc77333f211a..dacf10c3c2e663b03a251c86d69276d0be0dff9d 100644
--- a/src/crypto/crypto_context.cc
+++ b/src/crypto/crypto_context.cc
@@ -505,7 +505,11 @@ void ReadMacOSKeychainCertificates(
CFRelease(search);
if (ortn) {
- fprintf(stderr, "ERROR: SecItemCopyMatching failed %d\n", ortn);
+ per_process::Debug(DebugCategory::CRYPTO,
+ "Cannot read certificates from system because "
+ "SecItemCopyMatching failed %d\n",
+ ortn);
+ return;
}
CFIndex count = CFArrayGetCount(curr_anchors);
@@ -516,7 +520,9 @@ void ReadMacOSKeychainCertificates(
CFDataRef der_data = SecCertificateCopyData(cert_ref);
if (!der_data) {
- fprintf(stderr, "ERROR: SecCertificateCopyData failed\n");
+ per_process::Debug(DebugCategory::CRYPTO,
+ "Skipping read of a system certificate "
+ "because SecCertificateCopyData failed\n");
continue;
}
auto data_buffer_pointer = CFDataGetBytePtr(der_data);
@@ -524,9 +530,19 @@ void ReadMacOSKeychainCertificates(
X509* cert =
d2i_X509(nullptr, &data_buffer_pointer, CFDataGetLength(der_data));
CFRelease(der_data);
+
+ if (cert == nullptr) {
+ per_process::Debug(DebugCategory::CRYPTO,
+ "Skipping read of a system certificate "
+ "because decoding failed\n");
+ continue;
+ }
+
bool is_valid = IsCertificateTrustedForPolicy(cert, cert_ref);
if (is_valid) {
system_root_certificates_X509->emplace_back(cert);
+ } else {
+ X509_free(cert);
}
}
CFRelease(curr_anchors);
@@ -636,7 +652,14 @@ void GatherCertsForLocation(std::vector<X509*>* vector,
reinterpret_cast<const unsigned char*>(cert_from_store->pbCertEncoded);
const size_t cert_size = cert_from_store->cbCertEncoded;
- vector->emplace_back(d2i_X509(nullptr, &cert_data, cert_size));
+ X509* x509 = d2i_X509(nullptr, &cert_data, cert_size);
+ if (x509 == nullptr) {
+ per_process::Debug(DebugCategory::CRYPTO,
+ "Skipping read of a system certificate "
+ "because decoding failed\n");
+ } else {
+ vector->emplace_back(x509);
+ }
}
}

View File

@@ -0,0 +1,276 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: James M Snell <jasnell@gmail.com>
Date: Sun, 18 May 2025 10:46:30 -0700
Subject: src: prepare for v8 sandboxing
PR-URL: https://github.com/nodejs/node/pull/58376
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
diff --git a/src/crypto/crypto_dh.cc b/src/crypto/crypto_dh.cc
index f23cedf4f2449d8edc9a8de1b70332e75d693cdd..5ac2b1a83688fe99b13c37bf375ca6e22497dc18 100644
--- a/src/crypto/crypto_dh.cc
+++ b/src/crypto/crypto_dh.cc
@@ -22,6 +22,8 @@ using ncrypto::DHPointer;
using ncrypto::EVPKeyCtxPointer;
using ncrypto::EVPKeyPointer;
using v8::ArrayBuffer;
+using v8::BackingStoreInitializationMode;
+using v8::BackingStoreOnFailureMode;
using v8::ConstructorBehavior;
using v8::Context;
using v8::DontDelete;
@@ -55,12 +57,27 @@ void DiffieHellman::MemoryInfo(MemoryTracker* tracker) const {
namespace {
MaybeLocal<Value> DataPointerToBuffer(Environment* env, DataPointer&& data) {
+#ifdef V8_ENABLE_SANDBOX
+ auto backing = ArrayBuffer::NewBackingStore(
+ env->isolate(),
+ data.size(),
+ BackingStoreInitializationMode::kUninitialized,
+ BackingStoreOnFailureMode::kReturnNull);
+ if (!backing) {
+ THROW_ERR_MEMORY_ALLOCATION_FAILED(env);
+ return MaybeLocal<Value>();
+ }
+ if (data.size() > 0) {
+ memcpy(backing->Data(), data.get(), data.size());
+ }
+#else
auto backing = ArrayBuffer::NewBackingStore(
data.get(),
data.size(),
[](void* data, size_t len, void* ptr) { DataPointer free_me(data, len); },
nullptr);
data.release();
+#endif // V8_ENABLE_SANDBOX
auto ab = ArrayBuffer::New(env->isolate(), std::move(backing));
return Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local<Value>());
diff --git a/src/crypto/crypto_util.cc b/src/crypto/crypto_util.cc
index eab18ab9888e2f7c0757fefab80505d8c99dc742..7ecf810ea0f4106c7c44593dae1b0a3cf0673380 100644
--- a/src/crypto/crypto_util.cc
+++ b/src/crypto/crypto_util.cc
@@ -37,6 +37,8 @@ using ncrypto::SSLCtxPointer;
using ncrypto::SSLPointer;
using v8::ArrayBuffer;
using v8::BackingStore;
+using v8::BackingStoreInitializationMode;
+using v8::BackingStoreOnFailureMode;
using v8::BigInt;
using v8::Context;
using v8::Exception;
@@ -359,34 +361,29 @@ ByteSource& ByteSource::operator=(ByteSource&& other) noexcept {
return *this;
}
-std::unique_ptr<BackingStore> ByteSource::ReleaseToBackingStore(Environment* env) {
+std::unique_ptr<BackingStore> ByteSource::ReleaseToBackingStore(
+ Environment* env) {
// It's ok for allocated_data_ to be nullptr but
// only if size_ is zero.
CHECK_IMPLIES(size_ > 0, allocated_data_ != nullptr);
-#if defined(V8_ENABLE_SANDBOX)
- // When V8 sandboxed pointers are enabled, we have to copy into the memory
- // cage. We still want to ensure we erase the data on free though, so
- // provide a custom deleter that calls OPENSSL_cleanse.
- if (!size())
- return ArrayBuffer::NewBackingStore(env->isolate(), 0);
- std::unique_ptr<ArrayBuffer::Allocator> allocator(ArrayBuffer::Allocator::NewDefaultAllocator());
- void* v8_data = allocator->Allocate(size());
- CHECK(v8_data);
- memcpy(v8_data, allocated_data_, size());
- OPENSSL_clear_free(allocated_data_, size());
+#ifdef V8_ENABLE_SANDBOX
+ // If the v8 sandbox is enabled, then all array buffers must be allocated
+ // via the isolate. External buffers are not allowed. So, instead of wrapping
+ // the allocated data we'll copy it instead.
+
+ // TODO(@jasnell): It would be nice to use an abstracted utility to do this
+ // branch instead of duplicating the V8_ENABLE_SANDBOX check each time.
std::unique_ptr<BackingStore> ptr = ArrayBuffer::NewBackingStore(
- v8_data,
+ env->isolate(),
size(),
- [](void* data, size_t length, void*) {
- OPENSSL_cleanse(data, length);
- std::unique_ptr<ArrayBuffer::Allocator> allocator(ArrayBuffer::Allocator::NewDefaultAllocator());
- allocator->Free(data, length);
- }, nullptr);
- CHECK(ptr);
- allocated_data_ = nullptr;
- data_ = nullptr;
- size_ = 0;
- return ptr;
+ BackingStoreInitializationMode::kUninitialized,
+ BackingStoreOnFailureMode::kReturnNull);
+ if (!ptr) {
+ THROW_ERR_MEMORY_ALLOCATION_FAILED(env);
+ return nullptr;
+ }
+ memcpy(ptr->Data(), allocated_data_, size());
+ OPENSSL_clear_free(allocated_data_, size_);
#else
std::unique_ptr<BackingStore> ptr = ArrayBuffer::NewBackingStore(
allocated_data_,
@@ -394,12 +391,12 @@ std::unique_ptr<BackingStore> ByteSource::ReleaseToBackingStore(Environment* env
[](void* data, size_t length, void* deleter_data) {
OPENSSL_clear_free(deleter_data, length);
}, allocated_data_);
+#endif // V8_ENABLE_SANDBOX
CHECK(ptr);
allocated_data_ = nullptr;
data_ = nullptr;
size_ = 0;
return ptr;
-#endif // defined(V8_ENABLE_SANDBOX)
}
Local<ArrayBuffer> ByteSource::ToArrayBuffer(Environment* env) {
@@ -711,8 +708,19 @@ void SecureBuffer(const FunctionCallbackInfo<Value>& args) {
}
#else
void SecureBuffer(const FunctionCallbackInfo<Value>& args) {
- CHECK(args[0]->IsUint32());
Environment* env = Environment::GetCurrent(args);
+#ifdef V8_ENABLE_SANDBOX
+ // The v8 sandbox is enabled, so we cannot use the secure heap because
+ // the sandbox requires that all array buffers be allocated via the isolate.
+ // That is fundamentally incompatible with the secure heap which allocates
+ // in openssl's secure heap area. Instead we'll just throw an error here.
+ //
+ // That said, we really shouldn't get here in the first place since the
+ // option to enable the secure heap is only available when the sandbox
+ // is disabled.
+ UNREACHABLE();
+#else
+ CHECK(args[0]->IsUint32());
uint32_t len = args[0].As<Uint32>()->Value();
void* data = OPENSSL_malloc(len);
if (data == nullptr) {
@@ -730,6 +738,7 @@ void SecureBuffer(const FunctionCallbackInfo<Value>& args) {
data);
Local<ArrayBuffer> buffer = ArrayBuffer::New(env->isolate(), store);
args.GetReturnValue().Set(Uint8Array::New(buffer, 0, len));
+#endif // V8_ENABLE_SANDBOX
}
#endif // defined(V8_ENABLE_SANDBOX)
diff --git a/src/crypto/crypto_x509.cc b/src/crypto/crypto_x509.cc
index 7fe3d09851d4476fa3f77ea0a0b49e8af13fae4f..b60ad6b1cdb0b923ba2de1b7205ed5ce07612b81 100644
--- a/src/crypto/crypto_x509.cc
+++ b/src/crypto/crypto_x509.cc
@@ -29,6 +29,7 @@ using v8::ArrayBuffer;
using v8::ArrayBufferView;
using v8::BackingStore;
using v8::BackingStoreInitializationMode;
+using v8::BackingStoreOnFailureMode;
using v8::Boolean;
using v8::Context;
using v8::Date;
@@ -168,18 +169,20 @@ MaybeLocal<Value> ToV8Value(Local<Context> context, const BIOPointer& bio) {
MaybeLocal<Value> ToBuffer(Environment* env, BIOPointer* bio) {
if (bio == nullptr || !*bio) return {};
BUF_MEM* mem = *bio;
-#if defined(V8_ENABLE_SANDBOX)
- std::unique_ptr<ArrayBuffer::Allocator> allocator(ArrayBuffer::Allocator::NewDefaultAllocator());
- void* v8_data = allocator->Allocate(mem->length);
- CHECK(v8_data);
- memcpy(v8_data, mem->data, mem->length);
- std::unique_ptr<v8::BackingStore> backing = ArrayBuffer::NewBackingStore(
- v8_data,
+#ifdef V8_ENABLE_SANDBOX
+ // If the v8 sandbox is enabled, then all array buffers must be allocated
+ // via the isolate. External buffers are not allowed. So, instead of wrapping
+ // the BIOPointer we'll copy it instead.
+ auto backing = ArrayBuffer::NewBackingStore(
+ env->isolate(),
mem->length,
- [](void* data, size_t length, void*) {
- std::unique_ptr<ArrayBuffer::Allocator> allocator(ArrayBuffer::Allocator::NewDefaultAllocator());
- allocator->Free(data, length);
- }, nullptr);
+ BackingStoreInitializationMode::kUninitialized,
+ BackingStoreOnFailureMode::kReturnNull);
+ if (!backing) {
+ THROW_ERR_MEMORY_ALLOCATION_FAILED(env);
+ return MaybeLocal<Value>();
+ }
+ memcpy(backing->Data(), mem->data, mem->length);
#else
auto backing = ArrayBuffer::NewBackingStore(
mem->data,
@@ -188,8 +191,7 @@ MaybeLocal<Value> ToBuffer(Environment* env, BIOPointer* bio) {
BIOPointer free_me(static_cast<BIO*>(data));
},
bio->release());
-#endif
-
+#endif // V8_ENABLE_SANDBOX
auto ab = ArrayBuffer::New(env->isolate(), std::move(backing));
Local<Value> ret;
if (!Buffer::New(env, ab, 0, ab->ByteLength()).ToLocal(&ret)) return {};
diff --git a/src/js_native_api_v8.cc b/src/js_native_api_v8.cc
index 413db3ed9b88d7b7fb2ac6dd1153dade9ff830fd..6da93b8569a34841e846c320ec0a6ca7f1ea0da6 100644
--- a/src/js_native_api_v8.cc
+++ b/src/js_native_api_v8.cc
@@ -114,7 +114,7 @@ napi_status NewExternalString(napi_env env,
CHECK_NEW_STRING_ARGS(env, str, length, result);
napi_status status;
-#if defined(V8_ENABLE_SANDBOX)
+#ifdef V8_ENABLE_SANDBOX
status = create_api(env, str, length, result);
if (status == napi_ok) {
if (copied != nullptr) {
diff --git a/src/node_api.cc b/src/node_api.cc
index 2769997f0ede0e921fcb8826942609e497e5f9cb..d9b17780f6143f1c3f8488a20144376963e43fbc 100644
--- a/src/node_api.cc
+++ b/src/node_api.cc
@@ -1056,7 +1056,7 @@ napi_create_external_buffer(napi_env env,
NAPI_PREAMBLE(env);
CHECK_ARG(env, result);
-#if defined(V8_ENABLE_SANDBOX)
+#ifdef V8_ENABLE_SANDBOX
return napi_set_last_error(env, napi_no_external_buffers_allowed);
#else
v8::Isolate* isolate = env->isolate;
diff --git a/src/node_options.cc b/src/node_options.cc
index e93e8684e518b30a2514768a269be6d32d1f5b94..547cda780376f578b0f78eb9158dc14a3faf874d 100644
--- a/src/node_options.cc
+++ b/src/node_options.cc
@@ -83,6 +83,8 @@ void PerProcessOptions::CheckOptions(std::vector<std::string>* errors,
}
// Any value less than 2 disables use of the secure heap.
+#ifndef V8_ENABLE_SANDBOX
+ // The secure heap is not supported when V8_ENABLE_SANDBOX is enabled.
if (secure_heap >= 2) {
if ((secure_heap & (secure_heap - 1)) != 0)
errors->push_back("--secure-heap must be a power of 2");
@@ -95,6 +97,7 @@ void PerProcessOptions::CheckOptions(std::vector<std::string>* errors,
if ((secure_heap_min & (secure_heap_min - 1)) != 0)
errors->push_back("--secure-heap-min must be a power of 2");
}
+#endif // V8_ENABLE_SANDBOX
#endif // HAVE_OPENSSL
if (use_largepages != "off" &&
@@ -1243,6 +1246,7 @@ PerProcessOptionsParser::PerProcessOptionsParser(
"force FIPS crypto (cannot be disabled)",
&PerProcessOptions::force_fips_crypto,
kAllowedInEnvvar);
+#ifndef V8_ENABLE_SANDBOX
AddOption("--secure-heap",
"total size of the OpenSSL secure heap",
&PerProcessOptions::secure_heap,
@@ -1251,6 +1255,7 @@ PerProcessOptionsParser::PerProcessOptionsParser(
"minimum allocation size from the OpenSSL secure heap",
&PerProcessOptions::secure_heap_min,
kAllowedInEnvvar);
+#endif // V8_ENABLE_SANDBOX
#endif // HAVE_OPENSSL
#if OPENSSL_VERSION_MAJOR >= 3
AddOption("--openssl-legacy-provider",

View File

@@ -10,10 +10,10 @@ Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
Reviewed-By: James M Snell <jasnell@gmail.com>
diff --git a/src/api/environment.cc b/src/api/environment.cc
index 82f53bba29613de212f64be440ca20d7c630fddf..0a358735c331767e8eb563a80e9aaccfb544c27b 100644
index 33827edce63c9fe08b52aea59571391a83853443..79327877b0f34cbafb3efcc21617027d4011f806 100644
--- a/src/api/environment.cc
+++ b/src/api/environment.cc
@@ -886,7 +886,7 @@ Maybe<void> InitializePrimordials(Local<Context> context,
@@ -878,7 +878,7 @@ Maybe<void> InitializePrimordials(Local<Context> context,
CHECK(!exports->Has(context, primordials_string).FromJust());
Local<Object> primordials = Object::New(isolate);
@@ -51,10 +51,10 @@ index 7b2efa49468c0bed2f5935552addd3ab37d0a50b..413db3ed9b88d7b7fb2ac6dd1153dade
return GET_RETURN_STATUS(env);
}
diff --git a/src/node_buffer.cc b/src/node_buffer.cc
index c94b14741c827a81d69a6f036426a344e563ad72..15129e4455fdc8792f21511a04d534ba3a4ebb5f 100644
index 8a5b6b57321c2843a965a7e51b2ebed991a1e424..e844fe6cb33acefd075516e675075421ad5c3cff 100644
--- a/src/node_buffer.cc
+++ b/src/node_buffer.cc
@@ -284,8 +284,9 @@ MaybeLocal<Uint8Array> New(Environment* env,
@@ -283,8 +283,9 @@ MaybeLocal<Uint8Array> New(Environment* env,
size_t length) {
CHECK(!env->buffer_prototype_object().IsEmpty());
Local<Uint8Array> ui = Uint8Array::New(ab, byte_offset, length);

View File

@@ -136,10 +136,10 @@ index 75be21c9e8b413f522240a906da06d26c44d5b71..e94c2b5f2cf7cac413cd5cb782fa1cca
std::make_error_code(std::errc::file_exists),
"cp",
diff --git a/src/node_modules.cc b/src/node_modules.cc
index 14f2a35f87e8c2fa17898147d7247cc00c066f35..871282c6f8780ee0bca1e7230c0c2d83fd0c98c0 100644
index fa04b4a8cdd02a2cad1eaf2e5a848b951d1b1150..947513d5b91e8c13478b25d80a1157edbcd64b64 100644
--- a/src/node_modules.cc
+++ b/src/node_modules.cc
@@ -360,12 +360,13 @@ const BindingData::PackageConfig* BindingData::TraverseParent(
@@ -327,22 +327,24 @@ const BindingData::PackageConfig* BindingData::TraverseParent(
// Stop the search when the process doesn't have permissions
// to walk upwards
@@ -158,10 +158,6 @@ index 14f2a35f87e8c2fa17898147d7247cc00c066f35..871282c6f8780ee0bca1e7230c0c2d83
+ }
}
// If current path is outside the resources path, bail.
@@ -375,13 +376,14 @@ const BindingData::PackageConfig* BindingData::TraverseParent(
}
// Check if the path ends with `/node_modules`
- if (current_path.generic_string().ends_with("/node_modules")) {
+ if (current_path.filename() == "node_modules") {
@@ -176,7 +172,7 @@ index 14f2a35f87e8c2fa17898147d7247cc00c066f35..871282c6f8780ee0bca1e7230c0c2d83
if (package_json != nullptr) {
return package_json;
}
@@ -403,20 +405,12 @@ void BindingData::GetNearestParentPackageJSONType(
@@ -364,20 +366,12 @@ void BindingData::GetNearestParentPackageJSONType(
ToNamespacedPath(realm->env(), &path_value);

View File

@@ -6,63 +6,6 @@ Subject: support V8 sandboxed pointers
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/src/api/environment.cc b/src/api/environment.cc
index fd71ceac65ccef1d2832b45b0b5612877cee22c1..cb37fa080fc8e8d524cfa2758c4a8c2c5652324d 100644
--- a/src/api/environment.cc
+++ b/src/api/environment.cc
@@ -106,6 +106,14 @@ MaybeLocal<Value> PrepareStackTraceCallback(Local<Context> context,
return result;
}
+NodeArrayBufferAllocator::NodeArrayBufferAllocator() {
+ zero_fill_field_ = static_cast<uint32_t*>(allocator_->Allocate(sizeof(*zero_fill_field_)));
+}
+
+NodeArrayBufferAllocator::~NodeArrayBufferAllocator() {
+ allocator_->Free(zero_fill_field_, sizeof(*zero_fill_field_));
+}
+
void* NodeArrayBufferAllocator::Allocate(size_t size) {
void* ret;
if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
diff --git a/src/crypto/crypto_dh.cc b/src/crypto/crypto_dh.cc
index f23cedf4f2449d8edc9a8de1b70332e75d693cdd..976653dd1e9363e046788fc3419a9b649ceb2ea4 100644
--- a/src/crypto/crypto_dh.cc
+++ b/src/crypto/crypto_dh.cc
@@ -55,13 +55,32 @@ void DiffieHellman::MemoryInfo(MemoryTracker* tracker) const {
namespace {
MaybeLocal<Value> DataPointerToBuffer(Environment* env, DataPointer&& data) {
+#if defined(V8_ENABLE_SANDBOX)
+ std::unique_ptr<v8::BackingStore> backing;
+ if (data.size() > 0) {
+ std::unique_ptr<ArrayBuffer::Allocator> allocator(ArrayBuffer::Allocator::NewDefaultAllocator());
+ void* v8_data = allocator->Allocate(data.size());
+ CHECK(v8_data);
+ memcpy(v8_data, data.get(), data.size());
+ backing = ArrayBuffer::NewBackingStore(
+ v8_data,
+ data.size(),
+ [](void* data, size_t length, void*) {
+ std::unique_ptr<ArrayBuffer::Allocator> allocator(ArrayBuffer::Allocator::NewDefaultAllocator());
+ allocator->Free(data, length);
+ }, nullptr);
+ } else {
+ NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
+ backing = v8::ArrayBuffer::NewBackingStore(env->isolate(), data.size());
+ }
+#else
auto backing = ArrayBuffer::NewBackingStore(
data.get(),
data.size(),
[](void* data, size_t len, void* ptr) { DataPointer free_me(data, len); },
nullptr);
data.release();
-
+#endif
auto ab = ArrayBuffer::New(env->isolate(), std::move(backing));
return Buffer::New(env, ab, 0, ab->ByteLength()).FromMaybe(Local<Value>());
}
diff --git a/src/crypto/crypto_util.cc b/src/crypto/crypto_util.cc
index 4505786745c54a529f904d5e7813a86204e0a78b..eab18ab9888e2f7c0757fefab80505d8c99dc742 100644
--- a/src/crypto/crypto_util.cc
@@ -188,6 +131,28 @@ index f616223cfb0f6e10f7cf57ada9704316bde2797e..eb6dad44a49d997097c8fb5009eeb60a
auto ab = ArrayBuffer::New(env->isolate(), std::move(backing));
Local<Value> ret;
if (!Buffer::New(env, ab, 0, ab->ByteLength()).ToLocal(&ret)) return {};
diff --git a/src/node_buffer.cc b/src/node_buffer.cc
index 357dc5f6d1c1c2d3756a94c1326b0502403e1eaf..b9f0c97938203b4652780a7d707c5e83319330b0 100644
--- a/src/node_buffer.cc
+++ b/src/node_buffer.cc
@@ -1412,7 +1412,7 @@ inline size_t CheckNumberToSize(Local<Value> number) {
CHECK(value >= 0 && value < maxSize);
size_t size = static_cast<size_t>(value);
#ifdef V8_ENABLE_SANDBOX
- CHECK_LE(size, kMaxSafeBufferSizeForSandbox);
+ CHECK_LE(size, v8::internal::kMaxSafeBufferSizeForSandbox);
#endif
return size;
}
@@ -1437,7 +1437,7 @@ void CreateUnsafeArrayBuffer(const FunctionCallbackInfo<Value>& args) {
buf = ArrayBuffer::New(isolate, size);
} else {
std::unique_ptr<BackingStore> store =
- ArrayBuffer::NewBackingStoreForNodeLTS(isolate, size);
+ ArrayBuffer::NewBackingStore(isolate, size);
if (!store) {
return env->ThrowRangeError("Array buffer allocation failed");
}
diff --git a/src/node_i18n.cc b/src/node_i18n.cc
index 6be3920632b25db450025ebab6a2636e4811cdbe..b49916d2b5fc5e58cf3fb67329430fd3df8fb813 100644
--- a/src/node_i18n.cc
@@ -228,30 +193,6 @@ index 6be3920632b25db450025ebab6a2636e4811cdbe..b49916d2b5fc5e58cf3fb67329430fd3
}
constexpr const char* EncodingName(const enum encoding encoding) {
diff --git a/src/node_internals.h b/src/node_internals.h
index 12ea72b61b0a5e194207bb369dfed4b8667107cb..64442215714a98f648971e517ddd9c77e38fe3f2 100644
--- a/src/node_internals.h
+++ b/src/node_internals.h
@@ -121,7 +121,9 @@ v8::MaybeLocal<v8::Object> InitializePrivateSymbols(
class NodeArrayBufferAllocator : public ArrayBufferAllocator {
public:
- inline uint32_t* zero_fill_field() { return &zero_fill_field_; }
+ NodeArrayBufferAllocator();
+ ~NodeArrayBufferAllocator() override;
+ inline uint32_t* zero_fill_field() { return zero_fill_field_; }
void* Allocate(size_t size) override; // Defined in src/node.cc
void* AllocateUninitialized(size_t size) override;
@@ -139,7 +141,7 @@ class NodeArrayBufferAllocator : public ArrayBufferAllocator {
}
private:
- uint32_t zero_fill_field_ = 1; // Boolean but exposed as uint32 to JS land.
+ uint32_t* zero_fill_field_ = nullptr; // Boolean but exposed as uint32 to JS land.
std::atomic<size_t> total_mem_usage_ {0};
// Delegate to V8's allocator for compatibility with the V8 memory cage.
diff --git a/src/node_serdes.cc b/src/node_serdes.cc
index c55a2e28066147ae5ca5def10ec76ccc03c634b4..c54183c72944989219b6437c9e571a3f7f3f8dd5 100644
--- a/src/node_serdes.cc

View File

@@ -0,0 +1,33 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shelley Vohr <shelley.vohr@gmail.com>
Date: Tue, 4 Nov 2025 21:20:26 +0100
Subject: test: correct conditional secure heap flags test
PR-URL: https://github.com/nodejs/node/pull/60385
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
(cherry picked from commit 53c4a39fec941e04150554fdd3e654b48f2e1b31)
diff --git a/test/parallel/test-process-env-allowed-flags-are-documented.js b/test/parallel/test-process-env-allowed-flags-are-documented.js
index afd43cfffe638f4f084f1c36949068e7239eadc3..c70e073bab888c349e8f5c691f5679a3796c896c 100644
--- a/test/parallel/test-process-env-allowed-flags-are-documented.js
+++ b/test/parallel/test-process-env-allowed-flags-are-documented.js
@@ -49,6 +49,8 @@ if (!hasOpenSSL3) {
documented.delete('--openssl-shared-config');
}
+const isV8Sandboxed = process.config.variables.v8_enable_sandbox;
+
// Filter out options that are conditionally present.
const conditionalOpts = [
{
@@ -74,6 +76,9 @@ const conditionalOpts = [
}, {
include: process.features.inspector,
filter: (opt) => opt.startsWith('--inspect') || opt === '--debug-port'
+ }, {
+ include: !isV8Sandboxed,
+ filter: (opt) => ['--secure-heap', '--secure-heap-min'].includes(opt)
},
];
documented.forEach((opt) => {

View File

@@ -1,2 +1,5 @@
chore_allow_customizing_microtask_policy_per_context.patch
turboshaft_avoid_introducing_too_many_variables.patch
runtime_setprototypeproperties_handling_of.patch
runtime_correcting_setprototypeproperties.patch
reduce_stack_memory_consumption_in_bytecodegenerator.patch

View File

@@ -0,0 +1,263 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jakob Kummerow <jkummerow@chromium.org>
Date: Fri, 21 Nov 2025 11:52:15 +0100
Subject: Reduce stack memory consumption in BytecodeGenerator
Using a SmallVector with 64 stack-allocated entries is not great
for functions that can be used in deep recursions, so this patch
replaces that with a ZoneVector.
By allocating any backing store only when it's actually needed,
and presizing that initial backing store when that happens, this
should have similar performance while using a lot less stack space,
allowing us to compile more deeply nested expressions.
For the highly artificial example of a function full of nested
empty blocks `function f() {{{{{...}}}}}`, this increases the max
nesting level from around 670 to around 2600. With more aggressive
inlining in official builds, it can have similar effects on patterns
that don't even call `VisitStatements()` recursively.
Bug: 429332174
Change-Id: Id11e15ba0fd9bc39efa68bf83e1181fe0e7274a7
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/7180480
Reviewed-by: Raphael Herouart <rherouart@chromium.org>
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#103870}
diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc
index 63400abcc7ca0bd5369d566dd37e2ae93d7c3efe..a1cf142edc4c0224731ebab988bcbf9272acd57e 100644
--- a/src/interpreter/bytecode-generator.cc
+++ b/src/interpreter/bytecode-generator.cc
@@ -2306,10 +2306,7 @@ void BytecodeGenerator::VisitDeclarations(Declaration::List* declarations) {
// The subsequent ones must be about the same <var> to return true.
bool BytecodeGenerator::IsPrototypeAssignment(
- Statement* stmt, Variable** var, HoleCheckMode* hole_check_mode,
- SmallZoneVector<std::pair<const AstRawString*, Expression*>,
- kInitialPropertyCount>& properties,
- std::unordered_set<const AstRawString*>& duplicates) {
+ Statement* stmt, std::unique_ptr<PrototypeAssignments>* assignments) {
// The expression Statement is an assignment
// ========================================
ExpressionStatement* expr_stmt = stmt->AsExpressionStatement();
@@ -2381,41 +2378,46 @@ bool BytecodeGenerator::IsPrototypeAssignment(
return false;
}
- if (!duplicates.insert(prop_str).second) {
- return false;
- }
-
- if (*var == nullptr) {
- // This is the first proto assignment in the sequence
- *var = tmp_var;
- *hole_check_mode = proto_prop->obj()->AsVariableProxy()->hole_check_mode();
- } else if (*var != tmp_var) {
- // This prototype assignment is about another var
- return false;
+ if (!*assignments) {
+ // This is the first prototype assignment in the sequence.
+ *assignments = std::make_unique<PrototypeAssignments>(
+ tmp_var, proto_prop->obj()->AsVariableProxy()->hole_check_mode(),
+ ZoneVector<PrototypeAssignment>(zone()));
+ (*assignments)->properties.reserve(8);
+ (*assignments)->duplicates.insert(prop_str);
+ } else {
+ if (!(*assignments)->duplicates.insert(prop_str).second) return false;
+ if ((*assignments)->var != tmp_var) {
+ // This prototype assignment is about another var.
+ return false;
+ }
+ DCHECK_EQ((*assignments)->hole_check_mode,
+ proto_prop->obj()->AsVariableProxy()->hole_check_mode());
}
- // Success
- properties.push_back(std::make_pair(
- prop_str,
- value)); // This will be reused as part of an ObjectLiteral
+ // Success!
+ (*assignments)
+ ->properties.push_back(std::make_pair(
+ prop_str,
+ value)); // This will be reused as part of an ObjectLiteral.
- DCHECK_EQ(*hole_check_mode,
- proto_prop->obj()->AsVariableProxy()->hole_check_mode());
return true;
}
void BytecodeGenerator::VisitConsecutivePrototypeAssignments(
- const SmallZoneVector<std::pair<const AstRawString*, Expression*>,
- kInitialPropertyCount>& properties,
- Variable* var, HoleCheckMode hole_check_mode) {
+ std::unique_ptr<PrototypeAssignments> assignments) {
// Create a boiler plate object in the constant pool to be merged into the
- // proto
+ // proto.
size_t entry = builder()->AllocateDeferredConstantPoolEntry();
- proto_assign_seq_.push_back(std::make_pair(
- zone()->New<ProtoAssignmentSeqBuilder>(properties), entry));
+ proto_assign_seq_.push_back(
+ std::make_pair(zone()->New<ProtoAssignmentSeqBuilder>(
+ std::move(assignments->properties)),
+ entry));
+ const ZoneVector<PrototypeAssignment>* props =
+ proto_assign_seq_.back().first->properties();
int first_idx = -1;
- for (auto& p : properties) {
+ for (auto& p : *props) {
auto func = p.second->AsFunctionLiteral();
if (func) {
int idx = GetNewClosureSlot(func);
@@ -2426,13 +2428,13 @@ void BytecodeGenerator::VisitConsecutivePrototypeAssignments(
}
}
- // We need it to be valid, even if unused
+ // We need {first_idx} to be valid, even if it's unused.
if (first_idx == -1) {
first_idx = 0;
}
- // Load the variable whose prototype is to be set into the Accumulator
- BuildVariableLoad(var, hole_check_mode);
- // Merge in-place proto-def boilerplate object into Accumulator
+ // Load the variable whose prototype is to be set into the Accumulator.
+ BuildVariableLoad(assignments->var, assignments->hole_check_mode);
+ // Merge in-place proto-def boilerplate object into the Accumulator.
builder()->SetPrototypeProperties(entry, first_idx);
}
@@ -2440,25 +2442,23 @@ void BytecodeGenerator::VisitStatements(
const ZonePtrList<Statement>* statements, int start) {
for (int stmt_idx = start; stmt_idx < statements->length(); stmt_idx++) {
if (v8_flags.proto_assign_seq_opt) {
- Variable* var = nullptr;
- HoleCheckMode hole_check_mode;
-
int proto_assign_idx = stmt_idx;
- SmallZoneVector<std::pair<const AstRawString*, Expression*>,
- kInitialPropertyCount>
- properties(zone());
- std::unordered_set<const AstRawString*> duplicates;
+ // {VisitStatements} can be used for deep recursions, so this is a
+ // stack-friendly design: statically we only need one {unique_ptr}, and
+ // the actual storage is heap-allocated when it is needed.
+ std::unique_ptr<PrototypeAssignments> assignments;
while (proto_assign_idx < statements->length() &&
- IsPrototypeAssignment(statements->at(proto_assign_idx), &var,
- &hole_check_mode, properties, duplicates)) {
+ IsPrototypeAssignment(statements->at(proto_assign_idx),
+ &assignments)) {
++proto_assign_idx;
}
if (proto_assign_idx - stmt_idx > 1) {
- DCHECK_EQ((size_t)(proto_assign_idx - stmt_idx), properties.size());
- VisitConsecutivePrototypeAssignments(properties, var, hole_check_mode);
- stmt_idx = proto_assign_idx - 1; // the outer loop should now ignore
- // these statements
+ DCHECK_EQ(static_cast<size_t>(proto_assign_idx - stmt_idx),
+ assignments->properties.size());
+ VisitConsecutivePrototypeAssignments(std::move(assignments));
+ stmt_idx = proto_assign_idx - 1; // The outer loop should now ignore
+ // these statements.
DCHECK(!builder()->RemainderOfBlockIsDead());
continue;
}
diff --git a/src/interpreter/bytecode-generator.h b/src/interpreter/bytecode-generator.h
index 5dd136a01848aaf4a182dd31aa05a6ebe845fae8..b2e4cf6d40c3cd66042f5f52533b4883ff159418 100644
--- a/src/interpreter/bytecode-generator.h
+++ b/src/interpreter/bytecode-generator.h
@@ -30,6 +30,13 @@ class LoopBuilder;
class BlockCoverageBuilder;
class BytecodeJumpTable;
+struct PrototypeAssignments {
+ Variable* var;
+ HoleCheckMode hole_check_mode;
+ ZoneVector<PrototypeAssignment> properties;
+ std::unordered_set<const AstRawString*> duplicates;
+};
+
class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
public:
enum TypeHint : uint8_t {
@@ -69,18 +76,12 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
#define DECLARE_VISIT(type) void Visit##type(type* node);
AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT
- static constexpr int kInitialPropertyCount = 64;
bool IsPrototypeAssignment(
- Statement* stmt, Variable** var, HoleCheckMode* hole_check_mode,
- SmallZoneVector<std::pair<const AstRawString*, Expression*>,
- kInitialPropertyCount>& properties,
- std::unordered_set<const AstRawString*>& duplicate);
-
- void VisitConsecutivePrototypeAssignments(
- const SmallZoneVector<std::pair<const AstRawString*, Expression*>,
- kInitialPropertyCount>& properties,
- Variable* var, HoleCheckMode hole_check_mode);
+ Statement* stmt, std::unique_ptr<PrototypeAssignments>* assignments);
+ V8_NOINLINE void VisitConsecutivePrototypeAssignments(
+ std::unique_ptr<PrototypeAssignments> assignments);
+
// Visiting function for declarations list and statements are overridden.
void VisitModuleDeclarations(Declaration::List* declarations);
void VisitGlobalDeclarations(Declaration::List* declarations);
diff --git a/src/interpreter/prototype-assignment-sequence-builder.cc b/src/interpreter/prototype-assignment-sequence-builder.cc
index a7c05b6e8555fde41ba6a81523437fd03b16c3e6..fb427c825c2753d3e12f557279a5230985a1ec44 100644
--- a/src/interpreter/prototype-assignment-sequence-builder.cc
+++ b/src/interpreter/prototype-assignment-sequence-builder.cc
@@ -25,7 +25,7 @@ void ProtoAssignmentSeqBuilder::BuildBoilerplateDescription(
int position = 0;
for (size_t i = 0; i < properties_.size(); i++) {
- auto pair = properties_.at(i);
+ PrototypeAssignment pair = properties_.at(i);
const AstRawString* key_str = pair.first;
DirectHandle<Object> key = Cast<Object>(key_str->string());
diff --git a/src/interpreter/prototype-assignment-sequence-builder.h b/src/interpreter/prototype-assignment-sequence-builder.h
index 0c29f4f4bf0843877b2bd568866d8e290d4f3b51..6583022aa43a30df707325e6b7a14891f97a4ef1 100644
--- a/src/interpreter/prototype-assignment-sequence-builder.h
+++ b/src/interpreter/prototype-assignment-sequence-builder.h
@@ -7,17 +7,17 @@
#include "src/ast/ast.h"
#include "src/objects/literal-objects.h"
+#include "src/zone/zone-containers.h"
namespace v8 {
namespace internal {
+using PrototypeAssignment = std::pair<const AstRawString*, Expression*>;
+
class ProtoAssignmentSeqBuilder final : public ZoneObject {
public:
- static constexpr int kInitialPropertyCount = 64;
-
explicit ProtoAssignmentSeqBuilder(
- const SmallZoneVector<std::pair<const AstRawString*, Expression*>,
- kInitialPropertyCount>& properties)
+ ZoneVector<PrototypeAssignment>&& properties)
: properties_(std::move(properties)) {}
~ProtoAssignmentSeqBuilder() = default;
@@ -53,10 +53,10 @@ class ProtoAssignmentSeqBuilder final : public ZoneObject {
IsolateT* isolate,
Handle<Script> script);
+ const ZoneVector<PrototypeAssignment>* properties() { return &properties_; }
+
private:
- SmallZoneVector<std::pair<const AstRawString*, Expression*>,
- kInitialPropertyCount>
- properties_;
+ ZoneVector<PrototypeAssignment> properties_;
IndirectHandle<ObjectBoilerplateDescription> boilerplate_description_;
};

View File

@@ -0,0 +1,148 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Raphael Herouart <rherouart@chromium.org>
Date: Tue, 18 Nov 2025 11:00:26 +0000
Subject: [runtime] Correcting SetPrototypeProperties:
- Off by One Error in code generation
- Attributes should be preserved when setting properties
- SmallVector Memory Leak
Bug: 429332174
Change-Id: I8a669a98f44777ad54ea7e7bb06fc4f8c552c865
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/7160576
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Commit-Queue: Raphael Herouart <rherouart@chromium.org>
Cr-Commit-Position: refs/heads/main@{#103784}
diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc
index bf874d94ec34056d499fea9cbd034f959d506b58..63400abcc7ca0bd5369d566dd37e2ae93d7c3efe 100644
--- a/src/interpreter/bytecode-generator.cc
+++ b/src/interpreter/bytecode-generator.cc
@@ -2307,8 +2307,8 @@ void BytecodeGenerator::VisitDeclarations(Declaration::List* declarations) {
bool BytecodeGenerator::IsPrototypeAssignment(
Statement* stmt, Variable** var, HoleCheckMode* hole_check_mode,
- base::SmallVector<std::pair<const AstRawString*, Expression*>,
- kInitialPropertyCount>& properties,
+ SmallZoneVector<std::pair<const AstRawString*, Expression*>,
+ kInitialPropertyCount>& properties,
std::unordered_set<const AstRawString*>& duplicates) {
// The expression Statement is an assignment
// ========================================
@@ -2405,8 +2405,8 @@ bool BytecodeGenerator::IsPrototypeAssignment(
}
void BytecodeGenerator::VisitConsecutivePrototypeAssignments(
- const base::SmallVector<std::pair<const AstRawString*, Expression*>,
- kInitialPropertyCount>& properties,
+ const SmallZoneVector<std::pair<const AstRawString*, Expression*>,
+ kInitialPropertyCount>& properties,
Variable* var, HoleCheckMode hole_check_mode) {
// Create a boiler plate object in the constant pool to be merged into the
// proto
@@ -2444,9 +2444,9 @@ void BytecodeGenerator::VisitStatements(
HoleCheckMode hole_check_mode;
int proto_assign_idx = stmt_idx;
- base::SmallVector<std::pair<const AstRawString*, Expression*>,
- kInitialPropertyCount>
- properties;
+ SmallZoneVector<std::pair<const AstRawString*, Expression*>,
+ kInitialPropertyCount>
+ properties(zone());
std::unordered_set<const AstRawString*> duplicates;
while (proto_assign_idx < statements->length() &&
IsPrototypeAssignment(statements->at(proto_assign_idx), &var,
@@ -2457,10 +2457,10 @@ void BytecodeGenerator::VisitStatements(
if (proto_assign_idx - stmt_idx > 1) {
DCHECK_EQ((size_t)(proto_assign_idx - stmt_idx), properties.size());
VisitConsecutivePrototypeAssignments(properties, var, hole_check_mode);
- stmt_idx = proto_assign_idx; // the outer loop should now ignore these
- // statements
+ stmt_idx = proto_assign_idx - 1; // the outer loop should now ignore
+ // these statements
DCHECK(!builder()->RemainderOfBlockIsDead());
- if (stmt_idx == statements->length()) break;
+ continue;
}
}
diff --git a/src/interpreter/bytecode-generator.h b/src/interpreter/bytecode-generator.h
index 41c5cda1ca6dd4017b329e41bad8af3bcc4ee242..5dd136a01848aaf4a182dd31aa05a6ebe845fae8 100644
--- a/src/interpreter/bytecode-generator.h
+++ b/src/interpreter/bytecode-generator.h
@@ -73,13 +73,13 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
bool IsPrototypeAssignment(
Statement* stmt, Variable** var, HoleCheckMode* hole_check_mode,
- base::SmallVector<std::pair<const AstRawString*, Expression*>,
- kInitialPropertyCount>& properties,
+ SmallZoneVector<std::pair<const AstRawString*, Expression*>,
+ kInitialPropertyCount>& properties,
std::unordered_set<const AstRawString*>& duplicate);
void VisitConsecutivePrototypeAssignments(
- const base::SmallVector<std::pair<const AstRawString*, Expression*>,
- kInitialPropertyCount>& properties,
+ const SmallZoneVector<std::pair<const AstRawString*, Expression*>,
+ kInitialPropertyCount>& properties,
Variable* var, HoleCheckMode hole_check_mode);
// Visiting function for declarations list and statements are overridden.
void VisitModuleDeclarations(Declaration::List* declarations);
diff --git a/src/interpreter/prototype-assignment-sequence-builder.h b/src/interpreter/prototype-assignment-sequence-builder.h
index 880ed4dcec8399e9b52e6d1924b8773bff1db063..0c29f4f4bf0843877b2bd568866d8e290d4f3b51 100644
--- a/src/interpreter/prototype-assignment-sequence-builder.h
+++ b/src/interpreter/prototype-assignment-sequence-builder.h
@@ -16,8 +16,8 @@ class ProtoAssignmentSeqBuilder final : public ZoneObject {
static constexpr int kInitialPropertyCount = 64;
explicit ProtoAssignmentSeqBuilder(
- const base::SmallVector<std::pair<const AstRawString*, Expression*>,
- kInitialPropertyCount>& properties)
+ const SmallZoneVector<std::pair<const AstRawString*, Expression*>,
+ kInitialPropertyCount>& properties)
: properties_(std::move(properties)) {}
~ProtoAssignmentSeqBuilder() = default;
@@ -54,8 +54,8 @@ class ProtoAssignmentSeqBuilder final : public ZoneObject {
Handle<Script> script);
private:
- base::SmallVector<std::pair<const AstRawString*, Expression*>,
- kInitialPropertyCount>
+ SmallZoneVector<std::pair<const AstRawString*, Expression*>,
+ kInitialPropertyCount>
properties_;
IndirectHandle<ObjectBoilerplateDescription> boilerplate_description_;
};
diff --git a/src/runtime/runtime-literals.cc b/src/runtime/runtime-literals.cc
index ded3b466625c99da6f27936ae4e5e0c879baec1b..961b9ee5b7d329bb018300fe2f18bea60e1cd883 100644
--- a/src/runtime/runtime-literals.cc
+++ b/src/runtime/runtime-literals.cc
@@ -730,6 +730,13 @@ RUNTIME_FUNCTION(Runtime_SetPrototypeProperties) {
feedback_cell_array, current_slot));
}
+ if (IsSpecialReceiverMap(js_proto->map())) {
+ RETURN_RESULT_OR_FAILURE(
+ isolate, SetPrototypePropertiesSlow(isolate, context, obj,
+ object_boilerplate_description,
+ feedback_cell_array, current_slot));
+ }
+
bool is_default_func_prototype =
IsDefaultFunctionPrototype(js_proto, isolate);
@@ -782,7 +789,11 @@ RUNTIME_FUNCTION(Runtime_SetPrototypeProperties) {
value = InstantiateIfSharedFunctionInfo(
context, isolate, value, feedback_cell_array, current_slot);
DirectHandle<String> name = Cast<String>(key);
- JSObject::SetOwnPropertyIgnoreAttributes(js_proto, name, value, NONE)
+ Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
+ PropertyAttributes attr = maybe.ToChecked();
+ if (attr == ABSENT) attr = NONE;
+
+ JSObject::SetOwnPropertyIgnoreAttributes(js_proto, name, value, attr)
.Check();
result = value;

View File

@@ -0,0 +1,153 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Raphael Herouart <rherouart@chromium.org>
Date: Tue, 21 Oct 2025 14:49:06 +0000
Subject: [runtime] SetPrototypeProperties handling of
Hole/Undefined/Non-Object Values
Bug: 451750214
Change-Id: Ida29afe0b92ed4a6acff97214005ed3589093294
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/7062734
Commit-Queue: Raphael Herouart <rherouart@chromium.org>
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#103261}
diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc
index 6d444622bacbb71c4754bc055da5cae39ed213b7..bf874d94ec34056d499fea9cbd034f959d506b58 100644
--- a/src/interpreter/bytecode-generator.cc
+++ b/src/interpreter/bytecode-generator.cc
@@ -2306,7 +2306,7 @@ void BytecodeGenerator::VisitDeclarations(Declaration::List* declarations) {
// The subsequent ones must be about the same <var> to return true.
bool BytecodeGenerator::IsPrototypeAssignment(
- Statement* stmt, Variable** var,
+ Statement* stmt, Variable** var, HoleCheckMode* hole_check_mode,
base::SmallVector<std::pair<const AstRawString*, Expression*>,
kInitialPropertyCount>& properties,
std::unordered_set<const AstRawString*>& duplicates) {
@@ -2388,6 +2388,7 @@ bool BytecodeGenerator::IsPrototypeAssignment(
if (*var == nullptr) {
// This is the first proto assignment in the sequence
*var = tmp_var;
+ *hole_check_mode = proto_prop->obj()->AsVariableProxy()->hole_check_mode();
} else if (*var != tmp_var) {
// This prototype assignment is about another var
return false;
@@ -2398,13 +2399,15 @@ bool BytecodeGenerator::IsPrototypeAssignment(
prop_str,
value)); // This will be reused as part of an ObjectLiteral
+ DCHECK_EQ(*hole_check_mode,
+ proto_prop->obj()->AsVariableProxy()->hole_check_mode());
return true;
}
void BytecodeGenerator::VisitConsecutivePrototypeAssignments(
const base::SmallVector<std::pair<const AstRawString*, Expression*>,
kInitialPropertyCount>& properties,
- Variable* var) {
+ Variable* var, HoleCheckMode hole_check_mode) {
// Create a boiler plate object in the constant pool to be merged into the
// proto
size_t entry = builder()->AllocateDeferredConstantPoolEntry();
@@ -2428,7 +2431,7 @@ void BytecodeGenerator::VisitConsecutivePrototypeAssignments(
first_idx = 0;
}
// Load the variable whose prototype is to be set into the Accumulator
- BuildVariableLoad(var, HoleCheckMode::kElided);
+ BuildVariableLoad(var, hole_check_mode);
// Merge in-place proto-def boilerplate object into Accumulator
builder()->SetPrototypeProperties(entry, first_idx);
}
@@ -2438,6 +2441,8 @@ void BytecodeGenerator::VisitStatements(
for (int stmt_idx = start; stmt_idx < statements->length(); stmt_idx++) {
if (v8_flags.proto_assign_seq_opt) {
Variable* var = nullptr;
+ HoleCheckMode hole_check_mode;
+
int proto_assign_idx = stmt_idx;
base::SmallVector<std::pair<const AstRawString*, Expression*>,
kInitialPropertyCount>
@@ -2445,13 +2450,13 @@ void BytecodeGenerator::VisitStatements(
std::unordered_set<const AstRawString*> duplicates;
while (proto_assign_idx < statements->length() &&
IsPrototypeAssignment(statements->at(proto_assign_idx), &var,
- properties, duplicates)) {
+ &hole_check_mode, properties, duplicates)) {
++proto_assign_idx;
}
if (proto_assign_idx - stmt_idx > 1) {
DCHECK_EQ((size_t)(proto_assign_idx - stmt_idx), properties.size());
- VisitConsecutivePrototypeAssignments(properties, var);
+ VisitConsecutivePrototypeAssignments(properties, var, hole_check_mode);
stmt_idx = proto_assign_idx; // the outer loop should now ignore these
// statements
DCHECK(!builder()->RemainderOfBlockIsDead());
diff --git a/src/interpreter/bytecode-generator.h b/src/interpreter/bytecode-generator.h
index b6421819c353febe283069852645a6b85e4c855a..41c5cda1ca6dd4017b329e41bad8af3bcc4ee242 100644
--- a/src/interpreter/bytecode-generator.h
+++ b/src/interpreter/bytecode-generator.h
@@ -72,7 +72,7 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
static constexpr int kInitialPropertyCount = 64;
bool IsPrototypeAssignment(
- Statement* stmt, Variable** var,
+ Statement* stmt, Variable** var, HoleCheckMode* hole_check_mode,
base::SmallVector<std::pair<const AstRawString*, Expression*>,
kInitialPropertyCount>& properties,
std::unordered_set<const AstRawString*>& duplicate);
@@ -80,7 +80,7 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void VisitConsecutivePrototypeAssignments(
const base::SmallVector<std::pair<const AstRawString*, Expression*>,
kInitialPropertyCount>& properties,
- Variable* var);
+ Variable* var, HoleCheckMode hole_check_mode);
// Visiting function for declarations list and statements are overridden.
void VisitModuleDeclarations(Declaration::List* declarations);
void VisitGlobalDeclarations(Declaration::List* declarations);
diff --git a/src/runtime/runtime-literals.cc b/src/runtime/runtime-literals.cc
index 83074253314c438eed3006332c63c6bf7dfe4421..ded3b466625c99da6f27936ae4e5e0c879baec1b 100644
--- a/src/runtime/runtime-literals.cc
+++ b/src/runtime/runtime-literals.cc
@@ -613,7 +613,7 @@ static DirectHandle<Object> InstantiateIfSharedFunctionInfo(
}
static MaybeDirectHandle<Object> SetPrototypePropertiesSlow(
- Isolate* isolate, DirectHandle<Context> context, DirectHandle<JSObject> obj,
+ Isolate* isolate, DirectHandle<Context> context, DirectHandle<JSAny> obj,
Handle<ObjectBoilerplateDescription> object_boilerplate_description,
DirectHandle<ClosureFeedbackCellArray> feedback_cell_array,
int& current_slot, int start_index = 0) {
@@ -684,7 +684,7 @@ RUNTIME_FUNCTION(Runtime_SetPrototypeProperties) {
HandleScope scope(isolate);
DCHECK_EQ(4, args.length());
DirectHandle<Context> context(isolate->context(), isolate);
- DirectHandle<JSObject> obj = args.at<JSObject>(0); // acc JS Object
+ DirectHandle<JSAny> obj = args.at<JSAny>(0); // acc JS Object
Handle<ObjectBoilerplateDescription> object_boilerplate_description =
args.at<ObjectBoilerplateDescription>(1);
DirectHandle<ClosureFeedbackCellArray> feedback_cell_array =
diff --git a/test/unittests/interpreter/bytecode_expectations/SetPrototypePropertiesOptimization.golden b/test/unittests/interpreter/bytecode_expectations/SetPrototypePropertiesOptimization.golden
index 84ebbb755f8a5432c2e8da3d26ceb648bee2cf2d..bb9d697caec6e79810fa757abec4b71ad4cf3f2f 100644
--- a/test/unittests/interpreter/bytecode_expectations/SetPrototypePropertiesOptimization.golden
+++ b/test/unittests/interpreter/bytecode_expectations/SetPrototypePropertiesOptimization.golden
@@ -50,15 +50,17 @@ snippet: "
"
frame size: 0
parameter count: 1
-bytecode array length: 7
+bytecode array length: 9
bytecodes: [
B(LdaImmutableCurrentContextSlot), U8(2),
- /* 109 E> */ B(SetPrototypeProperties), U8(0), U8(0),
+ /* 109 E> */ B(ThrowReferenceErrorIfHole), U8(1),
+ B(SetPrototypeProperties), U8(0), U8(0),
B(LdaUndefined),
/* 245 S> */ B(Return),
]
constant pool: [
OBJECT_BOILERPLATE_DESCRIPTION_TYPE,
+ INTERNALIZED_ONE_BYTE_STRING_TYPE ["MyClass"],
]
handlers: [
]

View File

@@ -325,7 +325,7 @@ index 181d298bfa27d21f013016b34a586078d12f8a58..92d6f7b36d4c5c0a64723f7d18427a62
#undef TRACE
diff --git a/src/compiler/turboshaft/turbolev-graph-builder.cc b/src/compiler/turboshaft/turbolev-graph-builder.cc
index 9d1dafe2b0b733c88283b21eddb36c9827912eca..bcb461488899bcbf3a130845f39f0005bd34131e 100644
index 3db187b8c48cc0c7168be039e7d90078c4df7bda..d80362036da4c80e192ed489e3c66e8bfed271ba 100644
--- a/src/compiler/turboshaft/turbolev-graph-builder.cc
+++ b/src/compiler/turboshaft/turbolev-graph-builder.cc
@@ -118,12 +118,7 @@ class BlockOriginTrackingReducer : public Next {

View File

@@ -40,6 +40,7 @@ DevToolsSecurity -enable
# security import "$dir"/public.key -k $KEY_CHAIN
# Generate Trust Settings
# TODO: Remove NPX
npm_config_yes=true npx ts-node "$(dirname $0)"/gen-trust.ts "$dir"/certificate.cer "$dir"/trust.xml
# Import Trust Settings

View File

@@ -1,6 +1,6 @@
const chalk = require('chalk');
const { GitProcess } = require('dugite');
const childProcess = require('node:child_process');
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');
@@ -61,13 +61,16 @@ function getAbsoluteElectronExec () {
return path.resolve(SRC_DIR, getElectronExec());
}
async function handleGitCall (args, gitDir) {
const details = await GitProcess.exec(args, gitDir);
if (details.exitCode === 0) {
return details.stdout.replace(/^\*|\s+|\s+$/, '');
function handleGitCall (args, gitDir) {
const result = childProcess.spawnSync('git', args, {
cwd: gitDir,
encoding: 'utf8',
stdio: ['inherit', 'pipe', 'pipe']
});
if (result.status === 0) {
return result.stdout.replace(/^\*|\s+|\s+$/, '');
} else {
const error = GitProcess.parseError(details.stderr);
console.log(`${fail} couldn't parse git process call: `, error);
console.log(`${fail} couldn't parse git process call: `, result.stderr);
process.exit(1);
}
}

View File

@@ -1,6 +1,5 @@
#!/usr/bin/env node
const { GitProcess } = require('dugite');
const { ESLint } = require('eslint');
const minimist = require('minimist');
@@ -153,7 +152,7 @@ const LINTERS = [{
}, {
key: 'javascript',
roots: ['build', 'default_app', 'lib', 'npm', 'script', 'spec'],
ignoreRoots: ['spec/node_modules'],
ignoreRoots: ['spec/node_modules', 'spec/fixtures/native-addon'],
test: filename => filename.endsWith('.js') || filename.endsWith('.ts') || filename.endsWith('.mjs'),
run: async (opts, filenames) => {
const eslint = new ESLint({
@@ -282,7 +281,7 @@ const LINTERS = [{
}, {
key: 'md',
roots: ['.'],
ignoreRoots: ['.git', 'node_modules', 'spec/node_modules'],
ignoreRoots: ['.git', 'node_modules', 'spec/node_modules', 'spec/fixtures/native-addon'],
test: filename => filename.endsWith('.md'),
run: async (opts, filenames) => {
const { getCodeBlocks } = await import('@electron/lint-roller/dist/lib/markdown.js');
@@ -431,9 +430,13 @@ function populateLinterWithArgs (linter, opts) {
}
async function findChangedFiles (top) {
const result = await GitProcess.exec(['diff', '--name-only', '--cached'], top);
if (result.exitCode !== 0) {
console.log('Failed to find changed files', GitProcess.parseError(result.stderr));
const result = childProcess.spawnSync('git', ['diff', '--name-only', '--cached'], {
cwd: top,
encoding: 'utf8',
stdio: ['inherit', 'pipe', 'pipe']
});
if (result.status !== 0) {
console.log('Failed to find changed files', result.stderr);
process.exit(1);
}
const relativePaths = result.stdout.split(/\r\n|\r|\n/g);

View File

@@ -9,7 +9,7 @@ const NAN_DIR = path.resolve(BASE, 'third_party', 'nan');
const NPX_CMD = process.platform === 'win32' ? 'npx.cmd' : 'npx';
const utils = require('./lib/utils');
const { YARN_VERSION } = require('./yarn');
const { YARN_SCRIPT_PATH } = require('./yarn');
if (!require.main) {
throw new Error('Must call the nan spec runner directly');
@@ -106,13 +106,12 @@ async function main () {
stdio: 'inherit',
shell: process.platform === 'win32'
});
if (buildStatus !== 0 || signal != null) {
console.error('Failed to build nan test modules');
return process.exit(buildStatus !== 0 ? buildStatus : signal);
}
const { status: installStatus, signal: installSignal } = cp.spawnSync(NPX_CMD, [`yarn@${YARN_VERSION}`, 'install'], {
const { status: installStatus, signal: installSignal } = cp.spawnSync(process.execPath, [YARN_SCRIPT_PATH, 'install'], {
env,
cwd: NAN_DIR,
stdio: 'inherit',

View File

@@ -113,6 +113,7 @@
"parallel/test-tls-passphrase",
"parallel/test-tls-peer-certificate",
"parallel/test-tls-pfx-authorizationerror",
"parallel/test-tls-psk-alpn-callback-exception-handling",
"parallel/test-tls-psk-circuit",
"parallel/test-tls-reduced-SECLEVEL-in-cipher",
"parallel/test-tls-root-certificates",

View File

@@ -13,6 +13,7 @@ import { createGitHubTokenStrategy } from '../github-token';
import { ELECTRON_ORG, ELECTRON_REPO, ElectronReleaseRepo, NIGHTLY_REPO } from '../types';
const rootPackageJson = JSON.parse(fs.readFileSync(path.resolve(__dirname, '../../../package.json'), 'utf-8'));
rootPackageJson.name = 'electron';
if (!process.env.ELECTRON_NPM_OTP) {
console.error('Please set ELECTRON_NPM_OTP');
@@ -211,6 +212,7 @@ new Promise<string>((resolve, reject) => {
});
})
.then((tarballPath) => {
// TODO: Remove NPX
const existingVersionJSON = childProcess.execSync(`npx npm@7 view ${rootPackageJson.name}@${currentElectronVersion} --json`).toString('utf-8');
// It's possible this is a re-run and we already have published the package, if not we just publish like normal
if (!existingVersionJSON) {

View File

@@ -1,9 +1,9 @@
#!/usr/bin/env node
import { Octokit } from '@octokit/rest';
import { GitProcess } from 'dugite';
import { valid, compare, gte, lte } from 'semver';
import { spawnSync } from 'node:child_process';
import { basename } from 'node:path';
import { parseArgs } from 'node:util';
@@ -20,8 +20,12 @@ const semverify = (version: string) => version.replace(/^origin\//, '').replace(
const runGit = async (args: string[]) => {
console.info(`Running: git ${args.join(' ')}`);
const response = await GitProcess.exec(args, ELECTRON_DIR);
if (response.exitCode !== 0) {
const response = spawnSync('git', args, {
cwd: ELECTRON_DIR,
encoding: 'utf8',
stdio: ['inherit', 'pipe', 'pipe']
});
if (response.status !== 0) {
throw new Error(response.stderr.trim());
}
return response.stdout.trim();

View File

@@ -1,8 +1,8 @@
#!/usr/bin/env node
import { Octokit } from '@octokit/rest';
import { GitProcess } from 'dugite';
import { spawnSync } from 'node:child_process';
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
import { resolve as _resolve } from 'node:path';
@@ -105,8 +105,13 @@ class Pool {
**/
const runGit = async (dir: string, args: string[]) => {
const response = await GitProcess.exec(args, dir);
if (response.exitCode !== 0) {
const response = spawnSync('git', args, {
cwd: dir,
encoding: 'utf8',
stdio: ['inherit', 'pipe', 'pipe'],
maxBuffer: 100 * 1024 * 1024 // 100MB buffer to handle large git outputs
});
if (response.status !== 0) {
throw new Error(response.stderr.trim());
}
return response.stdout.trim();

View File

@@ -1,8 +1,7 @@
import { Octokit } from '@octokit/rest';
import * as chalk from 'chalk';
import { GitProcess } from 'dugite';
import { execSync } from 'node:child_process';
import { execSync, spawnSync } from 'node:child_process';
import { join } from 'node:path';
import { createGitHubTokenStrategy } from './github-token';
@@ -166,11 +165,12 @@ async function createRelease (
}
async function pushRelease (branch: string) {
const pushDetails = await GitProcess.exec(
['push', 'origin', `HEAD:${branch}`, '--follow-tags'],
ELECTRON_DIR
);
if (pushDetails.exitCode === 0) {
const pushDetails = spawnSync('git', ['push', 'origin', `HEAD:${branch}`, '--follow-tags'], {
cwd: ELECTRON_DIR,
encoding: 'utf8',
stdio: ['inherit', 'pipe', 'pipe']
});
if (pushDetails.status === 0) {
console.log(
`${pass} Successfully pushed the release. Wait for ` +
'release builds to finish before running "npm run release".'
@@ -191,11 +191,12 @@ async function runReleaseBuilds (branch: string, newVersion: string) {
async function tagRelease (version: string) {
console.log(`Tagging release ${version}.`);
const checkoutDetails = await GitProcess.exec(
['tag', '-a', '-m', version, version],
ELECTRON_DIR
);
if (checkoutDetails.exitCode === 0) {
const checkoutDetails = spawnSync('git', ['tag', '-a', '-m', version, version], {
cwd: ELECTRON_DIR,
encoding: 'utf8',
stdio: ['inherit', 'pipe', 'pipe']
});
if (checkoutDetails.status === 0) {
console.log(`${pass} Successfully tagged ${version}.`);
} else {
console.log(

View File

@@ -1,6 +1,7 @@
import { GitProcess } from 'dugite';
import * as semver from 'semver';
import { spawnSync } from 'node:child_process';
import { ELECTRON_DIR } from '../lib/utils';
export enum PreType {
@@ -27,7 +28,11 @@ export const isStable = (v: string) => {
export async function nextAlpha (v: string) {
const next = semver.coerce(semver.clean(v));
const tagBlob = await GitProcess.exec(['tag', '--list', '-l', `v${next}-alpha.*`], ELECTRON_DIR);
const tagBlob = spawnSync('git', ['tag', '--list', '-l', `v${next}-alpha.*`], {
cwd: ELECTRON_DIR,
encoding: 'utf8',
stdio: ['inherit', 'pipe', 'pipe']
});
const tags = tagBlob.stdout.split('\n').filter(e => e !== '');
tags.sort((t1, t2) => {
const a = parseInt(t1.split('.').pop()!, 10);
@@ -41,7 +46,11 @@ export async function nextAlpha (v: string) {
export async function nextBeta (v: string) {
const next = semver.coerce(semver.clean(v));
const tagBlob = await GitProcess.exec(['tag', '--list', '-l', `v${next}-beta.*`], ELECTRON_DIR);
const tagBlob = spawnSync('git', ['tag', '--list', '-l', `v${next}-beta.*`], {
cwd: ELECTRON_DIR,
encoding: 'utf8',
stdio: ['inherit', 'pipe', 'pipe']
});
const tags = tagBlob.stdout.split('\n').filter(e => e !== '');
tags.sort((t1, t2) => {
const a = parseInt(t1.split('.').pop()!, 10);
@@ -57,7 +66,11 @@ export async function nextNightly (v: string) {
let next = semver.valid(semver.coerce(v));
const pre = `nightly.${getCurrentDate()}`;
const branch = (await GitProcess.exec(['rev-parse', '--abbrev-ref', 'HEAD'], ELECTRON_DIR)).stdout.trim();
const branch = spawnSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], {
cwd: ELECTRON_DIR,
encoding: 'utf8',
stdio: ['inherit', 'pipe', 'pipe']
}).stdout.trim();
if (branch === 'main') {
next = semver.inc(await getLastMajorForMain(), 'major');
} else if (isStable(v)) {
@@ -69,8 +82,12 @@ export async function nextNightly (v: string) {
async function getLastMajorForMain () {
let branchNames;
const result = await GitProcess.exec(['branch', '-a', '--remote', '--list', 'origin/[0-9]*-x-y'], ELECTRON_DIR);
if (result.exitCode === 0) {
const result = spawnSync('git', ['branch', '-a', '--remote', '--list', 'origin/[0-9]*-x-y'], {
cwd: ELECTRON_DIR,
encoding: 'utf8',
stdio: ['inherit', 'pipe', 'pipe']
});
if (result.status === 0) {
branchNames = result.stdout.trim().split('\n');
const filtered = branchNames.map(b => b.replace('origin/', ''));
return getNextReleaseBranch(filtered);

View File

@@ -114,11 +114,14 @@ async function runClangTidy (
outDir: string,
filenames: string[],
checks: string = '',
jobs: number = 1
jobs: number = 1,
fix: boolean = false
): Promise<boolean> {
const cmd = path.resolve(LLVM_BIN, 'clang-tidy');
const args = [`-p=${outDir}`, '--use-color'];
const args = [`-p=${outDir}`];
if (!process.env.CI) args.push('--use-color');
if (fix) args.push('--fix');
if (checks) args.push(`--checks=${checks}`);
// Remove any files that aren't in the compilation database to prevent
@@ -209,7 +212,7 @@ function parseCommandLine () {
if (!arg || arg.startsWith('-')) {
console.log(
'Usage: script/run-clang-tidy.ts [-h|--help] [--jobs|-j] ' +
'[--checks] --out-dir OUTDIR [file1 file2]'
'[--fix] [--checks] --out-dir OUTDIR [file1 file2]'
);
process.exit(0);
}
@@ -218,7 +221,7 @@ function parseCommandLine () {
};
const opts = minimist(process.argv.slice(2), {
boolean: ['help'],
boolean: ['fix', 'help'],
string: ['checks', 'out-dir'],
default: { jobs: 1 },
alias: { help: 'h', jobs: 'j' },
@@ -270,17 +273,23 @@ async function main (): Promise<boolean> {
const filenames = [];
if (opts._.length > 0) {
if (opts._.some((filename) => filename.endsWith('.h'))) {
throw new ErrorWithExitCode(
'Filenames must be for translation units, not headers', 3
);
}
filenames.push(...opts._.map((filename) => path.resolve(filename)));
} else {
filenames.push(
...(await findMatchingFiles(
path.resolve(SOURCE_ROOT, 'shell'),
(filename: string) => /.*\.(?:cc|h|mm)$/.test(filename)
(filename: string) => /.*\.(?:cc|mm)$/.test(filename)
))
);
}
return runClangTidy(outDir, filenames, opts.checks, opts.jobs);
return runClangTidy(outDir, filenames, opts.checks, opts.jobs, opts.fix);
}
if (require.main === module) {

View File

@@ -21,6 +21,7 @@ const fail = chalk.red('✗');
const FAILURE_STATUS_KEY = 'Electron_Spec_Runner_Failures';
const args = minimist(process.argv, {
boolean: ['skipYarnInstall'],
string: ['runners', 'target', 'electronVersion'],
number: ['enableRerun'],
unknown: arg => unknownFlags.push(arg)
@@ -36,10 +37,9 @@ for (const flag of unknownFlags) {
}
const utils = require('./lib/utils');
const { YARN_VERSION } = require('./yarn');
const { YARN_SCRIPT_PATH } = require('./yarn');
const BASE = path.resolve(__dirname, '../..');
const NPX_CMD = process.platform === 'win32' ? 'npx.cmd' : 'npx';
const runners = new Map([
['main', { description: 'Main process specs', run: runMainProcessElectronTests }]
@@ -96,7 +96,7 @@ async function main () {
const somethingChanged = (currentSpecHash !== lastSpecHash) ||
(lastSpecInstallHash !== currentSpecInstallHash);
if (somethingChanged) {
if (somethingChanged && !args.skipYarnInstall) {
await installSpecModules(path.resolve(__dirname, '..', 'spec'));
await getSpecHash().then(saveSpecHash);
}
@@ -375,7 +375,7 @@ async function runTestUsingElectron (specDir, testName, shouldRerun, additionalA
if (shouldRerun) {
await rerunFailedTests(specDir, testName);
} else {
return false;
process.exit(1);
}
}
console.log(`${pass} Electron ${testName} process tests passed.`);
@@ -419,7 +419,8 @@ async function installSpecModules (dir) {
if (fs.existsSync(path.resolve(dir, 'node_modules'))) {
await fs.promises.rm(path.resolve(dir, 'node_modules'), { force: true, recursive: true });
}
const { status } = childProcess.spawnSync(NPX_CMD, [`yarn@${YARN_VERSION}`, 'install', '--frozen-lockfile'], {
const yarnArgs = [YARN_SCRIPT_PATH, 'install', '--immutable'];
const { status } = childProcess.spawnSync(process.execPath, yarnArgs, {
env,
cwd: dir,
stdio: 'inherit',
@@ -429,14 +430,27 @@ async function installSpecModules (dir) {
console.log(`${fail} Failed to yarn install in '${dir}'`);
process.exit(1);
}
if (process.platform === 'linux') {
const { status: rebuildStatus } = childProcess.spawnSync('npm', ['rebuild', 'abstract-socket'], {
env,
cwd: dir,
stdio: 'inherit',
shell: process.platform === 'win32'
});
if (rebuildStatus !== 0) {
console.log(`${fail} Failed to rebuild abstract-socket native module`);
process.exit(1);
}
}
}
function getSpecHash () {
return Promise.all([
(async () => {
const hasher = crypto.createHash('SHA256');
hasher.update(fs.readFileSync(path.resolve(__dirname, '../yarn.lock')));
hasher.update(fs.readFileSync(path.resolve(__dirname, '../spec/package.json')));
hasher.update(fs.readFileSync(path.resolve(__dirname, '../spec/yarn.lock')));
hasher.update(fs.readFileSync(path.resolve(__dirname, '../script/spec-runner.js')));
return hasher.digest('hex');
})(),

Some files were not shown because too many files have changed in this diff Show More