mirror of
https://github.com/electron/electron.git
synced 2026-02-19 03:14:51 -05:00
Compare commits
93 Commits
same-party
...
v29.4.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79ecc56d33 | ||
|
|
6d7653383a | ||
|
|
24faedab76 | ||
|
|
2eb7880cf1 | ||
|
|
8ca9e1543d | ||
|
|
fe869081b3 | ||
|
|
914d8f373e | ||
|
|
0bd7092e74 | ||
|
|
5cdfdcdffb | ||
|
|
fc5ee6d319 | ||
|
|
0529300980 | ||
|
|
3a142b6c4f | ||
|
|
3fd34fc4b6 | ||
|
|
dcf12182b8 | ||
|
|
537e8c3bea | ||
|
|
3041c956ce | ||
|
|
c57f515e43 | ||
|
|
4b3d3a5f07 | ||
|
|
0b51976cd2 | ||
|
|
4e1f54087d | ||
|
|
d2ffa6fe31 | ||
|
|
f7bb17ebd1 | ||
|
|
f9ed0eaee4 | ||
|
|
8933e7e2a9 | ||
|
|
262f4d34cf | ||
|
|
b721d420d5 | ||
|
|
4517547f07 | ||
|
|
4f30f731ee | ||
|
|
3b81b7efbc | ||
|
|
acd34fdca9 | ||
|
|
84ecd700db | ||
|
|
cbc0f6720e | ||
|
|
8fbabeaca7 | ||
|
|
4c737147c3 | ||
|
|
5ebc741819 | ||
|
|
cd6ad4d1bb | ||
|
|
19f0abd62e | ||
|
|
9d4f8a06e8 | ||
|
|
a43014a410 | ||
|
|
803698e2c4 | ||
|
|
557cadddcb | ||
|
|
fe01ed750a | ||
|
|
7f26c72af6 | ||
|
|
7a3e587a1d | ||
|
|
bf14d05830 | ||
|
|
384642792e | ||
|
|
5bbac9ae30 | ||
|
|
0da6411d11 | ||
|
|
297be64122 | ||
|
|
1c47ba0a91 | ||
|
|
1cd7a71bb1 | ||
|
|
feb81b6841 | ||
|
|
a3d9e4be58 | ||
|
|
ec4683cd91 | ||
|
|
a02e0f0f02 | ||
|
|
97eee463fa | ||
|
|
ed9a12cba7 | ||
|
|
fe4d3a2484 | ||
|
|
ad9a90ec53 | ||
|
|
8647232c48 | ||
|
|
f9e28e3e50 | ||
|
|
3698f89205 | ||
|
|
238cc80cef | ||
|
|
3b025ec0c7 | ||
|
|
d2c14f1c6c | ||
|
|
0d3f50fc12 | ||
|
|
d3da708f5c | ||
|
|
e64c123d80 | ||
|
|
9ce58dd0ea | ||
|
|
4da7bff05f | ||
|
|
53a7faa029 | ||
|
|
d2177e4d08 | ||
|
|
07f50757a3 | ||
|
|
98283d1dae | ||
|
|
d0fdc28c0e | ||
|
|
99dd9e2138 | ||
|
|
c5a2873f8f | ||
|
|
1e34cdda96 | ||
|
|
880aee0aa7 | ||
|
|
c00489396b | ||
|
|
30587d9700 | ||
|
|
ede0ebcc73 | ||
|
|
5966b42ac5 | ||
|
|
33e61a19ef | ||
|
|
a90c5b1b08 | ||
|
|
06e01e5b76 | ||
|
|
96d053677d | ||
|
|
8fe14665a0 | ||
|
|
c9384a609e | ||
|
|
fd2620bda4 | ||
|
|
dc04802296 | ||
|
|
90ca4e5f80 | ||
|
|
5013150cfd |
@@ -75,10 +75,6 @@ executors:
|
||||
resource_class: << parameters.size >>
|
||||
|
||||
# Electron Runners
|
||||
apple-silicon:
|
||||
resource_class: electronjs/macos-arm64
|
||||
machine: true
|
||||
|
||||
linux-arm:
|
||||
resource_class: electronjs/aks-linux-arm-test
|
||||
docker:
|
||||
@@ -264,9 +260,9 @@ step-depot-tools-get: &step-depot-tools-get
|
||||
index c305c248..e6e0fbdc 100755
|
||||
--- a/gclient.py
|
||||
+++ b/gclient.py
|
||||
@@ -735,7 +735,8 @@ class Dependency(gclient_utils.WorkItem, DependencySettings):
|
||||
|
||||
if dep_type == 'cipd':
|
||||
@@ -783,7 +783,8 @@ class Dependency(gclient_utils.WorkItem, DependencySettings):
|
||||
not condition or "non_git_source" not in condition):
|
||||
continue
|
||||
cipd_root = self.GetCipdRoot()
|
||||
- for package in dep_value.get('packages', []):
|
||||
+ packages = dep_value.get('packages', [])
|
||||
@@ -2296,8 +2292,10 @@ jobs:
|
||||
- electron-tests:
|
||||
artifact-key: darwin-x64
|
||||
|
||||
darwin-testing-arm64-tests:
|
||||
executor: apple-silicon
|
||||
darwin-testing-arm64-tests:
|
||||
executor:
|
||||
name: macos
|
||||
size: macos.m1.medium.gen1
|
||||
environment:
|
||||
<<: *env-mac-large
|
||||
<<: *env-stack-dumping
|
||||
@@ -2321,7 +2319,9 @@ jobs:
|
||||
artifact-key: mas-x64
|
||||
|
||||
mas-testing-arm64-tests:
|
||||
executor: apple-silicon
|
||||
executor:
|
||||
name: macos
|
||||
size: macos.m1.medium.gen1
|
||||
environment:
|
||||
<<: *env-mac-large
|
||||
<<: *env-stack-dumping
|
||||
|
||||
@@ -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",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
24
BUILD.gn
24
BUILD.gn
@@ -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
2
DEPS
@@ -2,7 +2,7 @@ gclient_gn_args_from = 'src'
|
||||
|
||||
vars = {
|
||||
'chromium_version':
|
||||
'122.0.6261.70',
|
||||
'122.0.6261.156',
|
||||
'node_version':
|
||||
'v20.9.0',
|
||||
'nan_version':
|
||||
|
||||
@@ -112,4 +112,4 @@ and more can be found on the [Community page](https://www.electronjs.org/communi
|
||||
|
||||
[MIT](https://github.com/electron/electron/blob/main/LICENSE)
|
||||
|
||||
When using Electron logos, make sure to follow [OpenJS Foundation Trademark Policy](https://openjsf.org/wp-content/uploads/sites/84/2021/01/OpenJS-Foundation-Trademark-Policy-2021-01-12.docx.pdf).
|
||||
When using Electron logos, make sure to follow [OpenJS Foundation Trademark Policy](https://trademark-policy.openjsf.org/).
|
||||
|
||||
@@ -32,7 +32,7 @@ In most cases, you should do everything in the `ready` event handler.
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `launchInfo` Record<string, any> | [NotificationResponse](structures/notification-response.md) _macOS_
|
||||
* `launchInfo` Record\<string, any\> | [NotificationResponse](structures/notification-response.md) _macOS_
|
||||
|
||||
Emitted once, when Electron has finished initializing. On macOS, `launchInfo`
|
||||
holds the `userInfo` of the [`NSUserNotification`](https://developer.apple.com/documentation/foundation/nsusernotification)
|
||||
@@ -970,7 +970,7 @@ app.setJumpList([
|
||||
|
||||
### `app.requestSingleInstanceLock([additionalData])`
|
||||
|
||||
* `additionalData` Record<any, any> (optional) - A JSON object containing additional data to send to the first instance.
|
||||
* `additionalData` Record\<any, any\> (optional) - A JSON object containing additional data to send to the first instance.
|
||||
|
||||
Returns `boolean`
|
||||
|
||||
@@ -1261,7 +1261,7 @@ Returns `Object`:
|
||||
|
||||
* `openAtLogin` boolean - `true` if the app is set to open at login.
|
||||
* `openAsHidden` boolean _macOS_ _Deprecated_ - `true` if the app is set to open as hidden at login. This does not work on macOS 13 and up.
|
||||
* `wasOpenedAtLogin` boolean _macOS_ _Deprecated_ - `true` if the app was opened at login automatically. This setting is not available on [MAS builds][mas-builds] or on macOS 13 and up.
|
||||
* `wasOpenedAtLogin` boolean _macOS_ - `true` if the app was opened at login automatically.
|
||||
* `wasOpenedAsHidden` boolean _macOS_ _Deprecated_ - `true` if the app was opened as a hidden login item. This indicates that the app should not open any windows at startup. This setting is not available on [MAS builds][mas-builds] or on macOS 13 and up.
|
||||
* `restoreState` boolean _macOS_ _Deprecated_ - `true` if the app was opened as a login item that should restore the state from the previous session. This indicates that the app should restore the windows that were open the last time the app was closed. This setting is not available on [MAS builds][mas-builds] or on macOS 13 and up.
|
||||
* `status` string _macOS_ - can be one of `not-registered`, `enabled`, `requires-approval`, or `not-found`.
|
||||
|
||||
@@ -103,7 +103,7 @@ The `autoUpdater` object has the following methods:
|
||||
|
||||
* `options` Object
|
||||
* `url` string
|
||||
* `headers` Record<string, string> (optional) _macOS_ - HTTP request headers.
|
||||
* `headers` Record\<string, string\> (optional) _macOS_ - HTTP request headers.
|
||||
* `serverType` string (optional) _macOS_ - Can be `json` or `default`, see the [Squirrel.Mac][squirrel-mac]
|
||||
README for more information.
|
||||
|
||||
|
||||
@@ -775,7 +775,7 @@ Closes the currently open [Quick Look][quick-look] panel.
|
||||
|
||||
#### `win.setBounds(bounds[, animate])`
|
||||
|
||||
* `bounds` Partial<[Rectangle](structures/rectangle.md)>
|
||||
* `bounds` Partial\<[Rectangle](structures/rectangle.md)\>
|
||||
* `animate` boolean (optional) _macOS_
|
||||
|
||||
Resizes and moves the window to the supplied bounds. Any properties that are not supplied will default to their current values.
|
||||
@@ -1211,7 +1211,7 @@ win.loadURL('http://localhost:8000/post', {
|
||||
|
||||
* `filePath` string
|
||||
* `options` Object (optional)
|
||||
* `query` Record<string, string> (optional) - Passed to `url.format()`.
|
||||
* `query` Record\<string, string\> (optional) - Passed to `url.format()`.
|
||||
* `search` string (optional) - Passed to `url.format()`.
|
||||
* `hash` string (optional) - Passed to `url.format()`.
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@ following properties:
|
||||
method.
|
||||
* `url` string (optional) - The request URL. Must be provided in the absolute
|
||||
form with the protocol scheme specified as http or https.
|
||||
* `headers` Record\<string, string | string[]\> (optional) - Headers to be sent
|
||||
with the request.
|
||||
* `session` Session (optional) - The [`Session`](session.md) instance with
|
||||
which the request is associated.
|
||||
* `partition` string (optional) - The name of the [`partition`](session.md)
|
||||
@@ -158,7 +160,7 @@ Returns:
|
||||
* `statusCode` Integer
|
||||
* `method` string
|
||||
* `redirectUrl` string
|
||||
* `responseHeaders` Record<string, string[]>
|
||||
* `responseHeaders` Record\<string, string[]\>
|
||||
|
||||
Emitted when the server returns a redirect response (e.g. 301 Moved
|
||||
Permanently). Calling [`request.followRedirect`](#requestfollowredirect) will
|
||||
|
||||
@@ -59,14 +59,14 @@ The `crashReporter` module has the following methods:
|
||||
number of crashes uploaded to 1/hour. Default is `false`.
|
||||
* `compress` boolean (optional) - If true, crash reports will be compressed
|
||||
and uploaded with `Content-Encoding: gzip`. Default is `true`.
|
||||
* `extra` Record<string, string> (optional) - Extra string key/value
|
||||
* `extra` Record\<string, string\> (optional) - Extra string key/value
|
||||
annotations that will be sent along with crash reports that are generated
|
||||
in the main process. Only string values are supported. Crashes generated in
|
||||
child processes will not contain these extra
|
||||
parameters to crash reports generated from child processes, call
|
||||
[`addExtraParameter`](#crashreporteraddextraparameterkey-value) from the
|
||||
child process.
|
||||
* `globalExtra` Record<string, string> (optional) - Extra string key/value
|
||||
* `globalExtra` Record\<string, string\> (optional) - Extra string key/value
|
||||
annotations that will be sent along with any crash reports generated in any
|
||||
process. These annotations cannot be changed once the crash reporter has
|
||||
been started. If a key is present in both the global extra parameters and
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -72,7 +72,7 @@ Removes listeners of the specified `channel`.
|
||||
### `ipcMain.handle(channel, listener)`
|
||||
|
||||
* `channel` string
|
||||
* `listener` Function<Promise\<any> | any>
|
||||
* `listener` Function\<Promise\<any\> | any\>
|
||||
* `event` [IpcMainInvokeEvent][ipc-main-invoke-event]
|
||||
* `...args` any[]
|
||||
|
||||
@@ -109,7 +109,7 @@ provided to the renderer process. Please refer to
|
||||
### `ipcMain.handleOnce(channel, listener)`
|
||||
|
||||
* `channel` string
|
||||
* `listener` Function<Promise\<any> | any>
|
||||
* `listener` Function\<Promise\<any\> | any\>
|
||||
* `event` [IpcMainInvokeEvent][ipc-main-invoke-event]
|
||||
* `...args` any[]
|
||||
|
||||
|
||||
@@ -4,36 +4,41 @@
|
||||
|
||||
Process: [Main](../glossary.md#main-process), [Renderer](../glossary.md#renderer-process)
|
||||
|
||||
In Electron, for the APIs that take images, you can pass either file paths or
|
||||
`NativeImage` instances. An empty image will be used when `null` is passed.
|
||||
The `nativeImage` module provides a unified interface for manipulating
|
||||
system images. These can be handy if you want to provide multiple scaled
|
||||
versions of the same icon or take advantage of macOS [template images][template-image].
|
||||
|
||||
For example, when creating a tray or setting a window's icon, you can pass an
|
||||
image file path as a `string`:
|
||||
Electron APIs that take image files accept either file paths or
|
||||
`NativeImage` instances. An empty and transparent image will be used when `null` is passed.
|
||||
|
||||
```js
|
||||
For example, when creating a [Tray](../api/tray.md) or setting a [BrowserWindow](../api/browser-window.md)'s
|
||||
icon, you can either pass an image file path as a string:
|
||||
|
||||
```js title='Main Process'
|
||||
const { BrowserWindow, Tray } = require('electron')
|
||||
|
||||
const appIcon = new Tray('/Users/somebody/images/icon.png')
|
||||
const tray = new Tray('/Users/somebody/images/icon.png')
|
||||
const win = new BrowserWindow({ icon: '/Users/somebody/images/window.png' })
|
||||
console.log(appIcon, win)
|
||||
```
|
||||
|
||||
Or read the image from the clipboard, which returns a `NativeImage`:
|
||||
or generate a `NativeImage` instance from the same file:
|
||||
|
||||
```js
|
||||
const { clipboard, Tray } = require('electron')
|
||||
const image = clipboard.readImage()
|
||||
const appIcon = new Tray(image)
|
||||
console.log(appIcon)
|
||||
```js title='Main Process'
|
||||
const { BrowserWindow, nativeImage, Tray } = require('electron')
|
||||
|
||||
const trayIcon = nativeImage.createFromPath('/Users/somebody/images/icon.png')
|
||||
const appIcon = nativeImage.createFromPath('/Users/somebody/images/window.png')
|
||||
const tray = new Tray(trayIcon)
|
||||
const win = new BrowserWindow({ icon: appIcon })
|
||||
```
|
||||
|
||||
## Supported Formats
|
||||
|
||||
Currently `PNG` and `JPEG` image formats are supported. `PNG` is recommended
|
||||
because of its support for transparency and lossless compression.
|
||||
Currently, `PNG` and `JPEG` image formats are supported across all platforms.
|
||||
`PNG` is recommended because of its support for transparency and lossless compression.
|
||||
|
||||
On Windows, you can also load `ICO` icons from file paths. For best visual
|
||||
quality, it is recommended to include at least the following sizes in the:
|
||||
quality, we recommend including at least the following sizes:
|
||||
|
||||
* Small icon
|
||||
* 16x16 (100% DPI scale)
|
||||
@@ -47,9 +52,9 @@ quality, it is recommended to include at least the following sizes in the:
|
||||
* 64x64 (200% DPI scale)
|
||||
* 256x256
|
||||
|
||||
Check the _Size requirements_ section in [this article][icons].
|
||||
Check the _Icon Scaling_ section in the Windows [App Icon Construction][icons] reference.
|
||||
|
||||
[icons]: https://learn.microsoft.com/en-us/windows/win32/uxguide/vis-icons
|
||||
[icons]: https://learn.microsoft.com/en-us/windows/apps/design/style/iconography/app-icon-construction#icon-scaling
|
||||
|
||||
:::note
|
||||
|
||||
@@ -60,16 +65,17 @@ image encoding and decoding.
|
||||
|
||||
## High Resolution Image
|
||||
|
||||
On platforms that have high-DPI support such as Apple Retina displays, you can
|
||||
append `@2x` after image's base filename to mark it as a high resolution image.
|
||||
On platforms that support high pixel density displays (such as Apple Retina),
|
||||
you can append `@2x` after image's base filename to mark it as a 2x scale
|
||||
high resolution image.
|
||||
|
||||
For example, if `icon.png` is a normal image that has standard resolution, then
|
||||
`icon@2x.png` will be treated as a high resolution image that has double DPI
|
||||
density.
|
||||
`icon@2x.png` will be treated as a high resolution image that has double
|
||||
Dots per Inch (DPI) density.
|
||||
|
||||
If you want to support displays with different DPI densities at the same time,
|
||||
you can put images with different sizes in the same folder and use the filename
|
||||
without DPI suffixes. For example:
|
||||
without DPI suffixes within Electron. For example:
|
||||
|
||||
```plaintext
|
||||
images/
|
||||
@@ -78,10 +84,9 @@ images/
|
||||
└── icon@3x.png
|
||||
```
|
||||
|
||||
```js
|
||||
```js title='Main Process'
|
||||
const { Tray } = require('electron')
|
||||
const appIcon = new Tray('/Users/somebody/images/icon.png')
|
||||
console.log(appIcon)
|
||||
const appTray = new Tray('/Users/somebody/images/icon.png')
|
||||
```
|
||||
|
||||
The following suffixes for DPI are also supported:
|
||||
@@ -98,27 +103,23 @@ The following suffixes for DPI are also supported:
|
||||
* `@4x`
|
||||
* `@5x`
|
||||
|
||||
## Template Image
|
||||
## Template Image _macOS_
|
||||
|
||||
Template images consist of black and an alpha channel.
|
||||
On macOS, [template images][template-image] consist of black and an alpha channel.
|
||||
Template images are not intended to be used as standalone images and are usually
|
||||
mixed with other content to create the desired final appearance.
|
||||
|
||||
The most common case is to use template images for a menu bar icon, so it can
|
||||
The most common case is to use template images for a menu bar (Tray) icon, so it can
|
||||
adapt to both light and dark menu bars.
|
||||
|
||||
**Note:** Template image is only supported on macOS.
|
||||
|
||||
To mark an image as a template image, its filename should end with the word
|
||||
`Template`. For example:
|
||||
|
||||
* `xxxTemplate.png`
|
||||
* `xxxTemplate@2x.png`
|
||||
To mark an image as a template image, its base filename should end with the word
|
||||
`Template` (e.g. `xxxTemplate.png`). You can also specify template images at
|
||||
different DPI densities (e.g. `xxxTemplate@2x.png`).
|
||||
|
||||
## Methods
|
||||
|
||||
The `nativeImage` module has the following methods, all of which return
|
||||
an instance of the `NativeImage` class:
|
||||
an instance of the [`NativeImage`](#class-nativeimage) class:
|
||||
|
||||
### `nativeImage.createEmpty()`
|
||||
|
||||
@@ -137,7 +138,7 @@ Note: The Windows implementation will ignore `size.height` and scale the height
|
||||
|
||||
### `nativeImage.createFromPath(path)`
|
||||
|
||||
* `path` string
|
||||
* `path` string - path to a file that we intend to construct an image out of.
|
||||
|
||||
Returns `NativeImage`
|
||||
|
||||
@@ -146,7 +147,7 @@ returns an empty image if the `path` does not exist, cannot be read, or is not
|
||||
a valid image.
|
||||
|
||||
```js
|
||||
const nativeImage = require('electron').nativeImage
|
||||
const { nativeImage } = require('electron')
|
||||
|
||||
const image = nativeImage.createFromPath('/Users/somebody/images/icon.png')
|
||||
console.log(image)
|
||||
@@ -183,7 +184,7 @@ Creates a new `NativeImage` instance from `buffer`. Tries to decode as PNG or JP
|
||||
|
||||
Returns `NativeImage`
|
||||
|
||||
Creates a new `NativeImage` instance from `dataURL`.
|
||||
Creates a new `NativeImage` instance from `dataUrl`, a base 64 encoded [Data URL][data-url] string.
|
||||
|
||||
### `nativeImage.createFromNamedImage(imageName[, hslShift])` _macOS_
|
||||
|
||||
@@ -192,14 +193,14 @@ Creates a new `NativeImage` instance from `dataURL`.
|
||||
|
||||
Returns `NativeImage`
|
||||
|
||||
Creates a new `NativeImage` instance from the NSImage that maps to the
|
||||
given image name. See [`System Icons`](https://developer.apple.com/design/human-interface-guidelines/macos/icons-and-images/system-icons/)
|
||||
for a list of possible values.
|
||||
Creates a new `NativeImage` instance from the `NSImage` that maps to the
|
||||
given image name. See Apple's [`NSImageName`](https://developer.apple.com/documentation/appkit/nsimagename#2901388)
|
||||
documentation for a list of possible values.
|
||||
|
||||
The `hslShift` is applied to the image with the following rules:
|
||||
|
||||
* `hsl_shift[0]` (hue): The absolute hue value for the image - 0 and 1 map
|
||||
to 0 and 360 on the hue color wheel (red).
|
||||
to 0 and 360 on the hue color wheel (red).
|
||||
* `hsl_shift[1]` (saturation): A saturation shift for the image, with the
|
||||
following key values:
|
||||
0 = remove all color.
|
||||
@@ -216,7 +217,9 @@ This means that `[-1, 0, 1]` will make the image completely white and
|
||||
|
||||
In some cases, the `NSImageName` doesn't match its string representation; one example of this is `NSFolderImageName`, whose string representation would actually be `NSFolder`. Therefore, you'll need to determine the correct string representation for your image before passing it in. This can be done with the following:
|
||||
|
||||
`echo -e '#import <Cocoa/Cocoa.h>\nint main() { NSLog(@"%@", SYSTEM_IMAGE_NAME); }' | clang -otest -x objective-c -framework Cocoa - && ./test`
|
||||
```sh
|
||||
echo -e '#import <Cocoa/Cocoa.h>\nint main() { NSLog(@"%@", SYSTEM_IMAGE_NAME); }' | clang -otest -x objective-c -framework Cocoa - && ./test
|
||||
```
|
||||
|
||||
where `SYSTEM_IMAGE_NAME` should be replaced with any value from [this list](https://developer.apple.com/documentation/appkit/nsimagename?language=objc).
|
||||
|
||||
@@ -257,7 +260,7 @@ data.
|
||||
* `options` Object (optional)
|
||||
* `scaleFactor` Number (optional) - Defaults to 1.0.
|
||||
|
||||
Returns `string` - The data URL of the image.
|
||||
Returns `string` - The [Data URL][data-url] of the image.
|
||||
|
||||
#### `image.getBitmap([options])`
|
||||
|
||||
@@ -273,7 +276,7 @@ current event loop tick; otherwise the data might be changed or destroyed.
|
||||
#### `image.getNativeHandle()` _macOS_
|
||||
|
||||
Returns `Buffer` - A [Buffer][buffer] that stores C pointer to underlying native handle of
|
||||
the image. On macOS, a pointer to `NSImage` instance would be returned.
|
||||
the image. On macOS, a pointer to `NSImage` instance is returned.
|
||||
|
||||
Notice that the returned pointer is a weak pointer to the underlying native
|
||||
image instead of a copy, so you _must_ ensure that the associated
|
||||
@@ -295,11 +298,11 @@ If `scaleFactor` is passed, this will return the size corresponding to the image
|
||||
|
||||
* `option` boolean
|
||||
|
||||
Marks the image as a template image.
|
||||
Marks the image as a macOS [template image][template-image].
|
||||
|
||||
#### `image.isTemplateImage()`
|
||||
|
||||
Returns `boolean` - Whether the image is a template image.
|
||||
Returns `boolean` - Whether the image is a macOS [template image][template-image].
|
||||
|
||||
#### `image.crop(rect)`
|
||||
|
||||
@@ -328,13 +331,13 @@ will be preserved in the resized image.
|
||||
|
||||
* `scaleFactor` Number (optional) - Defaults to 1.0.
|
||||
|
||||
Returns `Number` - The image's aspect ratio.
|
||||
Returns `Number` - The image's aspect ratio (width divided by height).
|
||||
|
||||
If `scaleFactor` is passed, this will return the aspect ratio corresponding to the image representation most closely matching the passed value.
|
||||
|
||||
#### `image.getScaleFactors()`
|
||||
|
||||
Returns `Number[]` - An array of all scale factors corresponding to representations for a given nativeImage.
|
||||
Returns `Number[]` - An array of all scale factors corresponding to representations for a given `NativeImage`.
|
||||
|
||||
#### `image.addRepresentation(options)`
|
||||
|
||||
@@ -349,15 +352,17 @@ Returns `Number[]` - An array of all scale factors corresponding to representati
|
||||
encoded PNG or JPEG image.
|
||||
|
||||
Add an image representation for a specific scale factor. This can be used
|
||||
to explicitly add different scale factor representations to an image. This
|
||||
to programmatically add different scale factor representations to an image. This
|
||||
can be called on empty images.
|
||||
|
||||
[buffer]: https://nodejs.org/api/buffer.html#buffer_class_buffer
|
||||
|
||||
### Instance Properties
|
||||
|
||||
#### `nativeImage.isMacTemplateImage` _macOS_
|
||||
|
||||
A `boolean` property that determines whether the image is considered a [template image](https://developer.apple.com/documentation/appkit/nsimage/1520017-template).
|
||||
A `boolean` property that determines whether the image is considered a [template image][template-image].
|
||||
|
||||
Please note that this property only has an effect on macOS.
|
||||
|
||||
[buffer]: https://nodejs.org/api/buffer.html#buffer_class_buffer
|
||||
[data-url]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs
|
||||
[template-image]: https://developer.apple.com/documentation/appkit/nsimage/1520017-template
|
||||
|
||||
29
docs/api/navigation-history.md
Normal file
29
docs/api/navigation-history.md
Normal 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.
|
||||
@@ -111,7 +111,7 @@ expect streaming responses.
|
||||
|
||||
* `scheme` string - scheme to handle, for example `https` or `my-app`. This is
|
||||
the bit before the `:` in a URL.
|
||||
* `handler` Function<[GlobalResponse](https://nodejs.org/api/globals.html#response) | Promise<GlobalResponse>>
|
||||
* `handler` Function\<[GlobalResponse](https://nodejs.org/api/globals.html#response) | Promise\<GlobalResponse\>\>
|
||||
* `request` [GlobalRequest](https://nodejs.org/api/globals.html#request)
|
||||
|
||||
Register a protocol handler for `scheme`. Requests made to URLs with this
|
||||
|
||||
@@ -27,7 +27,7 @@ The `pushNotification` module emits the following events:
|
||||
Returns:
|
||||
|
||||
* `event` Event
|
||||
* `userInfo` Record<String, any>
|
||||
* `userInfo` Record\<String, any\>
|
||||
|
||||
Emitted when the app receives a remote notification while running.
|
||||
See: https://developer.apple.com/documentation/appkit/nsapplicationdelegate/1428430-application?language=objc
|
||||
|
||||
@@ -813,6 +813,8 @@ win.webContents.session.setCertificateVerifyProc((request, callback) => {
|
||||
* `pointerLock` - Request to directly interpret mouse movements as an input method via the [Pointer Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API). These requests always appear to originate from the main frame.
|
||||
* `keyboardLock` - Request capture of keypresses for any or all of the keys on the physical keyboard via the [Keyboard Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Keyboard/lock). These requests always appear to originate from the main frame.
|
||||
* `openExternal` - Request to open links in external applications.
|
||||
* `storage-access` - Allows content loaded in a third-party context to request access to third-party cookies using the [Storage Access API](https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API).
|
||||
* `top-level-storage-access` - Allow top-level sites to request third-party cookie access on behalf of embedded content originating from another site in the same related website set using the [Storage Access API](https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API).
|
||||
* `window-management` - Request access to enumerate screens using the [`getScreenDetails`](https://developer.chrome.com/en/articles/multi-screen-window-placement/) API.
|
||||
* `unknown` - An unrecognized permission request.
|
||||
* `callback` Function
|
||||
@@ -861,6 +863,8 @@ session.fromPartition('some-partition').setPermissionRequestHandler((webContents
|
||||
* `openExternal` - Open links in external applications.
|
||||
* `pointerLock` - Directly interpret mouse movements as an input method via the [Pointer Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API). These requests always appear to originate from the main frame.
|
||||
* `serial` - Read from and write to serial devices with the [Web Serial API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Serial_API).
|
||||
* `storage-access` - Allows content loaded in a third-party context to request access to third-party cookies using the [Storage Access API](https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API).
|
||||
* `top-level-storage-access` - Allow top-level sites to request third-party cookie access on behalf of embedded content originating from another site in the same related website set using the [Storage Access API](https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API).
|
||||
* `usb` - Expose non-standard Universal Serial Bus (USB) compatible devices services to the web with the [WebUSB API](https://developer.mozilla.org/en-US/docs/Web/API/WebUSB_API).
|
||||
* `requestingOrigin` string - The origin URL of the permission check
|
||||
* `details` Object - Some properties are only available on certain permission types.
|
||||
@@ -1215,7 +1219,7 @@ Returns `Promise<Buffer>` - resolves with blob data.
|
||||
|
||||
* `url` string
|
||||
* `options` Object (optional)
|
||||
* `headers` Record<string, string> (optional) - HTTP request headers.
|
||||
* `headers` Record\<string, string\> (optional) - HTTP request headers.
|
||||
|
||||
Initiates a download of the resource at `url`.
|
||||
The API will generate a [DownloadItem](download-item.md) that can be accessed
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# FilePathWithHeaders Object
|
||||
|
||||
* `path` string - The path to the file to send.
|
||||
* `headers` Record<string, string> (optional) - Additional headers to be sent.
|
||||
* `headers` Record\<string, string\> (optional) - Additional headers to be sent.
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
* `actionIdentifier` string - The identifier string of the action that the user selected.
|
||||
* `date` number - The delivery date of the notification.
|
||||
* `identifier` string - The unique identifier for this notification request.
|
||||
* `userInfo` Record<string, any> - A dictionary of custom information associated with the notification.
|
||||
* `userInfo` Record\<string, any\> - A dictionary of custom information associated with the notification.
|
||||
* `userText` string (optional) - The text entered or chosen by the user.
|
||||
|
||||
@@ -4,4 +4,4 @@
|
||||
* `referrer` string
|
||||
* `method` string
|
||||
* `uploadData` [UploadData[]](upload-data.md) (optional)
|
||||
* `headers` Record<string, string>
|
||||
* `headers` Record\<string, string\>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
`"text/html"`. Setting `mimeType` would implicitly set the `content-type`
|
||||
header in response, but if `content-type` is already set in `headers`, the
|
||||
`mimeType` would be ignored.
|
||||
* `headers` Record<string, string | string[]> (optional) - An object containing the response headers. The
|
||||
* `headers` Record\<string, string | string[]\> (optional) - An object containing the response headers. The
|
||||
keys must be string, and values must be either string or Array of string.
|
||||
* `data` (Buffer | string | ReadableStream) (optional) - The response body. When
|
||||
returning stream as response, this is a Node.js readable stream representing
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
include in the trace. If not specified, trace all processes.
|
||||
* `histogram_names` string[] (optional) - a list of [histogram][] names to report
|
||||
with the trace.
|
||||
* `memory_dump_config` Record<string, any> (optional) - if the
|
||||
* `memory_dump_config` Record\<string, any\> (optional) - if the
|
||||
`disabled-by-default-memory-infra` category is enabled, this contains
|
||||
optional additional configuration for data collection. See the [Chromium
|
||||
memory-infra docs][memory-infra docs] for more information.
|
||||
|
||||
@@ -36,7 +36,7 @@ Returns `boolean` - Whether the Swipe between pages setting is on.
|
||||
### `systemPreferences.postNotification(event, userInfo[, deliverImmediately])` _macOS_
|
||||
|
||||
* `event` string
|
||||
* `userInfo` Record<string, any>
|
||||
* `userInfo` Record\<string, any\>
|
||||
* `deliverImmediately` boolean (optional) - `true` to post notifications immediately even when the subscribing app is inactive.
|
||||
|
||||
Posts `event` as native notifications of macOS. The `userInfo` is an Object
|
||||
@@ -45,7 +45,7 @@ that contains the user information dictionary sent along with the notification.
|
||||
### `systemPreferences.postLocalNotification(event, userInfo)` _macOS_
|
||||
|
||||
* `event` string
|
||||
* `userInfo` Record<string, any>
|
||||
* `userInfo` Record\<string, any\>
|
||||
|
||||
Posts `event` as native notifications of macOS. The `userInfo` is an Object
|
||||
that contains the user information dictionary sent along with the notification.
|
||||
@@ -53,7 +53,7 @@ that contains the user information dictionary sent along with the notification.
|
||||
### `systemPreferences.postWorkspaceNotification(event, userInfo)` _macOS_
|
||||
|
||||
* `event` string
|
||||
* `userInfo` Record<string, any>
|
||||
* `userInfo` Record\<string, any\>
|
||||
|
||||
Posts `event` as native notifications of macOS. The `userInfo` is an Object
|
||||
that contains the user information dictionary sent along with the notification.
|
||||
@@ -63,7 +63,7 @@ that contains the user information dictionary sent along with the notification.
|
||||
* `event` string | null
|
||||
* `callback` Function
|
||||
* `event` string
|
||||
* `userInfo` Record<string, unknown>
|
||||
* `userInfo` Record\<string, unknown\>
|
||||
* `object` string
|
||||
|
||||
Returns `number` - The ID of this subscription
|
||||
@@ -92,7 +92,7 @@ If `event` is null, the `NSDistributedNotificationCenter` doesn’t use it as cr
|
||||
* `event` string | null
|
||||
* `callback` Function
|
||||
* `event` string
|
||||
* `userInfo` Record<string, unknown>
|
||||
* `userInfo` Record\<string, unknown\>
|
||||
* `object` string
|
||||
|
||||
Returns `number` - The ID of this subscription
|
||||
@@ -107,7 +107,7 @@ If `event` is null, the `NSNotificationCenter` doesn’t use it as criteria for
|
||||
* `event` string | null
|
||||
* `callback` Function
|
||||
* `event` string
|
||||
* `userInfo` Record<string, unknown>
|
||||
* `userInfo` Record\<string, unknown\>
|
||||
* `object` string
|
||||
|
||||
Returns `number` - The ID of this subscription
|
||||
@@ -137,7 +137,7 @@ Same as `unsubscribeNotification`, but removes the subscriber from `NSWorkspace.
|
||||
|
||||
### `systemPreferences.registerDefaults(defaults)` _macOS_
|
||||
|
||||
* `defaults` Record<string, string | boolean | number> - a dictionary of (`key: value`) user defaults
|
||||
* `defaults` Record\<string, string | boolean | number\> - a dictionary of (`key: value`) user defaults
|
||||
|
||||
Add the specified defaults to your application's `NSUserDefaults`.
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ app.whenReady().then(() => {
|
||||
|
||||
**MacOS**
|
||||
|
||||
* Icons passed to the Tray constructor should be [Template Images](native-image.md#template-image).
|
||||
* Icons passed to the Tray constructor should be [Template Images](native-image.md#template-image-macos).
|
||||
* To make sure your icon isn't grainy on retina monitors, be sure your `@2x` image is 144dpi.
|
||||
* If you are bundling your application (e.g., with webpack for development), be sure that the file names are not being mangled or hashed. The filename needs to end in Template, and the `@2x` image needs to have the same filename as the standard image, or MacOS will not magically invert your image's colors or use the high density image.
|
||||
* 16x16 (72dpi) and 32x32@2x (144dpi) work well for most icons.
|
||||
|
||||
@@ -237,7 +237,7 @@ See [`window.open()`](window-open.md) for more details and how to use this in co
|
||||
|
||||
Returns:
|
||||
|
||||
* `details` Event<>
|
||||
* `details` Event\<\>
|
||||
* `url` string - The URL the frame is navigating to.
|
||||
* `isSameDocument` boolean - This event does not fire for same document navigations using window.history api and reference fragment navigations.
|
||||
This property is always set to `false` for this event.
|
||||
@@ -270,7 +270,7 @@ Calling `event.preventDefault()` will prevent the navigation.
|
||||
|
||||
Returns:
|
||||
|
||||
* `details` Event<>
|
||||
* `details` Event\<\>
|
||||
* `url` string - The URL the frame is navigating to.
|
||||
* `isSameDocument` boolean - This event does not fire for same document navigations using window.history api and reference fragment navigations.
|
||||
This property is always set to `false` for this event.
|
||||
@@ -300,7 +300,7 @@ Calling `event.preventDefault()` will prevent the navigation.
|
||||
|
||||
Returns:
|
||||
|
||||
* `details` Event<>
|
||||
* `details` Event\<\>
|
||||
* `url` string - The URL the frame is navigating to.
|
||||
* `isSameDocument` boolean - Whether the navigation happened without changing
|
||||
document. Examples of same document navigations are reference fragment
|
||||
@@ -324,7 +324,7 @@ Emitted when any frame (including main) starts navigating.
|
||||
|
||||
Returns:
|
||||
|
||||
* `details` Event<>
|
||||
* `details` Event\<\>
|
||||
* `url` string - The URL the frame is navigating to.
|
||||
* `isSameDocument` boolean - Whether the navigation happened without changing
|
||||
document. Examples of same document navigations are reference fragment
|
||||
@@ -355,7 +355,7 @@ redirect).
|
||||
|
||||
Returns:
|
||||
|
||||
* `details` Event<>
|
||||
* `details` Event\<\>
|
||||
* `url` string - The URL the frame is navigating to.
|
||||
* `isSameDocument` boolean - Whether the navigation happened without changing
|
||||
document. Examples of same document navigations are reference fragment
|
||||
@@ -674,7 +674,7 @@ Emitted when media is paused or done playing.
|
||||
|
||||
Returns:
|
||||
|
||||
* `event` Event<>
|
||||
* `event` Event\<\>
|
||||
* `audible` boolean - True if one or more frames or child `webContents` are emitting audio.
|
||||
|
||||
Emitted when media becomes audible or inaudible.
|
||||
@@ -894,7 +894,7 @@ Returns:
|
||||
* `webPreferences` [WebPreferences](structures/web-preferences.md) - The web preferences that will be used by the guest
|
||||
page. This object can be modified to adjust the preferences for the guest
|
||||
page.
|
||||
* `params` Record<string, string> - The other `<webview>` parameters such as the `src` URL.
|
||||
* `params` Record\<string, string\> - The other `<webview>` parameters such as the `src` URL.
|
||||
This object can be modified to adjust the parameters of the guest page.
|
||||
|
||||
Emitted when a `<webview>`'s web contents is being attached to this web
|
||||
@@ -1014,7 +1014,7 @@ win.webContents.loadURL('https://github.com', options)
|
||||
|
||||
* `filePath` string
|
||||
* `options` Object (optional)
|
||||
* `query` Record<string, string> (optional) - Passed to `url.format()`.
|
||||
* `query` Record\<string, string\> (optional) - Passed to `url.format()`.
|
||||
* `search` string (optional) - Passed to `url.format()`.
|
||||
* `hash` string (optional) - Passed to `url.format()`.
|
||||
|
||||
@@ -1045,7 +1045,7 @@ win.loadFile('src/index.html')
|
||||
|
||||
* `url` string
|
||||
* `options` Object (optional)
|
||||
* `headers` Record<string, string> (optional) - HTTP request headers.
|
||||
* `headers` Record\<string, string\> (optional) - HTTP request headers.
|
||||
|
||||
Initiates a download of the resource at `url` without navigating. The
|
||||
`will-download` event of `session` will be triggered.
|
||||
@@ -1282,7 +1282,7 @@ Ignore application menu shortcuts while this web contents is focused.
|
||||
|
||||
#### `contents.setWindowOpenHandler(handler)`
|
||||
|
||||
* `handler` Function<{action: 'deny'} | {action: 'allow', outlivesOpener?: boolean, overrideBrowserWindowOptions?: BrowserWindowConstructorOptions}>
|
||||
* `handler` Function\<{action: 'deny'} | {action: 'allow', outlivesOpener?: boolean, overrideBrowserWindowOptions?: BrowserWindowConstructorOptions}\>
|
||||
* `details` Object
|
||||
* `url` string - The _resolved_ version of the URL passed to `window.open()`. e.g. opening a window with `window.open('foo')` will yield something like `https://the-origin/the/current/path/foo`.
|
||||
* `frameName` string - Name of the window provided in `window.open()`
|
||||
@@ -1560,7 +1560,7 @@ Returns `Promise<PrinterInfo[]>` - Resolves with a [`PrinterInfo[]`](structures/
|
||||
* `from` number - Index of the first page to print (0-based).
|
||||
* `to` number - Index of the last page to print (inclusive) (0-based).
|
||||
* `duplexMode` string (optional) - Set the duplex mode of the printed web page. Can be `simplex`, `shortEdge`, or `longEdge`.
|
||||
* `dpi` Record<string, number> (optional)
|
||||
* `dpi` Record\<string, number\> (optional)
|
||||
* `horizontal` number (optional) - The horizontal dpi.
|
||||
* `vertical` number (optional) - The vertical dpi.
|
||||
* `header` string (optional) - string to be printed as page header.
|
||||
@@ -2200,6 +2200,10 @@ A `Integer` representing the unique ID of this WebContents. Each ID is unique am
|
||||
|
||||
A [`Session`](session.md) used by this webContents.
|
||||
|
||||
#### `contents.navigationHistory` _Readonly_
|
||||
|
||||
A [`NavigationHistory`](navigation-history.md) used by this webContents.
|
||||
|
||||
#### `contents.hostWebContents` _Readonly_
|
||||
|
||||
A [`WebContents`](web-contents.md) instance that might own this `WebContents`.
|
||||
|
||||
@@ -99,11 +99,11 @@ Some examples of valid `urls`:
|
||||
* `referrer` string
|
||||
* `timestamp` Double
|
||||
* `uploadData` [UploadData[]](structures/upload-data.md) (optional)
|
||||
* `requestHeaders` Record<string, string>
|
||||
* `requestHeaders` Record\<string, string\>
|
||||
* `callback` Function
|
||||
* `beforeSendResponse` Object
|
||||
* `cancel` boolean (optional)
|
||||
* `requestHeaders` Record<string, string | string[]> (optional) - When provided, request will be made
|
||||
* `requestHeaders` Record\<string, string | string[]\> (optional) - When provided, request will be made
|
||||
with these headers.
|
||||
|
||||
The `listener` will be called with `listener(details, callback)` before sending
|
||||
@@ -126,7 +126,7 @@ The `callback` has to be called with a `response` object.
|
||||
* `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`.
|
||||
* `referrer` string
|
||||
* `timestamp` Double
|
||||
* `requestHeaders` Record<string, string>
|
||||
* `requestHeaders` Record\<string, string\>
|
||||
|
||||
The `listener` will be called with `listener(details)` just before a request is
|
||||
going to be sent to the server, modifications of previous `onBeforeSendHeaders`
|
||||
@@ -148,11 +148,11 @@ response are visible by the time this listener is fired.
|
||||
* `timestamp` Double
|
||||
* `statusLine` string
|
||||
* `statusCode` Integer
|
||||
* `responseHeaders` Record<string, string[]> (optional)
|
||||
* `responseHeaders` Record\<string, string[]\> (optional)
|
||||
* `callback` Function
|
||||
* `headersReceivedResponse` Object
|
||||
* `cancel` boolean (optional)
|
||||
* `responseHeaders` Record<string, string | string[]> (optional) - When provided, the server is assumed
|
||||
* `responseHeaders` Record\<string, string | string[]\> (optional) - When provided, the server is assumed
|
||||
to have responded with these headers.
|
||||
* `statusLine` string (optional) - Should be provided when overriding
|
||||
`responseHeaders` to change header status otherwise original response
|
||||
@@ -177,7 +177,7 @@ The `callback` has to be called with a `response` object.
|
||||
* `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`.
|
||||
* `referrer` string
|
||||
* `timestamp` Double
|
||||
* `responseHeaders` Record<string, string[]> (optional)
|
||||
* `responseHeaders` Record\<string, string[]\> (optional)
|
||||
* `fromCache` boolean - Indicates whether the response was fetched from disk
|
||||
cache.
|
||||
* `statusCode` Integer
|
||||
@@ -207,7 +207,7 @@ and response headers are available.
|
||||
* `ip` string (optional) - The server IP address that the request was
|
||||
actually sent to.
|
||||
* `fromCache` boolean
|
||||
* `responseHeaders` Record<string, string[]> (optional)
|
||||
* `responseHeaders` Record\<string, string[]\> (optional)
|
||||
|
||||
The `listener` will be called with `listener(details)` when a server initiated
|
||||
redirect is about to occur.
|
||||
@@ -226,7 +226,7 @@ redirect is about to occur.
|
||||
* `resourceType` string - Can be `mainFrame`, `subFrame`, `stylesheet`, `script`, `image`, `font`, `object`, `xhr`, `ping`, `cspReport`, `media`, `webSocket` or `other`.
|
||||
* `referrer` string
|
||||
* `timestamp` Double
|
||||
* `responseHeaders` Record<string, string[]> (optional)
|
||||
* `responseHeaders` Record\<string, string[]\> (optional)
|
||||
* `fromCache` boolean
|
||||
* `statusCode` Integer
|
||||
* `statusLine` string
|
||||
|
||||
@@ -284,7 +284,7 @@ e.g. the `http://` or `file://`.
|
||||
|
||||
* `url` string
|
||||
* `options` Object (optional)
|
||||
* `headers` Record<string, string> (optional) - HTTP request headers.
|
||||
* `headers` Record\<string, string\> (optional) - HTTP request headers.
|
||||
|
||||
Initiates a download of the resource at `url` without navigating.
|
||||
|
||||
@@ -577,7 +577,7 @@ Stops any `findInPage` request for the `webview` with the provided `action`.
|
||||
* `from` number - Index of the first page to print (0-based).
|
||||
* `to` number - Index of the last page to print (inclusive) (0-based).
|
||||
* `duplexMode` string (optional) - Set the duplex mode of the printed web page. Can be `simplex`, `shortEdge`, or `longEdge`.
|
||||
* `dpi` Record<string, number> (optional)
|
||||
* `dpi` Record\<string, number\> (optional)
|
||||
* `horizontal` number (optional) - The horizontal dpi.
|
||||
* `vertical` number (optional) - The vertical dpi.
|
||||
* `header` string (optional) - string to be printed as page header.
|
||||
|
||||
@@ -1664,7 +1664,7 @@ folder
|
||||
└── file3
|
||||
```
|
||||
|
||||
In Electron <=6, this would return a `FileList` with a `File` object for:
|
||||
In Electron <=6, this would return a `FileList` with a `File` object for:
|
||||
|
||||
```console
|
||||
path/to/folder
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 4.2 MiB |
@@ -5,34 +5,25 @@ slug: code-signing
|
||||
hide_title: false
|
||||
---
|
||||
|
||||
Code signing is a security technology that you use to certify that an app was
|
||||
created by you. You should sign your application so it does not trigger any
|
||||
operating system security checks.
|
||||
Code signing is a security technology to certify that an app was created by you.
|
||||
You should sign your application so it does not trigger any operating system
|
||||
security warnings.
|
||||
|
||||
On macOS, the system can detect any change to the app, whether the change is
|
||||
introduced accidentally or by malicious code.
|
||||

|
||||
|
||||
On Windows, the system assigns a trust level to your code signing certificate
|
||||
which if you don't have, or if your trust level is low, will cause security
|
||||
dialogs to appear when users start using your application. Trust level builds
|
||||
over time so it's better to start code signing as early as possible.
|
||||
|
||||
While it is possible to distribute unsigned apps, it is not recommended. Both
|
||||
Windows and macOS will, by default, prevent either the download or the execution
|
||||
of unsigned applications. Starting with macOS Catalina (version 10.15), users
|
||||
have to go through multiple manual steps to open unsigned applications.
|
||||
|
||||

|
||||
|
||||
As you can see, users get two options: Move the app straight to the trash or
|
||||
cancel running it. You don't want your users to see that dialog.
|
||||
Both Windows and macOS prevent users from running unsigned applications. It is
|
||||
possible to distribute applications without codesigning them - but in order to
|
||||
run them, users need to go through multiple advanced and manual steps to run
|
||||
them.
|
||||
|
||||
If you are building an Electron app that you intend to package and distribute,
|
||||
it should be code signed.
|
||||
it should be code signed. The Electron ecosystem tooling makes codesigning your
|
||||
apps straightforward - this documentation explains how sign your apps on both
|
||||
Windows and macOS.
|
||||
|
||||
## Signing & notarizing macOS builds
|
||||
|
||||
Properly preparing macOS applications for release requires two steps. First, the
|
||||
Preparing macOS applications for release requires two steps: First, the
|
||||
app needs to be code signed. Then, the app needs to be uploaded to Apple for a
|
||||
process called **notarization**, where automated systems will further verify that
|
||||
your app isn't doing anything to endanger its users.
|
||||
@@ -65,7 +56,9 @@ are likely using [`@electron/packager`][], which includes [`@electron/osx-sign`]
|
||||
[`@electron/notarize`][].
|
||||
|
||||
If you're using Packager's API, you can pass [in configuration that both signs
|
||||
and notarizes your application](https://electron.github.io/packager/main/interfaces/electronpackager.options.html).
|
||||
and notarizes your application](https://electron.github.io/packager/main/modules.html).
|
||||
If the example below does not meet your needs, please see [`@electron/osx-sign`][] and
|
||||
[`@electron/notarize`][] for the many possible configuration options.
|
||||
|
||||
```js @ts-nocheck
|
||||
const packager = require('@electron/packager')
|
||||
@@ -86,35 +79,81 @@ See the [Mac App Store Guide][].
|
||||
|
||||
## Signing Windows builds
|
||||
|
||||
Before signing Windows builds, you must do the following:
|
||||
Before you can code sign your application, you need to acquire a code signing
|
||||
certificate. Unlike Apple, Microsoft allows developers to purchase those
|
||||
certificates on the open market. They are usually sold by the same companies
|
||||
also offering HTTPS certificates. Prices vary, so it may be worth your time to
|
||||
shop around. Popular resellers include:
|
||||
|
||||
1. Get a Windows Authenticode code signing certificate (requires an annual fee)
|
||||
2. Install Visual Studio to get the signing utility (the free [Community
|
||||
Edition](https://visualstudio.microsoft.com/vs/community/) is enough)
|
||||
- [Certum EV code signing certificate](https://shop.certum.eu/data-safety/code-signing-certificates/certum-ev-code-sigining.html)
|
||||
- [DigiCert EV code signing certificate](https://www.digicert.com/signing/code-signing-certificates)
|
||||
- [Entrust EV code signing certificate](https://www.entrustdatacard.com/products/digital-signing-certificates/code-signing-certificates)
|
||||
- [GlobalSign EV code signing certificate](https://www.globalsign.com/en/code-signing-certificate/ev-code-signing-certificates)
|
||||
- [IdenTrust EV code signing certificate](https://www.identrust.com/digital-certificates/trustid-ev-code-signing)
|
||||
- [Sectigo (formerly Comodo) EV code signing certificate](https://sectigo.com/ssl-certificates-tls/code-signing)
|
||||
- [SSL.com EV code signing certificate](https://www.ssl.com/certificates/ev-code-signing/)
|
||||
|
||||
You can get a code signing certificate from a lot of resellers. Prices vary, so
|
||||
it may be worth your time to shop around. Popular resellers include:
|
||||
It is important to call out that since June 2023, Microsoft requires software to
|
||||
be signed with an "extended validation" certificate, also called an "EV code signing
|
||||
certificate". In the past, developers could sign software with a simpler and cheaper
|
||||
certificate called "authenticode code signing certificate" or "software-based OV certificate".
|
||||
These simpler certificates no longer provide benefits: Windows will treat your app as
|
||||
completely unsigned and display the equivalent warning dialogs.
|
||||
|
||||
- [digicert](https://www.digicert.com/dc/code-signing/microsoft-authenticode.htm)
|
||||
- [Sectigo](https://sectigo.com/ssl-certificates-tls/code-signing)
|
||||
- Amongst others, please shop around to find one that suits your needs! 😄
|
||||
The new EV certificates are required to be stored on a hardware storage module
|
||||
compliant with FIPS 140 Level 2, Common Criteria EAL 4+ or equivalent. In other words,
|
||||
the certificate cannot be simply downloaded onto a CI infrastructure. In practice,
|
||||
those storage modules look like fancy USB thumb drives.
|
||||
|
||||
:::caution Keep your certificate password private
|
||||
Your certificate password should be a **secret**. Do not share it publicly or
|
||||
commit it to your source code.
|
||||
:::
|
||||
Many certificate providers now offer "cloud-based signing" - the entire signing hardware
|
||||
is in their data center and you can use it to remotely sign code. This approach is
|
||||
popular with Electron maintainers since it makes signing your applications in CI (like
|
||||
GitHub Actions, CircleCI, etc) relatively easy.
|
||||
|
||||
At the time of writing, Electron's own apps use [DigiCert KeyLocker](https://docs.digicert.com/en/digicert-keylocker.html), but any provider that provides a command line tool for
|
||||
signing files will be compatible with Electron's tooling.
|
||||
|
||||
All tools in the Electron ecosystem use [`@electron/windows-sign`][] and typically
|
||||
expose configuration options through a `windowsSign` property. You can either use it
|
||||
to sign files directly - or use the same `windowsSign` configuration across Electron
|
||||
Forge, [`@electron/packager`][], [`electron-winstaller`][], and [`electron-wix-msi`][].
|
||||
|
||||
### Using Electron Forge
|
||||
|
||||
Electron Forge is the recommended way to sign your `Squirrel.Windows` and `WiX MSI` installers. Detailed instructions on how to configure your application can be found in the [Electron Forge Code Signing Tutorial](https://www.electronforge.io/guides/code-signing/code-signing-macos).
|
||||
Electron Forge is the recommended way to sign your app as well as your `Squirrel.Windows`
|
||||
and `WiX MSI` installers. Detailed instructions on how to configure your application can
|
||||
be found in the [Electron Forge Code Signing Tutorial](https://www.electronforge.io/guides/code-signing/code-signing-windows).
|
||||
|
||||
### Using Electron Packager
|
||||
|
||||
If you're not using an integrated build pipeline like Forge, you
|
||||
are likely using [`@electron/packager`][], which includes [`@electron/windows-sign`][].
|
||||
|
||||
If you're using Packager's API, you can pass [in configuration that signs
|
||||
your application](https://electron.github.io/packager/main/modules.html). If the
|
||||
example below does not meet your needs, please see [`@electron/windows-sign`][]
|
||||
for the many possible configuration options.
|
||||
|
||||
```js @ts-nocheck
|
||||
const packager = require('@electron/packager')
|
||||
|
||||
packager({
|
||||
dir: '/path/to/my/app',
|
||||
windowsSign: {
|
||||
signWithParams: '--my=custom --parameters',
|
||||
// If signtool.exe does not work for you, customize!
|
||||
signToolPath: 'C:\\Path\\To\\my-custom-tool.exe'
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Using electron-winstaller (Squirrel.Windows)
|
||||
|
||||
[`electron-winstaller`][] is a package that can generate Squirrel.Windows installers for your
|
||||
Electron app. This is the tool used under the hood by Electron Forge's
|
||||
[Squirrel.Windows Maker][maker-squirrel]. If you're not using Electron Forge and want to use
|
||||
`electron-winstaller` directly, use the `certificateFile` and `certificatePassword` configuration
|
||||
options when creating your installer.
|
||||
[Squirrel.Windows Maker][maker-squirrel]. Just like `@electron/packager`, it uses
|
||||
[`@electron/windows-sign`][] under the hood and supports the same `windowsSign`
|
||||
options.
|
||||
|
||||
```js {10-11} @ts-nocheck
|
||||
const electronInstaller = require('electron-winstaller')
|
||||
@@ -126,8 +165,11 @@ try {
|
||||
outputDirectory: '/tmp/build/installer64',
|
||||
authors: 'My App Inc.',
|
||||
exe: 'myapp.exe',
|
||||
certificateFile: './cert.pfx',
|
||||
certificatePassword: 'this-is-a-secret'
|
||||
windowsSign: {
|
||||
signWithParams: '--my=custom --parameters',
|
||||
// If signtool.exe does not work for you, customize!
|
||||
signToolPath: 'C:\\Path\\To\\my-custom-tool.exe'
|
||||
}
|
||||
})
|
||||
console.log('It worked!')
|
||||
} catch (e) {
|
||||
@@ -141,10 +183,8 @@ For full configuration options, check out the [`electron-winstaller`][] reposito
|
||||
|
||||
[`electron-wix-msi`][] is a package that can generate MSI installers for your
|
||||
Electron app. This is the tool used under the hood by Electron Forge's [MSI Maker][maker-msi].
|
||||
|
||||
If you're not using Electron Forge and want to use `electron-wix-msi` directly, use the
|
||||
`certificateFile` and `certificatePassword` configuration options
|
||||
or pass in parameters directly to [SignTool.exe][] with the `signWithParams` option.
|
||||
Just like `@electron/packager`, it uses [`@electron/windows-sign`][] under the hood
|
||||
and supports the same `windowsSign` options.
|
||||
|
||||
```js {12-13} @ts-nocheck
|
||||
import { MSICreator } from 'electron-wix-msi'
|
||||
@@ -158,8 +198,11 @@ const msiCreator = new MSICreator({
|
||||
manufacturer: 'Kitten Technologies',
|
||||
version: '1.1.2',
|
||||
outputDirectory: '/path/to/output/folder',
|
||||
certificateFile: './cert.pfx',
|
||||
certificatePassword: 'this-is-a-secret'
|
||||
windowsSign: {
|
||||
signWithParams: '--my=custom --parameters',
|
||||
// If signtool.exe does not work for you, customize!
|
||||
signToolPath: 'C:\\Path\\To\\my-custom-tool.exe'
|
||||
}
|
||||
})
|
||||
|
||||
// Step 2: Create a .wxs template file
|
||||
@@ -192,6 +235,7 @@ See the [Windows Store Guide][].
|
||||
[`@electron/osx-sign`]: https://github.com/electron/osx-sign
|
||||
[`@electron/packager`]: https://github.com/electron/packager
|
||||
[`@electron/notarize`]: https://github.com/electron/notarize
|
||||
[`@electron/windows-sign`]: https://github.com/electron/windows-sign
|
||||
[`electron-winstaller`]: https://github.com/electron/windows-installer
|
||||
[`electron-wix-msi`]: https://github.com/electron-userland/electron-wix-msi
|
||||
[xcode]: https://developer.apple.com/xcode
|
||||
@@ -200,4 +244,3 @@ See the [Windows Store Guide][].
|
||||
[windows store guide]: ./windows-store-guide.md
|
||||
[maker-squirrel]: https://www.electronforge.io/config/makers/squirrel.windows
|
||||
[maker-msi]: https://www.electronforge.io/config/makers/wix-msi
|
||||
[signtool.exe]: https://learn.microsoft.com/en-us/dotnet/framework/tools/signtool-exe
|
||||
|
||||
@@ -9,10 +9,10 @@ check out our [Electron Versioning](./electron-versioning.md) doc.
|
||||
|
||||
| Electron | Alpha | Beta | Stable | EOL | Chrome | Node | Supported |
|
||||
| ------- | ----- | ------- | ------ | ------ | ---- | ---- | ---- |
|
||||
| 29.0.0 | 2023-Dec-07 | 2024-Jan-24 | 2024-Feb-20 | 2024-Aug-20 | M122 | v18.19 | ✅ |
|
||||
| 29.0.0 | 2023-Dec-07 | 2024-Jan-24 | 2024-Feb-20 | 2024-Aug-20 | M122 | v20.9 | ✅ |
|
||||
| 28.0.0 | 2023-Oct-11 | 2023-Nov-06 | 2023-Dec-05 | 2024-Jun-11 | M120 | v18.18 | ✅ |
|
||||
| 27.0.0 | 2023-Aug-17 | 2023-Sep-13 | 2023-Oct-10 | 2024-Apr-16 | M118 | v18.17 | ✅ |
|
||||
| 26.0.0 | 2023-Jun-01 | 2023-Jun-27 | 2023-Aug-15 | 2024-Feb-20 | M116 | v18.16 | ✅ |
|
||||
| 26.0.0 | 2023-Jun-01 | 2023-Jun-27 | 2023-Aug-15 | 2024-Feb-20 | M116 | v18.16 | 🚫 |
|
||||
| 25.0.0 | 2023-Apr-10 | 2023-May-02 | 2023-May-30 | 2023-Dec-05 | M114 | v18.15 | 🚫 |
|
||||
| 24.0.0 | 2023-Feb-09 | 2023-Mar-07 | 2023-Apr-04 | 2023-Oct-10 | M112 | v18.14 | 🚫 |
|
||||
| 23.0.0 | 2022-Dec-01 | 2023-Jan-10 | 2023-Feb-07 | 2023-Aug-15 | M110 | v18.12 | 🚫 |
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -77,6 +77,7 @@ template("electron_extra_paks") {
|
||||
"//content:content_resources",
|
||||
"//content/browser/resources/gpu:resources",
|
||||
"//content/browser/resources/media:resources",
|
||||
"//content/browser/resources/process:resources",
|
||||
"//content/browser/tracing:resources",
|
||||
"//content/browser/webrtc/resources",
|
||||
"//electron:resources",
|
||||
@@ -96,6 +97,7 @@ template("electron_extra_paks") {
|
||||
# New paks should be added here by default.
|
||||
sources += [
|
||||
"$root_gen_dir/content/browser/devtools/devtools_resources.pak",
|
||||
"$root_gen_dir/content/process_resources.pak",
|
||||
"$root_gen_dir/ui/resources/webui_resources.pak",
|
||||
]
|
||||
deps += [ "//content/browser/devtools:devtools_resources" ]
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -263,13 +263,11 @@ WebContents.prototype.printToPDF = async function (options) {
|
||||
|
||||
// TODO(codebytere): deduplicate argument sanitization by moving rest of
|
||||
// print param logic into new file shared between printToPDF and print
|
||||
WebContents.prototype.print = function (options: ElectronInternal.WebContentsPrintOptions, callback) {
|
||||
if (typeof options !== 'object') {
|
||||
WebContents.prototype.print = function (options: ElectronInternal.WebContentsPrintOptions = {}, callback) {
|
||||
if (typeof options !== 'object' || options == null) {
|
||||
throw new TypeError('webContents.print(): Invalid print settings specified.');
|
||||
}
|
||||
|
||||
const printSettings: Record<string, any> = { ...options };
|
||||
|
||||
const pageSize = options.pageSize ?? 'A4';
|
||||
if (typeof pageSize === 'object') {
|
||||
if (!pageSize.height || !pageSize.width) {
|
||||
@@ -283,7 +281,7 @@ WebContents.prototype.print = function (options: ElectronInternal.WebContentsPri
|
||||
throw new RangeError('height and width properties must be minimum 352 microns.');
|
||||
}
|
||||
|
||||
printSettings.mediaSize = {
|
||||
options.mediaSize = {
|
||||
name: 'CUSTOM',
|
||||
custom_display_name: 'Custom',
|
||||
height_microns: height,
|
||||
@@ -295,7 +293,7 @@ WebContents.prototype.print = function (options: ElectronInternal.WebContentsPri
|
||||
};
|
||||
} else if (typeof pageSize === 'string' && PDFPageSizes[pageSize]) {
|
||||
const mediaSize = PDFPageSizes[pageSize];
|
||||
printSettings.mediaSize = {
|
||||
options.mediaSize = {
|
||||
...mediaSize,
|
||||
imageable_area_left_microns: 0,
|
||||
imageable_area_bottom_microns: 0,
|
||||
@@ -308,9 +306,9 @@ WebContents.prototype.print = function (options: ElectronInternal.WebContentsPri
|
||||
|
||||
if (this._print) {
|
||||
if (callback) {
|
||||
this._print(printSettings, callback);
|
||||
this._print(options, callback);
|
||||
} else {
|
||||
this._print(printSettings);
|
||||
this._print(options);
|
||||
}
|
||||
} else {
|
||||
console.error('Error: Printing feature is disabled.');
|
||||
@@ -520,6 +518,17 @@ WebContents.prototype._init = function () {
|
||||
enumerable: true
|
||||
});
|
||||
|
||||
// Add navigationHistory property which handles session history,
|
||||
// maintaining a list of navigation entries for backward and forward navigation.
|
||||
Object.defineProperty(this, 'navigationHistory', {
|
||||
value: {
|
||||
getActiveIndex: this._getActiveIndex.bind(this),
|
||||
length: this._historyLength.bind(this),
|
||||
getEntryAtIndex: this._getNavigationEntryAtIndex.bind(this)
|
||||
},
|
||||
writable: false
|
||||
});
|
||||
|
||||
// Dispatch IPC messages to the ipc module.
|
||||
this.on('-ipc-message' as any, function (this: Electron.WebContents, event: Electron.IpcMainEvent, internal: boolean, channel: string, args: any[]) {
|
||||
addSenderToEvent(event, this);
|
||||
|
||||
@@ -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",
|
||||
|
||||
10
patches/DirectXShaderCompiler/.patches
Normal file
10
patches/DirectXShaderCompiler/.patches
Normal 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
|
||||
523
patches/DirectXShaderCompiler/cherry-pick-0b785e88fefa.patch
Normal file
523
patches/DirectXShaderCompiler/cherry-pick-0b785e88fefa.patch
Normal 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)
|
||||
419
patches/DirectXShaderCompiler/cherry-pick-2a434fd0af6b.patch
Normal file
419
patches/DirectXShaderCompiler/cherry-pick-2a434fd0af6b.patch
Normal 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)
|
||||
332
patches/DirectXShaderCompiler/cherry-pick-33051b084850.patch
Normal file
332
patches/DirectXShaderCompiler/cherry-pick-33051b084850.patch
Normal 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)
|
||||
243
patches/DirectXShaderCompiler/cherry-pick-511cfef8e050.patch
Normal file
243
patches/DirectXShaderCompiler/cherry-pick-511cfef8e050.patch
Normal 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)
|
||||
108
patches/DirectXShaderCompiler/cherry-pick-867c1001637e.patch
Normal file
108
patches/DirectXShaderCompiler/cherry-pick-867c1001637e.patch
Normal 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, we’re 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();
|
||||
+ }
|
||||
+}
|
||||
312
patches/DirectXShaderCompiler/cherry-pick-93c3cf1c787f.patch
Normal file
312
patches/DirectXShaderCompiler/cherry-pick-93c3cf1c787f.patch
Normal 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)
|
||||
66
patches/DirectXShaderCompiler/cherry-pick-a65e511a14b4.patch
Normal file
66
patches/DirectXShaderCompiler/cherry-pick-a65e511a14b4.patch
Normal 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();
|
||||
+}
|
||||
294
patches/DirectXShaderCompiler/cherry-pick-b845fed99111.patch
Normal file
294
patches/DirectXShaderCompiler/cherry-pick-b845fed99111.patch
Normal 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)
|
||||
57
patches/DirectXShaderCompiler/cherry-pick-bc18aec94c82.patch
Normal file
57
patches/DirectXShaderCompiler/cherry-pick-bc18aec94c82.patch
Normal 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());
|
||||
161
patches/DirectXShaderCompiler/cherry-pick-bd7aa9779873.patch
Normal file
161
patches/DirectXShaderCompiler/cherry-pick-bd7aa9779873.patch
Normal 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
5
patches/angle/.patches
Normal 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
|
||||
249
patches/angle/cherry-pick-ba3b4e239620.patch
Normal file
249
patches/angle/cherry-pick-ba3b4e239620.patch
Normal 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)
|
||||
{
|
||||
74
patches/angle/cherry-pick-bda89e1f7c71.patch
Normal file
74
patches/angle/cherry-pick-bda89e1f7c71.patch
Normal 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
|
||||
32
patches/angle/cherry-pick-c67f290ef0f0.patch
Normal file
32
patches/angle/cherry-pick-c67f290ef0f0.patch
Normal 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);
|
||||
267
patches/angle/cherry-pick-f6672dbbe223.patch
Normal file
267
patches/angle/cherry-pick-f6672dbbe223.patch
Normal 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();
|
||||
}
|
||||
@@ -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,
|
||||
@@ -131,4 +131,22 @@ fix_suppress_clang_-wimplicit-const-int-float-conversion_in.patch
|
||||
cherry-pick-e7ffe20ebfac.patch
|
||||
fix_getcursorscreenpoint_wrongly_returns_0_0.patch
|
||||
fix_add_support_for_skipping_first_2_no-op_refreshes_in_thumb_cap.patch
|
||||
revert_same_party_cookie_attribute_removal.patch
|
||||
remove_dxdiag_telemetry_code.patch
|
||||
cherry-pick-2607ddacd643.patch
|
||||
cherry-pick-1b1f34234346.patch
|
||||
bindings_refactor_domdatastore.patch
|
||||
merge_fix_domarraybuffer_isdetached_and_comment_out_a_check.patch
|
||||
cherry-pick-98bcf9ef5cdd.patch
|
||||
cherry-pick-c1f25647c2fc.patch
|
||||
cherry-pick-013961609785.patch
|
||||
a11y_avoid_clearing_resetting_focus_on_an_already_focus_event.patch
|
||||
cherry-pick-b2cc7b7ac538.patch
|
||||
feat_add_support_for_missing_dialog_features_to_shell_dialogs.patch
|
||||
cherry-pick-03609e39be8c.patch
|
||||
x11_use_localized_display_label_only_for_browser_process.patch
|
||||
cherry-pick-b922fcb61e3b.patch
|
||||
cherry-pick-0d9598145069.patch
|
||||
cherry-pick-24329fe5c4d0.patch
|
||||
m120-lts_mediasession_use_a_mediasessionimpl_weakptr_in.patch
|
||||
x11_fix_crash_when_randr_getmonitors_fails.patch
|
||||
feat_enable_passing_exit_code_on_service_process_crash.patch
|
||||
|
||||
@@ -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
|
||||
1231
patches/chromium/bindings_refactor_domdatastore.patch
Normal file
1231
patches/chromium/bindings_refactor_domdatastore.patch
Normal file
File diff suppressed because it is too large
Load Diff
139
patches/chromium/cherry-pick-013961609785.patch
Normal file
139
patches/chromium/cherry-pick-013961609785.patch
Normal 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
|
||||
117
patches/chromium/cherry-pick-03609e39be8c.patch
Normal file
117
patches/chromium/cherry-pick-03609e39be8c.patch
Normal 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();
|
||||
-
|
||||
805
patches/chromium/cherry-pick-0d9598145069.patch
Normal file
805
patches/chromium/cherry-pick-0d9598145069.patch
Normal 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) {
|
||||
42
patches/chromium/cherry-pick-1b1f34234346.patch
Normal file
42
patches/chromium/cherry-pick-1b1f34234346.patch
Normal 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())) {
|
||||
106
patches/chromium/cherry-pick-24329fe5c4d0.patch
Normal file
106
patches/chromium/cherry-pick-24329fe5c4d0.patch
Normal 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*,
|
||||
38
patches/chromium/cherry-pick-2607ddacd643.patch
Normal file
38
patches/chromium/cherry-pick-2607ddacd643.patch
Normal file
@@ -0,0 +1,38 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Calvin Watford <watfordcalvin@gmail.com>
|
||||
Date: Tue, 12 Mar 2024 20:37:32 +0000
|
||||
Subject: Fix primary display race condition crash on Windows
|
||||
|
||||
In rare cases, it's possible for the OS to provide us a list of displays
|
||||
that doesn't contain the primary display. This situation causes
|
||||
undefined behavior (dereference past vector end) and a crash to occur in
|
||||
|display::win::(anon)::DisplayInfosToScreenWinDisplays| on builds
|
||||
without DCHECK enabled.
|
||||
|
||||
Bug: 40265302
|
||||
Change-Id: I2154bedea84478a84147c380610c85d4ea3f703a
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5353255
|
||||
Reviewed-by: David Bienvenu <davidbienvenu@chromium.org>
|
||||
Reviewed-by: Robert Liao <robliao@chromium.org>
|
||||
Commit-Queue: David Bienvenu <davidbienvenu@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#1271793}
|
||||
|
||||
diff --git a/ui/display/win/screen_win.cc b/ui/display/win/screen_win.cc
|
||||
index 6b6189a124e3fde423b129ef34f2c96186b4e86d..1040e583c6c50ba01efc44faa1882657ff8f63b2 100644
|
||||
--- a/ui/display/win/screen_win.cc
|
||||
+++ b/ui/display/win/screen_win.cc
|
||||
@@ -324,7 +324,13 @@ std::vector<ScreenWinDisplay> DisplayInfosToScreenWinDisplays(
|
||||
display_infos_remaining, [](const internal::DisplayInfo& display_info) {
|
||||
return display_info.screen_rect().origin().IsOrigin();
|
||||
});
|
||||
- DCHECK(primary_display_iter != display_infos_remaining.end());
|
||||
+
|
||||
+ // If we can't find the primary display, we likely witnessed a race condition
|
||||
+ // when querying the OS for display info. We expect another OS notification to
|
||||
+ // trigger this lookup again soon, so just return an empty list for now.
|
||||
+ if (primary_display_iter == display_infos_remaining.end()) {
|
||||
+ return {};
|
||||
+ }
|
||||
|
||||
// Build the tree and determine DisplayPlacements along the way.
|
||||
DisplayLayoutBuilder builder(primary_display_iter->id());
|
||||
102
patches/chromium/cherry-pick-98bcf9ef5cdd.patch
Normal file
102
patches/chromium/cherry-pick-98bcf9ef5cdd.patch
Normal 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
|
||||
99
patches/chromium/cherry-pick-b2cc7b7ac538.patch
Normal file
99
patches/chromium/cherry-pick-b2cc7b7ac538.patch
Normal 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();
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
89
patches/chromium/cherry-pick-b922fcb61e3b.patch
Normal file
89
patches/chromium/cherry-pick-b922fcb61e3b.patch
Normal 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();
|
||||
27
patches/chromium/cherry-pick-c1f25647c2fc.patch
Normal file
27
patches/chromium/cherry-pick-c1f25647c2fc.patch
Normal 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.
|
||||
@@ -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();
|
||||
@@ -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_;
|
||||
|
||||
@@ -16,7 +16,7 @@ Linux or Windows to un-fullscreen in some circumstances without this
|
||||
change.
|
||||
|
||||
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
|
||||
index a543fb2ec5873da9d2b108748eaa5d52de4f0d50..a03f68e218dd540d3d1fd3d51e3fa67478198789 100644
|
||||
index 1a131cf3a34b32cae6180a6744c0169431d866a5..f57c698fe21e54c0687fe26093224d677fdc2c34 100644
|
||||
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
|
||||
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
|
||||
@@ -16,12 +16,16 @@
|
||||
@@ -115,8 +115,8 @@ index a543fb2ec5873da9d2b108748eaa5d52de4f0d50..a03f68e218dd540d3d1fd3d51e3fa674
|
||||
return;
|
||||
|
||||
+#if 0
|
||||
CHECK(fullscreen_start_time_);
|
||||
if (exclusive_access_tab()) {
|
||||
// `fullscreen_start_time_` is null if a fullscreen tab moves to a new window.
|
||||
if (fullscreen_start_time_ && exclusive_access_tab()) {
|
||||
ukm::SourceId source_id =
|
||||
@@ -562,15 +573,16 @@ void FullscreenController::ExitFullscreenModeInternal() {
|
||||
.Record(ukm::UkmRecorder::Get());
|
||||
|
||||
@@ -40,18 +40,16 @@ index 25896ab0f3ca233ae17bf509f2a6ae5a6cc3c54b..5a8e6d184e276833034c604be8c48e01
|
||||
// Called from BrowserMainLoop::PostCreateThreads().
|
||||
// TODO(content/browser/gpu/OWNERS): This should probably use a
|
||||
diff --git a/content/browser/gpu/gpu_data_manager_impl_private.cc b/content/browser/gpu/gpu_data_manager_impl_private.cc
|
||||
index 4fa857fed71485898f4ba7c6e78cc8be37d8dbf7..3306a36044eed8395b3a13cffa4754cadee1048d 100644
|
||||
index 4fa857fed71485898f4ba7c6e78cc8be37d8dbf7..c12a96390350b5bd14a43506d8a35e4b0dec4924 100644
|
||||
--- a/content/browser/gpu/gpu_data_manager_impl_private.cc
|
||||
+++ b/content/browser/gpu/gpu_data_manager_impl_private.cc
|
||||
@@ -1222,6 +1222,12 @@ void GpuDataManagerImplPrivate::TerminateInfoCollectionGpuProcess() {
|
||||
@@ -1222,6 +1222,10 @@ void GpuDataManagerImplPrivate::TerminateInfoCollectionGpuProcess() {
|
||||
if (host)
|
||||
host->ForceShutdown();
|
||||
}
|
||||
+
|
||||
+bool GpuDataManagerImplPrivate::DxdiagDx12VulkanRequested() const {
|
||||
+ return !(gpu_info_vulkan_request_failed_ ||
|
||||
+ gpu_info_dx12_request_failed_ ||
|
||||
+ gpu_info_dx_diag_request_failed_);
|
||||
+ return !(gpu_info_vulkan_request_failed_ || gpu_info_dx12_request_failed_);
|
||||
+}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -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_;
|
||||
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
@@ -133,10 +133,10 @@ index 38c8cf36fdf9366121c7ada96c167a4c9664952e..03b37fb62655a355e104870a088e4222
|
||||
const GURL& document_url,
|
||||
const WeakDocumentPtr& weak_document_ptr,
|
||||
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
|
||||
index b656054d342f53d655b8c068b127250a8e8af6c3..5f6267cce7c59eab684dda3f8bfc7982b6407841 100644
|
||||
index 545c860afff13c6aa5030128f508f325de0ab507..938844e3f653344b97dd8e59faacdb8eded561a9 100644
|
||||
--- a/content/browser/renderer_host/render_process_host_impl.cc
|
||||
+++ b/content/browser/renderer_host/render_process_host_impl.cc
|
||||
@@ -2045,7 +2045,7 @@ void RenderProcessHostImpl::CreateNotificationService(
|
||||
@@ -2048,7 +2048,7 @@ void RenderProcessHostImpl::CreateNotificationService(
|
||||
case RenderProcessHost::NotificationServiceCreatorType::kSharedWorker:
|
||||
case RenderProcessHost::NotificationServiceCreatorType::kDedicatedWorker: {
|
||||
storage_partition_impl_->GetPlatformNotificationContext()->CreateService(
|
||||
@@ -145,7 +145,7 @@ index b656054d342f53d655b8c068b127250a8e8af6c3..5f6267cce7c59eab684dda3f8bfc7982
|
||||
creator_type, std::move(receiver));
|
||||
break;
|
||||
}
|
||||
@@ -2053,7 +2053,7 @@ void RenderProcessHostImpl::CreateNotificationService(
|
||||
@@ -2056,7 +2056,7 @@ void RenderProcessHostImpl::CreateNotificationService(
|
||||
CHECK(rfh);
|
||||
|
||||
storage_partition_impl_->GetPlatformNotificationContext()->CreateService(
|
||||
|
||||
1118
patches/chromium/remove_dxdiag_telemetry_code.patch
Normal file
1118
patches/chromium/remove_dxdiag_telemetry_code.patch
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -22,13 +22,13 @@ However, the patch would need to be reviewed by the security team, as it
|
||||
does touch a security-sensitive class.
|
||||
|
||||
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
|
||||
index 5f6267cce7c59eab684dda3f8bfc7982b6407841..4551601cf77d57e74c725d4352b128c0ac8b09b7 100644
|
||||
index 938844e3f653344b97dd8e59faacdb8eded561a9..ae21df015a9e43d4c324bd79ff3bf00c23b5225e 100644
|
||||
--- a/content/browser/renderer_host/render_process_host_impl.cc
|
||||
+++ b/content/browser/renderer_host/render_process_host_impl.cc
|
||||
@@ -1727,9 +1727,15 @@ bool RenderProcessHostImpl::Init() {
|
||||
@@ -1730,9 +1730,15 @@ bool RenderProcessHostImpl::Init() {
|
||||
std::unique_ptr<SandboxedProcessLauncherDelegate> sandbox_delegate =
|
||||
std::make_unique<RendererSandboxedProcessLauncherDelegateWin>(
|
||||
*cmd_line, IsPdf(), IsJitDisabled());
|
||||
*cmd_line, IsPdf(), /*is_jit_disabled=*/IsPdf());
|
||||
+#else
|
||||
+#if BUILDFLAG(USE_ZYGOTE)
|
||||
+ bool use_zygote = !cmd_line->HasSwitch(switches::kNoZygote);
|
||||
|
||||
@@ -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;
|
||||
@@ -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());
|
||||
}
|
||||
@@ -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
1
patches/dawn/.patches
Normal file
@@ -0,0 +1 @@
|
||||
dawn_dxc_disable_dxc_pass_structurize-loop-exits-for-unroll.patch
|
||||
@@ -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");
|
||||
@@ -1 +1,2 @@
|
||||
chore_expose_ui_to_allow_electron_to_set_dock_side.patch
|
||||
fix_support_for_worklet_targets.patch
|
||||
|
||||
@@ -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
2
patches/libaom/.patches
Normal file
@@ -0,0 +1,2 @@
|
||||
update_codec_config_after_svc_scale_controls.patch
|
||||
encode_api_test_add_repro_for_chromium_339877165.patch
|
||||
@@ -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>> {};
|
||||
@@ -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;
|
||||
@@ -50,5 +50,9 @@ src_update_default_v8_platform_to_override_functions_with_location.patch
|
||||
fix_capture_embedder_exceptions_before_entering_v8.patch
|
||||
spec_add_iterator_to_global_intrinsics.patch
|
||||
fix_undici_incorrectly_copies_headers_onto_fetches.patch
|
||||
src_preload_function_for_environment.patch
|
||||
fix_revert_src_lb_reducing_c_calls_of_esm_legacy_main_resolve.patch
|
||||
src_preload_function_for_environment.patch
|
||||
fs_fix_wtf-8_decoding_issue.patch
|
||||
stream_do_not_defer_construction_by_one_microtick.patch
|
||||
deps_disable_io_uring_support_in_libuv_by_default.patch
|
||||
src_deps_disable_setuid_etc_if_io_uring_enabled.patch
|
||||
|
||||
@@ -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
|
||||
30
patches/node/fs_fix_wtf-8_decoding_issue.patch
Normal file
30
patches/node/fs_fix_wtf-8_decoding_issue.patch
Normal file
@@ -0,0 +1,30 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Richard Lau <rlau@redhat.com>
|
||||
Date: Fri, 1 Mar 2024 19:15:40 +0000
|
||||
Subject: fs: fix WTF-8 decoding issue
|
||||
|
||||
Cherry-pick of libuv/libuv@d09441c
|
||||
|
||||
Refs: https://github.com/libuv/libuv/pull/2970
|
||||
Fixes: https://github.com/nodejs/node/issues/48673
|
||||
|
||||
We forgot to mask off the high bits from the first byte, so we ended up
|
||||
always failing the subsequent range check.
|
||||
|
||||
diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c
|
||||
index fc209c54f470edaa031009979061cff071cbf66d..4fc13b04bdae5bd9e2627027a10c534c2d9675dc 100644
|
||||
--- a/deps/uv/src/win/fs.c
|
||||
+++ b/deps/uv/src/win/fs.c
|
||||
@@ -176,9 +176,11 @@ static int32_t fs__decode_wtf8_char(const char** input) {
|
||||
if ((b4 & 0xC0) != 0x80)
|
||||
return -1; /* invalid: not a continuation byte */
|
||||
code_point = (code_point << 6) | (b4 & 0x3F);
|
||||
- if (b1 <= 0xF4)
|
||||
+ if (b1 <= 0xF4) {
|
||||
+ code_point &= 0x1FFFFF;
|
||||
if (code_point <= 0x10FFFF)
|
||||
return code_point; /* four-byte character */
|
||||
+ }
|
||||
|
||||
/* code point too large */
|
||||
return -1;
|
||||
@@ -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')));
|
||||
+}
|
||||
@@ -1,23 +1,9 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Cheng Zhao <zcbenz@gmail.com>
|
||||
Date: Mon, 22 Jan 2024 13:45:55 +0900
|
||||
Date: Mon, 4 Mar 2024 11:41:18 +0900
|
||||
Subject: src: preload function for Environment
|
||||
|
||||
https://github.com/nodejs/node/pull/51539
|
||||
|
||||
This PR adds a |preload| arg to the node::CreateEnvironment to allow
|
||||
embedders to set a preload function for the environment, which will run
|
||||
after the environment is loaded and before the main script runs.
|
||||
|
||||
This is similiar to the --require CLI option, but runs a C++ function,
|
||||
and can only be set by embedders.
|
||||
|
||||
The preload function can be used by embedders to inject scripts before
|
||||
running the main script, for example:
|
||||
1. In Electron it is used to initialize the ASAR virtual filesystem,
|
||||
inject custom process properties, etc.
|
||||
2. In VS Code it can be used to reset the module search paths for
|
||||
extensions.
|
||||
Backport https://github.com/nodejs/node/pull/51539
|
||||
|
||||
diff --git a/lib/internal/process/pre_execution.js b/lib/internal/process/pre_execution.js
|
||||
index cbb89d76621de6a85b8e8697078d74c6bde0a742..4b1c0405a3bc7fb66d138b273cab05589b1a7360 100644
|
||||
@@ -45,92 +31,80 @@ index cbb89d76621de6a85b8e8697078d74c6bde0a742..4b1c0405a3bc7fb66d138b273cab0558
|
||||
// For user code, we preload modules if `-r` is passed
|
||||
const preloadModules = getOptionValue('--require');
|
||||
diff --git a/src/api/environment.cc b/src/api/environment.cc
|
||||
index 74b4e15b8230c6380d41e84aa504824bb79b2ee5..e033760193fcd4fedd645c9259f58bc6b06250f4 100644
|
||||
index 74b4e15b8230c6380d41e84aa504824bb79b2ee5..5ef231ba77b187ff4df3b3d2f3f4eec2b7667c92 100644
|
||||
--- a/src/api/environment.cc
|
||||
+++ b/src/api/environment.cc
|
||||
@@ -437,7 +437,8 @@ Environment* CreateEnvironment(
|
||||
const std::vector<std::string>& exec_args,
|
||||
EnvironmentFlags::Flags flags,
|
||||
ThreadId thread_id,
|
||||
- std::unique_ptr<InspectorParentHandle> inspector_parent_handle) {
|
||||
+ std::unique_ptr<InspectorParentHandle> inspector_parent_handle,
|
||||
+ EmbedderPreloadCallback preload) {
|
||||
Isolate* isolate = isolate_data->isolate();
|
||||
HandleScope handle_scope(isolate);
|
||||
@@ -549,25 +549,31 @@ NODE_EXTERN std::unique_ptr<InspectorParentHandle> GetInspectorParentHandle(
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -456,7 +457,8 @@ Environment* CreateEnvironment(
|
||||
exec_args,
|
||||
env_snapshot_info,
|
||||
flags,
|
||||
- thread_id);
|
||||
+ thread_id,
|
||||
+ std::move(preload));
|
||||
CHECK_NOT_NULL(env);
|
||||
-MaybeLocal<Value> LoadEnvironment(
|
||||
- Environment* env,
|
||||
- StartExecutionCallback cb) {
|
||||
+MaybeLocal<Value> LoadEnvironment(Environment* env,
|
||||
+ StartExecutionCallback cb,
|
||||
+ EmbedderPreloadCallback preload) {
|
||||
env->InitializeLibuv();
|
||||
env->InitializeDiagnostics();
|
||||
+ if (preload) {
|
||||
+ env->set_embedder_preload(std::move(preload));
|
||||
+ }
|
||||
|
||||
if (use_snapshot) {
|
||||
return StartExecution(env, cb);
|
||||
}
|
||||
|
||||
MaybeLocal<Value> LoadEnvironment(Environment* env,
|
||||
- std::string_view main_script_source_utf8) {
|
||||
+ std::string_view main_script_source_utf8,
|
||||
+ EmbedderPreloadCallback preload) {
|
||||
CHECK_NOT_NULL(main_script_source_utf8.data());
|
||||
return LoadEnvironment(
|
||||
- env, [&](const StartExecutionCallbackInfo& info) -> MaybeLocal<Value> {
|
||||
+ env,
|
||||
+ [&](const StartExecutionCallbackInfo& info) -> MaybeLocal<Value> {
|
||||
Local<Value> main_script =
|
||||
ToV8Value(env->context(), main_script_source_utf8).ToLocalChecked();
|
||||
return info.run_cjs->Call(
|
||||
env->context(), Null(env->isolate()), 1, &main_script);
|
||||
- });
|
||||
+ },
|
||||
+ std::move(preload));
|
||||
}
|
||||
|
||||
Environment* GetCurrentEnvironment(Local<Context> context) {
|
||||
diff --git a/src/env-inl.h b/src/env-inl.h
|
||||
index 524a9633ef16e48797dc6a1e507ca0be2bfffe7e..b5ec98128d4e08ef26121be070ac2ebe5e339534 100644
|
||||
index 524a9633ef16e48797dc6a1e507ca0be2bfffe7e..9f30ebb821dfcbfe4c7c55332a28d076b09b9177 100644
|
||||
--- a/src/env-inl.h
|
||||
+++ b/src/env-inl.h
|
||||
@@ -438,6 +438,10 @@ inline void Environment::set_embedder_entry_point(StartExecutionCallback&& fn) {
|
||||
@@ -438,6 +438,14 @@ inline void Environment::set_embedder_entry_point(StartExecutionCallback&& fn) {
|
||||
embedder_entry_point_ = std::move(fn);
|
||||
}
|
||||
|
||||
+inline const EmbedderPreloadCallback& Environment::embedder_preload() const {
|
||||
+ return embedder_preload_;
|
||||
+}
|
||||
+
|
||||
+inline void Environment::set_embedder_preload(EmbedderPreloadCallback fn) {
|
||||
+ embedder_preload_ = std::move(fn);
|
||||
+}
|
||||
+
|
||||
inline double Environment::new_async_id() {
|
||||
async_hooks()->async_id_fields()[AsyncHooks::kAsyncIdCounter] += 1;
|
||||
return async_hooks()->async_id_fields()[AsyncHooks::kAsyncIdCounter];
|
||||
diff --git a/src/env.cc b/src/env.cc
|
||||
index 25b81dee18aeeb1bd0452ba0b66085d451723709..1b4e783ca1f4ac6e09ce9fc1caad30de85e3be91 100644
|
||||
--- a/src/env.cc
|
||||
+++ b/src/env.cc
|
||||
@@ -763,7 +763,8 @@ Environment::Environment(IsolateData* isolate_data,
|
||||
const std::vector<std::string>& exec_args,
|
||||
const EnvSerializeInfo* env_info,
|
||||
EnvironmentFlags::Flags flags,
|
||||
- ThreadId thread_id)
|
||||
+ ThreadId thread_id,
|
||||
+ EmbedderPreloadCallback preload)
|
||||
: isolate_(isolate),
|
||||
isolate_data_(isolate_data),
|
||||
async_hooks_(isolate, MAYBE_FIELD_PTR(env_info, async_hooks)),
|
||||
@@ -789,7 +790,8 @@ Environment::Environment(IsolateData* isolate_data,
|
||||
flags_(flags),
|
||||
thread_id_(thread_id.id == static_cast<uint64_t>(-1)
|
||||
? AllocateEnvironmentThreadId().id
|
||||
- : thread_id.id) {
|
||||
+ : thread_id.id),
|
||||
+ embedder_preload_(std::move(preload)) {
|
||||
constexpr bool is_shared_ro_heap =
|
||||
#ifdef NODE_V8_SHARED_RO_HEAP
|
||||
true;
|
||||
diff --git a/src/env.h b/src/env.h
|
||||
index 448075e354c760a2dbd1dd763f40b7a645730250..a5aad9596953536b0a1f741dfbc4f21f6a961404 100644
|
||||
index 448075e354c760a2dbd1dd763f40b7a645730250..d6956873b1b7bdf49ed0217587729aaa974ae89f 100644
|
||||
--- a/src/env.h
|
||||
+++ b/src/env.h
|
||||
@@ -635,7 +635,8 @@ class Environment : public MemoryRetainer {
|
||||
const std::vector<std::string>& exec_args,
|
||||
const EnvSerializeInfo* env_info,
|
||||
EnvironmentFlags::Flags flags,
|
||||
- ThreadId thread_id);
|
||||
+ ThreadId thread_id,
|
||||
+ EmbedderPreloadCallback preload);
|
||||
void InitializeMainContext(v8::Local<v8::Context> context,
|
||||
const EnvSerializeInfo* env_info);
|
||||
~Environment() override;
|
||||
@@ -986,6 +987,8 @@ class Environment : public MemoryRetainer {
|
||||
@@ -985,6 +985,8 @@ class Environment : public MemoryRetainer {
|
||||
|
||||
inline const StartExecutionCallback& embedder_entry_point() const;
|
||||
inline void set_embedder_entry_point(StartExecutionCallback&& fn);
|
||||
|
||||
+ inline const EmbedderPreloadCallback& embedder_preload() const;
|
||||
+
|
||||
+ inline void set_embedder_preload(EmbedderPreloadCallback fn);
|
||||
|
||||
inline void set_process_exit_handler(
|
||||
std::function<void(Environment*, ExitCode)>&& handler);
|
||||
|
||||
@@ -1186,6 +1189,7 @@ class Environment : public MemoryRetainer {
|
||||
@@ -1186,6 +1188,7 @@ class Environment : public MemoryRetainer {
|
||||
|
||||
builtins::BuiltinLoader builtin_loader_;
|
||||
StartExecutionCallback embedder_entry_point_;
|
||||
@@ -139,43 +113,45 @@ index 448075e354c760a2dbd1dd763f40b7a645730250..a5aad9596953536b0a1f741dfbc4f21f
|
||||
// Used by allocate_managed_buffer() and release_managed_buffer() to keep
|
||||
// track of the BackingStore for a given pointer.
|
||||
diff --git a/src/node.h b/src/node.h
|
||||
index 3ffc51783b0b6dee1c0f0a37d2f52cb1aec2fa3f..4d88bbedb2fc2776d32cbaa755fd8657f17f78bc 100644
|
||||
index 3ffc51783b0b6dee1c0f0a37d2f52cb1aec2fa3f..400a6b91ccb9875352012bffc21bc842f6febb9c 100644
|
||||
--- a/src/node.h
|
||||
+++ b/src/node.h
|
||||
@@ -676,11 +676,23 @@ struct InspectorParentHandle {
|
||||
virtual ~InspectorParentHandle() = default;
|
||||
};
|
||||
@@ -716,12 +716,33 @@ struct StartExecutionCallbackInfo {
|
||||
|
||||
using StartExecutionCallback =
|
||||
std::function<v8::MaybeLocal<v8::Value>(const StartExecutionCallbackInfo&)>;
|
||||
+using EmbedderPreloadCallback =
|
||||
+ std::function<void(Environment* env,
|
||||
+ v8::Local<v8::Value> process,
|
||||
+ v8::Local<v8::Value> require)>;
|
||||
+
|
||||
// TODO(addaleax): Maybe move per-Environment options parsing here.
|
||||
// Returns nullptr when the Environment cannot be created e.g. there are
|
||||
// pending JavaScript exceptions.
|
||||
// `context` may be empty if an `EmbedderSnapshotData` instance was provided
|
||||
// to `NewIsolate()` and `CreateIsolateData()`.
|
||||
+//
|
||||
+// The |preload| function will run before executing the entry point, which
|
||||
+// is usually used by embedders to inject scripts. The function is executed
|
||||
+// with preload(process, require), and the passed require function has access
|
||||
+// to internal Node.js modules. The |preload| function is inherited by worker
|
||||
+// threads and thus will run in work threads, so make sure the function is
|
||||
+// thread-safe.
|
||||
NODE_EXTERN Environment* CreateEnvironment(
|
||||
IsolateData* isolate_data,
|
||||
v8::Local<v8::Context> context,
|
||||
@@ -688,7 +700,8 @@ NODE_EXTERN Environment* CreateEnvironment(
|
||||
const std::vector<std::string>& exec_args,
|
||||
EnvironmentFlags::Flags flags = EnvironmentFlags::kDefaultFlags,
|
||||
ThreadId thread_id = {} /* allocates a thread id automatically */,
|
||||
- std::unique_ptr<InspectorParentHandle> inspector_parent_handle = {});
|
||||
+ std::unique_ptr<InspectorParentHandle> inspector_parent_handle = {},
|
||||
+ EmbedderPreloadCallback preload = nullptr);
|
||||
|
||||
// Returns a handle that can be passed to `LoadEnvironment()`, making the
|
||||
// child Environment accessible to the inspector as if it were a Node.js Worker.
|
||||
+// Run initialization for the environment.
|
||||
+//
|
||||
+// The |preload| function, usually used by embedders to inject scripts,
|
||||
+// will be run by Node.js before Node.js executes the entry point.
|
||||
+// The function is guaranteed to run before the user land module loader running
|
||||
+// any user code, so it is safe to assume that at this point, no user code has
|
||||
+// been run yet.
|
||||
+// The function will be executed with preload(process, require), and the passed
|
||||
+// require function has access to internal Node.js modules. There is no
|
||||
+// stability guarantee about the internals exposed to the internal require
|
||||
+// function. Expect breakages when updating Node.js versions if the embedder
|
||||
+// imports internal modules with the internal require function.
|
||||
+// Worker threads created in the environment will also respect The |preload|
|
||||
+// function, so make sure the function is thread-safe.
|
||||
NODE_EXTERN v8::MaybeLocal<v8::Value> LoadEnvironment(
|
||||
Environment* env,
|
||||
- StartExecutionCallback cb);
|
||||
+ StartExecutionCallback cb,
|
||||
+ EmbedderPreloadCallback preload = nullptr);
|
||||
NODE_EXTERN v8::MaybeLocal<v8::Value> LoadEnvironment(
|
||||
- Environment* env, std::string_view main_script_source_utf8);
|
||||
+ Environment* env,
|
||||
+ std::string_view main_script_source_utf8,
|
||||
+ EmbedderPreloadCallback preload = nullptr);
|
||||
NODE_EXTERN void FreeEnvironment(Environment* env);
|
||||
|
||||
// Set a callback that is called when process.exit() is called from JS,
|
||||
diff --git a/src/node_options.cc b/src/node_options.cc
|
||||
index 6eb2c137e1dd05b05e781820905cf6778107275d..b098837338c2c0d435ee8e659433f168c453dde5 100644
|
||||
--- a/src/node_options.cc
|
||||
@@ -194,24 +170,28 @@ index 6eb2c137e1dd05b05e781820905cf6778107275d..b098837338c2c0d435ee8e659433f168
|
||||
}
|
||||
|
||||
diff --git a/src/node_snapshotable.cc b/src/node_snapshotable.cc
|
||||
index 562a47ddcc9c8e61590b7b09d84dc08ab4b3653d..325bebc1df9ad2e8b0bad468951cf1563ecefc14 100644
|
||||
index 562a47ddcc9c8e61590b7b09d84dc08ab4b3653d..431cbe1c2cb77669ceb10602a7b3ef1c2f7e8718 100644
|
||||
--- a/src/node_snapshotable.cc
|
||||
+++ b/src/node_snapshotable.cc
|
||||
@@ -1369,6 +1369,13 @@ static void RunEmbedderEntryPoint(const FunctionCallbackInfo<Value>& args) {
|
||||
@@ -1369,6 +1369,17 @@ static void RunEmbedderEntryPoint(const FunctionCallbackInfo<Value>& args) {
|
||||
}
|
||||
}
|
||||
|
||||
+static void RunEmbedderPreload(const FunctionCallbackInfo<Value>& args) {
|
||||
+void RunEmbedderPreload(const FunctionCallbackInfo<Value>& args) {
|
||||
+ Environment* env = Environment::GetCurrent(args);
|
||||
+ CHECK(env->embedder_preload());
|
||||
+ CHECK_EQ(args.Length(), 2);
|
||||
+ env->embedder_preload()(env, args[0], args[1]);
|
||||
+ Local<Value> process_obj = args[0];
|
||||
+ Local<Value> require_fn = args[1];
|
||||
+ CHECK(process_obj->IsObject());
|
||||
+ CHECK(require_fn->IsFunction());
|
||||
+ env->embedder_preload()(env, process_obj, require_fn);
|
||||
+}
|
||||
+
|
||||
void CompileSerializeMain(const FunctionCallbackInfo<Value>& args) {
|
||||
CHECK(args[0]->IsString());
|
||||
Local<String> filename = args[0].As<String>();
|
||||
@@ -1493,6 +1500,7 @@ void CreatePerIsolateProperties(IsolateData* isolate_data,
|
||||
@@ -1493,6 +1504,7 @@ void CreatePerIsolateProperties(IsolateData* isolate_data,
|
||||
Local<ObjectTemplate> target) {
|
||||
Isolate* isolate = isolate_data->isolate();
|
||||
SetMethod(isolate, target, "runEmbedderEntryPoint", RunEmbedderEntryPoint);
|
||||
@@ -219,7 +199,7 @@ index 562a47ddcc9c8e61590b7b09d84dc08ab4b3653d..325bebc1df9ad2e8b0bad468951cf156
|
||||
SetMethod(isolate, target, "compileSerializeMain", CompileSerializeMain);
|
||||
SetMethod(isolate, target, "setSerializeCallback", SetSerializeCallback);
|
||||
SetMethod(isolate, target, "setDeserializeCallback", SetDeserializeCallback);
|
||||
@@ -1506,6 +1514,7 @@ void CreatePerIsolateProperties(IsolateData* isolate_data,
|
||||
@@ -1506,6 +1518,7 @@ void CreatePerIsolateProperties(IsolateData* isolate_data,
|
||||
|
||||
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
|
||||
registry->Register(RunEmbedderEntryPoint);
|
||||
@@ -228,7 +208,7 @@ index 562a47ddcc9c8e61590b7b09d84dc08ab4b3653d..325bebc1df9ad2e8b0bad468951cf156
|
||||
registry->Register(SetSerializeCallback);
|
||||
registry->Register(SetDeserializeCallback);
|
||||
diff --git a/src/node_worker.cc b/src/node_worker.cc
|
||||
index 900674bbe4c90e9aeb2013c06c9979864b06dcd5..2a22d986585e93ea00c6dcdca1f7b783ef0723f8 100644
|
||||
index 900674bbe4c90e9aeb2013c06c9979864b06dcd5..52d7473b05ccb49e5fc915224b6d2972a14191da 100644
|
||||
--- a/src/node_worker.cc
|
||||
+++ b/src/node_worker.cc
|
||||
@@ -63,6 +63,7 @@ Worker::Worker(Environment* env,
|
||||
@@ -239,16 +219,20 @@ index 900674bbe4c90e9aeb2013c06c9979864b06dcd5..2a22d986585e93ea00c6dcdca1f7b783
|
||||
snapshot_data_(snapshot_data) {
|
||||
Debug(this, "Creating new worker instance with thread id %llu",
|
||||
thread_id_.id);
|
||||
@@ -360,7 +361,8 @@ void Worker::Run() {
|
||||
std::move(exec_argv_),
|
||||
static_cast<EnvironmentFlags::Flags>(environment_flags_),
|
||||
thread_id_,
|
||||
- std::move(inspector_parent_handle_)));
|
||||
+ std::move(inspector_parent_handle_),
|
||||
+ std::move(embedder_preload_)));
|
||||
if (is_stopped()) return;
|
||||
CHECK_NOT_NULL(env_);
|
||||
env_->set_env_vars(std::move(env_vars_));
|
||||
@@ -381,8 +382,12 @@ void Worker::Run() {
|
||||
}
|
||||
|
||||
Debug(this, "Created message port for worker %llu", thread_id_.id);
|
||||
- if (LoadEnvironment(env_.get(), StartExecutionCallback{}).IsEmpty())
|
||||
+ if (LoadEnvironment(env_.get(),
|
||||
+ StartExecutionCallback{},
|
||||
+ std::move(embedder_preload_))
|
||||
+ .IsEmpty()) {
|
||||
return;
|
||||
+ }
|
||||
|
||||
Debug(this, "Loaded environment for worker %llu", thread_id_.id);
|
||||
}
|
||||
diff --git a/src/node_worker.h b/src/node_worker.h
|
||||
index 531e2b5287010f9206ab4fd7f4dd0f3dec9fe55c..07fd7b460654e169e8b6822474dc3cc70fcec4c0 100644
|
||||
--- a/src/node_worker.h
|
||||
@@ -262,7 +246,7 @@ index 531e2b5287010f9206ab4fd7f4dd0f3dec9fe55c..07fd7b460654e169e8b6822474dc3cc7
|
||||
// A raw flag that is used by creator and worker threads to
|
||||
// sync up on pre-mature termination of worker - while in the
|
||||
diff --git a/test/cctest/test_environment.cc b/test/cctest/test_environment.cc
|
||||
index 2e747c7be58922897abd0424b797f3f12a89ada1..658f8df4b01d60759e858cf5283b9be9467dd142 100644
|
||||
index 2e747c7be58922897abd0424b797f3f12a89ada1..fcffaca89cf5aa24be6e539bfb4d9d6df690a709 100644
|
||||
--- a/test/cctest/test_environment.cc
|
||||
+++ b/test/cctest/test_environment.cc
|
||||
@@ -773,3 +773,31 @@ TEST_F(EnvironmentTest, RequestInterruptAtExit) {
|
||||
@@ -280,20 +264,20 @@ index 2e747c7be58922897abd0424b797f3f12a89ada1..658f8df4b01d60759e858cf5283b9be9
|
||||
+ v8::Local<v8::Value> require) {
|
||||
+ CHECK(process->IsObject());
|
||||
+ CHECK(require->IsFunction());
|
||||
+ process.As<v8::Object>()->Set(
|
||||
+ env->context(),
|
||||
+ v8::String::NewFromUtf8Literal(env->isolate(), "prop"),
|
||||
+ v8::String::NewFromUtf8Literal(env->isolate(), "preload")).Check();
|
||||
+ process.As<v8::Object>()
|
||||
+ ->Set(env->context(),
|
||||
+ v8::String::NewFromUtf8Literal(env->isolate(), "prop"),
|
||||
+ v8::String::NewFromUtf8Literal(env->isolate(), "preload"))
|
||||
+ .Check();
|
||||
+ };
|
||||
+
|
||||
+ std::unique_ptr<node::Environment, decltype(&node::FreeEnvironment)> env(
|
||||
+ node::CreateEnvironment(isolate_data_, context, {}, {},
|
||||
+ node::EnvironmentFlags::kDefaultFlags, {}, {},
|
||||
+ preload),
|
||||
+ node::CreateEnvironment(isolate_data_, context, {}, {}),
|
||||
+ node::FreeEnvironment);
|
||||
+
|
||||
+ v8::Local<v8::Value> main_ret =
|
||||
+ node::LoadEnvironment(env.get(), "return process.prop;").ToLocalChecked();
|
||||
+ node::LoadEnvironment(env.get(), "return process.prop;", preload)
|
||||
+ .ToLocalChecked();
|
||||
+ node::Utf8Value main_ret_str(isolate_, main_ret);
|
||||
+ EXPECT_EQ(std::string(*main_ret_str), "preload");
|
||||
+}
|
||||
|
||||
@@ -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';
|
||||
}
|
||||
@@ -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
|
||||
|
||||
41
patches/v8/cherry-pick-3e037e195e50.patch
Normal file
41
patches/v8/cherry-pick-3e037e195e50.patch
Normal 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
|
||||
56
patches/v8/cherry-pick-6503a987d966.patch
Normal file
56
patches/v8/cherry-pick-6503a987d966.patch
Normal 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();
|
||||
98
patches/v8/cherry-pick-8b400f9b7d66.patch
Normal file
98
patches/v8/cherry-pick-8b400f9b7d66.patch
Normal 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>>
|
||||
76
patches/v8/cherry-pick-b3c01ac1e60a.patch
Normal file
76
patches/v8/cherry-pick-b3c01ac1e60a.patch
Normal file
@@ -0,0 +1,76 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shu-yu Guo <syg@chromium.org>
|
||||
Date: Mon, 13 May 2024 11:23:20 -0700
|
||||
Subject: Don't build AccessInfo for storing to module exports
|
||||
|
||||
Bug: 340221135
|
||||
Change-Id: I5af35be6ebf6a69db1c4687107503575b23973c4
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5534518
|
||||
Reviewed-by: Adam Klein <adamk@chromium.org>
|
||||
Commit-Queue: Shu-yu Guo <syg@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#93872}
|
||||
|
||||
diff --git a/src/compiler/access-info.cc b/src/compiler/access-info.cc
|
||||
index 7cff878839c85cd9c6571ee48f1a0fce081f4471..9d022ba402d7bfdd5ca745a4193ee0de0e3d755e 100644
|
||||
--- a/src/compiler/access-info.cc
|
||||
+++ b/src/compiler/access-info.cc
|
||||
@@ -526,6 +526,14 @@ PropertyAccessInfo AccessorAccessInfoHelper(
|
||||
Cell::cast(module_namespace->module()->exports()->Lookup(
|
||||
isolate, name.object(),
|
||||
Smi::ToInt(Object::GetHash(*name.object())))));
|
||||
+ if (IsAnyStore(access_mode)) {
|
||||
+ // ES#sec-module-namespace-exotic-objects-set-p-v-receiver
|
||||
+ // ES#sec-module-namespace-exotic-objects-defineownproperty-p-desc
|
||||
+ //
|
||||
+ // Storing to a module namespace object is always an error or a no-op in
|
||||
+ // JS.
|
||||
+ return PropertyAccessInfo::Invalid(zone);
|
||||
+ }
|
||||
if (IsTheHole(cell->value(kRelaxedLoad), isolate)) {
|
||||
// This module has not been fully initialized yet.
|
||||
return PropertyAccessInfo::Invalid(zone);
|
||||
diff --git a/src/maglev/maglev-graph-builder.cc b/src/maglev/maglev-graph-builder.cc
|
||||
index 8a5b4483d148192d3106e75874f042ccc6b36e56..728105c0aaccbaeb018eb9b9a660b5acba4650d8 100644
|
||||
--- a/src/maglev/maglev-graph-builder.cc
|
||||
+++ b/src/maglev/maglev-graph-builder.cc
|
||||
@@ -3914,19 +3914,28 @@ ReduceResult MaglevGraphBuilder::TryBuildPropertyStore(
|
||||
access_info.holder().value());
|
||||
}
|
||||
|
||||
- if (access_info.IsFastAccessorConstant()) {
|
||||
- return TryBuildPropertySetterCall(access_info, receiver,
|
||||
- GetAccumulatorTagged());
|
||||
- } else {
|
||||
- DCHECK(access_info.IsDataField() || access_info.IsFastDataConstant());
|
||||
- ReduceResult res = TryBuildStoreField(access_info, receiver, access_mode);
|
||||
- if (res.IsDone()) {
|
||||
- RecordKnownProperty(receiver, name,
|
||||
- current_interpreter_frame_.accumulator(),
|
||||
- AccessInfoGuaranteedConst(access_info), access_mode);
|
||||
- return res;
|
||||
+ switch (access_info.kind()) {
|
||||
+ case compiler::PropertyAccessInfo::kFastAccessorConstant:
|
||||
+ return TryBuildPropertySetterCall(access_info, receiver,
|
||||
+ GetAccumulatorTagged());
|
||||
+ case compiler::PropertyAccessInfo::kDataField:
|
||||
+ case compiler::PropertyAccessInfo::kFastDataConstant: {
|
||||
+ ReduceResult res = TryBuildStoreField(access_info, receiver, access_mode);
|
||||
+ if (res.IsDone()) {
|
||||
+ RecordKnownProperty(
|
||||
+ receiver, name, current_interpreter_frame_.accumulator(),
|
||||
+ AccessInfoGuaranteedConst(access_info), access_mode);
|
||||
+ return res;
|
||||
+ }
|
||||
+ return ReduceResult::Fail();
|
||||
}
|
||||
- return ReduceResult::Fail();
|
||||
+ case compiler::PropertyAccessInfo::kInvalid:
|
||||
+ case compiler::PropertyAccessInfo::kNotFound:
|
||||
+ case compiler::PropertyAccessInfo::kDictionaryProtoDataConstant:
|
||||
+ case compiler::PropertyAccessInfo::kDictionaryProtoAccessorConstant:
|
||||
+ case compiler::PropertyAccessInfo::kModuleExport:
|
||||
+ case compiler::PropertyAccessInfo::kStringLength:
|
||||
+ UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user