Compare commits

..

63 Commits

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

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

* chore: update patches

---------

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

* chore: update patches

---------

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

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

* chore: update patches

---------

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

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

* chore: update patches

---------

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

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

* chore: update patches

---------

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

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

* chore: update patches after trop

---------

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

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

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

* fix: allow multiple directory selection in KDE implementation

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

* chore: update patches

---------

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

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

* Update shell/browser/javascript_environment.cc

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

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

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-06-11 12:10:16 -05:00
trop[bot]
dcf12182b8 fix: loginService -> loginItemService (#42405)
fix: loginService -> loginItemService

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

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

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

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

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

---------

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

* chore: update patches

---------

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

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

* chore: update patches

---------

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

* chore: update patches

---------

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

* chore: update patches

---------

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

* chore: update patches

---------

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

* c67f290ef0f0 from angle

* chore: update patches

---------

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

* chore: update patches

---------

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

* chore: update patches

---------

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

* 1b454576028b from chromium
* 0d9350b71fd0 from chromium

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

* 98bcf9ef5cdd from chromium
* bd7aa9779873 from DirectXShaderCompiler

* chore: update patches

---------

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

* bc18aec94c82 from DirectXShaderCompiler
* ba3b4e239620 from angle

* chore: update patches

---------

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

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

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

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

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

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

* chore: update patches

---------

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

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

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

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

* chore: remove code not related to this pr:

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

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

* chore: update patches

---------

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

* chore: update patches

---------

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

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

* fix: bluetooth dependency

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

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-04-01 10:55:37 -04:00
trop[bot]
f9e28e3e50 fix: Storage.{get|set|clear}Cookies via CDP not working (#41739)
* fix: Storage.{get|set|clear}Cookies via CDP not working

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

* chore: simplify BrowserContext plumbing

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

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-03-29 09:51:43 -05:00
trop[bot]
3698f89205 fix: don't do self-destroy in LibnotifyNotification::Dismiss() (#41707)
Callers of Notification::Dismiss() assume that the notification
instance is not deleted after the call, but this was not the case
for LibnotifyNotification:
- Destroy() would get `this` deleted.
- notify_notification_close() in portal environment triggers
LibnotifyNotification::OnNotificationClosed(), and finally calls
Destroy()

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

Fixes #40461.

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

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2024-03-27 10:59:00 -05:00
136 changed files with 9764 additions and 1842 deletions

View File

@@ -260,9 +260,9 @@ step-depot-tools-get: &step-depot-tools-get
index c305c248..e6e0fbdc 100755
--- a/gclient.py
+++ b/gclient.py
@@ -735,7 +735,8 @@ class Dependency(gclient_utils.WorkItem, DependencySettings):
if dep_type == 'cipd':
@@ -783,7 +783,8 @@ class Dependency(gclient_utils.WorkItem, DependencySettings):
not condition or "non_git_source" not in condition):
continue
cipd_root = self.GetCipdRoot()
- for package in dep_value.get('packages', []):
+ packages = dep_value.get('packages', [])

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

@@ -1261,7 +1261,7 @@ Returns `Object`:
* `openAtLogin` boolean - `true` if the app is set to open at login.
* `openAsHidden` boolean _macOS_ _Deprecated_ - `true` if the app is set to open as hidden at login. This does not work on macOS 13 and up.
* `wasOpenedAtLogin` boolean _macOS_ _Deprecated_ - `true` if the app was opened at login automatically. This setting is not available on [MAS builds][mas-builds] or on macOS 13 and up.
* `wasOpenedAtLogin` boolean _macOS_ - `true` if the app was opened at login automatically.
* `wasOpenedAsHidden` boolean _macOS_ _Deprecated_ - `true` if the app was opened as a hidden login item. This indicates that the app should not open any windows at startup. This setting is not available on [MAS builds][mas-builds] or on macOS 13 and up.
* `restoreState` boolean _macOS_ _Deprecated_ - `true` if the app was opened as a login item that should restore the state from the previous session. This indicates that the app should restore the windows that were open the last time the app was closed. This setting is not available on [MAS builds][mas-builds] or on macOS 13 and up.
* `status` string _macOS_ - can be one of `not-registered`, `enabled`, `requires-approval`, or `not-found`.

View File

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

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

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,10 @@
cherry-pick-a65e511a14b4.patch
cherry-pick-bc18aec94c82.patch
cherry-pick-bd7aa9779873.patch
cherry-pick-2a434fd0af6b.patch
cherry-pick-867c1001637e.patch
cherry-pick-0b785e88fefa.patch
cherry-pick-511cfef8e050.patch
cherry-pick-93c3cf1c787f.patch
cherry-pick-33051b084850.patch
cherry-pick-b845fed99111.patch

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

5
patches/angle/.patches Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -133,3 +133,20 @@ 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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

1
patches/dawn/.patches Normal file
View File

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

View File

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

View File

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

View File

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

2
patches/libaom/.patches Normal file
View File

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

View File

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

View File

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

View File

@@ -53,3 +53,6 @@ fix_undici_incorrectly_copies_headers_onto_fetches.patch
fix_revert_src_lb_reducing_c_calls_of_esm_legacy_main_resolve.patch
src_preload_function_for_environment.patch
fs_fix_wtf-8_decoding_issue.patch
stream_do_not_defer_construction_by_one_microtick.patch
deps_disable_io_uring_support_in_libuv_by_default.patch
src_deps_disable_setuid_etc_if_io_uring_enabled.patch

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,92 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jakob Kummerow <jkummerow@chromium.org>
Date: Thu, 13 Jun 2024 12:26:46 +0200
Subject: Merged: [wasm][liftoff][arm64] Fix DropExceptionValueAtOffset
We cannot exit the iteration early, we must update all entries
in the cache state.
Fixed: 343748812
(cherry picked from commit 910cb91733dc47b8f4a3dc9f1ca640b728f97aad)
Change-Id: Ib342467f35360baaa14cd098b258bd1acf4189a7
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5626023
Commit-Queue: Matthias Liedtke <mliedtke@chromium.org>
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Matthias Liedtke <mliedtke@chromium.org>
Auto-Submit: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/branch-heads/12.6@{#32}
Cr-Branched-From: 3c9fa12db3183a6f4ea53d2675adb66ea1194529-refs/heads/12.6.228@{#2}
Cr-Branched-From: 981bb15ba4dbf9e2381dfc94ec2c4af0b9c6a0b6-refs/heads/main@{#93835}
diff --git a/src/wasm/baseline/liftoff-assembler.cc b/src/wasm/baseline/liftoff-assembler.cc
index 821b6b80495849129c2c499302ac393278f72e92..e1ca7bebdc8408e21715dd0fc9861a474b989bcc 100644
--- a/src/wasm/baseline/liftoff-assembler.cc
+++ b/src/wasm/baseline/liftoff-assembler.cc
@@ -430,12 +430,13 @@ void LiftoffAssembler::DropExceptionValueAtOffset(int offset) {
slot != end; ++slot) {
*slot = *(slot + 1);
stack_offset = NextSpillOffset(slot->kind(), stack_offset);
- // Padding could allow us to exit early.
- if (slot->offset() == stack_offset) break;
- if (slot->is_stack()) {
- MoveStackValue(stack_offset, slot->offset(), slot->kind());
+ // Padding could cause some spill offsets to remain the same.
+ if (slot->offset() != stack_offset) {
+ if (slot->is_stack()) {
+ MoveStackValue(stack_offset, slot->offset(), slot->kind());
+ }
+ slot->set_offset(stack_offset);
}
- slot->set_offset(stack_offset);
}
cache_state_.stack_state.pop_back();
}
diff --git a/test/mjsunit/mjsunit.status b/test/mjsunit/mjsunit.status
index a7af302742da61501378af52ab32d0662fc6dd9c..def43115ba6cf4e4201d26c2949436c029b5379d 100644
--- a/test/mjsunit/mjsunit.status
+++ b/test/mjsunit/mjsunit.status
@@ -1689,6 +1689,7 @@
'regress/wasm/regress-1487077': [SKIP],
'regress/wasm/regress-1500812': [SKIP],
'regress/wasm/regress-323694592': [SKIP],
+ 'regress/wasm/regress-343748812': [SKIP],
'regress/wasm/regress-crbug-1338980': [SKIP],
'regress/wasm/regress-crbug-1355070': [SKIP],
'regress/wasm/regress-crbug-1356718': [SKIP],
diff --git a/test/mjsunit/regress/wasm/regress-343748812.js b/test/mjsunit/regress/wasm/regress-343748812.js
new file mode 100644
index 0000000000000000000000000000000000000000..8dc456c413665e97c5f8e48f95a65370cf051753
--- /dev/null
+++ b/test/mjsunit/regress/wasm/regress-343748812.js
@@ -0,0 +1,30 @@
+// Copyright 2024 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
+
+const builder = new WasmModuleBuilder();
+let $sig0 = builder.addType(kSig_v_v);
+let $sig7 = builder.addType(
+ makeSig([], [ kWasmExternRef, kWasmS128, kWasmExternRef ]));
+let $func0 = builder.addImport('imports', 'func0', $sig0);
+builder.addFunction("main", $sig0).exportFunc()
+ .addLocals(kWasmExternRef, 3)
+ .addBody([
+ kExprTry, $sig7,
+ kExprCallFunction, $func0,
+ kExprUnreachable,
+ kExprCatchAll,
+ kExprRefNull, kExternRefCode,
+ ...wasmS128Const([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
+ kExprRefNull, kExternRefCode,
+ kExprEnd,
+ kExprDrop,
+ kExprDrop,
+ kExprDrop,
+ ]);
+
+var instance = builder.instantiate({'imports': { 'func0': () => {} }});
+
+assertThrows(instance.exports.main, WebAssembly.RuntimeError, /unreachable/);

View File

@@ -0,0 +1,31 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Matthias Liedtke <mliedtke@chromium.org>
Date: Fri, 10 May 2024 10:38:29 +0200
Subject: Merged: [builtins] HasOnlySimpleElements is false for non-JSObjects
Bug: 338908243
(cherry picked from commit cc05792346fb017eaa961ee7d35cf1f9bb53bb0a)
Change-Id: I9b5c2333924a54169ea3fa48e67e7db2ec67f6b9
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5545380
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Matthias Liedtke <mliedtke@chromium.org>
Auto-Submit: Matthias Liedtke <mliedtke@chromium.org>
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/branch-heads/12.4@{#34}
Cr-Branched-From: 309640da62fae0485c7e4f64829627c92d53b35d-refs/heads/12.4.254@{#1}
Cr-Branched-From: 5dc24701432278556a9829d27c532f974643e6df-refs/heads/main@{#92862}
diff --git a/src/builtins/builtins-array.cc b/src/builtins/builtins-array.cc
index 60dc19367aa38997721ed85df6210f9de3a44313..dc82b658df09e5850ef2688fae1d748cb9873917 100644
--- a/src/builtins/builtins-array.cc
+++ b/src/builtins/builtins-array.cc
@@ -51,7 +51,7 @@ inline bool HasOnlySimpleElements(Isolate* isolate,
DisallowGarbageCollection no_gc;
PrototypeIterator iter(isolate, receiver, kStartAtReceiver);
for (; !iter.IsAtEnd(); iter.Advance()) {
- if (IsJSProxy(iter.GetCurrent())) return false;
+ if (!IsJSObject(iter.GetCurrent())) return false;
Tagged<JSObject> current = iter.GetCurrent<JSObject>();
if (!HasSimpleElements(current)) return false;
}

View File

@@ -0,0 +1,27 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shu-yu Guo <syg@chromium.org>
Date: Thu, 9 May 2024 12:03:28 -0700
Subject: Only normalize JSObject targets in SetOrCopyDataProperties
Bug: 339458194
Change-Id: I4d6eebdd921971fa28d7c474535d978900ba633f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5527397
Reviewed-by: Rezvan Mahdavi Hezaveh <rezvan@chromium.org>
Commit-Queue: Shu-yu Guo <syg@chromium.org>
Cr-Commit-Position: refs/heads/main@{#93811}
diff --git a/src/objects/js-objects.cc b/src/objects/js-objects.cc
index 32e1e89fc53217fe188c1f764bd97c03dadf35a2..0381a9f65a9e6cdfb30881077e4a442cd2a10802 100644
--- a/src/objects/js-objects.cc
+++ b/src/objects/js-objects.cc
@@ -429,9 +429,7 @@ Maybe<bool> JSReceiver::SetOrCopyDataProperties(
Nothing<bool>());
if (!from->HasFastProperties() && target->HasFastProperties() &&
- !IsJSGlobalProxy(*target)) {
- // JSProxy is always in slow-mode.
- DCHECK(!IsJSProxy(*target));
+ IsJSObject(*target) && !IsJSGlobalProxy(*target)) {
// Convert to slow properties if we're guaranteed to overflow the number of
// descriptors.
int source_length;

View File

@@ -0,0 +1,45 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shu-yu Guo <syg@chromium.org>
Date: Fri, 10 May 2024 12:08:04 -0700
Subject: Merged: [ic] Use slow stub element handler for non-JSObjects
Fixed: 339736513
(cherry picked from commit 8a69c7880844ab00ee2f32079579a040a87eedca)
Change-Id: If87462eb044c194798a32cb25a5f3648ff823196
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5555847
Commit-Queue: Shu-yu Guo <syg@chromium.org>
Reviewed-by: Adam Klein <adamk@chromium.org>
Commit-Queue: Adam Klein <adamk@chromium.org>
Auto-Submit: Shu-yu Guo <syg@chromium.org>
Cr-Commit-Position: refs/branch-heads/12.4@{#36}
Cr-Branched-From: 309640da62fae0485c7e4f64829627c92d53b35d-refs/heads/12.4.254@{#1}
Cr-Branched-From: 5dc24701432278556a9829d27c532f974643e6df-refs/heads/main@{#92862}
diff --git a/src/ic/ic.cc b/src/ic/ic.cc
index 61bb82aff98e4273b651801b875416c686de872e..34cf7eb6d2f5ef74b37103a6ee2356b8825d3f58 100644
--- a/src/ic/ic.cc
+++ b/src/ic/ic.cc
@@ -2349,15 +2349,16 @@ Handle<Object> KeyedStoreIC::StoreElementHandler(
isolate()),
IsStoreInArrayLiteralIC());
- if (IsJSProxyMap(*receiver_map)) {
+ if (!IsJSObjectMap(*receiver_map)) {
// DefineKeyedOwnIC, which is used to define computed fields in instances,
- // should be handled by the slow stub.
- if (IsDefineKeyedOwnIC()) {
- TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_SlowStub);
- return StoreHandler::StoreSlow(isolate(), store_mode);
+ // should handled by the slow stub below instead of the proxy stub.
+ if (IsJSProxyMap(*receiver_map) && !IsDefineKeyedOwnIC()) {
+ return StoreHandler::StoreProxy(isolate());
}
- return StoreHandler::StoreProxy(isolate());
+ // Wasm objects or other kind of special objects go through the slow stub.
+ TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_SlowStub);
+ return StoreHandler::StoreSlow(isolate(), store_mode);
}
// TODO(ishell): move to StoreHandler::StoreElement().

View File

@@ -0,0 +1,65 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Andreas Haas <ahaas@chromium.org>
Date: Mon, 18 Mar 2024 15:25:15 +0100
Subject: Merged: [wasm][gc] Scan the code field of the WasmInternalFunction
The code field in the WasmInternalFunction is a code pointer since
https://crrev.com/c/5110559, so it has to be scanned explicitly.
Bug: 329130358
(cherry picked from commit b93975a48c722c2e5fe9b39437738eb2e23dac74)
Change-Id: I0795d2188a8af3480c513d1dbaccfcef1da04473
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5410311
Reviewed-by: Deepti Gandluri <gdeepti@chromium.org>
Commit-Queue: Deepti Gandluri <gdeepti@chromium.org>
Auto-Submit: Shu-yu Guo <syg@chromium.org>
Cr-Commit-Position: refs/branch-heads/12.2@{#54}
Cr-Branched-From: 6eb5a9616aa6f8c705217aeb7c7ab8c037a2f676-refs/heads/12.2.281@{#1}
Cr-Branched-From: 44cf56d850167c6988522f8981730462abc04bcc-refs/heads/main@{#91934}
diff --git a/src/objects/objects-body-descriptors-inl.h b/src/objects/objects-body-descriptors-inl.h
index 4041a10b3d0e22fa95f263528f331dad1eadaf8b..e9ecda50718a85847ad1205bdcf2f275208fbc12 100644
--- a/src/objects/objects-body-descriptors-inl.h
+++ b/src/objects/objects-body-descriptors-inl.h
@@ -791,6 +791,7 @@ class WasmInternalFunction::BodyDescriptor final : public BodyDescriptorBase {
v->VisitExternalPointer(
obj, obj->RawExternalPointerField(kCallTargetOffset,
kWasmInternalFunctionCallTargetTag));
+ IterateCodePointer(obj, kCodeOffset, v, IndirectPointerMode::kStrong);
}
static inline int SizeOf(Tagged<Map> map, Tagged<HeapObject> object) {
diff --git a/test/mjsunit/regress/wasm/regress-329130358.js b/test/mjsunit/regress/wasm/regress-329130358.js
new file mode 100644
index 0000000000000000000000000000000000000000..d5231768989d9c709da7102bdd6be5702a89f2f8
--- /dev/null
+++ b/test/mjsunit/regress/wasm/regress-329130358.js
@@ -0,0 +1,27 @@
+// Copyright 2024 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+// Flags: --expose-gc --wasm-wrapper-tiering-budget=1 --experimental-wasm-type-reflection
+
+d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
+
+const builder = new WasmModuleBuilder();
+const type = builder.addType(kSig_i_i);
+const global = builder.addImportedGlobal('m', 'val', kWasmAnyFunc);
+
+builder.addFunction('main', type)
+ .addBody([
+ kExprLocalGet, 0, kExprGlobalGet, global, kGCPrefix, kExprRefCast, type,
+ kExprCallRef, type
+ ])
+ .exportFunc();
+
+function foo() {
+ gc();
+}
+const func =
+ new WebAssembly.Function({parameters: ['i32'], results: ['i32']}, foo);
+
+let instance = builder.instantiate({m: {val: func}});
+instance.exports.main(3);
+instance.exports.main(3);

View File

@@ -75,7 +75,8 @@ function spawnAndCheckExitCode (cmd, args, opts) {
function cpplint (args) {
args.unshift(`--root=${SOURCE_ROOT}`);
const result = childProcess.spawnSync(IS_WINDOWS ? 'cpplint.bat' : 'cpplint.py', args, { encoding: 'utf8', shell: true });
const cmd = IS_WINDOWS ? 'cpplint.bat' : 'cpplint.py';
const result = childProcess.spawnSync(cmd, args, { encoding: 'utf8', shell: true });
// cpplint.py writes EVERYTHING to stderr, including status messages
if (result.stderr) {
for (const line of result.stderr.split(/[\r\n]+/)) {

View File

@@ -93,7 +93,8 @@ async function main () {
const { status: buildStatus } = cp.spawnSync(NPX_CMD, ['node-gyp', 'rebuild', '--verbose', '--directory', 'test', '-j', 'max'], {
env,
cwd: NAN_DIR,
stdio: 'inherit'
stdio: 'inherit',
shell: process.platform === 'win32'
});
if (buildStatus !== 0) {
@@ -104,7 +105,8 @@ async function main () {
const { status: installStatus } = cp.spawnSync(NPX_CMD, [`yarn@${YARN_VERSION}`, 'install'], {
env,
cwd: NAN_DIR,
stdio: 'inherit'
stdio: 'inherit',
shell: process.platform === 'win32'
});
if (installStatus !== 0) {
console.error('Failed to install nan node_modules');

View File

@@ -10,7 +10,8 @@ if (fs.existsSync(checkPath)) {
command.slice(1),
{
stdio: 'inherit',
cwd: checkPath
cwd: checkPath,
shell: process.platform === 'win32'
}
);
child.on('exit', code => process.exit(code));

View File

@@ -221,7 +221,8 @@ async function installSpecModules (dir) {
const { status } = childProcess.spawnSync(NPX_CMD, [`yarn@${YARN_VERSION}`, 'install', '--frozen-lockfile'], {
env,
cwd: dir,
stdio: 'inherit'
stdio: 'inherit',
shell: process.platform === 'win32'
});
if (status !== 0 && !process.env.IGNORE_YARN_INSTALL_ERROR) {
console.log(`${fail} Failed to yarn install in '${dir}'`);

View File

@@ -11,7 +11,8 @@ if (require.main === module) {
env: {
...process.env,
npm_config_yes: 'true'
}
},
shell: process.platform === 'win32'
});
child.on('exit', code => process.exit(code));

View File

@@ -884,12 +884,6 @@ void App::BrowserChildProcessCrashedOrKilled(
if (!data.name.empty()) {
details.Set("name", data.name);
}
if (data.process_type == content::PROCESS_TYPE_UTILITY) {
base::ProcessId pid = data.GetProcess().Pid();
auto utility_process_wrapper = UtilityProcessWrapper::FromProcessId(pid);
if (utility_process_wrapper)
utility_process_wrapper->Shutdown(info.exit_code);
}
Emit("child-process-gone", details);
}

View File

@@ -11,6 +11,7 @@
#include "base/containers/contains.h"
#include "base/task/single_thread_task_runner.h"
#include "content/public/common/color_parser.h"
#include "electron/buildflags/buildflags.h"
#include "gin/dictionary.h"
#include "shell/browser/api/electron_api_browser_view.h"
@@ -37,6 +38,7 @@
#endif
#if BUILDFLAG(IS_WIN)
#include "shell/browser/ui/views/win_frame_view.h"
#include "shell/browser/ui/win/taskbar_host.h"
#include "ui/base/win/shell.h"
#endif
@@ -1134,6 +1136,63 @@ void BaseWindow::SetAppDetails(const gin_helper::Dictionary& options) {
relaunch_command, relaunch_display_name,
window_->GetAcceleratedWidget());
}
void BaseWindow::SetTitleBarOverlay(const gin_helper::Dictionary& options,
gin_helper::Arguments* args) {
// Ensure WCO is already enabled on this window
if (!window_->titlebar_overlay_enabled()) {
args->ThrowError("Titlebar overlay is not enabled");
return;
}
auto* window = static_cast<NativeWindowViews*>(window_.get());
bool updated = false;
// Check and update the button color
std::string btn_color;
if (options.Get(options::kOverlayButtonColor, &btn_color)) {
// Parse the string as a CSS color
SkColor color;
if (!content::ParseCssColorString(btn_color, &color)) {
args->ThrowError("Could not parse color as CSS color");
return;
}
// Update the view
window->set_overlay_button_color(color);
updated = true;
}
// Check and update the symbol color
std::string symbol_color;
if (options.Get(options::kOverlaySymbolColor, &symbol_color)) {
// Parse the string as a CSS color
SkColor color;
if (!content::ParseCssColorString(symbol_color, &color)) {
args->ThrowError("Could not parse symbol color as CSS color");
return;
}
// Update the view
window->set_overlay_symbol_color(color);
updated = true;
}
// Check and update the height
int height = 0;
if (options.Get(options::kOverlayHeight, &height)) {
window->set_titlebar_overlay_height(height);
updated = true;
}
// If anything was updated, invalidate the layout and schedule a paint of the
// window's frame view
if (updated) {
auto* frame_view = static_cast<WinFrameView*>(
window->widget()->non_client_view()->frame_view());
frame_view->InvalidateCaptionButtons();
}
}
#endif
int32_t BaseWindow::GetID() const {
@@ -1351,6 +1410,7 @@ void BaseWindow::BuildPrototype(v8::Isolate* isolate,
.SetMethod("setThumbnailClip", &BaseWindow::SetThumbnailClip)
.SetMethod("setThumbnailToolTip", &BaseWindow::SetThumbnailToolTip)
.SetMethod("setAppDetails", &BaseWindow::SetAppDetails)
.SetMethod("setTitleBarOverlay", &BaseWindow::SetTitleBarOverlay)
#endif
.SetProperty("id", &BaseWindow::GetID);
}

View File

@@ -251,6 +251,8 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>,
bool SetThumbnailClip(const gfx::Rect& region);
bool SetThumbnailToolTip(const std::string& tooltip);
void SetAppDetails(const gin_helper::Dictionary& options);
void SetTitleBarOverlay(const gin_helper::Dictionary& options,
gin_helper::Arguments* args);
#endif
int32_t GetID() const;

View File

@@ -10,7 +10,6 @@
#include "content/browser/web_contents/web_contents_impl.h" // nogncheck
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/common/color_parser.h"
#include "shell/browser/api/electron_api_web_contents_view.h"
#include "shell/browser/browser.h"
#include "shell/browser/native_browser_view.h"
@@ -28,10 +27,6 @@
#include "shell/browser/native_window_views.h"
#endif
#if BUILDFLAG(IS_WIN)
#include "shell/browser/ui/views/win_frame_view.h"
#endif
namespace electron::api {
BrowserWindow::BrowserWindow(gin::Arguments* args,
@@ -332,65 +327,6 @@ v8::Local<v8::Value> BrowserWindow::GetWebContents(v8::Isolate* isolate) {
return v8::Local<v8::Value>::New(isolate, web_contents_);
}
#if BUILDFLAG(IS_WIN)
void BrowserWindow::SetTitleBarOverlay(const gin_helper::Dictionary& options,
gin_helper::Arguments* args) {
// Ensure WCO is already enabled on this window
if (!window_->titlebar_overlay_enabled()) {
args->ThrowError("Titlebar overlay is not enabled");
return;
}
auto* window = static_cast<NativeWindowViews*>(window_.get());
bool updated = false;
// Check and update the button color
std::string btn_color;
if (options.Get(options::kOverlayButtonColor, &btn_color)) {
// Parse the string as a CSS color
SkColor color;
if (!content::ParseCssColorString(btn_color, &color)) {
args->ThrowError("Could not parse color as CSS color");
return;
}
// Update the view
window->set_overlay_button_color(color);
updated = true;
}
// Check and update the symbol color
std::string symbol_color;
if (options.Get(options::kOverlaySymbolColor, &symbol_color)) {
// Parse the string as a CSS color
SkColor color;
if (!content::ParseCssColorString(symbol_color, &color)) {
args->ThrowError("Could not parse symbol color as CSS color");
return;
}
// Update the view
window->set_overlay_symbol_color(color);
updated = true;
}
// Check and update the height
int height = 0;
if (options.Get(options::kOverlayHeight, &height)) {
window->set_titlebar_overlay_height(height);
updated = true;
}
// If anything was updated, invalidate the layout and schedule a paint of the
// window's frame view
if (updated) {
auto* frame_view = static_cast<WinFrameView*>(
window->widget()->non_client_view()->frame_view());
frame_view->InvalidateCaptionButtons();
}
}
#endif
void BrowserWindow::ScheduleUnresponsiveEvent(int ms) {
if (!window_unresponsive_closure_.IsCancelled())
return;
@@ -448,9 +384,6 @@ void BrowserWindow::BuildPrototype(v8::Isolate* isolate,
.SetMethod("focusOnWebView", &BrowserWindow::FocusOnWebView)
.SetMethod("blurWebView", &BrowserWindow::BlurWebView)
.SetMethod("isWebViewFocused", &BrowserWindow::IsWebViewFocused)
#if BUILDFLAG(IS_WIN)
.SetMethod("setTitleBarOverlay", &BrowserWindow::SetTitleBarOverlay)
#endif
.SetProperty("webContents", &BrowserWindow::GetWebContents);
}

View File

@@ -79,10 +79,6 @@ class BrowserWindow : public BaseWindow,
void BlurWebView();
bool IsWebViewFocused();
v8::Local<v8::Value> GetWebContents(v8::Isolate* isolate);
#if BUILDFLAG(IS_WIN)
void SetTitleBarOverlay(const gin_helper::Dictionary& options,
gin_helper::Arguments* args);
#endif
private:
// Helpers.

View File

@@ -171,25 +171,96 @@ base::Time ParseTimeProperty(const std::optional<double>& value) {
return base::Time::FromSecondsSinceUnixEpoch(*value);
}
std::string_view InclusionStatusToString(net::CookieInclusionStatus status) {
if (status.HasExclusionReason(net::CookieInclusionStatus::EXCLUDE_HTTP_ONLY))
return "Failed to create httponly cookie";
if (status.HasExclusionReason(
net::CookieInclusionStatus::EXCLUDE_SECURE_ONLY))
return "Cannot create a secure cookie from an insecure URL";
if (status.HasExclusionReason(
net::CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE))
return "Failed to parse cookie";
if (status.HasExclusionReason(
net::CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN))
return "Failed to set cookie with an invalid domain attribute";
if (status.HasExclusionReason(
net::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX))
return "Failed because the cookie violated prefix rules.";
if (status.HasExclusionReason(
net::CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME))
return "Cannot set cookie for current scheme";
return "Setting cookie failed";
const std::string InclusionStatusToString(net::CookieInclusionStatus status) {
// See net/cookies/cookie_inclusion_status.h for cookie error descriptions.
constexpr std::array<
std::pair<net::CookieInclusionStatus::ExclusionReason, std::string_view>,
net::CookieInclusionStatus::ExclusionReason::NUM_EXCLUSION_REASONS>
exclusion_reasons = {
{{net::CookieInclusionStatus::EXCLUDE_HTTP_ONLY,
"The cookie was HttpOnly, but the attempted access was through a "
"non-HTTP API."},
{net::CookieInclusionStatus::EXCLUDE_SECURE_ONLY,
"The cookie was Secure, but the URL was not allowed to access "
"Secure cookies."},
{net::CookieInclusionStatus::EXCLUDE_DOMAIN_MISMATCH,
"The cookie's domain attribute did not match the domain of the URL "
"attempting access."},
{net::CookieInclusionStatus::EXCLUDE_NOT_ON_PATH,
"The cookie's path attribute did not match the path of the URL "
"attempting access."},
{net::CookieInclusionStatus::EXCLUDE_SAMESITE_STRICT,
"The cookie had SameSite=Strict, and the attempted access did not "
"have an appropriate SameSiteCookieContext"},
{net::CookieInclusionStatus::EXCLUDE_SAMESITE_LAX,
"The cookie had SameSite=Lax, and the attempted access did not "
"have "
"an appropriate SameSiteCookieContext"},
{net::CookieInclusionStatus::
EXCLUDE_SAMESITE_UNSPECIFIED_TREATED_AS_LAX,
"The cookie did not specify a SameSite attribute, and therefore "
"was "
"treated as if it were SameSite=Lax, and the attempted access did "
"not have an appropriate SameSiteCookieContext."},
{net::CookieInclusionStatus::EXCLUDE_SAMESITE_NONE_INSECURE,
"The cookie specified SameSite=None, but it was not Secure."},
{net::CookieInclusionStatus::EXCLUDE_USER_PREFERENCES,
"Caller did not allow access to the cookie."},
{net::CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE,
"The cookie was malformed and could not be stored"},
{net::CookieInclusionStatus::EXCLUDE_NONCOOKIEABLE_SCHEME,
"Attempted to set a cookie from a scheme that does not support "
"cookies."},
{net::CookieInclusionStatus::EXCLUDE_OVERWRITE_SECURE,
"The cookie would have overwritten a Secure cookie, and was not "
"allowed to do so."},
{net::CookieInclusionStatus::EXCLUDE_OVERWRITE_HTTP_ONLY,
"The cookie would have overwritten an HttpOnly cookie, and was not "
"allowed to do so."},
{net::CookieInclusionStatus::EXCLUDE_INVALID_DOMAIN,
"The cookie was set with an invalid Domain attribute."},
{net::CookieInclusionStatus::EXCLUDE_INVALID_PREFIX,
"The cookie was set with an invalid __Host- or __Secure- prefix."},
{net::CookieInclusionStatus::EXCLUDE_INVALID_PARTITIONED,
"Cookie was set with an invalid Partitioned attribute, which is "
"only valid if the cookie has a __Host- prefix."},
{net::CookieInclusionStatus::
EXCLUDE_NAME_VALUE_PAIR_EXCEEDS_MAX_SIZE,
"The cookie exceeded the name/value pair size limit."},
{net::CookieInclusionStatus::
EXCLUDE_ATTRIBUTE_VALUE_EXCEEDS_MAX_SIZE,
"Cookie exceeded the attribute size limit."},
{net::CookieInclusionStatus::EXCLUDE_DOMAIN_NON_ASCII,
"The cookie was set with a Domain attribute containing non ASCII "
"characters."},
{net::CookieInclusionStatus::
EXCLUDE_THIRD_PARTY_BLOCKED_WITHIN_FIRST_PARTY_SET,
"The cookie is blocked by third-party cookie blocking but the two "
"sites are in the same First-Party Set"},
{net::CookieInclusionStatus::EXCLUDE_PORT_MISMATCH,
"The cookie's source_port did not match the port of the request."},
{net::CookieInclusionStatus::EXCLUDE_SCHEME_MISMATCH,
"The cookie's source_scheme did not match the scheme of the "
"request."},
{net::CookieInclusionStatus::EXCLUDE_SHADOWING_DOMAIN,
"The cookie is a domain cookie and has the same name as an origin "
"cookie on this origin."},
{net::CookieInclusionStatus::EXCLUDE_DISALLOWED_CHARACTER,
"The cookie contains ASCII control characters"},
{net::CookieInclusionStatus::EXCLUDE_THIRD_PARTY_PHASEOUT,
"The cookie is blocked for third-party cookie phaseout."},
{net::CookieInclusionStatus::EXCLUDE_NO_COOKIE_CONTENT,
"The cookie contains no content or only whitespace."}}};
std::string reason = "Failed to set cookie - ";
for (const auto& [val, str] : exclusion_reasons) {
if (status.HasExclusionReason(val)) {
reason += str;
}
}
reason += status.GetDebugString();
return reason;
}
std::string StringToCookieSameSite(const std::string* str_ptr,

View File

@@ -145,6 +145,9 @@ UtilityProcessWrapper::UtilityProcessWrapper(
}
}
if (!content::ServiceProcessHost::HasObserver(this))
content::ServiceProcessHost::AddObserver(this);
mojo::PendingReceiver<node::mojom::NodeService> receiver =
node_service_remote_.BindNewPipeAndPassReceiver();
@@ -172,9 +175,10 @@ UtilityProcessWrapper::UtilityProcessWrapper(
: content::ChildProcessHost::CHILD_NORMAL)
#endif
.WithProcessCallback(
base::BindOnce(&UtilityProcessWrapper::OnServiceProcessLaunched,
base::BindOnce(&UtilityProcessWrapper::OnServiceProcessLaunch,
weak_factory_.GetWeakPtr()))
.Pass());
node_service_remote_.set_disconnect_with_reason_handler(
base::BindOnce(&UtilityProcessWrapper::OnServiceProcessDisconnected,
weak_factory_.GetWeakPtr()));
@@ -210,37 +214,61 @@ UtilityProcessWrapper::UtilityProcessWrapper(
network_context->CreateHostResolver(
{}, host_resolver.InitWithNewPipeAndPassReceiver());
params->host_resolver = std::move(host_resolver);
node_service_remote_->Initialize(std::move(params));
}
UtilityProcessWrapper::~UtilityProcessWrapper() = default;
UtilityProcessWrapper::~UtilityProcessWrapper() {
content::ServiceProcessHost::RemoveObserver(this);
}
void UtilityProcessWrapper::OnServiceProcessLaunched(
void UtilityProcessWrapper::OnServiceProcessLaunch(
const base::Process& process) {
DCHECK(node_service_remote_.is_connected());
pid_ = process.Pid();
GetAllUtilityProcessWrappers().AddWithID(this, pid_);
if (stdout_read_fd_ != -1) {
if (stdout_read_fd_ != -1)
EmitWithoutEvent("stdout", stdout_read_fd_);
}
if (stderr_read_fd_ != -1) {
if (stderr_read_fd_ != -1)
EmitWithoutEvent("stderr", stderr_read_fd_);
}
// Emit 'spawn' event
EmitWithoutEvent("spawn");
}
void UtilityProcessWrapper::OnServiceProcessDisconnected(
uint32_t error_code,
const std::string& description) {
void UtilityProcessWrapper::HandleTermination(uint64_t exit_code) {
if (pid_ != base::kNullProcessId)
GetAllUtilityProcessWrappers().Remove(pid_);
CloseConnectorPort();
// Emit 'exit' event
EmitWithoutEvent("exit", error_code);
EmitWithoutEvent("exit", exit_code);
Unpin();
}
void UtilityProcessWrapper::OnServiceProcessDisconnected(
uint32_t exit_code,
const std::string& description) {
if (description == "process_exit_termination")
HandleTermination(exit_code);
}
void UtilityProcessWrapper::OnServiceProcessTerminatedNormally(
const content::ServiceProcessInfo& info) {
if (!info.IsService<node::mojom::NodeService>() ||
info.GetProcess().Pid() != pid_)
return;
HandleTermination(info.exit_code());
}
void UtilityProcessWrapper::OnServiceProcessCrashed(
const content::ServiceProcessInfo& info) {
if (!info.IsService<node::mojom::NodeService>() ||
info.GetProcess().Pid() != pid_)
return;
HandleTermination(info.exit_code());
}
void UtilityProcessWrapper::CloseConnectorPort() {
if (!connector_closed_ && connector_->is_valid()) {
host_port_.GiveDisentangledHandle(connector_->PassMessagePipe());
@@ -250,7 +278,7 @@ void UtilityProcessWrapper::CloseConnectorPort() {
}
}
void UtilityProcessWrapper::Shutdown(int exit_code) {
void UtilityProcessWrapper::Shutdown(uint64_t exit_code) {
if (pid_ != base::kNullProcessId)
GetAllUtilityProcessWrappers().Remove(pid_);
node_service_remote_.reset();

View File

@@ -13,9 +13,11 @@
#include "base/environment.h"
#include "base/memory/weak_ptr.h"
#include "base/process/process_handle.h"
#include "content/public/browser/service_process_host.h"
#include "gin/wrappable.h"
#include "mojo/public/cpp/bindings/connector.h"
#include "mojo/public/cpp/bindings/message.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "shell/browser/event_emitter_mixin.h"
#include "shell/common/gin_helper/pinnable.h"
@@ -38,7 +40,8 @@ class UtilityProcessWrapper
: public gin::Wrappable<UtilityProcessWrapper>,
public gin_helper::Pinnable<UtilityProcessWrapper>,
public gin_helper::EventEmitterMixin<UtilityProcessWrapper>,
public mojo::MessageReceiver {
public mojo::MessageReceiver,
public content::ServiceProcessHost::Observer {
public:
enum class IOHandle : size_t { STDIN = 0, STDOUT = 1, STDERR = 2 };
enum class IOType { IO_PIPE, IO_INHERIT, IO_IGNORE };
@@ -47,7 +50,7 @@ class UtilityProcessWrapper
static gin::Handle<UtilityProcessWrapper> Create(gin::Arguments* args);
static raw_ptr<UtilityProcessWrapper> FromProcessId(base::ProcessId pid);
void Shutdown(int exit_code);
void Shutdown(uint64_t exit_code);
// gin::Wrappable
static gin::WrapperInfo kWrapperInfo;
@@ -62,11 +65,11 @@ class UtilityProcessWrapper
base::EnvironmentMap env_map,
base::FilePath current_working_directory,
bool use_plugin_helper);
void OnServiceProcessDisconnected(uint32_t error_code,
const std::string& description);
void OnServiceProcessLaunched(const base::Process& process);
void OnServiceProcessLaunch(const base::Process& process);
void CloseConnectorPort();
void HandleTermination(uint64_t exit_code);
void PostMessage(gin::Arguments* args);
bool Kill() const;
v8::Local<v8::Value> GetOSProcessId(v8::Isolate* isolate) const;
@@ -74,6 +77,15 @@ class UtilityProcessWrapper
// mojo::MessageReceiver
bool Accept(mojo::Message* mojo_message) override;
// content::ServiceProcessHost::Observer
void OnServiceProcessTerminatedNormally(
const content::ServiceProcessInfo& info) override;
void OnServiceProcessCrashed(
const content::ServiceProcessInfo& info) override;
void OnServiceProcessDisconnected(uint32_t exit_code,
const std::string& description);
base::ProcessId pid_ = base::kNullProcessId;
#if BUILDFLAG(IS_WIN)
// Non-owning handles, these will be closed when the

View File

@@ -76,7 +76,6 @@
#include "mojo/public/cpp/system/platform_handle.h"
#include "ppapi/buildflags/buildflags.h"
#include "printing/buildflags/buildflags.h"
#include "printing/print_job_constants.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "shell/browser/api/electron_api_browser_window.h"
@@ -173,10 +172,10 @@
#include "components/printing/browser/print_manager_utils.h"
#include "components/printing/browser/print_to_pdf/pdf_print_result.h"
#include "components/printing/browser/print_to_pdf/pdf_print_utils.h"
#include "printing/backend/print_backend.h" // nogncheck
#include "printing/mojom/print.mojom.h" // nogncheck
#include "printing/mojom/print.mojom.h" // nogncheck
#include "printing/page_range.h"
#include "shell/browser/printing/print_view_manager_electron.h"
#include "shell/browser/printing/printing_utils.h"
#if BUILDFLAG(IS_WIN)
#include "printing/backend/win_helper.h"
@@ -352,6 +351,20 @@ struct Converter<scoped_refptr<content::DevToolsAgentHost>> {
}
};
template <>
struct Converter<content::NavigationEntry*> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
content::NavigationEntry* entry) {
if (!entry) {
return v8::Null(isolate);
}
gin_helper::Dictionary dict(isolate, v8::Object::New(isolate));
dict.Set("url", entry->GetURL().spec());
dict.Set("title", entry->GetTitleForDisplay());
return dict.GetHandle();
}
};
} // namespace gin
namespace electron::api {
@@ -516,96 +529,6 @@ std::optional<base::TimeDelta> GetCursorBlinkInterval() {
return std::nullopt;
}
#if BUILDFLAG(ENABLE_PRINTING)
// This will return false if no printer with the provided device_name can be
// found on the network. We need to check this because Chromium does not do
// sanity checking of device_name validity and so will crash on invalid names.
bool IsDeviceNameValid(const std::u16string& device_name) {
#if BUILDFLAG(IS_MAC)
base::apple::ScopedCFTypeRef<CFStringRef> new_printer_id(
base::SysUTF16ToCFStringRef(device_name));
PMPrinter new_printer = PMPrinterCreateFromPrinterID(new_printer_id.get());
bool printer_exists = new_printer != nullptr;
PMRelease(new_printer);
return printer_exists;
#else
scoped_refptr<printing::PrintBackend> print_backend =
printing::PrintBackend::CreateInstance(
g_browser_process->GetApplicationLocale());
return print_backend->IsValidPrinter(base::UTF16ToUTF8(device_name));
#endif
}
// This function returns a validated device name.
// If the user passed one to webContents.print(), we check that it's valid and
// return it or fail if the network doesn't recognize it. If the user didn't
// pass a device name, we first try to return the system default printer. If one
// isn't set, then pull all the printers and use the first one or fail if none
// exist.
std::pair<std::string, std::u16string> GetDeviceNameToUse(
const std::u16string& device_name) {
#if BUILDFLAG(IS_WIN)
// Blocking is needed here because Windows printer drivers are oftentimes
// not thread-safe and have to be accessed on the UI thread.
ScopedAllowBlockingForElectron allow_blocking;
#endif
if (!device_name.empty()) {
if (!IsDeviceNameValid(device_name))
return std::make_pair("Invalid deviceName provided", std::u16string());
return std::make_pair(std::string(), device_name);
}
scoped_refptr<printing::PrintBackend> print_backend =
printing::PrintBackend::CreateInstance(
g_browser_process->GetApplicationLocale());
std::string printer_name;
printing::mojom::ResultCode code =
print_backend->GetDefaultPrinterName(printer_name);
// We don't want to return if this fails since some devices won't have a
// default printer.
if (code != printing::mojom::ResultCode::kSuccess)
LOG(ERROR) << "Failed to get default printer name";
if (printer_name.empty()) {
printing::PrinterList printers;
if (print_backend->EnumeratePrinters(printers) !=
printing::mojom::ResultCode::kSuccess)
return std::make_pair("Failed to enumerate printers", std::u16string());
if (printers.empty())
return std::make_pair("No printers available on the network",
std::u16string());
printer_name = printers.front().printer_name;
}
return std::make_pair(std::string(), base::UTF8ToUTF16(printer_name));
}
// Copied from
// chrome/browser/ui/webui/print_preview/local_printer_handler_default.cc:L36-L54
scoped_refptr<base::TaskRunner> CreatePrinterHandlerTaskRunner() {
// USER_VISIBLE because the result is displayed in the print preview dialog.
#if !BUILDFLAG(IS_WIN)
static constexpr base::TaskTraits kTraits = {
base::MayBlock(), base::TaskPriority::USER_VISIBLE};
#endif
#if defined(USE_CUPS)
// CUPS is thread safe.
return base::ThreadPool::CreateTaskRunner(kTraits);
#elif BUILDFLAG(IS_WIN)
// Windows drivers are likely not thread-safe and need to be accessed on the
// UI thread.
return content::GetUIThreadTaskRunner({base::TaskPriority::USER_VISIBLE});
#else
// Be conservative on unsupported platforms.
return base::ThreadPool::CreateSingleThreadTaskRunner(kTraits);
#endif
}
#endif
struct UserDataLink : public base::SupportsUserData::Data {
explicit UserDataLink(base::WeakPtr<WebContents> contents)
: web_contents(contents) {}
@@ -2533,6 +2456,11 @@ int WebContents::GetActiveIndex() const {
return web_contents()->GetController().GetCurrentEntryIndex();
}
content::NavigationEntry* WebContents::GetNavigationEntryAtIndex(
int index) const {
return web_contents()->GetController().GetEntryAtIndex(index);
}
void WebContents::ClearHistory() {
// In some rare cases (normally while there is no real history) we are in a
// state where we can't prune navigation entries
@@ -2926,6 +2854,12 @@ void WebContents::OnGetDeviceNameToUse(
// If the user has passed a deviceName use it, otherwise use default printer.
print_settings.Set(printing::kSettingDeviceName, info.second);
if (!print_settings.FindInt(printing::kSettingDpiHorizontal)) {
gfx::Size dpi = GetDefaultPrinterDPI(info.second);
print_settings.Set(printing::kSettingDpiHorizontal, dpi.width());
print_settings.Set(printing::kSettingDpiVertical, dpi.height());
}
auto* print_view_manager =
PrintViewManagerElectron::FromWebContents(web_contents());
if (!print_view_manager)
@@ -3087,7 +3021,6 @@ void WebContents::Print(gin::Arguments* args) {
// Set custom dots per inch (dpi)
gin_helper::Dictionary dpi_settings;
int dpi = 72;
if (options.Get("dpi", &dpi_settings)) {
int horizontal = 72;
dpi_settings.Get("horizontal", &horizontal);
@@ -3095,9 +3028,6 @@ void WebContents::Print(gin::Arguments* args) {
int vertical = 72;
dpi_settings.Get("vertical", &vertical);
settings.Set(printing::kSettingDpiVertical, vertical);
} else {
settings.Set(printing::kSettingDpiHorizontal, dpi);
settings.Set(printing::kSettingDpiVertical, dpi);
}
print_task_runner_->PostTaskAndReplyWithResult(
@@ -4304,9 +4234,11 @@ void WebContents::FillObjectTemplate(v8::Isolate* isolate,
.SetMethod("goToOffset", &WebContents::GoToOffset)
.SetMethod("canGoToIndex", &WebContents::CanGoToIndex)
.SetMethod("goToIndex", &WebContents::GoToIndex)
.SetMethod("getActiveIndex", &WebContents::GetActiveIndex)
.SetMethod("_getActiveIndex", &WebContents::GetActiveIndex)
.SetMethod("_getNavigationEntryAtIndex",
&WebContents::GetNavigationEntryAtIndex)
.SetMethod("_historyLength", &WebContents::GetHistoryLength)
.SetMethod("clearHistory", &WebContents::ClearHistory)
.SetMethod("length", &WebContents::GetHistoryLength)
.SetMethod("isCrashed", &WebContents::IsCrashed)
.SetMethod("forcefullyCrashRenderer",
&WebContents::ForcefullyCrashRenderer)

View File

@@ -190,6 +190,7 @@ class WebContents : public ExclusiveAccessContext,
bool CanGoToIndex(int index) const;
void GoToIndex(int index);
int GetActiveIndex() const;
content::NavigationEntry* GetNavigationEntryAtIndex(int index) const;
void ClearHistory();
int GetHistoryLength() const;
const std::string GetWebRTCIPHandlingPolicy() const;

View File

@@ -235,6 +235,10 @@ class Browser : public WindowListObserver {
// Set docks' icon.
void DockSetIcon(v8::Isolate* isolate, v8::Local<v8::Value> icon);
void SetLaunchedAtLogin(bool launched_at_login) {
was_launched_at_login_ = launched_at_login;
}
#endif // BUILDFLAG(IS_MAC)
void ShowAboutPanel();
@@ -369,6 +373,7 @@ class Browser : public WindowListObserver {
#if BUILDFLAG(IS_MAC)
std::unique_ptr<ui::ScopedPasswordInputEnabler> password_input_enabler_;
base::Time last_dock_show_;
bool was_launched_at_login_;
#endif
base::Value::Dict about_panel_options_;

View File

@@ -389,6 +389,7 @@ Browser::LoginItemSettings Browser::GetLoginItemSettings(
platform_util::GetLoginItemEnabled(options.type, options.service_name);
settings.open_at_login =
status == "enabled" || status == "enabled-deprecated";
settings.opened_at_login = was_launched_at_login_;
if (@available(macOS 13, *))
settings.status = status;
#else
@@ -402,6 +403,7 @@ Browser::LoginItemSettings Browser::GetLoginItemSettings(
settings = settings_deprecated;
} else {
settings.open_at_login = status == "enabled";
settings.opened_at_login = was_launched_at_login_;
settings.status = status;
}
} else {

View File

@@ -455,7 +455,15 @@ void ElectronBrowserClient::AppendExtraCommandLineSwitches(
base::CommandLine* command_line,
int process_id) {
// Make sure we're about to launch a known executable
#if BUILDFLAG(IS_LINUX)
// On Linux, do not perform this check for /proc/self/exe. It will always
// point to the currently running executable so this check is not
// necessary, and if the executable has been deleted it will return a fake
// name that causes this check to fail.
if (command_line->GetProgram() != base::FilePath(base::kProcSelfExe)) {
#else
{
#endif
ScopedAllowBlockingForElectron allow_blocking;
base::FilePath child_path;
base::FilePath program =

View File

@@ -398,12 +398,6 @@ void ElectronBrowserMainParts::ToolkitInitialized() {
CHECK(linux_ui);
linux_ui_getter_ = std::make_unique<LinuxUiGetterImpl>();
// Try loading gtk symbols used by Electron.
electron::InitializeElectron_gtk(gtk::GetLibGtk());
if (!electron::IsElectron_gtkInitialized()) {
electron::UninitializeElectron_gtk();
}
electron::InitializeElectron_gdk_pixbuf(gtk::GetLibGdkPixbuf());
CHECK(electron::IsElectron_gdk_pixbufInitialized())
<< "Failed to initialize libgdk_pixbuf-2.0.so.0";

View File

@@ -6,6 +6,8 @@
#include <string>
#include "base/dcheck_is_on.h"
namespace electron {
std::string EnablePlatformSpecificFeatures() {
@@ -19,8 +21,12 @@ std::string EnablePlatformSpecificFeatures() {
// chrome/browser/media/webrtc/thumbnail_capturer_mac.mm
// kThumbnailCapturerMac,
// chrome/browser/media/webrtc/thumbnail_capturer_mac.mm
#if DCHECK_IS_ON()
return "";
#else
return "ScreenCaptureKitPickerScreen,ScreenCaptureKitStreamPickerSonoma,"
"ThumbnailCapturerMac:capture_mode/sc_screenshot_manager";
#endif
}
return "";
}

View File

@@ -46,8 +46,8 @@ class ElectronHidDelegate::ContextObservation
ContextObservation(ElectronHidDelegate* parent,
content::BrowserContext* browser_context)
: parent_(parent), browser_context_(browser_context) {
auto* chooser_context = GetChooserContext(browser_context_);
device_observation_.Observe(chooser_context);
if (auto* chooser_context = GetChooserContext(browser_context_))
device_observation_.Observe(chooser_context);
}
ContextObservation(ContextObservation&) = delete;

View File

@@ -282,13 +282,10 @@ class TracingControllerImpl : public node::tracing::TracingController {
v8::Isolate* JavascriptEnvironment::Initialize(uv_loop_t* event_loop,
bool setup_wasm_streaming) {
auto* cmd = base::CommandLine::ForCurrentProcess();
// --js-flags.
std::string js_flags =
cmd->GetSwitchValueASCII(blink::switches::kJavaScriptFlags);
js_flags.append(" --no-freeze-flags-after-init");
if (!js_flags.empty())
v8::V8::SetFlagsFromString(js_flags.c_str(), js_flags.size());
std::string js_flags = "--no-freeze-flags-after-init ";
js_flags.append(cmd->GetSwitchValueASCII(blink::switches::kJavaScriptFlags));
v8::V8::SetFlagsFromString(js_flags.c_str(), js_flags.size());
// The V8Platform of gin relies on Chromium's task schedule, which has not
// been started at this point, so we have to rely on Node's V8Platform.

View File

@@ -84,6 +84,14 @@ static NSDictionary* UNNotificationResponseToNSDictionary(
}
}
NSAppleEventDescriptor* event =
NSAppleEventManager.sharedAppleEventManager.currentAppleEvent;
BOOL launched_as_login_item =
(event.eventID == kAEOpenApplication &&
[event paramDescriptorForKeyword:keyAEPropData].enumCodeValue ==
keyAELaunchedAsLogInItem);
electron::Browser::Get()->SetLaunchedAtLogin(launched_as_login_item);
electron::Browser::Get()->DidFinishLaunching(
electron::NSDictionaryToValue(notification_info));
}

View File

@@ -159,21 +159,21 @@ void LibnotifyNotification::Show(const NotificationOptions& options) {
void LibnotifyNotification::Dismiss() {
if (!notification_) {
Destroy();
return;
}
GError* error = nullptr;
on_dismissing_ = true;
libnotify_loader_.notify_notification_close(notification_, &error);
if (error) {
log_and_clear_error(error, "notify_notification_close");
Destroy();
}
on_dismissing_ = false;
}
void LibnotifyNotification::OnNotificationClosed(
NotifyNotification* notification) {
NotificationDismissed();
NotificationDismissed(!on_dismissing_);
}
void LibnotifyNotification::OnNotificationView(NotifyNotification* notification,

View File

@@ -33,6 +33,7 @@ class LibnotifyNotification : public Notification {
RAW_PTR_EXCLUSION NotifyNotification* notification_ = nullptr;
ScopedGSignal signal_;
bool on_dismissing_ = false;
};
} // namespace electron

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