Compare commits

..

93 Commits

Author SHA1 Message Date
trop[bot]
79ecc56d33 fix: param passed to showSaveDialogSync on Linux (#42679) 2024-06-27 19:50:20 +02:00
trop[bot]
6d7653383a fix: utilityProcess exit codes (#42396)
* fix: utilityProcess exit codes

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

* chore: update patches

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2024-06-25 19:01:13 +02:00
Robo
24faedab76 chore: cherry-pick d18460a2 from chromium (#42641)
* chore: cherry-pick d18460a2 from chromium

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2024-06-25 09:54:15 +02:00
Pedro Pontes
2eb7880cf1 chore: cherry-pick 3 changes from 1-M126 (#42618)
* chore: [29-x-y] cherry-pick 3 changes from 1-M126

* 8b400f9b7d66 from v8
* ba6cab40612d from v8
* 93c3cf1c787f from DirectXShaderCompiler

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2024-06-22 20:19:32 +02:00
Pedro Pontes
8ca9e1543d chore: [29-x-y] cherry-pick 3 changes from 0-M126 (#42603)
* chore: [29-x-y] cherry-pick 3 changes from 0-M126

* 33051b084850 from DirectXShaderCompiler
* b845fed99111 from DirectXShaderCompiler
* 9c6534f82db3 from dawn

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2024-06-21 10:52:15 -04:00
Pedro Pontes
fe869081b3 chore: [29-x-y] cherry-pick 7 changes from 3-M125 (#42589) 2024-06-21 12:28:08 +02:00
Pedro Pontes
914d8f373e chore: cherry-pick 5 changes from 1-M125 (#42572)
* chore: [29-x-y] cherry-pick 5 changes from 1-M125

* e7b64c6ee185 from v8
* 867c1001637e from DirectXShaderCompiler
* b922fcb61e3b from chromium
* bda89e1f7c71 from angle
* 0d9598145069 from chromium

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2024-06-20 20:28:09 +02:00
trop[bot]
0bd7092e74 chore: cherry-pick f8010390 from chromium (#42569)
* chore: cherry-pick f8010390 from chromium

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

* chore: update patches after trop

---------

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>
2024-06-19 11:16:02 +09:00
trop[bot]
5cdfdcdffb test: use longer timeout on contentTracing tests on WOA (#42552)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2024-06-18 18:51:30 -04:00
trop[bot]
fc5ee6d319 fix: don't observe WebUSB for in-memory partitions (#42463)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-06-12 14:53:12 -05:00
trop[bot]
0529300980 fix: restore wasOpenedAtLogin functionality (#42421)
fix: restore opened at login functionality

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-06-11 12:14:19 -05:00
trop[bot]
3a142b6c4f fix: multiple selection in //shell_dialogs Portal/KDE implementations (#42425)
* fix: multiple selection in //shell_dialogs portal implementation

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

* fix: allow multiple directory selection in KDE implementation

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

* chore: update patches

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2024-06-11 12:10:24 -05:00
trop[bot]
3fd34fc4b6 fix: bad js-flags shouldn't crash the app (#42442)
* fix: bad js-flags shouldn't crash the app

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

* Update shell/browser/javascript_environment.cc

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

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>
2024-06-11 12:10:16 -05:00
trop[bot]
dcf12182b8 fix: loginService -> loginItemService (#42405)
fix: loginService -> loginItemService

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-06-08 12:43:04 +02:00
trop[bot]
537e8c3bea refactor: improve cookie failure rejection messages (#42399)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-06-07 14:03:26 -04:00
trop[bot]
3041c956ce build: fix depot_tools patch (#42406)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-06-07 15:44:10 +02:00
trop[bot]
c57f515e43 fix: WebUSB should not crash when using in-memory partitions (#42363)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-06-04 23:56:55 +02:00
Max Schmitt
4b3d3a5f07 build: update typescript-definitions to 8.15.6 (#42285)
build: update typescript-definitions to 8.15.6 (#41900)

Co-authored-by: Samuel Attard <sam@electronjs.org>
2024-05-29 19:29:28 +02:00
trop[bot]
0b51976cd2 fix: calculate a hash for the Tag property of ToastNotification. (#42273)
* fix: calculate a hash for the Tag property of ToastNotification.

Co-authored-by: bill.shen <shenyb32768@gmail.com>

* fix: calculate a hash for the Tag property of ToastNotification.

Co-authored-by: bill.shen <shenyb32768@gmail.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: bill.shen <shenyb32768@gmail.com>
2024-05-27 10:00:54 +02:00
Keeley Hammond
4e1f54087d chore: cherry-pick 3e037e195e50 from v8 (#42256)
* chore: cherry-pick 3e037e195e50 from v8

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2024-05-23 11:03:34 +02:00
Pedro Pontes
d2ffa6fe31 chore: cherry-pick 3 changes from 0-M125 (#42220)
* chore: [29-x-y] cherry-pick 3 changes from 0-M125

* 6503a987d966 from v8
* 2a434fd0af6b from DirectXShaderCompiler
* 03609e39be8c from chromium

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2024-05-20 12:00:16 -07:00
Shelley Vohr
f7bb17ebd1 fix: setTitleBarOverlay should be implemented on BaseWindow (#42152) 2024-05-15 13:53:06 -04:00
Keeley Hammond
f9ed0eaee4 chore: cherry-pick b3c01ac1e60a from v8 (#42175)
* chore: cherry-pick b3c01ac1e60a from v8

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2024-05-14 16:28:24 -04:00
Shelley Vohr
8933e7e2a9 refactor: use //ui/shell_dialogs on Linux (#42144)
refactor: use //ui/shell_dialogs on Linux
2024-05-13 15:15:54 -04:00
Robo
262f4d34cf fix: backport patches making io_uring backend opt-in for libuv (#42128) 2024-05-12 10:05:06 +02:00
Keeley Hammond
b721d420d5 chore: cherry-pick f320600cd1f4 from v8 (#42123)
* chore: cherry-pick f320600cd1f4 from v8

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2024-05-10 15:34:16 -07:00
Samuel Attard
4517547f07 chore: cherry-pick b2cc7b7ac538 from chromium (#42097)
* chore: cherry-pick b2cc7b7ac538 from chromium

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2024-05-08 14:26:23 -07:00
Pedro Pontes
4f30f731ee chore: cherry-pick 1 changes from 3-M124 (#42090)
* chore: [29-x-y] cherry-pick 1 changes from 3-M124

* c67f290ef0f0 from angle

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2024-05-08 21:10:21 +02:00
Keeley Hammond
3b81b7efbc chore: cherry-pick 013961609785 from chromium (#42069) 2024-05-08 13:37:00 +02:00
trop[bot]
acd34fdca9 fix: avoid crash after upgrade on Linux (#42065)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: cptpcrd <31829097+cptpcrd@users.noreply.github.com>
2024-05-07 20:30:47 -04:00
Shelley Vohr
84ecd700db fix: do not defer construction by one microtick in streams (#42047) 2024-05-07 19:24:15 -04:00
Robo
cbc0f6720e chore: cherry-pick 22871e619f from chromium (#42057)
* chore: cherry-pick 22871e619f from chromium

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2024-05-07 19:23:12 -04:00
cptpcrd
8fbabeaca7 fix: cherry-pick fix thumbnail size patch for macOS (#42049)
* chore: cherry-pick fix thumbnail size patch for macOS

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2024-05-06 19:36:34 +02:00
Pedro Pontes
4c737147c3 chore: cherry-pick 1 changes from 0-M124 (#41984)
chore: [29-x-y] cherry-pick 2 changes from 0-M124

* 1b454576028b from chromium
* 0d9350b71fd0 from chromium

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2024-05-03 22:55:20 -04:00
Pedro Pontes
5ebc741819 chore: cherry-pick 2 changes from 2-M124 (#42007)
* chore: [29-x-y] cherry-pick 2 changes from 2-M124

* 98bcf9ef5cdd from chromium
* bd7aa9779873 from DirectXShaderCompiler

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2024-05-03 13:04:41 -04:00
Charles Kerr
cd6ad4d1bb chore: disable tests that require nut.js (#42022) 2024-05-02 21:26:45 -04:00
trop[bot]
19f0abd62e fix: recentDocuments on macOS not working (#41994)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-04-29 22:25:16 -04:00
Pedro Pontes
9d4f8a06e8 chore: cherry-pick 2 changes from 1-M124 (#41982)
* chore: [29-x-y] cherry-pick 2 changes from 1-M124

* bc18aec94c82 from DirectXShaderCompiler
* ba3b4e239620 from angle

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2024-04-29 09:26:27 -04:00
trop[bot]
a43014a410 build: work around ScreenCaptureKit bad feature flag parsing in Chromium (#41962)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-04-25 09:11:33 -04:00
trop[bot]
803698e2c4 docs: Windows typo in Tutorial document (#41950)
Update tutorial-6-publishing-updating.md

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: South Drifted <shiy2008@gmail.com>
2024-04-23 21:13:44 -05:00
trop[bot]
557cadddcb fix: offscreen rendering does not paint after gpu process crashed (#41923)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: zhangqi.67 <zhangqi.67@bytedance.com>
2024-04-23 13:54:10 -04:00
trop[bot]
fe01ed750a docs: correct the return value for canceled showSaveDialog (#41946)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Kilian Valkhof <kilian@kilianvalkhof.com>
2024-04-23 12:52:40 -04:00
trop[bot]
7f26c72af6 fix: EINVAL when spawning cmd files on Windows (#41907)
fix: EINVAL when spawning on Windows

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-04-19 16:42:06 -04:00
trop[bot]
7a3e587a1d chore: remove unused hash function (#41884)
Unused since e1e73fa #24115

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
2024-04-18 17:07:03 -04:00
Shelley Vohr
bf14d05830 fix: console.log() in AudioWorkletGlobalScope (#41889) 2024-04-18 14:38:06 -04:00
trop[bot]
384642792e chore: delete unused PrintPreviewMessageHandler (#41862)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-04-15 17:35:46 -05:00
Shelley Vohr
5bbac9ae30 test: add tests for Storage Access API (#41863) 2024-04-15 13:03:33 -05:00
trop[bot]
0da6411d11 fix: package <__assertion_handler> as part of libcxx headers (#41845)
Refs https://chromium-review.googlesource.com/c/chromium/src/+/5208502

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: deepak1556 <hop2deep@gmail.com>
2024-04-15 16:50:28 +09:00
Pedro Pontes
297be64122 chore: cherry-pick 3 changes from 3-M123 (#41854)
* chore: [29-x-y] cherry-pick 3 changes from 3-M123

* a65e511a14b4 from DirectXShaderCompiler
* f6672dbbe223 from angle
* 1b1f34234346 from chromium

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2024-04-14 17:01:18 -07:00
trop[bot]
1c47ba0a91 fix: silent printing default dpi on Windows (#41836)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-04-12 14:28:23 +02:00
trop[bot]
1cd7a71bb1 fix: WCO maximize button visibility when non-maximizable (#41807)
fix: WCO button visibility when non-maximizable

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-04-09 19:20:32 -04:00
David Sanders
feb81b6841 build: add Markdown lint check for unescaped angle brackets (#41800) 2024-04-09 12:07:48 +02:00
trop[bot]
a3d9e4be58 build: add missing header for content::SyntheticGestureTarget (#41798)
IWYU: add missing header for `content::SyntheticGestureTarget`

GNU libstdc++ does not allow using std::unique_ptr on incomplete types,
leading to a compile error.

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Bruno Pitrus <brunopitrus@hotmail.com>
2024-04-08 21:00:18 +02:00
Pedro Pontes
ec4683cd91 chore: cherry-pick 1 change from Release-2-M123 (#41775) 2024-04-05 13:03:04 -04:00
Erick Zhao
a02e0f0f02 docs: update node.js version for Electron 29 (#41774) 2024-04-04 16:25:34 -04:00
Alice Zhao
97eee463fa feat: add navigationHistory.getEntryAtIndex(int index) method (#41661)
* feat: add `navigationHistory.getEntryAtIndex(int index)` method (#41577)

* chore: remove code not related to this pr:

* test: fix flaky tests by replacing real urls with data urls

* test: remove hardcoded url
2024-04-04 13:09:19 -04:00
electron-roller[bot]
ed9a12cba7 chore: bump chromium to 122.0.6261.156 (29-x-y) (#41765)
* chore: bump chromium in DEPS to 122.0.6261.156

* 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>
2024-04-03 15:53:09 -04:00
trop[bot]
fe4d3a2484 docs: add missing headers option to ClientRequest options (#41730)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Jeremy Rose <jeremya@chromium.org>
2024-04-01 11:33:37 -04:00
Pedro Pontes
ad9a90ec53 chore: cherry-pick 8 changes from Release-1-M123 (#41746)
* chore: cherry-pick 8 changes from Release-1-M123

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2024-04-01 11:20:34 -04:00
trop[bot]
8647232c48 feat(serial): allow Bluetooth ports to be requested by service class ID (#41735)
* feat(serial): allow Bluetooth ports to be requested by service class ID

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

* fix: bluetooth dependency

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>
2024-04-01 10:55:37 -04:00
trop[bot]
f9e28e3e50 fix: Storage.{get|set|clear}Cookies via CDP not working (#41739)
* fix: Storage.{get|set|clear}Cookies via CDP not working

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

* chore: simplify BrowserContext plumbing

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>
2024-03-29 09:51:43 -05:00
trop[bot]
3698f89205 fix: don't do self-destroy in LibnotifyNotification::Dismiss() (#41707)
Callers of Notification::Dismiss() assume that the notification
instance is not deleted after the call, but this was not the case
for LibnotifyNotification:
- Destroy() would get `this` deleted.
- notify_notification_close() in portal environment triggers
LibnotifyNotification::OnNotificationClosed(), and finally calls
Destroy()

This patch removes all Destroy() in Dismiss(), and adds a boolean
to tell whether notify_notification_close() is running, to avoid crash
under portal environment.

Fixes #40461.

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: taoky <me@taoky.moe>
2024-03-28 12:10:03 +01:00
electron-roller[bot]
238cc80cef chore: bump chromium to 122.0.6261.148 (29-x-y) (#41711)
chore: bump chromium in DEPS to 122.0.6261.148

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2024-03-27 10:59:00 -05:00
trop[bot]
3b025ec0c7 test: add test and api_feature definition for chrome.scripting.globalParams (#41699)
chore: add test and api_feature for chrome.scripting.globalParams

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-03-27 10:20:29 +01:00
trop[bot]
d2c14f1c6c fix: crash on extension unload when script validation finishes (#41701)
https://chromium-review.googlesource.com/c/chromium/src/+/5225796

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-03-27 10:19:48 +01:00
Erick Zhao
0d3f50fc12 docs: backslash escape parametrized TypeScript types (#41692) 2024-03-26 12:28:42 +01:00
trop[bot]
d3da708f5c fix: WTF-8 decoding issue in node:fs (#41680)
fix: WTF-8 decoding issue in node:fs

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-03-25 14:39:29 +01:00
trop[bot]
e64c123d80 fix: normalize path before calling showItemInFolder and openPath (#41672)
* fix: normalize path before calling ShowItemInFolder

Co-authored-by: piotrpdev <piotrpdev@gmail.com>

* fix: normalize path before calling OpenPath

Co-authored-by: piotrpdev <piotrpdev@gmail.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: piotrpdev <piotrpdev@gmail.com>
2024-03-24 20:14:53 +01:00
trop[bot]
9ce58dd0ea ci: use CircleCI hosted macOS arm64 runners for testing (#41655)
* ci: use CircleCI hosted macOS arm64 runners for testing

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

* chore: update patches

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2024-03-21 19:02:13 -04:00
trop[bot]
4da7bff05f docs: nodejs trademark policy link broken (#41653)
* Fix broken Trademark Policy link

Co-authored-by: kghamilton89 <kghamilton@protonmail.com>

* add durable link

Per codebyter: https://github.com/electron/electron/pull/41558#discussion_r1522938560

Co-authored-by: Kenneth Gerald Hamilton <29099829+kghamilton89@users.noreply.github.com>

* chore: update patches

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: kghamilton89 <kghamilton@protonmail.com>
Co-authored-by: Kenneth Gerald Hamilton <29099829+kghamilton89@users.noreply.github.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2024-03-21 19:01:32 -04:00
electron-roller[bot]
53a7faa029 chore: bump chromium to 122.0.6261.139 (29-x-y) (#41634)
* chore: bump chromium in DEPS to 122.0.6261.139

* 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>
2024-03-21 09:39:44 -04:00
Pedro Pontes
d2177e4d08 chore: cherry-pick 1 change from Release-0-M123 (#41631) 2024-03-21 12:58:16 +01:00
trop[bot]
07f50757a3 fix: serial-port-added should respect filters (#41636)
fix: serial-port-added should respect filters

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-03-21 12:57:07 +01:00
trop[bot]
98283d1dae fix: missing badge text on Windows (#41628)
https://chromium-review.googlesource.com/c/chromium/src/+/5053607

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-03-19 11:36:21 -07:00
trop[bot]
d0fdc28c0e fix: account for potentially swapped FrameTreeNodeId in WebFrameMain (#41593)
fix: account for potentially swapped FrameTreeNodeId in WebFrameMain

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-03-14 13:02:40 -04:00
electron-roller[bot]
99dd9e2138 chore: bump chromium to 122.0.6261.130 (29-x-y) (#41598)
chore: bump chromium in DEPS to 122.0.6261.130

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2024-03-14 10:58:47 -04:00
electron-roller[bot]
c5a2873f8f chore: bump chromium to 122.0.6261.129 (29-x-y) (#41583)
chore: bump chromium in DEPS to 122.0.6261.129

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2024-03-13 14:15:29 -04:00
Keeley Hammond
1e34cdda96 fix: remove DXDiag telemetry code (#41574)
* fix: remove dxdiag telemetry

* fix: update methods in GPU info manager

* fix: update gpu_notify_when_dxdiag_request_fails
2024-03-12 21:51:20 -07:00
Calvin
880aee0aa7 chore: cherry-pick 2607ddacd643 from chromium (#41573)
* chore: cherry-pick 2607ddacd643 from chromium

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2024-03-12 16:17:11 -07:00
trop[bot]
c00489396b fix: chrome://process-internals failing to load (#41542)
fix: chrome://process-internals failing to load

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2024-03-12 20:35:47 +01:00
trop[bot]
30587d9700 docs: nativeImage api cleanup (#41569)
* docs: `nativeImage` api cleanup

Co-authored-by: Erick Zhao <erick@hotmail.ca>

* Update docs/api/native-image.md

Co-authored-by: Erick Zhao <erick@hotmail.ca>

* Update native-image.md

Co-authored-by: Erick Zhao <erick@hotmail.ca>

* Update docs/api/native-image.md

Co-authored-by: Felix Rieseberg <fr@makenotion.com>

Co-authored-by: Erick Zhao <erick@hotmail.ca>

* Update link to app icon

Co-authored-by: Alice Zhao <66543449+alicelovescake@users.noreply.github.com>

Co-authored-by: Erick Zhao <erick@hotmail.ca>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Erick Zhao <erick@hotmail.ca>
2024-03-12 19:41:48 +01:00
trop[bot]
ede0ebcc73 docs: Update code signing documentation (#41554)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Felix Rieseberg <fr@makenotion.com>
2024-03-12 12:45:38 -04:00
electron-roller[bot]
5966b42ac5 chore: bump chromium to 122.0.6261.112 (29-x-y) (#41552)
chore: bump chromium in DEPS to 122.0.6261.112

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2024-03-08 14:31:35 -05:00
John Kleinschmidt
33e61a19ef test: disable CapturableScreen tests on Windows x64 (#41544)
* test: disable CapturableScreen tests on Windows x64

(cherry picked from commit 60a288a2ca)

* test: disable js-execute-iframe" case should not crash on win 32-bit

(cherry picked from commit d545ae049b)
2024-03-08 09:29:28 -05:00
trop[bot]
a90c5b1b08 docs: correct release timeline inaccuracy (#41516)
docs: correct timeline inaccuracy

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-03-07 11:38:05 +01:00
electron-roller[bot]
06e01e5b76 chore: bump chromium to 122.0.6261.111 (29-x-y) (#41532)
chore: bump chromium in DEPS to 122.0.6261.111

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2024-03-07 10:17:44 +01:00
trop[bot]
96d053677d chore: add missing gin::Wrappable GetTypeName overrides (#41530)
chore: add missing gin::Wrappable GetTypeName overrides

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-03-06 11:02:30 -05:00
trop[bot]
8fe14665a0 fix: user-did-{resign|become}-active events on macOS (#41527)
fix: user-did-{resign|become}-active events on macOS

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-03-06 15:57:59 +01:00
Cheng Zhao
c9384a609e chore: update src_preload_function_for_environment.patch (#41501) 2024-03-04 10:00:39 -05:00
trop[bot]
fd2620bda4 fix: webContents.print options should be optional (#41479)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-03-01 17:08:55 -05:00
electron-roller[bot]
dc04802296 chore: bump chromium to 122.0.6261.95 (29-x-y) (#41489)
chore: bump chromium in DEPS to 122.0.6261.95

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2024-03-01 16:52:04 -05:00
electron-roller[bot]
90ca4e5f80 chore: bump chromium to 122.0.6261.94 (29-x-y) (#41451)
* chore: bump chromium in DEPS to 122.0.6261.94

* 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>
2024-02-28 11:32:54 -08:00
trop[bot]
5013150cfd ci: add logging to uploading to GitHub releases (#41458)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2024-02-28 12:54:24 +09:00
196 changed files with 11564 additions and 7073 deletions

View File

@@ -75,10 +75,6 @@ executors:
resource_class: << parameters.size >>
# Electron Runners
apple-silicon:
resource_class: electronjs/macos-arm64
machine: true
linux-arm:
resource_class: electronjs/aks-linux-arm-test
docker:
@@ -264,9 +260,9 @@ step-depot-tools-get: &step-depot-tools-get
index c305c248..e6e0fbdc 100755
--- a/gclient.py
+++ b/gclient.py
@@ -735,7 +735,8 @@ class Dependency(gclient_utils.WorkItem, DependencySettings):
if dep_type == 'cipd':
@@ -783,7 +783,8 @@ class Dependency(gclient_utils.WorkItem, DependencySettings):
not condition or "non_git_source" not in condition):
continue
cipd_root = self.GetCipdRoot()
- for package in dep_value.get('packages', []):
+ packages = dep_value.get('packages', [])
@@ -2296,8 +2292,10 @@ jobs:
- electron-tests:
artifact-key: darwin-x64
darwin-testing-arm64-tests:
executor: apple-silicon
darwin-testing-arm64-tests:
executor:
name: macos
size: macos.m1.medium.gen1
environment:
<<: *env-mac-large
<<: *env-stack-dumping
@@ -2321,7 +2319,9 @@ jobs:
artifact-key: mas-x64
mas-testing-arm64-tests:
executor: apple-silicon
executor:
name: macos
size: macos.m1.medium.gen1
environment:
<<: *env-mac-large
<<: *env-stack-dumping

View File

@@ -1,3 +1,17 @@
{
"extends": "@electron/lint-roller/configs/markdownlint.json"
"extends": "@electron/lint-roller/configs/markdownlint.json",
"no-angle-brackets": true,
"no-inline-html": {
"allowed_elements": [
"br",
"details",
"img",
"li",
"summary",
"ul",
"unknown",
"Tabs",
"TabItem",
]
}
}

View File

@@ -81,18 +81,11 @@ if (is_linux) {
]
}
# Generates electron_gtk_stubs.h header which contains
# stubs for extracting function ptrs from the gtk library.
# Function signatures for which stubs are required should be
# declared in electron_gtk.sigs, currently this file contains
# signatures for the functions used with native file chooser
# implementation. In future, this file can be extended to contain
# gtk4 stubs to switch gtk version in runtime.
# Generates headers which contain stubs for extracting function ptrs
# from the gtk library. Function signatures for which stubs are
# required should be declared in the sig files.
generate_stubs("electron_gtk_stubs") {
sigs = [
"shell/browser/ui/electron_gdk_pixbuf.sigs",
"shell/browser/ui/electron_gtk.sigs",
]
sigs = [ "shell/browser/ui/electron_gdk_pixbuf.sigs" ]
extra_header = "shell/browser/ui/electron_gtk.fragment"
output_name = "electron_gtk_stubs"
public_deps = [ "//ui/gtk:gtk_config" ]
@@ -473,6 +466,7 @@ source_set("electron_lib") {
"//net:extras",
"//net:net_resources",
"//printing/buildflags",
"//services/device/public/cpp/bluetooth:bluetooth",
"//services/device/public/cpp/geolocation",
"//services/device/public/cpp/hid",
"//services/device/public/mojom",
@@ -704,6 +698,8 @@ source_set("electron_lib") {
sources += [
"shell/browser/printing/print_view_manager_electron.cc",
"shell/browser/printing/print_view_manager_electron.h",
"shell/browser/printing/printing_utils.cc",
"shell/browser/printing/printing_utils.h",
"shell/renderer/printing/print_render_frame_helper_delegate.cc",
"shell/renderer/printing/print_render_frame_helper_delegate.h",
]
@@ -1468,8 +1464,10 @@ dist_zip("hunspell_dictionaries_zip") {
}
copy("libcxx_headers") {
sources = libcxx_headers + libcxx_licenses +
[ "//buildtools/third_party/libc++/__config_site" ]
sources = libcxx_headers + libcxx_licenses + [
"//buildtools/third_party/libc++/__assertion_handler",
"//buildtools/third_party/libc++/__config_site",
]
outputs = [ "$target_gen_dir/electron_libcxx_include/{{source_root_relative_dir}}/{{source_file_part}}" ]
}

2
DEPS
View File

@@ -2,7 +2,7 @@ gclient_gn_args_from = 'src'
vars = {
'chromium_version':
'122.0.6261.70',
'122.0.6261.156',
'node_version':
'v20.9.0',
'nan_version':

View File

@@ -112,4 +112,4 @@ and more can be found on the [Community page](https://www.electronjs.org/communi
[MIT](https://github.com/electron/electron/blob/main/LICENSE)
When using Electron logos, make sure to follow [OpenJS Foundation Trademark Policy](https://openjsf.org/wp-content/uploads/sites/84/2021/01/OpenJS-Foundation-Trademark-Policy-2021-01-12.docx.pdf).
When using Electron logos, make sure to follow [OpenJS Foundation Trademark Policy](https://trademark-policy.openjsf.org/).

View File

@@ -32,7 +32,7 @@ In most cases, you should do everything in the `ready` event handler.
Returns:
* `event` Event
* `launchInfo` Record<string, any> | [NotificationResponse](structures/notification-response.md) _macOS_
* `launchInfo` Record\<string, any\> | [NotificationResponse](structures/notification-response.md) _macOS_
Emitted once, when Electron has finished initializing. On macOS, `launchInfo`
holds the `userInfo` of the [`NSUserNotification`](https://developer.apple.com/documentation/foundation/nsusernotification)
@@ -970,7 +970,7 @@ app.setJumpList([
### `app.requestSingleInstanceLock([additionalData])`
* `additionalData` Record<any, any> (optional) - A JSON object containing additional data to send to the first instance.
* `additionalData` Record\<any, any\> (optional) - A JSON object containing additional data to send to the first instance.
Returns `boolean`
@@ -1261,7 +1261,7 @@ Returns `Object`:
* `openAtLogin` boolean - `true` if the app is set to open at login.
* `openAsHidden` boolean _macOS_ _Deprecated_ - `true` if the app is set to open as hidden at login. This does not work on macOS 13 and up.
* `wasOpenedAtLogin` boolean _macOS_ _Deprecated_ - `true` if the app was opened at login automatically. This setting is not available on [MAS builds][mas-builds] or on macOS 13 and up.
* `wasOpenedAtLogin` boolean _macOS_ - `true` if the app was opened at login automatically.
* `wasOpenedAsHidden` boolean _macOS_ _Deprecated_ - `true` if the app was opened as a hidden login item. This indicates that the app should not open any windows at startup. This setting is not available on [MAS builds][mas-builds] or on macOS 13 and up.
* `restoreState` boolean _macOS_ _Deprecated_ - `true` if the app was opened as a login item that should restore the state from the previous session. This indicates that the app should restore the windows that were open the last time the app was closed. This setting is not available on [MAS builds][mas-builds] or on macOS 13 and up.
* `status` string _macOS_ - can be one of `not-registered`, `enabled`, `requires-approval`, or `not-found`.

View File

@@ -103,7 +103,7 @@ The `autoUpdater` object has the following methods:
* `options` Object
* `url` string
* `headers` Record<string, string> (optional) _macOS_ - HTTP request headers.
* `headers` Record\<string, string\> (optional) _macOS_ - HTTP request headers.
* `serverType` string (optional) _macOS_ - Can be `json` or `default`, see the [Squirrel.Mac][squirrel-mac]
README for more information.

View File

@@ -775,7 +775,7 @@ Closes the currently open [Quick Look][quick-look] panel.
#### `win.setBounds(bounds[, animate])`
* `bounds` Partial<[Rectangle](structures/rectangle.md)>
* `bounds` Partial\<[Rectangle](structures/rectangle.md)\>
* `animate` boolean (optional) _macOS_
Resizes and moves the window to the supplied bounds. Any properties that are not supplied will default to their current values.
@@ -1211,7 +1211,7 @@ win.loadURL('http://localhost:8000/post', {
* `filePath` string
* `options` Object (optional)
* `query` Record<string, string> (optional) - Passed to `url.format()`.
* `query` Record\<string, string\> (optional) - Passed to `url.format()`.
* `search` string (optional) - Passed to `url.format()`.
* `hash` string (optional) - Passed to `url.format()`.

View File

@@ -17,6 +17,8 @@ following properties:
method.
* `url` string (optional) - The request URL. Must be provided in the absolute
form with the protocol scheme specified as http or https.
* `headers` Record\<string, string | string[]\> (optional) - Headers to be sent
with the request.
* `session` Session (optional) - The [`Session`](session.md) instance with
which the request is associated.
* `partition` string (optional) - The name of the [`partition`](session.md)
@@ -158,7 +160,7 @@ Returns:
* `statusCode` Integer
* `method` string
* `redirectUrl` string
* `responseHeaders` Record<string, string[]>
* `responseHeaders` Record\<string, string[]\>
Emitted when the server returns a redirect response (e.g. 301 Moved
Permanently). Calling [`request.followRedirect`](#requestfollowredirect) will

View File

@@ -59,14 +59,14 @@ The `crashReporter` module has the following methods:
number of crashes uploaded to 1/hour. Default is `false`.
* `compress` boolean (optional) - If true, crash reports will be compressed
and uploaded with `Content-Encoding: gzip`. Default is `true`.
* `extra` Record<string, string> (optional) - Extra string key/value
* `extra` Record\<string, string\> (optional) - Extra string key/value
annotations that will be sent along with crash reports that are generated
in the main process. Only string values are supported. Crashes generated in
child processes will not contain these extra
parameters to crash reports generated from child processes, call
[`addExtraParameter`](#crashreporteraddextraparameterkey-value) from the
child process.
* `globalExtra` Record<string, string> (optional) - Extra string key/value
* `globalExtra` Record\<string, string\> (optional) - Extra string key/value
annotations that will be sent along with any crash reports generated in any
process. These annotations cannot be changed once the crash reporter has
been started. If a key is present in both the global extra parameters and

View File

@@ -174,7 +174,7 @@ dialog.showOpenDialog(mainWindow, {
* `dontAddToRecent` _Windows_ - Do not add the item being saved to the recent documents list.
* `securityScopedBookmarks` boolean (optional) _macOS_ _mas_ - Create a [security scoped bookmark](https://developer.apple.com/library/content/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW16) when packaged for the Mac App Store. If this option is enabled and the file doesn't already exist a blank file will be created at the chosen path.
Returns `string | undefined`, the path of the file chosen by the user; if the dialog is cancelled it returns `undefined`.
Returns `string`, the path of the file chosen by the user; if the dialog is cancelled it returns an empty string.
The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal.
@@ -207,7 +207,7 @@ The `filters` specifies an array of file types that can be displayed, see
Returns `Promise<Object>` - Resolve with an object containing the following:
* `canceled` boolean - whether or not the dialog was canceled.
* `filePath` string (optional) - If the dialog is canceled, this will be `undefined`.
* `filePath` string - If the dialog is canceled, this will be an empty string.
* `bookmark` string (optional) _macOS_ _mas_ - Base64 encoded string which contains the security scoped bookmark data for the saved file. `securityScopedBookmarks` must be enabled for this to be present. (For return values, see [table here](#bookmarks-array).)
The `browserWindow` argument allows the dialog to attach itself to a parent window, making it modal.

View File

@@ -72,7 +72,7 @@ Removes listeners of the specified `channel`.
### `ipcMain.handle(channel, listener)`
* `channel` string
* `listener` Function<Promise\<any&#62; | any&#62;
* `listener` Function\<Promise\<any\> | any\>
* `event` [IpcMainInvokeEvent][ipc-main-invoke-event]
* `...args` any[]
@@ -109,7 +109,7 @@ provided to the renderer process. Please refer to
### `ipcMain.handleOnce(channel, listener)`
* `channel` string
* `listener` Function<Promise\<any&#62; | any&#62;
* `listener` Function\<Promise\<any\> | any\>
* `event` [IpcMainInvokeEvent][ipc-main-invoke-event]
* `...args` any[]

View File

@@ -4,36 +4,41 @@
Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process)
In Electron, for the APIs that take images, you can pass either file paths or
`NativeImage` instances. An empty image will be used when `null` is passed.
The `nativeImage` module provides a unified interface for manipulating
system images. These can be handy if you want to provide multiple scaled
versions of the same icon or take advantage of macOS [template images][template-image].
For example, when creating a tray or setting a window's icon, you can pass an
image file path as a `string`:
Electron APIs that take image files accept either file paths or
`NativeImage` instances. An empty and transparent image will be used when `null` is passed.
```js
For example, when creating a [Tray](../api/tray.md) or setting a [BrowserWindow](../api/browser-window.md)'s
icon, you can either pass an image file path as a string:
```js title='Main Process'
const { BrowserWindow, Tray } = require('electron')
const appIcon = new Tray('/Users/somebody/images/icon.png')
const tray = new Tray('/Users/somebody/images/icon.png')
const win = new BrowserWindow({ icon: '/Users/somebody/images/window.png' })
console.log(appIcon, win)
```
Or read the image from the clipboard, which returns a `NativeImage`:
or generate a `NativeImage` instance from the same file:
```js
const { clipboard, Tray } = require('electron')
const image = clipboard.readImage()
const appIcon = new Tray(image)
console.log(appIcon)
```js title='Main Process'
const { BrowserWindow, nativeImage, Tray } = require('electron')
const trayIcon = nativeImage.createFromPath('/Users/somebody/images/icon.png')
const appIcon = nativeImage.createFromPath('/Users/somebody/images/window.png')
const tray = new Tray(trayIcon)
const win = new BrowserWindow({ icon: appIcon })
```
## Supported Formats
Currently `PNG` and `JPEG` image formats are supported. `PNG` is recommended
because of its support for transparency and lossless compression.
Currently, `PNG` and `JPEG` image formats are supported across all platforms.
`PNG` is recommended because of its support for transparency and lossless compression.
On Windows, you can also load `ICO` icons from file paths. For best visual
quality, it is recommended to include at least the following sizes in the:
quality, we recommend including at least the following sizes:
* Small icon
* 16x16 (100% DPI scale)
@@ -47,9 +52,9 @@ quality, it is recommended to include at least the following sizes in the:
* 64x64 (200% DPI scale)
* 256x256
Check the _Size requirements_ section in [this article][icons].
Check the _Icon Scaling_ section in the Windows [App Icon Construction][icons] reference.
[icons]: https://learn.microsoft.com/en-us/windows/win32/uxguide/vis-icons
[icons]: https://learn.microsoft.com/en-us/windows/apps/design/style/iconography/app-icon-construction#icon-scaling
:::note
@@ -60,16 +65,17 @@ image encoding and decoding.
## High Resolution Image
On platforms that have high-DPI support such as Apple Retina displays, you can
append `@2x` after image's base filename to mark it as a high resolution image.
On platforms that support high pixel density displays (such as Apple Retina),
you can append `@2x` after image's base filename to mark it as a 2x scale
high resolution image.
For example, if `icon.png` is a normal image that has standard resolution, then
`icon@2x.png` will be treated as a high resolution image that has double DPI
density.
`icon@2x.png` will be treated as a high resolution image that has double
Dots per Inch (DPI) density.
If you want to support displays with different DPI densities at the same time,
you can put images with different sizes in the same folder and use the filename
without DPI suffixes. For example:
without DPI suffixes within Electron. For example:
```plaintext
images/
@@ -78,10 +84,9 @@ images/
└── icon@3x.png
```
```js
```js title='Main Process'
const { Tray } = require('electron')
const appIcon = new Tray('/Users/somebody/images/icon.png')
console.log(appIcon)
const appTray = new Tray('/Users/somebody/images/icon.png')
```
The following suffixes for DPI are also supported:
@@ -98,27 +103,23 @@ The following suffixes for DPI are also supported:
* `@4x`
* `@5x`
## Template Image
## Template Image _macOS_
Template images consist of black and an alpha channel.
On macOS, [template images][template-image] consist of black and an alpha channel.
Template images are not intended to be used as standalone images and are usually
mixed with other content to create the desired final appearance.
The most common case is to use template images for a menu bar icon, so it can
The most common case is to use template images for a menu bar (Tray) icon, so it can
adapt to both light and dark menu bars.
**Note:** Template image is only supported on macOS.
To mark an image as a template image, its filename should end with the word
`Template`. For example:
* `xxxTemplate.png`
* `xxxTemplate@2x.png`
To mark an image as a template image, its base filename should end with the word
`Template` (e.g. `xxxTemplate.png`). You can also specify template images at
different DPI densities (e.g. `xxxTemplate@2x.png`).
## Methods
The `nativeImage` module has the following methods, all of which return
an instance of the `NativeImage` class:
an instance of the [`NativeImage`](#class-nativeimage) class:
### `nativeImage.createEmpty()`
@@ -137,7 +138,7 @@ Note: The Windows implementation will ignore `size.height` and scale the height
### `nativeImage.createFromPath(path)`
* `path` string
* `path` string - path to a file that we intend to construct an image out of.
Returns `NativeImage`
@@ -146,7 +147,7 @@ returns an empty image if the `path` does not exist, cannot be read, or is not
a valid image.
```js
const nativeImage = require('electron').nativeImage
const { nativeImage } = require('electron')
const image = nativeImage.createFromPath('/Users/somebody/images/icon.png')
console.log(image)
@@ -183,7 +184,7 @@ Creates a new `NativeImage` instance from `buffer`. Tries to decode as PNG or JP
Returns `NativeImage`
Creates a new `NativeImage` instance from `dataURL`.
Creates a new `NativeImage` instance from `dataUrl`, a base 64 encoded [Data URL][data-url] string.
### `nativeImage.createFromNamedImage(imageName[, hslShift])` _macOS_
@@ -192,14 +193,14 @@ Creates a new `NativeImage` instance from `dataURL`.
Returns `NativeImage`
Creates a new `NativeImage` instance from the NSImage that maps to the
given image name. See [`System Icons`](https://developer.apple.com/design/human-interface-guidelines/macos/icons-and-images/system-icons/)
for a list of possible values.
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.
The `hslShift` is applied to the image with the following rules:
* `hsl_shift[0]` (hue): The absolute hue value for the image - 0 and 1 map
to 0 and 360 on the hue color wheel (red).
to 0 and 360 on the hue color wheel (red).
* `hsl_shift[1]` (saturation): A saturation shift for the image, with the
following key values:
0 = remove all color.
@@ -216,7 +217,9 @@ This means that `[-1, 0, 1]` will make the image completely white and
In some cases, the `NSImageName` doesn't match its string representation; one example of this is `NSFolderImageName`, whose string representation would actually be `NSFolder`. Therefore, you'll need to determine the correct string representation for your image before passing it in. This can be done with the following:
`echo -e '#import <Cocoa/Cocoa.h>\nint main() { NSLog(@"%@", SYSTEM_IMAGE_NAME); }' | clang -otest -x objective-c -framework Cocoa - && ./test`
```sh
echo -e '#import <Cocoa/Cocoa.h>\nint main() { NSLog(@"%@", SYSTEM_IMAGE_NAME); }' | clang -otest -x objective-c -framework Cocoa - && ./test
```
where `SYSTEM_IMAGE_NAME` should be replaced with any value from [this list](https://developer.apple.com/documentation/appkit/nsimagename?language=objc).
@@ -257,7 +260,7 @@ data.
* `options` Object (optional)
* `scaleFactor` Number (optional) - Defaults to 1.0.
Returns `string` - The data URL of the image.
Returns `string` - The [Data URL][data-url] of the image.
#### `image.getBitmap([options])`
@@ -273,7 +276,7 @@ current event loop tick; otherwise the data might be changed or destroyed.
#### `image.getNativeHandle()` _macOS_
Returns `Buffer` - A [Buffer][buffer] that stores C pointer to underlying native handle of
the image. On macOS, a pointer to `NSImage` instance would be returned.
the image. On macOS, a pointer to `NSImage` instance is returned.
Notice that the returned pointer is a weak pointer to the underlying native
image instead of a copy, so you _must_ ensure that the associated
@@ -295,11 +298,11 @@ If `scaleFactor` is passed, this will return the size corresponding to the image
* `option` boolean
Marks the image as a template image.
Marks the image as a macOS [template image][template-image].
#### `image.isTemplateImage()`
Returns `boolean` - Whether the image is a template image.
Returns `boolean` - Whether the image is a macOS [template image][template-image].
#### `image.crop(rect)`
@@ -328,13 +331,13 @@ will be preserved in the resized image.
* `scaleFactor` Number (optional) - Defaults to 1.0.
Returns `Number` - The image's aspect ratio.
Returns `Number` - The image's aspect ratio (width divided by height).
If `scaleFactor` is passed, this will return the aspect ratio corresponding to the image representation most closely matching the passed value.
#### `image.getScaleFactors()`
Returns `Number[]` - An array of all scale factors corresponding to representations for a given nativeImage.
Returns `Number[]` - An array of all scale factors corresponding to representations for a given `NativeImage`.
#### `image.addRepresentation(options)`
@@ -349,15 +352,17 @@ Returns `Number[]` - An array of all scale factors corresponding to representati
encoded PNG or JPEG image.
Add an image representation for a specific scale factor. This can be used
to explicitly add different scale factor representations to an image. This
to programmatically add different scale factor representations to an image. This
can be called on empty images.
[buffer]: https://nodejs.org/api/buffer.html#buffer_class_buffer
### Instance Properties
#### `nativeImage.isMacTemplateImage` _macOS_
A `boolean` property that determines whether the image is considered a [template image](https://developer.apple.com/documentation/appkit/nsimage/1520017-template).
A `boolean` property that determines whether the image is considered a [template image][template-image].
Please note that this property only has an effect on macOS.
[buffer]: https://nodejs.org/api/buffer.html#buffer_class_buffer
[data-url]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs
[template-image]: https://developer.apple.com/documentation/appkit/nsimage/1520017-template

View File

@@ -0,0 +1,29 @@
## Class: NavigationHistory
> Manage a list of navigation entries, representing the user's browsing history within the application.
Process: [Main](../glossary.md#main-process)<br />
_This class is not exported from the `'electron'` module. It is only available as a return value of other methods in the Electron API._
Each navigation entry corresponds to a specific page. The indexing system follows a sequential order, where the first available navigation entry is at index 0, representing the earliest visited page, and the latest navigation entry is at index N, representing the most recent page. Maintaining this ordered list of navigation entries enables seamless navigation both backward and forward through the user's browsing history.
### Instance Methods
#### `navigationHistory.getActiveIndex()`
Returns `Integer` - The index of the current page, from which we would go back/forward or reload.
#### `navigationHistory.getEntryAtIndex(index)`
* `index` Integer
Returns `Object`:
* `url` string - The URL of the navigation entry at the given index.
* `title` string - The page title of the navigation entry at the given index.
If index is out of bounds (greater than history length or less than 0), null will be returned.
#### `navigationHistory.length()`
Returns `Integer` - History length.

View File

@@ -111,7 +111,7 @@ expect streaming responses.
* `scheme` string - scheme to handle, for example `https` or `my-app`. This is
the bit before the `:` in a URL.
* `handler` Function<[GlobalResponse](https://nodejs.org/api/globals.html#response) | Promise<GlobalResponse>>
* `handler` Function\<[GlobalResponse](https://nodejs.org/api/globals.html#response) | Promise\<GlobalResponse\>\>
* `request` [GlobalRequest](https://nodejs.org/api/globals.html#request)
Register a protocol handler for `scheme`. Requests made to URLs with this

View File

@@ -27,7 +27,7 @@ The `pushNotification` module emits the following events:
Returns:
* `event` Event
* `userInfo` Record<String, any>
* `userInfo` Record\<String, any\>
Emitted when the app receives a remote notification while running.
See: https://developer.apple.com/documentation/appkit/nsapplicationdelegate/1428430-application?language=objc

View File

@@ -813,6 +813,8 @@ win.webContents.session.setCertificateVerifyProc((request, callback) => {
* `pointerLock` - Request to directly interpret mouse movements as an input method via the [Pointer Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API). These requests always appear to originate from the main frame.
* `keyboardLock` - Request capture of keypresses for any or all of the keys on the physical keyboard via the [Keyboard Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Keyboard/lock). These requests always appear to originate from the main frame.
* `openExternal` - Request to open links in external applications.
* `storage-access` - Allows content loaded in a third-party context to request access to third-party cookies using the [Storage Access API](https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API).
* `top-level-storage-access` - Allow top-level sites to request third-party cookie access on behalf of embedded content originating from another site in the same related website set using the [Storage Access API](https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API).
* `window-management` - Request access to enumerate screens using the [`getScreenDetails`](https://developer.chrome.com/en/articles/multi-screen-window-placement/) API.
* `unknown` - An unrecognized permission request.
* `callback` Function
@@ -861,6 +863,8 @@ session.fromPartition('some-partition').setPermissionRequestHandler((webContents
* `openExternal` - Open links in external applications.
* `pointerLock` - Directly interpret mouse movements as an input method via the [Pointer Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API). These requests always appear to originate from the main frame.
* `serial` - Read from and write to serial devices with the [Web Serial API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Serial_API).
* `storage-access` - Allows content loaded in a third-party context to request access to third-party cookies using the [Storage Access API](https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API).
* `top-level-storage-access` - Allow top-level sites to request third-party cookie access on behalf of embedded content originating from another site in the same related website set using the [Storage Access API](https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API).
* `usb` - Expose non-standard Universal Serial Bus (USB) compatible devices services to the web with the [WebUSB API](https://developer.mozilla.org/en-US/docs/Web/API/WebUSB_API).
* `requestingOrigin` string - The origin URL of the permission check
* `details` Object - Some properties are only available on certain permission types.
@@ -1215,7 +1219,7 @@ Returns `Promise<Buffer>` - resolves with blob data.
* `url` string
* `options` Object (optional)
* `headers` Record<string, string> (optional) - HTTP request headers.
* `headers` Record\<string, string\> (optional) - HTTP request headers.
Initiates a download of the resource at `url`.
The API will generate a [DownloadItem](download-item.md) that can be accessed

View File

@@ -1,4 +1,4 @@
# FilePathWithHeaders Object
* `path` string - The path to the file to send.
* `headers` Record<string, string> (optional) - Additional headers to be sent.
* `headers` Record\<string, string\> (optional) - Additional headers to be sent.

View File

@@ -3,5 +3,5 @@
* `actionIdentifier` string - The identifier string of the action that the user selected.
* `date` number - The delivery date of the notification.
* `identifier` string - The unique identifier for this notification request.
* `userInfo` Record<string, any> - A dictionary of custom information associated with the notification.
* `userInfo` Record\<string, any\> - A dictionary of custom information associated with the notification.
* `userText` string (optional) - The text entered or chosen by the user.

View File

@@ -4,4 +4,4 @@
* `referrer` string
* `method` string
* `uploadData` [UploadData[]](upload-data.md) (optional)
* `headers` Record<string, string>
* `headers` Record\<string, string\>

View File

@@ -10,7 +10,7 @@
`"text/html"`. Setting `mimeType` would implicitly set the `content-type`
header in response, but if `content-type` is already set in `headers`, the
`mimeType` would be ignored.
* `headers` Record<string, string | string[]> (optional) - An object containing the response headers. The
* `headers` Record\<string, string | string[]\> (optional) - An object containing the response headers. The
keys must be string, and values must be either string or Array of string.
* `data` (Buffer | string | ReadableStream) (optional) - The response body. When
returning stream as response, this is a Node.js readable stream representing

View File

@@ -19,7 +19,7 @@
include in the trace. If not specified, trace all processes.
* `histogram_names` string[] (optional) - a list of [histogram][] names to report
with the trace.
* `memory_dump_config` Record<string, any> (optional) - if the
* `memory_dump_config` Record\<string, any\> (optional) - if the
`disabled-by-default-memory-infra` category is enabled, this contains
optional additional configuration for data collection. See the [Chromium
memory-infra docs][memory-infra docs] for more information.

View File

@@ -36,7 +36,7 @@ Returns `boolean` - Whether the Swipe between pages setting is on.
### `systemPreferences.postNotification(event, userInfo[, deliverImmediately])` _macOS_
* `event` string
* `userInfo` Record<string, any>
* `userInfo` Record\<string, any\>
* `deliverImmediately` boolean (optional) - `true` to post notifications immediately even when the subscribing app is inactive.
Posts `event` as native notifications of macOS. The `userInfo` is an Object
@@ -45,7 +45,7 @@ that contains the user information dictionary sent along with the notification.
### `systemPreferences.postLocalNotification(event, userInfo)` _macOS_
* `event` string
* `userInfo` Record<string, any>
* `userInfo` Record\<string, any\>
Posts `event` as native notifications of macOS. The `userInfo` is an Object
that contains the user information dictionary sent along with the notification.
@@ -53,7 +53,7 @@ that contains the user information dictionary sent along with the notification.
### `systemPreferences.postWorkspaceNotification(event, userInfo)` _macOS_
* `event` string
* `userInfo` Record<string, any>
* `userInfo` Record\<string, any\>
Posts `event` as native notifications of macOS. The `userInfo` is an Object
that contains the user information dictionary sent along with the notification.
@@ -63,7 +63,7 @@ that contains the user information dictionary sent along with the notification.
* `event` string | null
* `callback` Function
* `event` string
* `userInfo` Record<string, unknown>
* `userInfo` Record\<string, unknown\>
* `object` string
Returns `number` - The ID of this subscription
@@ -92,7 +92,7 @@ If `event` is null, the `NSDistributedNotificationCenter` doesnt use it as cr
* `event` string | null
* `callback` Function
* `event` string
* `userInfo` Record<string, unknown>
* `userInfo` Record\<string, unknown\>
* `object` string
Returns `number` - The ID of this subscription
@@ -107,7 +107,7 @@ If `event` is null, the `NSNotificationCenter` doesnt use it as criteria for
* `event` string | null
* `callback` Function
* `event` string
* `userInfo` Record<string, unknown>
* `userInfo` Record\<string, unknown\>
* `object` string
Returns `number` - The ID of this subscription
@@ -137,7 +137,7 @@ Same as `unsubscribeNotification`, but removes the subscriber from `NSWorkspace.
### `systemPreferences.registerDefaults(defaults)` _macOS_
* `defaults` Record<string, string | boolean | number> - a dictionary of (`key: value`) user defaults
* `defaults` Record\<string, string | boolean | number\> - a dictionary of (`key: value`) user defaults
Add the specified defaults to your application's `NSUserDefaults`.

View File

@@ -60,7 +60,7 @@ app.whenReady().then(() => {
**MacOS**
* Icons passed to the Tray constructor should be [Template Images](native-image.md#template-image).
* Icons passed to the Tray constructor should be [Template Images](native-image.md#template-image-macos).
* To make sure your icon isn't grainy on retina monitors, be sure your `@2x` image is 144dpi.
* If you are bundling your application (e.g., with webpack for development), be sure that the file names are not being mangled or hashed. The filename needs to end in Template, and the `@2x` image needs to have the same filename as the standard image, or MacOS will not magically invert your image's colors or use the high density image.
* 16x16 (72dpi) and 32x32@2x (144dpi) work well for most icons.

View File

@@ -237,7 +237,7 @@ See [`window.open()`](window-open.md) for more details and how to use this in co
Returns:
* `details` Event<>
* `details` Event\<\>
* `url` string - The URL the frame is navigating to.
* `isSameDocument` boolean - This event does not fire for same document navigations using window.history api and reference fragment navigations.
This property is always set to `false` for this event.
@@ -270,7 +270,7 @@ Calling `event.preventDefault()` will prevent the navigation.
Returns:
* `details` Event<>
* `details` Event\<\>
* `url` string - The URL the frame is navigating to.
* `isSameDocument` boolean - This event does not fire for same document navigations using window.history api and reference fragment navigations.
This property is always set to `false` for this event.
@@ -300,7 +300,7 @@ Calling `event.preventDefault()` will prevent the navigation.
Returns:
* `details` Event<>
* `details` Event\<\>
* `url` string - The URL the frame is navigating to.
* `isSameDocument` boolean - Whether the navigation happened without changing
document. Examples of same document navigations are reference fragment
@@ -324,7 +324,7 @@ Emitted when any frame (including main) starts navigating.
Returns:
* `details` Event<>
* `details` Event\<\>
* `url` string - The URL the frame is navigating to.
* `isSameDocument` boolean - Whether the navigation happened without changing
document. Examples of same document navigations are reference fragment
@@ -355,7 +355,7 @@ redirect).
Returns:
* `details` Event<>
* `details` Event\<\>
* `url` string - The URL the frame is navigating to.
* `isSameDocument` boolean - Whether the navigation happened without changing
document. Examples of same document navigations are reference fragment
@@ -674,7 +674,7 @@ Emitted when media is paused or done playing.
Returns:
* `event` Event<>
* `event` Event\<\>
* `audible` boolean - True if one or more frames or child `webContents` are emitting audio.
Emitted when media becomes audible or inaudible.
@@ -894,7 +894,7 @@ Returns:
* `webPreferences` [WebPreferences](structures/web-preferences.md) - The web preferences that will be used by the guest
page. This object can be modified to adjust the preferences for the guest
page.
* `params` Record<string, string> - The other `<webview>` parameters such as the `src` URL.
* `params` Record\<string, string\> - The other `<webview>` parameters such as the `src` URL.
This object can be modified to adjust the parameters of the guest page.
Emitted when a `<webview>`'s web contents is being attached to this web
@@ -1014,7 +1014,7 @@ win.webContents.loadURL('https://github.com', options)
* `filePath` string
* `options` Object (optional)
* `query` Record<string, string> (optional) - Passed to `url.format()`.
* `query` Record\<string, string\> (optional) - Passed to `url.format()`.
* `search` string (optional) - Passed to `url.format()`.
* `hash` string (optional) - Passed to `url.format()`.
@@ -1045,7 +1045,7 @@ win.loadFile('src/index.html')
* `url` string
* `options` Object (optional)
* `headers` Record<string, string> (optional) - HTTP request headers.
* `headers` Record\<string, string\> (optional) - HTTP request headers.
Initiates a download of the resource at `url` without navigating. The
`will-download` event of `session` will be triggered.
@@ -1282,7 +1282,7 @@ Ignore application menu shortcuts while this web contents is focused.
#### `contents.setWindowOpenHandler(handler)`
* `handler` Function<{action: 'deny'} | {action: 'allow', outlivesOpener?: boolean, overrideBrowserWindowOptions?: BrowserWindowConstructorOptions}>
* `handler` Function\<{action: 'deny'} | {action: 'allow', outlivesOpener?: boolean, overrideBrowserWindowOptions?: BrowserWindowConstructorOptions}\>
* `details` Object
* `url` string - The _resolved_ version of the URL passed to `window.open()`. e.g. opening a window with `window.open('foo')` will yield something like `https://the-origin/the/current/path/foo`.
* `frameName` string - Name of the window provided in `window.open()`
@@ -1560,7 +1560,7 @@ Returns `Promise<PrinterInfo[]>` - Resolves with a [`PrinterInfo[]`](structures/
* `from` number - Index of the first page to print (0-based).
* `to` number - Index of the last page to print (inclusive) (0-based).
* `duplexMode` string (optional) - Set the duplex mode of the printed web page. Can be `simplex`, `shortEdge`, or `longEdge`.
* `dpi` Record<string, number> (optional)
* `dpi` Record\<string, number\> (optional)
* `horizontal` number (optional) - The horizontal dpi.
* `vertical` number (optional) - The vertical dpi.
* `header` string (optional) - string to be printed as page header.
@@ -2200,6 +2200,10 @@ A `Integer` representing the unique ID of this WebContents. Each ID is unique am
A [`Session`](session.md) used by this webContents.
#### `contents.navigationHistory` _Readonly_
A [`NavigationHistory`](navigation-history.md) used by this webContents.
#### `contents.hostWebContents` _Readonly_
A [`WebContents`](web-contents.md) instance that might own this `WebContents`.

View File

@@ -99,11 +99,11 @@ Some examples of valid `urls`:
* `referrer` string
* `timestamp` Double
* `uploadData` [UploadData[]](structures/upload-data.md) (optional)
* `requestHeaders` Record<string, string>
* `requestHeaders` Record\<string, string\>
* `callback` Function
* `beforeSendResponse` Object
* `cancel` boolean (optional)
* `requestHeaders` Record<string, string | string[]> (optional) - When provided, request will be made
* `requestHeaders` Record\<string, string | string[]\> (optional) - When provided, request will be made
with these headers.
The `listener` will be called with `listener(details, callback)` before sending
@@ -126,7 +126,7 @@ The `callback` has to be called with a `response` object.
* `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`.
* `referrer` string
* `timestamp` Double
* `requestHeaders` Record<string, string>
* `requestHeaders` Record\<string, string\>
The `listener` will be called with `listener(details)` just before a request is
going to be sent to the server, modifications of previous `onBeforeSendHeaders`
@@ -148,11 +148,11 @@ response are visible by the time this listener is fired.
* `timestamp` Double
* `statusLine` string
* `statusCode` Integer
* `responseHeaders` Record<string, string[]> (optional)
* `responseHeaders` Record\<string, string[]\> (optional)
* `callback` Function
* `headersReceivedResponse` Object
* `cancel` boolean (optional)
* `responseHeaders` Record<string, string | string[]> (optional) - When provided, the server is assumed
* `responseHeaders` Record\<string, string | string[]\> (optional) - When provided, the server is assumed
to have responded with these headers.
* `statusLine` string (optional) - Should be provided when overriding
`responseHeaders` to change header status otherwise original response
@@ -177,7 +177,7 @@ The `callback` has to be called with a `response` object.
* `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`.
* `referrer` string
* `timestamp` Double
* `responseHeaders` Record<string, string[]> (optional)
* `responseHeaders` Record\<string, string[]\> (optional)
* `fromCache` boolean - Indicates whether the response was fetched from disk
cache.
* `statusCode` Integer
@@ -207,7 +207,7 @@ and response headers are available.
* `ip` string (optional) - The server IP address that the request was
actually sent to.
* `fromCache` boolean
* `responseHeaders` Record<string, string[]> (optional)
* `responseHeaders` Record\<string, string[]\> (optional)
The `listener` will be called with `listener(details)` when a server initiated
redirect is about to occur.
@@ -226,7 +226,7 @@ redirect is about to occur.
* `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`.
* `referrer` string
* `timestamp` Double
* `responseHeaders` Record<string, string[]> (optional)
* `responseHeaders` Record\<string, string[]\> (optional)
* `fromCache` boolean
* `statusCode` Integer
* `statusLine` string

View File

@@ -284,7 +284,7 @@ e.g. the `http://` or `file://`.
* `url` string
* `options` Object (optional)
* `headers` Record<string, string> (optional) - HTTP request headers.
* `headers` Record\<string, string\> (optional) - HTTP request headers.
Initiates a download of the resource at `url` without navigating.
@@ -577,7 +577,7 @@ Stops any `findInPage` request for the `webview` with the provided `action`.
* `from` number - Index of the first page to print (0-based).
* `to` number - Index of the last page to print (inclusive) (0-based).
* `duplexMode` string (optional) - Set the duplex mode of the printed web page. Can be `simplex`, `shortEdge`, or `longEdge`.
* `dpi` Record<string, number> (optional)
* `dpi` Record\<string, number\> (optional)
* `horizontal` number (optional) - The horizontal dpi.
* `vertical` number (optional) - The vertical dpi.
* `header` string (optional) - string to be printed as page header.

View File

@@ -1664,7 +1664,7 @@ folder
└── file3
```
In Electron <=6, this would return a `FileList` with a `File` object for:
In Electron &lt;=6, this would return a `FileList` with a `File` object for:
```console
path/to/folder

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 4.2 MiB

View File

@@ -5,34 +5,25 @@ slug: code-signing
hide_title: false
---
Code signing is a security technology that you use to certify that an app was
created by you. You should sign your application so it does not trigger any
operating system security checks.
Code signing is a security technology to certify that an app was created by you.
You should sign your application so it does not trigger any operating system
security warnings.
On macOS, the system can detect any change to the app, whether the change is
introduced accidentally or by malicious code.
![macOS Sonoma Gatekeeper warning: The app is damaged](../images/gatekeeper.png)
On Windows, the system assigns a trust level to your code signing certificate
which if you don't have, or if your trust level is low, will cause security
dialogs to appear when users start using your application. Trust level builds
over time so it's better to start code signing as early as possible.
While it is possible to distribute unsigned apps, it is not recommended. Both
Windows and macOS will, by default, prevent either the download or the execution
of unsigned applications. Starting with macOS Catalina (version 10.15), users
have to go through multiple manual steps to open unsigned applications.
![macOS Catalina Gatekeeper warning: The app cannot be opened because the developer cannot be verified](../images/gatekeeper.png)
As you can see, users get two options: Move the app straight to the trash or
cancel running it. You don't want your users to see that dialog.
Both Windows and macOS prevent users from running unsigned applications. It is
possible to distribute applications without codesigning them - but in order to
run them, users need to go through multiple advanced and manual steps to run
them.
If you are building an Electron app that you intend to package and distribute,
it should be code signed.
it should be code signed. The Electron ecosystem tooling makes codesigning your
apps straightforward - this documentation explains how sign your apps on both
Windows and macOS.
## Signing & notarizing macOS builds
Properly preparing macOS applications for release requires two steps. First, the
Preparing macOS applications for release requires two steps: First, the
app needs to be code signed. Then, the app needs to be uploaded to Apple for a
process called **notarization**, where automated systems will further verify that
your app isn't doing anything to endanger its users.
@@ -65,7 +56,9 @@ are likely using [`@electron/packager`][], which includes [`@electron/osx-sign`]
[`@electron/notarize`][].
If you're using Packager's API, you can pass [in configuration that both signs
and notarizes your application](https://electron.github.io/packager/main/interfaces/electronpackager.options.html).
and notarizes your application](https://electron.github.io/packager/main/modules.html).
If the example below does not meet your needs, please see [`@electron/osx-sign`][] and
[`@electron/notarize`][] for the many possible configuration options.
```js @ts-nocheck
const packager = require('@electron/packager')
@@ -86,35 +79,81 @@ See the [Mac App Store Guide][].
## Signing Windows builds
Before signing Windows builds, you must do the following:
Before you can code sign your application, you need to acquire a code signing
certificate. Unlike Apple, Microsoft allows developers to purchase those
certificates on the open market. They are usually sold by the same companies
also offering HTTPS certificates. Prices vary, so it may be worth your time to
shop around. Popular resellers include:
1. Get a Windows Authenticode code signing certificate (requires an annual fee)
2. Install Visual Studio to get the signing utility (the free [Community
Edition](https://visualstudio.microsoft.com/vs/community/) is enough)
- [Certum EV code signing certificate](https://shop.certum.eu/data-safety/code-signing-certificates/certum-ev-code-sigining.html)
- [DigiCert EV code signing certificate](https://www.digicert.com/signing/code-signing-certificates)
- [Entrust EV code signing certificate](https://www.entrustdatacard.com/products/digital-signing-certificates/code-signing-certificates)
- [GlobalSign EV code signing certificate](https://www.globalsign.com/en/code-signing-certificate/ev-code-signing-certificates)
- [IdenTrust EV code signing certificate](https://www.identrust.com/digital-certificates/trustid-ev-code-signing)
- [Sectigo (formerly Comodo) EV code signing certificate](https://sectigo.com/ssl-certificates-tls/code-signing)
- [SSL.com EV code signing certificate](https://www.ssl.com/certificates/ev-code-signing/)
You can get a code signing certificate from a lot of resellers. Prices vary, so
it may be worth your time to shop around. Popular resellers include:
It is important to call out that since June 2023, Microsoft requires software to
be signed with an "extended validation" certificate, also called an "EV code signing
certificate". In the past, developers could sign software with a simpler and cheaper
certificate called "authenticode code signing certificate" or "software-based OV certificate".
These simpler certificates no longer provide benefits: Windows will treat your app as
completely unsigned and display the equivalent warning dialogs.
- [digicert](https://www.digicert.com/dc/code-signing/microsoft-authenticode.htm)
- [Sectigo](https://sectigo.com/ssl-certificates-tls/code-signing)
- Amongst others, please shop around to find one that suits your needs! 😄
The new EV certificates are required to be stored on a hardware storage module
compliant with FIPS 140 Level 2, Common Criteria EAL 4+ or equivalent. In other words,
the certificate cannot be simply downloaded onto a CI infrastructure. In practice,
those storage modules look like fancy USB thumb drives.
:::caution Keep your certificate password private
Your certificate password should be a **secret**. Do not share it publicly or
commit it to your source code.
:::
Many certificate providers now offer "cloud-based signing" - the entire signing hardware
is in their data center and you can use it to remotely sign code. This approach is
popular with Electron maintainers since it makes signing your applications in CI (like
GitHub Actions, CircleCI, etc) relatively easy.
At the time of writing, Electron's own apps use [DigiCert KeyLocker](https://docs.digicert.com/en/digicert-keylocker.html), but any provider that provides a command line tool for
signing files will be compatible with Electron's tooling.
All tools in the Electron ecosystem use [`@electron/windows-sign`][] and typically
expose configuration options through a `windowsSign` property. You can either use it
to sign files directly - or use the same `windowsSign` configuration across Electron
Forge, [`@electron/packager`][], [`electron-winstaller`][], and [`electron-wix-msi`][].
### Using Electron Forge
Electron Forge is the recommended way to sign your `Squirrel.Windows` and `WiX MSI` installers. Detailed instructions on how to configure your application can be found in the [Electron Forge Code Signing Tutorial](https://www.electronforge.io/guides/code-signing/code-signing-macos).
Electron Forge is the recommended way to sign your app as well as your `Squirrel.Windows`
and `WiX MSI` installers. Detailed instructions on how to configure your application can
be found in the [Electron Forge Code Signing Tutorial](https://www.electronforge.io/guides/code-signing/code-signing-windows).
### Using Electron Packager
If you're not using an integrated build pipeline like Forge, you
are likely using [`@electron/packager`][], which includes [`@electron/windows-sign`][].
If you're using Packager's API, you can pass [in configuration that signs
your application](https://electron.github.io/packager/main/modules.html). If the
example below does not meet your needs, please see [`@electron/windows-sign`][]
for the many possible configuration options.
```js @ts-nocheck
const packager = require('@electron/packager')
packager({
dir: '/path/to/my/app',
windowsSign: {
signWithParams: '--my=custom --parameters',
// If signtool.exe does not work for you, customize!
signToolPath: 'C:\\Path\\To\\my-custom-tool.exe'
}
})
```
### Using electron-winstaller (Squirrel.Windows)
[`electron-winstaller`][] is a package that can generate Squirrel.Windows installers for your
Electron app. This is the tool used under the hood by Electron Forge's
[Squirrel.Windows Maker][maker-squirrel]. If you're not using Electron Forge and want to use
`electron-winstaller` directly, use the `certificateFile` and `certificatePassword` configuration
options when creating your installer.
[Squirrel.Windows Maker][maker-squirrel]. Just like `@electron/packager`, it uses
[`@electron/windows-sign`][] under the hood and supports the same `windowsSign`
options.
```js {10-11} @ts-nocheck
const electronInstaller = require('electron-winstaller')
@@ -126,8 +165,11 @@ try {
outputDirectory: '/tmp/build/installer64',
authors: 'My App Inc.',
exe: 'myapp.exe',
certificateFile: './cert.pfx',
certificatePassword: 'this-is-a-secret'
windowsSign: {
signWithParams: '--my=custom --parameters',
// If signtool.exe does not work for you, customize!
signToolPath: 'C:\\Path\\To\\my-custom-tool.exe'
}
})
console.log('It worked!')
} catch (e) {
@@ -141,10 +183,8 @@ For full configuration options, check out the [`electron-winstaller`][] reposito
[`electron-wix-msi`][] is a package that can generate MSI installers for your
Electron app. This is the tool used under the hood by Electron Forge's [MSI Maker][maker-msi].
If you're not using Electron Forge and want to use `electron-wix-msi` directly, use the
`certificateFile` and `certificatePassword` configuration options
or pass in parameters directly to [SignTool.exe][] with the `signWithParams` option.
Just like `@electron/packager`, it uses [`@electron/windows-sign`][] under the hood
and supports the same `windowsSign` options.
```js {12-13} @ts-nocheck
import { MSICreator } from 'electron-wix-msi'
@@ -158,8 +198,11 @@ const msiCreator = new MSICreator({
manufacturer: 'Kitten Technologies',
version: '1.1.2',
outputDirectory: '/path/to/output/folder',
certificateFile: './cert.pfx',
certificatePassword: 'this-is-a-secret'
windowsSign: {
signWithParams: '--my=custom --parameters',
// If signtool.exe does not work for you, customize!
signToolPath: 'C:\\Path\\To\\my-custom-tool.exe'
}
})
// Step 2: Create a .wxs template file
@@ -192,6 +235,7 @@ See the [Windows Store Guide][].
[`@electron/osx-sign`]: https://github.com/electron/osx-sign
[`@electron/packager`]: https://github.com/electron/packager
[`@electron/notarize`]: https://github.com/electron/notarize
[`@electron/windows-sign`]: https://github.com/electron/windows-sign
[`electron-winstaller`]: https://github.com/electron/windows-installer
[`electron-wix-msi`]: https://github.com/electron-userland/electron-wix-msi
[xcode]: https://developer.apple.com/xcode
@@ -200,4 +244,3 @@ See the [Windows Store Guide][].
[windows store guide]: ./windows-store-guide.md
[maker-squirrel]: https://www.electronforge.io/config/makers/squirrel.windows
[maker-msi]: https://www.electronforge.io/config/makers/wix-msi
[signtool.exe]: https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe

View File

@@ -9,10 +9,10 @@ check out our [Electron Versioning](./electron-versioning.md) doc.
| Electron | Alpha | Beta | Stable | EOL | Chrome | Node | Supported |
| ------- | ----- | ------- | ------ | ------ | ---- | ---- | ---- |
| 29.0.0 | 2023-Dec-07 | 2024-Jan-24 | 2024-Feb-20 | 2024-Aug-20 | M122 | v18.19 | ✅ |
| 29.0.0 | 2023-Dec-07 | 2024-Jan-24 | 2024-Feb-20 | 2024-Aug-20 | M122 | v20.9 | ✅ |
| 28.0.0 | 2023-Oct-11 | 2023-Nov-06 | 2023-Dec-05 | 2024-Jun-11 | M120 | v18.18 | ✅ |
| 27.0.0 | 2023-Aug-17 | 2023-Sep-13 | 2023-Oct-10 | 2024-Apr-16 | M118 | v18.17 | ✅ |
| 26.0.0 | 2023-Jun-01 | 2023-Jun-27 | 2023-Aug-15 | 2024-Feb-20 | M116 | v18.16 | |
| 26.0.0 | 2023-Jun-01 | 2023-Jun-27 | 2023-Aug-15 | 2024-Feb-20 | M116 | v18.16 | 🚫 |
| 25.0.0 | 2023-Apr-10 | 2023-May-02 | 2023-May-30 | 2023-Dec-05 | M114 | v18.15 | 🚫 |
| 24.0.0 | 2023-Feb-09 | 2023-Mar-07 | 2023-Apr-04 | 2023-Oct-10 | M112 | v18.14 | 🚫 |
| 23.0.0 | 2022-Dec-01 | 2023-Jan-10 | 2023-Feb-07 | 2023-Aug-15 | M110 | v18.12 | 🚫 |

View File

@@ -234,7 +234,7 @@ Notification) whereas camelCase modules are not instantiable (e.g. app, ipcRende
<details><summary>Typed import aliases</summary>
For better type checking when writing TypeScript code, you can choose to import
main process modules from <code>electron/main</code>.
main process modules from `electron/main`.
```js
const { app, BrowserWindow } = require('electron/main')

View File

@@ -152,7 +152,7 @@ command that can handle the version bumping and tagging for you.
#### Bonus: Publishing in GitHub Actions
Publishing locally can be painful, especially because you can only create distributables
for your host operating system (i.e. you can't publish a Window `.exe` file from macOS).
for your host operating system (i.e. you can't publish a Windows `.exe` file from macOS).
A solution for this would be to publish your app via automation workflows
such as [GitHub Actions][], which can run tasks in the

View File

@@ -77,6 +77,7 @@ template("electron_extra_paks") {
"//content:content_resources",
"//content/browser/resources/gpu:resources",
"//content/browser/resources/media:resources",
"//content/browser/resources/process:resources",
"//content/browser/tracing:resources",
"//content/browser/webrtc/resources",
"//electron:resources",
@@ -96,6 +97,7 @@ template("electron_extra_paks") {
# New paks should be added here by default.
sources += [
"$root_gen_dir/content/browser/devtools/devtools_resources.pak",
"$root_gen_dir/content/process_resources.pak",
"$root_gen_dir/ui/resources/webui_resources.pak",
]
deps += [ "//content/browser/devtools:devtools_resources" ]

View File

@@ -33,6 +33,7 @@ auto_filenames = {
"docs/api/message-port-main.md",
"docs/api/native-image.md",
"docs/api/native-theme.md",
"docs/api/navigation-history.md",
"docs/api/net-log.md",
"docs/api/net.md",
"docs/api/notification.md",

View File

@@ -34,7 +34,7 @@ filenames = {
"shell/browser/notifications/linux/notification_presenter_linux.h",
"shell/browser/relauncher_linux.cc",
"shell/browser/ui/electron_desktop_window_tree_host_linux.cc",
"shell/browser/ui/file_dialog_gtk.cc",
"shell/browser/ui/file_dialog_linux.cc",
"shell/browser/ui/gtk/menu_gtk.cc",
"shell/browser/ui/gtk/menu_gtk.h",
"shell/browser/ui/gtk/menu_util.cc",

View File

@@ -263,13 +263,11 @@ WebContents.prototype.printToPDF = async function (options) {
// TODO(codebytere): deduplicate argument sanitization by moving rest of
// print param logic into new file shared between printToPDF and print
WebContents.prototype.print = function (options: ElectronInternal.WebContentsPrintOptions, callback) {
if (typeof options !== 'object') {
WebContents.prototype.print = function (options: ElectronInternal.WebContentsPrintOptions = {}, callback) {
if (typeof options !== 'object' || options == null) {
throw new TypeError('webContents.print(): Invalid print settings specified.');
}
const printSettings: Record<string, any> = { ...options };
const pageSize = options.pageSize ?? 'A4';
if (typeof pageSize === 'object') {
if (!pageSize.height || !pageSize.width) {
@@ -283,7 +281,7 @@ WebContents.prototype.print = function (options: ElectronInternal.WebContentsPri
throw new RangeError('height and width properties must be minimum 352 microns.');
}
printSettings.mediaSize = {
options.mediaSize = {
name: 'CUSTOM',
custom_display_name: 'Custom',
height_microns: height,
@@ -295,7 +293,7 @@ WebContents.prototype.print = function (options: ElectronInternal.WebContentsPri
};
} else if (typeof pageSize === 'string' && PDFPageSizes[pageSize]) {
const mediaSize = PDFPageSizes[pageSize];
printSettings.mediaSize = {
options.mediaSize = {
...mediaSize,
imageable_area_left_microns: 0,
imageable_area_bottom_microns: 0,
@@ -308,9 +306,9 @@ WebContents.prototype.print = function (options: ElectronInternal.WebContentsPri
if (this._print) {
if (callback) {
this._print(printSettings, callback);
this._print(options, callback);
} else {
this._print(printSettings);
this._print(options);
}
} else {
console.error('Error: Printing feature is disabled.');
@@ -520,6 +518,17 @@ WebContents.prototype._init = function () {
enumerable: true
});
// Add navigationHistory property which handles session history,
// maintaining a list of navigation entries for backward and forward navigation.
Object.defineProperty(this, 'navigationHistory', {
value: {
getActiveIndex: this._getActiveIndex.bind(this),
length: this._historyLength.bind(this),
getEntryAtIndex: this._getNavigationEntryAtIndex.bind(this)
},
writable: false
});
// Dispatch IPC messages to the ipc module.
this.on('-ipc-message' as any, function (this: Electron.WebContents, event: Electron.IpcMainEvent, internal: boolean, channel: string, args: any[]) {
addSenderToEvent(event, this);

View File

@@ -9,7 +9,7 @@
"@electron/docs-parser": "^1.2.0",
"@electron/fiddle-core": "^1.0.4",
"@electron/github-app-auth": "^2.0.0",
"@electron/lint-roller": "^1.9.0",
"@electron/lint-roller": "^1.12.1",
"@electron/typescript-definitions": "^8.15.2",
"@octokit/rest": "^19.0.7",
"@primer/octicons": "^10.0.0",

View File

@@ -0,0 +1,10 @@
cherry-pick-a65e511a14b4.patch
cherry-pick-bc18aec94c82.patch
cherry-pick-bd7aa9779873.patch
cherry-pick-2a434fd0af6b.patch
cherry-pick-867c1001637e.patch
cherry-pick-0b785e88fefa.patch
cherry-pick-511cfef8e050.patch
cherry-pick-93c3cf1c787f.patch
cherry-pick-33051b084850.patch
cherry-pick-b845fed99111.patch

View File

@@ -0,0 +1,523 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Antonio Maiorano <amaiorano@google.com>
Date: Fri, 24 May 2024 15:51:26 -0400
Subject: Fix dxil-remove-dead-blocks removing switch with multiple same
successor (#6610)
Given a switch with a constant condition and all cases the same
(branching to the same successor), dxil-remove-dead-blocks would
incorrectly remove the switch when replacing it with a branch, by
forgetting to remove the N-1 incoming values to the PHIs in the
successor block.
Bug: chromium:338071106
Change-Id: Iaa2c42642f3e370afd19d88c96c81056c16349b6
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5570270
Reviewed-by: Ben Clayton <bclayton@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/lib/Transforms/Scalar/DxilRemoveDeadBlocks.cpp b/lib/Transforms/Scalar/DxilRemoveDeadBlocks.cpp
index 54308eed2e018903e518be4a5ff809e080be78c0..9a87f4e6740c8da0522c6bf00f2a365f838cb3c0 100644
--- a/lib/Transforms/Scalar/DxilRemoveDeadBlocks.cpp
+++ b/lib/Transforms/Scalar/DxilRemoveDeadBlocks.cpp
@@ -35,6 +35,7 @@
using namespace llvm;
using namespace hlsl;
+// Removes BB from PHI nodes in SuccBB, deleting the PHI nodes if empty.
static void RemoveIncomingValueFrom(BasicBlock *SuccBB, BasicBlock *BB) {
for (auto inst_it = SuccBB->begin(); inst_it != SuccBB->end();) {
Instruction *I = &*(inst_it++);
@@ -105,6 +106,8 @@ bool DeadBlockDeleter::Run(Function &F, DxilValueCache *DVC) {
} else if (SwitchInst *Switch = dyn_cast<SwitchInst>(BB->getTerminator())) {
Value *Cond = Switch->getCondition();
BasicBlock *Succ = nullptr;
+ // If the condition to Switch is constant, replace Switch with a branch
+ // to the current case successor.
if (ConstantInt *ConstCond = DVC->GetConstInt(Cond)) {
Succ = hlsl::dxilutil::GetSwitchSuccessorForCond(Switch, ConstCond);
}
@@ -112,16 +115,32 @@ bool DeadBlockDeleter::Run(Function &F, DxilValueCache *DVC) {
if (Succ) {
Add(Succ);
+ // Create branch from BB to Succ that will replace Switch.
+ // This adds BB to preds of Succ.
BranchInst *NewBr = BranchInst::Create(Succ, BB);
hlsl::DxilMDHelper::CopyMetadata(*NewBr, *Switch);
+ // For any successors we're not going to, remove incoming block BB from
+ // PHI nodes in those successors.
+ unsigned numSucc = 0;
for (unsigned i = 0; i < Switch->getNumSuccessors(); i++) {
BasicBlock *NotSucc = Switch->getSuccessor(i);
- if (NotSucc != Succ) {
+ if (NotSucc != Succ)
RemoveIncomingValueFrom(NotSucc, BB);
- }
+ else
+ ++numSucc;
+ }
+
+ // We're replacing Switch with a single unconditional branch. If Switch
+ // has N cases with the same Succ, we need to remove N-1 incoming values
+ // of BB from the PHI nodes in Succ. This ensures that the preds of Succ
+ // match the ones in its PHIs.
+ for (unsigned i = 1; i < numSucc; i++) {
+ RemoveIncomingValueFrom(Succ, BB);
}
+ // Finally, erase Switch, which will remove BB as pred from all
+ // successors.
Switch->eraseFromParent();
Switch = nullptr;
Changed = true;
diff --git a/tools/clang/test/DXC/Passes/DxilRemoveDeadBlocks/switch-with-multiple-same-successor.hlsl b/tools/clang/test/DXC/Passes/DxilRemoveDeadBlocks/switch-with-multiple-same-successor.hlsl
new file mode 100644
index 0000000000000000000000000000000000000000..43c3510b2ce18b15ff74a0db4697898da807f49f
--- /dev/null
+++ b/tools/clang/test/DXC/Passes/DxilRemoveDeadBlocks/switch-with-multiple-same-successor.hlsl
@@ -0,0 +1,68 @@
+// Test switch with multiple same successors
+// RUN: %dxc -T ps_6_6 %s | FileCheck %s
+
+// This test used to fail with validation errors:
+//
+// error: validation errors
+// error: Module bitcode is invalid.
+// error: PHINode should have one entry for each predecessor of its parent basic block!
+// %22 = phi i32 [ 1, %20 ], [ 1, %20 ], [ 1, %20 ], [ 1, %20 ], [ %11, %13 ]
+// PHINode should have one entry for each predecessor of its parent basic block!
+// %28 = phi i32 [ 1, %26 ], [ 1, %26 ], [ 1, %26 ], [ 1, %26 ], [ %22, %24 ]
+// PHINode should have one entry for each predecessor of its parent basic block!
+// %34 = phi i32 [ 1, %32 ], [ 1, %32 ], [ 1, %32 ], [ 1, %32 ], [ %28, %30 ]
+// PHINode should have one entry for each predecessor of its parent basic block!
+// %47 = phi i32 [ 1, %45 ], [ 1, %45 ], [ 1, %45 ], [ 1, %45 ], [ %41, %43 ]
+//
+// This was fixed in dxil-remove-dead-blocks. See switch-with-multiple-same-successor.ll
+// for the pass-specific checks. Here, we just want to make sure dxc compiles this without error.
+
+// CHECK: @main
+
+ByteAddressBuffer g_buff : register(t0);
+
+struct retval {
+ float4 value : SV_Target0;
+};
+
+retval main() {
+ float4 g = asfloat(g_buff.Load4(0u));
+ bool do_discard = false;
+
+ for (int i = 0; i < 10; ++i) {
+ if (g.x != 0.0f)
+ continue;
+
+ // Switch with the same successor in all cases
+ switch(i) {
+ case 1: {
+ g.x = g.x;
+ break;
+ }
+ case 2: {
+ g.x = g.x;
+ break;
+ }
+ case 3: {
+ g.x = g.x;
+ break;
+ }
+ // Skip 'case 4' to avoid case range combining
+ case 5: {
+ g.x = g.x;
+ break;
+ }
+ }
+ if (i == 6) {
+ break;
+ }
+ g.x = atan2(1.0f, g.x);
+ do_discard = true;
+ }
+
+ if (do_discard) {
+ discard;
+ }
+
+ return (retval)0;
+}
diff --git a/tools/clang/test/DXC/Passes/DxilRemoveDeadBlocks/switch-with-multiple-same-successor.ll b/tools/clang/test/DXC/Passes/DxilRemoveDeadBlocks/switch-with-multiple-same-successor.ll
new file mode 100644
index 0000000000000000000000000000000000000000..d3e7e2f1e40c816c4ed28bfc45a1569e130f472c
--- /dev/null
+++ b/tools/clang/test/DXC/Passes/DxilRemoveDeadBlocks/switch-with-multiple-same-successor.ll
@@ -0,0 +1,369 @@
+; RUN: %dxopt %s -hlsl-passes-resume -dxil-remove-dead-blocks -S | FileCheck %s
+
+; Validate that a switch with a constant condition and multiple of the same successor
+; is correctly removed, ensuring that PHIs in the successor are properly updated.
+; For instance, in:
+;
+;
+; if.end.1: ; preds = %for.inc
+; switch i32 1, label %sw.epilog.1 [
+; i32 1, label %dx.struct_exit.new_exiting.1
+; i32 2, label %dx.struct_exit.new_exiting.1
+; i32 3, label %dx.struct_exit.new_exiting.1
+; i32 5, label %dx.struct_exit.new_exiting.1
+; ], !dbg !31 ; line:23 col:5
+;
+; sw.epilog.1: ; preds = %if.end.1
+; br label %dx.struct_exit.new_exiting.1
+;
+; dx.struct_exit.new_exiting.1: ; preds = %sw.epilog.1, %if.end.1, %if.end.1, %if.end.1, %if.end.1, %for.inc
+; %dx.struct_exit.prop.1 = phi i32 [ %do_discard.2, %sw.epilog.1 ], [ 0, %if.end.1 ], [ 0, %if.end.1 ], [ 0, %if.end.1 ], [ 0, %if.end.1 ], [ 0, %for.inc ]
+; %do_discard.2.1 = phi i32 [ 1, %sw.epilog.1 ], [ 1, %if.end.1 ], [ 1, %if.end.1 ], [ 1, %if.end.1 ], [ 1, %if.end.1 ], [ %do_discard.2, %for.inc ]
+; %g.2.i0.1 = phi float [ 0x3FF921FB60000000, %sw.epilog.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ %g.2.i0, %for.inc ]
+; br i1 false, label %cleanup, label %for.inc.1
+;
+;
+; After dxil-remove-dead-blocks, the multiple `%if.end.1` in preds and in the two phi instructions should be removed,
+; and only one instance should be left.
+
+; CHECK: if.end.1: ; preds = %for.inc
+; CHECK-NEXT: br label %dx.struct_exit.new_exiting.1
+
+; CHECK: dx.struct_exit.new_exiting.1: ; preds = %if.end.1, %for.inc
+; CHECK-NEXT: %do_discard.2.1 = phi i32 [ 1, %if.end.1 ], [ %do_discard.2, %for.inc ]
+; CHECK-NEXT: %g.2.i0.1 = phi float [ 0x3FF921FB60000000, %if.end.1 ], [ %g.2.i0, %for.inc ]
+
+;
+; Output signature:
+;
+; Name Index InterpMode DynIdx
+; -------------------- ----- ---------------------- ------
+; SV_Target 0
+;
+; Buffer Definitions:
+;
+;
+; Resource Bindings:
+;
+; Name Type Format Dim ID HLSL Bind Count
+; ------------------------------ ---------- ------- ----------- ------- -------------- ------
+; g_buff texture byte r/o T0 t0 1
+;
+target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64"
+target triple = "dxil-ms-dx"
+
+%struct.ByteAddressBuffer = type { i32 }
+%dx.types.Handle = type { i8* }
+%dx.types.ResourceProperties = type { i32, i32 }
+%dx.types.ResRet.i32 = type { i32, i32, i32, i32, i32 }
+%struct.retval = type { <4 x float> }
+
+@"\01?g_buff@@3UByteAddressBuffer@@A" = external global %struct.ByteAddressBuffer, align 4
+@llvm.used = appending global [1 x i8*] [i8* bitcast (%struct.ByteAddressBuffer* @"\01?g_buff@@3UByteAddressBuffer@@A" to i8*)], section "llvm.metadata"
+
+; Function Attrs: nounwind
+define void @main(<4 x float>* noalias nocapture readnone) #0 {
+for.body.lr.ph:
+ %1 = load %struct.ByteAddressBuffer, %struct.ByteAddressBuffer* @"\01?g_buff@@3UByteAddressBuffer@@A", align 4, !dbg !23 ; line:15 col:22
+ %2 = call %dx.types.Handle @dx.op.createHandleForLib.struct.ByteAddressBuffer(i32 160, %struct.ByteAddressBuffer %1), !dbg !23 ; line:15 col:22 ; CreateHandleForLib(Resource)
+ %3 = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle %2, %dx.types.ResourceProperties { i32 11, i32 0 }), !dbg !23 ; line:15 col:22 ; AnnotateHandle(res,props) resource: ByteAddressBuffer
+ %RawBufferLoad = call %dx.types.ResRet.i32 @dx.op.rawBufferLoad.i32(i32 139, %dx.types.Handle %3, i32 0, i32 undef, i8 15, i32 4), !dbg !23 ; line:15 col:22 ; RawBufferLoad(srv,index,elementOffset,mask,alignment)
+ %4 = extractvalue %dx.types.ResRet.i32 %RawBufferLoad, 0, !dbg !23 ; line:15 col:22
+ %.i0 = bitcast i32 %4 to float, !dbg !27 ; line:15 col:14
+ br label %for.body, !dbg !28 ; line:18 col:3
+
+for.body: ; preds = %for.body.lr.ph
+ %cmp3 = fcmp fast une float %.i0, 0.000000e+00, !dbg !29 ; line:19 col:13
+ br i1 %cmp3, label %dx.struct_exit.new_exiting, label %if.end, !dbg !30 ; line:19 col:9
+
+if.end: ; preds = %for.body
+ switch i32 0, label %sw.epilog [
+ i32 1, label %dx.struct_exit.new_exiting
+ i32 2, label %dx.struct_exit.new_exiting
+ i32 3, label %dx.struct_exit.new_exiting
+ i32 5, label %dx.struct_exit.new_exiting
+ ], !dbg !31 ; line:23 col:5
+
+sw.epilog: ; preds = %if.end
+ br label %dx.struct_exit.new_exiting
+
+dx.struct_exit.new_exiting: ; preds = %sw.epilog, %if.end, %if.end, %if.end, %if.end, %for.body
+ %do_discard.2 = phi i32 [ 0, %for.body ], [ 1, %if.end ], [ 1, %if.end ], [ 1, %if.end ], [ 1, %if.end ], [ 1, %sw.epilog ]
+ %g.2.i0 = phi float [ %.i0, %for.body ], [ 0x3FF921FB60000000, %if.end ], [ 0x3FF921FB60000000, %if.end ], [ 0x3FF921FB60000000, %if.end ], [ 0x3FF921FB60000000, %if.end ], [ 0x3FF921FB60000000, %sw.epilog ]
+ br i1 false, label %cleanup, label %for.inc
+
+for.inc: ; preds = %dx.struct_exit.new_exiting
+ %cmp3.1 = fcmp fast une float %g.2.i0, 0.000000e+00, !dbg !29 ; line:19 col:13
+ br i1 %cmp3.1, label %dx.struct_exit.new_exiting.1, label %if.end.1, !dbg !30 ; line:19 col:9
+
+cleanup: ; preds = %for.inc.9, %dx.struct_exit.new_exiting.9, %dx.struct_exit.new_exiting.8, %dx.struct_exit.new_exiting.7, %dx.struct_exit.new_exiting.6, %dx.struct_exit.new_exiting.5, %dx.struct_exit.new_exiting.4, %dx.struct_exit.new_exiting.3, %dx.struct_exit.new_exiting.2, %dx.struct_exit.new_exiting.1, %dx.struct_exit.new_exiting
+ %do_discard.3 = phi i32 [ 0, %dx.struct_exit.new_exiting ], [ %dx.struct_exit.prop.1, %dx.struct_exit.new_exiting.1 ], [ %dx.struct_exit.prop.2, %dx.struct_exit.new_exiting.2 ], [ %dx.struct_exit.prop.3, %dx.struct_exit.new_exiting.3 ], [ %dx.struct_exit.prop.4, %dx.struct_exit.new_exiting.4 ], [ %dx.struct_exit.prop.5, %dx.struct_exit.new_exiting.5 ], [ %dx.struct_exit.prop.6, %dx.struct_exit.new_exiting.6 ], [ %dx.struct_exit.prop.7, %dx.struct_exit.new_exiting.7 ], [ %dx.struct_exit.prop.8, %dx.struct_exit.new_exiting.8 ], [ %dx.struct_exit.prop.9, %dx.struct_exit.new_exiting.9 ], [ %do_discard.2.9, %for.inc.9 ]
+ %tobool15 = icmp eq i32 %do_discard.3, 0, !dbg !32 ; line:49 col:7
+ br i1 %tobool15, label %if.end.17, label %if.then.16, !dbg !32 ; line:49 col:7
+
+if.then.16: ; preds = %cleanup
+ call void @dx.op.discard(i32 82, i1 true), !dbg !33 ; line:49 col:19 ; Discard(condition)
+ br label %if.end.17, !dbg !34 ; line:51 col:3
+
+if.end.17: ; preds = %cleanup, %if.then.16
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float 0.000000e+00), !dbg !35 ; line:53 col:18 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 1, float 0.000000e+00), !dbg !35 ; line:53 col:18 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 2, float 0.000000e+00), !dbg !35 ; line:53 col:18 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 3, float 0.000000e+00), !dbg !35 ; line:53 col:18 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
+ ret void, !dbg !36 ; line:54 col:1
+
+if.end.1: ; preds = %for.inc
+ switch i32 1, label %sw.epilog.1 [
+ i32 1, label %dx.struct_exit.new_exiting.1
+ i32 2, label %dx.struct_exit.new_exiting.1
+ i32 3, label %dx.struct_exit.new_exiting.1
+ i32 5, label %dx.struct_exit.new_exiting.1
+ ], !dbg !31 ; line:23 col:5
+
+sw.epilog.1: ; preds = %if.end.1
+ br label %dx.struct_exit.new_exiting.1
+
+dx.struct_exit.new_exiting.1: ; preds = %sw.epilog.1, %if.end.1, %if.end.1, %if.end.1, %if.end.1, %for.inc
+ %dx.struct_exit.prop.1 = phi i32 [ %do_discard.2, %sw.epilog.1 ], [ 0, %if.end.1 ], [ 0, %if.end.1 ], [ 0, %if.end.1 ], [ 0, %if.end.1 ], [ 0, %for.inc ]
+ %do_discard.2.1 = phi i32 [ 1, %sw.epilog.1 ], [ 1, %if.end.1 ], [ 1, %if.end.1 ], [ 1, %if.end.1 ], [ 1, %if.end.1 ], [ %do_discard.2, %for.inc ]
+ %g.2.i0.1 = phi float [ 0x3FF921FB60000000, %sw.epilog.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ 0x3FF921FB60000000, %if.end.1 ], [ %g.2.i0, %for.inc ]
+ br i1 false, label %cleanup, label %for.inc.1
+
+for.inc.1: ; preds = %dx.struct_exit.new_exiting.1
+ %cmp3.2 = fcmp fast une float %g.2.i0.1, 0.000000e+00, !dbg !29 ; line:19 col:13
+ br i1 %cmp3.2, label %dx.struct_exit.new_exiting.2, label %if.end.2, !dbg !30 ; line:19 col:9
+
+if.end.2: ; preds = %for.inc.1
+ switch i32 2, label %sw.epilog.2 [
+ i32 1, label %dx.struct_exit.new_exiting.2
+ i32 2, label %dx.struct_exit.new_exiting.2
+ i32 3, label %dx.struct_exit.new_exiting.2
+ i32 5, label %dx.struct_exit.new_exiting.2
+ ], !dbg !31 ; line:23 col:5
+
+sw.epilog.2: ; preds = %if.end.2
+ br label %dx.struct_exit.new_exiting.2
+
+dx.struct_exit.new_exiting.2: ; preds = %sw.epilog.2, %if.end.2, %if.end.2, %if.end.2, %if.end.2, %for.inc.1
+ %dx.struct_exit.prop.2 = phi i32 [ %do_discard.2.1, %sw.epilog.2 ], [ 0, %if.end.2 ], [ 0, %if.end.2 ], [ 0, %if.end.2 ], [ 0, %if.end.2 ], [ 0, %for.inc.1 ]
+ %do_discard.2.2 = phi i32 [ 1, %sw.epilog.2 ], [ 1, %if.end.2 ], [ 1, %if.end.2 ], [ 1, %if.end.2 ], [ 1, %if.end.2 ], [ %do_discard.2.1, %for.inc.1 ]
+ %g.2.i0.2 = phi float [ 0x3FF921FB60000000, %sw.epilog.2 ], [ 0x3FF921FB60000000, %if.end.2 ], [ 0x3FF921FB60000000, %if.end.2 ], [ 0x3FF921FB60000000, %if.end.2 ], [ 0x3FF921FB60000000, %if.end.2 ], [ %g.2.i0.1, %for.inc.1 ]
+ br i1 false, label %cleanup, label %for.inc.2
+
+for.inc.2: ; preds = %dx.struct_exit.new_exiting.2
+ %cmp3.3 = fcmp fast une float %g.2.i0.2, 0.000000e+00, !dbg !29 ; line:19 col:13
+ br i1 %cmp3.3, label %dx.struct_exit.new_exiting.3, label %if.end.3, !dbg !30 ; line:19 col:9
+
+if.end.3: ; preds = %for.inc.2
+ switch i32 3, label %sw.epilog.3 [
+ i32 1, label %dx.struct_exit.new_exiting.3
+ i32 2, label %dx.struct_exit.new_exiting.3
+ i32 3, label %dx.struct_exit.new_exiting.3
+ i32 5, label %dx.struct_exit.new_exiting.3
+ ], !dbg !31 ; line:23 col:5
+
+sw.epilog.3: ; preds = %if.end.3
+ br label %dx.struct_exit.new_exiting.3
+
+dx.struct_exit.new_exiting.3: ; preds = %sw.epilog.3, %if.end.3, %if.end.3, %if.end.3, %if.end.3, %for.inc.2
+ %dx.struct_exit.prop.3 = phi i32 [ %do_discard.2.2, %sw.epilog.3 ], [ 0, %if.end.3 ], [ 0, %if.end.3 ], [ 0, %if.end.3 ], [ 0, %if.end.3 ], [ 0, %for.inc.2 ]
+ %do_discard.2.3 = phi i32 [ 1, %sw.epilog.3 ], [ 1, %if.end.3 ], [ 1, %if.end.3 ], [ 1, %if.end.3 ], [ 1, %if.end.3 ], [ %do_discard.2.2, %for.inc.2 ]
+ %g.2.i0.3 = phi float [ 0x3FF921FB60000000, %sw.epilog.3 ], [ 0x3FF921FB60000000, %if.end.3 ], [ 0x3FF921FB60000000, %if.end.3 ], [ 0x3FF921FB60000000, %if.end.3 ], [ 0x3FF921FB60000000, %if.end.3 ], [ %g.2.i0.2, %for.inc.2 ]
+ br i1 false, label %cleanup, label %for.inc.3
+
+for.inc.3: ; preds = %dx.struct_exit.new_exiting.3
+ %cmp3.4 = fcmp fast une float %g.2.i0.3, 0.000000e+00, !dbg !29 ; line:19 col:13
+ br i1 %cmp3.4, label %dx.struct_exit.new_exiting.4, label %if.end.4, !dbg !30 ; line:19 col:9
+
+if.end.4: ; preds = %for.inc.3
+ switch i32 4, label %sw.epilog.4 [
+ i32 1, label %dx.struct_exit.new_exiting.4
+ i32 2, label %dx.struct_exit.new_exiting.4
+ i32 3, label %dx.struct_exit.new_exiting.4
+ i32 5, label %dx.struct_exit.new_exiting.4
+ ], !dbg !31 ; line:23 col:5
+
+sw.epilog.4: ; preds = %if.end.4
+ br label %dx.struct_exit.new_exiting.4
+
+dx.struct_exit.new_exiting.4: ; preds = %sw.epilog.4, %if.end.4, %if.end.4, %if.end.4, %if.end.4, %for.inc.3
+ %dx.struct_exit.prop.4 = phi i32 [ %do_discard.2.3, %sw.epilog.4 ], [ 0, %if.end.4 ], [ 0, %if.end.4 ], [ 0, %if.end.4 ], [ 0, %if.end.4 ], [ 0, %for.inc.3 ]
+ %do_discard.2.4 = phi i32 [ 1, %sw.epilog.4 ], [ 1, %if.end.4 ], [ 1, %if.end.4 ], [ 1, %if.end.4 ], [ 1, %if.end.4 ], [ %do_discard.2.3, %for.inc.3 ]
+ %g.2.i0.4 = phi float [ 0x3FF921FB60000000, %sw.epilog.4 ], [ 0x3FF921FB60000000, %if.end.4 ], [ 0x3FF921FB60000000, %if.end.4 ], [ 0x3FF921FB60000000, %if.end.4 ], [ 0x3FF921FB60000000, %if.end.4 ], [ %g.2.i0.3, %for.inc.3 ]
+ br i1 false, label %cleanup, label %for.inc.4
+
+for.inc.4: ; preds = %dx.struct_exit.new_exiting.4
+ %cmp3.5 = fcmp fast une float %g.2.i0.4, 0.000000e+00, !dbg !29 ; line:19 col:13
+ br i1 %cmp3.5, label %dx.struct_exit.new_exiting.5, label %if.end.5, !dbg !30 ; line:19 col:9
+
+if.end.5: ; preds = %for.inc.4
+ switch i32 5, label %sw.epilog.5 [
+ i32 1, label %dx.struct_exit.new_exiting.5
+ i32 2, label %dx.struct_exit.new_exiting.5
+ i32 3, label %dx.struct_exit.new_exiting.5
+ i32 5, label %dx.struct_exit.new_exiting.5
+ ], !dbg !31 ; line:23 col:5
+
+sw.epilog.5: ; preds = %if.end.5
+ br label %dx.struct_exit.new_exiting.5
+
+dx.struct_exit.new_exiting.5: ; preds = %sw.epilog.5, %if.end.5, %if.end.5, %if.end.5, %if.end.5, %for.inc.4
+ %dx.struct_exit.prop.5 = phi i32 [ %do_discard.2.4, %sw.epilog.5 ], [ 0, %if.end.5 ], [ 0, %if.end.5 ], [ 0, %if.end.5 ], [ 0, %if.end.5 ], [ 0, %for.inc.4 ]
+ %do_discard.2.5 = phi i32 [ 1, %sw.epilog.5 ], [ 1, %if.end.5 ], [ 1, %if.end.5 ], [ 1, %if.end.5 ], [ 1, %if.end.5 ], [ %do_discard.2.4, %for.inc.4 ]
+ %g.2.i0.5 = phi float [ 0x3FF921FB60000000, %sw.epilog.5 ], [ 0x3FF921FB60000000, %if.end.5 ], [ 0x3FF921FB60000000, %if.end.5 ], [ 0x3FF921FB60000000, %if.end.5 ], [ 0x3FF921FB60000000, %if.end.5 ], [ %g.2.i0.4, %for.inc.4 ]
+ br i1 false, label %cleanup, label %for.inc.5
+
+for.inc.5: ; preds = %dx.struct_exit.new_exiting.5
+ %cmp3.6 = fcmp fast une float %g.2.i0.5, 0.000000e+00, !dbg !29 ; line:19 col:13
+ br i1 %cmp3.6, label %dx.struct_exit.new_exiting.6, label %if.end.6, !dbg !30 ; line:19 col:9
+
+if.end.6: ; preds = %for.inc.5
+ switch i32 6, label %sw.epilog.6 [
+ i32 1, label %dx.struct_exit.new_exiting.6
+ i32 2, label %dx.struct_exit.new_exiting.6
+ i32 3, label %dx.struct_exit.new_exiting.6
+ i32 5, label %dx.struct_exit.new_exiting.6
+ ], !dbg !31 ; line:23 col:5
+
+sw.epilog.6: ; preds = %if.end.6
+ br label %dx.struct_exit.new_exiting.6
+
+dx.struct_exit.new_exiting.6: ; preds = %sw.epilog.6, %if.end.6, %if.end.6, %if.end.6, %if.end.6, %for.inc.5
+ %dx.struct_exit.prop23.6 = phi i1 [ true, %sw.epilog.6 ], [ false, %if.end.6 ], [ false, %if.end.6 ], [ false, %if.end.6 ], [ false, %if.end.6 ], [ false, %for.inc.5 ]
+ %dx.struct_exit.prop.6 = phi i32 [ %do_discard.2.5, %sw.epilog.6 ], [ 0, %if.end.6 ], [ 0, %if.end.6 ], [ 0, %if.end.6 ], [ 0, %if.end.6 ], [ 0, %for.inc.5 ]
+ %do_discard.2.6 = phi i32 [ 1, %sw.epilog.6 ], [ 1, %if.end.6 ], [ 1, %if.end.6 ], [ 1, %if.end.6 ], [ 1, %if.end.6 ], [ %do_discard.2.5, %for.inc.5 ]
+ %g.2.i0.6 = phi float [ 0x3FF921FB60000000, %sw.epilog.6 ], [ 0x3FF921FB60000000, %if.end.6 ], [ 0x3FF921FB60000000, %if.end.6 ], [ 0x3FF921FB60000000, %if.end.6 ], [ 0x3FF921FB60000000, %if.end.6 ], [ %g.2.i0.5, %for.inc.5 ]
+ br i1 %dx.struct_exit.prop23.6, label %cleanup, label %for.inc.6
+
+for.inc.6: ; preds = %dx.struct_exit.new_exiting.6
+ %cmp3.7 = fcmp fast une float %g.2.i0.6, 0.000000e+00, !dbg !29 ; line:19 col:13
+ br i1 %cmp3.7, label %dx.struct_exit.new_exiting.7, label %if.end.7, !dbg !30 ; line:19 col:9
+
+if.end.7: ; preds = %for.inc.6
+ switch i32 7, label %sw.epilog.7 [
+ i32 1, label %dx.struct_exit.new_exiting.7
+ i32 2, label %dx.struct_exit.new_exiting.7
+ i32 3, label %dx.struct_exit.new_exiting.7
+ i32 5, label %dx.struct_exit.new_exiting.7
+ ], !dbg !31 ; line:23 col:5
+
+sw.epilog.7: ; preds = %if.end.7
+ br label %dx.struct_exit.new_exiting.7
+
+dx.struct_exit.new_exiting.7: ; preds = %sw.epilog.7, %if.end.7, %if.end.7, %if.end.7, %if.end.7, %for.inc.6
+ %dx.struct_exit.prop.7 = phi i32 [ %do_discard.2.6, %sw.epilog.7 ], [ 0, %if.end.7 ], [ 0, %if.end.7 ], [ 0, %if.end.7 ], [ 0, %if.end.7 ], [ 0, %for.inc.6 ]
+ %do_discard.2.7 = phi i32 [ 1, %sw.epilog.7 ], [ 1, %if.end.7 ], [ 1, %if.end.7 ], [ 1, %if.end.7 ], [ 1, %if.end.7 ], [ %do_discard.2.6, %for.inc.6 ]
+ %g.2.i0.7 = phi float [ 0x3FF921FB60000000, %sw.epilog.7 ], [ 0x3FF921FB60000000, %if.end.7 ], [ 0x3FF921FB60000000, %if.end.7 ], [ 0x3FF921FB60000000, %if.end.7 ], [ 0x3FF921FB60000000, %if.end.7 ], [ %g.2.i0.6, %for.inc.6 ]
+ br i1 false, label %cleanup, label %for.inc.7
+
+for.inc.7: ; preds = %dx.struct_exit.new_exiting.7
+ %cmp3.8 = fcmp fast une float %g.2.i0.7, 0.000000e+00, !dbg !29 ; line:19 col:13
+ br i1 %cmp3.8, label %dx.struct_exit.new_exiting.8, label %if.end.8, !dbg !30 ; line:19 col:9
+
+if.end.8: ; preds = %for.inc.7
+ switch i32 8, label %sw.epilog.8 [
+ i32 1, label %dx.struct_exit.new_exiting.8
+ i32 2, label %dx.struct_exit.new_exiting.8
+ i32 3, label %dx.struct_exit.new_exiting.8
+ i32 5, label %dx.struct_exit.new_exiting.8
+ ], !dbg !31 ; line:23 col:5
+
+sw.epilog.8: ; preds = %if.end.8
+ br label %dx.struct_exit.new_exiting.8
+
+dx.struct_exit.new_exiting.8: ; preds = %sw.epilog.8, %if.end.8, %if.end.8, %if.end.8, %if.end.8, %for.inc.7
+ %dx.struct_exit.prop.8 = phi i32 [ %do_discard.2.7, %sw.epilog.8 ], [ 0, %if.end.8 ], [ 0, %if.end.8 ], [ 0, %if.end.8 ], [ 0, %if.end.8 ], [ 0, %for.inc.7 ]
+ %do_discard.2.8 = phi i32 [ 1, %sw.epilog.8 ], [ 1, %if.end.8 ], [ 1, %if.end.8 ], [ 1, %if.end.8 ], [ 1, %if.end.8 ], [ %do_discard.2.7, %for.inc.7 ]
+ %g.2.i0.8 = phi float [ 0x3FF921FB60000000, %sw.epilog.8 ], [ 0x3FF921FB60000000, %if.end.8 ], [ 0x3FF921FB60000000, %if.end.8 ], [ 0x3FF921FB60000000, %if.end.8 ], [ 0x3FF921FB60000000, %if.end.8 ], [ %g.2.i0.7, %for.inc.7 ]
+ br i1 false, label %cleanup, label %for.inc.8
+
+for.inc.8: ; preds = %dx.struct_exit.new_exiting.8
+ %cmp3.9 = fcmp fast une float %g.2.i0.8, 0.000000e+00, !dbg !29 ; line:19 col:13
+ br i1 %cmp3.9, label %dx.struct_exit.new_exiting.9, label %if.end.9, !dbg !30 ; line:19 col:9
+
+if.end.9: ; preds = %for.inc.8
+ switch i32 9, label %sw.epilog.9 [
+ i32 1, label %dx.struct_exit.new_exiting.9
+ i32 2, label %dx.struct_exit.new_exiting.9
+ i32 3, label %dx.struct_exit.new_exiting.9
+ i32 5, label %dx.struct_exit.new_exiting.9
+ ], !dbg !31 ; line:23 col:5
+
+sw.epilog.9: ; preds = %if.end.9
+ br label %dx.struct_exit.new_exiting.9
+
+dx.struct_exit.new_exiting.9: ; preds = %sw.epilog.9, %if.end.9, %if.end.9, %if.end.9, %if.end.9, %for.inc.8
+ %dx.struct_exit.prop.9 = phi i32 [ %do_discard.2.8, %sw.epilog.9 ], [ 0, %if.end.9 ], [ 0, %if.end.9 ], [ 0, %if.end.9 ], [ 0, %if.end.9 ], [ 0, %for.inc.8 ]
+ %do_discard.2.9 = phi i32 [ 1, %sw.epilog.9 ], [ 1, %if.end.9 ], [ 1, %if.end.9 ], [ 1, %if.end.9 ], [ 1, %if.end.9 ], [ %do_discard.2.8, %for.inc.8 ]
+ br i1 false, label %cleanup, label %for.inc.9
+
+for.inc.9: ; preds = %dx.struct_exit.new_exiting.9
+ br label %cleanup
+}
+
+; Function Attrs: nounwind
+declare void @dx.op.storeOutput.f32(i32, i32, i32, i8, float) #0
+
+; Function Attrs: nounwind
+declare void @dx.op.discard(i32, i1) #0
+
+; Function Attrs: nounwind readonly
+declare %dx.types.ResRet.i32 @dx.op.rawBufferLoad.i32(i32, %dx.types.Handle, i32, i32, i8, i32) #1
+
+; Function Attrs: nounwind readonly
+declare %dx.types.Handle @dx.op.createHandleForLib.struct.ByteAddressBuffer(i32, %struct.ByteAddressBuffer) #1
+
+; Function Attrs: nounwind readnone
+declare %dx.types.Handle @dx.op.annotateHandle(i32, %dx.types.Handle, %dx.types.ResourceProperties) #2
+
+attributes #0 = { nounwind }
+attributes #1 = { nounwind readonly }
+attributes #2 = { nounwind readnone }
+
+!llvm.module.flags = !{!0}
+!pauseresume = !{!1}
+!llvm.ident = !{!2}
+!dx.version = !{!3}
+!dx.valver = !{!4}
+!dx.shaderModel = !{!5}
+!dx.resources = !{!6}
+!dx.typeAnnotations = !{!9, !12}
+!dx.entryPoints = !{!19}
+
+!0 = !{i32 2, !"Debug Info Version", i32 3}
+!1 = !{!"hlsl-dxilemit", !"hlsl-dxilload"}
+!2 = !{!"dxc(private) 1.8.0.4514 (d9bd2a706-dirty)"}
+!3 = !{i32 1, i32 6}
+!4 = !{i32 1, i32 8}
+!5 = !{!"ps", i32 6, i32 6}
+!6 = !{!7, null, null, null}
+!7 = !{!8}
+!8 = !{i32 0, %struct.ByteAddressBuffer* @"\01?g_buff@@3UByteAddressBuffer@@A", !"g_buff", i32 0, i32 0, i32 1, i32 11, i32 0, null}
+!9 = !{i32 0, %struct.retval undef, !10}
+!10 = !{i32 16, !11}
+!11 = !{i32 6, !"value", i32 3, i32 0, i32 4, !"SV_Target0", i32 7, i32 9}
+!12 = !{i32 1, void (<4 x float>*)* @main, !13}
+!13 = !{!14, !16}
+!14 = !{i32 0, !15, !15}
+!15 = !{}
+!16 = !{i32 1, !17, !18}
+!17 = !{i32 4, !"SV_Target0", i32 7, i32 9}
+!18 = !{i32 0}
+!19 = !{void (<4 x float>*)* @main, !"main", !20, !6, null}
+!20 = !{null, !21, null}
+!21 = !{!22}
+!22 = !{i32 0, !"SV_Target", i8 9, i8 16, !18, i8 0, i32 1, i8 4, i32 0, i8 0, null}
+!23 = !DILocation(line: 15, column: 22, scope: !24)
+!24 = !DISubprogram(name: "main", scope: !25, file: !25, line: 14, type: !26, isLocal: false, isDefinition: true, scopeLine: 14, flags: DIFlagPrototyped, isOptimized: false, function: void (<4 x float>*)* @main)
+!25 = !DIFile(filename: "/home/amaiorano/src/external/DirectXShaderCompiler/tools/clang/test/DXC/Passes/DxilRemoveDeadBlocks/switch-with-multiple-same-successor.hlsl", directory: "")
+!26 = !DISubroutineType(types: !15)
+!27 = !DILocation(line: 15, column: 14, scope: !24)
+!28 = !DILocation(line: 18, column: 3, scope: !24)
+!29 = !DILocation(line: 19, column: 13, scope: !24)
+!30 = !DILocation(line: 19, column: 9, scope: !24)
+!31 = !DILocation(line: 23, column: 5, scope: !24)
+!32 = !DILocation(line: 49, column: 7, scope: !24)
+!33 = !DILocation(line: 49, column: 19, scope: !24)
+!34 = !DILocation(line: 51, column: 3, scope: !24)
+!35 = !DILocation(line: 53, column: 18, scope: !24)
+!36 = !DILocation(line: 54, column: 1, scope: !24)

View File

@@ -0,0 +1,419 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Antonio Maiorano <amaiorano@google.com>
Date: Wed, 8 May 2024 13:38:38 -0400
Subject: Fix invalid IR from scalarrepl-param-hlsl in ReplaceConstantWithInst
(#6556)
ReplaceConstantWithInst(C, V) replaces uses of C in the current function
with V. If such a use C is an instruction I, the it replaces uses of C
in I with V. However, this function did not make sure to only perform
this replacement if V dominates I. As a result, it may end up replacing
uses of C in instructions before the definition of V.
The fix is to lazily compute the dominator tree in
ReplaceConstantWithInst so that we can guard the replacement with that
dominance check.
Bug: chromium:333414294
Change-Id: I2a8bf64094298b49a1887cc7c1334e91a745c396
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5525429
Reviewed-by: James Price <jrprice@google.com>
Reviewed-by: dan sinclair <dsinclair@google.com>
diff --git a/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp b/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp
index 3f8ffdbcfa09a96899295fd85291cedb879a248b..9b843ef0e49e554001b827e30eb6256853d90f5b 100644
--- a/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp
+++ b/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp
@@ -3271,15 +3271,34 @@ bool SROA_Helper::DoScalarReplacement(GlobalVariable *GV,
return true;
}
-static void ReplaceConstantWithInst(Constant *C, Value *V,
+// Replaces uses of constant C in the current function
+// with V, when those uses are dominated by V.
+// Returns true if it was completely replaced.
+static bool ReplaceConstantWithInst(Constant *C, Value *V,
IRBuilder<> &Builder) {
+ bool bReplacedAll = true;
Function *F = Builder.GetInsertBlock()->getParent();
+ Instruction *VInst = dyn_cast<Instruction>(V);
+ // Lazily calculate dominance
+ DominatorTree DT;
+ bool Calculated = false;
+ auto Dominates = [&](llvm::Instruction *Def, llvm::Instruction *User) {
+ if (!Calculated) {
+ DT.recalculate(*F);
+ Calculated = true;
+ }
+ return DT.dominates(Def, User);
+ };
+
for (auto it = C->user_begin(); it != C->user_end();) {
User *U = *(it++);
if (Instruction *I = dyn_cast<Instruction>(U)) {
if (I->getParent()->getParent() != F)
continue;
- I->replaceUsesOfWith(C, V);
+ if (VInst && Dominates(VInst, I))
+ I->replaceUsesOfWith(C, V);
+ else
+ bReplacedAll = false;
} else {
// Skip unused ConstantExpr.
if (U->user_empty())
@@ -3288,10 +3307,12 @@ static void ReplaceConstantWithInst(Constant *C, Value *V,
Instruction *Inst = CE->getAsInstruction();
Builder.Insert(Inst);
Inst->replaceUsesOfWith(C, V);
- ReplaceConstantWithInst(CE, Inst, Builder);
+ if (!ReplaceConstantWithInst(CE, Inst, Builder))
+ bReplacedAll = false;
}
}
C->removeDeadConstantUsers();
+ return bReplacedAll;
}
static void ReplaceUnboundedArrayUses(Value *V, Value *Src) {
@@ -3531,7 +3552,8 @@ static bool ReplaceMemcpy(Value *V, Value *Src, MemCpyInst *MC,
} else {
// Replace Constant with a non-Constant.
IRBuilder<> Builder(MC);
- ReplaceConstantWithInst(C, Src, Builder);
+ if (!ReplaceConstantWithInst(C, Src, Builder))
+ return false;
}
} else {
// Try convert special pattern for cbuffer which copy array of float4 to
@@ -3539,7 +3561,8 @@ static bool ReplaceMemcpy(Value *V, Value *Src, MemCpyInst *MC,
if (!tryToReplaceCBVec4ArrayToScalarArray(V, TyV, Src, TySrc, MC, DL)) {
IRBuilder<> Builder(MC);
Src = Builder.CreateBitCast(Src, V->getType());
- ReplaceConstantWithInst(C, Src, Builder);
+ if (!ReplaceConstantWithInst(C, Src, Builder))
+ return false;
}
}
} else {
@@ -5447,9 +5470,9 @@ void SROA_Parameter_HLSL::flattenArgument(
if (Ty->isPointerTy())
Ty = Ty->getPointerElementType();
unsigned size = DL.getTypeAllocSize(Ty);
-#if 0 // HLSL Change
+#if 0 // HLSL Change
DIExpression *DDIExp = DIB.createBitPieceExpression(debugOffset, size);
-#else // HLSL Change
+#else // HLSL Change
Type *argTy = Arg->getType();
if (argTy->isPointerTy())
argTy = argTy->getPointerElementType();
diff --git a/tools/clang/test/DXC/Passes/ScalarReplHLSL/scalarrepl-param-hlsl-const-to-local-and-back.hlsl b/tools/clang/test/DXC/Passes/ScalarReplHLSL/scalarrepl-param-hlsl-const-to-local-and-back.hlsl
new file mode 100644
index 0000000000000000000000000000000000000000..0f30050e69decaf7da3f2ae645611c1a49a4a719
--- /dev/null
+++ b/tools/clang/test/DXC/Passes/ScalarReplHLSL/scalarrepl-param-hlsl-const-to-local-and-back.hlsl
@@ -0,0 +1,45 @@
+// RUN: not %dxc -T ps_6_2 %s 2>&1 | FileCheck %s
+
+// Validate that copying from static array to local, then back to static
+// array does not crash the compiler. This was resulting in an invalid
+// ReplaceConstantWithInst from ScalarReplAggregatesHLSL, which would
+// result in referenced deleted instruction in a later pass.
+
+// CHECK: error: Loop must have break.
+
+static int arr1[10] = (int[10])0;
+static int arr2[10] = (int[10])0;
+static float result = 0;
+ByteAddressBuffer buff : register(t0);
+
+void foo() {
+ int i = 0;
+ if (buff.Load(0u)) {
+ return;
+ }
+ arr2[i] = arr1[i];
+ result = float(arr1[0]);
+}
+
+struct tint_symbol {
+ float4 value : SV_Target0;
+};
+
+float main_inner() {
+ foo();
+ bool cond = false;
+ while (true) {
+ if (cond) { break; }
+ }
+ int arr1_copy[10] = arr1; // constant to local
+ arr1 = arr1_copy; // local to constant
+ foo();
+ return result;
+}
+
+tint_symbol main() {
+ float inner_result = main_inner();
+ tint_symbol wrapper_result = (tint_symbol)0;
+ wrapper_result.value.x = inner_result;
+ return wrapper_result;
+}
diff --git a/tools/clang/test/DXC/Passes/ScalarReplHLSL/scalarrepl-param-hlsl-const-to-local-and-back.ll b/tools/clang/test/DXC/Passes/ScalarReplHLSL/scalarrepl-param-hlsl-const-to-local-and-back.ll
new file mode 100644
index 0000000000000000000000000000000000000000..6ca08ab3a9c500cacb715f63ee407c7add4fc51c
--- /dev/null
+++ b/tools/clang/test/DXC/Passes/ScalarReplHLSL/scalarrepl-param-hlsl-const-to-local-and-back.ll
@@ -0,0 +1,253 @@
+; RUN: %dxopt %s -hlsl-passes-resume -scalarrepl-param-hlsl -S | FileCheck %s
+
+; The first memcpy, from arr1 to arr1_copy.i, should be replaced by a series of 10 loads and stores,
+; while the second memcpy, from arr1_copy.i back to arr1, should be removed:
+; %19 = bitcast [10 x i32]* %arr1_copy.i to i8*, !dbg !33 ; line:25 col:23
+; call void @llvm.memcpy.p0i8.p0i8.i64(i8* %19, i8* bitcast ([10 x i32]* @arr1 to i8*), i64 40, i32 1, i1 false) #0, !dbg !33 ; line:25 col:23
+; %20 = bitcast [10 x i32]* %arr1_copy.i to i8*, !dbg !34 ; line:26 col:10
+; call void @llvm.memcpy.p0i8.p0i8.i64(i8* bitcast ([10 x i32]* @arr1 to i8*), i8* %20, i64 40, i32 1, i1 false) #0, !dbg !34 ; line:26 col:10
+; store i32 0, i32* %i.i.1.i, align 4, !dbg !35, !tbaa !12 ; line:7 col:7
+
+; CHECK: [[DEST0:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 0
+; CHECK-NEXT: [[SRC0:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 0)
+; CHECK-NEXT: store i32 [[SRC0:%[a-z0-9\.]+]], i32* [[DEST0:%[a-z0-9\.]+]]
+; CHECK-NEXT: [[DEST1:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 1
+; CHECK-NEXT: [[SRC1:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 1)
+; CHECK-NEXT: store i32 [[SRC1:%[a-z0-9\.]+]], i32* [[DEST1:%[a-z0-9\.]+]]
+; CHECK-NEXT: [[DEST2:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 2
+; CHECK-NEXT: [[SRC2:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 2)
+; CHECK-NEXT: store i32 [[SRC2:%[a-z0-9\.]+]], i32* [[DEST2:%[a-z0-9\.]+]]
+; CHECK-NEXT: [[DEST3:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 3
+; CHECK-NEXT: [[SRC3:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 3)
+; CHECK-NEXT: store i32 [[SRC3:%[a-z0-9\.]+]], i32* [[DEST3:%[a-z0-9\.]+]]
+; CHECK-NEXT: [[DEST4:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 4
+; CHECK-NEXT: [[SRC4:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 4)
+; CHECK-NEXT: store i32 [[SRC4:%[a-z0-9\.]+]], i32* [[DEST4:%[a-z0-9\.]+]]
+; CHECK-NEXT: [[DEST5:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 5
+; CHECK-NEXT: [[SRC5:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 5)
+; CHECK-NEXT: store i32 [[SRC5:%[a-z0-9\.]+]], i32* [[DEST5:%[a-z0-9\.]+]]
+; CHECK-NEXT: [[DEST6:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 6
+; CHECK-NEXT: [[SRC6:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 6)
+; CHECK-NEXT: store i32 [[SRC6:%[a-z0-9\.]+]], i32* [[DEST6:%[a-z0-9\.]+]]
+; CHECK-NEXT: [[DEST7:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 7
+; CHECK-NEXT: [[SRC7:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 7)
+; CHECK-NEXT: store i32 [[SRC7:%[a-z0-9\.]+]], i32* [[DEST7:%[a-z0-9\.]+]]
+; CHECK-NEXT: [[DEST8:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 8
+; CHECK-NEXT: [[SRC8:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 8)
+; CHECK-NEXT: store i32 [[SRC8:%[a-z0-9\.]+]], i32* [[DEST8:%[a-z0-9\.]+]]
+; CHECK-NEXT: [[DEST9:%[a-z0-9\.]+]] = getelementptr inbounds [10 x i32], [10 x i32]* %arr1_copy.i, i32 0, i32 9
+; CHECK-NEXT: [[SRC9:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 9)
+; CHECK-NEXT: store i32 [[SRC9:%[a-z0-9\.]+]], i32* [[DEST9:%[a-z0-9\.]+]]
+
+;
+; Buffer Definitions:
+;
+; cbuffer $Globals
+; {
+;
+; [0 x i8] (type annotation not present)
+;
+; }
+;
+;
+; Resource Bindings:
+;
+; Name Type Format Dim ID HLSL Bind Count
+; ------------------------------ ---------- ------- ----------- ------- -------------- ------
+; $Globals cbuffer NA NA CB0 cb4294967295 1
+; buff texture byte r/o T0 t0 1
+;
+target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64"
+target triple = "dxil-ms-dx"
+
+%struct.ByteAddressBuffer = type { i32 }
+%ConstantBuffer = type opaque
+%struct.tint_symbol = type { <4 x float> }
+%dx.types.Handle = type { i8* }
+%dx.types.ResourceProperties = type { i32, i32 }
+
+@"\01?buff@@3UByteAddressBuffer@@A" = external global %struct.ByteAddressBuffer, align 4
+@arr1 = internal global [10 x i32] zeroinitializer, align 4
+@arr2 = internal global [10 x i32] zeroinitializer, align 4
+@"$Globals" = external constant %ConstantBuffer
+
+; Function Attrs: nounwind
+define void @main(%struct.tint_symbol* noalias sret %agg.result) #0 {
+ %1 = alloca float
+ store float 0.000000e+00, float* %1
+ %i.i.1.i = alloca i32, align 4
+ %i.i.i = alloca i32, align 4
+ %cond.i = alloca i32, align 4
+ %arr1_copy.i = alloca [10 x i32], align 4
+ %inner_result = alloca float, align 4
+ %wrapper_result = alloca %struct.tint_symbol, align 4
+ store i32 0, i32* %i.i.i, align 4, !dbg !23, !tbaa !31 ; line:7 col:7
+ %2 = load %struct.ByteAddressBuffer, %struct.ByteAddressBuffer* @"\01?buff@@3UByteAddressBuffer@@A", !dbg !35 ; line:8 col:7
+ %3 = call %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %struct.ByteAddressBuffer)"(i32 0, %struct.ByteAddressBuffer %2) #0, !dbg !35 ; line:8 col:7
+ %4 = call %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %struct.ByteAddressBuffer)"(i32 14, %dx.types.Handle %3, %dx.types.ResourceProperties { i32 11, i32 0 }, %struct.ByteAddressBuffer undef) #0, !dbg !35 ; line:8 col:7
+ %5 = call i32 @"dx.hl.op.ro.i32 (i32, %dx.types.Handle, i32)"(i32 231, %dx.types.Handle %4, i32 0) #0, !dbg !35 ; line:8 col:7
+ %6 = icmp ne i32 %5, 0, !dbg !35 ; line:8 col:7
+ br i1 %6, label %"\01?foo@@YAXXZ.exit.i", label %7, !dbg !35 ; line:8 col:7
+
+; <label>:7 ; preds = %0
+ %8 = load i32, i32* %i.i.i, align 4, !dbg !36, !tbaa !31 ; line:11 col:18
+ %9 = getelementptr inbounds [10 x i32], [10 x i32]* @arr1, i32 0, i32 %8, !dbg !37 ; line:11 col:13
+ %10 = load i32, i32* %9, align 4, !dbg !37, !tbaa !31 ; line:11 col:13
+ %11 = load i32, i32* %i.i.i, align 4, !dbg !38, !tbaa !31 ; line:11 col:8
+ %12 = getelementptr inbounds [10 x i32], [10 x i32]* @arr2, i32 0, i32 %11, !dbg !39 ; line:11 col:3
+ store i32 %10, i32* %12, align 4, !dbg !40, !tbaa !31 ; line:11 col:11
+ %13 = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 0), align 4, !dbg !41, !tbaa !31 ; line:12 col:18
+ %14 = sitofp i32 %13 to float, !dbg !41 ; line:12 col:18
+ store float %14, float* %1, align 4, !dbg !42, !tbaa !43 ; line:12 col:10
+ br label %"\01?foo@@YAXXZ.exit.i", !dbg !45 ; line:13 col:1
+
+"\01?foo@@YAXXZ.exit.i": ; preds = %7, %0
+ store i32 0, i32* %cond.i, align 4, !dbg !46, !tbaa !47 ; line:21 col:8
+ br label %15, !dbg !49 ; line:22 col:3
+
+; <label>:15 ; preds = %15, %"\01?foo@@YAXXZ.exit.i"
+ %16 = load i32, i32* %cond.i, align 4, !dbg !50, !tbaa !47, !range !51 ; line:23 col:9
+ %17 = icmp ne i32 %16, 0, !dbg !50 ; line:23 col:9
+ br i1 %17, label %18, label %15, !dbg !50 ; line:23 col:9
+
+; <label>:18 ; preds = %15
+ %19 = bitcast [10 x i32]* %arr1_copy.i to i8*, !dbg !52 ; line:25 col:23
+ call void @llvm.memcpy.p0i8.p0i8.i64(i8* %19, i8* bitcast ([10 x i32]* @arr1 to i8*), i64 40, i32 1, i1 false) #0, !dbg !52 ; line:25 col:23
+ %20 = bitcast [10 x i32]* %arr1_copy.i to i8*, !dbg !53 ; line:26 col:10
+ call void @llvm.memcpy.p0i8.p0i8.i64(i8* bitcast ([10 x i32]* @arr1 to i8*), i8* %20, i64 40, i32 1, i1 false) #0, !dbg !53 ; line:26 col:10
+ store i32 0, i32* %i.i.1.i, align 4, !dbg !54, !tbaa !31 ; line:7 col:7
+ %21 = load %struct.ByteAddressBuffer, %struct.ByteAddressBuffer* @"\01?buff@@3UByteAddressBuffer@@A", !dbg !56 ; line:8 col:7
+ %22 = call %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %struct.ByteAddressBuffer)"(i32 0, %struct.ByteAddressBuffer %21) #0, !dbg !56 ; line:8 col:7
+ %23 = call %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %struct.ByteAddressBuffer)"(i32 14, %dx.types.Handle %22, %dx.types.ResourceProperties { i32 11, i32 0 }, %struct.ByteAddressBuffer undef) #0, !dbg !56 ; line:8 col:7
+ %24 = call i32 @"dx.hl.op.ro.i32 (i32, %dx.types.Handle, i32)"(i32 231, %dx.types.Handle %23, i32 0) #0, !dbg !56 ; line:8 col:7
+ %25 = icmp ne i32 %24, 0, !dbg !56 ; line:8 col:7
+ br i1 %25, label %"\01?main_inner@@YAMXZ.exit", label %26, !dbg !56 ; line:8 col:7
+
+; <label>:26 ; preds = %18
+ %27 = load i32, i32* %i.i.1.i, align 4, !dbg !57, !tbaa !31 ; line:11 col:18
+ %28 = getelementptr inbounds [10 x i32], [10 x i32]* @arr1, i32 0, i32 %27, !dbg !58 ; line:11 col:13
+ %29 = load i32, i32* %28, align 4, !dbg !58, !tbaa !31 ; line:11 col:13
+ %30 = load i32, i32* %i.i.1.i, align 4, !dbg !59, !tbaa !31 ; line:11 col:8
+ %31 = getelementptr inbounds [10 x i32], [10 x i32]* @arr2, i32 0, i32 %30, !dbg !60 ; line:11 col:3
+ store i32 %29, i32* %31, align 4, !dbg !61, !tbaa !31 ; line:11 col:11
+ %32 = load i32, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @arr1, i32 0, i32 0), align 4, !dbg !62, !tbaa !31 ; line:12 col:18
+ %33 = sitofp i32 %32 to float, !dbg !62 ; line:12 col:18
+ store float %33, float* %1, align 4, !dbg !63, !tbaa !43 ; line:12 col:10
+ br label %"\01?main_inner@@YAMXZ.exit", !dbg !64 ; line:13 col:1
+
+"\01?main_inner@@YAMXZ.exit": ; preds = %18, %26
+ %34 = load float, float* %1, align 4, !dbg !65, !tbaa !43 ; line:28 col:10
+ store float %34, float* %inner_result, align 4, !dbg !66, !tbaa !43 ; line:32 col:9
+ %35 = getelementptr inbounds %struct.tint_symbol, %struct.tint_symbol* %wrapper_result, i32 0, i32 0, !dbg !67 ; line:33 col:45
+ store <4 x float> zeroinitializer, <4 x float>* %35, !dbg !67 ; line:33 col:45
+ %36 = load float, float* %inner_result, align 4, !dbg !68, !tbaa !43 ; line:34 col:28
+ %37 = getelementptr inbounds %struct.tint_symbol, %struct.tint_symbol* %wrapper_result, i32 0, i32 0, !dbg !69 ; line:34 col:18
+ %38 = load <4 x float>, <4 x float>* %37, align 4, !dbg !70 ; line:34 col:26
+ %39 = getelementptr <4 x float>, <4 x float>* %37, i32 0, i32 0, !dbg !70 ; line:34 col:26
+ store float %36, float* %39, !dbg !70 ; line:34 col:26
+ %40 = bitcast %struct.tint_symbol* %agg.result to i8*, !dbg !71 ; line:35 col:10
+ %41 = bitcast %struct.tint_symbol* %wrapper_result to i8*, !dbg !71 ; line:35 col:10
+ call void @llvm.memcpy.p0i8.p0i8.i64(i8* %40, i8* %41, i64 16, i32 1, i1 false), !dbg !71 ; line:35 col:10
+ ret void, !dbg !72 ; line:35 col:3
+}
+
+; Function Attrs: nounwind
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1) #0
+
+; Function Attrs: nounwind readonly
+declare i32 @"dx.hl.op.ro.i32 (i32, %dx.types.Handle, i32)"(i32, %dx.types.Handle, i32) #1
+
+; Function Attrs: nounwind readnone
+declare %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %struct.ByteAddressBuffer)"(i32, %struct.ByteAddressBuffer) #2
+
+; Function Attrs: nounwind readnone
+declare %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %struct.ByteAddressBuffer)"(i32, %dx.types.Handle, %dx.types.ResourceProperties, %struct.ByteAddressBuffer) #2
+
+attributes #0 = { nounwind }
+attributes #1 = { nounwind readonly }
+attributes #2 = { nounwind readnone }
+
+!llvm.module.flags = !{!0}
+!pauseresume = !{!1}
+!llvm.ident = !{!2}
+!dx.version = !{!3}
+!dx.valver = !{!4}
+!dx.shaderModel = !{!5}
+!dx.typeAnnotations = !{!6, !9}
+!dx.entryPoints = !{!14}
+!dx.fnprops = !{!20}
+!dx.options = !{!21, !22}
+
+!0 = !{i32 2, !"Debug Info Version", i32 3}
+!1 = !{!"hlsl-hlemit", !"hlsl-hlensure"}
+!2 = !{!"dxc(private) 1.8.0.4547 (14ec4b49d)"}
+!3 = !{i32 1, i32 2}
+!4 = !{i32 1, i32 8}
+!5 = !{!"ps", i32 6, i32 2}
+!6 = !{i32 0, %struct.tint_symbol undef, !7}
+!7 = !{i32 16, !8}
+!8 = !{i32 6, !"value", i32 3, i32 0, i32 4, !"SV_Target0", i32 7, i32 9}
+!9 = !{i32 1, void (%struct.tint_symbol*)* @main, !10}
+!10 = !{!11, !13}
+!11 = !{i32 0, !12, !12}
+!12 = !{}
+!13 = !{i32 1, !12, !12}
+!14 = !{void (%struct.tint_symbol*)* @main, !"main", null, !15, null}
+!15 = !{!16, null, !18, null}
+!16 = !{!17}
+!17 = !{i32 0, %struct.ByteAddressBuffer* @"\01?buff@@3UByteAddressBuffer@@A", !"buff", i32 0, i32 0, i32 1, i32 11, i32 0, null}
+!18 = !{!19}
+!19 = !{i32 0, %ConstantBuffer* @"$Globals", !"$Globals", i32 0, i32 -1, i32 1, i32 0, null}
+!20 = !{void (%struct.tint_symbol*)* @main, i32 0, i1 false}
+!21 = !{i32 144}
+!22 = !{i32 -1}
+!23 = !DILocation(line: 7, column: 7, scope: !24, inlinedAt: !27)
+!24 = !DISubprogram(name: "foo", scope: !25, file: !25, line: 6, type: !26, isLocal: false, isDefinition: true, scopeLine: 6, flags: DIFlagPrototyped, isOptimized: false)
+!25 = !DIFile(filename: "333414294_simplifed.hlsl", directory: "")
+!26 = !DISubroutineType(types: !12)
+!27 = distinct !DILocation(line: 20, column: 3, scope: !28, inlinedAt: !29)
+!28 = !DISubprogram(name: "main_inner", scope: !25, file: !25, line: 19, type: !26, isLocal: false, isDefinition: true, scopeLine: 19, flags: DIFlagPrototyped, isOptimized: false)
+!29 = distinct !DILocation(line: 32, column: 24, scope: !30)
+!30 = !DISubprogram(name: "main", scope: !25, file: !25, line: 31, type: !26, isLocal: false, isDefinition: true, scopeLine: 31, flags: DIFlagPrototyped, isOptimized: false, function: void (%struct.tint_symbol*)* @main)
+!31 = !{!32, !32, i64 0}
+!32 = !{!"int", !33, i64 0}
+!33 = !{!"omnipotent char", !34, i64 0}
+!34 = !{!"Simple C/C++ TBAA"}
+!35 = !DILocation(line: 8, column: 7, scope: !24, inlinedAt: !27)
+!36 = !DILocation(line: 11, column: 18, scope: !24, inlinedAt: !27)
+!37 = !DILocation(line: 11, column: 13, scope: !24, inlinedAt: !27)
+!38 = !DILocation(line: 11, column: 8, scope: !24, inlinedAt: !27)
+!39 = !DILocation(line: 11, column: 3, scope: !24, inlinedAt: !27)
+!40 = !DILocation(line: 11, column: 11, scope: !24, inlinedAt: !27)
+!41 = !DILocation(line: 12, column: 18, scope: !24, inlinedAt: !27)
+!42 = !DILocation(line: 12, column: 10, scope: !24, inlinedAt: !27)
+!43 = !{!44, !44, i64 0}
+!44 = !{!"float", !33, i64 0}
+!45 = !DILocation(line: 13, column: 1, scope: !24, inlinedAt: !27)
+!46 = !DILocation(line: 21, column: 8, scope: !28, inlinedAt: !29)
+!47 = !{!48, !48, i64 0}
+!48 = !{!"bool", !33, i64 0}
+!49 = !DILocation(line: 22, column: 3, scope: !28, inlinedAt: !29)
+!50 = !DILocation(line: 23, column: 9, scope: !28, inlinedAt: !29)
+!51 = !{i32 0, i32 2}
+!52 = !DILocation(line: 25, column: 23, scope: !28, inlinedAt: !29)
+!53 = !DILocation(line: 26, column: 10, scope: !28, inlinedAt: !29)
+!54 = !DILocation(line: 7, column: 7, scope: !24, inlinedAt: !55)
+!55 = distinct !DILocation(line: 27, column: 3, scope: !28, inlinedAt: !29)
+!56 = !DILocation(line: 8, column: 7, scope: !24, inlinedAt: !55)
+!57 = !DILocation(line: 11, column: 18, scope: !24, inlinedAt: !55)
+!58 = !DILocation(line: 11, column: 13, scope: !24, inlinedAt: !55)
+!59 = !DILocation(line: 11, column: 8, scope: !24, inlinedAt: !55)
+!60 = !DILocation(line: 11, column: 3, scope: !24, inlinedAt: !55)
+!61 = !DILocation(line: 11, column: 11, scope: !24, inlinedAt: !55)
+!62 = !DILocation(line: 12, column: 18, scope: !24, inlinedAt: !55)
+!63 = !DILocation(line: 12, column: 10, scope: !24, inlinedAt: !55)
+!64 = !DILocation(line: 13, column: 1, scope: !24, inlinedAt: !55)
+!65 = !DILocation(line: 28, column: 10, scope: !28, inlinedAt: !29)
+!66 = !DILocation(line: 32, column: 9, scope: !30)
+!67 = !DILocation(line: 33, column: 45, scope: !30)
+!68 = !DILocation(line: 34, column: 28, scope: !30)
+!69 = !DILocation(line: 34, column: 18, scope: !30)
+!70 = !DILocation(line: 34, column: 26, scope: !30)
+!71 = !DILocation(line: 35, column: 10, scope: !30)
+!72 = !DILocation(line: 35, column: 3, scope: !30)

View File

@@ -0,0 +1,332 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Antonio Maiorano <amaiorano@google.com>
Date: Mon, 10 Jun 2024 10:52:30 -0400
Subject: Loop exit restructurizer: don't iterate over uses while mutating them
(#6644)
The SkipBlockWithBranch function does the following:
- Splits the block into three blocks with an if-then-endif structure.
- Moves most instructions from the original block into the "then" block
- If any of those values are used outside the original block, they are
propagated through newly-constructed phis in the 'endif' block.
This algorithm had a bug where the uses of a value were being scanned
while the uses were also being updated. In some cases a downstream
out-of-block use could be skipped. That results in an invalid module
because now the original definition is now in the 'then' block, which
does not dominate the downstream out-of-block use.
Add a test that demonstrates the problem.
Bug: chromium:339171223
Change-Id: Ia34fd7a2fe84de635289f7499772d11866a28e24
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5615350
Reviewed-by: James Price <jrprice@google.com>
Reviewed-by: dan sinclair <dsinclair@google.com>
diff --git a/lib/Transforms/Scalar/DxilRemoveUnstructuredLoopExits.cpp b/lib/Transforms/Scalar/DxilRemoveUnstructuredLoopExits.cpp
index ef6718f0f22ee33e3f16f9801a64c1a6fb6c653a..70e6ccd8ddbaeabdb469710ad8529933f0286abd 100644
--- a/lib/Transforms/Scalar/DxilRemoveUnstructuredLoopExits.cpp
+++ b/lib/Transforms/Scalar/DxilRemoveUnstructuredLoopExits.cpp
@@ -322,24 +322,26 @@ static void SkipBlockWithBranch(BasicBlock *bb, Value *cond, Loop *L,
BranchInst::Create(end, body, cond, bb);
for (Instruction &inst : *body) {
- PHINode *phi = nullptr;
// For each user that's outside of 'body', replace its use of 'inst' with a
// phi created in 'end'
- for (auto it = inst.user_begin(); it != inst.user_end();) {
- Instruction *user_inst = cast<Instruction>(*(it++));
- if (user_inst == phi)
- continue;
+ SmallPtrSet<Instruction *, 8> users_in_other_blocks;
+ for (auto *user : inst.users()) {
+ Instruction *user_inst = cast<Instruction>(user);
if (user_inst->getParent() != body) {
- if (!phi) {
- phi = PHINode::Create(inst.getType(), 2, "", &*end->begin());
- phi->addIncoming(GetDefaultValue(inst.getType()), bb);
- phi->addIncoming(&inst, body);
- }
+ users_in_other_blocks.insert(user_inst);
+ }
+ }
+ if (users_in_other_blocks.size() > 0) {
+ auto *phi = PHINode::Create(inst.getType(), 2, "", &*end->begin());
+ phi->addIncoming(GetDefaultValue(inst.getType()), bb);
+ phi->addIncoming(&inst, body);
+
+ for (auto *user_inst : users_in_other_blocks) {
user_inst->replaceUsesOfWith(&inst, phi);
}
- } // For each user of inst of body
- } // For each inst in body
+ }
+ } // For each inst in body
L->addBasicBlockToLoop(body, *LI);
L->addBasicBlockToLoop(end, *LI);
diff --git a/tools/clang/test/DXC/Passes/DxilRemoveUnstructuredLoopExits/struct_exit_wrap_value_iteration_bug.ll b/tools/clang/test/DXC/Passes/DxilRemoveUnstructuredLoopExits/struct_exit_wrap_value_iteration_bug.ll
new file mode 100644
index 0000000000000000000000000000000000000000..ee912c929bdc0424959a29d16c3d5c64f885f809
--- /dev/null
+++ b/tools/clang/test/DXC/Passes/DxilRemoveUnstructuredLoopExits/struct_exit_wrap_value_iteration_bug.ll
@@ -0,0 +1,257 @@
+; RUN: %dxopt %s -hlsl-passes-resume -loop-unroll,StructurizeLoopExits=1 -S | FileCheck %s
+
+; The Loop exit structurizer will wrap the definition of %DerivFineX3 in a conditional block.
+; Its value will later be propagated into a phi, and that phi replaces all further uses
+; of %DerivFineX3.
+;
+; Tests that a bug is fixed where the code used to iterate through the uses of a value
+; while also updating those uses. The old code would fail to update the definition
+; of %g.i.2.i3 and the result would be an invalid module: %DerivFineX3 would not dominate
+; all its uses.
+
+
+; CHECK: define void @main
+; CHECK-NOT: %DerivFineX3
+; CHECK: "\01?f@@YAXXZ.exit.i":
+; CHECK-NEXT: br i1 true, label %dx.struct_exit.cond_end, label %dx.struct_exit.cond_body
+
+; CHECK: dx.struct_exit.cond_body:
+; CHECK: %DerivFineX3 = call
+; CHECK: br label %dx.struct_exit.cond_end
+
+; CHECK: dx.struct_exit.cond_end:
+; CHECK: = phi {{.*}} %DerivFineX3
+; CHECK: br
+; CHECK-NOT: %DerivFineX3
+; CHECK: ret void
+
+
+;
+;
+; void f() {
+; int l_1 = 10;
+; for (int l = 0, l_2 = 0; l < 5 && l_2 < 1; l++, l_2++) {
+; while (1 < l_1) { }
+; }
+; }
+;
+;
+; struct tint_symbol {
+; float4 value : SV_Target0;
+; };
+;
+; float4 main_inner() {
+; float4 g = float4(0.0f, 0.0f, 0.0f, 0.0f);
+; bool2 true2 = (true).xx;
+; uint2 _e8 = (0u).xx;
+; do {
+; if (_e8.x != 2u) {
+; f();
+; float4 _e15 = ddx_fine(g);
+; if (_e8[_e8.x] == 2u) {
+; g = _e15;
+; } else {
+; f();
+; }
+; switch(_e8.x) {
+; case 3u: {
+; break;
+; }
+; case 2u: {
+; g = _e15;
+; break;
+; }
+; default: {
+; g = _e15;
+; }
+; }
+; f();
+; }
+; } while(!all(true2));
+; return g;
+;}
+;
+;tint_symbol main() {
+; float4 inner_result = main_inner();
+; tint_symbol wrapper_result = (tint_symbol)0;
+; wrapper_result.value = inner_result;
+; return wrapper_result;
+;}
+
+target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64"
+target triple = "dxil-ms-dx"
+
+%struct.tint_symbol = type { <4 x float> }
+
+; Function Attrs: nounwind
+define void @main(<4 x float>* noalias) #0 {
+entry:
+ %1 = alloca [2 x i32], align 4
+ %2 = getelementptr inbounds [2 x i32], [2 x i32]* %1, i32 0, i32 0, !dbg !20 ; line:17 col:9
+ store i32 0, i32* %2, align 4, !dbg !20 ; line:17 col:9
+ %3 = getelementptr inbounds [2 x i32], [2 x i32]* %1, i32 0, i32 1, !dbg !20 ; line:17 col:9
+ store i32 0, i32* %3, align 4, !dbg !20 ; line:17 col:9
+ br label %do.body.i, !dbg !26 ; line:18 col:3
+
+do.body.i: ; preds = %do.cond.i, %entry
+ %g.i.0.i0 = phi float [ 0.000000e+00, %entry ], [ %g.i.3.i0, %do.cond.i ]
+ %g.i.0.i1 = phi float [ 0.000000e+00, %entry ], [ %g.i.3.i1, %do.cond.i ]
+ %g.i.0.i2 = phi float [ 0.000000e+00, %entry ], [ %g.i.3.i2, %do.cond.i ]
+ %g.i.0.i3 = phi float [ 0.000000e+00, %entry ], [ %g.i.3.i3, %do.cond.i ]
+ %4 = getelementptr inbounds [2 x i32], [2 x i32]* %1, i32 0, i32 0, !dbg !27 ; line:19 col:9
+ %5 = load i32, i32* %4, align 4, !dbg !27 ; line:19 col:9
+ %cmp.i = icmp ne i32 %5, 2, !dbg !28 ; line:19 col:15
+ br i1 %cmp.i, label %for.cond.i.i, label %do.cond.i, !dbg !27 ; line:19 col:9
+
+for.cond.i.i: ; preds = %do.body.i
+ br i1 true, label %while.cond.i.i.preheader, label %"\01?f@@YAXXZ.exit.i", !dbg !29 ; line:4 col:3
+
+while.cond.i.i.preheader: ; preds = %for.cond.i.i
+ br label %while.cond.i.i, !dbg !32 ; line:5 col:5
+
+while.cond.i.i: ; preds = %while.cond.i.i.preheader, %while.cond.i.i
+ br label %while.cond.i.i, !dbg !32 ; line:5 col:5
+
+"\01?f@@YAXXZ.exit.i": ; preds = %for.cond.i.i
+ %DerivFineX = call float @dx.op.unary.f32(i32 85, float %g.i.0.i0), !dbg !33 ; line:21 col:21 ; DerivFineX(value)
+ %DerivFineX1 = call float @dx.op.unary.f32(i32 85, float %g.i.0.i1), !dbg !33 ; line:21 col:21 ; DerivFineX(value)
+ %DerivFineX2 = call float @dx.op.unary.f32(i32 85, float %g.i.0.i2), !dbg !33 ; line:21 col:21 ; DerivFineX(value)
+ %DerivFineX3 = call float @dx.op.unary.f32(i32 85, float %g.i.0.i3), !dbg !33 ; line:21 col:21 ; DerivFineX(value)
+ %6 = getelementptr inbounds [2 x i32], [2 x i32]* %1, i32 0, i32 0, !dbg !34 ; line:22 col:15
+ %7 = load i32, i32* %6, align 4, !dbg !34 ; line:22 col:15
+ %8 = getelementptr [2 x i32], [2 x i32]* %1, i32 0, i32 %7, !dbg !35 ; line:22 col:11
+ %9 = load i32, i32* %8, !dbg !35, !tbaa !36 ; line:22 col:11
+ %cmp6.i = icmp eq i32 %9, 2, !dbg !40 ; line:22 col:22
+ br i1 %cmp6.i, label %if.end.i, label %for.cond.i.19.i, !dbg !35 ; line:22 col:11
+
+for.cond.i.19.i: ; preds = %"\01?f@@YAXXZ.exit.i"
+ br i1 true, label %while.cond.i.24.i.preheader, label %if.end.i, !dbg !41 ; line:4 col:3
+
+while.cond.i.24.i.preheader: ; preds = %for.cond.i.19.i
+ br label %while.cond.i.24.i, !dbg !43 ; line:5 col:5
+
+while.cond.i.24.i: ; preds = %while.cond.i.24.i.preheader, %while.cond.i.24.i
+ br label %while.cond.i.24.i, !dbg !43 ; line:5 col:5
+
+if.end.i: ; preds = %for.cond.i.19.i, %"\01?f@@YAXXZ.exit.i"
+ %g.i.1.i0 = phi float [ %DerivFineX, %"\01?f@@YAXXZ.exit.i" ], [ %g.i.0.i0, %for.cond.i.19.i ]
+ %g.i.1.i1 = phi float [ %DerivFineX1, %"\01?f@@YAXXZ.exit.i" ], [ %g.i.0.i1, %for.cond.i.19.i ]
+ %g.i.1.i2 = phi float [ %DerivFineX2, %"\01?f@@YAXXZ.exit.i" ], [ %g.i.0.i2, %for.cond.i.19.i ]
+ %g.i.1.i3 = phi float [ %DerivFineX3, %"\01?f@@YAXXZ.exit.i" ], [ %g.i.0.i3, %for.cond.i.19.i ]
+ %10 = getelementptr inbounds [2 x i32], [2 x i32]* %1, i32 0, i32 0, !dbg !44 ; line:27 col:14
+ %11 = load i32, i32* %10, align 4, !dbg !44 ; line:27 col:14
+ switch i32 %11, label %sw.default.i [
+ i32 3, label %for.cond.i.5.i
+ i32 2, label %sw.bb.10.i
+ ], !dbg !45 ; line:27 col:7
+
+sw.bb.10.i: ; preds = %if.end.i
+ br label %for.cond.i.5.i, !dbg !46 ; line:33 col:11
+
+sw.default.i: ; preds = %if.end.i
+ br label %for.cond.i.5.i, !dbg !47 ; line:38 col:7
+
+for.cond.i.5.i: ; preds = %if.end.i, %sw.bb.10.i, %sw.default.i
+ %g.i.2.i0 = phi float [ %DerivFineX, %sw.default.i ], [ %DerivFineX, %sw.bb.10.i ], [ %g.i.1.i0, %if.end.i ]
+ %g.i.2.i1 = phi float [ %DerivFineX1, %sw.default.i ], [ %DerivFineX1, %sw.bb.10.i ], [ %g.i.1.i1, %if.end.i ]
+ %g.i.2.i2 = phi float [ %DerivFineX2, %sw.default.i ], [ %DerivFineX2, %sw.bb.10.i ], [ %g.i.1.i2, %if.end.i ]
+ %g.i.2.i3 = phi float [ %DerivFineX3, %sw.default.i ], [ %DerivFineX3, %sw.bb.10.i ], [ %g.i.1.i3, %if.end.i ]
+ br i1 true, label %while.cond.i.10.i.preheader, label %do.cond.i, !dbg !48 ; line:4 col:3
+
+while.cond.i.10.i.preheader: ; preds = %for.cond.i.5.i
+ br label %while.cond.i.10.i, !dbg !50 ; line:5 col:5
+
+while.cond.i.10.i: ; preds = %while.cond.i.10.i.preheader, %while.cond.i.10.i
+ br label %while.cond.i.10.i, !dbg !50 ; line:5 col:5
+
+do.cond.i: ; preds = %for.cond.i.5.i, %do.body.i
+ %g.i.3.i0 = phi float [ %g.i.0.i0, %do.body.i ], [ %g.i.2.i0, %for.cond.i.5.i ]
+ %g.i.3.i1 = phi float [ %g.i.0.i1, %do.body.i ], [ %g.i.2.i1, %for.cond.i.5.i ]
+ %g.i.3.i2 = phi float [ %g.i.0.i2, %do.body.i ], [ %g.i.2.i2, %for.cond.i.5.i ]
+ %g.i.3.i3 = phi float [ %g.i.0.i3, %do.body.i ], [ %g.i.2.i3, %for.cond.i.5.i ]
+ br i1 false, label %do.body.i, label %"\01?main_inner@@YA?AV?$vector@M$03@@XZ.exit", !dbg !51 ; line:41 col:3
+
+"\01?main_inner@@YA?AV?$vector@M$03@@XZ.exit": ; preds = %do.cond.i
+ %g.i.3.i3.lcssa = phi float [ %g.i.3.i3, %do.cond.i ]
+ %g.i.3.i2.lcssa = phi float [ %g.i.3.i2, %do.cond.i ]
+ %g.i.3.i1.lcssa = phi float [ %g.i.3.i1, %do.cond.i ]
+ %g.i.3.i0.lcssa = phi float [ %g.i.3.i0, %do.cond.i ]
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float %g.i.3.i0.lcssa), !dbg !52 ; line:49 col:10 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 1, float %g.i.3.i1.lcssa), !dbg !52 ; line:49 col:10 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 2, float %g.i.3.i2.lcssa), !dbg !52 ; line:49 col:10 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 3, float %g.i.3.i3.lcssa), !dbg !52 ; line:49 col:10 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
+ ret void, !dbg !53 ; line:49 col:3
+}
+
+; Function Attrs: nounwind
+declare void @dx.op.storeOutput.f32(i32, i32, i32, i8, float) #0
+
+; Function Attrs: nounwind readnone
+declare float @dx.op.unary.f32(i32, float) #1
+
+attributes #0 = { nounwind }
+attributes #1 = { nounwind readnone }
+
+!llvm.module.flags = !{!0}
+!pauseresume = !{!1}
+!llvm.ident = !{!2}
+!dx.version = !{!3}
+!dx.valver = !{!4}
+!dx.shaderModel = !{!5}
+!dx.typeAnnotations = !{!6, !9}
+!dx.entryPoints = !{!16}
+
+!0 = !{i32 2, !"Debug Info Version", i32 3}
+!1 = !{!"hlsl-dxilemit", !"hlsl-dxilload"}
+!2 = !{!"dxc(private) 1.8.0.14549 (main, 0781ded87-dirty)"}
+!3 = !{i32 1, i32 0}
+!4 = !{i32 1, i32 8}
+!5 = !{!"ps", i32 6, i32 0}
+!6 = !{i32 0, %struct.tint_symbol undef, !7}
+!7 = !{i32 16, !8}
+!8 = !{i32 6, !"value", i32 3, i32 0, i32 4, !"SV_Target0", i32 7, i32 9}
+!9 = !{i32 1, void (<4 x float>*)* @main, !10}
+!10 = !{!11, !13}
+!11 = !{i32 0, !12, !12}
+!12 = !{}
+!13 = !{i32 1, !14, !15}
+!14 = !{i32 4, !"SV_Target0", i32 7, i32 9}
+!15 = !{i32 0}
+!16 = !{void (<4 x float>*)* @main, !"main", !17, null, null}
+!17 = !{null, !18, null}
+!18 = !{!19}
+!19 = !{i32 0, !"SV_Target", i8 9, i8 16, !15, i8 0, i32 1, i8 4, i32 0, i8 0, null}
+!20 = !DILocation(line: 17, column: 9, scope: !21, inlinedAt: !24)
+!21 = !DISubprogram(name: "main_inner", scope: !22, file: !22, line: 14, type: !23, isLocal: false, isDefinition: true, scopeLine: 14, flags: DIFlagPrototyped, isOptimized: false)
+!22 = !DIFile(filename: "s2.hlsl", directory: "")
+!23 = !DISubroutineType(types: !12)
+!24 = distinct !DILocation(line: 46, column: 25, scope: !25)
+!25 = !DISubprogram(name: "main", scope: !22, file: !22, line: 45, type: !23, isLocal: false, isDefinition: true, scopeLine: 45, flags: DIFlagPrototyped, isOptimized: false, function: void (<4 x float>*)* @main)
+!26 = !DILocation(line: 18, column: 3, scope: !21, inlinedAt: !24)
+!27 = !DILocation(line: 19, column: 9, scope: !21, inlinedAt: !24)
+!28 = !DILocation(line: 19, column: 15, scope: !21, inlinedAt: !24)
+!29 = !DILocation(line: 4, column: 3, scope: !30, inlinedAt: !31)
+!30 = !DISubprogram(name: "f", scope: !22, file: !22, line: 2, type: !23, isLocal: false, isDefinition: true, scopeLine: 2, flags: DIFlagPrototyped, isOptimized: false)
+!31 = distinct !DILocation(line: 20, column: 7, scope: !21, inlinedAt: !24)
+!32 = !DILocation(line: 5, column: 5, scope: !30, inlinedAt: !31)
+!33 = !DILocation(line: 21, column: 21, scope: !21, inlinedAt: !24)
+!34 = !DILocation(line: 22, column: 15, scope: !21, inlinedAt: !24)
+!35 = !DILocation(line: 22, column: 11, scope: !21, inlinedAt: !24)
+!36 = !{!37, !37, i64 0}
+!37 = !{!"int", !38, i64 0}
+!38 = !{!"omnipotent char", !39, i64 0}
+!39 = !{!"Simple C/C++ TBAA"}
+!40 = !DILocation(line: 22, column: 22, scope: !21, inlinedAt: !24)
+!41 = !DILocation(line: 4, column: 3, scope: !30, inlinedAt: !42)
+!42 = distinct !DILocation(line: 25, column: 9, scope: !21, inlinedAt: !24)
+!43 = !DILocation(line: 5, column: 5, scope: !30, inlinedAt: !42)
+!44 = !DILocation(line: 27, column: 14, scope: !21, inlinedAt: !24)
+!45 = !DILocation(line: 27, column: 7, scope: !21, inlinedAt: !24)
+!46 = !DILocation(line: 33, column: 11, scope: !21, inlinedAt: !24)
+!47 = !DILocation(line: 38, column: 7, scope: !21, inlinedAt: !24)
+!48 = !DILocation(line: 4, column: 3, scope: !30, inlinedAt: !49)
+!49 = distinct !DILocation(line: 39, column: 7, scope: !21, inlinedAt: !24)
+!50 = !DILocation(line: 5, column: 5, scope: !30, inlinedAt: !49)
+!51 = !DILocation(line: 41, column: 3, scope: !21, inlinedAt: !24)
+!52 = !DILocation(line: 49, column: 10, scope: !25)
+!53 = !DILocation(line: 49, column: 3, scope: !25)

View File

@@ -0,0 +1,243 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Antonio Maiorano <amaiorano@google.com>
Date: Mon, 27 May 2024 15:41:40 -0400
Subject: Fix use-after-free in SimplifyCFG (#6628)
When SimplifySwitchOnSelect calls SimplifyTerminatorOnSelect, it holds
onto the select's condition value to use for the conditional branch it
replaces the switch with. When removing the switch's unused
predecessors, it must make sure not to delete PHIs in case one of them
is used by the condition value, otherwise the condition value itself may
get deleted, resulting in an use-after-free.
Note that this was fixed in LLVM as well:
https://github.com/llvm/llvm-project/commit/dc3b67b4cad5c18a687edfabd50779c3c656c620
Bug: chromium:338103465
Change-Id: Iff5d5f2e3ecf38a3fb22bbc65e7c33ad0de659fb
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5570018
Reviewed-by: James Price <jrprice@google.com>
Reviewed-by: Natalie Chouinard <chouinard@chromium.org>
diff --git a/lib/Transforms/Utils/SimplifyCFG.cpp b/lib/Transforms/Utils/SimplifyCFG.cpp
index b45caa2929a5cc3aa064fdbd9c06c20ad9e1e155..0d3ba1e00719060c1e71fa238726f0c63bd5b32f 100644
--- a/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -2619,7 +2619,10 @@ static bool SimplifyTerminatorOnSelect(TerminatorInst *OldTerm, Value *Cond,
else if (Succ == KeepEdge2)
KeepEdge2 = nullptr;
else
- Succ->removePredecessor(OldTerm->getParent());
+ Succ->removePredecessor(
+ OldTerm->getParent(),
+ /*DontDeleteUselessPHIs=*/true // HLSL Change: foward port LLVM fix
+ );
}
IRBuilder<> Builder(OldTerm);
diff --git a/tools/clang/test/DXC/Passes/SimplifyCFG/simplifycfg-uaf-select-condition.ll b/tools/clang/test/DXC/Passes/SimplifyCFG/simplifycfg-uaf-select-condition.ll
new file mode 100644
index 0000000000000000000000000000000000000000..149906c11285ed99a19c0fe1743801a795827792
--- /dev/null
+++ b/tools/clang/test/DXC/Passes/SimplifyCFG/simplifycfg-uaf-select-condition.ll
@@ -0,0 +1,199 @@
+; RUN: %dxopt %s -hlsl-passes-resume -simplifycfg -S | FileCheck %s
+
+; The IR below comes from the following HLSL.
+; Compiling this HLSL with dxc was resulting in an ASAN
+; use-after-free in SimplifyCFG during
+; SimplifyTerminatorOnSelect because it was deleting
+; a PHI node with an input value that the pass later
+; emits (the select condition value).
+
+; ByteAddressBuffer buff : register(t0);
+;
+; [numthreads(1, 1, 1)]
+; void main() {
+; if (buff.Load(0u)) {
+; return;
+; }
+;
+; int i = 0;
+; int j = 0;
+; while (true) {
+; bool a = (i < 2);
+; switch(i) {
+; case 0: {
+; while (true) {
+; bool b = (j < 2);
+; if (b) {
+; } else {
+; break;
+; }
+; while (true) {
+; int unused = 0;
+; while (true) {
+; if (a) break;
+; }
+; while (true) {
+; while (true) {
+; if (b) {
+; if (b) return;
+; } else {
+; break;
+; }
+; while (true) {
+; i = 0;
+; if (b) break;
+; }
+; if (a) break;
+; }
+; if (a) break;
+; }
+; if (a) break;
+; }
+; j = (j + 2);
+; }
+; }
+; }
+; }
+; }
+
+; Make sure the phi node did not get deleted by simplifycfg
+; CHECK: cleanup:
+; CHECK-NEXT: %cleanup.dest.slot.0 = phi i32 [ 1, %while.body.20 ], [ %.mux, %while.end.37 ]
+; CHECK-NEXT: switch i32 %cleanup.dest.slot.0, label %cleanup.46 [
+
+;
+; Buffer Definitions:
+;
+;
+; Resource Bindings:
+;
+; Name Type Format Dim ID HLSL Bind Count
+; ------------------------------ ---------- ------- ----------- ------- -------------- ------
+; buff texture byte r/o T0 t0 1
+;
+target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64"
+target triple = "dxil-ms-dx"
+
+%struct.ByteAddressBuffer = type { i32 }
+%dx.types.Handle = type { i8* }
+%dx.types.ResourceProperties = type { i32, i32 }
+
+@"\01?buff@@3UByteAddressBuffer@@A" = external global %struct.ByteAddressBuffer, align 4
+
+; Function Attrs: nounwind
+define void @main() #0 {
+entry:
+ %0 = load %struct.ByteAddressBuffer, %struct.ByteAddressBuffer* @"\01?buff@@3UByteAddressBuffer@@A", !dbg !17 ; line:5 col:7
+ %1 = call %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %struct.ByteAddressBuffer)"(i32 0, %struct.ByteAddressBuffer %0), !dbg !17 ; line:5 col:7
+ %2 = call %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %struct.ByteAddressBuffer)"(i32 14, %dx.types.Handle %1, %dx.types.ResourceProperties { i32 11, i32 0 }, %struct.ByteAddressBuffer undef), !dbg !17 ; line:5 col:7
+ %3 = call i32 @"dx.hl.op.ro.i32 (i32, %dx.types.Handle, i32)"(i32 231, %dx.types.Handle %2, i32 0), !dbg !17 ; line:5 col:7
+ %tobool = icmp ne i32 %3, 0, !dbg !17 ; line:5 col:7
+ br i1 %tobool, label %return, label %while.body, !dbg !17 ; line:5 col:7
+
+while.body: ; preds = %while.body.3, %while.body, %cleanup.46, %entry
+ %j.0 = phi i32 [ 0, %entry ], [ %j.1, %cleanup.46 ], [ %j.0, %while.body ], [ %j.1, %while.body.3 ]
+ %i.0 = phi i32 [ 0, %entry ], [ %i.1, %cleanup.46 ], [ %i.0, %while.body ], [ %i.1, %while.body.3 ]
+ %cmp = icmp slt i32 %i.0, 2, !dbg !21 ; line:12 col:17
+ %cond = icmp eq i32 %i.0, 0, !dbg !22 ; line:13 col:5
+ br i1 %cond, label %while.body.3, label %while.body, !dbg !22 ; line:13 col:5
+
+while.body.3: ; preds = %cleanup.46.thread, %while.body, %cleanup.46
+ %j.1 = phi i32 [ %j.1, %cleanup.46 ], [ %j.0, %while.body ], [ %add, %cleanup.46.thread ]
+ %i.1 = phi i32 [ %i.1, %cleanup.46 ], [ %i.0, %while.body ], [ %i.1, %cleanup.46.thread ]
+ %cmp4 = icmp slt i32 %j.1, 2, !dbg !23 ; line:16 col:23
+ br i1 %cmp4, label %while.body.11, label %while.body, !dbg !24 ; line:17 col:15
+
+while.body.11: ; preds = %while.body.3, %cleanup
+ br label %while.body.13, !dbg !25 ; line:23 col:13
+
+while.body.13: ; preds = %while.body.13, %while.body.11
+ br i1 %cmp, label %while.body.20, label %while.body.13, !dbg !26 ; line:24 col:19
+
+while.body.20: ; preds = %while.body.13, %while.end.37
+ br i1 %cmp4, label %cleanup, label %while.end.37, !dbg !27 ; line:28 col:21
+
+while.end.37: ; preds = %while.body.20
+ br i1 %cmp, label %cleanup, label %while.body.20, !dbg !28 ; line:39 col:19
+
+cleanup: ; preds = %while.end.37, %while.body.20
+ %cleanup.dest.slot.0 = phi i32 [ 1, %while.body.20 ], [ 8, %while.end.37 ]
+ switch i32 %cleanup.dest.slot.0, label %cleanup.46 [
+ i32 0, label %while.body.11
+ i32 8, label %cleanup.46.thread
+ ]
+
+cleanup.46.thread: ; preds = %cleanup
+ %add = add nsw i32 %j.1, 2, !dbg !29 ; line:43 col:18
+ br label %while.body.3
+
+cleanup.46: ; preds = %cleanup
+ switch i32 %cleanup.dest.slot.0, label %return [
+ i32 0, label %while.body.3
+ i32 6, label %while.body
+ ]
+
+return: ; preds = %cleanup.46, %entry
+ ret void, !dbg !30 ; line:48 col:1
+}
+
+; Function Attrs: nounwind
+declare void @llvm.lifetime.start(i64, i8* nocapture) #0
+
+; Function Attrs: nounwind
+declare void @llvm.lifetime.end(i64, i8* nocapture) #0
+
+; Function Attrs: nounwind readonly
+declare i32 @"dx.hl.op.ro.i32 (i32, %dx.types.Handle, i32)"(i32, %dx.types.Handle, i32) #1
+
+; Function Attrs: nounwind readnone
+declare %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %struct.ByteAddressBuffer)"(i32, %struct.ByteAddressBuffer) #2
+
+; Function Attrs: nounwind readnone
+declare %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %struct.ByteAddressBuffer)"(i32, %dx.types.Handle, %dx.types.ResourceProperties, %struct.ByteAddressBuffer) #2
+
+attributes #0 = { nounwind }
+attributes #1 = { nounwind readonly }
+attributes #2 = { nounwind readnone }
+
+!llvm.module.flags = !{!0}
+!pauseresume = !{!1}
+!llvm.ident = !{!2}
+!dx.version = !{!3}
+!dx.valver = !{!4}
+!dx.shaderModel = !{!5}
+!dx.typeAnnotations = !{!6}
+!dx.entryPoints = !{!10}
+!dx.fnprops = !{!14}
+!dx.options = !{!15, !16}
+
+!0 = !{i32 2, !"Debug Info Version", i32 3}
+!1 = !{!"hlsl-hlemit", !"hlsl-hlensure"}
+!2 = !{!"dxc(private) 1.8.0.4514 (d9bd2a706-dirty)"}
+!3 = !{i32 1, i32 6}
+!4 = !{i32 1, i32 8}
+!5 = !{!"cs", i32 6, i32 6}
+!6 = !{i32 1, void ()* @main, !7}
+!7 = !{!8}
+!8 = !{i32 1, !9, !9}
+!9 = !{}
+!10 = !{void ()* @main, !"main", null, !11, null}
+!11 = !{!12, null, null, null}
+!12 = !{!13}
+!13 = !{i32 0, %struct.ByteAddressBuffer* @"\01?buff@@3UByteAddressBuffer@@A", !"buff", i32 0, i32 0, i32 1, i32 11, i32 0, null}
+!14 = !{void ()* @main, i32 5, i32 1, i32 1, i32 1}
+!15 = !{i32 64}
+!16 = !{i32 -1}
+!17 = !DILocation(line: 5, column: 7, scope: !18)
+!18 = !DISubprogram(name: "main", scope: !19, file: !19, line: 4, type: !20, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false, function: void ()* @main)
+!19 = !DIFile(filename: "/mnt/c/Users/amaiorano/Downloads/338103465/standalone_reduced.hlsl", directory: "")
+!20 = !DISubroutineType(types: !9)
+!21 = !DILocation(line: 12, column: 17, scope: !18)
+!22 = !DILocation(line: 13, column: 5, scope: !18)
+!23 = !DILocation(line: 16, column: 23, scope: !18)
+!24 = !DILocation(line: 17, column: 15, scope: !18)
+!25 = !DILocation(line: 23, column: 13, scope: !18)
+!26 = !DILocation(line: 24, column: 19, scope: !18)
+!27 = !DILocation(line: 28, column: 21, scope: !18)
+!28 = !DILocation(line: 39, column: 19, scope: !18)
+!29 = !DILocation(line: 43, column: 18, scope: !18)
+!30 = !DILocation(line: 48, column: 1, scope: !18)

View File

@@ -0,0 +1,108 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Antonio Maiorano <amaiorano@google.com>
Date: Thu, 16 May 2024 14:24:27 -0400
Subject: Fix invalid module bitcode when indexing a swizzled bool vector
(#6582)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
When indexing a swizzled bool vector, some HLSL-specific code in
EmitCXXMemberOrOperatorMemberCallExpr kicks in to handle the
HLSLVecType. In this case, were dealing with an ExtVectorElt because of
the swizzle, so this function creates a GEP, Load, and Store on the
vector. However, boolean scalars are returned as type i11 while the
store is storing to a bool, which is an i32, so we need to insert a cast
before the store.
Bug: chromium:338161969
Change-Id: I45f8ec383be49210a10f725d8266b66fd30c34be
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5545820
Reviewed-by: James Price <jrprice@google.com>
Reviewed-by: dan sinclair <dsinclair@google.com>
diff --git a/tools/clang/lib/CodeGen/CGExpr.cpp b/tools/clang/lib/CodeGen/CGExpr.cpp
index cc46d067e617f1032bd7bc3ea6f65276984df130..efef0593b334103e511d43e3986fed3c304d28a3 100644
--- a/tools/clang/lib/CodeGen/CGExpr.cpp
+++ b/tools/clang/lib/CodeGen/CGExpr.cpp
@@ -1137,6 +1137,12 @@ llvm::MDNode *CodeGenFunction::getRangeForLoadFromType(QualType Ty) {
return MDHelper.createRange(Min, End);
}
+static bool ShouldEmitRangeMD(llvm::Value *Value, QualType Ty) {
+ if (hasBooleanRepresentation(Ty))
+ return cast<llvm::IntegerType>(Value->getType())->getBitWidth() != 1;
+ return true;
+}
+
llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
unsigned Alignment, QualType Ty,
SourceLocation Loc,
@@ -1236,7 +1242,8 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
EmitCheck(std::make_pair(Check, Kind), "load_invalid_value", StaticArgs,
EmitCheckValue(Load));
}
- } else if (CGM.getCodeGenOpts().OptimizationLevel > 0)
+ } else if (CGM.getCodeGenOpts().OptimizationLevel > 0 &&
+ ShouldEmitRangeMD(Load, Ty))
if (llvm::MDNode *RangeInfo = getRangeForLoadFromType(Ty))
Load->setMetadata(llvm::LLVMContext::MD_range, RangeInfo);
diff --git a/tools/clang/lib/CodeGen/CGExprCXX.cpp b/tools/clang/lib/CodeGen/CGExprCXX.cpp
index 2efde7c30f7f25fed5b36fe7de062b31e6cd74a2..924a0f806e7a8acf310005a212bb3c50a3c519b9 100644
--- a/tools/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/tools/clang/lib/CodeGen/CGExprCXX.cpp
@@ -235,12 +235,17 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
llvm::Constant *zero = Builder.getInt32(0);
llvm::Value *TmpThis = CreateTempAlloca(Ty);
+ QualType ElTy = hlsl::GetElementTypeOrType(Base->getType());
+ bool IsBool = ElTy->isSpecificBuiltinType(BuiltinType::Bool);
for (unsigned i = 0; i < Ty->getVectorNumElements(); i++) {
llvm::Value *EltIdx = Elts->getAggregateElement(i);
llvm::Value *EltGEP = Builder.CreateGEP(This, {zero, EltIdx});
llvm::Value *TmpEltGEP =
Builder.CreateGEP(TmpThis, {zero, Builder.getInt32(i)});
llvm::Value *Elt = Builder.CreateLoad(EltGEP);
+ if (IsBool)
+ Elt = Builder.CreateTrunc(
+ Elt, llvm::Type::getInt1Ty(getLLVMContext()));
Builder.CreateStore(Elt, TmpEltGEP);
}
This = TmpThis;
diff --git a/tools/clang/test/CodeGenDXIL/operators/swizzle/indexSwizzledBoolVec.hlsl b/tools/clang/test/CodeGenDXIL/operators/swizzle/indexSwizzledBoolVec.hlsl
new file mode 100644
index 0000000000000000000000000000000000000000..a47482d204547d01b8f237bdde0765e61e6b7ab0
--- /dev/null
+++ b/tools/clang/test/CodeGenDXIL/operators/swizzle/indexSwizzledBoolVec.hlsl
@@ -0,0 +1,30 @@
+// Test indexing a swizzled bool vector
+// RUN: %dxc -fcgl -T cs_6_0 %s | FileCheck %s
+
+// This was asserting in Instructions.cpp with:
+// void llvm::StoreInst::AssertOK(): Assertion `getOperand(0)->getType() == cast<PointerType>(getOperand(1)->getType())->getElementType() && "Ptr must be a pointer to Val type!"' failed.
+
+// Make sure load of i32 gets truncated to i1 when indexing bool vectors
+// CHECK: [[TMP:%[a-z0-9\.]+]] = alloca <2 x i1>
+// CHECK: [[VA0:%[a-z0-9\.]+]] = getelementptr <2 x i1>, <2 x i1>* [[TMP]], i32 0, i32 0,
+// CHECK-NEXT: [[VA1:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds (<4 x i32>, <4 x i32>* @"\01?v_bool4@?1??main@@YAXXZ@3V?$vector@_N$03@@B", i32 0, i32 2),
+// CHECK-NEXT: [[VA2:%[a-z0-9\.]+]] = trunc i32 [[VA1]] to i1,
+// CHECK-NEXT: store i1 [[VA2]], i1* [[VA0]],
+// CHECK-NEXT: [[VB0:%[a-z0-9\.]+]] = getelementptr <2 x i1>, <2 x i1>* [[TMP]], i32 0, i32 1,
+// CHECK-NEXT: [[VB1:%[a-z0-9\.]+]] = load i32, i32* getelementptr inbounds (<4 x i32>, <4 x i32>* @"\01?v_bool4@?1??main@@YAXXZ@3V?$vector@_N$03@@B", i32 0, i32 3),
+// CHECK-NEXT: [[VB2:%[a-z0-9\.]+]] = trunc i32 [[VB1]] to i1,
+// CHECK-NEXT: store i1 [[VB2]], i1* [[VB0]],
+
+
+cbuffer cbuffer_tint_symbol_3 : register(b0) {
+ uint4 global_uint4[1];
+};
+
+[numthreads(1, 1, 1)]
+void main() {
+ const bool4 v_bool4 = bool4(true, true, true, true);
+ const uint gx = global_uint4[0].x;
+ if (v_bool4.zw[gx] == 0) {
+ GroupMemoryBarrierWithGroupSync();
+ }
+}

View File

@@ -0,0 +1,312 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Natalie Chouinard <chouinard@google.com>
Date: Fri, 14 Jun 2024 13:29:19 +0000
Subject: Fix another UAF in SimplifyCFG (#6680)
In certain cases of unreachable code, SimplifyCFG could try to replace a
phi node with a select where the phi node itself was the select's
condition. This resulted in an ASAN use-after-free during SimplifyCFG.
The test case added isn't quite ideal because by the end of the
SimplifyCFG pass, the phi node is restored to its original state both
before and after this fix. However, an ASAN build of `dxopt` or
`check-clang-dxc` will identify a heap-use-after-free failure in the
intermediary steps of this test without this patch and succeeds with it.
This was also fixed in upstream LLVM:
https://github.com/llvm/llvm-project/commit/602ab248335e1540e82667e74fea44b7f042e112
Bug: 344639860
Change-Id: I743e96fb172de867c89cad51805edf96387c04ec
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5631796
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/lib/Transforms/Utils/SimplifyCFG.cpp b/lib/Transforms/Utils/SimplifyCFG.cpp
index 0d3ba1e00719060c1e71fa238726f0c63bd5b32f..5b364856928af6aab007e958b24f1daea32cd733 100644
--- a/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -1830,6 +1830,14 @@ static bool FoldTwoEntryPHINode(PHINode *PN, const TargetTransformInfo &TTI,
isa<ConstantInt>(IfCond))
return false;
+ // HLSL Change Begins: Patching in llvm/llvm-project@602ab24
+ // Don't try to fold an unreachable block. For example, the phi node itself
+ // can't be the candidate if-condition for a select that we want to form.
+ if (auto *IfCondPhiInst = dyn_cast<PHINode>(IfCond))
+ if (IfCondPhiInst->getParent() == BB)
+ return false;
+ // HLSL Change Ends.
+
// Okay, we found that we can merge this two-entry phi node into a select.
// Doing so would require us to fold *all* two entry phi nodes in this block.
// At some point this becomes non-profitable (particularly if the target
diff --git a/tools/clang/test/DXC/Passes/SimplifyCFG/simplifycfg-uaf-phi-condition.ll b/tools/clang/test/DXC/Passes/SimplifyCFG/simplifycfg-uaf-phi-condition.ll
new file mode 100644
index 0000000000000000000000000000000000000000..573745a819fd1b51e3163d644088738d5128d30c
--- /dev/null
+++ b/tools/clang/test/DXC/Passes/SimplifyCFG/simplifycfg-uaf-phi-condition.ll
@@ -0,0 +1,263 @@
+; RUN: %dxopt %s -hlsl-passes-resume -simplifycfg -S | FileCheck %s
+
+; The IR below comes from the following HLSL.
+; Compiling this HLSL with dxc was resulting in an ASAN use-after-free in
+; SimplifyCFG during FoldTwoEntryPHINode because it was deleting a PHI node
+; which was itself used as the condition for the select that replaced it.
+
+; struct a {
+; int b[2];
+; };
+;
+; cbuffer cbuffer_c : register(b0) {
+; uint4 c[1];
+; };
+;
+; void d(inout a e, inout int f) {
+; int n = f;
+; int g = asint(c[0].x);
+; int s = f;
+; bool i = (s >= 0);
+; int j = (s * n);
+; bool k = (6 > g);
+; int l = 0;
+; bool q = (s > j);
+; while (true) {
+; while (true) {
+; while (true) {
+; if (k) {
+; {
+; int t[2] = e.b;
+; t[g] = n;
+; e.b = t;
+; }
+; }
+; e.b[1] = g;
+; e.b[0] = s;
+; if (q) {
+; break;
+; }
+; }
+; switch(j) {
+; case 0: {
+; break;
+; }
+; case 9: {
+; break;
+; }
+; default: {
+; {
+; int u[2] = e.b;
+; u[g] = l;
+; e.b = u;
+; }
+; break;
+; }
+; }
+; {
+; if (q) { break; }
+; }
+; }
+; {
+; int v[2] = e.b;
+; v[g] = j;
+; e.b = v;
+; }
+; if (!(i)) {
+; break;
+; }
+; }
+; }
+;
+; [numthreads(1, 1, 1)]
+; void main() {
+; int o = 0;
+; a p = (a)0;
+; while (true) {
+; bool i = (o < asint(c[0].x));
+; if (i) {
+; bool r = !(i);
+; if (!(r)) {
+; return;
+; }
+; d(p, o);
+; }
+; o = (o + 1);
+; }
+; return;
+; }
+
+; Make sure the phi node did not get deleted by simplifycfg
+; CHECK: while.body:
+; CHECK-NEXT: %o.0 = phi i32 [ 0, %entry ], [ %add, %if.end.6 ]
+
+;
+; Buffer Definitions:
+;
+; cbuffer cbuffer_c
+; {
+;
+; struct cbuffer_c
+; {
+;
+; uint4 c[1]; ; Offset: 0
+;
+; } cbuffer_c; ; Offset: 0 Size: 16
+;
+; }
+;
+;
+; Resource Bindings:
+;
+; Name Type Format Dim ID HLSL Bind Count
+; ------------------------------ ---------- ------- ----------- ------- -------------- ------
+; cbuffer_c cbuffer NA NA CB0 cb0 1
+;
+target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64"
+target triple = "dxil-ms-dx"
+
+%cbuffer_c = type { [1 x <4 x i32>] }
+%dx.types.Handle = type { i8* }
+%dx.types.ResourceProperties = type { i32, i32 }
+%dx.types.CBufRet.i32 = type { i32, i32, i32, i32 }
+%struct.a = type { [2 x i32] }
+
+@cbuffer_c = external constant %cbuffer_c
+@llvm.used = appending global [1 x i8*] [i8* bitcast (%cbuffer_c* @cbuffer_c to i8*)], section "llvm.metadata"
+
+; Function Attrs: nounwind
+define void @main() #0 {
+entry:
+ %0 = load %cbuffer_c, %cbuffer_c* @cbuffer_c, align 4
+ %cbuffer_c8 = call %dx.types.Handle @dx.op.createHandleForLib.cbuffer_c(i32 160, %cbuffer_c %0) ; CreateHandleForLib(Resource)
+ %1 = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle %cbuffer_c8, %dx.types.ResourceProperties { i32 13, i32 16 }) ; AnnotateHandle(res,props) resource: CBuffer
+ %cbuffer_c = call %dx.types.Handle @dx.op.createHandleForLib.cbuffer_c(i32 160, %cbuffer_c %0) ; CreateHandleForLib(Resource)
+ %2 = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle %cbuffer_c, %dx.types.ResourceProperties { i32 13, i32 16 }) ; AnnotateHandle(res,props) resource: CBuffer
+ br label %while.body, !dbg !21 ; line:69 col:3
+
+while.body: ; preds = %if.end.6, %entry
+ %o.0 = phi i32 [ 0, %entry ], [ %add, %if.end.6 ]
+ %3 = call %dx.types.CBufRet.i32 @dx.op.cbufferLoadLegacy.i32(i32 59, %dx.types.Handle %1, i32 0), !dbg !25 ; line:70 col:25 ; CBufferLoadLegacy(handle,regIndex)
+ %4 = extractvalue %dx.types.CBufRet.i32 %3, 0, !dbg !25 ; line:70 col:25
+ %cmp = icmp slt i32 %o.0, %4, !dbg !26 ; line:70 col:17
+ br i1 %cmp, label %if.then, label %if.end.6, !dbg !27 ; line:71 col:9
+
+if.then: ; preds = %while.body
+ br i1 %cmp, label %if.then.5, label %if.end, !dbg !28 ; line:73 col:11
+
+if.then.5: ; preds = %if.then
+ ret void, !dbg !29 ; line:74 col:9
+
+if.end: ; preds = %if.then
+ %5 = call %dx.types.CBufRet.i32 @dx.op.cbufferLoadLegacy.i32(i32 59, %dx.types.Handle %2, i32 0), !dbg !30 ; line:11 col:17 ; CBufferLoadLegacy(handle,regIndex)
+ %6 = extractvalue %dx.types.CBufRet.i32 %5, 0, !dbg !30 ; line:11 col:17
+ %cmp.i = icmp sgt i32 %o.0, -1, !dbg !33 ; line:13 col:15
+ %mul.i = mul nsw i32 %o.0, %o.0, !dbg !34 ; line:14 col:14
+ %cmp1.i = icmp slt i32 %6, 6, !dbg !35 ; line:15 col:15
+ %cmp4.i = icmp sgt i32 %o.0, %mul.i, !dbg !36 ; line:17 col:15
+ br label %while.body.10.i, !dbg !37 ; line:18 col:3
+
+while.body.10.i: ; preds = %while.end.27.i, %sw.epilog.i, %if.end.i, %if.end
+ br i1 %cmp1.i, label %if.then.i, label %if.end.i, !dbg !38 ; line:21 col:13
+
+if.then.i: ; preds = %while.body.10.i
+ br label %if.end.i, !dbg !39 ; line:27 col:9
+
+if.end.i: ; preds = %if.then.i, %while.body.10.i
+ br i1 %cmp4.i, label %while.end.i, label %while.body.10.i, !dbg !40 ; line:30 col:13
+
+while.end.i: ; preds = %if.end.i
+ switch i32 %mul.i, label %sw.default.i [
+ i32 0, label %sw.epilog.i
+ i32 9, label %sw.epilog.i
+ ], !dbg !41 ; line:34 col:7
+
+sw.default.i: ; preds = %while.end.i
+ br label %sw.epilog.i, !dbg !42 ; line:47 col:11
+
+sw.epilog.i: ; preds = %sw.default.i, %while.end.i, %while.end.i
+ br i1 %cmp4.i, label %while.end.27.i, label %while.body.10.i, !dbg !43 ; line:51 col:13
+
+while.end.27.i: ; preds = %sw.epilog.i
+ br i1 %cmp.i, label %while.body.10.i, label %if.end.6, !dbg !44 ; line:59 col:9
+
+if.end.6: ; preds = %while.end.27.i, %while.body
+ %add = add nsw i32 %o.0, 1, !dbg !45 ; line:78 col:12
+ br label %while.body, !dbg !21 ; line:69 col:3
+}
+
+; Function Attrs: nounwind readnone
+declare %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %cbuffer_c*, i32)"(i32, %cbuffer_c*, i32) #1
+
+; Function Attrs: nounwind readnone
+declare %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %cbuffer_c)"(i32, %dx.types.Handle, %dx.types.ResourceProperties, %cbuffer_c) #1
+
+; Function Attrs: nounwind readonly
+declare %dx.types.CBufRet.i32 @dx.op.cbufferLoadLegacy.i32(i32, %dx.types.Handle, i32) #2
+
+; Function Attrs: nounwind readonly
+declare %dx.types.Handle @dx.op.createHandleForLib.cbuffer_c(i32, %cbuffer_c) #2
+
+; Function Attrs: nounwind readnone
+declare %dx.types.Handle @dx.op.annotateHandle(i32, %dx.types.Handle, %dx.types.ResourceProperties) #1
+
+attributes #0 = { nounwind }
+attributes #1 = { nounwind readnone }
+attributes #2 = { nounwind readonly }
+
+!llvm.module.flags = !{!0}
+!pauseresume = !{!1}
+!llvm.ident = !{!2}
+!dx.version = !{!3}
+!dx.valver = !{!4}
+!dx.shaderModel = !{!5}
+!dx.resources = !{!6}
+!dx.typeAnnotations = !{!9, !14}
+!dx.entryPoints = !{!18}
+
+!0 = !{i32 2, !"Debug Info Version", i32 3}
+!1 = !{!"hlsl-dxilemit", !"hlsl-dxilload"}
+!2 = !{!"dxc(private) 1.8.0.14620 (main, 8408ae882)"}
+!3 = !{i32 1, i32 2}
+!4 = !{i32 1, i32 8}
+!5 = !{!"cs", i32 6, i32 2}
+!6 = !{null, null, !7, null}
+!7 = !{!8}
+!8 = !{i32 0, %cbuffer_c* @cbuffer_c, !"cbuffer_c", i32 0, i32 0, i32 1, i32 16, null}
+!9 = !{i32 0, %struct.a undef, !10, %cbuffer_c undef, !12}
+!10 = !{i32 20, !11}
+!11 = !{i32 6, !"b", i32 3, i32 0, i32 7, i32 4}
+!12 = !{i32 16, !13}
+!13 = !{i32 6, !"c", i32 3, i32 0, i32 7, i32 5}
+!14 = !{i32 1, void ()* @main, !15}
+!15 = !{!16}
+!16 = !{i32 1, !17, !17}
+!17 = !{}
+!18 = !{void ()* @main, !"main", null, !6, !19}
+!19 = !{i32 4, !20}
+!20 = !{i32 1, i32 1, i32 1}
+!21 = !DILocation(line: 69, column: 3, scope: !22)
+!22 = !DISubprogram(name: "main", scope: !23, file: !23, line: 66, type: !24, isLocal: false, isDefinition: true, scopeLine: 66, flags: DIFlagPrototyped, isOptimized: false, function: void ()* @main)
+!23 = !DIFile(filename: "/usr/local/google/home/chouinard/Downloads/standalone.hlsl", directory: "")
+!24 = !DISubroutineType(types: !17)
+!25 = !DILocation(line: 70, column: 25, scope: !22)
+!26 = !DILocation(line: 70, column: 17, scope: !22)
+!27 = !DILocation(line: 71, column: 9, scope: !22)
+!28 = !DILocation(line: 73, column: 11, scope: !22)
+!29 = !DILocation(line: 74, column: 9, scope: !22)
+!30 = !DILocation(line: 11, column: 17, scope: !31, inlinedAt: !32)
+!31 = !DISubprogram(name: "d", scope: !23, file: !23, line: 9, type: !24, isLocal: false, isDefinition: true, scopeLine: 9, flags: DIFlagPrototyped, isOptimized: false)
+!32 = distinct !DILocation(line: 76, column: 7, scope: !22)
+!33 = !DILocation(line: 13, column: 15, scope: !31, inlinedAt: !32)
+!34 = !DILocation(line: 14, column: 14, scope: !31, inlinedAt: !32)
+!35 = !DILocation(line: 15, column: 15, scope: !31, inlinedAt: !32)
+!36 = !DILocation(line: 17, column: 15, scope: !31, inlinedAt: !32)
+!37 = !DILocation(line: 18, column: 3, scope: !31, inlinedAt: !32)
+!38 = !DILocation(line: 21, column: 13, scope: !31, inlinedAt: !32)
+!39 = !DILocation(line: 27, column: 9, scope: !31, inlinedAt: !32)
+!40 = !DILocation(line: 30, column: 13, scope: !31, inlinedAt: !32)
+!41 = !DILocation(line: 34, column: 7, scope: !31, inlinedAt: !32)
+!42 = !DILocation(line: 47, column: 11, scope: !31, inlinedAt: !32)
+!43 = !DILocation(line: 51, column: 13, scope: !31, inlinedAt: !32)
+!44 = !DILocation(line: 59, column: 9, scope: !31, inlinedAt: !32)
+!45 = !DILocation(line: 78, column: 12, scope: !22)

View File

@@ -0,0 +1,66 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Antonio Maiorano <amaiorano@google.com>
Date: Wed, 3 Apr 2024 15:58:51 -0400
Subject: Fix ASAN use-after-free on unreferenced self-assignment of struct
instance (#6466)
When deleting an unused memcpy, ScalarReplAggregatesHLSL was attempting
to delete both the target and the source of the memcpy without first
checking if they were both same, resulting in a double-delete.
Bug: chromium:331123811
Change-Id: Idaef95a06b10a7fb6f0ca2e662972a44ec662fbc
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5419225
Reviewed-by: David Neto <dneto@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Reviewed-by: Ben Clayton <bclayton@chromium.org>
diff --git a/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp b/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp
index 59f32a953ac5991e38c44d685f0f8fc589377b4d..3f8ffdbcfa09a96899295fd85291cedb879a248b 100644
--- a/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp
+++ b/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp
@@ -1003,9 +1003,11 @@ void DeleteMemcpy(MemCpyInst *MI) {
if (op0->user_empty())
op0->eraseFromParent();
}
- if (Instruction *op1 = dyn_cast<Instruction>(Op1)) {
- if (op1->user_empty())
- op1->eraseFromParent();
+ if (Op0 != Op1) {
+ if (Instruction *op1 = dyn_cast<Instruction>(Op1)) {
+ if (op1->user_empty())
+ op1->eraseFromParent();
+ }
}
}
diff --git a/tools/clang/test/DXC/unreferenced_struct_selft_assignment_crash.hlsl b/tools/clang/test/DXC/unreferenced_struct_selft_assignment_crash.hlsl
new file mode 100644
index 0000000000000000000000000000000000000000..81adf71867c9868992372e12dc1ba81aebb48344
--- /dev/null
+++ b/tools/clang/test/DXC/unreferenced_struct_selft_assignment_crash.hlsl
@@ -0,0 +1,24 @@
+// RUN: %dxc -T cs_6_0 %s | FileCheck %s
+
+// Validate that self-assignment of a static struct instance that is not
+// referenced does not crash the compiler. This was resulting in an ASAN
+// use-after-free in ScalarReplAggregatesHLSL because DeleteMemcpy would
+// attempt to delete both source and target, even if both were the same.
+// CHECK: define void @main() {
+// CHECK-NEXT: ret void
+// CHECK-NEXT: }
+
+struct MyStruct {
+ int m0;
+};
+
+static MyStruct s;
+
+void foo() {
+ s = s;
+}
+
+[numthreads(1, 1, 1)]
+void main() {
+ foo();
+}

View File

@@ -0,0 +1,294 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Natalie Chouinard <chouinard@google.com>
Date: Mon, 10 Jun 2024 18:21:40 +0000
Subject: Fix LoopDeletion incorrectly updating PHI with multiple duplicate
inputs (#6643)
LoopDeletion was incorrectly updating PHI nodes in the target block when
it had duplicate input edges. This happens, for example, when deleting a
loop that uses a switch with multiple cases that exit the same way.
After determining that this was the bug, I found this fix in LLVM:
https://reviews.llvm.org/D34516 and applied it here.
Bug: 340196361
Change-Id: I98b150bb9a164466eb84dd3d46f720d5d92ef909
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5616791
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/lib/Transforms/Scalar/LoopDeletion.cpp b/lib/Transforms/Scalar/LoopDeletion.cpp
index 6c2c1d60548f5a8a7939fee70728e8a34572b648..6cd1fba7c085b6d61dcb23b073358fc4c798e099 100644
--- a/lib/Transforms/Scalar/LoopDeletion.cpp
+++ b/lib/Transforms/Scalar/LoopDeletion.cpp
@@ -195,15 +195,29 @@ bool LoopDeletion::runOnLoop(Loop *L, LPPassManager &LPM) {
// Rewrite phis in the exit block to get their inputs from
// the preheader instead of the exiting block.
- BasicBlock *exitingBlock = exitingBlocks[0];
BasicBlock::iterator BI = exitBlock->begin();
while (PHINode *P = dyn_cast<PHINode>(BI)) {
- int j = P->getBasicBlockIndex(exitingBlock);
- assert(j >= 0 && "Can't find exiting block in exit block's phi node!");
- P->setIncomingBlock(j, preheader);
- for (unsigned i = 1; i < exitingBlocks.size(); ++i)
- P->removeIncomingValue(exitingBlocks[i]);
+ // HLSL Change begin - apply https://reviews.llvm.org/D34516
+ // Set the zero'th element of Phi to be from the preheader and remove all
+ // other incoming values. Given the loop has dedicated exits, all other
+ // incoming values must be from the exiting blocks.
+ int PredIndex = 0;
+ P->setIncomingBlock(PredIndex, preheader);
+ // Removes all incoming values from all other exiting blocks (including
+ // duplicate values from an exiting block).
+ // Nuke all entries except the zero'th entry which is the preheader entry.
+ // NOTE! We need to remove Incoming Values in the reverse order as done
+ // below, to keep the indices valid for deletion (removeIncomingValues
+ // updates getNumIncomingValues and shifts all values down into the operand
+ // being deleted).
+ for (unsigned i = 0, e = P->getNumIncomingValues() - 1; i != e; ++i)
+ P->removeIncomingValue(e - i, false);
+
+ assert((P->getNumIncomingValues() == 1 &&
+ P->getIncomingBlock(PredIndex) == preheader) &&
+ "Should have exactly one value and that's from the preheader!");
++BI;
+ // HLSL Change end
}
// Update the dominator tree and remove the instructions and blocks that will
diff --git a/tools/clang/test/DXC/Passes/DxilLoopDeletion/dxil-loop-deletion-phi-with-duplicate-preds.ll b/tools/clang/test/DXC/Passes/DxilLoopDeletion/dxil-loop-deletion-phi-with-duplicate-preds.ll
new file mode 100644
index 0000000000000000000000000000000000000000..62736bf2934a5db67ee75386431498f49e101f49
--- /dev/null
+++ b/tools/clang/test/DXC/Passes/DxilLoopDeletion/dxil-loop-deletion-phi-with-duplicate-preds.ll
@@ -0,0 +1,229 @@
+; RUN: %dxopt %s -hlsl-passes-resume -dxil-loop-deletion,NoSink=0 -S | FileCheck %s
+
+; This test was generated from the following HLSL:
+;
+; cbuffer cbuffer_g : register(b0) {
+; uint4 gu4[1];
+; };
+;
+; float4 f() {
+; float4 r = float4(0.0f, 0.0f, 0.0f, 0.0f);
+; int i = 0;
+; int j = 0;
+; while (true) {
+; float a = asfloat(gu4[0].y);
+; int ai = int(a);
+; bool b = (j < ai);
+; if (j >= ai) {
+; break;
+; }
+; bool c = (i > 0);
+; if (c) {
+; break;
+; } else {
+; bool3 b3 = bool3(b.xxx);
+; if (b3[i]) {
+; switch(i) {
+; case 0: return r;
+; case -1: return r;
+; }
+; if (c) {
+; break;
+; }
+; } else {
+; r = float4(0.0f, 0.0f, 0.0f, a);
+; }
+; }
+; i = j;
+; j = (j + 1);
+; }
+; r = (0.0f).xxxx;
+; return r;
+; }
+;
+; struct return_val {
+; float4 value : SV_Target0;
+; };
+;
+; return_val main() {
+; float4 inner_result = f();
+; return_val wrapper_result = (return_val)0;
+; wrapper_result.value = inner_result;
+; return wrapper_result;
+; }
+;
+; When compiling the above with dxc, ASAN reported a use-after-free in simplifycfg,
+; which originated from a delete during the dxil-loop-deletion pass. This was due
+; to a bug in LoopDeletion::runOnLoop that did not properly handle updated PHIs
+; with duplicate input preds. After this test runs, the loop should be deleted,
+; and the program optimized to simply write out 0s to the cbuffer.
+
+; CHECK: define void @main
+; CHECK-NEXT: entry:
+; CHECK-NEXT: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float 0.000000e+00)
+; CHECK-NEXT: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 1, float 0.000000e+00)
+; CHECK-NEXT: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 2, float 0.000000e+00)
+; CHECK-NEXT: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 3, float 0.000000e+00)
+; CHECK-NEXT: ret void
+
+;
+; Output signature:
+;
+; Name Index InterpMode DynIdx
+; -------------------- ----- ---------------------- ------
+; SV_Target 0
+;
+; Buffer Definitions:
+;
+; cbuffer cbuffer_g
+; {
+;
+; struct cbuffer_g
+; {
+;
+; uint4 gu4[1]; ; Offset: 0
+;
+; } cbuffer_g; ; Offset: 0 Size: 16
+;
+; }
+;
+;
+; Resource Bindings:
+;
+; Name Type Format Dim ID HLSL Bind Count
+; ------------------------------ ---------- ------- ----------- ------- -------------- ------
+; cbuffer_g cbuffer NA NA CB0 cb0 1
+;
+target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64"
+target triple = "dxil-ms-dx"
+
+%cbuffer_g = type { [1 x <4 x i32>] }
+%dx.types.Handle = type { i8* }
+%dx.types.ResourceProperties = type { i32, i32 }
+%dx.types.CBufRet.i32 = type { i32, i32, i32, i32 }
+%struct.return_val = type { <4 x float> }
+
+@cbuffer_g = external constant %cbuffer_g
+@.hca = internal unnamed_addr constant [3 x i32] [i32 1, i32 1, i32 1]
+@llvm.used = appending global [1 x i8*] [i8* bitcast (%cbuffer_g* @cbuffer_g to i8*)], section "llvm.metadata"
+
+; Function Attrs: nounwind readnone
+declare %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %cbuffer_g*, i32)"(i32, %cbuffer_g*, i32) #0
+
+; Function Attrs: nounwind readnone
+declare %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %cbuffer_g)"(i32, %dx.types.Handle, %dx.types.ResourceProperties, %cbuffer_g) #0
+
+; Function Attrs: nounwind
+define void @main(<4 x float>* noalias nocapture readnone) #1 {
+entry:
+ %1 = load %cbuffer_g, %cbuffer_g* @cbuffer_g, align 4, !dbg !25 ; line:45 col:25
+ %cbuffer_g = call %dx.types.Handle @dx.op.createHandleForLib.cbuffer_g(i32 160, %cbuffer_g %1), !dbg !25 ; line:45 col:25 ; CreateHandleForLib(Resource)
+ %2 = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle %cbuffer_g, %dx.types.ResourceProperties { i32 13, i32 16 }), !dbg !25 ; line:45 col:25 ; AnnotateHandle(res,props) resource: CBuffer
+ %3 = call %dx.types.CBufRet.i32 @dx.op.cbufferLoadLegacy.i32(i32 59, %dx.types.Handle %2, i32 0), !dbg !29 ; line:10 col:23 ; CBufferLoadLegacy(handle,regIndex)
+ %4 = extractvalue %dx.types.CBufRet.i32 %3, 1, !dbg !29 ; line:10 col:23
+ %5 = bitcast i32 %4 to float, !dbg !32 ; line:10 col:15
+ %conv.i.6 = fptosi float %5 to i32, !dbg !33 ; line:11 col:18
+ %cmp1.i.8 = icmp sgt i32 %conv.i.6, 0, !dbg !34 ; line:13 col:11
+ br i1 %cmp1.i.8, label %if.end.i, label %"\01?f@@YA?AV?$vector@M$03@@XZ.exit", !dbg !35 ; line:13 col:9
+
+if.end.i: ; preds = %entry, %if.end.19.i
+ %6 = phi float [ %9, %if.end.19.i ], [ %5, %entry ]
+ %j.i.011 = phi i32 [ %add.i, %if.end.19.i ], [ 0, %entry ]
+ %r.i.0.i310 = phi float [ %r.i.0.i310, %if.end.19.i ], [ 0.000000e+00, %entry ]
+ %i.i.09 = phi i32 [ %j.i.011, %if.end.19.i ], [ 0, %entry ]
+ %cmp4.i = icmp sgt i32 %i.i.09, 0, !dbg !36 ; line:16 col:17
+ br i1 %cmp4.i, label %"\01?f@@YA?AV?$vector@M$03@@XZ.exit", label %if.then.12.i, !dbg !37 ; line:17 col:9
+
+if.then.12.i: ; preds = %if.end.i
+ switch i32 %i.i.09, label %if.end.19.i [
+ i32 0, label %"\01?f@@YA?AV?$vector@M$03@@XZ.exit"
+ i32 -1, label %"\01?f@@YA?AV?$vector@M$03@@XZ.exit"
+ ], !dbg !38 ; line:22 col:9
+
+if.end.19.i: ; preds = %if.then.12.i
+ %add.i = add nuw nsw i32 %j.i.011, 1, !dbg !39 ; line:34 col:12
+ %7 = call %dx.types.CBufRet.i32 @dx.op.cbufferLoadLegacy.i32(i32 59, %dx.types.Handle %2, i32 0), !dbg !29 ; line:10 col:23 ; CBufferLoadLegacy(handle,regIndex)
+ %8 = extractvalue %dx.types.CBufRet.i32 %7, 1, !dbg !29 ; line:10 col:23
+ %9 = bitcast i32 %8 to float, !dbg !32 ; line:10 col:15
+ %conv.i = fptosi float %9 to i32, !dbg !33 ; line:11 col:18
+ %cmp.i = icmp slt i32 %add.i, %conv.i, !dbg !40 ; line:12 col:17
+ br i1 %cmp.i, label %if.end.i, label %"\01?f@@YA?AV?$vector@M$03@@XZ.exit", !dbg !35 ; line:13 col:9
+
+"\01?f@@YA?AV?$vector@M$03@@XZ.exit": ; preds = %if.then.12.i, %if.then.12.i, %if.end.i, %if.end.19.i, %entry
+ %retval.i.0.i3 = phi float [ 0.000000e+00, %entry ], [ %r.i.0.i310, %if.then.12.i ], [ %r.i.0.i310, %if.then.12.i ], [ 0.000000e+00, %if.end.i ], [ 0.000000e+00, %if.end.19.i ]
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float 0.000000e+00), !dbg !41 ; line:48 col:10 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 1, float 0.000000e+00), !dbg !41 ; line:48 col:10 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 2, float 0.000000e+00), !dbg !41 ; line:48 col:10 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
+ call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 3, float %retval.i.0.i3), !dbg !41 ; line:48 col:10 ; StoreOutput(outputSigId,rowIndex,colIndex,value)
+ ret void, !dbg !42 ; line:48 col:3
+}
+
+; Function Attrs: nounwind
+declare void @dx.op.storeOutput.f32(i32, i32, i32, i8, float) #1
+
+; Function Attrs: nounwind readonly
+declare %dx.types.CBufRet.i32 @dx.op.cbufferLoadLegacy.i32(i32, %dx.types.Handle, i32) #2
+
+; Function Attrs: nounwind readonly
+declare %dx.types.Handle @dx.op.createHandleForLib.cbuffer_g(i32, %cbuffer_g) #2
+
+; Function Attrs: nounwind readnone
+declare %dx.types.Handle @dx.op.annotateHandle(i32, %dx.types.Handle, %dx.types.ResourceProperties) #0
+
+attributes #0 = { nounwind readnone }
+attributes #1 = { nounwind }
+attributes #2 = { nounwind readonly }
+
+!llvm.module.flags = !{!0}
+!pauseresume = !{!1}
+!llvm.ident = !{!2}
+!dx.version = !{!3}
+!dx.valver = !{!4}
+!dx.shaderModel = !{!5}
+!dx.resources = !{!6}
+!dx.typeAnnotations = !{!9, !14}
+!dx.entryPoints = !{!21}
+
+!0 = !{i32 2, !"Debug Info Version", i32 3}
+!1 = !{!"hlsl-dxilemit", !"hlsl-dxilload"}
+!2 = !{!"dxc(private) 1.8.0.4514 (d9bd2a706-dirty)"}
+!3 = !{i32 1, i32 5}
+!4 = !{i32 1, i32 8}
+!5 = !{!"ps", i32 6, i32 5}
+!6 = !{null, null, !7, null}
+!7 = !{!8}
+!8 = !{i32 0, %cbuffer_g* @cbuffer_g, !"cbuffer_g", i32 0, i32 0, i32 1, i32 16, null}
+!9 = !{i32 0, %struct.return_val undef, !10, %cbuffer_g undef, !12}
+!10 = !{i32 16, !11}
+!11 = !{i32 6, !"value", i32 3, i32 0, i32 4, !"SV_Target0", i32 7, i32 9}
+!12 = !{i32 16, !13}
+!13 = !{i32 6, !"gu4", i32 3, i32 0, i32 7, i32 5}
+!14 = !{i32 1, void (<4 x float>*)* @main, !15}
+!15 = !{!16, !18}
+!16 = !{i32 0, !17, !17}
+!17 = !{}
+!18 = !{i32 1, !19, !20}
+!19 = !{i32 4, !"SV_Target0", i32 7, i32 9}
+!20 = !{i32 0}
+!21 = !{void (<4 x float>*)* @main, !"main", !22, !6, null}
+!22 = !{null, !23, null}
+!23 = !{!24}
+!24 = !{i32 0, !"SV_Target", i8 9, i8 16, !20, i8 0, i32 1, i8 4, i32 0, i8 0, null}
+!25 = !DILocation(line: 45, column: 25, scope: !26)
+!26 = !DISubprogram(name: "main", scope: !27, file: !27, line: 44, type: !28, isLocal: false, isDefinition: true, scopeLine: 44, flags: DIFlagPrototyped, isOptimized: false, function: void (<4 x float>*)* @main)
+!27 = !DIFile(filename: "/mnt/c/Users/amaiorano/Downloads/340196361/standalone_reduced.hlsl", directory: "")
+!28 = !DISubroutineType(types: !17)
+!29 = !DILocation(line: 10, column: 23, scope: !30, inlinedAt: !31)
+!30 = !DISubprogram(name: "f", scope: !27, file: !27, line: 5, type: !28, isLocal: false, isDefinition: true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false)
+!31 = distinct !DILocation(line: 45, column: 25, scope: !26)
+!32 = !DILocation(line: 10, column: 15, scope: !30, inlinedAt: !31)
+!33 = !DILocation(line: 11, column: 18, scope: !30, inlinedAt: !31)
+!34 = !DILocation(line: 13, column: 11, scope: !30, inlinedAt: !31)
+!35 = !DILocation(line: 13, column: 9, scope: !30, inlinedAt: !31)
+!36 = !DILocation(line: 16, column: 17, scope: !30, inlinedAt: !31)
+!37 = !DILocation(line: 17, column: 9, scope: !30, inlinedAt: !31)
+!38 = !DILocation(line: 22, column: 9, scope: !30, inlinedAt: !31)
+!39 = !DILocation(line: 34, column: 12, scope: !30, inlinedAt: !31)
+!40 = !DILocation(line: 12, column: 17, scope: !30, inlinedAt: !31)
+!41 = !DILocation(line: 48, column: 10, scope: !26)
+!42 = !DILocation(line: 48, column: 3, scope: !26)

View File

@@ -0,0 +1,57 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Antonio Maiorano <amaiorano@google.com>
Date: Thu, 18 Apr 2024 13:07:04 -0400
Subject: Replace dynamic_cast with virtual call (#6515)
Make TextDiagnosticPrinter::setPrefix a virtual function in base class
DiagnosticConsumer. This allows us to avoid using dynamic_cast in
BackendConsumer::DxilDiagHandler, required for codebases that do not
enable RTTI. This is also the only place in the codebase that uses RTTI
(AFAICT).
Bug: chromium:333420620
Change-Id: Ida73077f24fdb4b705b5d868b04ac6cfecb30327
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5464347
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Reviewed-by: David Neto <dneto@google.com>
diff --git a/tools/clang/include/clang/Basic/Diagnostic.h b/tools/clang/include/clang/Basic/Diagnostic.h
index dc9f781c093c0bc8f6da773d514ac6d1503f842d..0b98dffb94185e242320409d43b74dae2c2a908d 100644
--- a/tools/clang/include/clang/Basic/Diagnostic.h
+++ b/tools/clang/include/clang/Basic/Diagnostic.h
@@ -1395,6 +1395,8 @@ public:
/// warnings and errors.
virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
const Diagnostic &Info);
+
+ virtual void setPrefix(std::string Value) {} // HLSL Change
};
/// \brief A diagnostic client that ignores all diagnostics.
diff --git a/tools/clang/include/clang/Frontend/TextDiagnosticPrinter.h b/tools/clang/include/clang/Frontend/TextDiagnosticPrinter.h
index 04a570559fe06a0670ef8a7e6e94c40aa37e55a9..936031e09673a09c6e1164c515efce02ac51b910 100644
--- a/tools/clang/include/clang/Frontend/TextDiagnosticPrinter.h
+++ b/tools/clang/include/clang/Frontend/TextDiagnosticPrinter.h
@@ -45,7 +45,8 @@ public:
/// setPrefix - Set the diagnostic printer prefix string, which will be
/// printed at the start of any diagnostics. If empty, no prefix string is
/// used.
- void setPrefix(std::string Value) { Prefix = Value; }
+ // HLSL Change: add override
+ void setPrefix(std::string Value) override { Prefix = Value; }
void BeginSourceFile(const LangOptions &LO, const Preprocessor *PP) override;
void EndSourceFile() override;
diff --git a/tools/clang/lib/CodeGen/CodeGenAction.cpp b/tools/clang/lib/CodeGen/CodeGenAction.cpp
index 4fa721e812296356e31fc1bf6ea35ce295c2592c..68ebaadf5a8960c8def189248412136fe9543422 100644
--- a/tools/clang/lib/CodeGen/CodeGenAction.cpp
+++ b/tools/clang/lib/CodeGen/CodeGenAction.cpp
@@ -557,7 +557,7 @@ BackendConsumer::DxilDiagHandler(const llvm::DiagnosticInfoDxil &D) {
// If no location information is available, add function name
if (Loc.isInvalid()) {
- auto *DiagClient = dynamic_cast<TextDiagnosticPrinter*>(Diags.getClient());
+ auto *DiagClient = Diags.getClient();
auto *func = D.getFunction();
if (DiagClient && func)
DiagClient->setPrefix("Function: " + func->getName().str());

View File

@@ -0,0 +1,161 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Antonio Maiorano <amaiorano@google.com>
Date: Thu, 25 Apr 2024 16:49:11 -0400
Subject: Fixed crash in loop unroll caused by bug in structurize loop exits
(#6548)
Fixed a bug in `hlsl::RemoveUnstructuredLoopExits` where when a new
exiting block is created from splitting, it was added to the current
loop being processed, when it could also part of an inner loop. Not
adding the new block to inner loops that it's part of makes the inner
loops malformed, and causes crash.
This fix adds the new block to the inner most loop that it should be
part of. Also adds the `StructurizeLoopExits` option to `loop-unroll`
pass, which was missing before.
Bug: chromium:333508731
Change-Id: I7efc21bc61aeb81b4906a600c35272af232710ea
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5490380
Reviewed-by: James Price <jrprice@google.com>
Reviewed-by: Ben Clayton <bclayton@chromium.org>
diff --git a/lib/Transforms/Scalar/DxilRemoveUnstructuredLoopExits.cpp b/lib/Transforms/Scalar/DxilRemoveUnstructuredLoopExits.cpp
index b6a07d6b27a23ee3831e84cee82299d6d405a288..ef6718f0f22ee33e3f16f9801a64c1a6fb6c653a 100644
--- a/lib/Transforms/Scalar/DxilRemoveUnstructuredLoopExits.cpp
+++ b/lib/Transforms/Scalar/DxilRemoveUnstructuredLoopExits.cpp
@@ -447,7 +447,12 @@ static bool RemoveUnstructuredLoopExitsIteration(BasicBlock *exiting_block,
new_exiting_block->splitBasicBlock(new_exiting_block->getFirstNonPHI());
new_exiting_block->setName("dx.struct_exit.new_exiting");
new_not_exiting_block->setName(old_name);
- L->addBasicBlockToLoop(new_not_exiting_block, *LI);
+ // Query for new_exiting_block's own loop to add new_not_exiting_block to.
+ // It's possible that new_exiting_block is part of another inner loop
+ // separate from L. If added directly to L, the inner loop(s) will not
+ // contain new_not_exiting_block, making them malformed.
+ Loop *inner_loop_of_exiting_block = LI->getLoopFor(new_exiting_block);
+ inner_loop_of_exiting_block->addBasicBlockToLoop(new_not_exiting_block, *LI);
// Branch to latch_exit
new_exiting_block->getTerminator()->eraseFromParent();
diff --git a/lib/Transforms/Scalar/LoopUnrollPass.cpp b/lib/Transforms/Scalar/LoopUnrollPass.cpp
index dd520f7e57d25311be7f3773849a00efaabe6717..b17a5a4a0bc368f16020c4153370ea2c92e5c26c 100644
--- a/lib/Transforms/Scalar/LoopUnrollPass.cpp
+++ b/lib/Transforms/Scalar/LoopUnrollPass.cpp
@@ -155,6 +155,18 @@ namespace {
bool UserAllowPartial;
bool UserRuntime;
+ // HLSL Change - begin
+ // Function overrides that resolve options when used for DxOpt
+ void applyOptions(PassOptions O) override {
+ GetPassOptionBool(O, "StructurizeLoopExits", &StructurizeLoopExits,
+ false);
+ }
+ void dumpConfig(raw_ostream &OS) override {
+ LoopPass::dumpConfig(OS);
+ OS << ",StructurizeLoopExits=" << StructurizeLoopExits;
+ }
+ // HLSL Change - end
+
bool runOnLoop(Loop *L, LPPassManager &LPM) override;
/// This transformation requires natural loop information & requires that
diff --git a/tools/clang/test/DXC/loop_structurize_exit_inner_latch_regression.ll b/tools/clang/test/DXC/loop_structurize_exit_inner_latch_regression.ll
new file mode 100644
index 0000000000000000000000000000000000000000..743135541cd8faec287164ba3b321a59432832b6
--- /dev/null
+++ b/tools/clang/test/DXC/loop_structurize_exit_inner_latch_regression.ll
@@ -0,0 +1,75 @@
+; RUN: %dxopt %s -S -loop-unroll,StructurizeLoopExits=1 | FileCheck %s
+; RUN: %dxopt %s -S -dxil-loop-unroll,StructurizeLoopExits=1 | FileCheck %s
+
+; CHECK: mul nsw i32
+; CHECK: mul nsw i32
+; CHECK-NOT: mul nsw i32
+
+; This is a regression test for a crash in loop unroll. When there are multiple
+; exits, the compiler will run hlsl::RemoveUnstructuredLoopExits to try to
+; avoid unstructured code.
+;
+; In this test, the compiler will try to unroll the middle loop. The exit edge
+; from %land.lhs.true to %if.then will be removed, and %if.end will be split at
+; the beginning, and branch to %if.end instead.
+;
+; Since the new split block at %if.end becomes the new latch of the inner-most
+; loop, it needs to be added to the Loop analysis structure of the inner loop.
+; However, it was only added to the current middle loop that is being unrolled.
+
+target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64"
+target triple = "dxil-ms-dx"
+
+; Function Attrs: nounwind
+define void @main(i32 *%arg0, i32 *%arg1, i32 *%arg2) #0 {
+entry:
+ br label %while.body.3.preheader.lr.ph
+
+while.body.3.preheader.lr.ph.loopexit: ; preds = %for.inc
+ br label %while.body.3.preheader.lr.ph
+
+while.body.3.preheader.lr.ph: ; preds = %while.body.3.preheader.lr.ph.loopexit, %entry
+ br label %while.body.3.preheader
+
+while.body.3.preheader: ; preds = %while.body.3.preheader.lr.ph, %for.inc
+ %i.0 = phi i32 [ 0, %while.body.3.preheader.lr.ph ], [ %inc, %for.inc ]
+ br label %while.body.3
+
+while.body.3: ; preds = %while.body.3.preheader, %if.end
+ %load_arg0 = load i32, i32* %arg0
+ %cmp4 = icmp sgt i32 %load_arg0, 0
+ br i1 %cmp4, label %land.lhs.true, label %if.end
+
+land.lhs.true: ; preds = %while.body.3
+ %load_arg1 = load i32, i32* %arg1
+ %load_arg2 = load i32, i32* %arg2
+ %mul = mul nsw i32 %load_arg2, %load_arg1
+ %cmp7 = icmp eq i32 %mul, 10
+ br i1 %cmp7, label %if.then, label %if.end
+
+if.then: ; preds = %land.lhs.true
+ ret void
+
+if.end: ; preds = %land.lhs.true, %while.body.3
+ %cmp10 = icmp sle i32 %i.0, 4
+ br i1 %cmp10, label %for.inc, label %while.body.3
+
+for.inc: ; preds = %if.end
+ %inc = add nsw i32 %i.0, 1
+ %cmp = icmp slt i32 %inc, 2
+ br i1 %cmp, label %while.body.3.preheader, label %while.body.3.preheader.lr.ph.loopexit, !llvm.loop !3
+}
+
+attributes #0 = { nounwind }
+attributes #1 = { nounwind readnone }
+attributes #2 = { nounwind readonly }
+
+!llvm.module.flags = !{!0}
+!pauseresume = !{!1}
+!llvm.ident = !{!2}
+
+!0 = !{i32 2, !"Debug Info Version", i32 3}
+!1 = !{!"hlsl-dxilemit", !"hlsl-dxilload"}
+!2 = !{!"dxc(private) 1.8.0.14563 (main, 07ce88034-dirty)"}
+!3 = distinct !{!3, !4}
+!4 = !{!"llvm.loop.unroll.full"}
diff --git a/utils/hct/hctdb.py b/utils/hct/hctdb.py
index 77f5671016eb66a4ddf8a943ec8cb05e8d87c9cd..ca8d16bd2562e26e8572413499d32dc2232de5c0 100644
--- a/utils/hct/hctdb.py
+++ b/utils/hct/hctdb.py
@@ -6680,6 +6680,12 @@ class db_dxil(object):
"t": "unsigned",
"d": "Unrolled size limit for loops with an unroll(full) or unroll_count pragma.",
},
+ {
+ "n": "StructurizeLoopExits",
+ "t": "bool",
+ "c": 1,
+ "d": "Whether the unroller should try to structurize loop exits first.",
+ },
],
)
add_pass("mldst-motion", "MergedLoadStoreMotion", "MergedLoadStoreMotion", [])

5
patches/angle/.patches Normal file
View File

@@ -0,0 +1,5 @@
m123_vulkan_fix_access_to_inactive_attributes.patch
cherry-pick-f6672dbbe223.patch
cherry-pick-ba3b4e239620.patch
cherry-pick-c67f290ef0f0.patch
cherry-pick-bda89e1f7c71.patch

View File

@@ -0,0 +1,249 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shahbaz Youssefi <syoussefi@chromium.org>
Date: Mon, 8 Apr 2024 10:14:45 -0400
Subject: M123: SPIR-V: Fix const constructors with single scalar
These constructors may be generated because of
RemoveArrayLengthTraverser.
Bug: chromium:332546345
Change-Id: I2b2bf3728ef5bae148abc2a8518f8f3f42850025
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5462388
(cherry picked from commit 0b776d32f69a932acb61963d9daad9e13f610944)
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5473406
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Daniel Gagnon <dgagnon@google.com>
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
index eddc5e724e8e949aff0624c6caf9aadec7c14647..57a71c5d13fbf5e458c26b084e1f9834edb37f58 100644
--- a/src/compiler/translator/Compiler.cpp
+++ b/src/compiler/translator/Compiler.cpp
@@ -1056,6 +1056,11 @@ bool TCompiler::checkAndSimplifyAST(TIntermBlock *root,
{
return false;
}
+ // Fold the expressions again, because |RemoveArrayLengthMethod| can introduce new constants.
+ if (!FoldExpressions(this, root, &mDiagnostics))
+ {
+ return false;
+ }
if (!RemoveUnreferencedVariables(this, root, &mSymbolTable))
{
diff --git a/src/compiler/translator/spirv/OutputSPIRV.cpp b/src/compiler/translator/spirv/OutputSPIRV.cpp
index caa8f956716abf53aaeb58a5f654f5a4f04c4d6a..67b1fdd4784660483a408f1ee27ce48b05ffcb0a 100644
--- a/src/compiler/translator/spirv/OutputSPIRV.cpp
+++ b/src/compiler/translator/spirv/OutputSPIRV.cpp
@@ -1335,6 +1335,8 @@ spirv::IdRef OutputSPIRVTraverser::createComplexConstant(const TType &type,
if (type.isMatrix() && !type.isArray())
{
+ ASSERT(parameters.size() == type.getRows() * type.getCols());
+
// Matrices are constructed from their columns.
spirv::IdRefList columnIds;
diff --git a/src/tests/gl_tests/GLSLTest.cpp b/src/tests/gl_tests/GLSLTest.cpp
index cfe6414d52647db92669be954cadd15344603559..a4035db329548491c91e2f7383f837001540c065 100644
--- a/src/tests/gl_tests/GLSLTest.cpp
+++ b/src/tests/gl_tests/GLSLTest.cpp
@@ -8486,6 +8486,198 @@ void main()
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
+// Test that array length inside vector constructor works.
+TEST_P(GLSLTest_ES3, ArrayLengthInVectorConstructor)
+{
+ const char kVS[] = R"(#version 300 es
+precision highp float;
+flat out uvec4 v;
+
+int[1] f0()
+{
+ return int[1](1);
+}
+void main()
+{
+ v = uvec4(vec4(f0().length()));
+
+ gl_Position.x = ((gl_VertexID & 1) == 0 ? -1.0 : 1.0);
+ gl_Position.y = ((gl_VertexID & 2) == 0 ? -1.0 : 1.0);
+ gl_Position.zw = vec2(0, 1);
+})";
+
+ const char kFS[] = R"(#version 300 es
+precision highp float;
+flat in uvec4 v;
+out vec4 color;
+
+bool isEq(uint a, float b) { return abs(float(a) - b) < 0.01; }
+
+void main()
+{
+ if (isEq(v[0], 1.) &&
+ isEq(v[1], 1.) &&
+ isEq(v[2], 1.) &&
+ isEq(v[3], 1.))
+ {
+ color = vec4(0, 1, 0, 1);
+ }
+ else
+ {
+ color = vec4(1, 0, 0, 1);
+ }
+})";
+
+ ANGLE_GL_PROGRAM(program, kVS, kFS);
+ glUseProgram(program);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+}
+
+// Test that array length inside vector constructor works in complex expression.
+TEST_P(GLSLTest_ES3, ArrayLengthInVectorConstructorComplex)
+{
+ const char kVS[] = R"(#version 300 es
+precision highp float;
+out vec4 v;
+
+int[1] f0()
+{
+ return int[1](1);
+}
+void main()
+{
+ v = vec4(float(uint(f0().length()) + 1u) / 4.);
+
+ gl_Position.x = ((gl_VertexID & 1) == 0 ? -1.0 : 1.0);
+ gl_Position.y = ((gl_VertexID & 2) == 0 ? -1.0 : 1.0);
+ gl_Position.zw = vec2(0, 1);
+})";
+
+ const char kFS[] = R"(#version 300 es
+precision highp float;
+in vec4 v;
+out vec4 color;
+
+bool isEq(float a, float b) { return abs(float(a) - b) < 0.01; }
+
+void main()
+{
+ if (isEq(v[0], 0.5) &&
+ isEq(v[1], 0.5) &&
+ isEq(v[2], 0.5) &&
+ isEq(v[3], 0.5))
+ {
+ color = vec4(0, 1, 0, 1);
+ }
+ else
+ {
+ color = vec4(1, 0, 0, 1);
+ }
+})";
+
+ ANGLE_GL_PROGRAM(program, kVS, kFS);
+ glUseProgram(program);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+}
+
+// Test that array length inside matrix constructor works.
+TEST_P(GLSLTest_ES3, ArrayLengthInMatrixConstructor)
+{
+ const char kVS[] = R"(#version 300 es
+precision highp float;
+out mat2x2 v;
+
+int[1] f0()
+{
+ return int[1](1);
+}
+void main()
+{
+ v = mat2x2(f0().length());
+
+ gl_Position.x = ((gl_VertexID & 1) == 0 ? -1.0 : 1.0);
+ gl_Position.y = ((gl_VertexID & 2) == 0 ? -1.0 : 1.0);
+ gl_Position.zw = vec2(0, 1);
+})";
+
+ const char kFS[] = R"(#version 300 es
+precision highp float;
+in mat2x2 v;
+out vec4 color;
+
+bool isEq(float a, float b) { return abs(a - b) < 0.01; }
+
+void main()
+{
+ if (isEq(v[0][0], 1.) &&
+ isEq(v[0][1], 0.) &&
+ isEq(v[1][0], 0.) &&
+ isEq(v[1][1], 1.))
+ {
+ color = vec4(0, 1, 0, 1);
+ }
+ else
+ {
+ color = vec4(1, 0, 0, 1);
+ }
+})";
+
+ ANGLE_GL_PROGRAM(program, kVS, kFS);
+ glUseProgram(program);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+}
+
+// Test that array length inside vector constructor inside matrix constructor works.
+TEST_P(GLSLTest_ES3, ArrayLengthInVectorInMatrixConstructor)
+{
+ const char kVS[] = R"(#version 300 es
+precision highp float;
+out mat2x2 v;
+
+int[1] f0()
+{
+ return int[1](1);
+}
+void main()
+{
+ v = mat2x2(vec2(f0().length()), f0().length(), 0);
+
+ gl_Position.x = ((gl_VertexID & 1) == 0 ? -1.0 : 1.0);
+ gl_Position.y = ((gl_VertexID & 2) == 0 ? -1.0 : 1.0);
+ gl_Position.zw = vec2(0, 1);
+})";
+
+ const char kFS[] = R"(#version 300 es
+precision highp float;
+in mat2x2 v;
+out vec4 color;
+
+bool isEq(float a, float b) { return abs(a - b) < 0.01; }
+
+void main()
+{
+ if (isEq(v[0][0], 1.) &&
+ isEq(v[0][1], 1.) &&
+ isEq(v[1][0], 1.) &&
+ isEq(v[1][1], 0.))
+ {
+ color = vec4(0, 1, 0, 1);
+ }
+ else
+ {
+ color = vec4(1, 0, 0, 1);
+ }
+})";
+
+ ANGLE_GL_PROGRAM(program, kVS, kFS);
+ glUseProgram(program);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+}
+
// Test that statements inside switch() get translated to correct HLSL.
TEST_P(GLSLTest_ES3, DifferentStatementsInsideSwitch)
{

View File

@@ -0,0 +1,74 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shahbaz Youssefi <syoussefi@chromium.org>
Date: Thu, 2 May 2024 11:17:33 -0400
Subject: M124: Vulkan: Turn SPIR-V limitations to crash instead of security
bug
The input shader can be made complex in a number of different ways,
resulting in instructions with a length higher than what can fit in
SPIR-V (i.e. 16 bits). Ideally, the translator would catch such complex
usage early on and gracefully fail compilation. However, as a safety
net, this change makes sure such a case is detected when the SPIR-V
instruction is being generated and turned into a crash. This makes sure
such bugs are no longer security bugs.
Bug: chromium:335613092
Change-Id: Iab16b49ed80929fc343b4c7bffce306919de2e96
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5547611
Reviewed-by: Roman Lavrov <romanl@google.com>
diff --git a/scripts/code_generation_hashes/SPIR-V_helpers.json b/scripts/code_generation_hashes/SPIR-V_helpers.json
index cb1b596b6d02f35e2817cac53ace42d64e33bffd..944cf1a2cbd34a0e28e7cfad4b874344f662512b 100644
--- a/scripts/code_generation_hashes/SPIR-V_helpers.json
+++ b/scripts/code_generation_hashes/SPIR-V_helpers.json
@@ -1,8 +1,8 @@
{
"src/common/spirv/gen_spirv_builder_and_parser.py":
- "e95670a30a4eda80a146b61c986fb03c",
+ "868a697edbc38c95e36be54cf5c71435",
"src/common/spirv/spirv_instruction_builder_autogen.cpp":
- "1b5f60a24d459e7a30c29cf7acfa2106",
+ "c149de371bcd571bd31cc8eb1e517910",
"src/common/spirv/spirv_instruction_builder_autogen.h":
"56b1309d8afabb2b64d7e16f0c4a4898",
"src/common/spirv/spirv_instruction_parser_autogen.cpp":
diff --git a/src/common/spirv/gen_spirv_builder_and_parser.py b/src/common/spirv/gen_spirv_builder_and_parser.py
index 5e8e9bc4e8914cf2173a8fa720446f6647dd065e..c7e1f401b380f3b4fe0bd6b9178b42ee5ac41250 100755
--- a/src/common/spirv/gen_spirv_builder_and_parser.py
+++ b/src/common/spirv/gen_spirv_builder_and_parser.py
@@ -93,6 +93,15 @@ uint32_t MakeLengthOp(size_t length, spv::Op op)
ASSERT(length <= 0xFFFFu);
ASSERT(op <= 0xFFFFu);
+ // It's easy for a complex shader to be crafted to hit the length limit,
+ // turn that into a crash instead of a security bug. Ideally, the compiler
+ // would gracefully fail compilation, so this is more of a safety net.
+ if (ANGLE_UNLIKELY(length > 0xFFFFu))
+ {
+ ERR() << "Complex shader not representible in SPIR-V";
+ ANGLE_CRASH();
+ }
+
return static_cast<uint32_t>(length) << 16 | op;
}
} // anonymous namespace
diff --git a/src/common/spirv/spirv_instruction_builder_autogen.cpp b/src/common/spirv/spirv_instruction_builder_autogen.cpp
index 3c73c58e3c0141f3e00a61eab784d3e3b96dff8e..6e6ad6f510cb76588f61dacee8dbcac5a544d8d1 100644
--- a/src/common/spirv/spirv_instruction_builder_autogen.cpp
+++ b/src/common/spirv/spirv_instruction_builder_autogen.cpp
@@ -25,6 +25,15 @@ uint32_t MakeLengthOp(size_t length, spv::Op op)
ASSERT(length <= 0xFFFFu);
ASSERT(op <= 0xFFFFu);
+ // It's easy for a complex shader to be crafted to hit the length limit,
+ // turn that into a crash instead of a security bug. Ideally, the compiler
+ // would gracefully fail compilation, so this is more of a safety net.
+ if (ANGLE_UNLIKELY(length > 0xFFFFu))
+ {
+ ERR() << "Complex shader not representible in SPIR-V";
+ ANGLE_CRASH();
+ }
+
return static_cast<uint32_t>(length) << 16 | op;
}
} // anonymous namespace

View File

@@ -0,0 +1,32 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Geoff Lang <geofflang@chromium.org>
Date: Mon, 29 Apr 2024 15:27:36 -0400
Subject: M124: GL: Sync unpack state for glCompressedTexSubImage3D
Unpack state is supposed to be ignored for compressed tex image calls
but some drivers use it anyways and read incorrect data.
Texture3DTestES3.PixelUnpackStateTexSubImage covers this case.
Bug: chromium:337766133
Change-Id: Ic11a056113b1850bd5b4d6840527164a12849a22
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5498735
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
(cherry picked from commit 1bb1ee061fe0bce322fb93b447a72e72c993a1f2)
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5518811
Commit-Queue: Srinivas Sista <srinivassista@chromium.org>
Reviewed-by: Srinivas Sista <srinivassista@chromium.org>
diff --git a/src/libANGLE/renderer/gl/TextureGL.cpp b/src/libANGLE/renderer/gl/TextureGL.cpp
index c659aacb9e48d7eab033f0ea59d3514f557a430b..f96eefe53f11a8a57fc88998c2ba22a2dacf1d65 100644
--- a/src/libANGLE/renderer/gl/TextureGL.cpp
+++ b/src/libANGLE/renderer/gl/TextureGL.cpp
@@ -664,6 +664,7 @@ angle::Result TextureGL::setCompressedSubImage(const gl::Context *context,
nativegl::GetCompressedSubTexImageFormat(functions, features, format);
stateManager->bindTexture(getType(), mTextureID);
+ ANGLE_TRY(stateManager->setPixelUnpackState(context, unpack));
if (nativegl::UseTexImage2D(getType()))
{
ASSERT(area.z == 0 && area.depth == 1);

View File

@@ -0,0 +1,267 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shahbaz Youssefi <syoussefi@chromium.org>
Date: Mon, 25 Mar 2024 14:46:56 -0400
Subject: M123: Translator: Disallow samplers in structs in interface blocks
As disallowed by the spec:
> Types and declarators are the same as for other uniform variable
> declarations outside blocks, with these exceptions:
>
> * opaque types are not allowed
Bug: chromium:328859176
Change-Id: Ib94977860102329e520e635c3757827c93ca2163
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5391986
Auto-Submit: Shahbaz Youssefi <syoussefi@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
(cherry picked from commit a0fa06f6d79ced897c0fe2795551268199d29806)
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5435737
Reviewed-by: Yuly Novikov <ynovikov@chromium.org>
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index 38bd4ca13a4a8828ebbe64e19bd740639bce5083..98b4dc46fec65269a87ee920d8e63a1d0350fbae 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -34,27 +34,39 @@ namespace
const int kWebGLMaxStructNesting = 4;
-bool ContainsSampler(const TStructure *structType);
+struct IsSamplerFunc
+{
+ bool operator()(TBasicType type) { return IsSampler(type); }
+};
+struct IsOpaqueFunc
+{
+ bool operator()(TBasicType type) { return IsOpaqueType(type); }
+};
+
+template <typename OpaqueFunc>
+bool ContainsOpaque(const TStructure *structType);
-bool ContainsSampler(const TType &type)
+template <typename OpaqueFunc>
+bool ContainsOpaque(const TType &type)
{
- if (IsSampler(type.getBasicType()))
+ if (OpaqueFunc{}(type.getBasicType()))
{
return true;
}
if (type.getBasicType() == EbtStruct)
{
- return ContainsSampler(type.getStruct());
+ return ContainsOpaque<OpaqueFunc>(type.getStruct());
}
return false;
}
-bool ContainsSampler(const TStructure *structType)
+template <typename OpaqueFunc>
+bool ContainsOpaque(const TStructure *structType)
{
for (const auto &field : structType->fields())
{
- if (ContainsSampler(*field->type()))
+ if (ContainsOpaque<OpaqueFunc>(*field->type()))
return true;
}
return false;
@@ -1113,7 +1125,7 @@ bool TParseContext::checkIsNotOpaqueType(const TSourceLoc &line,
{
if (pType.type == EbtStruct)
{
- if (ContainsSampler(pType.userDef))
+ if (ContainsOpaque<IsSamplerFunc>(pType.userDef))
{
std::stringstream reasonStream = sh::InitializeStream<std::stringstream>();
reasonStream << reason << " (structure contains a sampler)";
@@ -4979,12 +4991,9 @@ TIntermDeclaration *TParseContext::addInterfaceBlock(
{
TField *field = (*fieldList)[memberIndex];
TType *fieldType = field->type();
- if (IsOpaqueType(fieldType->getBasicType()))
+ if (ContainsOpaque<IsOpaqueFunc>(*fieldType))
{
- std::string reason("unsupported type - ");
- reason += fieldType->getBasicString();
- reason += " types are not allowed in interface blocks";
- error(field->line(), reason.c_str(), fieldType->getBasicString());
+ error(field->line(), "Opaque types are not allowed in interface blocks", blockName);
}
const TQualifier qualifier = fieldType->getQualifier();
diff --git a/src/tests/gl_tests/GLSLTest.cpp b/src/tests/gl_tests/GLSLTest.cpp
index ed63153e49b2425a974a497a1fae2f9fdc79afa6..cfe6414d52647db92669be954cadd15344603559 100644
--- a/src/tests/gl_tests/GLSLTest.cpp
+++ b/src/tests/gl_tests/GLSLTest.cpp
@@ -6716,7 +6716,34 @@ void main()
gl_FragColor = vec4(f(us), 0, 0, 1);
})";
- CompileShader(GL_FRAGMENT_SHADER, kFS);
+ GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);
+ EXPECT_NE(fs, 0u);
+ ASSERT_GL_NO_ERROR();
+}
+
+// Test that structs with samplers are not allowed in interface blocks. This is forbidden per
+// GLES3:
+//
+// > Types and declarators are the same as for other uniform variable declarations outside blocks,
+// > with these exceptions:
+// > * opaque types are not allowed
+TEST_P(GLSLTest_ES3, StructWithSamplersDisallowedInInterfaceBlock)
+{
+ const char kFS[] = R"(#version 300 es
+precision mediump float;
+struct S { sampler2D samp; bool b; };
+
+layout(std140) uniform Buffer { S s; } buffer;
+
+out vec4 color;
+
+void main()
+{
+ color = texture(buffer.s.samp, vec2(0));
+})";
+
+ GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);
+ EXPECT_EQ(fs, 0u);
ASSERT_GL_NO_ERROR();
}
@@ -18357,6 +18384,116 @@ void main() {
EXPECT_EQ(0u, shader);
}
+// Same as TooManyFieldsInStruct, but with samplers in the struct.
+TEST_P(GLSLTest_ES3, TooManySamplerFieldsInStruct)
+{
+ std::ostringstream fs;
+ fs << R"(#version 300 es
+precision highp float;
+struct TooManyFields
+{
+)";
+ for (uint32_t i = 0; i < (1 << 16); ++i)
+ {
+ fs << " sampler2D field" << i << ";\n";
+ }
+ fs << R"(};
+uniform TooManyFields s;
+out vec4 color;
+void main() {
+ color = texture(s.field0, vec2(0));
+})";
+
+ GLuint shader = CompileShader(GL_FRAGMENT_SHADER, fs.str().c_str());
+ EXPECT_EQ(0u, shader);
+}
+
+// More complex variation of ManySamplerFieldsInStruct. This one compiles fine.
+TEST_P(GLSLTest_ES3, ManySamplerFieldsInStructComplex)
+{
+ // D3D and OpenGL may be more restrictive about this many samplers.
+ ANGLE_SKIP_TEST_IF(IsD3D() || IsOpenGL());
+
+ std::ostringstream fs;
+ fs << R"(#version 300 es
+precision highp float;
+
+struct X {
+ mediump sampler2D a[0xf00];
+ mediump sampler2D b[0xf00];
+ mediump sampler2D c[0xf000];
+ mediump sampler2D d[0xf00];
+};
+
+struct Y {
+ X s1;
+ mediump sampler2D a[0xf00];
+ mediump sampler2D b[0xf000];
+ mediump sampler2D c[0x14000];
+};
+
+struct S {
+ Y s1;
+};
+
+struct structBuffer { S s; };
+
+uniform structBuffer b;
+
+out vec4 color;
+void main()
+{
+ color = texture(b.s.s1.s1.c[0], vec2(0));
+})";
+
+ GLuint shader = CompileShader(GL_FRAGMENT_SHADER, fs.str().c_str());
+ EXPECT_NE(0u, shader);
+}
+
+// Make sure a large array of samplers works.
+TEST_P(GLSLTest, ManySamplers)
+{
+ // D3D and OpenGL may be more restrictive about this many samplers.
+ ANGLE_SKIP_TEST_IF(IsD3D() || IsOpenGL());
+
+ std::ostringstream fs;
+ fs << R"(precision highp float;
+
+uniform mediump sampler2D c[0x12000];
+
+void main()
+{
+ gl_FragColor = texture2D(c[0], vec2(0));
+})";
+
+ GLuint shader = CompileShader(GL_FRAGMENT_SHADER, fs.str().c_str());
+ EXPECT_NE(0u, shader);
+}
+
+// Make sure a large array of samplers works when declared in a struct.
+TEST_P(GLSLTest, ManySamplersInStruct)
+{
+ // D3D and OpenGL may be more restrictive about this many samplers.
+ ANGLE_SKIP_TEST_IF(IsD3D() || IsOpenGL());
+
+ std::ostringstream fs;
+ fs << R"(precision highp float;
+
+struct X {
+ mediump sampler2D c[0x12000];
+};
+
+uniform X x;
+
+void main()
+{
+ gl_FragColor = texture2D(x.c[0], vec2(0));
+})";
+
+ GLuint shader = CompileShader(GL_FRAGMENT_SHADER, fs.str().c_str());
+ EXPECT_NE(0u, shader);
+}
+
// Test that passing large arrays to functions are compiled correctly. Regression test for the
// SPIR-V generator that made a copy of the array to pass to the function, by decomposing and
// reconstructing it (in the absence of OpCopyLogical), but the reconstruction instruction has a
diff --git a/src/tests/gl_tests/PixelLocalStorageTest.cpp b/src/tests/gl_tests/PixelLocalStorageTest.cpp
index c49ba5741ad565ad9637fb2188a472ccbebc6284..126936271eb25eec601349a560fabc6f0f7d4b75 100644
--- a/src/tests/gl_tests/PixelLocalStorageTest.cpp
+++ b/src/tests/gl_tests/PixelLocalStorageTest.cpp
@@ -5573,8 +5573,7 @@ TEST_P(PixelLocalStorageCompilerTest, Declarations)
EXPECT_FALSE(log.compileFragmentShader(kPLSInStruct));
EXPECT_TRUE(log.has("ERROR: 0:5: 'pixelLocalANGLE' : disallowed type in struct"));
EXPECT_TRUE(
- log.has("ERROR: 0:10: 'pixelLocalANGLE' : unsupported type - pixelLocalANGLE types are not "
- "allowed in interface blocks"));
+ log.has("ERROR: 0:10: 'PLSBlock' : Opaque types are not allowed in interface blocks"));
ASSERT_GL_NO_ERROR();
}

View File

@@ -0,0 +1,112 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Geoff Lang <geofflang@chromium.org>
Date: Tue, 12 Mar 2024 16:06:37 -0400
Subject: M123: Vulkan: Fix access to inactive attributes
... within range of active ones. Since a buffer is bound for inactive
attributes, it must be considered accessed.
Ultimately, the nullDescriptor feature could be used to avoid binding a
buffer for inactive attributes.
Bug: chromium:327807820
Change-Id: I953b419d8ec51760e8848409024cad5083888fa2
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5386431
Reviewed-by: Shahbaz Youssefi <syoussefi@google.com>
diff --git a/src/libANGLE/renderer/vulkan/ContextVk.cpp b/src/libANGLE/renderer/vulkan/ContextVk.cpp
index 63bfa0729b266ceca54e10153f561f74a1be0c27..a0cbaf8cefbae1453922e09aadcd13df6f478782 100644
--- a/src/libANGLE/renderer/vulkan/ContextVk.cpp
+++ b/src/libANGLE/renderer/vulkan/ContextVk.cpp
@@ -2610,8 +2610,7 @@ angle::Result ContextVk::handleDirtyGraphicsVertexBuffers(DirtyBits::Iterator *d
vertexArrayVk->getCurrentArrayBuffers();
// Mark all active vertex buffers as accessed.
- const gl::AttributesMask attribsMask = executable->getActiveAttribLocationsMask();
- for (size_t attribIndex : attribsMask)
+ for (uint32_t attribIndex = 0; attribIndex < maxAttrib; ++attribIndex)
{
vk::BufferHelper *arrayBuffer = arrayBufferResources[attribIndex];
if (arrayBuffer)
diff --git a/src/tests/gl_tests/VertexAttributeTest.cpp b/src/tests/gl_tests/VertexAttributeTest.cpp
index b8a1c87728b3ba54a32cf0e4da6ca626c05d1d92..773bbf026821795c0db34239d27fd2bb1e5a751a 100644
--- a/src/tests/gl_tests/VertexAttributeTest.cpp
+++ b/src/tests/gl_tests/VertexAttributeTest.cpp
@@ -1256,6 +1256,19 @@ class VertexAttributeOORTest : public VertexAttributeTest
}
};
+class RobustVertexAttributeTest : public VertexAttributeTest
+{
+ public:
+ RobustVertexAttributeTest()
+ {
+ // mac GL and metal do not support robustness.
+ if (!IsMac() && !IsIOS())
+ {
+ setRobustAccess(true);
+ }
+ }
+};
+
// Verify that drawing with a large out-of-range offset generates INVALID_OPERATION.
// Requires WebGL compatibility with robust access behaviour disabled.
TEST_P(VertexAttributeOORTest, ANGLEDrawArraysBufferTooSmall)
@@ -1316,6 +1329,48 @@ TEST_P(VertexAttributeOORTest, ANGLEDrawArraysOutOfBoundsCases)
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
}
+// Test that enabling a buffer in an unused attribute doesn't crash. There should be an active
+// attribute after that.
+TEST_P(RobustVertexAttributeTest, BoundButUnusedBuffer)
+{
+ constexpr char kVS[] = R"(attribute vec2 offset;
+void main()
+{
+ gl_Position = vec4(offset.xy, 0, 1);
+ gl_PointSize = 1.0;
+})";
+
+ constexpr char kFS[] = R"(precision mediump float;
+void main()
+{
+ gl_FragColor = vec4(1.0, 0, 0, 1.0);
+})";
+
+ const GLuint vs = CompileShader(GL_VERTEX_SHADER, kVS);
+ const GLuint fs = CompileShader(GL_FRAGMENT_SHADER, kFS);
+
+ GLuint program = glCreateProgram();
+ glBindAttribLocation(program, 1, "offset");
+ glAttachShader(program, vs);
+ glAttachShader(program, fs);
+ glLinkProgram(program);
+
+ GLBuffer buffer;
+ glBindBuffer(GL_ARRAY_BUFFER, buffer);
+ glBufferData(GL_ARRAY_BUFFER, 100, nullptr, GL_STATIC_DRAW);
+
+ // Enable an unused attribute that is within the range of active attributes (not beyond it)
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(0, 4, GL_FLOAT, false, 0, 0);
+
+ glUseProgram(program);
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+
+ // Destroy the buffer. Regression test for a tracking bug where the buffer was used by
+ // SwiftShader (even though location 1 is inactive), but not marked as used by ANGLE.
+ buffer.reset();
+}
+
// Verify that using a different start vertex doesn't mess up the draw.
TEST_P(VertexAttributeTest, DrawArraysWithBufferOffset)
{
@@ -4913,6 +4968,8 @@ ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND(
ES3_METAL().disable(Feature::HasExplicitMemBarrier).disable(Feature::HasCheapRenderPass),
ES3_METAL().disable(Feature::HasExplicitMemBarrier).enable(Feature::HasCheapRenderPass));
+ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(RobustVertexAttributeTest);
+
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VertexAttributeTestES3);
ANGLE_INSTANTIATE_TEST_ES3_AND(
VertexAttributeTestES3,

View File

@@ -131,4 +131,22 @@ fix_suppress_clang_-wimplicit-const-int-float-conversion_in.patch
cherry-pick-e7ffe20ebfac.patch
fix_getcursorscreenpoint_wrongly_returns_0_0.patch
fix_add_support_for_skipping_first_2_no-op_refreshes_in_thumb_cap.patch
revert_same_party_cookie_attribute_removal.patch
remove_dxdiag_telemetry_code.patch
cherry-pick-2607ddacd643.patch
cherry-pick-1b1f34234346.patch
bindings_refactor_domdatastore.patch
merge_fix_domarraybuffer_isdetached_and_comment_out_a_check.patch
cherry-pick-98bcf9ef5cdd.patch
cherry-pick-c1f25647c2fc.patch
cherry-pick-013961609785.patch
a11y_avoid_clearing_resetting_focus_on_an_already_focus_event.patch
cherry-pick-b2cc7b7ac538.patch
feat_add_support_for_missing_dialog_features_to_shell_dialogs.patch
cherry-pick-03609e39be8c.patch
x11_use_localized_display_label_only_for_browser_process.patch
cherry-pick-b922fcb61e3b.patch
cherry-pick-0d9598145069.patch
cherry-pick-24329fe5c4d0.patch
m120-lts_mediasession_use_a_mediasessionimpl_weakptr_in.patch
x11_fix_crash_when_randr_getmonitors_fails.patch
feat_enable_passing_exit_code_on_service_process_crash.patch

View File

@@ -0,0 +1,56 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Benjamin Beaudry <benjamin.beaudry@microsoft.com>
Date: Fri, 8 Mar 2024 21:16:50 +0000
Subject: Avoid clearing/resetting focus on an already focus event
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
When we set the focus via an accessibility API on an element that
is already focused, we first remove the focus and reset it. This
leads to blur/focusout/focusin events being fired again.
This behavior is different than the one we get when we set focus
programmatically, with a mouse, or a keyboard, on an already
focused element. In order to keep the same experience across all
input modalities, this CL removes the divergent focus behavior
for accessibility APIs.
We tried to remove this code two years ago (CL:3547796) but it
got reverted due to bug:40850837. This time, I made sure to discuss
this issue with the Chrome Android accessibility owners to make 
sure it's safe to remove. They landed CL:5345750, and then gave
us the green light to land this CL.
Fixed: 40830307
Change-Id: I8ad70ed6813e0ae52238292f1b7e6d038a5238f1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5356613
Reviewed-by: Mark Schillaci <mschillaci@google.com>
Commit-Queue: Benjamin Beaudry <benjamin.beaudry@microsoft.com>
Auto-Submit: Benjamin Beaudry <benjamin.beaudry@microsoft.com>
Cr-Commit-Position: refs/heads/main@{#1270380}
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
index a94e88e79c4fb5ed1336a776eafe3e302f5d50f8..a5c4b06e278f805e81799b2d19f27bffe0701c68 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -5095,19 +5095,6 @@ bool AXNodeObject::OnNativeFocusAction() {
return true;
}
- // If this node is already the currently focused node, then calling
- // focus() won't do anything. That is a problem when focus is removed
- // from the webpage to chrome, and then returns. In these cases, we need
- // to do what keyboard and mouse focus do, which is reset focus first.
- if (document->FocusedElement() == element) {
- document->ClearFocusedElement();
-
- // Calling ClearFocusedElement could result in changes to the document,
- // like this AXObject becoming detached.
- if (IsDetached())
- return false;
- }
-
if (base::FeatureList::IsEnabled(blink::features::kSimulateClickOnAXFocus)) {
// If the object is not natively focusable but can be focused using an ARIA
// active descendant, perform a native click instead. This will enable Web

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,139 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: John Stiles <johnstiles@google.com>
Date: Thu, 28 Mar 2024 00:51:13 +0000
Subject: Detect overflow in JPEG image size calculations.
Bug: 330756841
Change-Id: Ib30493152e08fd2347f76de276c5805d6fef9a7d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5402199
Commit-Queue: John Stiles <johnstiles@google.com>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1279376}
diff --git a/ui/gfx/codec/jpeg_codec.cc b/ui/gfx/codec/jpeg_codec.cc
index a4de17094e69b36bb2c34b3b4f70eece9c088cc3..595966d724146df33701b1225e659ec085ca115b 100644
--- a/ui/gfx/codec/jpeg_codec.cc
+++ b/ui/gfx/codec/jpeg_codec.cc
@@ -6,10 +6,12 @@
#include <setjmp.h>
+#include <climits>
#include <memory>
#include <ostream>
#include "base/notreached.h"
+#include "base/numerics/checked_math.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkColorPriv.h"
#include "ui/gfx/codec/vector_wstream.h"
@@ -244,16 +246,27 @@ bool JPEGCodec::Decode(const unsigned char* input, size_t input_size,
jpeg_start_decompress(cinfo.get());
- // FIXME(brettw) we may want to allow the capability for callers to request
- // how to align row lengths as we do for the compressor.
- int row_read_stride = cinfo->output_width * cinfo->output_components;
+ // Confirm that the image width * height * component-size fits within an int.
+ // Note that image width and height are unsigned ints (JDIMENSION) in memory,
+ // but the file format only holds a uint16.
+ base::CheckedNumeric<size_t> checked_output_size = cinfo->output_width;
+ checked_output_size *= cinfo->output_components;
- // Create memory for a decoded image and write decoded lines to the memory
- // without conversions same as JPEGCodec::Encode().
- int row_write_stride = row_read_stride;
- output->resize(row_write_stride * cinfo->output_height);
+ // This shouldn't ever overflow a `size_t`; it's multiplying a uint16 by four.
+ size_t row_write_stride = checked_output_size.ValueOrDie();
- for (int row = 0; row < static_cast<int>(cinfo->output_height); row++) {
+ // Extremely large JPEGs could overflow here if `size_t` is 32 bits.
+ checked_output_size *= cinfo->output_height;
+ size_t output_size = checked_output_size.ValueOrDefault(INT_MAX);
+ if (output_size >= INT_MAX) {
+ return false;
+ }
+
+ // Create memory for a decoded image.
+ output->resize(output_size);
+
+ // Write decoded lines to the memory.
+ for (unsigned int row = 0; row < cinfo->output_height; row++) {
unsigned char* rowptr = &(*output)[row * row_write_stride];
if (!jpeg_read_scanlines(cinfo.get(), &rowptr, 1))
return false;
diff --git a/ui/gfx/codec/jpeg_codec_unittest.cc b/ui/gfx/codec/jpeg_codec_unittest.cc
index 9f1bee95e0e476b34382aceffbf6df3bdde095ea..b446fe77896e254820db77afe7ed4e48b8525c79 100644
--- a/ui/gfx/codec/jpeg_codec_unittest.cc
+++ b/ui/gfx/codec/jpeg_codec_unittest.cc
@@ -61,6 +61,53 @@ const uint8_t kTopSitesMigrationTestImage[] =
"\xfa\xff\xda\x00\x0c\x03\x01\x00\x02\x11\x03\x11\x00\x3f\x00\xf9"
"\xd2\x8a\x28\xaf\xc3\x0f\xf5\x4c\xff\xd9";
+// This is a copy of the above JPEG, with the Start-of-Frame header manually
+// rewritten to indicate an image size of 25000x25000. An image this large would
+// require more than 2GB of RAM to decode, so the decoder will reject the image
+// as soon as the header is parsed.
+const uint8_t kExtremelyLargeTestImage[] =
+ "\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49\x46\x00\x01\x01\x00\x00\x01"
+ "\x00\x01\x00\x00\xff\xdb\x00\x43\x00\x03\x02\x02\x03\x02\x02\x03"
+ "\x03\x03\x03\x04\x03\x03\x04\x05\x08\x05\x05\x04\x04\x05\x0a\x07"
+ "\x07\x06\x08\x0c\x0a\x0c\x0c\x0b\x0a\x0b\x0b\x0d\x0e\x12\x10\x0d"
+ "\x0e\x11\x0e\x0b\x0b\x10\x16\x10\x11\x13\x14\x15\x15\x15\x0c\x0f"
+ "\x17\x18\x16\x14\x18\x12\x14\x15\x14\xff\xdb\x00\x43\x01\x03\x04"
+ "\x04\x05\x04\x05\x09\x05\x05\x09\x14\x0d\x0b\x0d\x14\x14\x14\x14"
+ "\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14"
+ "\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14"
+ "\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\xff\xc0"
+ "\x00\x11\x08\x61\xa8\x61\xa8\x03\x01\x22\x00\x02\x11\x01\x03\x11"
+ // ^^ ^^ ^^ ^^ image size forced to 25000x25000
+ "\x01\xff\xc4\x00\x1f\x00\x00\x01\x05\x01\x01\x01\x01\x01\x01\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09"
+ "\x0a\x0b\xff\xc4\x00\xb5\x10\x00\x02\x01\x03\x03\x02\x04\x03\x05"
+ "\x05\x04\x04\x00\x00\x01\x7d\x01\x02\x03\x00\x04\x11\x05\x12\x21"
+ "\x31\x41\x06\x13\x51\x61\x07\x22\x71\x14\x32\x81\x91\xa1\x08\x23"
+ "\x42\xb1\xc1\x15\x52\xd1\xf0\x24\x33\x62\x72\x82\x09\x0a\x16\x17"
+ "\x18\x19\x1a\x25\x26\x27\x28\x29\x2a\x34\x35\x36\x37\x38\x39\x3a"
+ "\x43\x44\x45\x46\x47\x48\x49\x4a\x53\x54\x55\x56\x57\x58\x59\x5a"
+ "\x63\x64\x65\x66\x67\x68\x69\x6a\x73\x74\x75\x76\x77\x78\x79\x7a"
+ "\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96\x97\x98\x99"
+ "\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6\xb7"
+ "\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4\xd5"
+ "\xd6\xd7\xd8\xd9\xda\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf1"
+ "\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xff\xc4\x00\x1f\x01\x00\x03"
+ "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x01"
+ "\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\xff\xc4\x00\xb5\x11\x00"
+ "\x02\x01\x02\x04\x04\x03\x04\x07\x05\x04\x04\x00\x01\x02\x77\x00"
+ "\x01\x02\x03\x11\x04\x05\x21\x31\x06\x12\x41\x51\x07\x61\x71\x13"
+ "\x22\x32\x81\x08\x14\x42\x91\xa1\xb1\xc1\x09\x23\x33\x52\xf0\x15"
+ "\x62\x72\xd1\x0a\x16\x24\x34\xe1\x25\xf1\x17\x18\x19\x1a\x26\x27"
+ "\x28\x29\x2a\x35\x36\x37\x38\x39\x3a\x43\x44\x45\x46\x47\x48\x49"
+ "\x4a\x53\x54\x55\x56\x57\x58\x59\x5a\x63\x64\x65\x66\x67\x68\x69"
+ "\x6a\x73\x74\x75\x76\x77\x78\x79\x7a\x82\x83\x84\x85\x86\x87\x88"
+ "\x89\x8a\x92\x93\x94\x95\x96\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6"
+ "\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xc2\xc3\xc4"
+ "\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xe2"
+ "\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9"
+ "\xfa\xff\xda\x00\x0c\x03\x01\x00\x02\x11\x03\x11\x00\x3f\x00\xf9"
+ "\xd2\x8a\x28\xaf\xc3\x0f\xf5\x4c\xff\xd9";
+
} // namespace
namespace gfx {
@@ -211,4 +258,15 @@ TEST(JPEGCodec, ParallelEncoding) {
encode_loop.Run();
}
+TEST(JPEGCodec, ExtremelyLargeImage) {
+ std::vector<unsigned char> output;
+ int outw, outh;
+ bool ok = JPEGCodec::Decode(kExtremelyLargeTestImage,
+ std::size(kExtremelyLargeTestImage),
+ JPEGCodec::FORMAT_RGBA, &output, &outw, &outh);
+ EXPECT_FALSE(ok);
+ EXPECT_EQ(outw, 25000);
+ EXPECT_EQ(outh, 25000);
+}
+
} // namespace gfx

View File

@@ -0,0 +1,117 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: David Benjamin <davidben@chromium.org>
Date: Fri, 10 May 2024 15:10:48 +0000
Subject: Fix size calculations in V8StringToUTF8
While I'm here, remove the unnecessary use of base::WriteInto, which is
a remnant of C++03 copy-on-write strings. Also ask V8 not to write a
NUL terminator because std::(u16)string already owns that byte.
(cherry picked from commit f414dc31032a453f4a6c88977d7894fcb3cba44e)
Bug: 338574384
Change-Id: I5c6eaa99093925db799736f321eab92d35f5acbb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5515743
Reviewed-by: mmenke <mmenke@chromium.org>
Commit-Queue: David Benjamin <davidben@chromium.org>
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1297196}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5527764
Auto-Submit: David Benjamin <davidben@chromium.org>
Commit-Queue: mmenke <mmenke@chromium.org>
Cr-Commit-Position: refs/branch-heads/6367@{#1148}
Cr-Branched-From: d158c6dc6e3604e6f899041972edf26087a49740-refs/heads/main@{#1274542}
diff --git a/services/proxy_resolver/proxy_resolver_v8.cc b/services/proxy_resolver/proxy_resolver_v8.cc
index eca8014359b60f54d47c46aa7e106da83ec8a85f..da8232b229f3c6387d5ec063b197650ea24ec292 100644
--- a/services/proxy_resolver/proxy_resolver_v8.cc
+++ b/services/proxy_resolver/proxy_resolver_v8.cc
@@ -17,6 +17,7 @@
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ptr_exclusion.h"
#include "base/notreached.h"
+#include "base/numerics/safe_conversions.h"
#include "base/strings/string_tokenizer.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -148,25 +149,22 @@ const size_t kMaxStringBytesForCopy = 256;
// Converts a V8 String to a UTF8 std::string.
std::string V8StringToUTF8(v8::Isolate* isolate, v8::Local<v8::String> s) {
- int len = s->Length();
- std::string result;
- if (len > 0)
- s->WriteUtf8(isolate, base::WriteInto(&result, len + 1));
- return result;
+ int len = s->Utf8Length(isolate);
+ std::string str(base::checked_cast<size_t>(len), '\0');
+ s->WriteUtf8(isolate, str.data(), len, /*nchars_ref=*/nullptr,
+ v8::String::NO_NULL_TERMINATION);
+ return str;
}
// Converts a V8 String to a UTF16 std::u16string.
std::u16string V8StringToUTF16(v8::Isolate* isolate, v8::Local<v8::String> s) {
int len = s->Length();
- std::u16string result;
- // Note that the reinterpret cast is because on Windows string16 is an alias
- // to wstring, and hence has character type wchar_t not uint16_t.
- if (len > 0) {
- s->Write(isolate,
- reinterpret_cast<uint16_t*>(base::WriteInto(&result, len + 1)), 0,
- len);
- }
- return result;
+ std::u16string str(base::checked_cast<size_t>(len), '\0');
+ // `char16_t` and `uint16_t` are not the same type, but we build with strict
+ // aliasing off. See https://crbug.com/42209752.
+ s->Write(isolate, reinterpret_cast<uint16_t*>(str.data()), /*start=*/0, len,
+ v8::String::NO_NULL_TERMINATION);
+ return str;
}
// Converts an ASCII std::string to a V8 string.
diff --git a/services/proxy_resolver/test/data/proxy_resolver_v8_unittest/pac_library_unittest.js b/services/proxy_resolver/test/data/proxy_resolver_v8_unittest/pac_library_unittest.js
index 3414dc0b4a33a64c8fe09b0d2a5cd48123a5d9ac..1b8bc17862f0c3cfa4fdc97121619afac8777a9d 100644
--- a/services/proxy_resolver/test/data/proxy_resolver_v8_unittest/pac_library_unittest.js
+++ b/services/proxy_resolver/test/data/proxy_resolver_v8_unittest/pac_library_unittest.js
@@ -69,6 +69,11 @@ Tests.testIsPlainHostName = function(t) {
t.expectFalse(isPlainHostName("."));
t.expectFalse(isPlainHostName(".:"));
+ // These are not really hostnames, but `isPlainHostName` accepts any dotless,
+ // non-IP string.
+ t.expectTrue(isPlainHostName("\uffff".repeat(256)));
+ t.expectTrue(isPlainHostName(""));
+
// Valid IPv6 address
t.expectFalse(isPlainHostName("::1"));
@@ -178,6 +183,7 @@ Tests.testSortIpAddressList = function(t) {
t.expectEquals(null, sortIpAddressList());
t.expectEquals(null, sortIpAddressList(null));
t.expectEquals(null, sortIpAddressList(null, null));
+ t.expectEquals(null, sortIpAddressList("\uffff".repeat(256)));
};
Tests.testIsInNetEx = function(t) {
@@ -223,10 +229,14 @@ Tests.testIsInNetEx = function(t) {
// Invalid IP address.
t.expectFalse(isInNetEx("256.0.0.1", "198.95.249.79"));
t.expectFalse(isInNetEx("127.0.0.1 ", "127.0.0.1/32")); // Extra space.
+ t.expectFalse(isInNetEx("\uffff".repeat(256), "127.0.0.1/32"));
+ t.expectFalse(isInNetEx("", "127.0.0.1/32"));
// Invalid prefix.
t.expectFalse(isInNetEx("198.95.115.10", "198.95.0.0/34"));
t.expectFalse(isInNetEx("127.0.0.1", "127.0.0.1")); // Missing '/' in prefix.
+ t.expectFalse(isInNetEx("127.0.0.1", "\uffff".repeat(256)));
+ t.expectFalse(isInNetEx("127.0.0.1", ""));
};
Tests.testWeekdayRange = function(t) {
@@ -465,4 +475,3 @@ MockDate.setCurrent = function(currentDateString) {
// Bind the methods to proxy requests to the wrapped Date().
MockDate.init();
-

View File

@@ -0,0 +1,805 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Brendon Tiszka <tiszka@chromium.org>
Date: Mon, 20 May 2024 18:33:53 +0000
Subject: Fix bugs in GLES* command handlers
If the command buffer is in an invalid state then we can't trust
the contents of the get buffer.
(cherry picked from commit 374789ab8f5eeac24e2e335af825d34b8c3fde81)
Bug: 340822365,40947303
Change-Id: I465d617e5056877fb464dd59df983a9e8d866b85
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5542488
Commit-Queue: Brendon Tiszka <tiszka@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1301529}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5550571
Reviewed-by: Brendon Tiszka <tiszka@chromium.org>
Owners-Override: Prudhvikumar Bommana <pbommana@google.com>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/branch-heads/6367@{#1205}
Cr-Branched-From: d158c6dc6e3604e6f899041972edf26087a49740-refs/heads/main@{#1274542}
diff --git a/gpu/command_buffer/build_cmd_buffer_lib.py b/gpu/command_buffer/build_cmd_buffer_lib.py
index b8ca818edd2d225ea6309f202edbba6e957f1f35..4f1aa8efefd3ef8591aad3e90fc57f4b78347317 100644
--- a/gpu/command_buffer/build_cmd_buffer_lib.py
+++ b/gpu/command_buffer/build_cmd_buffer_lib.py
@@ -2954,7 +2954,9 @@ class GETnHandler(TypeHandler):
result->SetNumResults(0);
helper_->%(func_name)s(%(arg_string)s,
GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
result->CopyResult(%(last_arg_name)s);
GPU_CLIENT_LOG_CODE_BLOCK({
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
@@ -4456,7 +4458,9 @@ TEST_P(%(test_name)s, %(name)sInvalidArgsBadSharedMemoryId) {
f.write(
" helper_->%s(%s, GetResultShmId(), result.offset());\n" %
(func.name, arg_string))
- f.write(" WaitForCmd();\n")
+ f.write(" if (!WaitForCmd()) {\n")
+ f.write(" return %s; \n" % error_value)
+ f.write(" }\n")
f.write(" %s result_value = *result" % func.return_type)
if func.return_type == "GLboolean":
f.write(" != 0")
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index e02399bcbdc6b2e642751038aa47ecfdf80e587c..ad9aa976ec776ff6be69c57c701bbcfc7cdfbd93 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -595,7 +595,9 @@ GLenum GLES2Implementation::GetGLError() {
}
*result = GL_NO_ERROR;
helper_->GetError(GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return GL_NO_ERROR;
+ }
GLenum error = *result;
if (error == GL_NO_ERROR) {
error = GetClientSideGLError();
@@ -720,7 +722,9 @@ GLboolean GLES2Implementation::IsEnabled(GLenum cap) {
}
*result = 0;
helper_->IsEnabled(cap, GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return GL_FALSE;
+ }
state = (*result) != 0;
}
@@ -741,7 +745,9 @@ GLboolean GLES2Implementation::IsEnablediOES(GLenum target, GLuint index) {
auto result = GetResultAs<Result>();
*result = 0;
helper_->IsEnablediOES(target, index, GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return GL_FALSE;
+ }
state = (*result) != 0;
}
@@ -1360,7 +1366,9 @@ GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUMHelper(GLuint buffer_id,
*result = 0;
helper_->GetMaxValueInBufferCHROMIUM(buffer_id, count, type, offset,
GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return 0;
+ }
return *result;
}
@@ -1663,7 +1671,9 @@ void GLES2Implementation::GetVertexAttribPointerv(GLuint index,
result->SetNumResults(0);
helper_->GetVertexAttribPointerv(index, pname, GetResultShmId(),
result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
result->CopyResult(ptr);
GPU_CLIENT_LOG_CODE_BLOCK(num_results = result->GetNumResults());
}
@@ -1738,7 +1748,9 @@ GLint GLES2Implementation::GetAttribLocationHelper(GLuint program,
*result = -1;
helper_->GetAttribLocation(program, kResultBucketId, GetResultShmId(),
result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return -1;
+ }
helper_->SetBucketSize(kResultBucketId, 0);
return *result;
}
@@ -1766,7 +1778,9 @@ GLint GLES2Implementation::GetUniformLocationHelper(GLuint program,
*result = -1;
helper_->GetUniformLocation(program, kResultBucketId, GetResultShmId(),
result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return -1;
+ }
helper_->SetBucketSize(kResultBucketId, 0);
return *result;
}
@@ -1799,7 +1813,9 @@ bool GLES2Implementation::GetUniformIndicesHelper(GLuint program,
result->SetNumResults(0);
helper_->GetUniformIndices(program, kResultBucketId, GetResultShmId(),
result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return false;
+ }
if (result->GetNumResults() != count) {
return false;
}
@@ -1859,7 +1875,9 @@ GLint GLES2Implementation::GetFragDataIndexEXTHelper(GLuint program,
*result = -1;
helper_->GetFragDataIndexEXT(program, kResultBucketId, GetResultShmId(),
result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return -1;
+ }
helper_->SetBucketSize(kResultBucketId, 0);
return *result;
}
@@ -1888,7 +1906,9 @@ GLint GLES2Implementation::GetFragDataLocationHelper(GLuint program,
*result = -1;
helper_->GetFragDataLocation(program, kResultBucketId, GetResultShmId(),
result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return -1;
+ }
helper_->SetBucketSize(kResultBucketId, 0);
return *result;
}
@@ -1917,7 +1937,9 @@ GLuint GLES2Implementation::GetUniformBlockIndexHelper(GLuint program,
*result = GL_INVALID_INDEX;
helper_->GetUniformBlockIndex(program, kResultBucketId, GetResultShmId(),
result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return GL_INVALID_INDEX;
+ }
helper_->SetBucketSize(kResultBucketId, 0);
return *result;
}
@@ -1962,7 +1984,9 @@ GLuint GLES2Implementation::GetProgramResourceIndexHelper(
*result = GL_INVALID_INDEX;
helper_->GetProgramResourceIndex(program, program_interface, kResultBucketId,
GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return GL_INVALID_INDEX;
+ }
helper_->SetBucketSize(kResultBucketId, 0);
return *result;
}
@@ -2007,7 +2031,9 @@ bool GLES2Implementation::GetProgramResourceNameHelper(GLuint program,
helper_->GetProgramResourceName(program, program_interface, index,
kResultBucketId, GetResultShmId(),
result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return false;
+ }
success = !!*result;
}
if (success) {
@@ -2066,7 +2092,9 @@ bool GLES2Implementation::GetProgramResourceivHelper(GLuint program,
helper_->GetProgramResourceiv(program, program_interface, index,
kResultBucketId, GetResultShmId(),
result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return false;
+ }
if (length) {
*length = result->GetNumResults();
}
@@ -2138,7 +2166,9 @@ GLint GLES2Implementation::GetProgramResourceLocationHelper(
helper_->GetProgramResourceLocation(program, program_interface,
kResultBucketId, GetResultShmId(),
result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return -1;
+ }
helper_->SetBucketSize(kResultBucketId, 0);
return *result;
}
@@ -4015,7 +4045,9 @@ bool GLES2Implementation::GetActiveAttribHelper(GLuint program,
result->success = false;
helper_->GetActiveAttrib(program, index, kResultBucketId, GetResultShmId(),
result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return false;
+ }
bool success = !!result->success;
if (success) {
if (size) {
@@ -4083,7 +4115,9 @@ bool GLES2Implementation::GetActiveUniformHelper(GLuint program,
result->success = false;
helper_->GetActiveUniform(program, index, kResultBucketId, GetResultShmId(),
result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return false;
+ }
bool success = !!result->success;
if (success) {
if (size) {
@@ -4150,7 +4184,9 @@ bool GLES2Implementation::GetActiveUniformBlockNameHelper(GLuint program,
*result = 0;
helper_->GetActiveUniformBlockName(program, index, kResultBucketId,
GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return false;
+ }
bool success = !!result;
if (success) {
// Note: this can invalidate |result|.
@@ -4197,7 +4233,9 @@ bool GLES2Implementation::GetActiveUniformBlockivHelper(GLuint program,
result->SetNumResults(0);
helper_->GetActiveUniformBlockiv(program, index, pname, GetResultShmId(),
result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return false;
+ }
if (result->GetNumResults() > 0) {
if (params) {
result->CopyResult(params);
@@ -4254,7 +4292,9 @@ bool GLES2Implementation::GetActiveUniformsivHelper(GLuint program,
result->SetNumResults(0);
helper_->GetActiveUniformsiv(program, kResultBucketId, pname,
GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return false;
+ }
bool success = result->GetNumResults() == count;
if (success) {
if (params) {
@@ -4330,7 +4370,9 @@ void GLES2Implementation::GetAttachedShaders(GLuint program,
transfer_buffer_->GetOffset(result),
checked_size);
int32_t token = helper_->InsertToken();
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
if (count) {
*count = result->GetNumResults();
}
@@ -4372,7 +4414,9 @@ void GLES2Implementation::GetShaderPrecisionFormat(GLenum shadertype,
result->success = false;
helper_->GetShaderPrecisionFormat(shadertype, precisiontype,
GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
if (result->success)
static_state_.shader_precisions[key] = *result;
}
@@ -4485,7 +4529,9 @@ bool GLES2Implementation::GetTransformFeedbackVaryingHelper(GLuint program,
result->success = false;
helper_->GetTransformFeedbackVarying(program, index, kResultBucketId,
GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return false;
+ }
if (result->success) {
if (size) {
*size = result->size;
@@ -4553,7 +4599,9 @@ void GLES2Implementation::GetUniformfv(GLuint program,
}
result->SetNumResults(0);
helper_->GetUniformfv(program, location, GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
result->CopyResult(params);
GPU_CLIENT_LOG_CODE_BLOCK({
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
@@ -4581,7 +4629,9 @@ void GLES2Implementation::GetUniformiv(GLuint program,
}
result->SetNumResults(0);
helper_->GetUniformiv(program, location, GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
result->CopyResult(params);
GPU_CLIENT_LOG_CODE_BLOCK({
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
@@ -4610,7 +4660,9 @@ void GLES2Implementation::GetUniformuiv(GLuint program,
result->SetNumResults(0);
helper_->GetUniformuiv(program, location, GetResultShmId(),
result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
result->CopyResult(params);
GPU_CLIENT_LOG_CODE_BLOCK({
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
@@ -4788,7 +4840,9 @@ void GLES2Implementation::ReadbackARGBImagePixelsINTERNAL(
dst_sk_color_type, dst_sk_alpha_type, shm_id, shm_offset,
color_space_offset, pixels_offset, mailbox_offset);
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
if (!*readback_result) {
return;
}
@@ -4936,7 +4990,9 @@ void GLES2Implementation::ReadPixels(GLint xoffset,
helper_->ReadPixels(xoffset, y_index, width, num_rows, format, type,
buffer.shm_id(), buffer.offset(), GetResultShmId(),
result.offset(), false);
- WaitForCmd();
+ if (!WaitForCmd()) {
+ break;
+ }
// If it was not marked as successful exit.
if (!result->success) {
break;
@@ -5645,7 +5701,9 @@ void GLES2Implementation::GetVertexAttribfv(GLuint index,
}
result->SetNumResults(0);
helper_->GetVertexAttribfv(index, pname, GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
result->CopyResult(params);
GPU_CLIENT_LOG_CODE_BLOCK({
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
@@ -5678,7 +5736,9 @@ void GLES2Implementation::GetVertexAttribiv(GLuint index,
}
result->SetNumResults(0);
helper_->GetVertexAttribiv(index, pname, GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
result->CopyResult(params);
GPU_CLIENT_LOG_CODE_BLOCK({
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
@@ -5712,7 +5772,9 @@ void GLES2Implementation::GetVertexAttribIiv(GLuint index,
result->SetNumResults(0);
helper_->GetVertexAttribIiv(index, pname, GetResultShmId(),
result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
result->CopyResult(params);
GPU_CLIENT_LOG_CODE_BLOCK({
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
@@ -5746,7 +5808,9 @@ void GLES2Implementation::GetVertexAttribIuiv(GLuint index,
result->SetNumResults(0);
helper_->GetVertexAttribIuiv(index, pname, GetResultShmId(),
result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
result->CopyResult(params);
GPU_CLIENT_LOG_CODE_BLOCK({
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
@@ -5781,7 +5845,9 @@ GLboolean GLES2Implementation::EnableFeatureCHROMIUM(const char* feature) {
*result = 0;
helper_->EnableFeatureCHROMIUM(kResultBucketId, GetResultShmId(),
result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return false;
+ }
helper_->SetBucketSize(kResultBucketId, 0);
GPU_CLIENT_LOG(" returned " << GLES2Util::GetStringBool(*result));
return *result != 0;
@@ -5936,7 +6002,9 @@ void* GLES2Implementation::MapBufferRange(GLenum target,
GetResultShmId(), result.offset());
// TODO(zmo): For write only mode with MAP_INVALID_*_BIT, we should
// consider an early return without WaitForCmd(). crbug.com/465804.
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return nullptr;
+ }
if (*result) {
const GLbitfield kInvalidateBits =
GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_INVALIDATE_RANGE_BIT;
@@ -7211,7 +7279,9 @@ GLenum GLES2Implementation::ClientWaitSync(GLsync sync,
*result = GL_WAIT_FAILED;
helper_->ClientWaitSync(ToGLuint(sync), flags, timeout, GetResultShmId(),
result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return GL_WAIT_FAILED;
+ }
localResult = *result;
GPU_CLIENT_LOG("returned " << localResult);
}
@@ -7289,7 +7359,9 @@ void GLES2Implementation::GetInternalformativ(GLenum target,
result->SetNumResults(0);
helper_->GetInternalformativ(target, format, pname, GetResultShmId(),
result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
GPU_CLIENT_LOG_CODE_BLOCK({
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
diff --git a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
index 5db0583dceea74aaa819979d2253bb0ae5b03413..9e578e3f4c69a16098250ff22e04b8b4e0391d1b 100644
--- a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
@@ -207,7 +207,9 @@ GLenum GLES2Implementation::CheckFramebufferStatus(GLenum target) {
}
*result = 0;
helper_->CheckFramebufferStatus(target, GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return GL_FRAMEBUFFER_UNSUPPORTED;
+ }
GLenum result_value = *result;
GPU_CLIENT_LOG("returned " << result_value);
CheckGLError();
@@ -882,7 +884,9 @@ void GLES2Implementation::GetBooleanv(GLenum pname, GLboolean* params) {
}
result->SetNumResults(0);
helper_->GetBooleanv(pname, GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
result->CopyResult(params);
GPU_CLIENT_LOG_CODE_BLOCK({
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
@@ -910,7 +914,9 @@ void GLES2Implementation::GetBooleani_v(GLenum pname,
}
result->SetNumResults(0);
helper_->GetBooleani_v(pname, index, GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
result->CopyResult(data);
GPU_CLIENT_LOG_CODE_BLOCK({
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
@@ -939,7 +945,9 @@ void GLES2Implementation::GetBufferParameteri64v(GLenum target,
result->SetNumResults(0);
helper_->GetBufferParameteri64v(target, pname, GetResultShmId(),
result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
result->CopyResult(params);
GPU_CLIENT_LOG_CODE_BLOCK({
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
@@ -969,7 +977,9 @@ void GLES2Implementation::GetBufferParameteriv(GLenum target,
result->SetNumResults(0);
helper_->GetBufferParameteriv(target, pname, GetResultShmId(),
result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
result->CopyResult(params);
GPU_CLIENT_LOG_CODE_BLOCK({
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
@@ -994,7 +1004,9 @@ void GLES2Implementation::GetFloatv(GLenum pname, GLfloat* params) {
}
result->SetNumResults(0);
helper_->GetFloatv(pname, GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
result->CopyResult(params);
GPU_CLIENT_LOG_CODE_BLOCK({
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
@@ -1029,7 +1041,9 @@ void GLES2Implementation::GetFramebufferAttachmentParameteriv(GLenum target,
result->SetNumResults(0);
helper_->GetFramebufferAttachmentParameteriv(
target, attachment, pname, GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
result->CopyResult(params);
GPU_CLIENT_LOG_CODE_BLOCK({
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
@@ -1054,7 +1068,9 @@ void GLES2Implementation::GetInteger64v(GLenum pname, GLint64* params) {
}
result->SetNumResults(0);
helper_->GetInteger64v(pname, GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
result->CopyResult(params);
GPU_CLIENT_LOG_CODE_BLOCK({
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
@@ -1082,7 +1098,9 @@ void GLES2Implementation::GetIntegeri_v(GLenum pname,
}
result->SetNumResults(0);
helper_->GetIntegeri_v(pname, index, GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
result->CopyResult(data);
GPU_CLIENT_LOG_CODE_BLOCK({
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
@@ -1109,7 +1127,9 @@ void GLES2Implementation::GetInteger64i_v(GLenum pname,
}
result->SetNumResults(0);
helper_->GetInteger64i_v(pname, index, GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
result->CopyResult(data);
GPU_CLIENT_LOG_CODE_BLOCK({
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
@@ -1135,7 +1155,9 @@ void GLES2Implementation::GetIntegerv(GLenum pname, GLint* params) {
}
result->SetNumResults(0);
helper_->GetIntegerv(pname, GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
result->CopyResult(params);
GPU_CLIENT_LOG_CODE_BLOCK({
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
@@ -1163,7 +1185,9 @@ void GLES2Implementation::GetProgramiv(GLuint program,
}
result->SetNumResults(0);
helper_->GetProgramiv(program, pname, GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
result->CopyResult(params);
GPU_CLIENT_LOG_CODE_BLOCK({
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
@@ -1220,7 +1244,9 @@ void GLES2Implementation::GetRenderbufferParameteriv(GLenum target,
result->SetNumResults(0);
helper_->GetRenderbufferParameteriv(target, pname, GetResultShmId(),
result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
result->CopyResult(params);
GPU_CLIENT_LOG_CODE_BLOCK({
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
@@ -1249,7 +1275,9 @@ void GLES2Implementation::GetSamplerParameterfv(GLuint sampler,
result->SetNumResults(0);
helper_->GetSamplerParameterfv(sampler, pname, GetResultShmId(),
result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
result->CopyResult(params);
GPU_CLIENT_LOG_CODE_BLOCK({
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
@@ -1279,7 +1307,9 @@ void GLES2Implementation::GetSamplerParameteriv(GLuint sampler,
result->SetNumResults(0);
helper_->GetSamplerParameteriv(sampler, pname, GetResultShmId(),
result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
result->CopyResult(params);
GPU_CLIENT_LOG_CODE_BLOCK({
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
@@ -1307,7 +1337,9 @@ void GLES2Implementation::GetShaderiv(GLuint shader,
}
result->SetNumResults(0);
helper_->GetShaderiv(shader, pname, GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
result->CopyResult(params);
GPU_CLIENT_LOG_CODE_BLOCK({
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
@@ -1396,7 +1428,9 @@ void GLES2Implementation::GetSynciv(GLsync sync,
}
result->SetNumResults(0);
helper_->GetSynciv(ToGLuint(sync), pname, GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
result->CopyResult(values);
GPU_CLIENT_LOG_CODE_BLOCK({
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
@@ -1427,7 +1461,9 @@ void GLES2Implementation::GetTexParameterfv(GLenum target,
}
result->SetNumResults(0);
helper_->GetTexParameterfv(target, pname, GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
result->CopyResult(params);
GPU_CLIENT_LOG_CODE_BLOCK({
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
@@ -1456,7 +1492,9 @@ void GLES2Implementation::GetTexParameteriv(GLenum target,
}
result->SetNumResults(0);
helper_->GetTexParameteriv(target, pname, GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
result->CopyResult(params);
GPU_CLIENT_LOG_CODE_BLOCK({
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
@@ -1541,7 +1579,9 @@ GLboolean GLES2Implementation::IsBuffer(GLuint buffer) {
}
*result = 0;
helper_->IsBuffer(buffer, GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return GL_FALSE;
+ }
GLboolean result_value = *result != 0;
GPU_CLIENT_LOG("returned " << result_value);
CheckGLError();
@@ -1560,7 +1600,9 @@ GLboolean GLES2Implementation::IsFramebuffer(GLuint framebuffer) {
}
*result = 0;
helper_->IsFramebuffer(framebuffer, GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return GL_FALSE;
+ }
GLboolean result_value = *result != 0;
GPU_CLIENT_LOG("returned " << result_value);
CheckGLError();
@@ -1578,7 +1620,9 @@ GLboolean GLES2Implementation::IsProgram(GLuint program) {
}
*result = 0;
helper_->IsProgram(program, GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return GL_FALSE;
+ }
GLboolean result_value = *result != 0;
GPU_CLIENT_LOG("returned " << result_value);
CheckGLError();
@@ -1597,7 +1641,9 @@ GLboolean GLES2Implementation::IsRenderbuffer(GLuint renderbuffer) {
}
*result = 0;
helper_->IsRenderbuffer(renderbuffer, GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return GL_FALSE;
+ }
GLboolean result_value = *result != 0;
GPU_CLIENT_LOG("returned " << result_value);
CheckGLError();
@@ -1615,7 +1661,9 @@ GLboolean GLES2Implementation::IsSampler(GLuint sampler) {
}
*result = 0;
helper_->IsSampler(sampler, GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return GL_FALSE;
+ }
GLboolean result_value = *result != 0;
GPU_CLIENT_LOG("returned " << result_value);
CheckGLError();
@@ -1633,7 +1681,9 @@ GLboolean GLES2Implementation::IsShader(GLuint shader) {
}
*result = 0;
helper_->IsShader(shader, GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return GL_FALSE;
+ }
GLboolean result_value = *result != 0;
GPU_CLIENT_LOG("returned " << result_value);
CheckGLError();
@@ -1651,7 +1701,9 @@ GLboolean GLES2Implementation::IsSync(GLsync sync) {
}
*result = 0;
helper_->IsSync(ToGLuint(sync), GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return GL_FALSE;
+ }
GLboolean result_value = *result != 0;
GPU_CLIENT_LOG("returned " << result_value);
CheckGLError();
@@ -1669,7 +1721,9 @@ GLboolean GLES2Implementation::IsTexture(GLuint texture) {
}
*result = 0;
helper_->IsTexture(texture, GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return GL_FALSE;
+ }
GLboolean result_value = *result != 0;
GPU_CLIENT_LOG("returned " << result_value);
CheckGLError();
@@ -1689,7 +1743,9 @@ GLboolean GLES2Implementation::IsTransformFeedback(GLuint transformfeedback) {
*result = 0;
helper_->IsTransformFeedback(transformfeedback, GetResultShmId(),
result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return GL_FALSE;
+ }
GLboolean result_value = *result != 0;
GPU_CLIENT_LOG("returned " << result_value);
CheckGLError();
@@ -3093,7 +3149,9 @@ GLboolean GLES2Implementation::IsVertexArrayOES(GLuint array) {
}
*result = 0;
helper_->IsVertexArrayOES(array, GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return GL_FALSE;
+ }
GLboolean result_value = *result != 0;
GPU_CLIENT_LOG("returned " << result_value);
CheckGLError();
@@ -3187,7 +3245,9 @@ void GLES2Implementation::GetProgramInterfaceiv(GLuint program,
result->SetNumResults(0);
helper_->GetProgramInterfaceiv(program, program_interface, pname,
GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
result->CopyResult(params);
GPU_CLIENT_LOG_CODE_BLOCK({
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
@@ -3905,7 +3965,9 @@ void GLES2Implementation::GetFramebufferPixelLocalStorageParameterfvANGLE(
result->SetNumResults(0);
helper_->GetFramebufferPixelLocalStorageParameterfvANGLE(
plane, pname, GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
result->CopyResult(params);
GPU_CLIENT_LOG_CODE_BLOCK({
for (int32_t i = 0; i < result->GetNumResults(); ++i) {
@@ -3939,7 +4001,9 @@ void GLES2Implementation::GetFramebufferPixelLocalStorageParameterivANGLE(
result->SetNumResults(0);
helper_->GetFramebufferPixelLocalStorageParameterivANGLE(
plane, pname, GetResultShmId(), result.offset());
- WaitForCmd();
+ if (!WaitForCmd()) {
+ return;
+ }
result->CopyResult(params);
GPU_CLIENT_LOG_CODE_BLOCK({
for (int32_t i = 0; i < result->GetNumResults(); ++i) {

View File

@@ -0,0 +1,42 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: kylechar <kylechar@chromium.org>
Date: Tue, 9 Apr 2024 17:14:26 +0000
Subject: Validate buffer length
The BitmapInSharedMemory mojo traits were only validating row length and
not total buffer length.
(cherry picked from commit 1a19ff70bd54847d818566bd7a1e7c384c419746)
(cherry picked from commit f15315f1cb7897e208947a40d538aac693283d7f)
Bug: 331237485
Change-Id: Ia2318899c44e9e7ac72fc7183954e6ce2c702179
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5396796
Commit-Queue: Kyle Charbonneau <kylechar@chromium.org>
Cr-Original-Original-Commit-Position: refs/heads/main@{#1278417}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5420432
Commit-Queue: danakj <danakj@chromium.org>
Cr-Original-Commit-Position: refs/branch-heads/6312@{#786}
Cr-Original-Branched-From: 6711dcdae48edaf98cbc6964f90fac85b7d9986e-refs/heads/main@{#1262506}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5433678
Reviewed-by: danakj <danakj@chromium.org>
Reviewed-by: Kyle Charbonneau <kylechar@chromium.org>
Cr-Commit-Position: refs/branch-heads/6099@{#2003}
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
diff --git a/services/viz/public/cpp/compositing/bitmap_in_shared_memory_mojom_traits.cc b/services/viz/public/cpp/compositing/bitmap_in_shared_memory_mojom_traits.cc
index a6e5f45d9e72b9ac48e536c3a7756966b3c263cf..519d554055e5182cdcbae44fafdac339a64a923b 100644
--- a/services/viz/public/cpp/compositing/bitmap_in_shared_memory_mojom_traits.cc
+++ b/services/viz/public/cpp/compositing/bitmap_in_shared_memory_mojom_traits.cc
@@ -76,6 +76,10 @@ bool StructTraits<viz::mojom::BitmapInSharedMemoryDataView, SkBitmap>::Read(
if (!mapping_ptr->IsValid())
return false;
+ if (mapping_ptr->size() < image_info.computeByteSize(data.row_bytes())) {
+ return false;
+ }
+
if (!sk_bitmap->installPixels(image_info, mapping_ptr->memory(),
data.row_bytes(), &DeleteSharedMemoryMapping,
mapping_ptr.get())) {

View File

@@ -0,0 +1,106 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nidhi Jaju <nidhijaju@chromium.org>
Date: Fri, 24 May 2024 01:26:02 +0000
Subject: Streams: Check if buffer is detached when filling pull-into
descriptor
The pull-into descriptor can become out-of-sync with the array buffer
when the buffer is detached. This CL adds a check to see if the buffer
is detached before trying to fill it.
(cherry picked from commit cd405492789ec4bc6ecd598754154c527ff60e95)
Bug: 339877167
Change-Id: Ibf46a75e36dc739910db07f2e88ff9998c21e8a8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5553232
Reviewed-by: Domenic Denicola <domenic@chromium.org>
Commit-Queue: Nidhi Jaju <nidhijaju@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1303628}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5553411
Cr-Commit-Position: refs/branch-heads/6367@{#1228}
Cr-Branched-From: d158c6dc6e3604e6f899041972edf26087a49740-refs/heads/main@{#1274542}
diff --git a/third_party/blink/renderer/core/streams/readable_byte_stream_controller.cc b/third_party/blink/renderer/core/streams/readable_byte_stream_controller.cc
index 85e2214ca95790f547819e2a14628d342f7913bb..a844d84d20e68172e285cefe3301c49f3edfbd3a 100644
--- a/third_party/blink/renderer/core/streams/readable_byte_stream_controller.cc
+++ b/third_party/blink/renderer/core/streams/readable_byte_stream_controller.cc
@@ -494,7 +494,8 @@ void ReadableByteStreamController::ProcessPullIntoDescriptorsUsingQueue(
controller->pending_pull_intos_[0];
// c. If ! ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(
// controller, pullIntoDescriptor) is true,
- if (FillPullIntoDescriptorFromQueue(controller, pull_into_descriptor)) {
+ if (FillPullIntoDescriptorFromQueue(controller, pull_into_descriptor,
+ exception_state)) {
// i. Perform !
// ReadableByteStreamControllerShiftPendingPullInto(controller).
ShiftPendingPullInto(controller);
@@ -505,6 +506,15 @@ void ReadableByteStreamController::ProcessPullIntoDescriptorsUsingQueue(
pull_into_descriptor, exception_state);
DCHECK(!exception_state.HadException());
}
+ if (exception_state.HadException()) {
+ // Instead of returning a rejection, which is inconvenient here,
+ // call ControllerError(). The only difference this makes is that it
+ // happens synchronously, but that should not be observable.
+ ReadableByteStreamController::Error(script_state, controller,
+ exception_state.GetException());
+ exception_state.ClearException();
+ return;
+ }
}
}
@@ -989,7 +999,12 @@ void ReadableByteStreamController::FillHeadPullIntoDescriptor(
bool ReadableByteStreamController::FillPullIntoDescriptorFromQueue(
ReadableByteStreamController* controller,
- PullIntoDescriptor* pull_into_descriptor) {
+ PullIntoDescriptor* pull_into_descriptor,
+ ExceptionState& exception_state) {
+ if (pull_into_descriptor->buffer->IsDetached()) {
+ exception_state.ThrowTypeError("buffer is detached");
+ return false;
+ }
// https://streams.spec.whatwg.org/#readable-byte-stream-controller-fill-pull-into-descriptor-from-queue
// 1. Let elementSize be pullIntoDescriptor.[[elementSize]].
const size_t element_size = pull_into_descriptor->element_size;
@@ -1240,7 +1255,8 @@ void ReadableByteStreamController::PullInto(
// a. If !
// ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller,
// pullIntoDescriptor) is true,
- if (FillPullIntoDescriptorFromQueue(controller, pull_into_descriptor)) {
+ if (FillPullIntoDescriptorFromQueue(controller, pull_into_descriptor,
+ exception_state)) {
// i. Let filledView be !
// ReadableByteStreamControllerConvertPullIntoDescriptor(pullIntoDescriptor).
DOMArrayBufferView* filled_view = ConvertPullIntoDescriptor(
@@ -1254,6 +1270,15 @@ void ReadableByteStreamController::PullInto(
// iv. Return.
return;
}
+ if (exception_state.HadException()) {
+ // Instead of returning a rejection, which is inconvenient here,
+ // call ControllerError(). The only difference this makes is that it
+ // happens synchronously, but that should not be observable.
+ ReadableByteStreamController::Error(script_state, controller,
+ exception_state.GetException());
+ exception_state.ClearException();
+ return;
+ }
// b. If controller.[[closeRequested]] is true,
if (controller->close_requested_) {
// i. Let e be a TypeError exception.
diff --git a/third_party/blink/renderer/core/streams/readable_byte_stream_controller.h b/third_party/blink/renderer/core/streams/readable_byte_stream_controller.h
index aff7d589cef5a32f43e1dc0b06aa0d2921e39169..f31f660fddbc01d95dff904ad9ac5b1cf3ee8d86 100644
--- a/third_party/blink/renderer/core/streams/readable_byte_stream_controller.h
+++ b/third_party/blink/renderer/core/streams/readable_byte_stream_controller.h
@@ -218,7 +218,8 @@ class CORE_EXPORT ReadableByteStreamController
// https://streams.spec.whatwg.org/#readable-byte-stream-controller-fill-pull-into-descriptor-from-queue
static bool FillPullIntoDescriptorFromQueue(ReadableByteStreamController*,
- PullIntoDescriptor*);
+ PullIntoDescriptor*,
+ ExceptionState&);
// https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamcontrollerfillreadrequestfromqueue
static void FillReadRequestFromQueue(ScriptState*,

View File

@@ -0,0 +1,38 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Calvin Watford <watfordcalvin@gmail.com>
Date: Tue, 12 Mar 2024 20:37:32 +0000
Subject: Fix primary display race condition crash on Windows
In rare cases, it's possible for the OS to provide us a list of displays
that doesn't contain the primary display. This situation causes
undefined behavior (dereference past vector end) and a crash to occur in
|display::win::(anon)::DisplayInfosToScreenWinDisplays| on builds
without DCHECK enabled.
Bug: 40265302
Change-Id: I2154bedea84478a84147c380610c85d4ea3f703a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5353255
Reviewed-by: David Bienvenu <davidbienvenu@chromium.org>
Reviewed-by: Robert Liao <robliao@chromium.org>
Commit-Queue: David Bienvenu <davidbienvenu@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1271793}
diff --git a/ui/display/win/screen_win.cc b/ui/display/win/screen_win.cc
index 6b6189a124e3fde423b129ef34f2c96186b4e86d..1040e583c6c50ba01efc44faa1882657ff8f63b2 100644
--- a/ui/display/win/screen_win.cc
+++ b/ui/display/win/screen_win.cc
@@ -324,7 +324,13 @@ std::vector<ScreenWinDisplay> DisplayInfosToScreenWinDisplays(
display_infos_remaining, [](const internal::DisplayInfo& display_info) {
return display_info.screen_rect().origin().IsOrigin();
});
- DCHECK(primary_display_iter != display_infos_remaining.end());
+
+ // If we can't find the primary display, we likely witnessed a race condition
+ // when querying the OS for display info. We expect another OS notification to
+ // trigger this lookup again soon, so just return an empty list for now.
+ if (primary_display_iter == display_infos_remaining.end()) {
+ return {};
+ }
// Build the tree and determine DisplayPlacements along the way.
DisplayLayoutBuilder builder(primary_display_iter->id());

View File

@@ -0,0 +1,102 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Tommy Steimel <steimel@chromium.org>
Date: Tue, 23 Apr 2024 19:29:23 +0000
Subject: Don't assume the enter event window is a LocalDOMWindow
This CL changes DocumentPictureInPictureEvent to store a DOMWindow
instead of a LocalDOMWindow to prevent crashes when the window it gets
is actually a RemoteDOMWindow.
(cherry picked from commit 2314741cdf2c4a6e11234dda7006ec0dd9005bbb)
Bug: 335003891
Change-Id: I86a0ec5a89b51a26d5dd89559f86e6e4d6c3e8fe
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5467978
Commit-Queue: Tommy Steimel <steimel@chromium.org>
Reviewed-by: Frank Liberato <liberato@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1290122}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5477908
Auto-Submit: Tommy Steimel <steimel@chromium.org>
Commit-Queue: Frank Liberato <liberato@chromium.org>
Cr-Commit-Position: refs/branch-heads/6367@{#974}
Cr-Branched-From: d158c6dc6e3604e6f899041972edf26087a49740-refs/heads/main@{#1274542}
diff --git a/third_party/blink/renderer/modules/document_picture_in_picture/document_picture_in_picture_event.cc b/third_party/blink/renderer/modules/document_picture_in_picture/document_picture_in_picture_event.cc
index 037813c62c2f0dfc78b3451320a799a349ffde23..572d0803c25a99ef5dfd631e7872b05a681f0444 100644
--- a/third_party/blink/renderer/modules/document_picture_in_picture/document_picture_in_picture_event.cc
+++ b/third_party/blink/renderer/modules/document_picture_in_picture/document_picture_in_picture_event.cc
@@ -8,7 +8,7 @@ namespace blink {
DocumentPictureInPictureEvent* DocumentPictureInPictureEvent::Create(
const AtomicString& type,
- LocalDOMWindow* document_picture_in_picture_window) {
+ DOMWindow* document_picture_in_picture_window) {
return MakeGarbageCollected<DocumentPictureInPictureEvent>(
type, document_picture_in_picture_window);
}
@@ -19,13 +19,13 @@ DocumentPictureInPictureEvent* DocumentPictureInPictureEvent::Create(
return MakeGarbageCollected<DocumentPictureInPictureEvent>(type, initializer);
}
-LocalDOMWindow* DocumentPictureInPictureEvent::window() const {
+DOMWindow* DocumentPictureInPictureEvent::window() const {
return document_picture_in_picture_window_.Get();
}
DocumentPictureInPictureEvent::DocumentPictureInPictureEvent(
AtomicString const& type,
- LocalDOMWindow* document_picture_in_picture_window)
+ DOMWindow* document_picture_in_picture_window)
: Event(type, Bubbles::kYes, Cancelable::kNo),
document_picture_in_picture_window_(document_picture_in_picture_window) {}
@@ -33,8 +33,7 @@ DocumentPictureInPictureEvent::DocumentPictureInPictureEvent(
AtomicString const& type,
const DocumentPictureInPictureEventInit* initializer)
: Event(type, initializer),
- document_picture_in_picture_window_(
- static_cast<LocalDOMWindow*>(initializer->window())) {}
+ document_picture_in_picture_window_(initializer->window()) {}
void DocumentPictureInPictureEvent::Trace(Visitor* visitor) const {
visitor->Trace(document_picture_in_picture_window_);
diff --git a/third_party/blink/renderer/modules/document_picture_in_picture/document_picture_in_picture_event.h b/third_party/blink/renderer/modules/document_picture_in_picture/document_picture_in_picture_event.h
index 7af2022146905a3c3d71e1420aaa68da30e6a9ce..59cd8cb7a2e3a2e2a81db1d146f8075b13755c0e 100644
--- a/third_party/blink/renderer/modules/document_picture_in_picture/document_picture_in_picture_event.h
+++ b/third_party/blink/renderer/modules/document_picture_in_picture/document_picture_in_picture_event.h
@@ -6,7 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_MODULES_DOCUMENT_PICTURE_IN_PICTURE_DOCUMENT_PICTURE_IN_PICTURE_EVENT_H_
#include "third_party/blink/renderer/bindings/modules/v8/v8_document_picture_in_picture_event_init.h"
-#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/frame/dom_window.h"
#include "third_party/blink/renderer/modules/event_modules.h"
#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
@@ -18,22 +18,21 @@ class MODULES_EXPORT DocumentPictureInPictureEvent final : public Event {
DEFINE_WRAPPERTYPEINFO();
public:
- static DocumentPictureInPictureEvent* Create(const AtomicString&,
- LocalDOMWindow*);
+ static DocumentPictureInPictureEvent* Create(const AtomicString&, DOMWindow*);
static DocumentPictureInPictureEvent* Create(
const AtomicString&,
const DocumentPictureInPictureEventInit*);
- DocumentPictureInPictureEvent(AtomicString const&, LocalDOMWindow*);
+ DocumentPictureInPictureEvent(AtomicString const&, DOMWindow*);
DocumentPictureInPictureEvent(AtomicString const&,
const DocumentPictureInPictureEventInit*);
- LocalDOMWindow* window() const;
+ DOMWindow* window() const;
void Trace(Visitor*) const override;
private:
- Member<LocalDOMWindow> document_picture_in_picture_window_;
+ Member<DOMWindow> document_picture_in_picture_window_;
};
} // namespace blink

View File

@@ -0,0 +1,99 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ken Rockot <rockot@google.com>
Date: Wed, 8 May 2024 15:32:48 +0000
Subject: Viz: Tolerate SinkGroup destruction during submit
Fixed: 339266700
Change-Id: I8c0ea8c540948016346b00db64fe33260d2446f0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5523748
Reviewed-by: Kyle Charbonneau <kylechar@chromium.org>
Reviewed-by: Jonathan Ross <jonross@chromium.org>
Commit-Queue: Ken Rockot <rockot@google.com>
Cr-Commit-Position: refs/heads/main@{#1298119}
diff --git a/components/viz/service/frame_sinks/frame_sink_bundle_impl.cc b/components/viz/service/frame_sinks/frame_sink_bundle_impl.cc
index a43e274a920a7cc189652c29eb2fe4a09ab66ded..9fefc2446d9c95964db512e4c98654c3fcc4e8b4 100644
--- a/components/viz/service/frame_sinks/frame_sink_bundle_impl.cc
+++ b/components/viz/service/frame_sinks/frame_sink_bundle_impl.cc
@@ -4,12 +4,15 @@
#include "components/viz/service/frame_sinks/frame_sink_bundle_impl.h"
+#include <map>
#include <utility>
#include <vector>
#include "base/check.h"
#include "base/functional/bind.h"
+#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ref.h"
+#include "base/memory/weak_ptr.h"
#include "build/build_config.h"
#include "components/viz/service/frame_sinks/compositor_frame_sink_impl.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
@@ -45,6 +48,10 @@ class FrameSinkBundleImpl::SinkGroup : public BeginFrameObserver {
bool IsEmpty() const { return frame_sinks_.empty(); }
+ base::WeakPtr<SinkGroup> GetWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
+ }
+
void AddFrameSink(uint32_t sink_id) {
frame_sinks_.insert(sink_id);
@@ -206,6 +213,8 @@ class FrameSinkBundleImpl::SinkGroup : public BeginFrameObserver {
std::set<uint32_t> unacked_submissions_;
BeginFrameArgs last_used_begin_frame_args_;
+
+ base::WeakPtrFactory<SinkGroup> weak_ptr_factory_{this};
};
FrameSinkBundleImpl::FrameSinkBundleImpl(
@@ -282,8 +291,9 @@ void FrameSinkBundleImpl::SetWantsBeginFrameAcks(uint32_t sink_id) {
void FrameSinkBundleImpl::Submit(
std::vector<mojom::BundledFrameSubmissionPtr> submissions) {
- std::set<SinkGroup*> groups;
- std::set<SinkGroup*> affected_groups;
+ std::map<raw_ptr<SinkGroup>, base::WeakPtr<SinkGroup>> groups;
+ std::map<raw_ptr<SinkGroup>, base::WeakPtr<SinkGroup>> affected_groups;
+
// Count the frame submissions before processing anything. This ensures that
// any frames submitted here will be acked together in a batch, and not acked
// individually in case they happen to ack synchronously within
@@ -294,10 +304,10 @@ void FrameSinkBundleImpl::Submit(
// through to the client without batching.
for (auto& submission : submissions) {
if (auto* group = GetSinkGroup(submission->sink_id)) {
- groups.insert(group);
+ groups.emplace(group, group->GetWeakPtr());
if (submission->data->is_frame()) {
group->WillSubmitFrame(submission->sink_id);
- affected_groups.insert(group);
+ affected_groups.emplace(group, group->GetWeakPtr());
}
}
}
@@ -327,12 +337,16 @@ void FrameSinkBundleImpl::Submit(
}
}
- for (auto* group : groups) {
- group->DidFinishFrame();
+ for (const auto& [unsafe_group, weak_group] : groups) {
+ if (weak_group) {
+ weak_group->DidFinishFrame();
+ }
}
- for (auto* group : affected_groups) {
- group->FlushMessages();
+ for (const auto& [unsafe_group, weak_group] : affected_groups) {
+ if (weak_group) {
+ weak_group->FlushMessages();
+ }
}
}

View File

@@ -0,0 +1,89 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: rubberyuzu <yuzus@chromium.org>
Date: Fri, 17 May 2024 02:53:09 +0000
Subject: Use WeakPtr for delegate_
This CL starts using a WeakPtr for `delegate_`. This is because
`ReportFeaturesToDelegate()` is posted and when it's executed,
`delegate_` might be destroyed.
(cherry picked from commit da7a6845e589dc71da9898f7e181a7c88a62e2e1)
Bug: 336012573
Change-Id: I9aa5ee7ae7d484d4208e6bdd8ea2853763d69a6b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5493004
Reviewed-by: Kentaro Hara <haraken@chromium.org>
Commit-Queue: Yuzu Saijo <yuzus@chromium.org>
Reviewed-by: Fergal Daly <fergal@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1297242}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5547038
Auto-Submit: Yuzu Saijo <yuzus@chromium.org>
Commit-Queue: Kentaro Hara <haraken@chromium.org>
Cr-Commit-Position: refs/branch-heads/6367@{#1190}
Cr-Branched-From: d158c6dc6e3604e6f899041972edf26087a49740-refs/heads/main@{#1274542}
diff --git a/third_party/blink/renderer/platform/scheduler/common/back_forward_cache_disabling_feature_tracker.cc b/third_party/blink/renderer/platform/scheduler/common/back_forward_cache_disabling_feature_tracker.cc
index e2f7dc1ff4384fa2e0dcb07539b269cdbb3f0c89..6bb65c49603e8efd3a84cabc6bf77a8a0fb359be 100644
--- a/third_party/blink/renderer/platform/scheduler/common/back_forward_cache_disabling_feature_tracker.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/back_forward_cache_disabling_feature_tracker.cc
@@ -22,9 +22,13 @@ BackForwardCacheDisablingFeatureTracker::
void BackForwardCacheDisablingFeatureTracker::SetDelegate(
FrameOrWorkerScheduler::Delegate* delegate) {
+ // This function is only called when initializing. `delegate_` should be
+ // nullptr at first.
DCHECK(!delegate_);
- delegate_ = delegate;
- // `delegate` might be nullptr on tests.
+ // `delegate` can be nullptr for tests.
+ if (delegate) {
+ delegate_ = (*delegate).AsWeakPtr();
+ }
}
void BackForwardCacheDisablingFeatureTracker::Reset() {
@@ -162,7 +166,13 @@ void BackForwardCacheDisablingFeatureTracker::ReportFeaturesToDelegate() {
last_reported_sticky_ = sticky_features_and_js_locations_;
FrameOrWorkerScheduler::Delegate::BlockingDetails details(
non_sticky_features_and_js_locations_, sticky_features_and_js_locations_);
- delegate_->UpdateBackForwardCacheDisablingFeatures(details);
+
+ // Check if the delegate still exists. This check is necessary because
+ // `FrameOrWorkerScheduler::Delegate` might be destroyed and thus `delegate_`
+ // might be gone when `ReportFeaturesToDelegate() is executed.
+ if (delegate_) {
+ delegate_->UpdateBackForwardCacheDisablingFeatures(details);
+ }
}
} // namespace scheduler
diff --git a/third_party/blink/renderer/platform/scheduler/common/back_forward_cache_disabling_feature_tracker.h b/third_party/blink/renderer/platform/scheduler/common/back_forward_cache_disabling_feature_tracker.h
index c78d791aa7c40a6775e84f79fd1a5e357328581e..1ec5cc4627cc71a941df32ecd989a5897f796dce 100644
--- a/third_party/blink/renderer/platform/scheduler/common/back_forward_cache_disabling_feature_tracker.h
+++ b/third_party/blink/renderer/platform/scheduler/common/back_forward_cache_disabling_feature_tracker.h
@@ -119,8 +119,7 @@ class PLATFORM_EXPORT BackForwardCacheDisablingFeatureTracker {
BFCacheBlockingFeatureAndLocations non_sticky_features_and_js_locations_;
BFCacheBlockingFeatureAndLocations sticky_features_and_js_locations_;
- raw_ptr<FrameOrWorkerScheduler::Delegate, DanglingUntriaged> delegate_ =
- nullptr;
+ base::WeakPtr<FrameOrWorkerScheduler::Delegate> delegate_ = nullptr;
raw_ptr<ThreadSchedulerBase, DanglingUntriaged> scheduler_;
base::WeakPtrFactory<BackForwardCacheDisablingFeatureTracker> weak_factory_{
diff --git a/third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h b/third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h
index 82befdeabdce4904002d6b35aaef8a796b613209..7f95ec0339cc2baabbae05a1a9b332e4dbc23bf5 100644
--- a/third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h
+++ b/third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h
@@ -149,6 +149,11 @@ class PLATFORM_EXPORT FrameOrWorkerScheduler {
// changed when a blocking feature and its JS location are registered or
// removed.
virtual void UpdateBackForwardCacheDisablingFeatures(BlockingDetails) = 0;
+
+ base::WeakPtr<Delegate> AsWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
+ }
+ base::WeakPtrFactory<Delegate> weak_ptr_factory_{this};
};
virtual ~FrameOrWorkerScheduler();

View File

@@ -0,0 +1,27 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Johannes Kron <kron@chromium.org>
Date: Tue, 13 Feb 2024 23:22:49 +0000
Subject: Update thumbnail size when sources are selected
(cherry picked from commit c1f25647c2fcbf5e5a2d574feb284bc7284b944d)
Bug: b/40281869
Change-Id: I2d5a3954886bc6a5742321aeab415362da19c0ce
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5285701
Commit-Queue: Johannes Kron <kron@chromium.org>
Reviewed-by: Elad Alon <eladalon@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1260137}
diff --git a/chrome/browser/media/webrtc/thumbnail_capturer_mac.mm b/chrome/browser/media/webrtc/thumbnail_capturer_mac.mm
index ebe194e9d4a77d74996cb575364a32b61ccfac52..b27f6348d338d8952716b51825586e5d29b75651 100644
--- a/chrome/browser/media/webrtc/thumbnail_capturer_mac.mm
+++ b/chrome/browser/media/webrtc/thumbnail_capturer_mac.mm
@@ -365,6 +365,8 @@ void API_AVAILABLE(macos(14.0))
gfx::Size thumbnail_size) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
+ thumbnail_size_ = thumbnail_size;
+
// The iteration is in reverse order so that the sources
// first in the list are captured first. This way we make sure that the first
// thumbnails in the view are captured first.

View File

@@ -0,0 +1,402 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shelley Vohr <shelley.vohr@gmail.com>
Date: Sun, 5 May 2024 09:17:17 +0000
Subject: feat: add support for missing dialog features to //shell_dialogs
This CL adds support for the following features to //shell_dialogs:
* buttonLabel - Custom label for the confirmation button.
* showHiddenFiles - Show hidden files in dialog.
* showOverwriteConfirmation - Whether the user will be presented a confirmation dialog if the user types a file name that already exists.
This may be partially upstreamed to Chromium in the future.
diff --git a/ui/gtk/select_file_dialog_linux_gtk.cc b/ui/gtk/select_file_dialog_linux_gtk.cc
index 38f8b2fa5ef4a8c86b9efa93d34dfb5ab1099c76..c1b5bd6cc2f31eee1f84cc57da58eba48576f139 100644
--- a/ui/gtk/select_file_dialog_linux_gtk.cc
+++ b/ui/gtk/select_file_dialog_linux_gtk.cc
@@ -244,6 +244,10 @@ void SelectFileDialogLinuxGtk::SelectFileImpl(
std::string title_string = base::UTF16ToUTF8(title);
+ ExtraSettings extra_settings;
+ if (params)
+ extra_settings = *(static_cast<ExtraSettings*>(params));
+
set_file_type_index(file_type_index);
if (file_types)
set_file_types(*file_types);
@@ -262,23 +266,23 @@ void SelectFileDialogLinuxGtk::SelectFileImpl(
case SELECT_UPLOAD_FOLDER:
case SELECT_EXISTING_FOLDER:
dialog = CreateSelectFolderDialog(type, title_string, default_path,
- owning_window);
+ owning_window, extra_settings);
connect("response",
&SelectFileDialogLinuxGtk::OnSelectSingleFolderDialogResponse);
break;
case SELECT_OPEN_FILE:
- dialog = CreateFileOpenDialog(title_string, default_path, owning_window);
+ dialog = CreateFileOpenDialog(title_string, default_path, owning_window, extra_settings);
connect("response",
&SelectFileDialogLinuxGtk::OnSelectSingleFileDialogResponse);
break;
case SELECT_OPEN_MULTI_FILE:
dialog =
- CreateMultiFileOpenDialog(title_string, default_path, owning_window);
+ CreateMultiFileOpenDialog(title_string, default_path, owning_window, extra_settings);
connect("response",
&SelectFileDialogLinuxGtk::OnSelectMultiFileDialogResponse);
break;
case SELECT_SAVEAS_FILE:
- dialog = CreateSaveAsDialog(title_string, default_path, owning_window);
+ dialog = CreateSaveAsDialog(title_string, default_path, owning_window, extra_settings);
connect("response",
&SelectFileDialogLinuxGtk::OnSelectSingleFileDialogResponse);
break;
@@ -413,10 +417,14 @@ void SelectFileDialogLinuxGtk::FileNotSelected(GtkWidget* dialog) {
GtkWidget* SelectFileDialogLinuxGtk::CreateFileOpenHelper(
const std::string& title,
const base::FilePath& default_path,
- gfx::NativeWindow parent) {
+ gfx::NativeWindow parent,
+ const ExtraSettings& settings) {
+ const char* button_label = settings.button_label.empty()
+ ? GetOpenLabel()
+ : settings.button_label.c_str();
GtkWidget* dialog = GtkFileChooserDialogNew(
title.c_str(), nullptr, GTK_FILE_CHOOSER_ACTION_OPEN, GetCancelLabel(),
- GTK_RESPONSE_CANCEL, GetOpenLabel(), GTK_RESPONSE_ACCEPT);
+ GTK_RESPONSE_CANCEL, button_label, GTK_RESPONSE_ACCEPT);
SetGtkTransientForAura(dialog, parent);
AddFilters(GTK_FILE_CHOOSER(dialog));
@@ -432,6 +440,8 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateFileOpenHelper(
GtkFileChooserSetCurrentFolder(GTK_FILE_CHOOSER(dialog),
*last_opened_path());
}
+ gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dialog),
+ settings.show_hidden);
return dialog;
}
@@ -439,7 +449,8 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSelectFolderDialog(
Type type,
const std::string& title,
const base::FilePath& default_path,
- gfx::NativeWindow parent) {
+ gfx::NativeWindow parent,
+ const ExtraSettings& settings) {
std::string title_string = title;
if (title_string.empty()) {
title_string =
@@ -447,11 +458,14 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSelectFolderDialog(
? l10n_util::GetStringUTF8(IDS_SELECT_UPLOAD_FOLDER_DIALOG_TITLE)
: l10n_util::GetStringUTF8(IDS_SELECT_FOLDER_DIALOG_TITLE);
}
- std::string accept_button_label =
- (type == SELECT_UPLOAD_FOLDER)
- ? l10n_util::GetStringUTF8(
- IDS_SELECT_UPLOAD_FOLDER_DIALOG_UPLOAD_BUTTON)
- : GetOpenLabel();
+
+ std::string accept_button_label = settings.button_label;
+ if (accept_button_label.empty()) {
+ accept_button_label = (type == SELECT_UPLOAD_FOLDER)
+ ? l10n_util::GetStringUTF8(
+ IDS_SELECT_UPLOAD_FOLDER_DIALOG_UPLOAD_BUTTON)
+ : GetOpenLabel();
+ }
GtkWidget* dialog = GtkFileChooserDialogNew(
title_string.c_str(), nullptr, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
@@ -473,19 +487,21 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSelectFolderDialog(
gtk_file_filter_add_mime_type(only_folders, "inode/directory");
gtk_file_filter_add_mime_type(only_folders, "text/directory");
gtk_file_chooser_add_filter(chooser, only_folders);
- gtk_file_chooser_set_select_multiple(chooser, FALSE);
+ gtk_file_chooser_set_select_multiple(chooser, settings.allow_multiple_selection);
+ gtk_file_chooser_set_show_hidden(chooser, settings.show_hidden);
return dialog;
}
GtkWidget* SelectFileDialogLinuxGtk::CreateFileOpenDialog(
const std::string& title,
const base::FilePath& default_path,
- gfx::NativeWindow parent) {
+ gfx::NativeWindow parent,
+ const ExtraSettings& settings) {
std::string title_string =
!title.empty() ? title
: l10n_util::GetStringUTF8(IDS_OPEN_FILE_DIALOG_TITLE);
- GtkWidget* dialog = CreateFileOpenHelper(title_string, default_path, parent);
+ GtkWidget* dialog = CreateFileOpenHelper(title_string, default_path, parent, settings);
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), FALSE);
return dialog;
}
@@ -493,12 +509,14 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateFileOpenDialog(
GtkWidget* SelectFileDialogLinuxGtk::CreateMultiFileOpenDialog(
const std::string& title,
const base::FilePath& default_path,
- gfx::NativeWindow parent) {
+ gfx::NativeWindow parent,
+ const ExtraSettings& settings) {
std::string title_string =
!title.empty() ? title
: l10n_util::GetStringUTF8(IDS_OPEN_FILES_DIALOG_TITLE);
- GtkWidget* dialog = CreateFileOpenHelper(title_string, default_path, parent);
+ GtkWidget* dialog =
+ CreateFileOpenHelper(title_string, default_path, parent, settings);
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE);
return dialog;
}
@@ -506,14 +524,17 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateMultiFileOpenDialog(
GtkWidget* SelectFileDialogLinuxGtk::CreateSaveAsDialog(
const std::string& title,
const base::FilePath& default_path,
- gfx::NativeWindow parent) {
+ gfx::NativeWindow parent,
+ const ExtraSettings& settings) {
std::string title_string =
!title.empty() ? title
: l10n_util::GetStringUTF8(IDS_SAVE_AS_DIALOG_TITLE);
-
+ const char* button_label = settings.button_label.empty()
+ ? GetSaveLabel()
+ : settings.button_label.c_str();
GtkWidget* dialog = GtkFileChooserDialogNew(
title_string.c_str(), nullptr, GTK_FILE_CHOOSER_ACTION_SAVE,
- GetCancelLabel(), GTK_RESPONSE_CANCEL, GetSaveLabel(),
+ GetCancelLabel(), GTK_RESPONSE_CANCEL, button_label,
GTK_RESPONSE_ACCEPT);
SetGtkTransientForAura(dialog, parent);
@@ -539,9 +560,10 @@ GtkWidget* SelectFileDialogLinuxGtk::CreateSaveAsDialog(
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), FALSE);
// Overwrite confirmation is always enabled in GTK4.
if (!GtkCheckVersion(4)) {
- gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog),
- TRUE);
+ gtk_file_chooser_set_do_overwrite_confirmation(
+ GTK_FILE_CHOOSER(dialog), settings.show_overwrite_confirmation);
}
+ gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dialog), settings.show_hidden);
return dialog;
}
diff --git a/ui/gtk/select_file_dialog_linux_gtk.h b/ui/gtk/select_file_dialog_linux_gtk.h
index 53ae15f14c45ee72abdae172fc4555c9e4b3ff9a..ee19c3f399a1d060d5e9bd0dc5f1b3828381e8df 100644
--- a/ui/gtk/select_file_dialog_linux_gtk.h
+++ b/ui/gtk/select_file_dialog_linux_gtk.h
@@ -90,19 +90,23 @@ class SelectFileDialogLinuxGtk : public ui::SelectFileDialogLinux,
GtkWidget* CreateSelectFolderDialog(Type type,
const std::string& title,
const base::FilePath& default_path,
- gfx::NativeWindow parent);
+ gfx::NativeWindow parent,
+ const ExtraSettings& settings);
GtkWidget* CreateFileOpenDialog(const std::string& title,
const base::FilePath& default_path,
- gfx::NativeWindow parent);
+ gfx::NativeWindow parent,
+ const ExtraSettings& settings);
GtkWidget* CreateMultiFileOpenDialog(const std::string& title,
const base::FilePath& default_path,
- gfx::NativeWindow parent);
+ gfx::NativeWindow parent,
+ const ExtraSettings& settings);
GtkWidget* CreateSaveAsDialog(const std::string& title,
const base::FilePath& default_path,
- gfx::NativeWindow parent);
+ gfx::NativeWindow parent,
+ const ExtraSettings& settings);
// Removes and returns the |params| associated with |dialog| from
// |params_map_|.
@@ -121,7 +125,8 @@ class SelectFileDialogLinuxGtk : public ui::SelectFileDialogLinux,
// Common function for CreateFileOpenDialog and CreateMultiFileOpenDialog.
GtkWidget* CreateFileOpenHelper(const std::string& title,
const base::FilePath& default_path,
- gfx::NativeWindow parent);
+ gfx::NativeWindow parent,
+ const ExtraSettings& settings);
// Callback for when the user responds to a Save As or Open File dialog.
void OnSelectSingleFileDialogResponse(GtkWidget* dialog, int response_id);
diff --git a/ui/shell_dialogs/select_file_dialog_linux.h b/ui/shell_dialogs/select_file_dialog_linux.h
index 20ad001988831afca73315c577f90c824a36e282..57a8d35ace583eaafb526f70935d21c0f8fd1078 100644
--- a/ui/shell_dialogs/select_file_dialog_linux.h
+++ b/ui/shell_dialogs/select_file_dialog_linux.h
@@ -26,6 +26,13 @@ class SHELL_DIALOGS_EXPORT SelectFileDialogLinux : public SelectFileDialog {
SelectFileDialogLinux(const SelectFileDialogLinux&) = delete;
SelectFileDialogLinux& operator=(const SelectFileDialogLinux&) = delete;
+ struct ExtraSettings {
+ std::string button_label;
+ bool show_overwrite_confirmation = true;
+ bool show_hidden = false;
+ bool allow_multiple_selection = false;
+ };
+
// Returns true if the SelectFileDialog class returned by
// NewSelectFileDialogImplKDE will actually work.
static bool CheckKDEDialogWorksOnUIThread(std::string& kdialog_version);
diff --git a/ui/shell_dialogs/select_file_dialog_linux_kde.cc b/ui/shell_dialogs/select_file_dialog_linux_kde.cc
index 796e98cd42a5c6087da6cdf1d7bff4248113aeab..bcf43ab96bcb426fde6362dd0da4421758854449 100644
--- a/ui/shell_dialogs/select_file_dialog_linux_kde.cc
+++ b/ui/shell_dialogs/select_file_dialog_linux_kde.cc
@@ -479,6 +479,9 @@ void SelectFileDialogLinuxKde::CreateSelectFolderDialog(
int title_message_id = (type == SELECT_UPLOAD_FOLDER)
? IDS_SELECT_UPLOAD_FOLDER_DIALOG_TITLE
: IDS_SELECT_FOLDER_DIALOG_TITLE;
+ ExtraSettings extra_settings;
+ if (params)
+ extra_settings = *(static_cast<ExtraSettings*>(params));
pipe_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(
@@ -486,7 +489,7 @@ void SelectFileDialogLinuxKde::CreateSelectFolderDialog(
KDialogParams(
"--getexistingdirectory", GetTitle(title, title_message_id),
default_path.empty() ? *last_opened_path() : default_path, parent,
- false, false)),
+ false, extra_settings.allow_multiple_selection)),
base::BindOnce(
&SelectFileDialogLinuxKde::OnSelectSingleFolderDialogResponse, this,
parent, params));
diff --git a/ui/shell_dialogs/select_file_dialog_linux_portal.cc b/ui/shell_dialogs/select_file_dialog_linux_portal.cc
index decba61300c21f7f5d070b24c23ff2e08b06d161..ae6e76186b6db9d0d32d51baaaeafa6106225c0f 100644
--- a/ui/shell_dialogs/select_file_dialog_linux_portal.cc
+++ b/ui/shell_dialogs/select_file_dialog_linux_portal.cc
@@ -218,6 +218,10 @@ void SelectFileDialogLinuxPortal::SelectFileImpl(
info_->main_task_runner = base::SequencedTaskRunner::GetCurrentDefault();
listener_params_ = params;
+ ExtraSettings extra_settings;
+ if (params)
+ extra_settings = *(static_cast<ExtraSettings*>(params));
+
if (owning_window) {
if (auto* root = owning_window->GetRootWindow()) {
if (auto* host = root->GetNativeWindowProperty(
@@ -245,7 +249,7 @@ void SelectFileDialogLinuxPortal::SelectFileImpl(
host_->GetAcceleratedWidget(),
base::BindOnce(
&SelectFileDialogLinuxPortal::SelectFileImplWithParentHandle,
- this, title, default_path, filter_set, default_extension))) {
+ this, title, default_path, filter_set, default_extension, extra_settings))) {
// Return early to skip the fallback below.
return;
} else {
@@ -255,7 +259,7 @@ void SelectFileDialogLinuxPortal::SelectFileImpl(
// No parent, so just use a blank parent handle.
SelectFileImplWithParentHandle(title, default_path, filter_set,
- default_extension, "");
+ default_extension, extra_settings, "");
}
bool SelectFileDialogLinuxPortal::HasMultipleFileTypeChoicesImpl() {
@@ -452,6 +456,7 @@ void SelectFileDialogLinuxPortal::SelectFileImplWithParentHandle(
base::FilePath default_path,
PortalFilterSet filter_set,
base::FilePath::StringType default_extension,
+ const ExtraSettings& settings,
std::string parent_handle) {
bool default_path_exists = CallDirectoryExistsOnUIThread(default_path);
dbus_thread_linux::GetTaskRunner()->PostTask(
@@ -460,7 +465,7 @@ void SelectFileDialogLinuxPortal::SelectFileImplWithParentHandle(
&SelectFileDialogLinuxPortal::DialogInfo::SelectFileImplOnBusThread,
info_, std::move(title), std::move(default_path), default_path_exists,
std::move(filter_set), std::move(default_extension),
- std::move(parent_handle)));
+ std::move(parent_handle), std::move(settings)));
}
void SelectFileDialogLinuxPortal::DialogInfo::SelectFileImplOnBusThread(
@@ -469,7 +474,8 @@ void SelectFileDialogLinuxPortal::DialogInfo::SelectFileImplOnBusThread(
const bool default_path_exists,
PortalFilterSet filter_set,
base::FilePath::StringType default_extension,
- std::string parent_handle) {
+ std::string parent_handle,
+ const ExtraSettings& settings) {
DCHECK(dbus_thread_linux::GetTaskRunner()->RunsTasksInCurrentSequence());
dbus::Bus* bus = AcquireBusOnBusThread();
if (!bus->Connect())
@@ -515,7 +521,7 @@ void SelectFileDialogLinuxPortal::DialogInfo::SelectFileImplOnBusThread(
base::StringPrintf("handle_%d", handle_token_counter_++);
AppendOptions(&writer, response_handle_token, default_path,
- default_path_exists, filter_set);
+ default_path_exists, filter_set, settings);
// The sender part of the handle object contains the D-Bus connection name
// without the prefix colon and with all dots replaced with underscores.
@@ -545,7 +551,8 @@ void SelectFileDialogLinuxPortal::DialogInfo::AppendOptions(
const std::string& response_handle_token,
const base::FilePath& default_path,
const bool default_path_exists,
- const SelectFileDialogLinuxPortal::PortalFilterSet& filter_set) {
+ const SelectFileDialogLinuxPortal::PortalFilterSet& filter_set,
+ const ExtraSettings& settings) {
dbus::MessageWriter options_writer(nullptr);
writer->OpenArray("{sv}", &options_writer);
@@ -553,8 +560,10 @@ void SelectFileDialogLinuxPortal::DialogInfo::AppendOptions(
response_handle_token);
if (type == SelectFileDialog::Type::SELECT_UPLOAD_FOLDER) {
- AppendStringOption(&options_writer, kFileChooserOptionAcceptLabel,
- l10n_util::GetStringUTF8(
+ const std::string accept_label = settings.button_label.empty()
+ ? kFileChooserOptionAcceptLabel
+ : settings.button_label;
+ AppendStringOption(&options_writer, accept_label, l10n_util::GetStringUTF8(
IDS_SELECT_UPLOAD_FOLDER_DIALOG_UPLOAD_BUTTON));
}
@@ -562,6 +571,7 @@ void SelectFileDialogLinuxPortal::DialogInfo::AppendOptions(
type == SelectFileDialog::Type::SELECT_UPLOAD_FOLDER ||
type == SelectFileDialog::Type::SELECT_EXISTING_FOLDER) {
AppendBoolOption(&options_writer, kFileChooserOptionDirectory, true);
+ AppendBoolOption(&options_writer, kFileChooserOptionMultiple, settings.allow_multiple_selection);
} else if (type == SelectFileDialog::Type::SELECT_OPEN_MULTI_FILE) {
AppendBoolOption(&options_writer, kFileChooserOptionMultiple, true);
}
diff --git a/ui/shell_dialogs/select_file_dialog_linux_portal.h b/ui/shell_dialogs/select_file_dialog_linux_portal.h
index 59de8f49a1626f34c8bb73c04098244bdccb9c3e..816b7b099be0859096aed2282446b0b2decfaa6a 100644
--- a/ui/shell_dialogs/select_file_dialog_linux_portal.h
+++ b/ui/shell_dialogs/select_file_dialog_linux_portal.h
@@ -115,7 +115,8 @@ class SelectFileDialogLinuxPortal : public SelectFileDialogLinux {
const bool default_path_exists,
PortalFilterSet filter_set,
base::FilePath::StringType default_extension,
- std::string parent_handle);
+ std::string parent_handle,
+ const ExtraSettings& settings);
Type type;
// The task runner the SelectFileImpl method was called on.
scoped_refptr<base::SequencedTaskRunner> main_task_runner;
@@ -143,7 +144,8 @@ class SelectFileDialogLinuxPortal : public SelectFileDialogLinux {
const std::string& response_handle_token,
const base::FilePath& default_path,
const bool derfault_path_exists,
- const PortalFilterSet& filter_set);
+ const PortalFilterSet& filter_set,
+ const ExtraSettings& settings);
void AppendFilterStruct(dbus::MessageWriter* writer,
const PortalFilter& filter);
std::vector<base::FilePath> ConvertUrisToPaths(
@@ -190,6 +192,7 @@ class SelectFileDialogLinuxPortal : public SelectFileDialogLinux {
base::FilePath default_path,
PortalFilterSet filter_set,
base::FilePath::StringType default_extension,
+ const ExtraSettings& settings,
std::string parent_handle);
void DialogCreatedOnMainThread();

View File

@@ -0,0 +1,136 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shelley Vohr <shelley.vohr@gmail.com>
Date: Tue, 28 May 2024 10:44:06 +0200
Subject: feat: enable passing exit code on service process crash
This patch enables plumbing the exit code of the service process to the
browser process when the service process crashes. The process can perform cleanup
after the message pipe disconnection, which previously led to racy and incorrect
exit codes in some crashing scenarios. To mitigate this, we can rely on
ServiceProcessHost::Observer functions, but we need to pass the exit code to
the observer.
diff --git a/content/browser/service_process_host_impl.cc b/content/browser/service_process_host_impl.cc
index 75d7bc00759226859af635d66cdfbc3dd565b4a2..6f952e56348f3bf4cd0ddbae2d4bf74dd680ed8a 100644
--- a/content/browser/service_process_host_impl.cc
+++ b/content/browser/service_process_host_impl.cc
@@ -77,12 +77,15 @@ class ServiceProcessTracker {
processes_.erase(iter);
}
- void NotifyCrashed(ServiceProcessId id) {
+ void NotifyCrashed(ServiceProcessId id, int exit_code) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
auto iter = processes_.find(id);
DCHECK(iter != processes_.end());
- for (auto& observer : observers_)
- observer.OnServiceProcessCrashed(iter->second.Duplicate());
+ for (auto& observer : observers_) {
+ auto params = iter->second.Duplicate();
+ params.set_exit_code(exit_code);
+ observer.OnServiceProcessCrashed(params);
+ }
processes_.erase(iter);
}
@@ -91,6 +94,11 @@ class ServiceProcessTracker {
observers_.AddObserver(observer);
}
+ bool HasObserver(ServiceProcessHost::Observer* observer) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ return observers_.HasObserver(observer);
+ }
+
void RemoveObserver(ServiceProcessHost::Observer* observer) {
// NOTE: Some tests may remove observers after BrowserThreads are shut down.
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
@@ -158,7 +166,7 @@ class UtilityProcessClient : public UtilityProcessHost::Client {
process_info_->service_process_id());
}
- void OnProcessCrashed() override {
+ void OnProcessCrashed(int exit_code) override {
// TODO(https://crbug.com/1016027): It is unclear how we can observe
// |OnProcessCrashed()| without observing |OnProcessLaunched()| first, but
// it can happen on Android. Ignore the notification in this case.
@@ -166,7 +174,7 @@ class UtilityProcessClient : public UtilityProcessHost::Client {
return;
GetServiceProcessTracker().NotifyCrashed(
- process_info_->service_process_id());
+ process_info_->service_process_id(), exit_code);
}
private:
@@ -233,6 +241,11 @@ void ServiceProcessHost::AddObserver(Observer* observer) {
GetServiceProcessTracker().AddObserver(observer);
}
+// static
+bool ServiceProcessHost::HasObserver(Observer* observer) {
+ return GetServiceProcessTracker().HasObserver(observer);
+}
+
// static
void ServiceProcessHost::RemoveObserver(Observer* observer) {
GetServiceProcessTracker().RemoveObserver(observer);
diff --git a/content/browser/utility_process_host.cc b/content/browser/utility_process_host.cc
index e7f30e95727137fc54f8493dfa8eb36b74fbdcb4..51d60ffdabb72f0448d67667813d6fe006a1b3e0 100644
--- a/content/browser/utility_process_host.cc
+++ b/content/browser/utility_process_host.cc
@@ -549,7 +549,7 @@ void UtilityProcessHost::OnProcessCrashed(int exit_code) {
// Take ownership of |client_| so the destructor doesn't notify it of
// termination.
auto client = std::move(client_);
- client->OnProcessCrashed();
+ client->OnProcessCrashed(exit_code);
}
std::optional<std::string> UtilityProcessHost::GetServiceName() {
diff --git a/content/browser/utility_process_host.h b/content/browser/utility_process_host.h
index 9bfc30138a01520d59760a49d15dd4819feb0556..1107ad8691869d37196ea9d8dd29ef53e0a7ae10 100644
--- a/content/browser/utility_process_host.h
+++ b/content/browser/utility_process_host.h
@@ -84,7 +84,7 @@ class CONTENT_EXPORT UtilityProcessHost
virtual void OnProcessLaunched(const base::Process& process) {}
virtual void OnProcessTerminatedNormally() {}
- virtual void OnProcessCrashed() {}
+ virtual void OnProcessCrashed(int exit_code) {}
};
// This class is self-owned. It must be instantiated using new, and shouldn't
diff --git a/content/public/browser/service_process_host.h b/content/public/browser/service_process_host.h
index 8efbbd030729276114c40b33ee72822b02444a84..bf9325406c7358a3dce4f56d0f66acc0871190cc 100644
--- a/content/public/browser/service_process_host.h
+++ b/content/public/browser/service_process_host.h
@@ -231,6 +231,10 @@ class CONTENT_EXPORT ServiceProcessHost {
// removed before destruction. Must be called from the UI thread only.
static void AddObserver(Observer* observer);
+ // Returns true if the given observer is currently registered.
+ // Must be called from the UI thread only.
+ static bool HasObserver(Observer* observer);
+
// Removes a registered observer. This must be called some time before
// |*observer| is destroyed and must be called from the UI thread only.
static void RemoveObserver(Observer* observer);
diff --git a/content/public/browser/service_process_info.h b/content/public/browser/service_process_info.h
index 1a8656aef341cd3b23af588fb00569b79d6cd100..f904af7ee6bbacf4474e0939855ecf9f2c9a5eaa 100644
--- a/content/public/browser/service_process_info.h
+++ b/content/public/browser/service_process_info.h
@@ -64,7 +64,13 @@ class CONTENT_EXPORT ServiceProcessInfo {
const std::optional<GURL>& site() const { return site_; }
const base::Process& GetProcess() const { return process_; }
+ void set_exit_code(int exit_code) { exit_code_ = exit_code; }
+ int exit_code() const { return exit_code_; }
+
private:
+ // The exit code of the process, if it has exited.
+ int exit_code_;
+
// The name of the service interface for which the process was launched.
std::string service_interface_name_;

View File

@@ -16,7 +16,7 @@ Linux or Windows to un-fullscreen in some circumstances without this
change.
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
index a543fb2ec5873da9d2b108748eaa5d52de4f0d50..a03f68e218dd540d3d1fd3d51e3fa67478198789 100644
index 1a131cf3a34b32cae6180a6744c0169431d866a5..f57c698fe21e54c0687fe26093224d677fdc2c34 100644
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
@@ -16,12 +16,16 @@
@@ -115,8 +115,8 @@ index a543fb2ec5873da9d2b108748eaa5d52de4f0d50..a03f68e218dd540d3d1fd3d51e3fa674
return;
+#if 0
CHECK(fullscreen_start_time_);
if (exclusive_access_tab()) {
// `fullscreen_start_time_` is null if a fullscreen tab moves to a new window.
if (fullscreen_start_time_ && exclusive_access_tab()) {
ukm::SourceId source_id =
@@ -562,15 +573,16 @@ void FullscreenController::ExitFullscreenModeInternal() {
.Record(ukm::UkmRecorder::Get());

View File

@@ -40,18 +40,16 @@ index 25896ab0f3ca233ae17bf509f2a6ae5a6cc3c54b..5a8e6d184e276833034c604be8c48e01
// Called from BrowserMainLoop::PostCreateThreads().
// TODO(content/browser/gpu/OWNERS): This should probably use a
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.cc b/content/browser/gpu/gpu_data_manager_impl_private.cc
index 4fa857fed71485898f4ba7c6e78cc8be37d8dbf7..3306a36044eed8395b3a13cffa4754cadee1048d 100644
index 4fa857fed71485898f4ba7c6e78cc8be37d8dbf7..c12a96390350b5bd14a43506d8a35e4b0dec4924 100644
--- a/content/browser/gpu/gpu_data_manager_impl_private.cc
+++ b/content/browser/gpu/gpu_data_manager_impl_private.cc
@@ -1222,6 +1222,12 @@ void GpuDataManagerImplPrivate::TerminateInfoCollectionGpuProcess() {
@@ -1222,6 +1222,10 @@ void GpuDataManagerImplPrivate::TerminateInfoCollectionGpuProcess() {
if (host)
host->ForceShutdown();
}
+
+bool GpuDataManagerImplPrivate::DxdiagDx12VulkanRequested() const {
+ return !(gpu_info_vulkan_request_failed_ ||
+ gpu_info_dx12_request_failed_ ||
+ gpu_info_dx_diag_request_failed_);
+ return !(gpu_info_vulkan_request_failed_ || gpu_info_dx12_request_failed_);
+}
#endif

View File

@@ -0,0 +1,207 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zakhar Voit <voit@google.com>
Date: Fri, 7 Jun 2024 11:26:03 +0000
Subject: MediaSession: Use a MediaSessionImpl WeakPtr in
MediaSessionServiceImpl
Currently, every time MediaSessionServiceImpl wants to talk to its
associated MediaSessionImpl, it recalculates it from its
RenderFrameHostId. This can lead to issues where a
MediaSessionServiceImpl of a disconnected RenderFrameHost can no longer
access the MediaSessionImpl to tell it that it is being deleted,
leaving MediaSessionImpl with a dangling raw_ptr.
(cherry picked from commit 1f0de3303671c6c041930c7f4f8a9ad017a7f211)
(cherry picked from commit 11c5f7911caab6930812a515eac27e35776ba35c)
Bug: 338929744
Change-Id: I092d217d4a975b67a84280687ed5461a14ead98a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5577944
Commit-Queue: Tommy Steimel <steimel@chromium.org>
Cr-Original-Commit-Position: refs/branch-heads/6367@{#1245}
Cr-Original-Branched-From: d158c6dc6e3604e6f899041972edf26087a49740-refs/heads/main@{#1274542}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5583452
Owners-Override: Michael Ershov <miersh@google.com>
Commit-Queue: Michael Ershov <miersh@google.com>
Reviewed-by: Dale Curtis <dalecurtis@chromium.org>
Reviewed-by: Michael Ershov <miersh@google.com>
Cr-Commit-Position: refs/branch-heads/6099@{#2035}
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
diff --git a/content/browser/media/session/media_session_impl.cc b/content/browser/media/session/media_session_impl.cc
index 5ccef5240eef2e3b5c82bc50b97331e1b2fb9f31..710aeb26aee5bcfd95fef96fc7b8be7aa27173ad 100644
--- a/content/browser/media/session/media_session_impl.cc
+++ b/content/browser/media/session/media_session_impl.cc
@@ -1669,6 +1669,10 @@ const base::UnguessableToken& MediaSessionImpl::GetRequestId() const {
return delegate_->request_id();
}
+base::WeakPtr<MediaSessionImpl> MediaSessionImpl::GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+}
+
void MediaSessionImpl::RebuildAndNotifyActionsChanged() {
std::set<media_session::mojom::MediaSessionAction> actions =
routed_service_ ? routed_service_->actions()
diff --git a/content/browser/media/session/media_session_impl.h b/content/browser/media/session/media_session_impl.h
index 1f30f99fdd94617e3ddb8fb701c01201fbebf9df..af0f967b45e52778837ea716bc8290c6c0e20a6a 100644
--- a/content/browser/media/session/media_session_impl.h
+++ b/content/browser/media/session/media_session_impl.h
@@ -17,6 +17,7 @@
#include "base/containers/id_map.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ptr_exclusion.h"
+#include "base/memory/weak_ptr.h"
#include "base/timer/timer.h"
#include "build/build_config.h"
#include "content/browser/media/session/audio_focus_delegate.h"
@@ -346,6 +347,9 @@ class MediaSessionImpl : public MediaSession,
// Returns the Audio Focus request ID associated with this media session.
const base::UnguessableToken& GetRequestId() const;
+ // Returns a WeakPtr to `this`.
+ base::WeakPtr<MediaSessionImpl> GetWeakPtr();
+
CONTENT_EXPORT bool HasImageCacheForTest(const GURL& image_url) const;
// Make sure that all observers have received any pending callbacks from us,
@@ -641,6 +645,8 @@ class MediaSessionImpl : public MediaSession,
media_session::mojom::RemotePlaybackMetadataPtr remote_playback_metadata_;
+ base::WeakPtrFactory<MediaSessionImpl> weak_factory_{this};
+
WEB_CONTENTS_USER_DATA_KEY_DECL();
};
diff --git a/content/browser/media/session/media_session_service_impl.cc b/content/browser/media/session/media_session_service_impl.cc
index 532d1161b5321fbe37552f1caca2d20782356f36..a3ca009421a22d51a9d85f4665dd769319d26c22 100644
--- a/content/browser/media/session/media_session_service_impl.cc
+++ b/content/browser/media/session/media_session_service_impl.cc
@@ -22,14 +22,16 @@ MediaSessionServiceImpl::MediaSessionServiceImpl(
: render_frame_host_id_(render_frame_host->GetGlobalId()),
playback_state_(blink::mojom::MediaSessionPlaybackState::NONE) {
MediaSessionImpl* session = GetMediaSession();
- if (session)
- session->OnServiceCreated(this);
+ if (session) {
+ media_session_ = session->GetWeakPtr();
+ media_session_->OnServiceCreated(this);
+ }
}
MediaSessionServiceImpl::~MediaSessionServiceImpl() {
- MediaSessionImpl* session = GetMediaSession();
- if (session)
- session->OnServiceDestroyed(this);
+ if (media_session_) {
+ media_session_->OnServiceDestroyed(this);
+ }
}
// static
@@ -70,17 +72,17 @@ void MediaSessionServiceImpl::SetClient(
void MediaSessionServiceImpl::SetPlaybackState(
blink::mojom::MediaSessionPlaybackState state) {
playback_state_ = state;
- MediaSessionImpl* session = GetMediaSession();
- if (session)
- session->OnMediaSessionPlaybackStateChanged(this);
+ if (media_session_) {
+ media_session_->OnMediaSessionPlaybackStateChanged(this);
+ }
}
void MediaSessionServiceImpl::SetPositionState(
const std::optional<media_session::MediaPosition>& position) {
position_ = position;
- MediaSessionImpl* session = GetMediaSession();
- if (session)
- session->RebuildAndNotifyMediaPositionChanged();
+ if (media_session_) {
+ media_session_->RebuildAndNotifyMediaPositionChanged();
+ }
}
void MediaSessionServiceImpl::SetMetadata(
@@ -102,48 +104,48 @@ void MediaSessionServiceImpl::SetMetadata(
metadata_ = std::move(metadata);
}
- MediaSessionImpl* session = GetMediaSession();
- if (session)
- session->OnMediaSessionMetadataChanged(this);
+ if (media_session_) {
+ media_session_->OnMediaSessionMetadataChanged(this);
+ }
}
void MediaSessionServiceImpl::SetMicrophoneState(
media_session::mojom::MicrophoneState microphone_state) {
microphone_state_ = microphone_state;
- MediaSessionImpl* session = GetMediaSession();
- if (session)
- session->OnMediaSessionInfoChanged(this);
+ if (media_session_) {
+ media_session_->OnMediaSessionInfoChanged(this);
+ }
}
void MediaSessionServiceImpl::SetCameraState(
media_session::mojom::CameraState camera_state) {
camera_state_ = camera_state;
- MediaSessionImpl* session = GetMediaSession();
- if (session)
- session->OnMediaSessionInfoChanged(this);
+ if (media_session_) {
+ media_session_->OnMediaSessionInfoChanged(this);
+ }
}
void MediaSessionServiceImpl::EnableAction(
media_session::mojom::MediaSessionAction action) {
actions_.insert(action);
- MediaSessionImpl* session = GetMediaSession();
- if (session)
- session->OnMediaSessionActionsChanged(this);
+ if (media_session_) {
+ media_session_->OnMediaSessionActionsChanged(this);
+ }
}
void MediaSessionServiceImpl::DisableAction(
media_session::mojom::MediaSessionAction action) {
actions_.erase(action);
- MediaSessionImpl* session = GetMediaSession();
- if (session)
- session->OnMediaSessionActionsChanged(this);
+ if (media_session_) {
+ media_session_->OnMediaSessionActionsChanged(this);
+ }
}
void MediaSessionServiceImpl::ClearActions() {
actions_.clear();
- MediaSessionImpl* session = GetMediaSession();
- if (session)
- session->OnMediaSessionActionsChanged(this);
+ if (media_session_) {
+ media_session_->OnMediaSessionActionsChanged(this);
+ }
}
MediaSessionImpl* MediaSessionServiceImpl::GetMediaSession() {
diff --git a/content/browser/media/session/media_session_service_impl.h b/content/browser/media/session/media_session_service_impl.h
index 4eeffe2a8bbc532d15e5deb7bc77eebea41326cf..514c043648e70b3c29a57ddc5faabaf85e103491 100644
--- a/content/browser/media/session/media_session_service_impl.h
+++ b/content/browser/media/session/media_session_service_impl.h
@@ -85,6 +85,8 @@ class CONTENT_EXPORT MediaSessionServiceImpl
const GlobalRenderFrameHostId render_frame_host_id_;
+ base::WeakPtr<MediaSessionImpl> media_session_;
+
mojo::Remote<blink::mojom::MediaSessionClient> client_;
blink::mojom::MediaSessionPlaybackState playback_state_;
blink::mojom::SpecMediaMetadataPtr metadata_;

View File

@@ -1,13 +1,13 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: deepak1556 <hop2deep@gmail.com>
Date: Thu, 7 Apr 2022 20:30:16 +0900
Subject: Make gtk::GetLibGtk and gtk::GetLibGdkPixbuf public
Subject: Make gtk::GetLibGdkPixbuf public
Allows embedders to get a handle to the gtk and
gdk_pixbuf libraries already loaded in the process.
Allows embedders to get a handle to the gdk_pixbuf
library already loaded in the process.
diff --git a/ui/gtk/gtk_compat.cc b/ui/gtk/gtk_compat.cc
index d196e304a43191b6dc82f25b0b4bf24d242edb3c..85d618efa0574b00fc0cb1e5bde5ed725b2a90ab 100644
index d196e304a43191b6dc82f25b0b4bf24d242edb3c..0156ed1c3e8e1de8ce875ca9a17e69358074743e 100644
--- a/ui/gtk/gtk_compat.cc
+++ b/ui/gtk/gtk_compat.cc
@@ -66,11 +66,6 @@ void* GetLibGio() {
@@ -22,20 +22,7 @@ index d196e304a43191b6dc82f25b0b4bf24d242edb3c..85d618efa0574b00fc0cb1e5bde5ed72
void* GetLibGdk3() {
static void* libgdk3 = DlOpen("libgdk-3.so.0");
return libgdk3;
@@ -86,12 +81,6 @@ void* GetLibGtk4(bool check = true) {
return libgtk4;
}
-void* GetLibGtk() {
- if (GtkCheckVersion(4))
- return GetLibGtk4();
- return GetLibGtk3();
-}
-
bool LoadGtk3() {
if (!GetLibGtk3(false))
return false;
@@ -134,6 +123,17 @@ gfx::Insets InsetsFromGtkBorder(const GtkBorder& border) {
@@ -134,6 +129,11 @@ gfx::Insets InsetsFromGtkBorder(const GtkBorder& border) {
} // namespace
@@ -43,29 +30,20 @@ index d196e304a43191b6dc82f25b0b4bf24d242edb3c..85d618efa0574b00fc0cb1e5bde5ed72
+ static void* libgdk_pixbuf = DlOpen("libgdk_pixbuf-2.0.so.0");
+ return libgdk_pixbuf;
+}
+
+void* GetLibGtk() {
+ if (GtkCheckVersion(4))
+ return GetLibGtk4();
+ return GetLibGtk3();
+}
+
bool LoadGtk() {
static bool loaded = LoadGtkImpl();
return loaded;
diff --git a/ui/gtk/gtk_compat.h b/ui/gtk/gtk_compat.h
index 409e385fc952662c9887d9a810bb3c547c5be282..1518b681f98b3bc051aed74713a23c016c7b755e 100644
index 409e385fc952662c9887d9a810bb3c547c5be282..579ac4f6a39654f1e58ed0eb165c2773e5620475 100644
--- a/ui/gtk/gtk_compat.h
+++ b/ui/gtk/gtk_compat.h
@@ -40,6 +40,12 @@ using SkColor = uint32_t;
@@ -40,6 +40,9 @@ using SkColor = uint32_t;
namespace gtk {
+// Get handle to the currently loaded gdk_pixbuf library in the process.
+void* GetLibGdkPixbuf();
+
+// Get handle to the currently loaded gtk library in the process.
+void* GetLibGtk();
+
// Loads libgtk and related libraries and returns true on success.
bool LoadGtk();

View File

@@ -0,0 +1,206 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marja=20H=C3=B6ltt=C3=A4?= <marja@google.com>
Date: Tue, 9 Apr 2024 08:32:27 +0000
Subject: Merge "Fix DOMArrayBuffer::IsDetached()" and "Comment out a CHECK
that a DOMAB has maximally one non-detached JSAB"
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
1)
A DOMArrayBuffer was maintaining its own "is_detached_" state, and
would consider itself non-detached even if the corresponding
JSArrayBuffer (or, all of them, in case there are several) was
detached.
Piping in the v8::Isolate would be a too big change for this fix, so this is using v8::Isolate::GetCurrent() for now.
2)
Comment out a CHECK that a DOMAB has maximally one non-detached JSAB
Based on crash reports, this assumption is not true and has to be
investigated.
Removing this newly introduced CHECK to be able to merge fixes in this
area - we still violate this invariant but the fixes are a step into
the right direction.
Fix in question:
https://chromium-review.googlesource.com/5387887
which also introduced this CHECK.
(cherry picked from commit 04e7550d7aa3bf4ac4e49d7074972d357de139e6)
Change-Id: I6a46721e24c6f04fe8252bc4a5e94caeec3a8b51
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5435035
Commit-Queue: Marja Hölttä <marja@chromium.org>
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/branch-heads/6367@{#667}
Cr-Branched-From: d158c6dc6e3604e6f899041972edf26087a49740-refs/heads/main@{#1274542}
diff --git a/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc b/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc
index 44e2849c8e4dfc38834c88937dc561858c13e726..f26b6de5baded254d1ae5c3db458d0405e9751cb 100644
--- a/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc
+++ b/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.cc
@@ -46,8 +46,19 @@ const WrapperTypeInfo& DOMArrayBuffer::wrapper_type_info_ =
static void AccumulateArrayBuffersForAllWorlds(
v8::Isolate* isolate,
- DOMArrayBuffer* object,
+ const DOMArrayBuffer* object,
v8::LocalVector<v8::ArrayBuffer>& buffers) {
+ if (!object->has_non_main_world_wrappers() && IsMainThread()) {
+ const DOMWrapperWorld& world = DOMWrapperWorld::MainWorld(isolate);
+ v8::Local<v8::Object> wrapper;
+ if (world.DomDataStore()
+ .Get</*entered_context=*/false>(isolate, object)
+ .ToLocal(&wrapper)) {
+ buffers.push_back(v8::Local<v8::ArrayBuffer>::Cast(wrapper));
+ }
+ return;
+ }
+
Vector<scoped_refptr<DOMWrapperWorld>> worlds;
DOMWrapperWorld::AllWorldsInIsolate(isolate, worlds);
for (const auto& world : worlds) {
@@ -259,6 +270,52 @@ v8::Local<v8::Value> DOMArrayBuffer::Wrap(ScriptState* script_state) {
wrapper);
}
+bool DOMArrayBuffer::IsDetached() const {
+ if (contents_.BackingStore() == nullptr) {
+ return is_detached_;
+ }
+ if (is_detached_) {
+ return true;
+ }
+
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope handle_scope(isolate);
+ v8::LocalVector<v8::ArrayBuffer> buffer_handles(isolate);
+ AccumulateArrayBuffersForAllWorlds(isolate, this, buffer_handles);
+
+ // There may be several v8::ArrayBuffers corresponding to the DOMArrayBuffer,
+ // but at most one of them may be non-detached.
+ int nondetached_count = 0;
+ int detached_count = 0;
+
+ for (const auto& buffer_handle : buffer_handles) {
+ if (buffer_handle->WasDetached()) {
+ ++detached_count;
+ } else {
+ ++nondetached_count;
+ }
+ }
+
+ // This CHECK fires even though it should not. TODO(330759272): Investigate
+ // under which conditions we end up with multiple non-detached JSABs for the
+ // same DOMAB and potentially restore this check.
+
+ // CHECK_LE(nondetached_count, 1);
+
+ return nondetached_count == 0 && detached_count > 0;
+}
+
+v8::Local<v8::Object> DOMArrayBuffer::AssociateWithWrapper(
+ v8::Isolate* isolate,
+ const WrapperTypeInfo* wrapper_type_info,
+ v8::Local<v8::Object> wrapper) {
+ if (!DOMWrapperWorld::Current(isolate).IsMainWorld()) {
+ has_non_main_world_wrappers_ = true;
+ }
+ return ScriptWrappable::AssociateWithWrapper(isolate, wrapper_type_info,
+ wrapper);
+}
+
DOMArrayBuffer* DOMArrayBuffer::Slice(size_t begin, size_t end) const {
begin = std::min(begin, ByteLength());
end = std::min(end, ByteLength());
diff --git a/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h b/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h
index a7d4bac99e608bcfaa02dc9bfcef20b5a29d0ddc..9d4827f548ca7db3be85011c68d8346fc8dfa909 100644
--- a/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h
+++ b/third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h
@@ -91,6 +91,17 @@ class CORE_EXPORT DOMArrayBuffer : public DOMArrayBufferBase {
void Trace(Visitor*) const override;
+ bool IsDetached() const override;
+
+ v8::Local<v8::Object> AssociateWithWrapper(
+ v8::Isolate* isolate,
+ const WrapperTypeInfo* wrapper_type_info,
+ v8::Local<v8::Object> wrapper) override;
+
+ bool has_non_main_world_wrappers() const {
+ return has_non_main_world_wrappers_;
+ }
+
private:
v8::Maybe<bool> TransferDetachable(v8::Isolate*,
v8::Local<v8::Value> detach_key,
@@ -101,6 +112,8 @@ class CORE_EXPORT DOMArrayBuffer : public DOMArrayBufferBase {
// support only v8::String as the detach key type. It's also convenient that
// we can write `array_buffer->SetDetachKey(isolate, "my key")`.
TraceWrapperV8Reference<v8::String> detach_key_;
+
+ bool has_non_main_world_wrappers_ = false;
};
} // namespace blink
diff --git a/third_party/blink/renderer/core/typed_arrays/dom_array_buffer_base.h b/third_party/blink/renderer/core/typed_arrays/dom_array_buffer_base.h
index 90c4c70755babdc8c88a7c6bf02803c5858c2194..43618b8ef4b831678b45c72ca47f5729c4f2aaef 100644
--- a/third_party/blink/renderer/core/typed_arrays/dom_array_buffer_base.h
+++ b/third_party/blink/renderer/core/typed_arrays/dom_array_buffer_base.h
@@ -27,7 +27,9 @@ class CORE_EXPORT DOMArrayBufferBase : public ScriptWrappable {
size_t ByteLength() const { return contents_.DataLength(); }
- bool IsDetached() const { return is_detached_; }
+ // TODO(331348222): It doesn't make sense to detach DomSharedArrayBuffers,
+ // remove that possibility.
+ virtual bool IsDetached() const { return is_detached_; }
void Detach() { is_detached_ = true; }
diff --git a/third_party/blink/renderer/modules/gamepad/BUILD.gn b/third_party/blink/renderer/modules/gamepad/BUILD.gn
index 572d8ce27fa808707ae17ed05f14e2ed103f131e..a871cbd002795bf49ad48f0002ac4996135f8b10 100644
--- a/third_party/blink/renderer/modules/gamepad/BUILD.gn
+++ b/third_party/blink/renderer/modules/gamepad/BUILD.gn
@@ -55,6 +55,7 @@ source_set("unit_tests") {
"//testing/gtest",
"//third_party/blink/renderer/modules",
"//third_party/blink/renderer/platform",
+ "//third_party/blink/renderer/platform:test_support",
"//third_party/blink/renderer/platform/wtf",
]
}
diff --git a/third_party/blink/renderer/modules/gamepad/gamepad_comparisons_test.cc b/third_party/blink/renderer/modules/gamepad/gamepad_comparisons_test.cc
index e0a7f48630ba423b19641232c026d72ba71dfc4b..b9f422e6fff36da62575d803f132573a24d03c05 100644
--- a/third_party/blink/renderer/modules/gamepad/gamepad_comparisons_test.cc
+++ b/third_party/blink/renderer/modules/gamepad/gamepad_comparisons_test.cc
@@ -4,9 +4,11 @@
#include "third_party/blink/renderer/modules/gamepad/gamepad_comparisons.h"
+#include "base/test/task_environment.h"
#include "device/gamepad/public/cpp/gamepad.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/modules/gamepad/gamepad.h"
+#include "third_party/blink/renderer/platform/testing/main_thread_isolate.h"
namespace blink {
@@ -241,6 +243,11 @@ class GamepadComparisonsTest : public testing::Test {
list[0] = gamepad;
return list;
}
+
+ private:
+ // Needed so we can do v8::Isolate::GetCurrent().
+ base::test::TaskEnvironment task_environment_;
+ blink::test::MainThreadIsolate isolate_;
};
TEST_F(GamepadComparisonsTest, EmptyListCausesNoActivation) {

View File

@@ -133,10 +133,10 @@ index 38c8cf36fdf9366121c7ada96c167a4c9664952e..03b37fb62655a355e104870a088e4222
const GURL& document_url,
const WeakDocumentPtr& weak_document_ptr,
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index b656054d342f53d655b8c068b127250a8e8af6c3..5f6267cce7c59eab684dda3f8bfc7982b6407841 100644
index 545c860afff13c6aa5030128f508f325de0ab507..938844e3f653344b97dd8e59faacdb8eded561a9 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -2045,7 +2045,7 @@ void RenderProcessHostImpl::CreateNotificationService(
@@ -2048,7 +2048,7 @@ void RenderProcessHostImpl::CreateNotificationService(
case RenderProcessHost::NotificationServiceCreatorType::kSharedWorker:
case RenderProcessHost::NotificationServiceCreatorType::kDedicatedWorker: {
storage_partition_impl_->GetPlatformNotificationContext()->CreateService(
@@ -145,7 +145,7 @@ index b656054d342f53d655b8c068b127250a8e8af6c3..5f6267cce7c59eab684dda3f8bfc7982
creator_type, std::move(receiver));
break;
}
@@ -2053,7 +2053,7 @@ void RenderProcessHostImpl::CreateNotificationService(
@@ -2056,7 +2056,7 @@ void RenderProcessHostImpl::CreateNotificationService(
CHECK(rfh);
storage_partition_impl_->GetPlatformNotificationContext()->CreateService(

File diff suppressed because it is too large Load Diff

View File

@@ -22,13 +22,13 @@ However, the patch would need to be reviewed by the security team, as it
does touch a security-sensitive class.
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 5f6267cce7c59eab684dda3f8bfc7982b6407841..4551601cf77d57e74c725d4352b128c0ac8b09b7 100644
index 938844e3f653344b97dd8e59faacdb8eded561a9..ae21df015a9e43d4c324bd79ff3bf00c23b5225e 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1727,9 +1727,15 @@ bool RenderProcessHostImpl::Init() {
@@ -1730,9 +1730,15 @@ bool RenderProcessHostImpl::Init() {
std::unique_ptr<SandboxedProcessLauncherDelegate> sandbox_delegate =
std::make_unique<RendererSandboxedProcessLauncherDelegateWin>(
*cmd_line, IsPdf(), IsJitDisabled());
*cmd_line, IsPdf(), /*is_jit_disabled=*/IsPdf());
+#else
+#if BUILDFLAG(USE_ZYGOTE)
+ bool use_zygote = !cmd_line->HasSwitch(switches::kNoZygote);

View File

@@ -0,0 +1,30 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Tom Anderson <thomasanderson@chromium.org>
Date: Tue, 27 Feb 2024 00:35:14 +0000
Subject: Fix crash when RandR::GetMonitors fails
R=sky
Change-Id: Id3c01221cec6edb4b782a273653758c1375c0acb
Fixed: 326328413
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5324886
Commit-Queue: Scott Violet <sky@chromium.org>
Reviewed-by: Scott Violet <sky@chromium.org>
Auto-Submit: Thomas Anderson <thomasanderson@chromium.org>
Commit-Queue: Thomas Anderson <thomasanderson@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1265556}
diff --git a/ui/base/x/x11_display_util.cc b/ui/base/x/x11_display_util.cc
index bf3077d80fc0ce31f381d5ff1defef16cfdbee0a..fda1c3cb239210ac7efbf0aa2311548d0142c413 100644
--- a/ui/base/x/x11_display_util.cc
+++ b/ui/base/x/x11_display_util.cc
@@ -44,6 +44,9 @@ constexpr const char kRandrEdidProperty[] = "EDID";
std::map<x11::RandR::Output, size_t> GetMonitors(
const x11::Response<x11::RandR::GetMonitorsReply>& reply) {
std::map<x11::RandR::Output, size_t> output_to_monitor;
+ if (!reply) {
+ return output_to_monitor;
+ }
for (size_t monitor = 0; monitor < reply->monitors.size(); monitor++) {
for (x11::RandR::Output output : reply->monitors[monitor].outputs) {
output_to_monitor[output] = monitor;

View File

@@ -0,0 +1,62 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: deepak1556 <hop2deep@gmail.com>
Date: Mon, 17 Jun 2024 18:05:47 +0000
Subject: Use localized display label only for browser process
With https://crrev.com/c/5098130, GetPrimaryDisplayRefreshIntervalFromXrandr uses BuildDisplaysFromXRandRInfo
to calculate the primary display frequency. In software compositing mode --disable-gpu-compositing,
this code path will be called from the gpu process via SoftwareOutputSurface::SwapBuffers and
can trigger a crash when attempting to set localized string. This is because on linux,
gpu process does not have access to the resource bundle.
Bug: none
Change-Id: I9d66b98c07a1a8671369546d4fc685213904a84f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5631219
Auto-Submit: Deepak Mohan (Robo) <hop2deep@gmail.com>
Reviewed-by: Thomas Anderson <thomasanderson@chromium.org>
Reviewed-by: Scott Violet <sky@chromium.org>
Commit-Queue: Scott Violet <sky@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1315980}
diff --git a/ui/base/x/x11_display_util.cc b/ui/base/x/x11_display_util.cc
index 373be9bfad6766b8ba50140418263fa14c295689..bf3077d80fc0ce31f381d5ff1defef16cfdbee0a 100644
--- a/ui/base/x/x11_display_util.cc
+++ b/ui/base/x/x11_display_util.cc
@@ -294,6 +294,7 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo(
const DisplayConfig& display_config,
size_t* primary_display_index_out) {
DCHECK(primary_display_index_out);
+ auto* command_line = base::CommandLine::ForCurrentProcess();
const float primary_scale = display_config.primary_scale;
auto* connection = x11::Connection::Get();
@@ -343,7 +344,7 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo(
connection->Flush();
std::vector<x11::Future<x11::GetPropertyReply>> icc_futures{n_iccs};
- if (!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kHeadless)) {
+ if (!command_line->HasSwitch(switches::kHeadless)) {
for (size_t monitor = 0; monitor < n_iccs; ++monitor) {
icc_futures[monitor] = GetIccProfileFuture(connection, monitor);
}
@@ -441,11 +442,18 @@ std::vector<display::Display> BuildDisplaysFromXRandRInfo(
}
const std::string name(output_info->name.begin(), output_info->name.end());
+ auto process_type =
+ command_line->GetSwitchValueASCII("type");
if (base::StartsWith(name, "eDP") || base::StartsWith(name, "LVDS")) {
display::SetInternalDisplayIds({display_id});
- // Use localized variant of "Built-in display" for internal displays.
+ // For browser process which has access to resource bundle,
+ // use localized variant of "Built-in display" for internal displays.
// This follows the ozone DRM behavior (i.e. ChromeOS).
- display.set_label(l10n_util::GetStringUTF8(IDS_DISPLAY_NAME_INTERNAL));
+ if (process_type.empty()) {
+ display.set_label(l10n_util::GetStringUTF8(IDS_DISPLAY_NAME_INTERNAL));
+ } else {
+ display.set_label("Built-in display");
+ }
} else {
display.set_label(edid_parser.display_name());
}

View File

@@ -11,5 +11,9 @@
{ "patch_dir": "src/electron/patches/Mantle", "repo": "src/third_party/squirrel.mac/vendor/Mantle" },
{ "patch_dir": "src/electron/patches/ReactiveObjC", "repo": "src/third_party/squirrel.mac/vendor/ReactiveObjC" },
{ "patch_dir": "src/electron/patches/webrtc", "repo": "src/third_party/webrtc" },
{ "patch_dir": "src/electron/patches/reclient-configs", "repo": "src/third_party/engflow-reclient-configs" }
{ "patch_dir": "src/electron/patches/reclient-configs", "repo": "src/third_party/engflow-reclient-configs" },
{ "patch_dir": "src/electron/patches/angle", "repo": "src/third_party/angle" },
{ "patch_dir": "src/electron/patches/DirectXShaderCompiler", "repo": "src/third_party/dawn/third_party/dxc" },
{ "patch_dir": "src/electron/patches/libaom", "repo": "src/third_party/libaom/source/libaom"},
{ "patch_dir": "src/electron/patches/dawn", "repo": "src/third_party/dawn" }
]

1
patches/dawn/.patches Normal file
View File

@@ -0,0 +1 @@
dawn_dxc_disable_dxc_pass_structurize-loop-exits-for-unroll.patch

View File

@@ -0,0 +1,34 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Antonio Maiorano <amaiorano@google.com>
Date: Mon, 17 Jun 2024 18:33:47 +0000
Subject: dawn/dxc: disable DXC pass 'structurize-loop-exits-for-unroll'
Multiple security bugs have been reported related to this optimization pass, and after careful consideration, we have decided to disable it.
Bug: chromium:333508731
Bug: chromium:339171223
Bug: chromium:339169163
Bug: chromium:346595893
Change-Id: I5c9d7180ed09e7417c120595937bcb1013b6ce66
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/184422
Commit-Queue: Antonio Maiorano <amaiorano@google.com>
Reviewed-by: Natalie Chouinard <chouinard@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/194160
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/dawn/native/d3d/ShaderUtils.cpp b/src/dawn/native/d3d/ShaderUtils.cpp
index c0aeea4d192c4498c0e802f4c693e82cab395715..bfc2f0c5ba189e0912310c50a48d5e2233956223 100644
--- a/src/dawn/native/d3d/ShaderUtils.cpp
+++ b/src/dawn/native/d3d/ShaderUtils.cpp
@@ -58,6 +58,10 @@ std::vector<const wchar_t*> GetDXCArguments(std::wstring_view entryPointNameW,
arguments.push_back(L"-E");
arguments.push_back(entryPointNameW.data());
+ // TODO(chromium:346595893): Disable buggy DXC pass
+ arguments.push_back(L"-opt-disable");
+ arguments.push_back(L"structurize-loop-exits-for-unroll");
+
uint32_t compileFlags = r.compileFlags;
if (compileFlags & D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY) {
arguments.push_back(L"/Gec");

View File

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

View File

@@ -0,0 +1,26 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Andrey Kosyakov <caseq@chromium.org>
Date: Tue, 12 Mar 2024 19:58:44 -0700
Subject: Fix support for worklet targets
Fixes an issue where console.log() did not work in AudioWorkletGlobalScope.
Bug: 327027138
Change-Id: I051565c591645f0a4ccc297825d299c0764501ca
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/5367245
Reviewed-by: Danil Somsikov <dsv@chromium.org>
Commit-Queue: Andrey Kosyakov <caseq@chromium.org>
diff --git a/front_end/core/sdk/ChildTargetManager.ts b/front_end/core/sdk/ChildTargetManager.ts
index 1d790363b8a45655140353863b422fce35f2ae0e..9305546e8777abf582437e0978c114ad5db514ca 100644
--- a/front_end/core/sdk/ChildTargetManager.ts
+++ b/front_end/core/sdk/ChildTargetManager.ts
@@ -173,6 +173,8 @@ export class ChildTargetManager extends SDKModel<EventTypes> implements Protocol
type = Type.Frame;
} else if (targetInfo.type === 'worker') {
type = Type.Worker;
+ } else if (targetInfo.type === 'worklet') {
+ type = Type.Worklet;
} else if (targetInfo.type === 'shared_worker') {
type = Type.SharedWorker;
} else if (targetInfo.type === 'shared_storage_worklet') {

2
patches/libaom/.patches Normal file
View File

@@ -0,0 +1,2 @@
update_codec_config_after_svc_scale_controls.patch
encode_api_test_add_repro_for_chromium_339877165.patch

View File

@@ -0,0 +1,162 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: James Zern <jzern@google.com>
Date: Thu, 16 May 2024 13:44:52 -0700
Subject: encode_api_test: add repro for chromium 339877165
BUG=chromium:339877165
Change-Id: I69dcc2cda098ec96a34e1e5f7ef557ee8caf5521
(cherry picked from commit 01467cdbd524900eed283660836179fd1b2cd536)
diff --git a/test/encode_api_test.cc b/test/encode_api_test.cc
index 605743f9be8ccc776aa3b8dcae0a79e7dc6711e6..c0a79fe734e7985b52bdbaaa5d8dec2c541275e5 100644
--- a/test/encode_api_test.cc
+++ b/test/encode_api_test.cc
@@ -556,6 +556,147 @@ TEST(EncodeAPI, Buganizer310457427) {
encoder.Encode(false);
}
+// Reproduces https://crbug.com/339877165.
+TEST(EncodeAPI, Buganizer339877165) {
+ // Initialize libaom encoder.
+ aom_codec_iface_t *const iface = aom_codec_av1_cx();
+ aom_codec_ctx_t enc;
+ aom_codec_enc_cfg_t cfg;
+
+ ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_REALTIME),
+ AOM_CODEC_OK);
+
+ cfg.g_w = 2560;
+ cfg.g_h = 1600;
+ cfg.rc_target_bitrate = 231;
+ cfg.rc_end_usage = AOM_CBR;
+ cfg.g_threads = 8;
+
+ ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK);
+
+ // From libaom_av1_encoder.cc in WebRTC.
+ ASSERT_EQ(aom_codec_control(&enc, AOME_SET_CPUUSED, 11), AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_CDEF, 1), AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_TPL_MODEL, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_DELTAQ_MODE, 0), AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_ORDER_HINT, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_AQ_MODE, 3), AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AOME_SET_MAX_INTRA_BITRATE_PCT, 300),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_COEFF_COST_UPD_FREQ, 3),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_MODE_COST_UPD_FREQ, 3),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_MV_COST_UPD_FREQ, 3),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_TUNE_CONTENT, AOM_CONTENT_SCREEN),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_PALETTE, 1), AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_TILE_ROWS, 1), AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_TILE_COLUMNS, 2), AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_OBMC, 0), AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_NOISE_SENSITIVITY, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_WARPED_MOTION, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_GLOBAL_MOTION, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_REF_FRAME_MVS, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_SUPERBLOCK_SIZE,
+ AOM_SUPERBLOCK_SIZE_DYNAMIC),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_CFL_INTRA, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_SMOOTH_INTRA, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_ANGLE_DELTA, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_FILTER_INTRA, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_INTRA_DEFAULT_TX_ONLY, 1),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_DISABLE_TRELLIS_QUANT, 1),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_DIST_WTD_COMP, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_DIFF_WTD_COMP, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_DUAL_FILTER, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_INTERINTRA_COMP, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_INTERINTRA_WEDGE, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_INTRA_EDGE_FILTER, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_INTRABC, 0), AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_MASKED_COMP, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_PAETH_INTRA, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_QM, 0), AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_RECT_PARTITIONS, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_RESTORATION, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_SMOOTH_INTERINTRA, 0),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_ENABLE_TX64, 0), AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_MAX_REFERENCE_FRAMES, 3),
+ AOM_CODEC_OK);
+ ASSERT_EQ(aom_codec_enc_config_set(&enc, &cfg), AOM_CODEC_OK);
+
+ aom_svc_params_t svc_params = {};
+ svc_params.number_spatial_layers = 2;
+ svc_params.number_temporal_layers = 1;
+ svc_params.max_quantizers[0] = svc_params.max_quantizers[1] = 56;
+ svc_params.min_quantizers[0] = svc_params.min_quantizers[1] = 10;
+ svc_params.scaling_factor_num[0] = svc_params.scaling_factor_num[1] = 1;
+ svc_params.scaling_factor_den[0] = 2;
+ svc_params.scaling_factor_den[1] = 1;
+ svc_params.layer_target_bitrate[0] = cfg.rc_target_bitrate;
+ svc_params.framerate_factor[0] = 1;
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_SVC_PARAMS, &svc_params),
+ AOM_CODEC_OK);
+
+ aom_svc_layer_id_t layer_id = {};
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_SVC_LAYER_ID, &layer_id),
+ AOM_CODEC_OK);
+
+ aom_svc_ref_frame_config_t ref_frame_config = {};
+ ref_frame_config.refresh[0] = 1;
+ ASSERT_EQ(
+ aom_codec_control(&enc, AV1E_SET_SVC_REF_FRAME_CONFIG, &ref_frame_config),
+ AOM_CODEC_OK);
+
+ // Create input image.
+ aom_image_t *const image =
+ CreateGrayImage(AOM_IMG_FMT_I420, cfg.g_w, cfg.g_h);
+ ASSERT_NE(image, nullptr);
+
+ // Encode layer 0.
+ ASSERT_EQ(aom_codec_encode(&enc, image, 0, 1, 0), AOM_CODEC_OK);
+
+ layer_id.spatial_layer_id = 1;
+ ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_SVC_LAYER_ID, &layer_id),
+ AOM_CODEC_OK);
+
+ ref_frame_config.refresh[0] = 0;
+ ASSERT_EQ(
+ aom_codec_control(&enc, AV1E_SET_SVC_REF_FRAME_CONFIG, &ref_frame_config),
+ AOM_CODEC_OK);
+
+ // Encode layer 1.
+ ASSERT_EQ(aom_codec_encode(&enc, image, 0, 1, 0), AOM_CODEC_OK);
+
+ // Free resources.
+ aom_img_free(image);
+ aom_codec_destroy(&enc);
+}
+
class EncodeAPIParameterized
: public testing::TestWithParam<std::tuple<
/*usage=*/unsigned int, /*speed=*/int, /*aq_mode=*/unsigned int>> {};

View File

@@ -0,0 +1,196 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: James Zern <jzern@google.com>
Date: Tue, 14 May 2024 17:54:10 -0700
Subject: update codec config after svc/scale controls
This ensures the encoder state/allocations stay in sync with scaling and
svc layer changes. In the SVC case, depending on the resolution,
differences in the chosen superblock size among layers may have caused a
crash. This was reproducible in WebRTC in screen content mode.
The fix is based on a change by Yuan Tong (tongyuan200097) [1]. It
refreshes the encoder config after AOME_SET_SCALEMODE,
AOME_SET_NUMBER_SPATIAL_LAYERS and AV1E_SET_SVC_PARAMS if no frames have
been encoded. AV1E_SET_SVC_PARAMS was missed in the original change.
[1]: https://aomedia-review.googlesource.com/c/aom/+/171941/2
Bug: chromium:339877165
Change-Id: Ib3d2a123b159898d7c7e19c81e89ff148920e1f1
(cherry picked from commit e42f4b1980bbbc772aa886d8b43a885461d7b89e)
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index 9214feb4e6f9dd068444e76bf8073a0bbe772134..68d6de21845a4e635f67f0a972126563d8f4fb7c 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -1602,37 +1602,42 @@ static aom_codec_err_t ctrl_get_baseline_gf_interval(aom_codec_alg_priv_t *ctx,
return AOM_CODEC_OK;
}
+static aom_codec_err_t update_encoder_cfg(aom_codec_alg_priv_t *ctx) {
+ set_encoder_config(&ctx->oxcf, &ctx->cfg, &ctx->extra_cfg);
+ av1_check_fpmt_config(ctx->ppi, &ctx->oxcf);
+ bool is_sb_size_changed = false;
+ av1_change_config_seq(ctx->ppi, &ctx->oxcf, &is_sb_size_changed);
+ for (int i = 0; i < ctx->ppi->num_fp_contexts; i++) {
+ AV1_COMP *const cpi = ctx->ppi->parallel_cpi[i];
+ struct aom_internal_error_info *const error = cpi->common.error;
+ if (setjmp(error->jmp)) {
+ error->setjmp = 0;
+ return error->error_code;
+ }
+ error->setjmp = 1;
+ av1_change_config(cpi, &ctx->oxcf, is_sb_size_changed);
+ error->setjmp = 0;
+ }
+ if (ctx->ppi->cpi_lap != NULL) {
+ AV1_COMP *const cpi_lap = ctx->ppi->cpi_lap;
+ struct aom_internal_error_info *const error = cpi_lap->common.error;
+ if (setjmp(error->jmp)) {
+ error->setjmp = 0;
+ return error->error_code;
+ }
+ error->setjmp = 1;
+ av1_change_config(cpi_lap, &ctx->oxcf, is_sb_size_changed);
+ error->setjmp = 0;
+ }
+ return AOM_CODEC_OK;
+}
+
static aom_codec_err_t update_extra_cfg(aom_codec_alg_priv_t *ctx,
const struct av1_extracfg *extra_cfg) {
const aom_codec_err_t res = validate_config(ctx, &ctx->cfg, extra_cfg);
if (res == AOM_CODEC_OK) {
ctx->extra_cfg = *extra_cfg;
- set_encoder_config(&ctx->oxcf, &ctx->cfg, &ctx->extra_cfg);
- av1_check_fpmt_config(ctx->ppi, &ctx->oxcf);
- bool is_sb_size_changed = false;
- av1_change_config_seq(ctx->ppi, &ctx->oxcf, &is_sb_size_changed);
- for (int i = 0; i < ctx->ppi->num_fp_contexts; i++) {
- AV1_COMP *const cpi = ctx->ppi->parallel_cpi[i];
- struct aom_internal_error_info *const error = cpi->common.error;
- if (setjmp(error->jmp)) {
- error->setjmp = 0;
- return error->error_code;
- }
- error->setjmp = 1;
- av1_change_config(cpi, &ctx->oxcf, is_sb_size_changed);
- error->setjmp = 0;
- }
- if (ctx->ppi->cpi_lap != NULL) {
- AV1_COMP *const cpi_lap = ctx->ppi->cpi_lap;
- struct aom_internal_error_info *const error = cpi_lap->common.error;
- if (setjmp(error->jmp)) {
- error->setjmp = 0;
- return error->error_code;
- }
- error->setjmp = 1;
- av1_change_config(cpi_lap, &ctx->oxcf, is_sb_size_changed);
- error->setjmp = 0;
- }
+ return update_encoder_cfg(ctx);
}
return res;
}
@@ -3573,11 +3578,23 @@ static aom_codec_err_t ctrl_set_scale_mode(aom_codec_alg_priv_t *ctx,
aom_scaling_mode_t *const mode = va_arg(args, aom_scaling_mode_t *);
if (mode) {
- const int res = av1_set_internal_size(
- &ctx->ppi->cpi->oxcf, &ctx->ppi->cpi->resize_pending_params,
- mode->h_scaling_mode, mode->v_scaling_mode);
- av1_check_fpmt_config(ctx->ppi, &ctx->ppi->cpi->oxcf);
- return (res == 0) ? AOM_CODEC_OK : AOM_CODEC_INVALID_PARAM;
+ AV1EncoderConfig *const oxcf =
+ ctx->ppi->seq_params_locked ? &ctx->ppi->cpi->oxcf : &ctx->oxcf;
+ const int res =
+ av1_set_internal_size(oxcf, &ctx->ppi->cpi->resize_pending_params,
+ mode->h_scaling_mode, mode->v_scaling_mode);
+ if (res == 0) {
+ // update_encoder_cfg() is somewhat costly and this control may be called
+ // multiple times, so update_encoder_cfg() is only called to ensure frame
+ // and superblock sizes are updated before they're fixed by the first
+ // encode call.
+ if (ctx->ppi->seq_params_locked) {
+ av1_check_fpmt_config(ctx->ppi, &ctx->ppi->cpi->oxcf);
+ return AOM_CODEC_OK;
+ }
+ return update_encoder_cfg(ctx);
+ }
+ return AOM_CODEC_INVALID_PARAM;
} else {
return AOM_CODEC_INVALID_PARAM;
}
@@ -3598,6 +3615,13 @@ static aom_codec_err_t ctrl_set_number_spatial_layers(aom_codec_alg_priv_t *ctx,
if (number_spatial_layers > MAX_NUM_SPATIAL_LAYERS)
return AOM_CODEC_INVALID_PARAM;
ctx->ppi->number_spatial_layers = number_spatial_layers;
+ // update_encoder_cfg() is somewhat costly and this control may be called
+ // multiple times, so update_encoder_cfg() is only called to ensure frame and
+ // superblock sizes are updated before they're fixed by the first encode
+ // call.
+ if (!ctx->ppi->seq_params_locked) {
+ return update_encoder_cfg(ctx);
+ }
return AOM_CODEC_OK;
}
@@ -3615,8 +3639,6 @@ static aom_codec_err_t ctrl_set_svc_params(aom_codec_alg_priv_t *ctx,
va_list args) {
AV1_PRIMARY *const ppi = ctx->ppi;
AV1_COMP *const cpi = ppi->cpi;
- AV1_COMMON *const cm = &cpi->common;
- AV1EncoderConfig *oxcf = &cpi->oxcf;
aom_svc_params_t *const params = va_arg(args, aom_svc_params_t *);
int64_t target_bandwidth = 0;
ppi->number_spatial_layers = params->number_spatial_layers;
@@ -3656,19 +3678,38 @@ static aom_codec_err_t ctrl_set_svc_params(aom_codec_alg_priv_t *ctx,
target_bandwidth += lc->layer_target_bitrate;
}
}
- if (cm->current_frame.frame_number == 0) {
- if (!cpi->ppi->seq_params_locked) {
- SequenceHeader *const seq_params = &ppi->seq_params;
- seq_params->operating_points_cnt_minus_1 =
- ppi->number_spatial_layers * ppi->number_temporal_layers - 1;
- av1_init_seq_coding_tools(ppi, &cpi->oxcf, 1);
- }
+
+ if (ppi->seq_params_locked) {
+ AV1EncoderConfig *const oxcf = &cpi->oxcf;
+ // Keep ctx->oxcf in sync in case further codec controls are made prior
+ // to encoding.
+ ctx->oxcf.rc_cfg.target_bandwidth = oxcf->rc_cfg.target_bandwidth =
+ target_bandwidth;
+ set_primary_rc_buffer_sizes(oxcf, ppi);
+ av1_update_layer_context_change_config(cpi, target_bandwidth);
+ check_reset_rc_flag(cpi);
+ } else {
+ // Note av1_init_layer_context() relies on cpi->oxcf. The order of that
+ // call and the ones in the other half of this block (which
+ // update_encoder_cfg() transitively makes) is important. So we keep
+ // ctx->oxcf and cpi->oxcf in sync here as update_encoder_cfg() will
+ // overwrite cpi->oxcf with ctx->oxcf.
+ ctx->oxcf.rc_cfg.target_bandwidth = cpi->oxcf.rc_cfg.target_bandwidth =
+ target_bandwidth;
+ SequenceHeader *const seq_params = &ppi->seq_params;
+ seq_params->operating_points_cnt_minus_1 =
+ ppi->number_spatial_layers * ppi->number_temporal_layers - 1;
+
av1_init_layer_context(cpi);
+ // update_encoder_cfg() is somewhat costly and this control may be called
+ // multiple times, so update_encoder_cfg() is only called to ensure frame
+ // and superblock sizes are updated before they're fixed by the first
+ // encode call.
+ return update_encoder_cfg(ctx);
}
- oxcf->rc_cfg.target_bandwidth = target_bandwidth;
- set_primary_rc_buffer_sizes(oxcf, cpi->ppi);
- av1_update_layer_context_change_config(cpi, target_bandwidth);
- check_reset_rc_flag(cpi);
+ } else if (!ppi->seq_params_locked) {
+ // Ensure frame and superblock sizes are updated.
+ return update_encoder_cfg(ctx);
}
av1_check_fpmt_config(ctx->ppi, &ctx->ppi->cpi->oxcf);
return AOM_CODEC_OK;

View File

@@ -50,5 +50,9 @@ src_update_default_v8_platform_to_override_functions_with_location.patch
fix_capture_embedder_exceptions_before_entering_v8.patch
spec_add_iterator_to_global_intrinsics.patch
fix_undici_incorrectly_copies_headers_onto_fetches.patch
src_preload_function_for_environment.patch
fix_revert_src_lb_reducing_c_calls_of_esm_legacy_main_resolve.patch
src_preload_function_for_environment.patch
fs_fix_wtf-8_decoding_issue.patch
stream_do_not_defer_construction_by_one_microtick.patch
deps_disable_io_uring_support_in_libuv_by_default.patch
src_deps_disable_setuid_etc_if_io_uring_enabled.patch

View File

@@ -0,0 +1,70 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tobias=20Nie=C3=9Fen?= <tniessen@tnie.de>
Date: Tue, 19 Sep 2023 16:01:49 +0000
Subject: deps: disable io_uring support in libuv by default
setuid() does not affect libuv's internal io_uring operations if
initialized before the call to setuid(). This potentially allows the
process to perform privileged operations despite presumably having
dropped such privileges through a call to setuid(). Similar concerns
apply to other functions that modify the process's user identity.
This commit changes libuv's io_uring behavior from opt-out (through
UV_USE_IO_URING=0) to opt-in (through UV_USE_IO_URING=1) until we figure
out a better long-term solution.
PR-URL: https://github.com/nodejs-private/node-private/pull/529
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
CVE-ID: CVE-2024-22017
diff --git a/deps/uv/src/unix/linux.c b/deps/uv/src/unix/linux.c
index 48b9c2c43e104079d3ccb5d830d1d79f891fb1a3..656206c6ca8e808a840e006d776eeb64b4b14923 100644
--- a/deps/uv/src/unix/linux.c
+++ b/deps/uv/src/unix/linux.c
@@ -431,8 +431,9 @@ static int uv__use_io_uring(void) {
use = atomic_load_explicit(&use_io_uring, memory_order_relaxed);
if (use == 0) {
+ /* Disable io_uring by default due to CVE-2024-22017. */
val = getenv("UV_USE_IO_URING");
- use = val == NULL || atoi(val) ? 1 : -1;
+ use = val != NULL && atoi(val) ? 1 : -1;
atomic_store_explicit(&use_io_uring, use, memory_order_relaxed);
}
diff --git a/doc/api/cli.md b/doc/api/cli.md
index f50b22f729c28386823d64ef8c9d5fc36c0bf9b1..053c0f94aef5b1681d1ab0513bcc76063ab3a2a6 100644
--- a/doc/api/cli.md
+++ b/doc/api/cli.md
@@ -2596,6 +2596,22 @@ threadpool by setting the `'UV_THREADPOOL_SIZE'` environment variable to a value
greater than `4` (its current default value). For more information, see the
[libuv threadpool documentation][].
+### `UV_USE_IO_URING=value`
+
+Enable or disable libuv's use of `io_uring` on supported platforms.
+
+On supported platforms, `io_uring` can significantly improve the performance of
+various asynchronous I/O operations.
+
+`io_uring` is disabled by default due to security concerns. When `io_uring`
+is enabled, applications must not change the user identity of the process at
+runtime, neither through JavaScript functions such as [`process.setuid()`][] nor
+through native addons that can invoke system functions such as [`setuid(2)`][].
+
+This environment variable is implemented by a dependency of Node.js and may be
+removed in future versions of Node.js. No stability guarantees are provided for
+the behavior of this environment variable.
+
## Useful V8 options
V8 has its own set of CLI options. Any V8 CLI option that is provided to `node`
@@ -2693,6 +2709,8 @@ done
[`dnsPromises.lookup()`]: dns.md#dnspromiseslookuphostname-options
[`import` specifier]: esm.md#import-specifiers
[`process.setUncaughtExceptionCaptureCallback()`]: process.md#processsetuncaughtexceptioncapturecallbackfn
+[`process.setuid()`]: process.md#processsetuidid
+[`setuid(2)`]: https://man7.org/linux/man-pages/man2/setuid.2.html
[`tls.DEFAULT_MAX_VERSION`]: tls.md#tlsdefault_max_version
[`tls.DEFAULT_MIN_VERSION`]: tls.md#tlsdefault_min_version
[`unhandledRejection`]: process.md#event-unhandledrejection

View File

@@ -0,0 +1,30 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Richard Lau <rlau@redhat.com>
Date: Fri, 1 Mar 2024 19:15:40 +0000
Subject: fs: fix WTF-8 decoding issue
Cherry-pick of libuv/libuv@d09441c
Refs: https://github.com/libuv/libuv/pull/2970
Fixes: https://github.com/nodejs/node/issues/48673
We forgot to mask off the high bits from the first byte, so we ended up
always failing the subsequent range check.
diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c
index fc209c54f470edaa031009979061cff071cbf66d..4fc13b04bdae5bd9e2627027a10c534c2d9675dc 100644
--- a/deps/uv/src/win/fs.c
+++ b/deps/uv/src/win/fs.c
@@ -176,9 +176,11 @@ static int32_t fs__decode_wtf8_char(const char** input) {
if ((b4 & 0xC0) != 0x80)
return -1; /* invalid: not a continuation byte */
code_point = (code_point << 6) | (b4 & 0x3F);
- if (b1 <= 0xF4)
+ if (b1 <= 0xF4) {
+ code_point &= 0x1FFFFF;
if (code_point <= 0x10FFFF)
return code_point; /* four-byte character */
+ }
/* code point too large */
return -1;

View File

@@ -0,0 +1,217 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tobias=20Nie=C3=9Fen?= <tniessen@tnie.de>
Date: Mon, 9 Oct 2023 08:10:00 +0000
Subject: src,deps: disable setuid() etc if io_uring enabled
Within Node.js, attempt to determine if libuv is using io_uring. If it
is, disable process.setuid() and other user identity setters.
We cannot fully prevent users from changing the process's user identity,
but this should still prevent some accidental, dangerous scenarios.
PR-URL: https://github.com/nodejs-private/node-private/pull/529
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
CVE-ID: CVE-2024-22017
diff --git a/deps/uv/src/unix/linux.c b/deps/uv/src/unix/linux.c
index 656206c6ca8e808a840e006d776eeb64b4b14923..0c99718510fe1ca449ec685f323171475ab16552 100644
--- a/deps/uv/src/unix/linux.c
+++ b/deps/uv/src/unix/linux.c
@@ -442,6 +442,14 @@ static int uv__use_io_uring(void) {
}
+UV_EXTERN int uv__node_patch_is_using_io_uring(void) {
+ // This function exists only in the modified copy of libuv in the Node.js
+ // repository. Node.js checks if this function exists and, if it does, uses it
+ // to determine whether libuv is using io_uring or not.
+ return uv__use_io_uring();
+}
+
+
static void uv__iou_init(int epollfd,
struct uv__iou* iou,
uint32_t entries,
diff --git a/doc/api/cli.md b/doc/api/cli.md
index 053c0f94aef5b1681d1ab0513bcc76063ab3a2a6..9b32639532bf6377aade96b86faccf050a396e63 100644
--- a/doc/api/cli.md
+++ b/doc/api/cli.md
@@ -2605,8 +2605,9 @@ various asynchronous I/O operations.
`io_uring` is disabled by default due to security concerns. When `io_uring`
is enabled, applications must not change the user identity of the process at
-runtime, neither through JavaScript functions such as [`process.setuid()`][] nor
-through native addons that can invoke system functions such as [`setuid(2)`][].
+runtime. In this case, JavaScript functions such as [`process.setuid()`][] are
+unavailable, and native addons must not invoke system functions such as
+[`setuid(2)`][].
This environment variable is implemented by a dependency of Node.js and may be
removed in future versions of Node.js. No stability guarantees are provided for
diff --git a/src/node_credentials.cc b/src/node_credentials.cc
index c1f7a4f2acbdf66a45230e2b9fdd860d9d3b4458..3b5eec8244024f58713c668c9dcd84617a18db88 100644
--- a/src/node_credentials.cc
+++ b/src/node_credentials.cc
@@ -1,4 +1,5 @@
#include "env-inl.h"
+#include "node_errors.h"
#include "node_external_reference.h"
#include "node_internals.h"
#include "util-inl.h"
@@ -12,6 +13,7 @@
#include <unistd.h> // setuid, getuid
#endif
#ifdef __linux__
+#include <dlfcn.h> // dlsym()
#include <linux/capability.h>
#include <sys/auxv.h>
#include <sys/syscall.h>
@@ -232,6 +234,45 @@ static gid_t gid_by_name(Isolate* isolate, Local<Value> value) {
}
}
+#ifdef __linux__
+extern "C" {
+int uv__node_patch_is_using_io_uring(void);
+
+int uv__node_patch_is_using_io_uring(void) __attribute__((weak));
+
+typedef int (*is_using_io_uring_fn)(void);
+}
+#endif // __linux__
+
+static bool UvMightBeUsingIoUring() {
+#ifdef __linux__
+ // Support for io_uring is only included in libuv 1.45.0 and later, and only
+ // on Linux (and Android, but there it is always disabled). The patch that we
+ // apply to libuv to work around the io_uring security issue adds a function
+ // that tells us whether io_uring is being used. If that function is not
+ // present, we assume that we are dynamically linking against an unpatched
+ // version.
+ static std::atomic<is_using_io_uring_fn> check =
+ uv__node_patch_is_using_io_uring;
+ if (check == nullptr) {
+ check = reinterpret_cast<is_using_io_uring_fn>(
+ dlsym(RTLD_DEFAULT, "uv__node_patch_is_using_io_uring"));
+ }
+ return uv_version() >= 0x012d00u && (check == nullptr || (*check)());
+#else
+ return false;
+#endif
+}
+
+static bool ThrowIfUvMightBeUsingIoUring(Environment* env, const char* fn) {
+ if (UvMightBeUsingIoUring()) {
+ node::THROW_ERR_INVALID_STATE(
+ env, "%s() disabled: io_uring may be enabled. See CVE-2024-22017.", fn);
+ return true;
+ }
+ return false;
+}
+
static void GetUid(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK(env->has_run_bootstrapping_code());
@@ -267,6 +308,8 @@ static void SetGid(const FunctionCallbackInfo<Value>& args) {
CHECK_EQ(args.Length(), 1);
CHECK(args[0]->IsUint32() || args[0]->IsString());
+ if (ThrowIfUvMightBeUsingIoUring(env, "setgid")) return;
+
gid_t gid = gid_by_name(env->isolate(), args[0]);
if (gid == gid_not_found) {
@@ -286,6 +329,8 @@ static void SetEGid(const FunctionCallbackInfo<Value>& args) {
CHECK_EQ(args.Length(), 1);
CHECK(args[0]->IsUint32() || args[0]->IsString());
+ if (ThrowIfUvMightBeUsingIoUring(env, "setegid")) return;
+
gid_t gid = gid_by_name(env->isolate(), args[0]);
if (gid == gid_not_found) {
@@ -305,6 +350,8 @@ static void SetUid(const FunctionCallbackInfo<Value>& args) {
CHECK_EQ(args.Length(), 1);
CHECK(args[0]->IsUint32() || args[0]->IsString());
+ if (ThrowIfUvMightBeUsingIoUring(env, "setuid")) return;
+
uid_t uid = uid_by_name(env->isolate(), args[0]);
if (uid == uid_not_found) {
@@ -324,6 +371,8 @@ static void SetEUid(const FunctionCallbackInfo<Value>& args) {
CHECK_EQ(args.Length(), 1);
CHECK(args[0]->IsUint32() || args[0]->IsString());
+ if (ThrowIfUvMightBeUsingIoUring(env, "seteuid")) return;
+
uid_t uid = uid_by_name(env->isolate(), args[0]);
if (uid == uid_not_found) {
@@ -364,6 +413,8 @@ static void SetGroups(const FunctionCallbackInfo<Value>& args) {
CHECK_EQ(args.Length(), 1);
CHECK(args[0]->IsArray());
+ if (ThrowIfUvMightBeUsingIoUring(env, "setgroups")) return;
+
Local<Array> groups_list = args[0].As<Array>();
size_t size = groups_list->Length();
MaybeStackBuffer<gid_t, 64> groups(size);
@@ -395,6 +446,8 @@ static void InitGroups(const FunctionCallbackInfo<Value>& args) {
CHECK(args[0]->IsUint32() || args[0]->IsString());
CHECK(args[1]->IsUint32() || args[1]->IsString());
+ if (ThrowIfUvMightBeUsingIoUring(env, "initgroups")) return;
+
Utf8Value arg0(env->isolate(), args[0]);
gid_t extra_group;
bool must_free;
diff --git a/test/parallel/test-process-setuid-io-uring.js b/test/parallel/test-process-setuid-io-uring.js
new file mode 100644
index 0000000000000000000000000000000000000000..93193ac2f8ab99f0cf8f2de368bc27958c92be76
--- /dev/null
+++ b/test/parallel/test-process-setuid-io-uring.js
@@ -0,0 +1,43 @@
+'use strict';
+const common = require('../common');
+
+const assert = require('node:assert');
+const { execFileSync } = require('node:child_process');
+
+if (!common.isLinux) {
+ common.skip('test is Linux specific');
+}
+
+if (process.arch !== 'x64' && process.arch !== 'arm64') {
+ common.skip('io_uring support on this architecture is uncertain');
+}
+
+const kv = /^(\d+)\.(\d+)\.(\d+)/.exec(execFileSync('uname', ['-r'])).slice(1).map((n) => parseInt(n, 10));
+if (((kv[0] << 16) | (kv[1] << 8) | kv[2]) < 0x050ABA) {
+ common.skip('io_uring is likely buggy due to old kernel');
+}
+
+const userIdentitySetters = [
+ ['setuid', [1000]],
+ ['seteuid', [1000]],
+ ['setgid', [1000]],
+ ['setegid', [1000]],
+ ['setgroups', [[1000]]],
+ ['initgroups', ['nodeuser', 1000]],
+];
+
+for (const [fnName, args] of userIdentitySetters) {
+ const call = `process.${fnName}(${args.map((a) => JSON.stringify(a)).join(', ')})`;
+ const code = `try { ${call}; } catch (err) { console.log(err); }`;
+
+ const stdout = execFileSync(process.execPath, ['-e', code], {
+ encoding: 'utf8',
+ env: { ...process.env, UV_USE_IO_URING: '1' },
+ });
+
+ const msg = new RegExp(`^Error: ${fnName}\\(\\) disabled: io_uring may be enabled\\. See CVE-[X0-9]{4}-`);
+ assert.match(stdout, msg);
+ assert.match(stdout, /code: 'ERR_INVALID_STATE'/);
+
+ console.log(call, stdout.slice(0, stdout.indexOf('\n')));
+}

View File

@@ -1,23 +1,9 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Cheng Zhao <zcbenz@gmail.com>
Date: Mon, 22 Jan 2024 13:45:55 +0900
Date: Mon, 4 Mar 2024 11:41:18 +0900
Subject: src: preload function for Environment
https://github.com/nodejs/node/pull/51539
This PR adds a |preload| arg to the node::CreateEnvironment to allow
embedders to set a preload function for the environment, which will run
after the environment is loaded and before the main script runs.
This is similiar to the --require CLI option, but runs a C++ function,
and can only be set by embedders.
The preload function can be used by embedders to inject scripts before
running the main script, for example:
1. In Electron it is used to initialize the ASAR virtual filesystem,
inject custom process properties, etc.
2. In VS Code it can be used to reset the module search paths for
extensions.
Backport https://github.com/nodejs/node/pull/51539
diff --git a/lib/internal/process/pre_execution.js b/lib/internal/process/pre_execution.js
index cbb89d76621de6a85b8e8697078d74c6bde0a742..4b1c0405a3bc7fb66d138b273cab05589b1a7360 100644
@@ -45,92 +31,80 @@ index cbb89d76621de6a85b8e8697078d74c6bde0a742..4b1c0405a3bc7fb66d138b273cab0558
// For user code, we preload modules if `-r` is passed
const preloadModules = getOptionValue('--require');
diff --git a/src/api/environment.cc b/src/api/environment.cc
index 74b4e15b8230c6380d41e84aa504824bb79b2ee5..e033760193fcd4fedd645c9259f58bc6b06250f4 100644
index 74b4e15b8230c6380d41e84aa504824bb79b2ee5..5ef231ba77b187ff4df3b3d2f3f4eec2b7667c92 100644
--- a/src/api/environment.cc
+++ b/src/api/environment.cc
@@ -437,7 +437,8 @@ Environment* CreateEnvironment(
const std::vector<std::string>& exec_args,
EnvironmentFlags::Flags flags,
ThreadId thread_id,
- std::unique_ptr<InspectorParentHandle> inspector_parent_handle) {
+ std::unique_ptr<InspectorParentHandle> inspector_parent_handle,
+ EmbedderPreloadCallback preload) {
Isolate* isolate = isolate_data->isolate();
HandleScope handle_scope(isolate);
@@ -549,25 +549,31 @@ NODE_EXTERN std::unique_ptr<InspectorParentHandle> GetInspectorParentHandle(
#endif
}
@@ -456,7 +457,8 @@ Environment* CreateEnvironment(
exec_args,
env_snapshot_info,
flags,
- thread_id);
+ thread_id,
+ std::move(preload));
CHECK_NOT_NULL(env);
-MaybeLocal<Value> LoadEnvironment(
- Environment* env,
- StartExecutionCallback cb) {
+MaybeLocal<Value> LoadEnvironment(Environment* env,
+ StartExecutionCallback cb,
+ EmbedderPreloadCallback preload) {
env->InitializeLibuv();
env->InitializeDiagnostics();
+ if (preload) {
+ env->set_embedder_preload(std::move(preload));
+ }
if (use_snapshot) {
return StartExecution(env, cb);
}
MaybeLocal<Value> LoadEnvironment(Environment* env,
- std::string_view main_script_source_utf8) {
+ std::string_view main_script_source_utf8,
+ EmbedderPreloadCallback preload) {
CHECK_NOT_NULL(main_script_source_utf8.data());
return LoadEnvironment(
- env, [&](const StartExecutionCallbackInfo& info) -> MaybeLocal<Value> {
+ env,
+ [&](const StartExecutionCallbackInfo& info) -> MaybeLocal<Value> {
Local<Value> main_script =
ToV8Value(env->context(), main_script_source_utf8).ToLocalChecked();
return info.run_cjs->Call(
env->context(), Null(env->isolate()), 1, &main_script);
- });
+ },
+ std::move(preload));
}
Environment* GetCurrentEnvironment(Local<Context> context) {
diff --git a/src/env-inl.h b/src/env-inl.h
index 524a9633ef16e48797dc6a1e507ca0be2bfffe7e..b5ec98128d4e08ef26121be070ac2ebe5e339534 100644
index 524a9633ef16e48797dc6a1e507ca0be2bfffe7e..9f30ebb821dfcbfe4c7c55332a28d076b09b9177 100644
--- a/src/env-inl.h
+++ b/src/env-inl.h
@@ -438,6 +438,10 @@ inline void Environment::set_embedder_entry_point(StartExecutionCallback&& fn) {
@@ -438,6 +438,14 @@ inline void Environment::set_embedder_entry_point(StartExecutionCallback&& fn) {
embedder_entry_point_ = std::move(fn);
}
+inline const EmbedderPreloadCallback& Environment::embedder_preload() const {
+ return embedder_preload_;
+}
+
+inline void Environment::set_embedder_preload(EmbedderPreloadCallback fn) {
+ embedder_preload_ = std::move(fn);
+}
+
inline double Environment::new_async_id() {
async_hooks()->async_id_fields()[AsyncHooks::kAsyncIdCounter] += 1;
return async_hooks()->async_id_fields()[AsyncHooks::kAsyncIdCounter];
diff --git a/src/env.cc b/src/env.cc
index 25b81dee18aeeb1bd0452ba0b66085d451723709..1b4e783ca1f4ac6e09ce9fc1caad30de85e3be91 100644
--- a/src/env.cc
+++ b/src/env.cc
@@ -763,7 +763,8 @@ Environment::Environment(IsolateData* isolate_data,
const std::vector<std::string>& exec_args,
const EnvSerializeInfo* env_info,
EnvironmentFlags::Flags flags,
- ThreadId thread_id)
+ ThreadId thread_id,
+ EmbedderPreloadCallback preload)
: isolate_(isolate),
isolate_data_(isolate_data),
async_hooks_(isolate, MAYBE_FIELD_PTR(env_info, async_hooks)),
@@ -789,7 +790,8 @@ Environment::Environment(IsolateData* isolate_data,
flags_(flags),
thread_id_(thread_id.id == static_cast<uint64_t>(-1)
? AllocateEnvironmentThreadId().id
- : thread_id.id) {
+ : thread_id.id),
+ embedder_preload_(std::move(preload)) {
constexpr bool is_shared_ro_heap =
#ifdef NODE_V8_SHARED_RO_HEAP
true;
diff --git a/src/env.h b/src/env.h
index 448075e354c760a2dbd1dd763f40b7a645730250..a5aad9596953536b0a1f741dfbc4f21f6a961404 100644
index 448075e354c760a2dbd1dd763f40b7a645730250..d6956873b1b7bdf49ed0217587729aaa974ae89f 100644
--- a/src/env.h
+++ b/src/env.h
@@ -635,7 +635,8 @@ class Environment : public MemoryRetainer {
const std::vector<std::string>& exec_args,
const EnvSerializeInfo* env_info,
EnvironmentFlags::Flags flags,
- ThreadId thread_id);
+ ThreadId thread_id,
+ EmbedderPreloadCallback preload);
void InitializeMainContext(v8::Local<v8::Context> context,
const EnvSerializeInfo* env_info);
~Environment() override;
@@ -986,6 +987,8 @@ class Environment : public MemoryRetainer {
@@ -985,6 +985,8 @@ class Environment : public MemoryRetainer {
inline const StartExecutionCallback& embedder_entry_point() const;
inline void set_embedder_entry_point(StartExecutionCallback&& fn);
+ inline const EmbedderPreloadCallback& embedder_preload() const;
+
+ inline void set_embedder_preload(EmbedderPreloadCallback fn);
inline void set_process_exit_handler(
std::function<void(Environment*, ExitCode)>&& handler);
@@ -1186,6 +1189,7 @@ class Environment : public MemoryRetainer {
@@ -1186,6 +1188,7 @@ class Environment : public MemoryRetainer {
builtins::BuiltinLoader builtin_loader_;
StartExecutionCallback embedder_entry_point_;
@@ -139,43 +113,45 @@ index 448075e354c760a2dbd1dd763f40b7a645730250..a5aad9596953536b0a1f741dfbc4f21f
// Used by allocate_managed_buffer() and release_managed_buffer() to keep
// track of the BackingStore for a given pointer.
diff --git a/src/node.h b/src/node.h
index 3ffc51783b0b6dee1c0f0a37d2f52cb1aec2fa3f..4d88bbedb2fc2776d32cbaa755fd8657f17f78bc 100644
index 3ffc51783b0b6dee1c0f0a37d2f52cb1aec2fa3f..400a6b91ccb9875352012bffc21bc842f6febb9c 100644
--- a/src/node.h
+++ b/src/node.h
@@ -676,11 +676,23 @@ struct InspectorParentHandle {
virtual ~InspectorParentHandle() = default;
};
@@ -716,12 +716,33 @@ struct StartExecutionCallbackInfo {
using StartExecutionCallback =
std::function<v8::MaybeLocal<v8::Value>(const StartExecutionCallbackInfo&)>;
+using EmbedderPreloadCallback =
+ std::function<void(Environment* env,
+ v8::Local<v8::Value> process,
+ v8::Local<v8::Value> require)>;
+
// TODO(addaleax): Maybe move per-Environment options parsing here.
// Returns nullptr when the Environment cannot be created e.g. there are
// pending JavaScript exceptions.
// `context` may be empty if an `EmbedderSnapshotData` instance was provided
// to `NewIsolate()` and `CreateIsolateData()`.
+//
+// The |preload| function will run before executing the entry point, which
+// is usually used by embedders to inject scripts. The function is executed
+// with preload(process, require), and the passed require function has access
+// to internal Node.js modules. The |preload| function is inherited by worker
+// threads and thus will run in work threads, so make sure the function is
+// thread-safe.
NODE_EXTERN Environment* CreateEnvironment(
IsolateData* isolate_data,
v8::Local<v8::Context> context,
@@ -688,7 +700,8 @@ NODE_EXTERN Environment* CreateEnvironment(
const std::vector<std::string>& exec_args,
EnvironmentFlags::Flags flags = EnvironmentFlags::kDefaultFlags,
ThreadId thread_id = {} /* allocates a thread id automatically */,
- std::unique_ptr<InspectorParentHandle> inspector_parent_handle = {});
+ std::unique_ptr<InspectorParentHandle> inspector_parent_handle = {},
+ EmbedderPreloadCallback preload = nullptr);
// Returns a handle that can be passed to `LoadEnvironment()`, making the
// child Environment accessible to the inspector as if it were a Node.js Worker.
+// Run initialization for the environment.
+//
+// The |preload| function, usually used by embedders to inject scripts,
+// will be run by Node.js before Node.js executes the entry point.
+// The function is guaranteed to run before the user land module loader running
+// any user code, so it is safe to assume that at this point, no user code has
+// been run yet.
+// The function will be executed with preload(process, require), and the passed
+// require function has access to internal Node.js modules. There is no
+// stability guarantee about the internals exposed to the internal require
+// function. Expect breakages when updating Node.js versions if the embedder
+// imports internal modules with the internal require function.
+// Worker threads created in the environment will also respect The |preload|
+// function, so make sure the function is thread-safe.
NODE_EXTERN v8::MaybeLocal<v8::Value> LoadEnvironment(
Environment* env,
- StartExecutionCallback cb);
+ StartExecutionCallback cb,
+ EmbedderPreloadCallback preload = nullptr);
NODE_EXTERN v8::MaybeLocal<v8::Value> LoadEnvironment(
- Environment* env, std::string_view main_script_source_utf8);
+ Environment* env,
+ std::string_view main_script_source_utf8,
+ EmbedderPreloadCallback preload = nullptr);
NODE_EXTERN void FreeEnvironment(Environment* env);
// Set a callback that is called when process.exit() is called from JS,
diff --git a/src/node_options.cc b/src/node_options.cc
index 6eb2c137e1dd05b05e781820905cf6778107275d..b098837338c2c0d435ee8e659433f168c453dde5 100644
--- a/src/node_options.cc
@@ -194,24 +170,28 @@ index 6eb2c137e1dd05b05e781820905cf6778107275d..b098837338c2c0d435ee8e659433f168
}
diff --git a/src/node_snapshotable.cc b/src/node_snapshotable.cc
index 562a47ddcc9c8e61590b7b09d84dc08ab4b3653d..325bebc1df9ad2e8b0bad468951cf1563ecefc14 100644
index 562a47ddcc9c8e61590b7b09d84dc08ab4b3653d..431cbe1c2cb77669ceb10602a7b3ef1c2f7e8718 100644
--- a/src/node_snapshotable.cc
+++ b/src/node_snapshotable.cc
@@ -1369,6 +1369,13 @@ static void RunEmbedderEntryPoint(const FunctionCallbackInfo<Value>& args) {
@@ -1369,6 +1369,17 @@ static void RunEmbedderEntryPoint(const FunctionCallbackInfo<Value>& args) {
}
}
+static void RunEmbedderPreload(const FunctionCallbackInfo<Value>& args) {
+void RunEmbedderPreload(const FunctionCallbackInfo<Value>& args) {
+ Environment* env = Environment::GetCurrent(args);
+ CHECK(env->embedder_preload());
+ CHECK_EQ(args.Length(), 2);
+ env->embedder_preload()(env, args[0], args[1]);
+ Local<Value> process_obj = args[0];
+ Local<Value> require_fn = args[1];
+ CHECK(process_obj->IsObject());
+ CHECK(require_fn->IsFunction());
+ env->embedder_preload()(env, process_obj, require_fn);
+}
+
void CompileSerializeMain(const FunctionCallbackInfo<Value>& args) {
CHECK(args[0]->IsString());
Local<String> filename = args[0].As<String>();
@@ -1493,6 +1500,7 @@ void CreatePerIsolateProperties(IsolateData* isolate_data,
@@ -1493,6 +1504,7 @@ void CreatePerIsolateProperties(IsolateData* isolate_data,
Local<ObjectTemplate> target) {
Isolate* isolate = isolate_data->isolate();
SetMethod(isolate, target, "runEmbedderEntryPoint", RunEmbedderEntryPoint);
@@ -219,7 +199,7 @@ index 562a47ddcc9c8e61590b7b09d84dc08ab4b3653d..325bebc1df9ad2e8b0bad468951cf156
SetMethod(isolate, target, "compileSerializeMain", CompileSerializeMain);
SetMethod(isolate, target, "setSerializeCallback", SetSerializeCallback);
SetMethod(isolate, target, "setDeserializeCallback", SetDeserializeCallback);
@@ -1506,6 +1514,7 @@ void CreatePerIsolateProperties(IsolateData* isolate_data,
@@ -1506,6 +1518,7 @@ void CreatePerIsolateProperties(IsolateData* isolate_data,
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
registry->Register(RunEmbedderEntryPoint);
@@ -228,7 +208,7 @@ index 562a47ddcc9c8e61590b7b09d84dc08ab4b3653d..325bebc1df9ad2e8b0bad468951cf156
registry->Register(SetSerializeCallback);
registry->Register(SetDeserializeCallback);
diff --git a/src/node_worker.cc b/src/node_worker.cc
index 900674bbe4c90e9aeb2013c06c9979864b06dcd5..2a22d986585e93ea00c6dcdca1f7b783ef0723f8 100644
index 900674bbe4c90e9aeb2013c06c9979864b06dcd5..52d7473b05ccb49e5fc915224b6d2972a14191da 100644
--- a/src/node_worker.cc
+++ b/src/node_worker.cc
@@ -63,6 +63,7 @@ Worker::Worker(Environment* env,
@@ -239,16 +219,20 @@ index 900674bbe4c90e9aeb2013c06c9979864b06dcd5..2a22d986585e93ea00c6dcdca1f7b783
snapshot_data_(snapshot_data) {
Debug(this, "Creating new worker instance with thread id %llu",
thread_id_.id);
@@ -360,7 +361,8 @@ void Worker::Run() {
std::move(exec_argv_),
static_cast<EnvironmentFlags::Flags>(environment_flags_),
thread_id_,
- std::move(inspector_parent_handle_)));
+ std::move(inspector_parent_handle_),
+ std::move(embedder_preload_)));
if (is_stopped()) return;
CHECK_NOT_NULL(env_);
env_->set_env_vars(std::move(env_vars_));
@@ -381,8 +382,12 @@ void Worker::Run() {
}
Debug(this, "Created message port for worker %llu", thread_id_.id);
- if (LoadEnvironment(env_.get(), StartExecutionCallback{}).IsEmpty())
+ if (LoadEnvironment(env_.get(),
+ StartExecutionCallback{},
+ std::move(embedder_preload_))
+ .IsEmpty()) {
return;
+ }
Debug(this, "Loaded environment for worker %llu", thread_id_.id);
}
diff --git a/src/node_worker.h b/src/node_worker.h
index 531e2b5287010f9206ab4fd7f4dd0f3dec9fe55c..07fd7b460654e169e8b6822474dc3cc70fcec4c0 100644
--- a/src/node_worker.h
@@ -262,7 +246,7 @@ index 531e2b5287010f9206ab4fd7f4dd0f3dec9fe55c..07fd7b460654e169e8b6822474dc3cc7
// A raw flag that is used by creator and worker threads to
// sync up on pre-mature termination of worker - while in the
diff --git a/test/cctest/test_environment.cc b/test/cctest/test_environment.cc
index 2e747c7be58922897abd0424b797f3f12a89ada1..658f8df4b01d60759e858cf5283b9be9467dd142 100644
index 2e747c7be58922897abd0424b797f3f12a89ada1..fcffaca89cf5aa24be6e539bfb4d9d6df690a709 100644
--- a/test/cctest/test_environment.cc
+++ b/test/cctest/test_environment.cc
@@ -773,3 +773,31 @@ TEST_F(EnvironmentTest, RequestInterruptAtExit) {
@@ -280,20 +264,20 @@ index 2e747c7be58922897abd0424b797f3f12a89ada1..658f8df4b01d60759e858cf5283b9be9
+ v8::Local<v8::Value> require) {
+ CHECK(process->IsObject());
+ CHECK(require->IsFunction());
+ process.As<v8::Object>()->Set(
+ env->context(),
+ v8::String::NewFromUtf8Literal(env->isolate(), "prop"),
+ v8::String::NewFromUtf8Literal(env->isolate(), "preload")).Check();
+ process.As<v8::Object>()
+ ->Set(env->context(),
+ v8::String::NewFromUtf8Literal(env->isolate(), "prop"),
+ v8::String::NewFromUtf8Literal(env->isolate(), "preload"))
+ .Check();
+ };
+
+ std::unique_ptr<node::Environment, decltype(&node::FreeEnvironment)> env(
+ node::CreateEnvironment(isolate_data_, context, {}, {},
+ node::EnvironmentFlags::kDefaultFlags, {}, {},
+ preload),
+ node::CreateEnvironment(isolate_data_, context, {}, {}),
+ node::FreeEnvironment);
+
+ v8::Local<v8::Value> main_ret =
+ node::LoadEnvironment(env.get(), "return process.prop;").ToLocalChecked();
+ node::LoadEnvironment(env.get(), "return process.prop;", preload)
+ .ToLocalChecked();
+ node::Utf8Value main_ret_str(isolate_, main_ret);
+ EXPECT_EQ(std::string(*main_ret_str), "preload");
+}

View File

@@ -0,0 +1,37 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Matteo Collina <hello@matteocollina.com>
Date: Thu, 7 Mar 2024 17:28:25 +0100
Subject: stream: do not defer construction by one microtick
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Fixes: https://github.com/nodejs/node/issues/51993
PR-URL: https://github.com/nodejs/node/pull/52005
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
diff --git a/lib/internal/streams/destroy.js b/lib/internal/streams/destroy.js
index cfb49f2c7c72730356e530e22cb13adca38f5991..08f1fca0d5de26c80839e30b33e96ff2a59561eb 100644
--- a/lib/internal/streams/destroy.js
+++ b/lib/internal/streams/destroy.js
@@ -267,7 +267,7 @@ function constructNT(stream) {
} else if (err) {
errorOrDestroy(stream, err, true);
} else {
- process.nextTick(emitConstructNT, stream);
+ stream.emit(kConstruct);
}
}
@@ -280,10 +280,6 @@ function constructNT(stream) {
}
}
-function emitConstructNT(stream) {
- stream.emit(kConstruct);
-}
-
function isRequest(stream) {
return stream?.setHeader && typeof stream.abort === 'function';
}

View File

@@ -1,2 +1,11 @@
chore_allow_customizing_microtask_policy_per_context.patch
deps_add_v8_object_setinternalfieldfornodecore.patch
merged_wasm_gc_scan_the_code_field_of_the_wasminternalfunction.patch
cherry-pick-f320600cd1f4.patch
cherry-pick-b3c01ac1e60a.patch
cherry-pick-6503a987d966.patch
cherry-pick-3e037e195e50.patch
cherry-pick-e7b64c6ee185.patch
cherry-pick-f911ff372723.patch
cherry-pick-8b400f9b7d66.patch
cherry-pick-ba6cab40612d.patch

View File

@@ -0,0 +1,41 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shu-yu Guo <syg@chromium.org>
Date: Tue, 21 May 2024 10:06:20 -0700
Subject: Using FunctionParsingScope for parsing class static blocks
Class static blocks contain statements, don't inherit the
ExpressionScope stack.
Bug: 341663589
Change-Id: Id52a60d77781201a706fcf2290d7d103f39bed83
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5553030
Commit-Queue: Shu-yu Guo <syg@chromium.org>
Commit-Queue: Adam Klein <adamk@chromium.org>
Reviewed-by: Adam Klein <adamk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#94014}
diff --git a/src/ast/scopes.cc b/src/ast/scopes.cc
index 6dfcd45cf208e58a2fc0cd18ba3b115bae35a0d5..61b8fbf0cfcaa02a92ead411e4bcbc1f36dfdad3 100644
--- a/src/ast/scopes.cc
+++ b/src/ast/scopes.cc
@@ -2441,7 +2441,7 @@ bool Scope::MustAllocate(Variable* var) {
var->set_is_used();
if (inner_scope_calls_eval_ && !var->is_this()) var->SetMaybeAssigned();
}
- DCHECK(!var->has_forced_context_allocation() || var->is_used());
+ CHECK(!var->has_forced_context_allocation() || var->is_used());
// Global variables do not need to be allocated.
return !var->IsGlobalObjectProperty() && var->is_used();
}
diff --git a/src/parsing/parser-base.h b/src/parsing/parser-base.h
index ac35090ca5d129c58c0e4fb31ee2e2456e202dce..059133f32d30c94e400de96313734b64c5421b09 100644
--- a/src/parsing/parser-base.h
+++ b/src/parsing/parser-base.h
@@ -2619,6 +2619,7 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseClassStaticBlock(
}
FunctionState initializer_state(&function_state_, &scope_, initializer_scope);
+ FunctionParsingScope body_parsing_scope(impl());
AcceptINScope accept_in(this, true);
// Each static block has its own var and lexical scope, so make a new var

View File

@@ -0,0 +1,56 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Victor Gomes <victorgomes@chromium.org>
Date: Thu, 21 Mar 2024 09:59:19 +0100
Subject: Deal with large strings in NoSideEffectsErrorToString
If name is too big, StringBuilder will fail to even add
"<a very large string>" suffix.
In this case, we truncate name first.
Bug: 329699609
Change-Id: I6e4440c07eae84371f44b54f88127e2c70af0db5
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5378286
Commit-Queue: Victor Gomes <victorgomes@chromium.org>
Reviewed-by: Patrick Thier <pthier@chromium.org>
Auto-Submit: Victor Gomes <victorgomes@chromium.org>
Cr-Commit-Position: refs/heads/main@{#92932}
diff --git a/src/objects/objects.cc b/src/objects/objects.cc
index ed640e14dd43b3a1268afd196db8d7a0cb8601da..06e81c96c504e27eb218ca60d67a7bd4b4f4487f 100644
--- a/src/objects/objects.cc
+++ b/src/objects/objects.cc
@@ -469,14 +469,27 @@ Handle<String> NoSideEffectsErrorToString(Isolate* isolate,
if (name_str->length() == 0) return msg_str;
if (msg_str->length() == 0) return name_str;
- IncrementalStringBuilder builder(isolate);
- builder.AppendString(name_str);
- builder.AppendCStringLiteral(": ");
+ constexpr const char error_suffix[] = "<a very large string>";
+ constexpr int error_suffix_size = sizeof(error_suffix);
+ int suffix_size = std::min(error_suffix_size, msg_str->length());
- if (builder.Length() + msg_str->length() <= String::kMaxLength) {
- builder.AppendString(msg_str);
+ IncrementalStringBuilder builder(isolate);
+ if (name_str->length() + suffix_size + 2 /* ": " */ > String::kMaxLength) {
+ constexpr const char connector[] = "... : ";
+ int connector_size = sizeof(connector);
+ Handle<String> truncated_name = isolate->factory()->NewProperSubString(
+ name_str, 0, name_str->length() - error_suffix_size - connector_size);
+ builder.AppendString(truncated_name);
+ builder.AppendCStringLiteral(connector);
+ builder.AppendCStringLiteral(error_suffix);
} else {
- builder.AppendCStringLiteral("<a very large string>");
+ builder.AppendString(name_str);
+ builder.AppendCStringLiteral(": ");
+ if (builder.Length() + msg_str->length() <= String::kMaxLength) {
+ builder.AppendString(msg_str);
+ } else {
+ builder.AppendCStringLiteral(error_suffix);
+ }
}
return builder.Finish().ToHandleChecked();

View File

@@ -0,0 +1,98 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jakob Kummerow <jkummerow@chromium.org>
Date: Thu, 6 Jun 2024 16:44:37 +0200
Subject: Merged: [wasm] Enforce maximum number of canonicalized types
Storing canonical indices in ValueTypes doesn't work well if the
canonical index is too large.
Fixed: 344608204
(cherry picked from commit 422cdc5eddcadb53b8eafb099722fb211a35739e)
Change-Id: Id281d6a38e8f2c64c42352f2d3dd3df54e289525
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5625825
Auto-Submit: Jakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Matthias Liedtke <mliedtke@chromium.org>
Commit-Queue: Matthias Liedtke <mliedtke@chromium.org>
Cr-Commit-Position: refs/branch-heads/12.6@{#30}
Cr-Branched-From: 3c9fa12db3183a6f4ea53d2675adb66ea1194529-refs/heads/12.6.228@{#2}
Cr-Branched-From: 981bb15ba4dbf9e2381dfc94ec2c4af0b9c6a0b6-refs/heads/main@{#93835}
diff --git a/src/wasm/canonical-types.cc b/src/wasm/canonical-types.cc
index ea6e0d6c6a49c281f715a005bcd40e1fb25ee802..a048c8bddb841f4d08234374e8e4e50d0a3f2c3c 100644
--- a/src/wasm/canonical-types.cc
+++ b/src/wasm/canonical-types.cc
@@ -4,6 +4,7 @@
#include "src/wasm/canonical-types.h"
+#include "src/init/v8.h"
#include "src/wasm/std-object-sizes.h"
#include "src/wasm/wasm-engine.h"
@@ -20,6 +21,19 @@ TypeCanonicalizer::TypeCanonicalizer() {
AddPredefinedArrayType(kPredefinedArrayI16Index, kWasmI16);
}
+// We currently store canonical indices in {ValueType} instances, so they
+// must fit into the range of valid module-relative (non-canonical) type
+// indices.
+// TODO(jkummerow): Raise this limit, to make long-lived WasmEngines scale
+// better. Plan: stop constructing ValueTypes from canonical type indices.
+static constexpr size_t kMaxCanonicalTypes = kV8MaxWasmTypes;
+
+void TypeCanonicalizer::CheckMaxCanonicalIndex() const {
+ if (canonical_supertypes_.size() > kMaxCanonicalTypes) {
+ V8::FatalProcessOutOfMemory(nullptr, "too many canonicalized types");
+ }
+}
+
void TypeCanonicalizer::AddRecursiveGroup(WasmModule* module, uint32_t size) {
AddRecursiveGroup(module, size,
static_cast<uint32_t>(module->types.size() - size));
@@ -60,6 +74,7 @@ void TypeCanonicalizer::AddRecursiveGroup(WasmModule* module, uint32_t size,
uint32_t first_canonical_index =
static_cast<uint32_t>(canonical_supertypes_.size());
canonical_supertypes_.resize(first_canonical_index + size);
+ CheckMaxCanonicalIndex();
for (uint32_t i = 0; i < size; i++) {
CanonicalType& canonical_type = group.types[i];
// Compute the canonical index of the supertype: If it is relative, we
@@ -106,6 +121,7 @@ void TypeCanonicalizer::AddRecursiveSingletonGroup(WasmModule* module,
uint32_t first_canonical_index =
static_cast<uint32_t>(canonical_supertypes_.size());
canonical_supertypes_.resize(first_canonical_index + 1);
+ CheckMaxCanonicalIndex();
CanonicalType& canonical_type = group.type;
// Compute the canonical index of the supertype: If it is relative, we
// need to add {first_canonical_index}.
@@ -149,6 +165,7 @@ uint32_t TypeCanonicalizer::AddRecursiveGroup(const FunctionSig* sig) {
group.type.is_relative_supertype = false;
canonical_singleton_groups_.emplace(group, canonical_index);
canonical_supertypes_.emplace_back(kNoSuperType);
+ CheckMaxCanonicalIndex();
return canonical_index;
}
@@ -164,6 +181,7 @@ void TypeCanonicalizer::AddPredefinedArrayType(uint32_t index,
group.type.is_relative_supertype = false;
canonical_singleton_groups_.emplace(group, index);
canonical_supertypes_.emplace_back(kNoSuperType);
+ DCHECK_LE(canonical_supertypes_.size(), kMaxCanonicalTypes);
}
ValueType TypeCanonicalizer::CanonicalizeValueType(
diff --git a/src/wasm/canonical-types.h b/src/wasm/canonical-types.h
index 7a882acaa00c5e826b7e8adc0a27817f28450c3c..c35d350626f6cbbd8b8f8197940a0127b674c15c 100644
--- a/src/wasm/canonical-types.h
+++ b/src/wasm/canonical-types.h
@@ -161,6 +161,8 @@ class TypeCanonicalizer {
ValueType CanonicalizeValueType(const WasmModule* module, ValueType type,
uint32_t recursive_group_start) const;
+ void CheckMaxCanonicalIndex() const;
+
std::vector<uint32_t> canonical_supertypes_;
// Maps groups of size >=2 to the canonical id of the first type.
std::unordered_map<CanonicalGroup, uint32_t, base::hash<CanonicalGroup>>

View File

@@ -0,0 +1,76 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shu-yu Guo <syg@chromium.org>
Date: Mon, 13 May 2024 11:23:20 -0700
Subject: Don't build AccessInfo for storing to module exports
Bug: 340221135
Change-Id: I5af35be6ebf6a69db1c4687107503575b23973c4
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5534518
Reviewed-by: Adam Klein <adamk@chromium.org>
Commit-Queue: Shu-yu Guo <syg@chromium.org>
Cr-Commit-Position: refs/heads/main@{#93872}
diff --git a/src/compiler/access-info.cc b/src/compiler/access-info.cc
index 7cff878839c85cd9c6571ee48f1a0fce081f4471..9d022ba402d7bfdd5ca745a4193ee0de0e3d755e 100644
--- a/src/compiler/access-info.cc
+++ b/src/compiler/access-info.cc
@@ -526,6 +526,14 @@ PropertyAccessInfo AccessorAccessInfoHelper(
Cell::cast(module_namespace->module()->exports()->Lookup(
isolate, name.object(),
Smi::ToInt(Object::GetHash(*name.object())))));
+ if (IsAnyStore(access_mode)) {
+ // ES#sec-module-namespace-exotic-objects-set-p-v-receiver
+ // ES#sec-module-namespace-exotic-objects-defineownproperty-p-desc
+ //
+ // Storing to a module namespace object is always an error or a no-op in
+ // JS.
+ return PropertyAccessInfo::Invalid(zone);
+ }
if (IsTheHole(cell->value(kRelaxedLoad), isolate)) {
// This module has not been fully initialized yet.
return PropertyAccessInfo::Invalid(zone);
diff --git a/src/maglev/maglev-graph-builder.cc b/src/maglev/maglev-graph-builder.cc
index 8a5b4483d148192d3106e75874f042ccc6b36e56..728105c0aaccbaeb018eb9b9a660b5acba4650d8 100644
--- a/src/maglev/maglev-graph-builder.cc
+++ b/src/maglev/maglev-graph-builder.cc
@@ -3914,19 +3914,28 @@ ReduceResult MaglevGraphBuilder::TryBuildPropertyStore(
access_info.holder().value());
}
- if (access_info.IsFastAccessorConstant()) {
- return TryBuildPropertySetterCall(access_info, receiver,
- GetAccumulatorTagged());
- } else {
- DCHECK(access_info.IsDataField() || access_info.IsFastDataConstant());
- ReduceResult res = TryBuildStoreField(access_info, receiver, access_mode);
- if (res.IsDone()) {
- RecordKnownProperty(receiver, name,
- current_interpreter_frame_.accumulator(),
- AccessInfoGuaranteedConst(access_info), access_mode);
- return res;
+ switch (access_info.kind()) {
+ case compiler::PropertyAccessInfo::kFastAccessorConstant:
+ return TryBuildPropertySetterCall(access_info, receiver,
+ GetAccumulatorTagged());
+ case compiler::PropertyAccessInfo::kDataField:
+ case compiler::PropertyAccessInfo::kFastDataConstant: {
+ ReduceResult res = TryBuildStoreField(access_info, receiver, access_mode);
+ if (res.IsDone()) {
+ RecordKnownProperty(
+ receiver, name, current_interpreter_frame_.accumulator(),
+ AccessInfoGuaranteedConst(access_info), access_mode);
+ return res;
+ }
+ return ReduceResult::Fail();
}
- return ReduceResult::Fail();
+ case compiler::PropertyAccessInfo::kInvalid:
+ case compiler::PropertyAccessInfo::kNotFound:
+ case compiler::PropertyAccessInfo::kDictionaryProtoDataConstant:
+ case compiler::PropertyAccessInfo::kDictionaryProtoAccessorConstant:
+ case compiler::PropertyAccessInfo::kModuleExport:
+ case compiler::PropertyAccessInfo::kStringLength:
+ UNREACHABLE();
}
}

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