Compare commits

..

85 Commits

Author SHA1 Message Date
Shelley Vohr
387a1af666 fix: gin_helper::MicrotasksScope instantiation (#43357)
fix: gin_helper::MicrotasksScope instantiation

Co-authored-by: Charles Kerr <charles@charleskerr.com>
2024-08-19 18:09:00 -05:00
trop[bot]
3b1d09d7e6 fix: check screen capture permissions in desktopCapturer (#43273)
fix: check screen capture permissions in desktopCapturer

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-08-09 19:08:27 +02:00
trop[bot]
4401b62044 docs: Document ideal iconPath size (#43239)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Felix Rieseberg <fr@makenotion.com>
2024-08-07 11:57:24 +02:00
trop[bot]
164c526716 perf: don't build unused vectors in HidChooserContext (#43213)
* refactor: remove unused code in HidChooserContext::DeviceRemoved()

Co-authored-by: Charles Kerr <charles@charleskerr.com>

* refactor: remove unused code in HidChooserContext::OnHidManagerConnectionError()

Co-authored-by: Charles Kerr <charles@charleskerr.com>

* refactor: use structured bindings for readability

Co-authored-by: Charles Kerr <charles@charleskerr.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
2024-08-05 13:20:52 -04:00
Keeley Hammond
13fd9851c9 chore: cherry-pick 10 changes from 3-M126 (#43142)
* chore: [29-x-y] cherry-pick 11 changes from 3-M126

* d54105311590 from chromium
* 43b8b682d05c from chromium
* c5dd8839bfaf from chromium
* cdbc1d9684a3 from v8
* 38e4483e47f9 from chromium
* 70d2fe6b7c47 from v8
* 901377bb2f3b from v8
* 1b9040817119 from chromium
* bb28367eed73 from v8
* 99cafbf4b4b9 from chromium
* bc545b15a0ee from v8

* chore: update patches

* 5672472: [M120-LTS] Prevent script injection on reload when racing with a navigation | https://chromium-review.googlesource.com/c/chromium/src/+/5672472

* 5645901: [maglev] Fix skipped smi check due to phi hoisting | https://chromium-review.googlesource.com/c/v8/v8/+/5645901

Patch does not apply, hoisting is not used

* 5639725: [wasm] Fix scanning of wasm-to-js params | https://chromium-review.googlesource.com/c/v8/v8/+/5639725

* 5630530: [turboshaft] Lower LoadStackArgument to a Tagged load | https://chromium-review.googlesource.com/c/v8/v8/+/5630530

---------

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-08-02 15:59:20 -07:00
Pedro Pontes
f7f4c59ee4 chore: cherry-pick 3 changes from 0-M127 (#43160)
* chore: [29-x-y] cherry-pick 3 changes from 0-M127

* 44b7fbf35b10 from chromium
* c9815acd5a88 from dawn
* 9463ce9cd8d9 from DirectXShaderCompiler

* chore: e patches all

to make GH actions happy

---------

Co-authored-by: Charles Kerr <charles@charleskerr.com>
2024-08-02 10:11:08 +02:00
trop[bot]
d0b7ee20c8 chore: remove unused internal env.unSetVar() (#43173)
chore: remove unused unSetVar JS binding

Added in Oct 2020 (b33f2260, #25623) but never used

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
2024-08-01 21:31:39 -05:00
trop[bot]
4e2c6b5eb8 fix: handle failing to enter fullscreen on macOS (#43153)
* fix: handle failing to enter/exit fullscreen on macOS

On macOS, failing to enter/exit fullscreen can fail. If this happens,
properly restore the original window state.

Co-authored-by: cptpcrd <31829097+cptpcrd@users.noreply.github.com>

* refactor: remove fail to exit fullscreen handlers

Seem to be unnecessary since the window exits fullscreen anyway.

Co-authored-by: cptpcrd <31829097+cptpcrd@users.noreply.github.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: cptpcrd <31829097+cptpcrd@users.noreply.github.com>
2024-08-01 14:57:20 +02:00
trop[bot]
33f9c92300 chore: remove unused KeyWeakMap JS bindings (#43146)
The last three pieces of code that used it were removed in:

- Oct 2020 (8df4faa8 #25711)
- Jun 2020 (e1e73fa5 #24115)
- Jun 2020 (c0182bca #24116).

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
2024-07-31 21:26:28 -05:00
trop[bot]
11d87ceab5 build: fixup ffmpeg release on x64 macOS (#43119)
chore: fixup arch on x64 macOS ffmpeg

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2024-07-30 18:57:53 -05:00
trop[bot]
a7b2771039 chore: remove unused & undocumented function v8Util.deleteHiddenValue() (#43116)
chore: remove unused v8Util.deleteHiddenValue()

Its last use was removed in Nov 2020 by c8d77cae4a (#26659)

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
2024-07-30 18:41:03 -05:00
trop[bot]
c099fcc5b4 chore: remove unused class electron::ObjectLifeMonitor (#43107)
chore: remove unused class `electron::ObjectLifeMonitor` (#43089)

The last users were removed in June 2020 e1e73fa5f (#24115)
and May 2020 9d7ba982 (#23592).

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
2024-07-30 17:19:50 -04:00
John Kleinschmidt
c760554929 build: remove CircleCI (#42910)
build: remove CircleCI (#42844)

* build: remove CircleCI

* chore: remove remaining CircleCI references

(cherry picked from commit c006e129b3)

Co-authored-by: Keeley Hammond <vertedinde@electronjs.org>
2024-07-17 11:32:00 +02:00
trop[bot]
8a98ed797e build: update build-tools for GHA (#42871)
* chore: update build-tools for GHA

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

* build: fixup GHA running on fork PRs (#42880)

* chore: update build-tools for GHA

* chore: don't rely on environment variables for source cache location

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2024-07-15 12:16:34 -04:00
Keeley Hammond
ce5a8fefa6 build: fix Linux binary strip on publish, Linux x64 PrintInPDF test flake (#42877)
* build: fix up strip Linux binaries

* test: skip flaky Linux x64 test

* test: disable test-domain-error-types

this test is also disabled in main and other release branches
2024-07-15 09:57:39 -04:00
Samuel Attard
0ce3c29db1 build: use new arc runner names (#42888)
build: use new arc runner names (#42881)
2024-07-13 12:12:31 -07:00
trop[bot]
886b453b6d ci: fix Nan test failure on Linux (#42867)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-07-11 16:19:55 -04:00
Keeley Hammond
b206e7d5ac build: migrate to GitHub Actions (#42722)
* build: migrate to GitHub Actions

* build: use old clang-format binary path

* debug (do not merge): intentionally bust cache

* build: unbust cache

* build: redundant regex character class in generate-config-gypi.py (#41858)

fix: redundant regex character class in generate-config-gypi.py

'\w' already includes '_'. solves a SyntaxWarning on python 3.12.

* build: fix python 3.12

* build: add fix-sync to Linux

* fixup! fix python 3.12

* build: install python-setuptools

* Revert "build: fix python 3.12"

This reverts commit 551f2de072.

* fixup: build: install python-setuptools

* fixup: Revert "build: fix python 3.12"

---------

Co-authored-by: lauren n. liberda <msgh@selfisekai.rocks>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2024-07-10 15:38:05 -07:00
trop[bot]
4bfc9cd193 build: fix release, add newVersion for tagging (#42845)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Keeley Hammond <khammond@slack-corp.com>
2024-07-09 16:13:23 -04:00
trop[bot]
32dd4aa025 fix: multiple move() calls on the same unique_ptr (#42818)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
2024-07-08 13:42:32 -04:00
Keeley Hammond
2076981802 build: remove MacOS x64 from CircleCI (#42740) 2024-07-01 13:56:45 -04:00
Pedro Pontes
6d8485193b chore: cherry-pick 5 changes from 2-M126 (#42694)
* chore: [29-x-y] cherry-pick 4 changes from 2-M126

* 5d4df51d1d7d from angle
* 771e74ab497d from DirectXShaderCompiler
* 8f07d39227f6 from DirectXShaderCompiler
* b3c64851765c from DirectXShaderCompiler
* d5217a718925 from v8

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2024-06-28 10:11:23 +02:00
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
227 changed files with 14608 additions and 5015 deletions

View File

@@ -1 +0,0 @@
config-staging

View File

@@ -1,79 +0,0 @@
version: 2.1
# Required for dynamic configuration
setup: true
# Orbs
orbs:
path-filtering: circleci/path-filtering@0.1.0
continuation: circleci/continuation@0.2.0
# All input parameters to pass to build config
parameters:
run-docs-only:
type: boolean
default: false
upload-to-storage:
type: string
default: '1'
run-build-linux:
type: boolean
default: false
run-build-mac:
type: boolean
default: false
run-linux-publish:
type: boolean
default: false
linux-publish-arch-limit:
type: enum
default: all
enum: ["all", "arm", "arm64", "x64", "ia32"]
run-macos-publish:
type: boolean
default: false
macos-publish-arch-limit:
type: enum
default: all
enum: ["all", "osx-x64", "osx-arm64", "mas-x64", "mas-arm64"]
jobs:
generate-config:
docker:
- image: cimg/node:16.14
steps:
- checkout
- path-filtering/set-parameters:
base-revision: main
mapping: |
^((?!docs/).)*$ run-build-mac true
^((?!docs/).)*$ run-build-linux true
docs/.* run-docs-only true
^((?!docs/).)*$ run-docs-only false
- run:
command: |
cd .circleci/config
yarn
export CIRCLECI_BINARY="$HOME/circleci"
curl -fLSs https://raw.githubusercontent.com/CircleCI-Public/circleci-cli/main/install.sh | DESTDIR=$CIRCLECI_BINARY bash
node build.js
name: Pack config.yml
- run:
name: Set params
command: node .circleci/config/params.js
- continuation/continue:
configuration_path: .circleci/config-staging/built.yml
parameters: /tmp/pipeline-parameters.json
# Initial setup workflow
workflows:
setup:
jobs:
- generate-config

File diff suppressed because it is too large Load Diff

View File

@@ -1,34 +0,0 @@
const cp = require('child_process');
const fs = require('fs-extra');
const path = require('path');
const yaml = require('js-yaml');
const STAGING_DIR = path.resolve(__dirname, '..', 'config-staging');
function copyAndExpand(dir = './') {
const absDir = path.resolve(__dirname, dir);
const targetDir = path.resolve(STAGING_DIR, dir);
if (!fs.existsSync(targetDir)) {
fs.mkdirSync(targetDir);
}
for (const file of fs.readdirSync(absDir)) {
if (!file.endsWith('.yml')) {
if (fs.statSync(path.resolve(absDir, file)).isDirectory()) {
copyAndExpand(path.join(dir, file));
}
continue;
}
fs.writeFileSync(path.resolve(targetDir, file), yaml.dump(yaml.load(fs.readFileSync(path.resolve(absDir, file), 'utf8')), {
noRefs: true,
}));
}
}
if (fs.pathExists(STAGING_DIR)) fs.removeSync(STAGING_DIR);
copyAndExpand();
const output = cp.spawnSync(process.env.CIRCLECI_BINARY || 'circleci', ['config', 'pack', STAGING_DIR]);
fs.writeFileSync(path.resolve(STAGING_DIR, 'built.yml'), output.stdout.toString());

View File

@@ -1,10 +0,0 @@
{
"name": "@electron/circleci-config",
"version": "0.0.0",
"private": true,
"license": "MIT",
"dependencies": {
"fs-extra": "^10.1.0",
"js-yaml": "^4.1.0"
}
}

View File

@@ -1,12 +0,0 @@
const fs = require('fs');
const PARAMS_PATH = '/tmp/pipeline-parameters.json';
const content = JSON.parse(fs.readFileSync(PARAMS_PATH, 'utf-8'));
// Choose resource class for linux hosts
const currentBranch = process.env.CIRCLE_BRANCH || '';
content['large-linux-executor'] = /^pull\/[0-9-]+$/.test(currentBranch) ? '2xlarge' : 'electronjs/aks-linux-large';
content['medium-linux-executor'] = /^pull\/[0-9-]+$/.test(currentBranch) ? 'medium' : 'electronjs/aks-linux-medium';
fs.writeFileSync(PARAMS_PATH, JSON.stringify(content));

View File

@@ -1,43 +0,0 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
argparse@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
fs-extra@^10.1.0:
version "10.1.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf"
integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==
dependencies:
graceful-fs "^4.2.0"
jsonfile "^6.0.1"
universalify "^2.0.0"
graceful-fs@^4.1.6, graceful-fs@^4.2.0:
version "4.2.10"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
js-yaml@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
dependencies:
argparse "^2.0.1"
jsonfile@^6.0.1:
version "6.1.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
dependencies:
universalify "^2.0.0"
optionalDependencies:
graceful-fs "^4.1.6"
universalify@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==

View File

@@ -1,8 +0,0 @@
#!/bin/bash
set -e
mkdir -p ~/.ssh
echo "github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl
github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=
github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk=" >> ~/.ssh/known_hosts

View File

@@ -39,7 +39,6 @@
"dbaeumer.vscode-eslint",
"shakram02.bash-beautify",
"marshallofsound.gnls-electron",
"CircleCI.circleci"
],
"settings": {
"editor.tabSize": 2,

View File

@@ -2,5 +2,4 @@
# See docs/development/releasing.md
APPVEYOR_CLOUD_TOKEN=
CIRCLE_TOKEN=
ELECTRON_GITHUB_TOKEN=

View File

@@ -0,0 +1,220 @@
name: 'Build Electron'
description: 'Builds Electron & Friends'
inputs:
target-arch:
description: 'Target arch'
required: true
target-platform:
description: 'Target platform'
required: true
artifact-platform:
description: 'Artifact platform, should be linux, darwin or mas'
required: true
step-suffix:
description: 'Suffix for build steps'
required: false
default: ''
is-release:
description: 'Is release build'
required: true
strip-binaries:
description: 'Strip binaries (Linux only)'
required: false
generate-symbols:
description: 'Generate symbols'
required: true
upload-to-storage:
description: 'Upload to storage'
required: true
is-asan:
description: 'The ASan Linux build'
required: false
runs:
using: "composite"
steps:
- name: Set GN_EXTRA_ARGS for MacOS x64 Builds
shell: bash
if: ${{ inputs.target-arch == 'x64' && inputs.target-platform == 'macos' }}
run: |
GN_APPENDED_ARGS="$GN_EXTRA_ARGS target_cpu=\"x64\" v8_snapshot_toolchain=\"//build/toolchain/mac:clang_x64\""
echo "GN_EXTRA_ARGS=$GN_APPENDED_ARGS" >> $GITHUB_ENV
- name: Build Electron ${{ inputs.step-suffix }}
shell: bash
run: |
rm -rf "src/out/Default/Electron Framework.framework"
rm -rf src/out/Default/Electron*.app
cd src/electron
# TODO(codebytere): remove this once we figure out why .git/packed-refs is initially missing
git pack-refs
cd ..
if [ "`uname`" = "Darwin" ]; then
ulimit -n 10000
sudo launchctl limit maxfiles 65536 200000
fi
NINJA_SUMMARIZE_BUILD=1 e build -j $NUMBER_OF_NINJA_PROCESSES
cp out/Default/.ninja_log out/electron_ninja_log
node electron/script/check-symlinks.js
- name: Strip Electron Binaries ${{ inputs.step-suffix }}
shell: bash
if: ${{ inputs.strip-binaries == 'true' }}
run: |
cd src
electron/script/copy-debug-symbols.py --target-cpu="${{ inputs.target-arch }}" --out-dir=out/Default/debug --compress
electron/script/strip-binaries.py --target-cpu="${{ inputs.target-arch }}"
electron/script/add-debug-link.py --target-cpu="${{ inputs.target-arch }}" --debug-dir=out/Default/debug
- name: Build Electron dist.zip ${{ inputs.step-suffix }}
shell: bash
run: |
cd src
e build electron:electron_dist_zip -j $NUMBER_OF_NINJA_PROCESSES
if [ "${{ inputs.is-asan }}" != "true" ]; then
target_os=${{ inputs.target-platform == 'linux' && 'linux' || 'mac'}}
if [ "${{ inputs.artifact-platform }}" = "mas" ]; then
target_os="${target_os}_mas"
fi
electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip electron/script/zip_manifests/dist_zip.$target_os.${{ inputs.target-arch }}.manifest
fi
- name: Build Mksnapshot ${{ inputs.step-suffix }}
shell: bash
run: |
cd src
e build electron:electron_mksnapshot -j $NUMBER_OF_NINJA_PROCESSES
gn desc out/Default v8:run_mksnapshot_default args > out/Default/mksnapshot_args
# Remove unused args from mksnapshot_args
SEDOPTION="-i"
if [ "`uname`" = "Darwin" ]; then
SEDOPTION="-i ''"
fi
sed $SEDOPTION '/.*builtins-pgo/d' out/Default/mksnapshot_args
sed $SEDOPTION '/--turbo-profiling-input/d' out/Default/mksnapshot_args
sed $SEDOPTION '/The gn arg use_goma=true .*/d' out/Default/mksnapshot_args
if [ "`uname`" = "Linux" ]; then
if [ "${{ inputs.target-arch }}" = "arm" ]; then
electron/script/strip-binaries.py --file $PWD/out/Default/clang_x86_v8_arm/mksnapshot
electron/script/strip-binaries.py --file $PWD/out/Default/clang_x86_v8_arm/v8_context_snapshot_generator
elif [ "${{ inputs.target-arch }}" = "arm64" ]; then
electron/script/strip-binaries.py --file $PWD/out/Default/clang_x64_v8_arm64/mksnapshot
electron/script/strip-binaries.py --file $PWD/out/Default/clang_x64_v8_arm64/v8_context_snapshot_generator
else
electron/script/strip-binaries.py --file $PWD/out/Default/mksnapshot
electron/script/strip-binaries.py --file $PWD/out/Default/v8_context_snapshot_generator
fi
fi
e build electron:electron_mksnapshot_zip -j $NUMBER_OF_NINJA_PROCESSES
(cd out/Default; zip mksnapshot.zip mksnapshot_args gen/v8/embedded.S)
- name: Generate Cross-Arch Snapshot (arm/arm64) ${{ inputs.step-suffix }}
shell: bash
if: ${{ (inputs.target-arch == 'arm' || inputs.target-arch == 'arm64') && inputs.target-platform == 'linux' }}
run: |
cd src
if [ "${{ inputs.target-arch }}" = "arm" ]; then
MKSNAPSHOT_PATH="clang_x86_v8_arm"
elif [ "${{ inputs.target-arch }}" = "arm64" ]; then
MKSNAPSHOT_PATH="clang_x64_v8_arm64"
fi
cp "out/Default/$MKSNAPSHOT_PATH/mksnapshot" out/Default
cp "out/Default/$MKSNAPSHOT_PATH/v8_context_snapshot_generator" out/Default
cp "out/Default/$MKSNAPSHOT_PATH/libffmpeg.so" out/Default
python3 electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default --create-snapshot-only
mkdir cross-arch-snapshots
cp out/Default-mksnapshot-test/*.bin cross-arch-snapshots
# Clean up so that ninja does not get confused
rm -f out/Default/libffmpeg.so
- name: Build Chromedriver ${{ inputs.step-suffix }}
shell: bash
run: |
cd src
e build electron:electron_chromedriver -j $NUMBER_OF_NINJA_PROCESSES
e build electron:electron_chromedriver_zip
- name: Build Node.js headers ${{ inputs.step-suffix }}
shell: bash
run: |
cd src
e build electron:node_headers
- name: Generate & Zip Symbols ${{ inputs.step-suffix }}
shell: bash
run: |
# Generate breakpad symbols on release builds
if [ "${{ inputs.generate-symbols }}" = "true" ]; then
e build electron:electron_symbols
fi
cd src
export BUILD_PATH="$(pwd)/out/Default"
e build electron:licenses
e build electron:electron_version_file
if [ "${{ inputs.is-release }}" = "true" ]; then
DELETE_DSYMS_AFTER_ZIP=1 electron/script/zip-symbols.py -b $BUILD_PATH
else
electron/script/zip-symbols.py -b $BUILD_PATH
fi
- name: Generate FFMpeg ${{ inputs.step-suffix }}
shell: bash
if: ${{ inputs.is-release == 'true' }}
run: |
cd src
gn gen out/ffmpeg --args="import(\"//electron/build/args/ffmpeg.gn\") use_remoteexec=true $GN_EXTRA_ARGS"
autoninja -C out/ffmpeg electron:electron_ffmpeg_zip -j $NUMBER_OF_NINJA_PROCESSES
- name: Generate Hunspell Dictionaries ${{ inputs.step-suffix }}
shell: bash
if: ${{ inputs.is-release == 'true' && inputs.target-platform == 'linux' }}
run: |
cd src
autoninja -C out/Default electron:hunspell_dictionaries_zip -j $NUMBER_OF_NINJA_PROCESSES
- name: Generate Libcxx ${{ inputs.step-suffix }}
shell: bash
if: ${{ inputs.is-release == 'true' && inputs.target-platform == 'linux' }}
run: |
cd src
autoninja -C out/Default electron:libcxx_headers_zip -j $NUMBER_OF_NINJA_PROCESSES
autoninja -C out/Default electron:libcxxabi_headers_zip -j $NUMBER_OF_NINJA_PROCESSES
autoninja -C out/Default electron:libcxx_objects_zip -j $NUMBER_OF_NINJA_PROCESSES
- name: Generate TypeScript Definitions ${{ inputs.step-suffix }}
if: ${{ inputs.is-release == 'true' }}
shell: bash
run: |
cd src/electron
node script/yarn create-typescript-definitions
- name: Publish Electron Dist ${{ inputs.step-suffix }}
if: ${{ inputs.is-release == 'true' }}
shell: bash
run: |
rm -rf src/out/Default/obj
cd src/electron
if [ "${{ inputs.upload-to-storage }}" = "1" ]; then
echo 'Uploading Electron release distribution to Azure'
script/release/uploaders/upload.py --verbose --upload_to_storage
else
echo 'Uploading Electron release distribution to GitHub releases'
script/release/uploaders/upload.py --verbose
fi
- name: Generate Artifact Key
shell: bash
run: |
if [ "${{ inputs.is-asan }}" = "true" ]; then
ARTIFACT_KEY=${{ inputs.artifact-platform }}_${{ inputs.target-arch }}_asan
else
ARTIFACT_KEY=${{ inputs.artifact-platform }}_${{ inputs.target-arch }}
fi
echo "ARTIFACT_KEY=$ARTIFACT_KEY" >> $GITHUB_ENV
# The current generated_artifacts_<< artifact.key >> name was taken from CircleCI
# to ensure we don't break anything, but we may be able to improve that.
- name: Move all Generated Artifacts to Upload Folder ${{ inputs.step-suffix }}
shell: bash
run: ./src/electron/script/actions/move-artifacts.sh
- name: Upload Generated Artifacts ${{ inputs.step-suffix }}
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808
with:
name: generated_artifacts_${{ env.ARTIFACT_KEY }}
path: ./generated_artifacts_${{ inputs.artifact-platform }}_${{ inputs.target-arch }}
- name: Upload Src Artifacts ${{ inputs.step-suffix }}
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808
with:
name: src_artifacts_${{ env.ARTIFACT_KEY }}
path: ./src_artifacts_${{ inputs.artifact-platform }}_${{ inputs.target-arch }}

154
.github/actions/checkout/action.yml vendored Normal file
View File

@@ -0,0 +1,154 @@
name: 'Checkout'
description: 'Checks out Electron and stores it in the AKS Cache'
inputs:
generate-sas-token:
description: 'Whether to generate and persist a SAS token for the item in the cache'
required: false
default: 'false'
runs:
using: "composite"
steps:
- name: Set GIT_CACHE_PATH to make gclient to use the cache
shell: bash
run: |
echo "GIT_CACHE_PATH=$(pwd)/git-cache" >> $GITHUB_ENV
- name: Install Dependencies
shell: bash
run: |
cd src/electron
node script/yarn install --frozen-lockfile
- name: Get Depot Tools
shell: bash
run: |
git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
sed -i '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
# Remove swift-format dep from cipd on macOS until we send a patch upstream.
cd depot_tools
git apply --3way ../src/electron/.github/workflows/config/gclient.diff
# Ensure depot_tools does not update.
test -d depot_tools && cd depot_tools
touch .disable_auto_update
- name: Add Depot Tools to PATH
shell: bash
run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH
- name: Generate DEPS Hash
shell: bash
run: |
node src/electron/script/generate-deps-hash.js && cat src/electron/.depshash-target
echo "DEPSHASH=v1-src-cache-$(shasum src/electron/.depshash | cut -f1 -d' ')" >> $GITHUB_ENV
- name: Generate SAS Key
if: ${{ inputs.generate-sas-token == 'true' }}
shell: bash
run: |
curl --unix-socket /var/run/sas/sas.sock --fail "http://foo/$DEPSHASH.tar" > sas-token
- name: Save SAS Key
if: ${{ inputs.generate-sas-token == 'true' }}
uses: actions/cache/save@v4
with:
path: |
sas-token
key: sas-key-${{ github.run_number }}-${{ github.run_attempt }}
- name: Check If Cache Exists
id: check-cache
shell: bash
run: |
cache_path=/mnt/cross-instance-cache/$DEPSHASH.tar
echo "Using cache key: $DEPSHASH"
echo "Checking for cache in: $cache_path"
if [ ! -f "$cache_path" ]; then
echo "cache_exists=false" >> $GITHUB_OUTPUT
echo "Cache Does Not Exist for $DEPSHASH"
else
echo "cache_exists=false" >> $GITHUB_OUTPUT
echo "Cache Already Exists for $DEPSHASH, Busting Cache.."
fi
- name: Gclient Sync
if: steps.check-cache.outputs.cache_exists == 'false'
shell: bash
run: |
gclient config \
--name "src/electron" \
--unmanaged \
${GCLIENT_EXTRA_ARGS} \
"$GITHUB_SERVER_URL/$GITHUB_REPOSITORY"
ELECTRON_USE_THREE_WAY_MERGE_FOR_PATCHES=1 gclient sync --with_branch_heads --with_tags -vvvvv
if [ "${{ inputs.is-release }}" != "true" ]; then
# Re-export all the patches to check if there were changes.
python3 src/electron/script/export_all_patches.py src/electron/patches/config.json
cd src/electron
git update-index --refresh || true
if ! git diff-index --quiet HEAD --; then
# There are changes to the patches. Make a git commit with the updated patches
git add patches
GIT_COMMITTER_NAME="PatchUp" GIT_COMMITTER_EMAIL="73610968+patchup[bot]@users.noreply.github.com" git commit -m "chore: update patches" --author="PatchUp <73610968+patchup[bot]@users.noreply.github.com>"
# Export it
mkdir -p ../../patches
git format-patch -1 --stdout --keep-subject --no-stat --full-index > ../../patches/update-patches.patch
if (node ./script/push-patch.js 2> /dev/null > /dev/null); then
echo
echo "======================================================================"
echo "Changes to the patches when applying, we have auto-pushed the diff to the current branch"
echo "A new CI job will kick off shortly"
echo "======================================================================"
exit 1
else
echo
echo "======================================================================"
echo "There were changes to the patches when applying."
echo "Check the CI artifacts for a patch you can apply to fix it."
echo "======================================================================"
exit 1
fi
fi
fi
# delete all .git directories under src/ except for
# third_party/angle/ and third_party/dawn/ because of build time generation of files
# gen/angle/commit.h depends on third_party/angle/.git/HEAD
# https://chromium-review.googlesource.com/c/angle/angle/+/2074924
# and dawn/common/Version_autogen.h depends on third_party/dawn/.git/HEAD
# https://dawn-review.googlesource.com/c/dawn/+/83901
# TODO: maybe better to always leave out */.git/HEAD file for all targets ?
- name: Delete .git directories under src to free space
if: steps.check-cache.outputs.cache_exists == 'false'
shell: bash
run: |
cd src
( find . -type d -name ".git" -not -path "./third_party/angle/*" -not -path "./third_party/dawn/*" -not -path "./electron/*" ) | xargs rm -rf
- name: Minimize Cache Size for Upload
if: steps.check-cache.outputs.cache_exists == 'false'
shell: bash
run: |
rm -rf src/android_webview
rm -rf src/ios/chrome
rm -rf src/third_party/blink/web_tests
rm -rf src/third_party/blink/perf_tests
rm -rf src/chrome/test/data/xr/webvr_info
rm -rf src/third_party/angle/third_party/VK-GL-CTS/src
rm -rf src/third_party/swift-toolchain
rm -rf src/third_party/swiftshader/tests/regres/testlists
rm -rf src/electron
- name: Compress Src Directory
if: steps.check-cache.outputs.cache_exists == 'false'
shell: bash
run: |
echo "Uncompressed src size: $(du -sh src | cut -f1 -d' ')"
tar -cf $DEPSHASH.tar src
echo "Compressed src to $(du -sh $DEPSHASH.tar | cut -f1 -d' ')"
cp ./$DEPSHASH.tar /mnt/cross-instance-cache/
- name: Persist Src Cache
if: steps.check-cache.outputs.cache_exists == 'false'
shell: bash
run: |
final_cache_path=/mnt/cross-instance-cache/$DEPSHASH.tar
echo "Using cache key: $DEPSHASH"
echo "Checking path: $final_cache_path"
if [ ! -f "$final_cache_path" ]; then
echo "Cache key not found"
exit 1
else
echo "Cache key persisted in $final_cache_path"
fi

71
.github/actions/fix-sync/action.yml vendored Normal file
View File

@@ -0,0 +1,71 @@
name: 'Fix Sync'
description: 'Checks out Electron and stores it in the AKS Cache'
inputs:
target-arch:
description: 'Target arch'
required: true
target-platform:
description: 'Target platform'
required: true
runs:
using: "composite"
steps:
- name: Fix Sync
shell: bash
# This step is required to correct for differences between "gclient sync"
# on Linux and the expected state. This requires:
# 1. Fixing Clang Install (wrong binary)
# 2. Fixing esbuild (wrong binary)
# 3. Fixing rustc (wrong binary)
# 4. Fixing gn (wrong binary)
# 5. Fix reclient (wrong binary)
# 6. Fixing dsymutil (wrong binary)
# 7. Ensuring we are using the correct ninja and adding it to PATH
# 8. Fixing angle (wrong remote)
run : |
SEDOPTION="-i"
if [ "${{ inputs.target-platform }}" = "macos" ]; then
SEDOPTION="-i ''"
rm -rf src/third_party/llvm-build
python3 src/tools/clang/scripts/update.py
echo 'infra/3pp/tools/esbuild/${platform}' `gclient getdep --deps-file=src/third_party/devtools-frontend/src/DEPS -r 'third_party/esbuild:infra/3pp/tools/esbuild/${platform}'` > esbuild_ensure_file
# Remove extra output from calling gclient getdep which always calls update_depot_tools
sed -i '' "s/Updating depot_tools... //g" esbuild_ensure_file
cipd ensure --root src/third_party/devtools-frontend/src/third_party/esbuild -ensure-file esbuild_ensure_file
rm -rf src/third_party/rust-toolchain
python3 src/tools/rust/update_rust.py
# Prevent calling gclient getdep which always calls update_depot_tools
echo 'gn/gn/mac-${arch}' `gclient getdep --deps-file=src/DEPS -r 'src/buildtools/mac:gn/gn/mac-${arch}'` > gn_ensure_file
sed -i '' "s/Updating depot_tools... //g" gn_ensure_file
cipd ensure --root src/buildtools/mac -ensure-file gn_ensure_file
# Prevent calling gclient getdep which always calls update_depot_tools
echo 'infra/rbe/client/${platform}' `gclient getdep --deps-file=src/DEPS -r 'src/buildtools/reclient:infra/rbe/client/${platform}'` > gn_ensure_file
sed -i '' "s/Updating depot_tools... //g" gn_ensure_file
cipd ensure --root src/buildtools/reclient -ensure-file gn_ensure_file
python3 src/buildtools/reclient_cfgs/configure_reclient_cfgs.py --rbe_instance "projects/rbe-chrome-untrusted/instances/default_instance" --reproxy_cfg_template reproxy.cfg.template --rewrapper_cfg_project "" --skip_remoteexec_cfg_fetch
if [ "${{ inputs.target-arch }}" == "arm64" ]; then
DSYM_SHA_FILE=src/tools/clang/dsymutil/bin/dsymutil.arm64.sha1
else
DSYM_SHA_FILE=src/tools/clang/dsymutil/bin/dsymutil.x64.sha1
fi
python3 src/third_party/depot_tools/download_from_google_storage.py --no_resume --no_auth --bucket chromium-browser-clang -s $DSYM_SHA_FILE -o src/tools/clang/dsymutil/bin/dsymutil
fi
echo 'infra/3pp/tools/ninja/${platform}' `gclient getdep --deps-file=src/DEPS -r 'src/third_party/ninja:infra/3pp/tools/ninja/${platform}'` > ninja_ensure_file
sed $SEDOPTION "s/Updating depot_tools... //g" ninja_ensure_file
cipd ensure --root src/third_party/ninja -ensure-file ninja_ensure_file
echo "$(pwd)/src/third_party/ninja" >> $GITHUB_PATH
cd src/third_party/angle
rm -f .git/objects/info/alternates
git remote set-url origin https://chromium.googlesource.com/angle/angle.git
cp .git/config .git/config.backup
git remote remove origin
mv .git/config.backup .git/config
git fetch

View File

@@ -0,0 +1,65 @@
name: 'Free Space macOS'
description: 'Checks out Electron and stores it in the AKS Cache'
runs:
using: "composite"
steps:
- name: Free Space on MacOS
shell: bash
run: |
sudo mkdir -p $TMPDIR/del-target
tmpify() {
if [ -d "$1" ]; then
sudo mv "$1" $TMPDIR/del-target/$(echo $1|shasum -a 256|head -n1|cut -d " " -f1)
fi
}
strip_universal_deep() {
opwd=$(pwd)
cd $1
f=$(find . -perm +111 -type f)
for fp in $f
do
if [[ $(file "$fp") == *"universal binary"* ]]; then
if [ "`arch`" == "arm64" ]; then
if [[ $(file "$fp") == *"x86_64"* ]]; then
sudo lipo -remove x86_64 "$fp" -o "$fp" || true
fi
else
if [[ $(file "$fp") == *"arm64e)"* ]]; then
sudo lipo -remove arm64e "$fp" -o "$fp" || true
fi
if [[ $(file "$fp") == *"arm64)"* ]]; then
sudo lipo -remove arm64 "$fp" -o "$fp" || true
fi
fi
fi
done
cd $opwd
}
tmpify /Library/Developer/CoreSimulator
tmpify ~/Library/Developer/CoreSimulator
tmpify $(xcode-select -p)/Platforms/AppleTVOS.platform
tmpify $(xcode-select -p)/Platforms/iPhoneOS.platform
tmpify $(xcode-select -p)/Platforms/WatchOS.platform
tmpify $(xcode-select -p)/Platforms/WatchSimulator.platform
tmpify $(xcode-select -p)/Platforms/AppleTVSimulator.platform
tmpify $(xcode-select -p)/Platforms/iPhoneSimulator.platform
tmpify $(xcode-select -p)/Toolchains/XcodeDefault.xctoolchain/usr/metal/ios
tmpify $(xcode-select -p)/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift
tmpify $(xcode-select -p)/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift-5.0
tmpify ~/.rubies
tmpify ~/Library/Caches/Homebrew
tmpify /usr/local/Homebrew
sudo rm -rf $TMPDIR/del-target
sudo rm -rf /Applications/Safari.app
sudo rm -rf ~/project/src/third_party/catapult/tracing/test_data
sudo rm -rf ~/project/src/third_party/angle/third_party/VK-GL-CTS
# lipo off some huge binaries arm64 versions to save space
strip_universal_deep $(xcode-select -p)/../SharedFrameworks
# strip_arm_deep /System/Volumes/Data/Library/Developer/CommandLineTools/usr

View File

@@ -0,0 +1,11 @@
name: 'Install Build Tools'
description: 'Installs an exact SHA of build tools'
runs:
using: "composite"
steps:
- name: Install Build Tools
shell: bash
run: |
export BUILD_TOOLS_SHA=d5b87591842be19058e8d75d2c5b7f1fabe9f450
npm i -g @electron/build-tools
e auto-update disable

View File

@@ -0,0 +1,36 @@
name: 'Restore Cache AKS'
description: 'Restores Electron src cache via AKS'
runs:
using: "composite"
steps:
- name: Restore and Ensure Src Cache
shell: bash
run: |
cache_path=/mnt/cross-instance-cache/$DEPSHASH.tar
echo "Using cache key: $DEPSHASH"
echo "Checking for cache in: $cache_path"
if [ ! -f "$cache_path" ]; then
echo "Cache Does Not Exist for $DEPSHASH - exiting"
exit 1
else
echo "Found Cache for $DEPSHASH at $cache_path"
fi
echo "Persisted cache is $(du -sh $cache_path | cut -f1)"
mkdir temp-cache
tar -xf $cache_path -C temp-cache
echo "Unzipped cache is $(du -sh temp-cache/src | cut -f1)"
if [ -d "temp-cache/src" ]; then
echo "Relocating Cache"
rm -rf src
mv temp-cache/src src
fi
if [ ! -d "src/third_party/blink" ]; then
echo "Cache was not correctly restored - exiting"
exit 1
fi
echo "Wiping Electron Directory"
rm -rf src/electron

View File

@@ -0,0 +1,66 @@
name: 'Restore Cache AZCopy'
description: 'Restores Electron src cache via AZCopy'
runs:
using: "composite"
steps:
- name: Obtain SAS Key
continue-on-error: true
uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9
with:
path: |
sas-token
key: sas-key-${{ github.run_number }}-1
- name: Obtain SAS Key
continue-on-error: true
uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9
with:
path: |
sas-token
key: sas-key-${{ github.run_number }}-${{ github.run_attempt }}
- name: Download Src Cache from AKS
# The cache will always exist here as a result of the checkout job
# Either it was uploaded to Azure in the checkout job for this commit
# or it was uploaded in the checkout job for a previous commit.
uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e # v3.0.0
with:
timeout_minutes: 20
max_attempts: 3
retry_on: error
command: |
sas_token=$(cat sas-token)
if [ -z $sas-token ]; then
echo "SAS Token not found; exiting src cache download early..."
exit 1
fi
azcopy copy \
"https://${{ env.AZURE_AKS_CACHE_STORAGE_ACCOUNT }}.file.core.windows.net/${{ env.AZURE_AKS_CACHE_SHARE_NAME }}/${{ env.CACHE_PATH }}?$sas_token" $DEPSHASH.tar
env:
AZURE_AKS_CACHE_STORAGE_ACCOUNT: f723719aa87a34622b5f7f3
AZURE_AKS_CACHE_SHARE_NAME: pvc-f6a4089f-b082-4bee-a3f9-c3e1c0c02d8f
- name: Clean SAS Key
shell: bash
run: rm -f sas-token
- name: Unzip and Ensure Src Cache
shell: bash
run: |
echo "Downloaded cache is $(du -sh $DEPSHASH.tar | cut -f1)"
mkdir temp-cache
tar -xf $DEPSHASH.tar -C temp-cache
echo "Unzipped cache is $(du -sh temp-cache/src | cut -f1)"
if [ -d "temp-cache/src" ]; then
echo "Relocating Cache"
rm -rf src
mv temp-cache/src src
echo "Deleting zip file"
rm -rf $DEPSHASH.tar
fi
if [ ! -d "src/third_party/blink" ]; then
echo "Cache was not correctly restored - exiting"
exit 1
fi
echo "Wiping Electron Directory"
rm -rf src/electron

245
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,245 @@
name: Build
on:
workflow_dispatch:
inputs:
build-image-sha:
type: string
description: 'SHA for electron/build image'
default: 'cf814a4d2501e8e843caea071a6b70a48e78b855'
required: true
skip-macos:
type: boolean
description: 'Skip macOS builds'
default: false
required: false
skip-linux:
type: boolean
description: 'Skip Linux builds'
default: false
required: false
skip-lint:
type: boolean
description: 'Skip lint check'
default: false
required: false
push:
branches:
- main
- '[1-9][0-9]-x-y'
pull_request:
jobs:
setup:
runs-on: ubuntu-latest
permissions:
pull-requests: read
outputs:
docs: ${{ steps.filter.outputs.docs }}
src: ${{ steps.filter.outputs.src }}
build-image-sha: ${{ steps.set-output.outputs.build-image-sha }}
docs-only: ${{ steps.set-output.outputs.docs-only }}
steps:
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 #v4.0.2
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
id: filter
with:
filters: |
docs:
- 'docs/**'
src:
- '!docs/**'
- name: Set Outputs for Build Image SHA & Docs Only
id: set-output
run: |
if [ -z "${{ inputs.build-image-sha }}" ]; then
echo "build-image-sha=cf814a4d2501e8e843caea071a6b70a48e78b855" >> "$GITHUB_OUTPUT"
else
echo "build-image-sha=${{ inputs.build-image-sha }}" >> "$GITHUB_OUTPUT"
fi
echo "docs-only=${{ steps.filter.outputs.docs == 'true' && steps.filter.outputs.src == 'false' }}" >> "$GITHUB_OUTPUT"
# Lint Jobs
lint:
needs: setup
if: ${{ !inputs.skip-lint }}
uses: ./.github/workflows/pipeline-electron-lint.yml
with:
container: '{"image":"ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }}","options":"--user root"}'
secrets: inherit
# Docs Only Jobs
docs-only:
needs: setup
if: ${{ needs.setup.outputs.docs-only == 'true' }}
uses: ./.github/workflows/pipeline-electron-docs-only.yml
with:
container: '{"image":"ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }}","options":"--user root"}'
secrets: inherit
# Checkout Jobs
checkout-macos:
needs: setup
if: ${{ needs.setup.outputs.src == 'true' && !inputs.skip-macos}}
runs-on: electron-arc-linux-amd64-32core
container:
image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }}
options: --user root
volumes:
- /mnt/cross-instance-cache:/mnt/cross-instance-cache
- /var/run/sas:/var/run/sas
env:
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac'
outputs:
build-image-sha: ${{ needs.setup.outputs.build-image-sha }}
steps:
- name: Checkout Electron
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
with:
path: src/electron
fetch-depth: 0
- name: Checkout & Sync & Save
uses: ./src/electron/.github/actions/checkout
with:
generate-sas-token: 'true'
checkout-linux:
needs: setup
if: ${{ needs.setup.outputs.src == 'true' && !inputs.skip-linux}}
runs-on: electron-arc-linux-amd64-32core
container:
image: ghcr.io/electron/build:${{ needs.setup.outputs.build-image-sha }}
options: --user root
volumes:
- /mnt/cross-instance-cache:/mnt/cross-instance-cache
- /var/run/sas:/var/run/sas
env:
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True'
outputs:
build-image-sha: ${{ needs.setup.outputs.build-image-sha}}
steps:
- name: Checkout Electron
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
with:
path: src/electron
fetch-depth: 0
- name: Checkout & Sync & Save
uses: ./src/electron/.github/actions/checkout
# Build Jobs - These cascade into testing jobs
macos-x64:
permissions:
contents: read
issues: read
pull-requests: read
uses: ./.github/workflows/pipeline-electron-build-and-test.yml
needs: checkout-macos
with:
build-runs-on: macos-14-xlarge
test-runs-on: macos-13
target-platform: macos
target-arch: x64
is-release: false
gn-build-type: testing
generate-symbols: false
upload-to-storage: '0'
secrets: inherit
macos-arm64:
permissions:
contents: read
issues: read
pull-requests: read
uses: ./.github/workflows/pipeline-electron-build-and-test.yml
needs: checkout-macos
with:
build-runs-on: macos-14-xlarge
test-runs-on: macos-14
target-platform: macos
target-arch: arm64
is-release: false
gn-build-type: testing
generate-symbols: false
upload-to-storage: '0'
secrets: inherit
linux-x64:
permissions:
contents: read
issues: read
pull-requests: read
uses: ./.github/workflows/pipeline-electron-build-and-test-and-nan.yml
needs: checkout-linux
with:
build-runs-on: electron-arc-linux-amd64-32core
test-runs-on: electron-arc-linux-amd64-4core
build-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
test-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root --privileged --init"}'
target-platform: linux
target-arch: x64
is-release: false
gn-build-type: testing
generate-symbols: false
upload-to-storage: '0'
secrets: inherit
linux-x64-asan:
permissions:
contents: read
issues: read
pull-requests: read
uses: ./.github/workflows/pipeline-electron-build-and-test.yml
needs: checkout-linux
with:
build-runs-on: electron-arc-linux-amd64-32core
test-runs-on: electron-arc-linux-amd64-4core
build-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
test-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root --privileged --init"}'
target-platform: linux
target-arch: x64
is-release: false
gn-build-type: testing
generate-symbols: false
upload-to-storage: '0'
is-asan: true
secrets: inherit
linux-arm:
permissions:
contents: read
issues: read
pull-requests: read
uses: ./.github/workflows/pipeline-electron-build-and-test.yml
needs: checkout-linux
with:
build-runs-on: electron-arc-linux-amd64-32core
test-runs-on: electron-arc-linux-arm64-4core
build-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
test-container: '{"image":"ghcr.io/electron/test:arm32v7-${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root --privileged --init","volumes":["/home/runner/externals:/mnt/runner-externals"]}'
target-platform: linux
target-arch: arm
is-release: false
gn-build-type: testing
generate-symbols: false
upload-to-storage: '0'
secrets: inherit
linux-arm64:
permissions:
contents: read
issues: read
pull-requests: read
uses: ./.github/workflows/pipeline-electron-build-and-test.yml
needs: checkout-linux
with:
build-runs-on: electron-arc-linux-amd64-32core
test-runs-on: electron-arc-linux-arm64-4core
build-container: '{"image":"ghcr.io/electron/build:${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
test-container: '{"image":"ghcr.io/electron/test:arm64v8-${{ needs.checkout-linux.outputs.build-image-sha }}","options":"--user root --privileged --init"}'
target-platform: linux
target-arch: arm64
is-release: false
gn-build-type: testing
generate-symbols: false
upload-to-storage: '0'
secrets: inherit

14
.github/workflows/config/gclient.diff vendored Normal file
View File

@@ -0,0 +1,14 @@
diff --git a/gclient.py b/gclient.py
index 59e2b4c5197928bdba1ef69bdbe637d7dfe471c1..b4bae5e48c83c84bd867187afaf40eed16e69851 100755
--- a/gclient.py
+++ b/gclient.py
@@ -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', [])
+ for package in (x for x in packages if "infra/3pp/tools/swift-format" not in x.get('package')):
deps_to_add.append(
CipdDependency(parent=self,
name=name,

86
.github/workflows/linux-publish.yml vendored Normal file
View File

@@ -0,0 +1,86 @@
name: Publish Linux
on:
workflow_dispatch:
inputs:
build-image-sha:
type: string
description: 'SHA for electron/build image'
default: 'cf814a4d2501e8e843caea071a6b70a48e78b855'
upload-to-storage:
description: 'Uploads to Azure storage'
required: false
default: '1'
type: string
run-linux-publish:
description: 'Run the publish jobs vs just the build jobs'
type: boolean
default: false
jobs:
checkout-linux:
runs-on: electron-arc-linux-amd64-32core
container:
image: ghcr.io/electron/build:${{ inputs.build-image-sha }}
options: --user root
volumes:
- /mnt/cross-instance-cache:/mnt/cross-instance-cache
- /var/run/sas:/var/run/sas
env:
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True'
steps:
- name: Checkout Electron
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
with:
path: src/electron
fetch-depth: 0
- name: Checkout & Sync & Save
uses: ./src/electron/.github/actions/checkout
publish-x64:
uses: ./.github/workflows/pipeline-segment-electron-build.yml
needs: checkout-linux
with:
environment: production-release
build-runs-on: electron-arc-linux-amd64-32core
build-container: '{"image":"ghcr.io/electron/build:${{ inputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
target-platform: linux
target-arch: x64
is-release: true
gn-build-type: release
generate-symbols: true
strip-binaries: true
upload-to-storage: ${{ inputs.upload-to-storage }}
secrets: inherit
publish-arm:
uses: ./.github/workflows/pipeline-segment-electron-build.yml
needs: checkout-linux
with:
environment: production-release
build-runs-on: electron-arc-linux-amd64-32core
build-container: '{"image":"ghcr.io/electron/build:${{ inputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
target-platform: linux
target-arch: arm
is-release: true
gn-build-type: release
generate-symbols: true
strip-binaries: true
upload-to-storage: ${{ inputs.upload-to-storage }}
secrets: inherit
publish-arm64:
uses: ./.github/workflows/pipeline-segment-electron-build.yml
needs: checkout-linux
with:
environment: production-release
build-runs-on: electron-arc-linux-amd64-32core
build-container: '{"image":"ghcr.io/electron/build:${{ inputs.build-image-sha }}","options":"--user root","volumes":["/mnt/cross-instance-cache:/mnt/cross-instance-cache"]}'
target-platform: linux
target-arch: arm64
is-release: true
gn-build-type: release
generate-symbols: true
strip-binaries: true
upload-to-storage: ${{ inputs.upload-to-storage }}
secrets: inherit

69
.github/workflows/macos-publish.yml vendored Normal file
View File

@@ -0,0 +1,69 @@
name: Publish MacOS
on:
workflow_dispatch:
inputs:
build-image-sha:
type: string
description: 'SHA for electron/build image'
default: 'cf814a4d2501e8e843caea071a6b70a48e78b855'
required: true
upload-to-storage:
description: 'Uploads to Azure storage'
required: false
default: '1'
type: string
run-macos-publish:
description: 'Run the publish jobs vs just the build jobs'
type: boolean
default: false
jobs:
checkout-macos:
runs-on: electron-arc-linux-amd64-32core
container:
image: ghcr.io/electron/build:${{ inputs.build-image-sha }}
options: --user root
volumes:
- /mnt/cross-instance-cache:/mnt/cross-instance-cache
- /var/run/sas:/var/run/sas
env:
GCLIENT_EXTRA_ARGS: '--custom-var=checkout_mac=True --custom-var=host_os=mac'
steps:
- name: Checkout Electron
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
with:
path: src/electron
fetch-depth: 0
- name: Checkout & Sync & Save
uses: ./src/electron/.github/actions/checkout
with:
generate-sas-token: 'true'
publish-x64:
uses: ./.github/workflows/pipeline-segment-electron-build.yml
needs: checkout-macos
with:
environment: production-release
build-runs-on: macos-14-xlarge
target-platform: macos
target-arch: x64
is-release: true
gn-build-type: release
generate-symbols: true
upload-to-storage: ${{ inputs.upload-to-storage }}
secrets: inherit
publish-arm64:
uses: ./.github/workflows/pipeline-segment-electron-build.yml
needs: checkout-macos
with:
environment: production-release
build-runs-on: macos-14-xlarge
target-platform: macos
target-arch: arm64
is-release: true
gn-build-type: release
generate-symbols: true
upload-to-storage: ${{ inputs.upload-to-storage }}
secrets: inherit

View File

@@ -0,0 +1,103 @@
name: Electron Build & Test (+ Node + NaN) Pipeline
on:
workflow_call:
inputs:
target-platform:
type: string
description: 'Platform to run on, can be macos or linux'
required: true
target-arch:
type: string
description: 'Arch to build for, can be x64, arm64 or arm'
required: true
build-runs-on:
type: string
description: 'What host to run the build'
required: true
test-runs-on:
type: string
description: 'What host to run the tests on'
required: true
build-container:
type: string
description: 'JSON container information for aks runs-on'
required: false
default: '{"image":null}'
test-container:
type: string
description: 'JSON container information for testing'
required: false
default: '{"image":null}'
is-release:
description: 'Whether this build job is a release job'
required: true
type: boolean
default: false
gn-build-type:
description: 'The gn build type - testing or release'
required: true
type: string
default: testing
generate-symbols:
description: 'Whether or not to generate symbols'
required: true
type: boolean
default: false
upload-to-storage:
description: 'Whether or not to upload build artifacts to external storage'
required: true
type: string
default: '0'
is-asan:
description: 'Building the Address Sanitizer (ASan) Linux build'
required: false
type: boolean
default: false
concurrency:
group: electron-build-and-test-and-nan-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }}
jobs:
build:
uses: ./.github/workflows/pipeline-segment-electron-build.yml
with:
build-runs-on: ${{ inputs.build-runs-on }}
build-container: ${{ inputs.build-container }}
target-platform: ${{ inputs.target-platform }}
target-arch: ${{ inputs.target-arch }}
is-release: ${{ inputs.is-release }}
gn-build-type: ${{ inputs.gn-build-type }}
generate-symbols: ${{ inputs.generate-symbols }}
upload-to-storage: ${{ inputs.upload-to-storage }}
secrets: inherit
gn-check:
uses: ./.github/workflows/pipeline-segment-electron-gn-check.yml
with:
target-platform: ${{ inputs.target-platform }}
target-arch: ${{ inputs.target-arch }}
check-runs-on: ${{ inputs.build-runs-on }}
check-container: ${{ inputs.build-container }}
gn-build-type: ${{ inputs.gn-build-type }}
is-asan: ${{ inputs.is-asan }}
secrets: inherit
test:
uses: ./.github/workflows/pipeline-segment-electron-test.yml
needs: build
with:
target-arch: ${{ inputs.target-arch }}
target-platform: ${{ inputs.target-platform }}
test-runs-on: ${{ inputs.test-runs-on }}
test-container: ${{ inputs.test-container }}
secrets: inherit
nn-test:
uses: ./.github/workflows/pipeline-segment-node-nan-test.yml
needs: build
with:
target-arch: ${{ inputs.target-arch }}
target-platform: ${{ inputs.target-platform }}
test-runs-on: ${{ inputs.test-runs-on }}
test-container: ${{ inputs.test-container }}
gn-build-type: ${{ inputs.gn-build-type }}
secrets: inherit

View File

@@ -0,0 +1,100 @@
name: Electron Build & Test Pipeline
on:
workflow_call:
inputs:
target-platform:
type: string
description: 'Platform to run on, can be macos or linux'
required: true
target-arch:
type: string
description: 'Arch to build for, can be x64, arm64 or arm'
required: true
build-runs-on:
type: string
description: 'What host to run the build'
required: true
test-runs-on:
type: string
description: 'What host to run the tests on'
required: true
build-container:
type: string
description: 'JSON container information for aks runs-on'
required: false
default: '{"image":null}'
test-container:
type: string
description: 'JSON container information for testing'
required: false
default: '{"image":null}'
is-release:
description: 'Whether this build job is a release job'
required: true
type: boolean
default: false
gn-build-type:
description: 'The gn build type - testing or release'
required: true
type: string
default: testing
generate-symbols:
description: 'Whether or not to generate symbols'
required: true
type: boolean
default: false
upload-to-storage:
description: 'Whether or not to upload build artifacts to external storage'
required: true
type: string
default: '0'
is-asan:
description: 'Building the Address Sanitizer (ASan) Linux build'
required: false
type: boolean
default: false
concurrency:
group: electron-build-and-test-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }}
permissions:
contents: read
issues: read
pull-requests: read
jobs:
build:
uses: ./.github/workflows/pipeline-segment-electron-build.yml
with:
build-runs-on: ${{ inputs.build-runs-on }}
build-container: ${{ inputs.build-container }}
target-platform: ${{ inputs.target-platform }}
target-arch: ${{ inputs.target-arch }}
is-release: ${{ inputs.is-release }}
gn-build-type: ${{ inputs.gn-build-type }}
generate-symbols: ${{ inputs.generate-symbols }}
upload-to-storage: ${{ inputs.upload-to-storage }}
is-asan: ${{ inputs.is-asan}}
secrets: inherit
gn-check:
uses: ./.github/workflows/pipeline-segment-electron-gn-check.yml
with:
target-platform: ${{ inputs.target-platform }}
target-arch: ${{ inputs.target-arch }}
check-runs-on: ${{ inputs.build-runs-on }}
check-container: ${{ inputs.build-container }}
gn-build-type: ${{ inputs.gn-build-type }}
is-asan: ${{ inputs.is-asan }}
secrets: inherit
test:
uses: ./.github/workflows/pipeline-segment-electron-test.yml
needs: build
with:
target-arch: ${{ inputs.target-arch }}
target-platform: ${{ inputs.target-platform }}
test-runs-on: ${{ inputs.test-runs-on }}
test-container: ${{ inputs.test-container }}
is-asan: ${{ inputs.is-asan}}
secrets: inherit

View File

@@ -0,0 +1,43 @@
name: Electron Docs Compile
on:
workflow_call:
inputs:
container:
required: true
description: 'Container to run the docs-only ts compile in'
type: string
concurrency:
group: electron-docs-only-${{ github.ref }}
cancel-in-progress: true
jobs:
docs-only:
name: Docs Only Compile
runs-on: electron-arc-linux-amd64-4core
timeout-minutes: 20
container: ${{ fromJSON(inputs.container) }}
steps:
- name: Checkout Electron
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
with:
path: src/electron
fetch-depth: 0
- name: Install Dependencies
run: |
cd src/electron
node script/yarn install --frozen-lockfile
- name: Run TS/JS compile
shell: bash
run: |
cd src/electron
node script/yarn create-typescript-definitions
node script/yarn tsc -p tsconfig.default_app.json --noEmit
for f in build/webpack/*.js
do
out="${f:29}"
if [ "$out" != "base.js" ]; then
node script/yarn webpack --config $f --output-filename=$out --output-path=./.tmp --env mode=development
fi
done

View File

@@ -1,40 +1,65 @@
executor:
name: linux-docker
size: medium
steps:
- checkout:
path: src/electron
- run:
name: Setup third_party Depot Tools
command: |
name: Electron Lint
on:
workflow_call:
inputs:
container:
required: true
description: 'Container to run lint in'
type: string
concurrency:
group: electron-lint-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }}
jobs:
lint:
name: Lint
runs-on: electron-arc-linux-amd64-4core
timeout-minutes: 20
container: ${{ fromJSON(inputs.container) }}
steps:
- name: Checkout Electron
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
with:
path: src/electron
fetch-depth: 0
- name: Install Dependencies
run: |
cd src/electron
node script/yarn install --frozen-lockfile
- name: Setup third_party Depot Tools
shell: bash
run: |
# "depot_tools" has to be checkout into "//third_party/depot_tools" so pylint.py can a "pylintrc" file.
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git src/third_party/depot_tools
echo 'export PATH="$PATH:'"$PWD"'/src/third_party/depot_tools"' >> $BASH_ENV
- run:
name: Download GN Binary
command: |
echo "$(pwd)/src/third_party/depot_tools" >> $GITHUB_PATH
- name: Download GN Binary
shell: bash
run: |
chromium_revision="$(grep -A1 chromium_version src/electron/DEPS | tr -d '\n' | cut -d\' -f4)"
gn_version="$(curl -sL "https://chromium.googlesource.com/chromium/src/+/${chromium_revision}/DEPS?format=TEXT" | base64 -d | grep gn_version | head -n1 | cut -d\' -f4)"
cipd ensure -ensure-file - -root . \<<-CIPD
cipd ensure -ensure-file - -root . <<-CIPD
\$ServiceURL https://chrome-infra-packages.appspot.com/
@Subdir src/buildtools/linux64
gn/gn/linux-amd64 $gn_version
CIPD
echo 'export CHROMIUM_BUILDTOOLS_PATH="'"$PWD"'/src/buildtools"' >> $BASH_ENV
- run:
name: Download clang-format Binary
command: |
buildtools_path="$(pwd)/src/buildtools"
echo "CHROMIUM_BUILDTOOLS_PATH=$buildtools_path" >> $GITHUB_ENV
- name: Download clang-format Binary
shell: bash
run: |
chromium_revision="$(grep -A1 chromium_version src/electron/DEPS | tr -d '\n' | cut -d\' -f4)"
sha1_path='buildtools/linux64/clang-format.sha1'
curl -sL "https://chromium.googlesource.com/chromium/src/+/${chromium_revision}/${sha1_path}?format=TEXT" | base64 -d > "src/${sha1_path}"
download_from_google_storage.py --no_resume --no_auth --bucket chromium-clang-format -s "src/${sha1_path}"
- run:
name: Run Lint
command: |
- name: Run Lint
shell: bash
run: |
# gn.py tries to find a gclient root folder starting from the current dir.
# When it fails and returns "None" path, the whole script fails. Let's "fix" it.
touch .gclient
@@ -44,8 +69,9 @@ steps:
cd src/electron
node script/yarn install --frozen-lockfile
node script/yarn lint
- run:
name: Run Script Typechecker
command: |
- name: Run Script Typechecker
shell: bash
run: |
cd src/electron
node script/yarn tsc -p tsconfig.script.json

View File

@@ -0,0 +1,216 @@
name: Pipeline Segment - Electron Build
on:
workflow_call:
inputs:
environment:
description: using the production or testing environment
required: false
type: string
target-platform:
type: string
description: 'Platform to run on, can be macos or linux'
required: true
target-arch:
type: string
description: 'Arch to build for, can be x64, arm64 or arm'
required: true
build-runs-on:
type: string
description: 'What host to run the build'
required: true
build-container:
type: string
description: 'JSON container information for aks runs-on'
required: false
default: '{"image":null}'
is-release:
description: 'Whether this build job is a release job'
required: true
type: boolean
default: false
gn-build-type:
description: 'The gn build type - testing or release'
required: true
type: string
default: testing
generate-symbols:
description: 'Whether or not to generate symbols'
required: true
type: boolean
default: false
upload-to-storage:
description: 'Whether or not to upload build artifacts to external storage'
required: true
type: string
default: '0'
strip-binaries:
description: 'Strip the binaries before release (Linux only)'
required: false
type: boolean
default: false
is-asan:
description: 'Building the Address Sanitizer (ASan) Linux build'
required: false
type: boolean
default: false
concurrency:
group: electron-build-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ inputs.is-asan }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }}
env:
ELECTRON_ARTIFACTS_BLOB_STORAGE: ${{ secrets.ELECTRON_ARTIFACTS_BLOB_STORAGE }}
ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }}
ELECTRON_GITHUB_TOKEN: ${{ secrets.ELECTRON_GITHUB_TOKEN }}
GCLIENT_EXTRA_ARGS: ${{ inputs.target-platform == 'macos' && '--custom-var=checkout_mac=True --custom-var=host_os=mac' || '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' }}
ELECTRON_OUT_DIR: Default
jobs:
build:
runs-on: ${{ inputs.build-runs-on }}
container: ${{ fromJSON(inputs.build-container) }}
environment: ${{ inputs.environment }}
env:
TARGET_ARCH: ${{ inputs.target-arch }}
steps:
- name: Create src dir
run: mkdir src
- name: Checkout Electron
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
with:
path: src/electron
fetch-depth: 0
- name: Setup Node.js/npm
if: ${{ inputs.target-platform == 'macos' }}
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8
with:
node-version: 20.11.x
cache: yarn
cache-dependency-path: src/electron/yarn.lock
- name: Install Dependencies
run: |
cd src/electron
node script/yarn install --frozen-lockfile
- name: Install Python Tools (Mac)
if: ${{ inputs.target-platform == 'macos' }}
run: brew install python-setuptools
- name: Install AZCopy
if: ${{ inputs.target-platform == 'macos' }}
run: brew install azcopy
- name: Set GN_EXTRA_ARGS for Linux
if: ${{ inputs.target-platform == 'linux' }}
run: |
if [ "${{ inputs.target-arch }}" = "arm" ]; then
if [ "${{ inputs.is-release }}" = true ]; then
GN_EXTRA_ARGS='target_cpu="arm" build_tflite_with_xnnpack=false symbol_level=1'
else
GN_EXTRA_ARGS='target_cpu="arm" build_tflite_with_xnnpack=false'
fi
elif [ "${{ inputs.target-arch }}" = "arm64" ]; then
GN_EXTRA_ARGS='target_cpu="arm64" fatal_linker_warnings=false enable_linux_installer=false'
elif [ "${{ inputs.is-asan }}" = true ]; then
GN_EXTRA_ARGS='is_asan=true'
fi
echo "GN_EXTRA_ARGS=$GN_EXTRA_ARGS" >> $GITHUB_ENV
- name: Get Depot Tools
timeout-minutes: 5
run: |
git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
SEDOPTION="-i"
if [ "`uname`" = "Darwin" ]; then
SEDOPTION="-i ''"
fi
# remove ninjalog_uploader_wrapper.py from autoninja since we don't use it and it causes problems
sed $SEDOPTION '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
# Ensure depot_tools does not update.
test -d depot_tools && cd depot_tools
if [ "`uname`" = "Linux" ]; then
git apply --3way ../src/electron/.github/workflows/config/gclient.diff
fi
touch .disable_auto_update
- name: Add Depot Tools to PATH
run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH
- name: Generate DEPS Hash
run: |
node src/electron/script/generate-deps-hash.js && cat src/electron/.depshash-target
DEPSHASH=v1-src-cache-$(shasum src/electron/.depshash | cut -f1 -d' ')
echo "DEPSHASH=$DEPSHASH" >> $GITHUB_ENV
echo "CACHE_PATH=$DEPSHASH.tar" >> $GITHUB_ENV
- name: Restore src cache via AZCopy
if: ${{ inputs.target-platform == 'macos' }}
uses: ./src/electron/.github/actions/restore-cache-azcopy
- name: Restore src cache via AKS
if: ${{ inputs.target-platform == 'linux' }}
uses: ./src/electron/.github/actions/restore-cache-aks
- name: Checkout Electron
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
with:
path: src/electron
fetch-depth: 0
- name: Install Build Tools
uses: ./src/electron/.github/actions/install-build-tools
- name: Init Build Tools
run: |
e init -f --root=$(pwd) --out=Default ${{ inputs.gn-build-type }} --import ${{ inputs.gn-build-type }} --target-cpu ${{ inputs.target-arch }} --only-sdk
- name: Run Electron Only Hooks
run: |
gclient runhooks --spec="solutions=[{'name':'src/electron','url':None,'deps_file':'DEPS','custom_vars':{'process_deps':False},'managed':False}]"
- name: Regenerate DEPS Hash
run: |
(cd src/electron && git checkout .) && node src/electron/script/generate-deps-hash.js && cat src/electron/.depshash-target
echo "DEPSHASH=$(shasum src/electron/.depshash | cut -f1 -d' ')" >> $GITHUB_ENV
- name: Add CHROMIUM_BUILDTOOLS_PATH to env
run: echo "CHROMIUM_BUILDTOOLS_PATH=$(pwd)/src/buildtools" >> $GITHUB_ENV
- name: Fix Sync
uses: ./src/electron/.github/actions/fix-sync
with:
target-arch: ${{ inputs.target-arch }}
target-platform: ${{ inputs.target-platform }}
- name: Install build-tools & Setup RBE
run: |
echo "NUMBER_OF_NINJA_PROCESSES=${{ inputs.target-platform == 'linux' && '300' || '200' }}" >> $GITHUB_ENV
cd ~/.electron_build_tools
npx yarn --ignore-engines
# Pull down credential helper and print status
node -e "require('./src/utils/reclient.js').downloadAndPrepare({})"
HELPER=$(node -p "require('./src/utils/reclient.js').helperPath({})")
$HELPER login
echo 'RBE_service='`node -e "console.log(require('./src/utils/reclient.js').serviceAddress)"` >> $GITHUB_ENV
echo 'RBE_experimental_credentials_helper='`node -e "console.log(require('./src/utils/reclient.js').helperPath({}))"` >> $GITHUB_ENV
echo 'RBE_experimental_credentials_helper_args=print' >> $GITHUB_ENV
- name: Free up space (macOS)
if: ${{ inputs.target-platform == 'macos' }}
uses: ./src/electron/.github/actions/free-space-macos
- name: Build Electron
uses: ./src/electron/.github/actions/build-electron
with:
target-arch: ${{ inputs.target-arch }}
target-platform: ${{ inputs.target-platform }}
artifact-platform: ${{ inputs.target-platform == 'linux' && 'linux' || 'darwin' }}
is-release: '${{ inputs.is-release }}'
generate-symbols: '${{ inputs.generate-symbols }}'
strip-binaries: '${{ inputs.strip-binaries }}'
upload-to-storage: '${{ inputs.upload-to-storage }}'
is-asan: '${{ inputs.is-asan }}'
- name: Set GN_EXTRA_ARGS for MAS Build
if: ${{ inputs.target-platform == 'macos' }}
run: |
echo "MAS_BUILD=true" >> $GITHUB_ENV
GN_EXTRA_ARGS='is_mas_build=true'
echo "GN_EXTRA_ARGS=$GN_EXTRA_ARGS" >> $GITHUB_ENV
- name: Build Electron (MAS)
if: ${{ inputs.target-platform == 'macos' }}
uses: ./src/electron/.github/actions/build-electron
with:
target-arch: ${{ inputs.target-arch }}
target-platform: ${{ inputs.target-platform }}
artifact-platform: 'mas'
is-release: '${{ inputs.is-release }}'
generate-symbols: '${{ inputs.generate-symbols }}'
upload-to-storage: '${{ inputs.upload-to-storage }}'
step-suffix: '(mas)'

View File

@@ -0,0 +1,141 @@
name: Pipeline Segment - Electron GN Check
on:
workflow_call:
inputs:
target-platform:
type: string
description: 'Platform to run on, can be macos or linux'
required: true
target-arch:
type: string
description: 'Arch to build for, can be x64, arm64 or arm'
required: true
check-runs-on:
type: string
description: 'What host to run the tests on'
required: true
check-container:
type: string
description: 'JSON container information for aks runs-on'
required: false
default: '{"image":null}'
gn-build-type:
description: 'The gn build type - testing or release'
required: true
type: string
default: testing
is-asan:
description: 'Building the Address Sanitizer (ASan) Linux build'
required: false
type: boolean
default: false
concurrency:
group: electron-gn-check-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ inputs.is-asan }}-${{ github.ref }}
cancel-in-progress: true
env:
ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }}
GCLIENT_EXTRA_ARGS: ${{ inputs.target-platform == 'macos' && '--custom-var=checkout_mac=True --custom-var=host_os=mac' || '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' }}
ELECTRON_OUT_DIR: Default
TARGET_ARCH: ${{ inputs.target-arch }}
jobs:
gn-check:
# TODO(codebytere): Change this to medium VM
runs-on: ${{ inputs.check-runs-on }}
container: ${{ fromJSON(inputs.check-container) }}
env:
TARGET_ARCH: ${{ inputs.target-arch }}
steps:
- name: Checkout Electron
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
with:
path: src/electron
fetch-depth: 0
- name: Install Build Tools
uses: ./src/electron/.github/actions/install-build-tools
- name: Init Build Tools
run: |
e init -f --root=$(pwd) --out=Default ${{ inputs.gn-build-type }} --import ${{ inputs.gn-build-type }} --target-cpu ${{ inputs.target-arch }} --only-sdk
- name: Get Depot Tools
timeout-minutes: 5
run: |
git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
SEDOPTION="-i"
if [ "`uname`" = "Darwin" ]; then
SEDOPTION="-i ''"
fi
# remove ninjalog_uploader_wrapper.py from autoninja since we don't use it and it causes problems
sed $SEDOPTION '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
# Ensure depot_tools does not update.
test -d depot_tools && cd depot_tools
if [ "`uname`" = "Linux" ]; then
git apply --3way ../src/electron/.github/workflows/config/gclient.diff
fi
touch .disable_auto_update
- name: Add Depot Tools to PATH
run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH
- name: Set GN_EXTRA_ARGS for Linux
if: ${{ inputs.target-platform == 'linux' }}
run: |
if [ "${{ inputs.target-arch }}" = "arm" ]; then
GN_EXTRA_ARGS='build_tflite_with_xnnpack=false'
elif [ "${{ inputs.target-arch }}" = "arm64" ]; then
GN_EXTRA_ARGS='fatal_linker_warnings=false enable_linux_installer=false'
fi
echo "GN_EXTRA_ARGS=$GN_EXTRA_ARGS" >> $GITHUB_ENV
- name: Generate DEPS Hash
run: |
node src/electron/script/generate-deps-hash.js && cat src/electron/.depshash-target
DEPSHASH=v1-src-cache-$(shasum src/electron/.depshash | cut -f1 -d' ')
echo "DEPSHASH=$DEPSHASH" >> $GITHUB_ENV
echo "CACHE_PATH=$DEPSHASH.tar" >> $GITHUB_ENV
- name: Restore src cache via AZCopy
if: ${{ inputs.target-platform == 'macos' }}
uses: ./src/electron/.github/actions/restore-cache-azcopy
- name: Restore src cache via AKS
if: ${{ inputs.target-platform == 'linux' }}
uses: ./src/electron/.github/actions/restore-cache-aks
- name: Run Electron Only Hooks
run: |
gclient runhooks --spec="solutions=[{'name':'src/electron','url':None,'deps_file':'DEPS','custom_vars':{'process_deps':False},'managed':False}]"
- name: Regenerate DEPS Hash
run: |
(cd src/electron && git checkout .) && node src/electron/script/generate-deps-hash.js && cat src/electron/.depshash-target
echo "DEPSHASH=$(shasum src/electron/.depshash | cut -f1 -d' ')" >> $GITHUB_ENV
- name: Add CHROMIUM_BUILDTOOLS_PATH to env
run: echo "CHROMIUM_BUILDTOOLS_PATH=$(pwd)/src/buildtools" >> $GITHUB_ENV
- name: Checkout Electron
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
with:
path: src/electron
fetch-depth: 0
- name: Default GN gen
run: |
cd src/electron
git pack-refs
cd ..
e build --only-gen
- name: Run GN Check
run: |
cd src
gn check out/Default //electron:electron_lib
gn check out/Default //electron:electron_app
gn check out/Default //electron/shell/common/api:mojo
# Check the hunspell filenames
node electron/script/gen-hunspell-filenames.js --check
node electron/script/gen-libc++-filenames.js --check
- name: Wait for active SSH sessions
if: always() && !cancelled()
run: |
while [ -f /var/.ssh-lock ]
do
sleep 60
done

View File

@@ -0,0 +1,196 @@
name: Pipeline Segment - Electron Test
on:
workflow_call:
inputs:
target-platform:
type: string
description: 'Platform to run on, can be macos or linux'
required: true
target-arch:
type: string
description: 'Arch to build for, can be x64, arm64 or arm'
required: true
test-runs-on:
type: string
description: 'What host to run the tests on'
required: true
test-container:
type: string
description: 'JSON container information for aks runs-on'
required: false
default: '{"image":null}'
is-asan:
description: 'Building the Address Sanitizer (ASan) Linux build'
required: false
type: boolean
default: false
concurrency:
group: electron-test-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ inputs.is-asan }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }}
permissions:
contents: read
issues: read
pull-requests: read
env:
ELECTRON_OUT_DIR: Default
ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }}
ELECTRON_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
jobs:
test:
runs-on: ${{ inputs.test-runs-on }}
container: ${{ fromJSON(inputs.test-container) }}
strategy:
fail-fast: false
matrix:
build-type: ${{ inputs.target-platform == 'macos' && fromJSON('["darwin","mas"]') || fromJSON('["linux"]') }}
shard: ${{ inputs.target-platform == 'macos' && fromJSON('[1, 2]') || fromJSON('[1, 2, 3]') }}
env:
BUILD_TYPE: ${{ matrix.build-type }}
TARGET_ARCH: ${{ inputs.target-arch }}
ARTIFACT_KEY: ${{ matrix.build-type }}_${{ inputs.target-arch }}
steps:
- name: Fix node20 on arm32 runners
if: ${{ inputs.target-arch == 'arm' }}
run: |
cp $(which node) /mnt/runner-externals/node20/bin/
- name: Add TCC permissions on macOS
if: ${{ inputs.target-platform == 'macos' }}
run: |
configure_user_tccdb () {
local values=$1
local dbPath="$HOME/Library/Application Support/com.apple.TCC/TCC.db"
local sqlQuery="INSERT OR REPLACE INTO access VALUES($values);"
sqlite3 "$dbPath" "$sqlQuery"
}
configure_sys_tccdb () {
local values=$1
local dbPath="/Library/Application Support/com.apple.TCC/TCC.db"
local sqlQuery="INSERT OR REPLACE INTO access VALUES($values);"
sudo sqlite3 "$dbPath" "$sqlQuery"
}
userValuesArray=(
"'kTCCServiceMicrophone','/usr/local/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159"
"'kTCCServiceCamera','/usr/local/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159"
"'kTCCServiceBluetoothAlways','/usr/local/opt/runner/provisioner/provisioner',1,2,4,1,NULL,NULL,0,'UNUSED',NULL,0,1687786159"
)
for values in "${userValuesArray[@]}"; do
# Sonoma and higher have a few extra values
# Ref: https://github.com/actions/runner-images/blob/main/images/macos/scripts/build/configure-tccdb-macos.sh
if [ "$OSTYPE" = "darwin23" ]; then
configure_user_tccdb "$values,NULL,NULL,'UNUSED',${values##*,}"
configure_sys_tccdb "$values,NULL,NULL,'UNUSED',${values##*,}"
else
configure_user_tccdb "$values"
configure_sys_tccdb "$values"
fi
done
- name: Checkout Electron
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
with:
path: src/electron
fetch-depth: 0
- name: Install Dependencies
run: |
cd src/electron
node script/yarn install --frozen-lockfile
- name: Get Depot Tools
timeout-minutes: 5
run: |
git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
if [ "`uname`" = "Darwin" ]; then
# remove ninjalog_uploader_wrapper.py from autoninja since we don't use it and it causes problems
sed -i '' '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
else
sed -i '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
# Remove swift-format dep from cipd on macOS until we send a patch upstream.
cd depot_tools
git apply --3way ../src/electron/.github/workflows/config/gclient.diff
fi
# Ensure depot_tools does not update.
test -d depot_tools && cd depot_tools
touch .disable_auto_update
- name: Add Depot Tools to PATH
run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH
- name: Load ASan specific environment variables
if: ${{ inputs.is-asan == true }}
run: |
echo "ARTIFACT_KEY=${{ matrix.build-type }}_${{ inputs.target-arch }}_asan" >> $GITHUB_ENV
echo "DISABLE_CRASH_REPORTER_TESTS=true" >> $GITHUB_ENV
echo "IS_ASAN=true" >> $GITHUB_ENV
- name: Download Generated Artifacts
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e
with:
name: generated_artifacts_${{ env.ARTIFACT_KEY }}
path: ./generated_artifacts_${{ matrix.build-type }}_${{ inputs.target-arch }}
- name: Download Src Artifacts
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e
with:
name: src_artifacts_${{ env.ARTIFACT_KEY }}
path: ./src_artifacts_${{ matrix.build-type }}_${{ inputs.target-arch }}
- name: Restore Generated Artifacts
run: ./src/electron/script/actions/restore-artifacts.sh
- name: Unzip Dist, Mksnapshot & Chromedriver
run: |
cd src/out/Default
unzip -:o dist.zip
unzip -:o chromedriver.zip
unzip -:o mksnapshot.zip
- name: Import & Trust Self-Signed Codesigning Cert on MacOS
if: ${{ inputs.target-platform == 'macos' && inputs.target-arch == 'x64' }}
run: |
sudo security authorizationdb write com.apple.trust-settings.admin allow
cd src/electron
./script/codesign/generate-identity.sh
- name: Run Electron Tests
shell: bash
env:
MOCHA_REPORTER: mocha-multi-reporters
ELECTRON_TEST_RESULTS_DIR: junit
MOCHA_MULTI_REPORTERS: mocha-junit-reporter, tap
ELECTRON_DISABLE_SECURITY_WARNINGS: 1
ELECTRON_SKIP_NATIVE_MODULE_TESTS: true
DISPLAY: ':99.0'
run: |
cd src/electron
# Get which tests are on this shard
tests_files=$(node script/split-tests ${{ matrix.shard }} ${{ inputs.target-platform == 'macos' && 2 || 3 }})
# Run tests
if [ "`uname`" = "Darwin" ]; then
echo "About to start tests"
node script/yarn test --runners=main --trace-uncaught --enable-logging --files $tests_files
else
chown :builduser .. && chmod g+w ..
chown -R :builduser . && chmod -R g+w .
chmod 4755 ../out/Default/chrome-sandbox
runuser -u builduser -- git config --global --add safe.directory $(pwd)
if [ "${{ inputs.is-asan }}" == "true" ]; then
cd ..
ASAN_SYMBOLIZE="$PWD/tools/valgrind/asan/asan_symbolize.py --executable-path=$PWD/out/Default/electron"
export ASAN_OPTIONS="symbolize=0 handle_abort=1"
export G_SLICE=always-malloc
export NSS_DISABLE_ARENA_FREE_LIST=1
export NSS_DISABLE_UNLOAD=1
export LLVM_SYMBOLIZER_PATH=$PWD/third_party/llvm-build/Release+Asserts/bin/llvm-symbolizer
export MOCHA_TIMEOUT=180000
echo "Piping output to ASAN_SYMBOLIZE ($ASAN_SYMBOLIZE)"
cd electron
runuser -u builduser -- xvfb-run script/actions/run-tests.sh script/yarn test --runners=main --trace-uncaught --enable-logging --files $tests_files | $ASAN_SYMBOLIZE
else
runuser -u builduser -- xvfb-run script/actions/run-tests.sh script/yarn test --runners=main --trace-uncaught --enable-logging --files $tests_files
fi
fi
- name: Wait for active SSH sessions
if: always() && !cancelled()
run: |
while [ -f /var/.ssh-lock ]
do
sleep 60
done

View File

@@ -0,0 +1,165 @@
name: Pipeline Segment - Node/Nan Test
on:
workflow_call:
inputs:
target-platform:
type: string
description: 'Platform to run on, can be macos or linux'
required: true
target-arch:
type: string
description: 'Arch to build for, can be x64, arm64 or arm'
required: true
test-runs-on:
type: string
description: 'What host to run the tests on'
required: true
test-container:
type: string
description: 'JSON container information for aks runs-on'
required: false
default: '{"image":null}'
gn-build-type:
description: 'The gn build type - testing or release'
required: true
type: string
default: testing
concurrency:
group: electron-node-nan-test-${{ inputs.target-platform }}-${{ inputs.target-arch }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' && !endsWith(github.ref, '-x-y') }}
env:
ELECTRON_OUT_DIR: Default
ELECTRON_RBE_JWT: ${{ secrets.ELECTRON_RBE_JWT }}
jobs:
node-tests:
name: Run Node.js Tests
runs-on: electron-arc-linux-amd64-8core
timeout-minutes: 20
env:
TARGET_ARCH: ${{ inputs.target-arch }}
BUILD_TYPE: linux
container: ${{ fromJSON(inputs.test-container) }}
steps:
- name: Checkout Electron
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
with:
path: src/electron
fetch-depth: 0
- name: Install Build Tools
uses: ./src/electron/.github/actions/install-build-tools
- name: Init Build Tools
run: |
e init -f --root=$(pwd) --out=Default ${{ inputs.gn-build-type }} --import ${{ inputs.gn-build-type }} --target-cpu ${{ inputs.target-arch }}
- name: Install Dependencies
run: |
cd src/electron
node script/yarn install --frozen-lockfile
- name: Get Depot Tools
timeout-minutes: 5
run: |
git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
sed -i '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
cd depot_tools
git apply --3way ../src/electron/.github/workflows/config/gclient.diff
# Ensure depot_tools does not update.
test -d depot_tools && cd depot_tools
touch .disable_auto_update
- name: Add Depot Tools to PATH
run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH
- name: Download Generated Artifacts
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e
with:
name: generated_artifacts_${{ env.BUILD_TYPE }}_${{ env.TARGET_ARCH }}
path: ./generated_artifacts_${{ env.BUILD_TYPE }}_${{ env.TARGET_ARCH }}
- name: Download Src Artifacts
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e
with:
name: src_artifacts_linux_${{ env.TARGET_ARCH }}
path: ./src_artifacts_linux_${{ env.TARGET_ARCH }}
- name: Restore Generated Artifacts
run: ./src/electron/script/actions/restore-artifacts.sh
- name: Unzip Dist
run: |
cd src/out/Default
unzip -:o dist.zip
- name: Setup Linux for Headless Testing
run: sh -e /etc/init.d/xvfb start
- name: Run Node.js Tests
run: |
cd src
node electron/script/node-spec-runner.js --default --jUnitDir=junit
- name: Wait for active SSH sessions
if: always() && !cancelled()
run: |
while [ -f /var/.ssh-lock ]
do
sleep 60
done
nan-tests:
name: Run Nan Tests
runs-on: electron-arc-linux-amd64-4core
timeout-minutes: 20
env:
TARGET_ARCH: ${{ inputs.target-arch }}
BUILD_TYPE: linux
container: ${{ fromJSON(inputs.test-container) }}
steps:
- name: Checkout Electron
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
with:
path: src/electron
fetch-depth: 0
- name: Install Build Tools
uses: ./src/electron/.github/actions/install-build-tools
- name: Init Build Tools
run: |
e init -f --root=$(pwd) --out=Default ${{ inputs.gn-build-type }}
- name: Install Dependencies
run: |
cd src/electron
node script/yarn install --frozen-lockfile
- name: Get Depot Tools
timeout-minutes: 5
run: |
git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
sed -i '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
cd depot_tools
git apply --3way ../src/electron/.github/workflows/config/gclient.diff
# Ensure depot_tools does not update.
test -d depot_tools && cd depot_tools
touch .disable_auto_update
- name: Add Depot Tools to PATH
run: echo "$(pwd)/depot_tools" >> $GITHUB_PATH
- name: Download Generated Artifacts
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e
with:
name: generated_artifacts_${{ env.BUILD_TYPE }}_${{ env.TARGET_ARCH }}
path: ./generated_artifacts_${{ env.BUILD_TYPE }}_${{ env.TARGET_ARCH }}
- name: Download Src Artifacts
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e
with:
name: src_artifacts_linux_${{ env.TARGET_ARCH }}
path: ./src_artifacts_linux_${{ env.TARGET_ARCH }}
- name: Restore Generated Artifacts
run: ./src/electron/script/actions/restore-artifacts.sh
- name: Unzip Dist
run: |
cd src/out/Default
unzip -:o dist.zip
- name: Setup Linux for Headless Testing
run: sh -e /etc/init.d/xvfb start
- name: Run Node.js Tests
run: |
cd src
node electron/script/nan-spec-runner.js
- name: Wait for active SSH sessions
if: always() && !cancelled()
run: |
while [ -f /var/.ssh-lock ]
do
sleep 60
done

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.139',
'122.0.6261.156',
'node_version':
'v20.9.0',
'nan_version':

View File

@@ -1,6 +1,6 @@
[![Electron Logo](https://electronjs.org/images/electron-logo.svg)](https://electronjs.org)
[![CircleCI Build Status](https://circleci.com/gh/electron/electron/tree/main.svg?style=shield)](https://circleci.com/gh/electron/electron/tree/main)
[![GitHub Actions Build Status](https://github.com/electron/electron/actions/workflows/build.yml/badge.svg)](https://github.com/electron/electron/actions/workflows/build.yml)
[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/4lggi9dpjc1qob7k/branch/main?svg=true)](https://ci.appveyor.com/project/electron-bot/electron-ljo26/branch/main)
[![Electron Discord Invite](https://img.shields.io/discord/745037351163527189?color=%237289DA&label=chat&logo=discord&logoColor=white)](https://discord.gg/electronjs)

View File

@@ -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`.
@@ -1354,7 +1354,7 @@ Show the app's about panel options. These options can be overridden with `app.se
* `credits` string (optional) _macOS_ _Windows_ - Credit information.
* `authors` string[] (optional) _Linux_ - List of app authors.
* `website` string (optional) _Linux_ - The app's website.
* `iconPath` string (optional) _Linux_ _Windows_ - Path to the app's icon in a JPEG or PNG file format. On Linux, will be shown as 64x64 pixels while retaining aspect ratio.
* `iconPath` string (optional) _Linux_ _Windows_ - Path to the app's icon in a JPEG or PNG file format. On Linux, will be shown as 64x64 pixels while retaining aspect ratio. On Windows, a 48x48 PNG will result in the best visual quality.
Set the about panel options. This will override the values defined in the app's `.plist` file on macOS. See the [Apple docs][about-panel-options] for more details. On Linux, values must be set in order to be shown; there are no defaults.

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)

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

@@ -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

@@ -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.

View File

@@ -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

@@ -78,8 +78,7 @@ Electron
## Structure of Other Directories
* **.circleci** - Config file for CI with CircleCI.
* **.github** - GitHub-specific config files including issues templates and CODEOWNERS.
* **.github** - GitHub-specific config files including issues templates, CI with GitHub Actions and CODEOWNERS.
* **dist** - Temporary directory created by `script/create-dist.py` script
when creating a distribution.
* **node_modules** - Third party node modules used for building.

View File

@@ -9,7 +9,7 @@ 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 | 🚫 |

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

@@ -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",
@@ -543,7 +543,6 @@ filenames = {
"shell/common/api/electron_api_clipboard.h",
"shell/common/api/electron_api_command_line.cc",
"shell/common/api/electron_api_environment.cc",
"shell/common/api/electron_api_key_weak_map.h",
"shell/common/api/electron_api_native_image.cc",
"shell/common/api/electron_api_native_image.h",
"shell/common/api/electron_api_net.cc",
@@ -555,8 +554,6 @@ filenames = {
"shell/common/api/electron_bindings.cc",
"shell/common/api/electron_bindings.h",
"shell/common/api/features.cc",
"shell/common/api/object_life_monitor.cc",
"shell/common/api/object_life_monitor.h",
"shell/common/application_info.cc",
"shell/common/application_info.h",
"shell/common/asar/archive.cc",

View File

@@ -518,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,14 @@
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
cherry-pick-771e74ab497d.patch
cherry-pick-8f07d39227f6.patch
cherry-pick-b3c64851765c.patch
cherry-pick-9463ce9cd8d9.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,116 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Antonio Maiorano <amaiorano@google.com>
Date: Thu, 20 Jun 2024 14:02:42 -0400
Subject: indvars: don't replace a phi when that breaks LCSSA (#6695)
Induction variable simplification (indvars) tries to rewrite exit
values; these appear as phi nodes in loop exit blocks. If the
replacement for the phi is still in the loop, then that would break the
LCSSA property. Don't do that.
Add a test for this.
Bug: chromium:345993680
Change-Id: Ib2330afa3c6f47373cb4336cfd00e851044fea3a
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5645925
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/lib/Transforms/Scalar/IndVarSimplify.cpp b/lib/Transforms/Scalar/IndVarSimplify.cpp
index f5b1455d5932b63dfef699991c5eeab38e447a7d..e6ff7b3ab4d81bbb782f0bd0a7b5185a30fd1285 100644
--- a/lib/Transforms/Scalar/IndVarSimplify.cpp
+++ b/lib/Transforms/Scalar/IndVarSimplify.cpp
@@ -24,7 +24,6 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/Transforms/Scalar.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
@@ -41,11 +40,13 @@
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
#include "llvm/IR/PatternMatch.h"
#include "llvm/IR/Type.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Transforms/Utils/SimplifyIndVar.h"
@@ -698,6 +699,16 @@ void IndVarSimplify::RewriteLoopExitValues(Loop *L, SCEVExpander &Rewriter) {
continue;
}
+ // HLSL Change Begin
+ // Avoid breaking LCSSA: Don't replace the PHI if its replacement
+ // is defined inside the loop.
+ if (auto *ExitValInst = dyn_cast<Instruction>(ExitVal)) {
+ if (L->contains(ExitValInst)) {
+ continue;
+ }
+ }
+ // HLSL Change End
+
// Collect all the candidate PHINodes to be rewritten.
RewritePhiSet.push_back(
RewritePhi(PN, i, ExitVal, HighCost, LCSSASafePhiForRAUW));
diff --git a/test/HLSL/passes/indvars/preserve-phi-when-replacement-is-in-loop.ll b/test/HLSL/passes/indvars/preserve-phi-when-replacement-is-in-loop.ll
new file mode 100644
index 0000000000000000000000000000000000000000..b550ce993837814229f8223a47b2af328cc7c87c
--- /dev/null
+++ b/test/HLSL/passes/indvars/preserve-phi-when-replacement-is-in-loop.ll
@@ -0,0 +1,49 @@
+; RUN: opt < %s -indvars -S | FileCheck %s
+
+; The inner loop (%header1) has a fixed trip count.
+; The indvars pass is tempted to delete the phi instruction %hexit,
+; and replace its uses with %add3.
+; But %hexit is used in %latch0, which is outside the inner loop and
+; its exit block. Deleting the phi %hexit would break LCSSA form.
+
+; CHECK: @main
+; CHECK: exit1:
+; CHECK-NEXT: %hexit = phi i32 [ %hnext, %header1 ]
+; CHECK-NEXT: br label %latch0
+
+; CHECK: latch0:
+
+target triple = "dxil-ms-dx"
+
+define void @main(i32 %arg) {
+entry:
+ br label %header0
+
+header0:
+ %isgt0 = icmp sgt i32 %arg, 0
+ %smax = select i1 %isgt0, i32 %arg, i32 0
+ %h0 = add i32 %smax, 1
+ %j0 = add i32 %smax, 2
+ %doinner = icmp slt i32 %j0, 1
+ br i1 %doinner, label %header1.pre, label %latch0
+
+header1.pre:
+ br label %header1
+
+header1:
+ %hi = phi i32 [ %hnext, %header1 ], [ %h0, %header1.pre ]
+ %ji = phi i32 [ %jnext, %header1 ], [ %j0, %header1.pre ]
+ %add3 = add i32 %smax, 3
+ %hnext = add i32 %hi, 1
+ %jnext = add nsw i32 %ji, 1 ; the nsw here is essential
+ %do1again = icmp slt i32 %ji, %add3
+ br i1 %do1again, label %header1, label %exit1
+
+exit1:
+ %hexit = phi i32 [ %hnext, %header1 ]
+ br label %latch0
+
+latch0:
+ %useh = phi i32 [ %h0, %header0 ], [ %hexit, %exit1 ]
+ br label %header0
+}

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,151 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Antonio Maiorano <amaiorano@google.com>
Date: Thu, 20 Jun 2024 14:49:58 -0400
Subject: Fix crash in scalarrepl-param-hlsl when dynamically indexing a GEP of
a constant indexed GEP (#6670)
When processing global values to determine when to flatten vectors, this
pass was only checking the immdiate users of the value for non-dynamic
indexing of the vector. But this would fail in the case of a dynamic
indexed GEP of a constant indexed GEP (e.g. h[0][a]) because the first
level GEP was constant indexed, but not the second. We fix this by
checking the full User tree of the value in `hasDynamicVectorIndexing`.
Bug: chromium:342428008
Change-Id: Ibf2ae3a6528cfc9b50634058385c5a45aa1d3b75
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5645927
Reviewed-by: James Price <jrprice@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp b/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp
index 9b843ef0e49e554001b827e30eb6256853d90f5b..b1b38c0ee038dedb2064f5726663992a5bec736b 100644
--- a/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp
+++ b/lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp
@@ -1645,6 +1645,10 @@ bool hasDynamicVectorIndexing(Value *V) {
}
}
}
+ // Also recursively check the uses of this User to find a possible
+ // dynamically indexed GEP of this GEP.
+ if (hasDynamicVectorIndexing(U))
+ return true;
}
return false;
}
diff --git a/tools/clang/test/DXC/Passes/ScalarReplHLSL/scalarrepl-param-hlsl-dyn-idx-gep-of-const-idx-gep.ll b/tools/clang/test/DXC/Passes/ScalarReplHLSL/scalarrepl-param-hlsl-dyn-idx-gep-of-const-idx-gep.ll
new file mode 100644
index 0000000000000000000000000000000000000000..04fdea1500e75266a59705a1c2da98a4aef7391c
--- /dev/null
+++ b/tools/clang/test/DXC/Passes/ScalarReplHLSL/scalarrepl-param-hlsl-dyn-idx-gep-of-const-idx-gep.ll
@@ -0,0 +1,111 @@
+; RUN: %dxopt %s -hlsl-passes-resume -scalarrepl-param-hlsl -S | FileCheck %s
+
+; Produced from the following HLSL:
+; static int4 g[4] = (int4[4])0;
+; static int4 h[4] = (int4[4])0;
+;
+; [numthreads(1, 1, 1)]
+; void main() {
+; int a = 0;
+; int b = h[0][a];
+; h = g;
+; }
+;
+; This was crashing in scalarrepl-param-hlsl because it was attempting to flatten
+; global variable 'h' even though it is dynamically indexed. This was not detected
+; because the resulting IR was a dynamically indexed GEP of a constant-indexed GEP,
+; and the code was only checking the immediate users of 'h':
+;
+; %1 = getelementptr <4 x i32>, <4 x i32>* getelementptr inbounds ([4 x <4 x i32>], [4 x <4 x i32>]* @h, i32 0, i32 0), i32 0, i32 %0, !dbg !26 ; line:7 col:11
+;
+; Verify that it does not get flattened
+; CHECK: %1 = getelementptr <4 x i32>, <4 x i32>* getelementptr inbounds ([4 x <4 x i32>], [4 x <4 x i32>]* @g, i32 0, i32 0), i32 0, i32 %0
+
+;
+; 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
+;
+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"
+
+%ConstantBuffer = type opaque
+
+@h = internal global [4 x <4 x i32>] zeroinitializer, align 4
+@g = internal global [4 x <4 x i32>] zeroinitializer, align 4
+@"$Globals" = external constant %ConstantBuffer
+
+; Function Attrs: nounwind
+define void @main() #0 {
+entry:
+ %a = alloca i32, align 4
+ %b = alloca i32, align 4
+ store i32 0, i32* %a, align 4, !dbg !17, !tbaa !21 ; line:6 col:7
+ %0 = load i32, i32* %a, align 4, !dbg !25, !tbaa !21 ; line:7 col:16
+ %1 = getelementptr <4 x i32>, <4 x i32>* getelementptr inbounds ([4 x <4 x i32>], [4 x <4 x i32>]* @h, i32 0, i32 0), i32 0, i32 %0, !dbg !26 ; line:7 col:11
+ %2 = load i32, i32* %1, !dbg !26, !tbaa !21 ; line:7 col:11
+ store i32 %2, i32* %b, align 4, !dbg !27, !tbaa !21 ; line:7 col:7
+ %3 = bitcast [4 x <4 x i32>]* @h to i8*, !dbg !28 ; line:8 col:7
+ %4 = bitcast [4 x <4 x i32>]* @g to i8*, !dbg !28 ; line:8 col:7
+ call void @llvm.memcpy.p0i8.p0i8.i64(i8* %3, i8* %4, i64 64, i32 1, i1 false), !dbg !28 ; line:8 col:7
+ ret void, !dbg !29 ; line:9 col:1
+}
+
+; Function Attrs: nounwind
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1) #0
+
+attributes #0 = { nounwind }
+
+!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 0}
+!4 = !{i32 1, i32 8}
+!5 = !{!"cs", i32 6, i32 0}
+!6 = !{i32 1, void ()* @main, !7}
+!7 = !{!8}
+!8 = !{i32 1, !9, !9}
+!9 = !{}
+!10 = !{void ()* @main, !"main", null, !11, null}
+!11 = !{null, null, !12, null}
+!12 = !{!13}
+!13 = !{i32 0, %ConstantBuffer* @"$Globals", !"$Globals", i32 0, i32 -1, i32 1, i32 0, null}
+!14 = !{void ()* @main, i32 5, i32 1, i32 1, i32 1}
+!15 = !{i32 64}
+!16 = !{i32 -1}
+!17 = !DILocation(line: 6, column: 7, scope: !18)
+!18 = !DISubprogram(name: "main", scope: !19, file: !19, line: 5, type: !20, isLocal: false, isDefinition: true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false, function: void ()* @main)
+!19 = !DIFile(filename: "/mnt/c/Users/amaiorano/Downloads/342428008/standalone_reduced.hlsl", directory: "")
+!20 = !DISubroutineType(types: !9)
+!21 = !{!22, !22, i64 0}
+!22 = !{!"int", !23, i64 0}
+!23 = !{!"omnipotent char", !24, i64 0}
+!24 = !{!"Simple C/C++ TBAA"}
+!25 = !DILocation(line: 7, column: 16, scope: !18)
+!26 = !DILocation(line: 7, column: 11, scope: !18)
+!27 = !DILocation(line: 7, column: 7, scope: !18)
+!28 = !DILocation(line: 8, column: 7, scope: !18)
+!29 = !DILocation(line: 9, column: 1, scope: !18)

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,261 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: David Neto <dneto@google.com>
Date: Tue, 16 Jul 2024 16:34:52 -0400
Subject: Add CMake option DXC_CODEGEN_EXCEPTIONS_TRAP (#6764)
When enabled, any hlsl::Exception thrown during code generation and
optimization will cause the process to trap.
Bug: 346618785
Change-Id: I9ac966d339ec3090e3455d51a9d7516cc5a3f153
HLMatrixLower: allow exceptions to propagate out (#6710)
If an exception is thrown, don't block it in the TempOverloadPool
destructor. Allow it to propagate out as a user-visible error.
Explicitly clear the TempOverloadPool before returning from the
HLMatrixLowerPass::runOnModule. In the normal case, when no exception is
thrown, that will still verify that all the overloads actually have been
lowered, and will assert out if they aren't.
Bug: 346618785
Change-Id: Id421ca324e4d799477a41abb14b966e8f39be482
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5715228
Reviewed-by: Natalie Chouinard <chouinard@google.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 15097b8473bf9f6c2b6c28ac095936616aa917f6..ac35ebd1a6afd55934da502ddb0e0c286da10db8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -104,6 +104,9 @@ endif()
option(DXC_DISABLE_ALLOCATOR_OVERRIDES "Disable usage of allocator overrides" OFF)
mark_as_advanced(DXC_DISABLE_ALLOCATOR_OVERRIDES)
+option(DXC_CODEGEN_EXCEPTIONS_TRAP "An exception in code generation generates a trap, ending the compiler process" OFF)
+mark_as_advanced(DXC_CODEGEN_EXCEPTIONS_TRAP)
+
# adjust link option to enable debugging from kernel mode; not compatible with incremental linking
if(NOT CMAKE_VERSION VERSION_LESS "3.13" AND WIN32 AND NOT CMAKE_C_COMPILER_ARCHITECTURE_ID STREQUAL "ARM64EC")
add_link_options(/DEBUGTYPE:CV,FIXUP,PDATA /INCREMENTAL:NO)
diff --git a/include/dxc/config.h.cmake b/include/dxc/config.h.cmake
index 6d7450323ec864ef5f6e8796c46423d49f278b76..7226ed75a108f63c3c894b59eb7e0dbc5fb66002 100644
--- a/include/dxc/config.h.cmake
+++ b/include/dxc/config.h.cmake
@@ -1,2 +1,4 @@
/* Disable overriding memory allocators. */
#cmakedefine DXC_DISABLE_ALLOCATOR_OVERRIDES
+/* Generate a trap if an hlsl::Exception is thrown during code generation */
+#cmakedefine DXC_CODEGEN_EXCEPTIONS_TRAP
diff --git a/lib/HLSL/HLMatrixLowerPass.cpp b/lib/HLSL/HLMatrixLowerPass.cpp
index d5959eb9335465f67d8e7ef7d7ab4eb720274226..3bb9f65834ecfd0c7a25c8a176f62c124e9967e5 100644
--- a/lib/HLSL/HLMatrixLowerPass.cpp
+++ b/lib/HLSL/HLMatrixLowerPass.cpp
@@ -60,7 +60,12 @@ class TempOverloadPool {
public:
TempOverloadPool(llvm::Module &Module, const char *BaseName)
: Module(Module), BaseName(BaseName) {}
- ~TempOverloadPool() { clear(); }
+ ~TempOverloadPool() {
+ if (!Funcs.empty()) {
+ // The flow has thrown an exception. Let that exception
+ // propagate out and be reported as a compile error.
+ }
+ }
Function *get(FunctionType *Ty);
bool contains(FunctionType *Ty) const { return Funcs.count(Ty) != 0; }
@@ -248,12 +253,15 @@ bool HLMatrixLowerPass::runOnModule(Module &M) {
m_matToVecStubs = nullptr;
m_vecToMatStubs = nullptr;
- // If you hit an assert during TempOverloadPool destruction,
+ // If you hit an assert while clearing TempOverloadPool,
// it means that either a matrix producer was lowered,
// causing a translation stub to be created,
// but the consumer of that matrix was never (properly) lowered.
// Or the opposite: a matrix consumer was lowered and not its producer.
+ matToVecStubs.clear();
+ vecToMatStubs.clear();
+
return true;
}
diff --git a/tools/clang/lib/CodeGen/BackendUtil.cpp b/tools/clang/lib/CodeGen/BackendUtil.cpp
index 294ca05946eed6d87a3ad4e2b56a641d24065760..1e9adb40f4bae4cada42b5581582d50dc3676594 100644
--- a/tools/clang/lib/CodeGen/BackendUtil.cpp
+++ b/tools/clang/lib/CodeGen/BackendUtil.cpp
@@ -8,6 +8,10 @@
//===----------------------------------------------------------------------===//
#include "clang/CodeGen/BackendUtil.h"
+#include "dxc/HLSL/DxilGenerationPass.h" // HLSL Change
+#include "dxc/HLSL/HLMatrixLowerPass.h" // HLSL Change
+#include "dxc/Support/Global.h" // HLSL Change
+#include "dxc/config.h" // HLSL Change
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetOptions.h"
@@ -41,10 +45,8 @@
#include "llvm/Transforms/ObjCARC.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/SymbolRewriter.h"
+#include <cstdio>
#include <memory>
-#include "dxc/HLSL/DxilGenerationPass.h" // HLSL Change
-#include "dxc/HLSL/HLMatrixLowerPass.h" // HLSL Change
-#include "dxc/Support/Global.h" // HLSL Change
using namespace clang;
using namespace llvm;
@@ -780,6 +782,13 @@ void clang::EmitBackendOutput(DiagnosticsEngine &Diags,
} catch (const ::hlsl::Exception &hlslException) {
Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Error, "%0\n"))
<< StringRef(hlslException.what());
+#if defined(DXC_CODEGEN_EXCEPTIONS_TRAP)
+ // llvm::errs() doesn't work in release builds on Linux.
+ // Use C-style fprintf because it works everywhere.
+ fprintf(stderr, "internal codegen error: %s\n", hlslException.what());
+ fflush(stderr);
+ LLVM_BUILTIN_TRAP;
+#endif
} // HLSL Change Ends
// If an optional clang TargetInfo description string was passed in, use it to
diff --git a/tools/clang/test/DXC/Passes/HLMatrixLower/dont_crash_on_invalid_cast.ll b/tools/clang/test/DXC/Passes/HLMatrixLower/dont_crash_on_invalid_cast.ll
new file mode 100644
index 0000000000000000000000000000000000000000..fca52d11595d3ac99dedb28219f0746a26add6c9
--- /dev/null
+++ b/tools/clang/test/DXC/Passes/HLMatrixLower/dont_crash_on_invalid_cast.ll
@@ -0,0 +1,130 @@
+; RUN: not %dxopt %s -hlsl-passes-resume -hlmatrixlower -S | FileCheck %s
+
+
+; The HL matrix lowering pass can sometimes throw an exception
+; due to an invalid LLVM-level cast<Ty> call. Make sure that
+; propagates out to a user-level error.
+
+; Note: There is still a bug in the compiler here. Not all matrix
+; lowerings are covered by the pass.
+
+; TODO: Fix the underlying bug https://github.com/microsoft/DirectXShaderCompiler/issues/6723
+; Once that is fixed, this test changes or should be deleted.
+
+
+; CHECK: Operation failed - error code
+
+;
+; 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
+;
+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"
+
+%ConstantBuffer = type opaque
+%class.matrix.float.2.4 = type { [2 x <4 x float>] }
+%struct.e = type { [1 x %struct.d], [1 x %struct.d] }
+%struct.d = type { %struct.a }
+%struct.a = type { float, %class.matrix.float.2.4 }
+
+@"$Globals" = external constant %ConstantBuffer
+@g.0.0.0 = internal global [1 x float] undef, align 4
+@g.0.0.1 = internal global [1 x %class.matrix.float.2.4] undef, align 4
+@g.1.0.0 = internal global [1 x float] undef, align 4
+@g.1.0.1 = internal global [1 x %class.matrix.float.2.4] undef, align 4
+
+; Function Attrs: nounwind
+define void @main() #0 {
+entry:
+ %h.0.1 = alloca %class.matrix.float.2.4, !dbg !26 ; line:13 col:17
+ store float 0.000000e+00, float* getelementptr inbounds ([1 x float], [1 x float]* @g.0.0.0, i32 0, i32 0), !dbg !26 ; line:13 col:17
+ %0 = call %class.matrix.float.2.4 @"dx.hl.init.rn.%class.matrix.float.2.4 (i32, <8 x float>)"(i32 0, <8 x float> zeroinitializer) #0, !dbg !26 ; line:13 col:17
+ %1 = call %class.matrix.float.2.4 @"dx.hl.cast.rowMatToColMat.%class.matrix.float.2.4 (i32, %class.matrix.float.2.4)"(i32 7, %class.matrix.float.2.4 %0) #0, !dbg !26 ; line:13 col:17
+ %2 = call %class.matrix.float.2.4 @"dx.hl.matldst.colStore.%class.matrix.float.2.4 (i32, %class.matrix.float.2.4*, %class.matrix.float.2.4)"(i32 1, %class.matrix.float.2.4* getelementptr inbounds ([1 x %class.matrix.float.2.4], [1 x %class.matrix.float.2.4]* @g.0.0.1, i32 0, i32 0), %class.matrix.float.2.4 %1) #0, !dbg !26 ; line:13 col:17
+ store float 0.000000e+00, float* getelementptr inbounds ([1 x float], [1 x float]* @g.1.0.0, i32 0, i32 0), !dbg !26 ; line:13 col:17
+ %3 = call %class.matrix.float.2.4 @"dx.hl.init.rn.%class.matrix.float.2.4 (i32, <8 x float>)"(i32 0, <8 x float> zeroinitializer) #0, !dbg !26 ; line:13 col:17
+ %4 = call %class.matrix.float.2.4 @"dx.hl.cast.rowMatToColMat.%class.matrix.float.2.4 (i32, %class.matrix.float.2.4)"(i32 7, %class.matrix.float.2.4 %3) #0, !dbg !26 ; line:13 col:17
+ %5 = call %class.matrix.float.2.4 @"dx.hl.matldst.colStore.%class.matrix.float.2.4 (i32, %class.matrix.float.2.4*, %class.matrix.float.2.4)"(i32 1, %class.matrix.float.2.4* getelementptr inbounds ([1 x %class.matrix.float.2.4], [1 x %class.matrix.float.2.4]* @g.1.0.1, i32 0, i32 0), %class.matrix.float.2.4 %4) #0, !dbg !26 ; line:13 col:17
+ %6 = load float, float* getelementptr inbounds ([1 x float], [1 x float]* @g.1.0.0, i32 0, i32 0), !dbg !32 ; line:17 col:9
+ %7 = getelementptr inbounds %class.matrix.float.2.4, %class.matrix.float.2.4* %h.0.1, i32 0, i32 0, i32 0, !dbg !32 ; line:17 col:9
+ %8 = load <4 x float>, <4 x float>* getelementptr inbounds ([1 x %class.matrix.float.2.4], [1 x %class.matrix.float.2.4]* @g.1.0.1, i32 0, i32 0, i32 0, i32 0), !dbg !32 ; line:17 col:9
+ store <4 x float> %8, <4 x float>* %7, !dbg !32 ; line:17 col:9
+ %9 = getelementptr inbounds %class.matrix.float.2.4, %class.matrix.float.2.4* %h.0.1, i32 0, i32 0, i32 1, !dbg !32 ; line:17 col:9
+ %10 = load <4 x float>, <4 x float>* getelementptr inbounds ([1 x %class.matrix.float.2.4], [1 x %class.matrix.float.2.4]* @g.1.0.1, i32 0, i32 0, i32 0, i32 1), !dbg !32 ; line:17 col:9
+ store <4 x float> %10, <4 x float>* %9, !dbg !32 ; line:17 col:9
+ ret void, !dbg !33 ; line:18 col:3
+}
+
+; Function Attrs: nounwind
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1) #0
+
+; Function Attrs: nounwind readnone
+declare %class.matrix.float.2.4 @"dx.hl.init.rn.%class.matrix.float.2.4 (i32, <8 x float>)"(i32, <8 x float>) #1
+
+; Function Attrs: nounwind readnone
+declare %class.matrix.float.2.4 @"dx.hl.cast.rowMatToColMat.%class.matrix.float.2.4 (i32, %class.matrix.float.2.4)"(i32, %class.matrix.float.2.4) #1
+
+; Function Attrs: nounwind
+declare %class.matrix.float.2.4 @"dx.hl.matldst.colStore.%class.matrix.float.2.4 (i32, %class.matrix.float.2.4*, %class.matrix.float.2.4)"(i32, %class.matrix.float.2.4*, %class.matrix.float.2.4) #0
+
+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, !15}
+!dx.entryPoints = !{!19}
+!dx.fnprops = !{!23}
+!dx.options = !{!24, !25}
+
+!0 = !{i32 2, !"Debug Info Version", i32 3}
+!1 = !{!"hlsl-hlemit", !"hlsl-hlensure"}
+!2 = !{!"dxc(private) 1.8.0.4640 (issue-785, 45018c752d)"}
+!3 = !{i32 1, i32 0}
+!4 = !{i32 1, i32 8}
+!5 = !{!"cs", i32 6, i32 0}
+!6 = !{i32 0, %struct.e undef, !7, %struct.d undef, !10, %struct.a undef, !11}
+!7 = !{i32 152, !8, !9}
+!8 = !{i32 6, !"c", i32 3, i32 0}
+!9 = !{i32 6, !"f", i32 3, i32 80}
+!10 = !{i32 72, !8}
+!11 = !{i32 72, !12, !13}
+!12 = !{i32 6, !"b", i32 3, i32 0, i32 7, i32 9}
+!13 = !{i32 6, !"c", i32 2, !14, i32 3, i32 16, i32 7, i32 9}
+!14 = !{i32 2, i32 4, i32 2}
+!15 = !{i32 1, void ()* @main, !16}
+!16 = !{!17}
+!17 = !{i32 1, !18, !18}
+!18 = !{}
+!19 = !{void ()* @main, !"main", null, !20, null}
+!20 = !{null, null, !21, null}
+!21 = !{!22}
+!22 = !{i32 0, %ConstantBuffer* @"$Globals", !"$Globals", i32 0, i32 -1, i32 1, i32 0, null}
+!23 = !{void ()* @main, i32 5, i32 1, i32 1, i32 1}
+!24 = !{i32 64}
+!25 = !{i32 -1}
+!26 = !DILocation(line: 13, column: 17, scope: !27, inlinedAt: !30)
+!27 = !DISubprogram(name: "??__Eg@@YAXXZ", scope: !28, file: !28, line: 13, type: !29, isLocal: true, isDefinition: true, scopeLine: 13, flags: DIFlagPrototyped, isOptimized: false)
+!28 = !DIFile(filename: "a.hlsl", directory: "")
+!29 = !DISubroutineType(types: !18)
+!30 = distinct !DILocation(line: 16, scope: !31)
+!31 = !DISubprogram(name: "main", scope: !28, file: !28, line: 16, type: !29, isLocal: false, isDefinition: true, scopeLine: 16, flags: DIFlagPrototyped, isOptimized: false, function: void ()* @main)
+!32 = !DILocation(line: 17, column: 9, scope: !31)
+!33 = !DILocation(line: 18, column: 3, scope: !31)

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,231 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Antonio Maiorano <amaiorano@google.com>
Date: Thu, 20 Jun 2024 15:39:00 -0400
Subject: Fix instcombine overflow check inserting inst at wrong place (#6679)
When optimizing an overflow check of an add followed by a compare, the
new instruction was being inserted at the compare, and the add removed.
This produced invalid IR in cases where there were other uses of the
former add between it and the compare. This fix makes sure to insert the
new instruction at the old add location, rather than at the compare.
Note that this was also fixed in LLVM:
https://github.com/llvm/llvm-project/commit/6f5dca70ed1c030957a45ad91bd295921f17b18d
Bug: chromium:342545100
Change-Id: Iecf758e4465b32371266bbe9879790328f363322
Reviewed-on: https://chromium-review.googlesource.com/c/external/github.com/microsoft/DirectXShaderCompiler/+/5644335
Reviewed-by: dan sinclair <dsinclair@google.com>
Reviewed-by: Ryan Harrison <rharrison@chromium.org>
diff --git a/lib/Transforms/InstCombine/InstCombineCompares.cpp b/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 7274304b3de7b110a4fa3a5123ea7215d99935ef..82e7e49003e65846c84e3df2801453fb463aa23e 100644
--- a/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -2145,6 +2145,12 @@ bool InstCombiner::OptimizeOverflowCheck(OverflowCheckFlavor OCF, Value *LHS,
return true;
};
+ // If the overflow check was an add followed by a compare, the insertion point
+ // may be pointing to the compare. We want to insert the new instructions
+ // before the add in case there are uses of the add between the add and the
+ // compare.
+ Builder->SetInsertPoint(&OrigI);
+
switch (OCF) {
case OCF_INVALID:
llvm_unreachable("bad overflow check kind!");
diff --git a/tools/clang/test/DXC/Passes/InstructionCombining/instcombine-opt-overflow-check-inserts-at-add.ll b/tools/clang/test/DXC/Passes/InstructionCombining/instcombine-opt-overflow-check-inserts-at-add.ll
new file mode 100644
index 0000000000000000000000000000000000000000..70efa00c91c6523867980de0fb9f69c7fcfb318c
--- /dev/null
+++ b/tools/clang/test/DXC/Passes/InstructionCombining/instcombine-opt-overflow-check-inserts-at-add.ll
@@ -0,0 +1,187 @@
+; RUN: %dxopt %s -hlsl-passes-resume -instcombine,NoSink=0 -S | FileCheck %s
+
+; Generated from the following HLSL:
+; cbuffer cbuffer_g : register(b0) {
+; uint4 g[1];
+; };
+;
+; [numthreads(1, 1, 1)]
+; void main() {
+; uint a = 2147483648u;
+; uint b = (g[0].x | 2651317025u);
+; uint c = (b + 2651317025u);
+; while (true) {
+; bool d = (a > c);
+; if (d) {
+; break;
+; } else {
+; while (true) {
+; if (!d) {
+; return;
+; }
+; a = b;
+; bool e = (d ? d : d);
+; if (e) {
+; break;
+; }
+; }
+; }
+; }
+; }
+;
+; Compiling this was resulting in invalid IR being produced from instcombine.
+; Specifically, when optimizing an overflow check of an add followed by a compare,
+; the new instruction was being inserted at the compare, and the add removed. This
+; broke in cases like this one, where there were other uses of the former add between
+; it and the compare. The fix was to make sure to insert the new instruction
+; (another add in this case) at the old add rather than at the compare.
+
+; Make sure the new %add is still in the entry block before its uses.
+; CHECK-LABEL: entry
+; CHECK: %add = add i32 %or, -1643650271
+; CHECK-NEXT: %cmp.2 = icmp sgt i32 %add, -1,
+;
+; Make sure the new %add is NOT in the loopexit where %cmp was optimized.
+; CHECK-LABEL: while.body.loopexit
+; CHECK-NEXT: br i1 false, label %if.end.preheader, label %while.end.14
+
+;
+; Buffer Definitions:
+;
+; cbuffer cbuffer_g
+; {
+;
+; struct cbuffer_g
+; {
+;
+; uint4 g[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 }
+
+@cbuffer_g = external constant %cbuffer_g
+@llvm.used = appending global [1 x i8*] [i8* bitcast (%cbuffer_g* @cbuffer_g to i8*)], section "llvm.metadata"
+
+; Function Attrs: nounwind
+define void @main() #0 {
+entry:
+ %0 = load %cbuffer_g, %cbuffer_g* @cbuffer_g
+ %cbuffer_g = call %dx.types.Handle @dx.op.createHandleForLib.cbuffer_g(i32 160, %cbuffer_g %0) ; CreateHandleForLib(Resource)
+ %1 = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle %cbuffer_g, %dx.types.ResourceProperties { i32 13, i32 16 }) ; AnnotateHandle(res,props) resource: CBuffer
+ %2 = call %dx.types.CBufRet.i32 @dx.op.cbufferLoadLegacy.i32(i32 59, %dx.types.Handle %1, i32 0), !dbg !19 ; line:8 col:13 ; CBufferLoadLegacy(handle,regIndex)
+ %3 = extractvalue %dx.types.CBufRet.i32 %2, 0, !dbg !19 ; line:8 col:13
+ %or = or i32 %3, -1643650271, !dbg !23 ; line:8 col:20
+ %add = add i32 %or, -1643650271, !dbg !24 ; line:9 col:15
+ %cmp.2 = icmp ugt i32 -2147483648, %add, !dbg !25 ; line:11 col:17
+ %frombool.3 = zext i1 %cmp.2 to i32, !dbg !26 ; line:11 col:10
+ %tobool1.4 = icmp eq i32 %frombool.3, 0, !dbg !27 ; line:12 col:9
+ %or.cond.6 = and i1 %tobool1.4, %cmp.2, !dbg !27 ; line:12 col:9
+ br i1 %or.cond.6, label %if.end.preheader, label %while.end.14, !dbg !27 ; line:12 col:9
+
+while.body.loopexit: ; preds = %if.end
+ %cmp = icmp ugt i32 %or, %add, !dbg !25 ; line:11 col:17
+ %frombool = zext i1 %cmp to i32, !dbg !26 ; line:11 col:10
+ %tobool1 = icmp eq i32 %frombool, 0, !dbg !27 ; line:12 col:9
+ %or.cond = and i1 %tobool1, %cmp, !dbg !27 ; line:12 col:9
+ br i1 %or.cond, label %if.end.preheader, label %while.end.14, !dbg !27 ; line:12 col:9
+
+if.end.preheader: ; preds = %entry, %while.body.loopexit
+ %d.0 = phi i32 [ %frombool, %while.body.loopexit ], [ %frombool.3, %entry ]
+ br label %if.end, !dbg !28 ; line:19 col:13
+
+while.body.3: ; preds = %if.end
+ %tobool4.old = icmp ne i32 %d.0, 0, !dbg !29 ; line:16 col:14
+ br i1 %tobool4.old, label %if.end, label %while.end.14, !dbg !30 ; line:16 col:13
+
+if.end: ; preds = %if.end.preheader, %while.body.3
+ %tobool6 = icmp ne i32 %d.0, 0, !dbg !31 ; line:20 col:19
+ %tobool7 = icmp ne i32 %d.0, 0, !dbg !32 ; line:20 col:23
+ %tobool8 = icmp ne i32 %d.0, 0, !dbg !33 ; line:20 col:27
+ %4 = select i1 %tobool6, i1 %tobool7, i1 %tobool8, !dbg !31 ; line:20 col:19
+ br i1 %4, label %while.body.loopexit, label %while.body.3, !dbg !34 ; line:21 col:13
+
+while.end.14: ; preds = %while.body.loopexit, %while.body.3, %entry
+ ret void, !dbg !35 ; line:27 col:1
+}
+
+; Function Attrs: nounwind readnone
+declare %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %cbuffer_g*, i32)"(i32, %cbuffer_g*, i32) #1
+
+; 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) #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) #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, !12}
+!dx.entryPoints = !{!16}
+
+!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 0}
+!4 = !{i32 1, i32 8}
+!5 = !{!"cs", i32 6, i32 0}
+!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, %cbuffer_g undef, !10}
+!10 = !{i32 16, !11}
+!11 = !{i32 6, !"g", i32 3, i32 0, i32 7, i32 5}
+!12 = !{i32 1, void ()* @main, !13}
+!13 = !{!14}
+!14 = !{i32 1, !15, !15}
+!15 = !{}
+!16 = !{void ()* @main, !"main", null, !6, !17}
+!17 = !{i32 4, !18}
+!18 = !{i32 1, i32 1, i32 1}
+!19 = !DILocation(line: 8, column: 13, scope: !20)
+!20 = !DISubprogram(name: "main", scope: !21, file: !21, line: 6, type: !22, isLocal: false, isDefinition: true, scopeLine: 6, flags: DIFlagPrototyped, isOptimized: false, function: void ()* @main)
+!21 = !DIFile(filename: "/mnt/c/Users/amaiorano/Downloads/342545100/standalone_reduced.hlsl", directory: "")
+!22 = !DISubroutineType(types: !15)
+!23 = !DILocation(line: 8, column: 20, scope: !20)
+!24 = !DILocation(line: 9, column: 15, scope: !20)
+!25 = !DILocation(line: 11, column: 17, scope: !20)
+!26 = !DILocation(line: 11, column: 10, scope: !20)
+!27 = !DILocation(line: 12, column: 9, scope: !20)
+!28 = !DILocation(line: 19, column: 13, scope: !20)
+!29 = !DILocation(line: 16, column: 14, scope: !20)
+!30 = !DILocation(line: 16, column: 13, scope: !20)
+!31 = !DILocation(line: 20, column: 19, scope: !20)
+!32 = !DILocation(line: 20, column: 23, scope: !20)
+!33 = !DILocation(line: 20, column: 27, scope: !20)
+!34 = !DILocation(line: 21, column: 13, scope: !20)
+!35 = !DILocation(line: 27, column: 1, scope: !20)

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", [])

6
patches/angle/.patches Normal file
View File

@@ -0,0 +1,6 @@
m123_vulkan_fix_access_to_inactive_attributes.patch
cherry-pick-f6672dbbe223.patch
cherry-pick-ba3b4e239620.patch
cherry-pick-c67f290ef0f0.patch
cherry-pick-bda89e1f7c71.patch
m126_vulkan_disable_vk_ext_shader_stencil_export_on_swiftshader.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

@@ -0,0 +1,27 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shahbaz Youssefi <syoussefi@chromium.org>
Date: Thu, 13 Jun 2024 16:54:03 -0400
Subject: M126: Vulkan: Disable VK_EXT_shader_stencil_export on SwiftShader
Bug: chromium:40942995
Change-Id: I5035d9b11997a1c7c839d7d62544fecca9fd1f73
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5634418
Reviewed-by: Yuly Novikov <ynovikov@chromium.org>
diff --git a/src/libANGLE/renderer/vulkan/RendererVk.cpp b/src/libANGLE/renderer/vulkan/RendererVk.cpp
index 25beb6a346798f117b8fe15de9858adcc32881cd..4827c61a166633d191e1f9b03a3dc47066ce9522 100644
--- a/src/libANGLE/renderer/vulkan/RendererVk.cpp
+++ b/src/libANGLE/renderer/vulkan/RendererVk.cpp
@@ -4175,9 +4175,11 @@ void RendererVk::initFeatures(DisplayVk *displayVk,
}
#endif // defined(ANGLE_PLATFORM_ANDROID) || defined(ANGLE_PLATFORM_LINUX)
+ // Disabled on SwiftShader due to http://crbug.com/40942995
ANGLE_FEATURE_CONDITION(
&mFeatures, supportsShaderStencilExport,
- ExtensionFound(VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME, deviceExtensionNames));
+ ExtensionFound(VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME, deviceExtensionNames) &&
+ !isSwiftShader);
ANGLE_FEATURE_CONDITION(
&mFeatures, supportsRenderPassLoadStoreOpNone,

View File

@@ -133,3 +133,27 @@ fix_getcursorscreenpoint_wrongly_returns_0_0.patch
fix_add_support_for_skipping_first_2_no-op_refreshes_in_thumb_cap.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
cherry-pick-d54105311590.patch
cherry-pick-43b8b682d05c.patch
cherry-pick-c5dd8839bfaf.patch
cherry-pick-38e4483e47f9.patch
cherry-pick-1b9040817119.patch
cherry-pick-99cafbf4b4b9.patch
cherry-pick-44b7fbf35b10.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,84 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Bryant Chandler <bryantchandler@chromium.org>
Date: Mon, 24 Jun 2024 17:28:53 +0000
Subject: Fix pointer tear down order problem
Holding a RenderFrameHost* in the `OnceBinding` isn't safe,
because the `RenderFrameHost` can be destroyed before the
binding. This CL changes the task strategy so that the
RenderFrameHost* doesn't need to be bound in a callback.
Tested using the repro steps in the bug and this change stops
it from reproducing.
Fixed: 347373236
Change-Id: Id639f317b0f37a508833aba9fe52ffc5c0ed590c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5640501
Reviewed-by: Dave Tapuska <dtapuska@chromium.org>
Commit-Queue: Bryant Chandler <bryantchandler@chromium.org>
Reviewed-by: Guido Urdaneta <guidou@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1318653}
diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc
index 5db8665f1466dcfd896b3de3b2f3a2ae307e87de..0153cd1160cb47de471df92211c320920758058a 100644
--- a/content/browser/renderer_host/media/media_stream_manager.cc
+++ b/content/browser/renderer_host/media/media_stream_manager.cc
@@ -2847,25 +2847,19 @@ void MediaStreamManager::GetRawDeviceIdsOpenedForFrame(
RenderFrameHost* render_frame_host,
blink::mojom::MediaStreamType type,
GetRawDeviceIdsOpenedForFrameCallback callback) const {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- CHECK(render_frame_host);
- auto collect_all_render_frame_host_ids = base::BindOnce(
- [](RenderFrameHost* render_frame_host) {
- base::flat_set<GlobalRenderFrameHostId> all_render_frame_host_ids;
- render_frame_host->ForEachRenderFrameHost(
- [&all_render_frame_host_ids](RenderFrameHost* render_frame_host) {
- all_render_frame_host_ids.insert(
- render_frame_host->GetGlobalId());
- });
- return all_render_frame_host_ids;
- },
- render_frame_host);
-
- GetUIThreadTaskRunner()->PostTaskAndReplyWithResult(
- FROM_HERE, std::move(collect_all_render_frame_host_ids),
- base::BindPostTaskToCurrentDefault(
- base::BindOnce(&MediaStreamManager::GetRawDeviceIdsOpenedForFrameIds,
- base::Unretained(this), type, std::move(callback))));
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ base::flat_set<GlobalRenderFrameHostId> all_render_frame_host_ids;
+ render_frame_host->ForEachRenderFrameHost(
+ [&all_render_frame_host_ids](RenderFrameHost* render_frame_host) {
+ all_render_frame_host_ids.insert(render_frame_host->GetGlobalId());
+ });
+
+ GetIOThreadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&MediaStreamManager::GetRawDeviceIdsOpenedForFrameIds,
+ base::Unretained(this), type, std::move(callback),
+ all_render_frame_host_ids));
}
void MediaStreamManager::GetRawDeviceIdsOpenedForFrameIds(
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 00e0321382a562ffb3733c48540d4f3071f13527..90cd9138510cf1c4a77bdd39610890a407870a22 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -10613,12 +10613,9 @@ void WebContentsImpl::GetMediaCaptureRawDeviceIdsOpened(
return;
}
- GetIOThreadTaskRunner({})->PostTask(
- FROM_HERE,
- base::BindOnce(&MediaStreamManager::GetRawDeviceIdsOpenedForFrame,
- base::Unretained(media_stream_manager),
- GetPrimaryMainFrame(), type,
- base::BindPostTaskToCurrentDefault(std::move(callback))));
+ media_stream_manager->GetRawDeviceIdsOpenedForFrame(
+ GetPrimaryMainFrame(), type,
+ base::BindPostTaskToCurrentDefault(std::move(callback)));
}
} // namespace content

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,88 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Johannes Kron <kron@chromium.org>
Date: Wed, 19 Jun 2024 20:59:48 +0000
Subject: Use BindPostTask() + weak pointer in callback handler
The callback handler incorrectly accessed member objects directly which may
cause UAF. Avoid this by using BindPostTask() together with a weak pointer.
Fixed: 346898524
Change-Id: I9d03d6decfd0212af88d3d0d8d70f83f1081d2e3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5639016
Reviewed-by: Avi Drissman <avi@chromium.org>
Reviewed-by: Mark Foltz <mfoltz@chromium.org>
Commit-Queue: Johannes Kron <kron@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1317142}
diff --git a/content/browser/media/capture/screen_capture_kit_device_mac.mm b/content/browser/media/capture/screen_capture_kit_device_mac.mm
index 4fb3e8eb5f34a7ee9e8b0f22a7c842129cdc31eb..e2710fba1a8d7a4cee6023558898c74706a9c189 100644
--- a/content/browser/media/capture/screen_capture_kit_device_mac.mm
+++ b/content/browser/media/capture/screen_capture_kit_device_mac.mm
@@ -326,13 +326,18 @@ void OnStreamSample(gfx::ScopedInUseIOSurface io_surface,
destRectInFrame:dest_rect_in_frame
frameRate:requested_capture_format_->
frame_rate];
+
+ __block base::OnceCallback<void()> on_update_configuration_error =
+ base::BindPostTask(
+ device_task_runner_,
+ base::BindOnce(
+ &ScreenCaptureKitDeviceMac::OnUpdateConfigurationError,
+ weak_factory_.GetWeakPtr()));
[stream_
updateConfiguration:config
completionHandler:^(NSError* _Nullable error) {
if (error) {
- client()->OnError(
- media::VideoCaptureError::kScreenCaptureKitStreamError,
- FROM_HERE, "Error on updateConfiguration");
+ std::move(on_update_configuration_error).Run();
}
}];
}
@@ -361,6 +366,21 @@ void OnStreamError() {
FROM_HERE, "Stream delegate called didStopWithError");
}
}
+ void OnUpdateContentFilterCompleted(NSError* _Nullable error) {
+ DCHECK(device_task_runner_->RunsTasksInCurrentSequence());
+ is_resetting_ = false;
+
+ if (error) {
+ client()->OnError(media::VideoCaptureError::kScreenCaptureKitStreamError,
+ FROM_HERE,
+ "Error on updateContentFilter (fullscreen window).");
+ }
+ }
+ void OnUpdateConfigurationError() {
+ DCHECK(device_task_runner_->RunsTasksInCurrentSequence());
+ client()->OnError(media::VideoCaptureError::kScreenCaptureKitStreamError,
+ FROM_HERE, "Error on updateConfiguration");
+ }
// IOSurfaceCaptureDeviceBase:
void OnStart() override {
@@ -411,15 +431,16 @@ void ResetStreamTo(SCWindow* window) override {
SCContentFilter* filter =
[[SCContentFilter alloc] initWithDesktopIndependentWindow:window];
+ __block base::OnceCallback<void(NSError*)>
+ on_update_content_filter_completed = base::BindPostTask(
+ device_task_runner_,
+ base::BindOnce(
+ &ScreenCaptureKitDeviceMac::OnUpdateContentFilterCompleted,
+ weak_factory_.GetWeakPtr()));
+
[stream_ updateContentFilter:filter
completionHandler:^(NSError* _Nullable error) {
- is_resetting_ = false;
- if (error) {
- client()->OnError(
- media::VideoCaptureError::kScreenCaptureKitStreamError,
- FROM_HERE,
- "Error on updateContentFilter (fullscreen window).");
- }
+ std::move(on_update_content_filter_completed).Run(error);
}];
}

View File

@@ -0,0 +1,264 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Philip Pfaffe <pfaffe@chromium.org>
Date: Tue, 18 Jun 2024 10:04:45 +0000
Subject: Prevent script injection on reload when racing with a navigation
DevTools passes the loaderId now when calling Page.reload, in order to
prevent accidentally reloading the wrong page when a navigation occurred
concurrently. It can still happen that the navigation kicks in in between the reload iniated in the browser and the script injection that happens in the renderer, which would run the injected script on the wrong target. We need to check the loaderId also on the renderer side.
Fixed: 341136300
Change-Id: I891fb37fa10e6789c8697a0f29bf7118788a9319
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5625857
Reviewed-by: Andrey Kosyakov <caseq@chromium.org>
Commit-Queue: Philip Pfaffe <pfaffe@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1316330}
diff --git a/third_party/blink/renderer/core/inspector/build.gni b/third_party/blink/renderer/core/inspector/build.gni
index 2e9feebe066f938506d63d157be65828aa2a27c9..39de006f5f97f9e2a84ee4d38f7bb98e99c41924 100644
--- a/third_party/blink/renderer/core/inspector/build.gni
+++ b/third_party/blink/renderer/core/inspector/build.gni
@@ -138,6 +138,7 @@ blink_core_tests_inspector = [
"inspector_emulation_agent_test.cc",
"inspector_highlight_test.cc",
"inspector_history_test.cc",
+ "inspector_page_agent_unittest.cc",
"inspector_preload_agent_unittest.cc",
"inspector_media_context_impl_unittest.cc",
"inspector_session_state_test.cc",
diff --git a/third_party/blink/renderer/core/inspector/inspector_page_agent.cc b/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
index 6936ee92726937deba7e85e30259d7d276f6a397..b4a38117cad3fbe032ac578724032fec7fd6e586 100644
--- a/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_page_agent.cc
@@ -477,6 +477,42 @@ String InspectorPageAgent::CachedResourceTypeJson(
return ResourceTypeJson(ToResourceType(cached_resource.GetType()));
}
+InspectorPageAgent::PageReloadScriptInjection::PageReloadScriptInjection(
+ InspectorAgentState& agent_state)
+ : pending_script_to_evaluate_on_load_once_(&agent_state,
+ /*default_value=*/{}),
+ target_url_for_pending_script_(&agent_state,
+ /*default_value=*/{}) {}
+
+void InspectorPageAgent::PageReloadScriptInjection::clear() {
+ script_to_evaluate_on_load_once_ = {};
+ pending_script_to_evaluate_on_load_once_.Set({});
+ target_url_for_pending_script_.Set({});
+}
+
+void InspectorPageAgent::PageReloadScriptInjection::SetPending(
+ String script,
+ const KURL& target_url) {
+ pending_script_to_evaluate_on_load_once_.Set(script);
+ target_url_for_pending_script_.Set(target_url.GetString());
+}
+
+void InspectorPageAgent::PageReloadScriptInjection::PromoteToLoadOnce() {
+ script_to_evaluate_on_load_once_ =
+ pending_script_to_evaluate_on_load_once_.Get();
+ target_url_for_active_script_ = target_url_for_pending_script_.Get();
+ pending_script_to_evaluate_on_load_once_.Set({});
+ target_url_for_pending_script_.Set({});
+}
+
+String InspectorPageAgent::PageReloadScriptInjection::GetScriptForInjection(
+ const KURL& target_url) {
+ if (target_url_for_active_script_ == target_url.GetString()) {
+ return script_to_evaluate_on_load_once_;
+ }
+ return {};
+}
+
InspectorPageAgent::InspectorPageAgent(
InspectedFrames* inspected_frames,
Client* client,
@@ -493,8 +529,6 @@ InspectorPageAgent::InspectorPageAgent(
screencast_enabled_(&agent_state_, /*default_value=*/false),
lifecycle_events_enabled_(&agent_state_, /*default_value=*/false),
bypass_csp_enabled_(&agent_state_, /*default_value=*/false),
- pending_script_to_evaluate_on_load_once_(&agent_state_,
- /*default_value=*/String()),
scripts_to_evaluate_on_load_(&agent_state_,
/*default_value=*/String()),
worlds_to_evaluate_on_load_(&agent_state_,
@@ -504,7 +538,8 @@ InspectorPageAgent::InspectorPageAgent(
/*default_value=*/false),
standard_font_size_(&agent_state_, /*default_value=*/0),
fixed_font_size_(&agent_state_, /*default_value=*/0),
- script_font_families_cbor_(&agent_state_, std::vector<uint8_t>()) {}
+ script_font_families_cbor_(&agent_state_, std::vector<uint8_t>()),
+ script_injection_on_load_(agent_state_) {}
void InspectorPageAgent::Restore() {
if (enabled_.Get())
@@ -543,8 +578,7 @@ protocol::Response InspectorPageAgent::enable() {
protocol::Response InspectorPageAgent::disable() {
agent_state_.ClearAllFields();
pending_isolated_worlds_.clear();
- script_to_evaluate_on_load_once_ = String();
- pending_script_to_evaluate_on_load_once_.Set(String());
+ script_injection_on_load_.clear();
instrumenting_agents_->RemoveInspectorPageAgent(this);
inspector_resource_content_loader_->Cancel(
resource_content_loader_client_id_);
@@ -670,8 +704,9 @@ protocol::Response InspectorPageAgent::setAdBlockingEnabled(bool enable) {
protocol::Response InspectorPageAgent::reload(
Maybe<bool> optional_bypass_cache,
Maybe<String> optional_script_to_evaluate_on_load) {
- pending_script_to_evaluate_on_load_once_.Set(
- optional_script_to_evaluate_on_load.value_or(""));
+ script_injection_on_load_.SetPending(
+ optional_script_to_evaluate_on_load.value_or(""),
+ inspected_frames_->Root()->Loader().GetDocumentLoader()->Url());
v8_session_->setSkipAllPauses(true);
v8_session_->resume(true /* terminate on resume */);
return protocol::Response::Success();
@@ -987,7 +1022,9 @@ void InspectorPageAgent::DidCreateMainWorldContext(LocalFrame* frame) {
EvaluateScriptOnNewDocument(*frame, key);
}
- if (script_to_evaluate_on_load_once_.empty()) {
+ String script = script_injection_on_load_.GetScriptForInjection(
+ frame->Loader().GetDocumentLoader()->Url());
+ if (script.empty()) {
return;
}
ScriptState* script_state = ToScriptStateForMainWorld(frame);
@@ -995,9 +1032,8 @@ void InspectorPageAgent::DidCreateMainWorldContext(LocalFrame* frame) {
return;
}
- v8_session_->evaluate(
- script_state->GetContext(),
- ToV8InspectorStringView(script_to_evaluate_on_load_once_));
+ v8_session_->evaluate(script_state->GetContext(),
+ ToV8InspectorStringView(script));
}
void InspectorPageAgent::EvaluateScriptOnNewDocument(
@@ -1047,9 +1083,7 @@ void InspectorPageAgent::LoadEventFired(LocalFrame* frame) {
void InspectorPageAgent::WillCommitLoad(LocalFrame*, DocumentLoader* loader) {
if (loader->GetFrame() == inspected_frames_->Root()) {
- script_to_evaluate_on_load_once_ =
- pending_script_to_evaluate_on_load_once_.Get();
- pending_script_to_evaluate_on_load_once_.Set(String());
+ script_injection_on_load_.PromoteToLoadOnce();
}
GetFrontend()->frameNavigated(BuildObjectForFrame(loader->GetFrame()),
protocol::Page::NavigationTypeEnum::Navigation);
diff --git a/third_party/blink/renderer/core/inspector/inspector_page_agent.h b/third_party/blink/renderer/core/inspector/inspector_page_agent.h
index d0da21e12df1dd11bd57b2226491f61aa34d62c9..3eb5e24fb13428e38a1ebc2e64bdeab9eed28ef2 100644
--- a/third_party/blink/renderer/core/inspector/inspector_page_agent.h
+++ b/third_party/blink/renderer/core/inspector/inspector_page_agent.h
@@ -93,6 +93,22 @@ class CORE_EXPORT InspectorPageAgent final
kOtherResource
};
+ class CORE_EXPORT PageReloadScriptInjection {
+ private:
+ String script_to_evaluate_on_load_once_;
+ String target_url_for_active_script_;
+ InspectorAgentState::String pending_script_to_evaluate_on_load_once_;
+ InspectorAgentState::String target_url_for_pending_script_;
+
+ public:
+ explicit PageReloadScriptInjection(InspectorAgentState&);
+
+ void clear();
+ void SetPending(String script, const KURL& target_url);
+ void PromoteToLoadOnce();
+ String GetScriptForInjection(const KURL& target_url);
+ };
+
static bool CachedResourceContent(const Resource*,
String* result,
bool* base64_encoded);
@@ -306,7 +322,6 @@ class CORE_EXPORT InspectorPageAgent final
ad_script_identifiers_;
v8_inspector::V8InspectorSession* v8_session_;
Client* client_;
- String script_to_evaluate_on_load_once_;
Member<InspectorResourceContentLoader> inspector_resource_content_loader_;
int resource_content_loader_client_id_;
InspectorAgentState::Boolean intercept_file_chooser_;
@@ -314,7 +329,6 @@ class CORE_EXPORT InspectorPageAgent final
InspectorAgentState::Boolean screencast_enabled_;
InspectorAgentState::Boolean lifecycle_events_enabled_;
InspectorAgentState::Boolean bypass_csp_enabled_;
- InspectorAgentState::String pending_script_to_evaluate_on_load_once_;
InspectorAgentState::StringMap scripts_to_evaluate_on_load_;
InspectorAgentState::StringMap worlds_to_evaluate_on_load_;
InspectorAgentState::BooleanMap
@@ -322,6 +336,7 @@ class CORE_EXPORT InspectorPageAgent final
InspectorAgentState::Integer standard_font_size_;
InspectorAgentState::Integer fixed_font_size_;
InspectorAgentState::Bytes script_font_families_cbor_;
+ PageReloadScriptInjection script_injection_on_load_;
};
} // namespace blink
diff --git a/third_party/blink/renderer/core/inspector/inspector_page_agent_unittest.cc b/third_party/blink/renderer/core/inspector/inspector_page_agent_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..b81f6b4735392f3f542ccbb2a114c2def185be1c
--- /dev/null
+++ b/third_party/blink/renderer/core/inspector/inspector_page_agent_unittest.cc
@@ -0,0 +1,57 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/inspector/inspector_page_agent.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/inspector/inspector_session_state.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+
+class PageReloadScriptInjectionTest : public testing::Test {
+ protected:
+ blink::mojom::blink::DevToolsSessionStatePtr session_state_cookie_;
+ blink::InspectorAgentState agent_state_;
+ blink::InspectorPageAgent::PageReloadScriptInjection injection_;
+ blink::InspectorSessionState state_;
+
+ public:
+ PageReloadScriptInjectionTest()
+ : agent_state_("page"),
+ injection_(agent_state_),
+ state_(session_state_cookie_.Clone()) {}
+
+ void SetUp() override { agent_state_.InitFrom(&state_); }
+};
+
+TEST_F(PageReloadScriptInjectionTest, PromotesScript) {
+ blink::KURL url("http://example.com");
+ injection_.SetPending("script", url);
+ ASSERT_TRUE(injection_.GetScriptForInjection(url).empty());
+ injection_.PromoteToLoadOnce();
+ ASSERT_EQ(injection_.GetScriptForInjection(url), "script");
+ injection_.PromoteToLoadOnce();
+ ASSERT_TRUE(injection_.GetScriptForInjection(url).empty());
+}
+
+TEST_F(PageReloadScriptInjectionTest, ClearsScript) {
+ blink::KURL url("http://example.com");
+ injection_.SetPending("script", url);
+ injection_.clear();
+ injection_.PromoteToLoadOnce();
+ ASSERT_TRUE(injection_.GetScriptForInjection(url).empty());
+
+ injection_.SetPending("script", url);
+ injection_.PromoteToLoadOnce();
+ ASSERT_EQ(injection_.GetScriptForInjection(url), "script");
+ injection_.clear();
+ ASSERT_TRUE(injection_.GetScriptForInjection(url).empty());
+}
+
+TEST_F(PageReloadScriptInjectionTest, ChecksLoaderId) {
+ blink::KURL url("http://example.com");
+ blink::KURL url2("about:blank");
+ injection_.SetPending("script", url);
+ injection_.PromoteToLoadOnce();
+ ASSERT_TRUE(injection_.GetScriptForInjection(url2).empty());
+}

View File

@@ -0,0 +1,281 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Hiroshige Hayashizaki <hiroshige@chromium.org>
Date: Mon, 8 Jul 2024 01:13:43 +0000
Subject: Handle ThrottlingURLLoader deletion during throttle calls
Theoretically `ThrottlingURLLoader` can be deleted during
throttle calls and some call sites have already protection
for such cases. This CL adds the protection for more call sites.
This CL also adds more unit tests for cancelling/deleting
`ThrottlingURLLoader` during throttle calls.
Bug: 349342289
Change-Id: I80d64be9ba1a3ac920315f5b4012b29c9737e414
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5665925
Commit-Queue: Hiroshige Hayashizaki <hiroshige@chromium.org>
Reviewed-by: Tsuyoshi Horo <horo@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1323986}
diff --git a/third_party/blink/common/loader/throttling_url_loader.cc b/third_party/blink/common/loader/throttling_url_loader.cc
index 3da99026feaf92a0b7a2440e2ba2a99012ee9378..3160006eb73cd0205a3ba0c23e5fa598f1ac3a2c 100644
--- a/third_party/blink/common/loader/throttling_url_loader.cc
+++ b/third_party/blink/common/loader/throttling_url_loader.cc
@@ -720,8 +720,12 @@ void ThrottlingURLLoader::OnReceiveResponse(
auto* throttle = entry.throttle.get();
bool throttle_deferred = false;
base::Time start = base::Time::Now();
+ auto weak_ptr = weak_factory_.GetWeakPtr();
throttle->BeforeWillProcessResponse(response_url_, *response_head,
&throttle_deferred);
+ if (!weak_ptr) {
+ return;
+ }
RecordExecutionTimeHistogram(
GetStageNameForHistogram(DEFERRED_BEFORE_RESPONSE), start);
if (!HandleThrottleResult(throttle, throttle_deferred, &deferred))
@@ -747,8 +751,12 @@ void ThrottlingURLLoader::OnReceiveResponse(
auto* throttle = entry.throttle.get();
bool throttle_deferred = false;
base::Time start = base::Time::Now();
+ auto weak_ptr = weak_factory_.GetWeakPtr();
throttle->WillProcessResponse(response_url_, response_head.get(),
&throttle_deferred);
+ if (!weak_ptr) {
+ return;
+ }
RecordExecutionTimeHistogram(GetStageNameForHistogram(DEFERRED_RESPONSE),
start);
if (!HandleThrottleResult(throttle, throttle_deferred, &deferred))
@@ -914,7 +922,11 @@ void ThrottlingURLLoader::OnComplete(
auto* throttle = entry.throttle.get();
bool throttle_deferred = false;
base::Time start = base::Time::Now();
+ auto weak_ptr = weak_factory_.GetWeakPtr();
throttle->WillOnCompleteWithError(status, &throttle_deferred);
+ if (!weak_ptr) {
+ return;
+ }
RecordExecutionTimeHistogram(GetStageNameForHistogram(DEFERRED_COMPLETE),
start);
if (!HandleThrottleResult(throttle, throttle_deferred, &deferred))
diff --git a/third_party/blink/common/loader/throttling_url_loader_unittest.cc b/third_party/blink/common/loader/throttling_url_loader_unittest.cc
index 4cc2d23b968c40d1b26ec32fd1bf05ae7b846d4c..475a81e7cdc08304f26309761abc68c4718d6045 100644
--- a/third_party/blink/common/loader/throttling_url_loader_unittest.cc
+++ b/third_party/blink/common/loader/throttling_url_loader_unittest.cc
@@ -342,9 +342,9 @@ class TestURLLoaderThrottle : public blink::URLLoaderThrottle {
network::mojom::URLResponseHead* response_head,
bool* defer) override {
will_process_response_called_++;
+ response_url_ = response_url;
if (will_process_response_callback_)
will_process_response_callback_.Run(delegate_.get(), defer);
- response_url_ = response_url;
}
void BeforeWillProcessResponse(
@@ -424,6 +424,11 @@ class ThrottlingURLLoaderTest : public testing::Test {
factory_.factory_remote().FlushForTesting();
}
+ void ResetLoader() {
+ ResetThrottleRawPointer();
+ loader_.reset();
+ }
+
void ResetThrottleRawPointer() { throttle_ = nullptr; }
// Be the first member so it is destroyed last.
@@ -469,6 +474,25 @@ TEST_F(ThrottlingURLLoaderTest, CancelBeforeStart) {
EXPECT_EQ(1u, client_.on_complete_called());
}
+TEST_F(ThrottlingURLLoaderTest, DeleteBeforeStart) {
+ base::RunLoop run_loop;
+ throttle_->set_will_start_request_callback(base::BindLambdaForTesting(
+ [this, &run_loop](blink::URLLoaderThrottle::Delegate* delegate,
+ bool* defer) {
+ ResetLoader();
+ run_loop.Quit();
+ }));
+
+ CreateLoaderAndStart();
+ run_loop.Run();
+
+ EXPECT_EQ(1u, factory_.create_loader_and_start_called());
+
+ EXPECT_EQ(0u, client_.on_received_response_called());
+ EXPECT_EQ(0u, client_.on_received_redirect_called());
+ EXPECT_EQ(0u, client_.on_complete_called());
+}
+
TEST_F(ThrottlingURLLoaderTest, DeferBeforeStart) {
throttle_->set_will_start_request_callback(base::BindLambdaForTesting(
[](blink::URLLoaderThrottle::Delegate* delegate, bool* defer) {
@@ -699,6 +723,88 @@ TEST_F(ThrottlingURLLoaderTest, CancelBeforeRedirect) {
EXPECT_EQ(1u, client_.on_complete_called());
}
+TEST_F(ThrottlingURLLoaderTest, DeleteBeforeRedirect) {
+ base::RunLoop run_loop;
+ throttle_->set_will_redirect_request_callback(base::BindLambdaForTesting(
+ [this, &run_loop](
+ blink::URLLoaderThrottle::Delegate* delegate, bool* /* defer */,
+ std::vector<std::string>* /* removed_headers */,
+ net::HttpRequestHeaders* /* modified_headers */,
+ net::HttpRequestHeaders* /* modified_cors_exempt_headers */) {
+ ResetLoader();
+ run_loop.Quit();
+ }));
+
+ CreateLoaderAndStart();
+
+ factory_.NotifyClientOnReceiveRedirect();
+
+ run_loop.Run();
+
+ EXPECT_EQ(0u, client_.on_received_response_called());
+ EXPECT_EQ(0u, client_.on_received_redirect_called());
+ EXPECT_EQ(0u, client_.on_complete_called());
+}
+
+TEST_F(ThrottlingURLLoaderTest, CancelBeforeWillRedirect) {
+ throttle_->set_before_will_redirect_request_callback(
+ base::BindLambdaForTesting(
+ [](blink::URLLoaderThrottle::Delegate* delegate,
+ RestartWithURLReset* restart_with_url_reset,
+ std::vector<std::string>* /* removed_headers */,
+ net::HttpRequestHeaders* /* modified_headers */,
+ net::HttpRequestHeaders* /* modified_cors_exempt_headers */) {
+ delegate->CancelWithError(net::ERR_ACCESS_DENIED);
+ }));
+
+ base::RunLoop run_loop;
+ client_.set_on_complete_callback(
+ base::BindLambdaForTesting([&run_loop](int error) {
+ EXPECT_EQ(net::ERR_ACCESS_DENIED, error);
+ run_loop.Quit();
+ }));
+
+ CreateLoaderAndStart();
+
+ factory_.NotifyClientOnReceiveRedirect();
+
+ run_loop.Run();
+
+ EXPECT_EQ(1u, throttle_->will_start_request_called());
+ EXPECT_EQ(1u, throttle_->will_redirect_request_called());
+ EXPECT_EQ(0u, throttle_->before_will_process_response_called());
+ EXPECT_EQ(0u, throttle_->will_process_response_called());
+
+ EXPECT_EQ(0u, client_.on_received_response_called());
+ EXPECT_EQ(0u, client_.on_received_redirect_called());
+ EXPECT_EQ(1u, client_.on_complete_called());
+}
+
+TEST_F(ThrottlingURLLoaderTest, DeleteBeforeWillRedirect) {
+ base::RunLoop run_loop;
+ throttle_->set_before_will_redirect_request_callback(
+ base::BindLambdaForTesting(
+ [this, &run_loop](
+ blink::URLLoaderThrottle::Delegate* delegate,
+ RestartWithURLReset* restart_with_url_reset,
+ std::vector<std::string>* /* removed_headers */,
+ net::HttpRequestHeaders* /* modified_headers */,
+ net::HttpRequestHeaders* /* modified_cors_exempt_headers */) {
+ ResetLoader();
+ run_loop.Quit();
+ }));
+
+ CreateLoaderAndStart();
+
+ factory_.NotifyClientOnReceiveRedirect();
+
+ run_loop.Run();
+
+ EXPECT_EQ(0u, client_.on_received_response_called());
+ EXPECT_EQ(0u, client_.on_received_redirect_called());
+ EXPECT_EQ(0u, client_.on_complete_called());
+}
+
TEST_F(ThrottlingURLLoaderTest, DeferBeforeRedirect) {
base::RunLoop run_loop1;
throttle_->set_will_redirect_request_callback(base::BindLambdaForTesting(
@@ -946,6 +1052,77 @@ TEST_F(ThrottlingURLLoaderTest, CancelBeforeResponse) {
EXPECT_EQ(1u, client_.on_complete_called());
}
+TEST_F(ThrottlingURLLoaderTest, DeleteBeforeResponse) {
+ base::RunLoop run_loop;
+ throttle_->set_will_process_response_callback(base::BindLambdaForTesting(
+ [this, &run_loop](blink::URLLoaderThrottle::Delegate* delegate,
+ bool* defer) {
+ ResetLoader();
+ run_loop.Quit();
+ }));
+
+ CreateLoaderAndStart();
+
+ factory_.NotifyClientOnReceiveResponse();
+
+ run_loop.Run();
+
+ EXPECT_EQ(0u, client_.on_received_response_called());
+ EXPECT_EQ(0u, client_.on_received_redirect_called());
+ EXPECT_EQ(0u, client_.on_complete_called());
+}
+
+TEST_F(ThrottlingURLLoaderTest, CancelBeforeWillProcessResponse) {
+ throttle_->set_before_will_process_response_callback(
+ base::BindLambdaForTesting(
+ [](blink::URLLoaderThrottle::Delegate* delegate,
+ RestartWithURLReset* restart_with_url_reset) {
+ delegate->CancelWithError(net::ERR_ACCESS_DENIED);
+ }));
+
+ base::RunLoop run_loop;
+ client_.set_on_complete_callback(
+ base::BindLambdaForTesting([&run_loop](int error) {
+ EXPECT_EQ(net::ERR_ACCESS_DENIED, error);
+ run_loop.Quit();
+ }));
+
+ CreateLoaderAndStart();
+
+ factory_.NotifyClientOnReceiveResponse();
+
+ run_loop.Run();
+
+ EXPECT_EQ(1u, throttle_->will_start_request_called());
+ EXPECT_EQ(0u, throttle_->will_redirect_request_called());
+ EXPECT_EQ(1u, throttle_->before_will_process_response_called());
+ EXPECT_EQ(0u, throttle_->will_process_response_called());
+ EXPECT_EQ(0u, client_.on_received_response_called());
+ EXPECT_EQ(0u, client_.on_received_redirect_called());
+ EXPECT_EQ(1u, client_.on_complete_called());
+}
+
+TEST_F(ThrottlingURLLoaderTest, DeleteBeforeWillProcessResponse) {
+ base::RunLoop run_loop;
+ throttle_->set_before_will_process_response_callback(
+ base::BindLambdaForTesting(
+ [this, &run_loop](blink::URLLoaderThrottle::Delegate* delegate,
+ RestartWithURLReset* restart_with_url_reset) {
+ ResetLoader();
+ run_loop.Quit();
+ }));
+
+ CreateLoaderAndStart();
+
+ factory_.NotifyClientOnReceiveResponse();
+
+ run_loop.Run();
+
+ EXPECT_EQ(0u, client_.on_received_response_called());
+ EXPECT_EQ(0u, client_.on_received_redirect_called());
+ EXPECT_EQ(0u, client_.on_complete_called());
+}
+
TEST_F(ThrottlingURLLoaderTest, DeferBeforeResponse) {
base::RunLoop run_loop1;
throttle_->set_will_process_response_callback(base::BindRepeating(

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,166 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Yann Dago <ydago@chromium.org>
Date: Mon, 8 Jul 2024 16:20:32 +0000
Subject: Ensure chrome://policy/test messages ignored when not supported
It was possible to go to chrome://policy and in the dev tools and send
the right message to set test policies even if the policy test page was disabled and/or unavailable because both pages share the same handler.
Bug: 338248595
Change-Id: If689325999cb108b2b71b2821d905e42efd3390d
Low-Coverage-Reason: TRIVIAL_CHANGE
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5679162
Auto-Submit: Yann Dago <ydago@chromium.org>
Reviewed-by: Rohit Rao <rohitrao@chromium.org>
Reviewed-by: Sergey Poromov <poromov@chromium.org>
Commit-Queue: Rohit Rao <rohitrao@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1324277}
diff --git a/chrome/browser/ui/webui/policy/policy_test_ui_browsertest.cc b/chrome/browser/ui/webui/policy/policy_test_ui_browsertest.cc
index 1a597e03d83d6efeb6dc7890745cbb88fd251a23..54f1edd9a386469825b6a42217fb1210b1f6e811 100644
--- a/chrome/browser/ui/webui/policy/policy_test_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/policy/policy_test_ui_browsertest.cc
@@ -8,6 +8,7 @@
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
+#include "chrome/browser/enterprise/browser_management/browser_management_service.h"
#include "chrome/browser/enterprise/browser_management/management_service_factory.h"
#include "chrome/browser/lifetime/application_lifetime.h"
#include "chrome/browser/policy/chrome_browser_policy_connector.h"
@@ -268,6 +269,57 @@ class PolicyTestHandlerTest : public PlatformBrowserTest {
#endif
};
+IN_PROC_BROWSER_TEST_F(PolicyTestHandlerTest,
+ HandleSetLocalTestPoliciesNotSupported) {
+ // Ensure chrome://policy/test not supported.
+ policy::ScopedManagementServiceOverrideForTesting profile_management(
+ policy::ManagementServiceFactory::GetForProfile(GetProfile()),
+ policy::EnterpriseManagementAuthority::CLOUD);
+ std::unique_ptr<PolicyUIHandler> handler = SetUpHandler();
+ const std::string jsonString =
+ R"([
+ {"level": 0,"scope": 0,"source": 0, "namespace": "chrome",
+ "name": "AutofillAddressEnabled","value": false},
+ {"level": 1,"scope": 1,"source": 2, "namespace": "chrome",
+ "name": "CloudReportingEnabled","value": true}
+ ])";
+ const std::string revertAppliedPoliciesButtonDisabledJs =
+ R"(
+ document
+ .querySelector('#revert-applied-policies')
+ .disabled;
+ )";
+
+ base::Value::List list_args;
+
+ list_args.Append("setLocalTestPolicies");
+ list_args.Append(jsonString);
+ list_args.Append("{}");
+
+ // Open chrome://policy
+ ASSERT_TRUE(
+ content::NavigateToURL(web_contents(), GURL(chrome::kChromeUIPolicyURL)));
+ web_ui()->HandleReceivedMessage("setLocalTestPolicies", list_args);
+
+ base::RunLoop().RunUntilIdle();
+
+ const policy::PolicyNamespace chrome_namespace(policy::POLICY_DOMAIN_CHROME,
+ std::string());
+ policy::PolicyService* policy_service =
+ GetProfile()->GetProfilePolicyConnector()->policy_service();
+
+ // Check policies not applied
+ const policy::PolicyMap* policy_map =
+ &policy_service->GetPolicies(chrome_namespace);
+ ASSERT_TRUE(policy_map);
+
+ {
+ const policy::PolicyMap::Entry* entry =
+ policy_map->Get(policy::key::kAutofillAddressEnabled);
+ ASSERT_FALSE(entry);
+ }
+}
+
IN_PROC_BROWSER_TEST_F(PolicyTestHandlerTest,
HandleSetAndRevertLocalTestPolicies) {
if (!policy::utils::IsPolicyTestingEnabled(/*pref_service=*/nullptr,
diff --git a/chrome/browser/ui/webui/policy/policy_ui_handler.cc b/chrome/browser/ui/webui/policy/policy_ui_handler.cc
index 87c5e5be7936533506def5cb8d6eaaa253ca9110..4878c9951b2ef77a5ff875f2fc00a8b41d0f7140 100644
--- a/chrome/browser/ui/webui/policy/policy_ui_handler.cc
+++ b/chrome/browser/ui/webui/policy/policy_ui_handler.cc
@@ -47,6 +47,7 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/chrome_select_file_policy.h"
#include "chrome/browser/ui/webui/webui_util.h"
+#include "chrome/common/channel_info.h"
#include "chrome/grit/branded_strings.h"
#include "components/crx_file/id_util.h"
#include "components/enterprise/browser/controller/browser_dm_token_storage.h"
@@ -67,6 +68,7 @@
#include "components/policy/core/common/policy_pref_names.h"
#include "components/policy/core/common/policy_scheduler.h"
#include "components/policy/core/common/policy_types.h"
+#include "components/policy/core/common/policy_utils.h"
#include "components/policy/core/common/remote_commands/remote_commands_service.h"
#include "components/policy/core/common/schema.h"
#include "components/policy/core/common/schema_map.h"
@@ -288,6 +290,12 @@ void PolicyUIHandler::HandleCopyPoliciesJson(const base::Value::List& args) {
void PolicyUIHandler::HandleSetLocalTestPolicies(
const base::Value::List& args) {
std::string policies = args[1].GetString();
+ AllowJavascript();
+
+ if (!PolicyUI::ShouldLoadTestPage(Profile::FromWebUI(web_ui()))) {
+ ResolveJavascriptCallback(args[0], true);
+ return;
+ }
policy::LocalTestPolicyProvider* local_test_provider =
static_cast<policy::LocalTestPolicyProvider*>(
@@ -310,12 +318,14 @@ void PolicyUIHandler::HandleSetLocalTestPolicies(
->UseLocalTestPolicyProvider();
local_test_provider->LoadJsonPolicies(policies);
- AllowJavascript();
ResolveJavascriptCallback(args[0], true);
}
void PolicyUIHandler::HandleRevertLocalTestPolicies(
const base::Value::List& args) {
+ if (!PolicyUI::ShouldLoadTestPage(Profile::FromWebUI(web_ui()))) {
+ return;
+ }
#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_CHROMEOS)
Profile::FromWebUI(web_ui())->GetPrefs()->ClearPref(
prefs::kUserCloudSigninPolicyResponseFromPolicyTestPage);
diff --git a/ios/chrome/browser/ui/webui/policy/policy_ui_handler.mm b/ios/chrome/browser/ui/webui/policy/policy_ui_handler.mm
index a88ad7da3898757ccff4e9f7fa776ca8bef390d6..69429779c9848b5ab72ce9dd1c83efaa7c0eda33 100644
--- a/ios/chrome/browser/ui/webui/policy/policy_ui_handler.mm
+++ b/ios/chrome/browser/ui/webui/policy/policy_ui_handler.mm
@@ -217,6 +217,12 @@
const base::Value::List& args) {
std::string json_policies_string = args[1].GetString();
+ if (!PolicyUI::ShouldLoadTestPage(
+ ChromeBrowserState::FromWebUIIOS(web_ui()))) {
+ web_ui()->ResolveJavascriptCallback(args[0], true);
+ return;
+ }
+
policy::LocalTestPolicyProvider* local_test_provider =
static_cast<policy::LocalTestPolicyProvider*>(
GetApplicationContext()
@@ -235,6 +241,11 @@
void PolicyUIHandler::HandleRevertLocalTestPolicies(
const base::Value::List& args) {
+ if (!PolicyUI::ShouldLoadTestPage(
+ ChromeBrowserState::FromWebUIIOS(web_ui()))) {
+ return;
+ }
+
ChromeBrowserState::FromWebUIIOS(web_ui())
->GetPolicyConnector()
->RevertUseLocalTestPolicyProvider();

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,32 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Rakina Zata Amni <rakina@chromium.org>
Date: Wed, 19 Jun 2024 02:49:58 +0000
Subject: Destruct controller before referenced WebUI in CreateWebUIIfNeeded
Reset `controller` first before resetting `web_ui_`, since the
controller still has a pointer to `web_ui_`, to avoid referencing to
the already deleted `web_ui_` object from `controller`'s destructor.
Bug: 345640549
Change-Id: Ie9c193436b593845d8269605f68bf94bc75beed7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5624749
Commit-Queue: Rakina Zata Amni <rakina@chromium.org>
Reviewed-by: Nasko Oskov <nasko@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1316830}
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index 28a5ef2a8751e85cfa8c29138fe45bdec06ed332..b44b27c099ad798f6ed2e91050263cf03d07d8aa 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -10086,6 +10086,11 @@ void NavigationRequest::CreateWebUIIfNeeded(RenderFrameHostImpl* frame_host) {
bindings() != web_ui_->GetBindings()) {
RecordAction(base::UserMetricsAction("ProcessSwapBindingsMismatch_RVHM"));
base::WeakPtr<NavigationRequest> self = GetWeakPtr();
+ // Reset `controller` first before resetting `web_ui_`, since the controller
+ // still has a pointer to `web_ui_`, to avoid referencing to the already
+ // deleted `web_ui_` object from `controller`'s destructor. See also
+ // https://crbug.com/345640549.
+ controller.reset();
web_ui_.reset();
// Resetting the WebUI may indirectly call content's embedders and delete
// `this`. There are no known occurrences of it, so we assume this never

View File

@@ -0,0 +1,37 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: "mark a. foltz" <mfoltz@chromium.org>
Date: Mon, 17 Jun 2024 23:07:32 +0000
Subject: Retain refptr to shared helper to prevent UAF.
Capture a reference to the shared helper in the onerror handler to
prevent a UAF that can occur when the browser drops the mojo
connection.
Bug: 346692546
Change-Id: Ifb264488a6fa8417c134a34d902605d2c141720b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5634908
Reviewed-by: Avi Drissman <avi@chromium.org>
Commit-Queue: Mark Foltz <mfoltz@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1316145}
diff --git a/media/audio/mac/audio_loopback_input_mac_impl.mm b/media/audio/mac/audio_loopback_input_mac_impl.mm
index 7b301492f17a3f1da96b8ff990f6deeb4a19b6e3..f90c00e668f58c2389e622466422ae7aa237c94d 100644
--- a/media/audio/mac/audio_loopback_input_mac_impl.mm
+++ b/media/audio/mac/audio_loopback_input_mac_impl.mm
@@ -394,12 +394,15 @@ - (void)stream:(SCStream*)stream
base::BindRepeating(&SCKAudioInputStream::OnStreamError,
base::Unretained(this)));
+ // Make a local copy of the shared_refptr in case the error handler is called
+ // after `this` is destroyed.
+ auto local_shared_helper = shared_helper_;
[stream_ startCaptureWithCompletionHandler:^(NSError* error) {
if (!error) {
return;
}
- shared_helper_->OnStreamError(error);
+ local_shared_helper->OnStreamError(error);
}];
}

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

@@ -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

@@ -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" }
]

2
patches/dawn/.patches Normal file
View File

@@ -0,0 +1,2 @@
dawn_dxc_disable_dxc_pass_structurize-loop-exits-for-unroll.patch
reland_deps_update_dxc_to_patched_branch.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

@@ -0,0 +1,39 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: David Neto <dneto@google.com>
Date: Mon, 29 Jul 2024 20:20:18 +0000
Subject: Reland "DEPS: Update DXC to patched branch"
This is a reland of commit 5fd60bc03720ebd5a804cd64e8a52ba9e95593f5
Original change's description:
> DEPS: Update DXC to patched branch
>
> Also, add DXC_CODEGEN_EXCEPTIONS_TRAP=1 to DXC gn config.
>
> Bug: chromium:346618785, chromium:350696474
> Change-Id: I4c1ac753d824c4790e78d8f36231c8f2fe0e2722
> Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/198756
> Reviewed-by: Natalie Chouinard <chouinard@google.com>
Bug: chromium:346618785, chromium:350696474
Change-Id: I9205dc9a028654388e09ffb853c64ff2010b793f
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/200494
Reviewed-by: David Neto <dneto@google.com>
Reviewed-by: Natalie Chouinard <chouinard@google.com>
diff --git a/third_party/gn/dxc/BUILD.gn b/third_party/gn/dxc/BUILD.gn
index aadb64eeb4fba2f2da442a8a7f4b285a469c5cdd..0060484cefcf1835138b111258c33e09fab1279c 100644
--- a/third_party/gn/dxc/BUILD.gn
+++ b/third_party/gn/dxc/BUILD.gn
@@ -453,7 +453,10 @@ cmake_configure_file("clang-config-h") {
cmake_configure_file("dxc-config-h") {
input = "$dawn_dxc_dir/include/dxc/config.h.cmake"
output = "$target_gen_dir/include/dxc/config.h"
- values = [ "DXC_DISABLE_ALLOCATOR_OVERRIDES=1" ]
+ values = [
+ "DXC_DISABLE_ALLOCATOR_OVERRIDES=1",
+ "DXC_CODEGEN_EXCEPTIONS_TRAP=1",
+ ]
}
#######################################################################

View File

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

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