Compare commits

..

33 Commits

Author SHA1 Message Date
Pedro Pontes
763729c9ef chore: cherry-pick 4 changes from Release-2-M121 and Release-3-M121 (#41376)
* chore: cherry-pick 4 changes from Release-2-M121 and Release-3-M121

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2024-02-21 09:43:40 +01:00
trop[bot]
bc7b2a3589 build: peg to a specific depot_tools so that we can use goma on older branches (#41342)
chore: peg to a specific depot_tools so that we can use goma on older branches

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2024-02-14 13:53:19 -08:00
Shelley Vohr
13908747ab chore: cherry-pick 3 changes from Release-1-M121 (#41177)
* chore: [26-x-y] cherry-pick 4 changes from Release-1-M121

* ee0b8769f428 from chromium
* 1f8bec968902 from chromium
* 4a98f9e304be from chromium

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2024-02-02 12:33:14 +01:00
Pedro Pontes
0ebe40354e chore: cherry-pick 2 changes from Release-0-M121 (#41107)
* chore: [26-x-y] cherry-pick 2 changes from Release-0-M121

* cc07a95bc309 from chromium

* test: fixup assertNotWindows (#41045)

* chore: fixup assertNotWindows

* remove logging

(cherry picked from commit 3dafb318a8)

* chore: cleanup global reject handler leaking into tests (#40689)

(cherry picked from commit 3a510a26d0)

---------

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
Co-authored-by: Robo <hop2deep@gmail.com>
2024-01-29 14:56:59 -05:00
trop[bot]
e16d9f99e6 fix: only remove hijackable envs from foreign parent (#41099)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2024-01-26 09:46:25 +09:00
trop[bot]
682b27f606 docs: update Playwright automated-testing guide (#41095)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Max Schmitt <max@schmitt.mx>
2024-01-25 15:44:29 +09:00
John Kleinschmidt
0b94b5b86f chore: cleanup tests creating crashpad handler in the test runner process (#41049)
chore: cleanup tests creating crashpad handler in the test runner process (#40668)

* chore: cleanup tests creating crashpad handler in the test runner process

* ci: logging

* ci: enable logging

* ci: more logging

* ci: run all tests

* ci: more logging

* ci: increase timeout

* Revert "ci: increase timeout"

This reverts commit 870f74455d.

* Revert "ci: more logging"

This reverts commit 46837f8b3a.

* Revert "ci: run all tests"

This reverts commit 6a7889ce67.

* Revert "ci: more logging"

This reverts commit 351473ab43.

* Revert "ci: enable logging"

This reverts commit 194109ed5a.

* Revert "ci: logging"

This reverts commit 9a3396fc7a.

* chore: disable flaky ia32 tests

(cherry picked from commit 83f15bd957)

Co-authored-by: Robo <hop2deep@gmail.com>
2024-01-18 20:33:02 -05:00
Samuel Attard
0c3113a4c5 chore: cherry-pick 389ea9be7d68 from v8 (#40972)
* chore: cherry-pick 389ea9be7d68 from v8

* chore: update patches

---------

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2024-01-18 11:28:39 -08:00
Keeley Hammond
5917fe9143 chore: cherry-pick 3 changes from Release-5-M120 (#41015)
* chore: [26-x-y] cherry-pick 3 changes from Release-5-M120

* 46cb67e3b296 from v8
* c1cda70a433a from chromium
* 78dd4b31847a from v8

* chore: update patches
2024-01-17 10:57:16 -05:00
trop[bot]
8638667c66 build: fix mojom_ts_generator empty module path failure (#41012)
* build: fix mojom_ts_generator empty module path failure

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

* chore: update .patches after trop

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2024-01-16 19:42:33 -05:00
trop[bot]
2c7c8b2d44 build: use container runner for arm tests (#40931)
* build: use aks arm64 test runners

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

* build: better image

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

* build: even more stuff

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

* build: arm par

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

* build: use aks arm32

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

* build: arm32 par

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

* build: get test timings from abs paths

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

* build: avoid realpath, use echo

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

* chore: fix contentTracing test

* cry

* build: use arm test runner with git

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Samuel Attard <samuel.r.attard@gmail.com>
Co-authored-by: Samuel Attard <marshallofsound@electronjs.org>
2024-01-11 01:22:10 +13:00
trop[bot]
9c7f63cc9c fix: crash using powerMonitor before ready event (#40922)
* fix: crash using powerMonitor before ready event

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

* refactor: continue using DBusBluezManagerWrapperLinux

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

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2024-01-09 20:55:59 +01:00
Pedro Pontes
6cdb2fb3af chore: cherry-pick 8 changes from Release-3-M120 (#40901)
* chore: [26-x-y] cherry-pick 5 changes from Release-3-M120

* 5b2fddadaa12 from chromium
* cd9486849ba3 from sqlite
* 50a1bddfca85 from chromium
* 0c1d249c3fe2 from angle
* 01f439363dcb from angle

* chore: [26-x-y] remove unused and unnecessary patches.

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2024-01-08 15:58:45 -05:00
Cheng Zhao
0d99c8a222 fix: ignore all NODE_ envs from foreign parent in node process (#40882) 2024-01-05 18:58:52 +09:00
Pedro Pontes
783f23bfdb chore: cherry-pick 6 changes from Release-1-M120 (#40803)
* chore: [26-x-y] cherry-pick 6 changes from Release-1-M120

* 58bc7b8bb840 from libavif
* 021598ea43c1 from chromium
* 76340163a820 from chromium
* f15cfb9371c4 from chromium
* 4ca62c7a8b88 from chromium
* cbd09b2ca928 from v8

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2023-12-21 15:55:01 -08:00
Pedro Pontes
9ba6477dcb chore: cherry-pick 1 changes from Release-2-M120 (#40808)
* chore: [26-x-y] cherry-pick 1 changes from Release-2-M120

* 8d607d3921b8 from chromium

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2023-12-21 09:26:32 -08:00
trop[bot]
24c06a45ef fix: ShowItemUsingFileManager should escape path in Linux (#40560)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: hsfzxjy <hsfzxjy@gmail.com>
2023-12-13 12:41:02 -06:00
Cheng Zhao
8e074bc1d0 fix: prevent node mode to be used as script runner by other apps (#40738) 2023-12-13 17:28:47 +09:00
Pascal Ernster
eb2173846b fix: Update node's simdutf to 3.2.9 to fix AVX-related crashes (#40446)
Fix: Backport AVX detection fix from simdutf 3.2.9

simdutf < 3.2.9 contains a flawed detection routine to decide whether
AVX and/or AVX2 can be used. In most cases, it works good enough, but
in some corner cases (combination of specific CPU model, microcode
version, operating system and OS configuration), that flawed detection
results in simdutf trying to use AVX/AVX2 although the OS doesn't allow
its use (for example as a mitigation measure against the "gather data
sampling" vulnerability), which then crashes the application with an
illegal instruction error.

This fix is only needed for node < 18.17.0, because later versions use
a simdutf version > 3.2.9.

Cherry-picked and backported from 55b107f609

Signed-off-by: Pascal Ernster <git@hardfalcon.net>
Co-authored-by: Daniel Lemire <daniel@lemire.me>
Co-authored-by: easyaspi314 <easyaspi314@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-12-08 15:34:40 -05:00
Pedro Pontes
1813586545 chore: cherry-pick 1 changes from Release-0-M120 (#40725)
* chore: [26-x-y] cherry-pick 1 changes from Release-0-M120

* 5fde415e06f9 from chromium

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2023-12-07 19:14:28 -08:00
trop[bot]
d47906c855 build: fix release notes script bug that omitted edited release-clerk comments (#40654)
* build: fix release notes script bug that omitted edited release-clerk comments

add a warning when neither notes nor no-notes are found

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

* fixup! build: fix release notes script bug that omitted edited release-clerk comments

use console.warn() instead of console.log()

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

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
2023-12-04 12:51:53 +01:00
Keeley Hammond
aa688f9a45 chore: cherry-pick 6 changes from Release-3-M119 (#40644)
chore: [26-x-y] cherry-pick 6 changes from Release-3-M119

* 971d6055e7b7 from openscreen
* 3f45b1af5e41 from chromium
* e13061c50998 from chromium
* 6169a1fabae1 from skia
* 6cc0d9aa5b3fb from libavif
* 922fca786b61a from libavif
2023-11-30 15:07:51 +01:00
trop[bot]
4cfc4bf074 fix: add missing set_wants_to_be_visible(true) to NativeWindowMac::ShowInactive() (#40657)
* fix: add missing set_wants_to_be_visible(true) to NativeWindowMac::ShowInactive()

Co-authored-by: zaza <tamas@miro.com>

* add test

Co-authored-by: Tamás Zahola <tzahola@gmail.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: zaza <tamas@miro.com>
Co-authored-by: Tamás Zahola <tzahola@gmail.com>
2023-11-30 15:06:58 +01:00
trop[bot]
a0af9e0e3c fix: add patch for simdutf base64 crash (#40540)
* fix: add patch for simdutf base64 crash

Co-authored-by: Samuel Attard <marshallofsound@electronjs.org>

* chore: update .patches file after trop

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Samuel Attard <marshallofsound@electronjs.org>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2023-11-27 22:16:41 -05:00
trop[bot]
f2ce1ce1b4 fix: do not call after() async_hook for asyncId 0 (#40592)
fix: do not call after() async_hook for asyncId 0

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-11-23 11:15:28 +01:00
trop[bot]
af61c40ee0 fix: restore performance of macOS window resizing (#40584)
* fix: restore performance of macOS window resizing

Co-authored-by: Samuel Attard <marshallofsound@electronjs.org>

* Update .patches

* chore: update patches

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Samuel Attard <marshallofsound@electronjs.org>
Co-authored-by: Samuel Attard <sam@electronjs.org>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2023-11-22 16:26:59 +01:00
trop[bot]
917664c68b fix: maximized window bounds when toggle setResizable (#40580)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Tomasz Malinowski <tomasz@openfin.co>
2023-11-22 10:59:52 +01:00
Pedro Pontes
ead3de1ac5 chore: cherry-pick 1 changes from Release-2-M119 (#40537)
* chore: [26-x-y] cherry-pick 1 changes from Release-2-M119

* 9384cddc7705 from chromium

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2023-11-20 09:00:20 +09:00
Shelley Vohr
44bf2a7a6a fix: scale rects properly in SyncGetFirstRectForRange (#40535)
fix: scale rects properly in SyncGetFirstRectForRange

Refs https://chromium-review.googlesource.com/c/chromium/src/+/4894366
2023-11-15 15:30:19 -05:00
Pedro Pontes
0337b2c9f5 chore: cherry-pick 1 changes from Release-1-M119 (#40518)
* chore: [26-x-y] cherry-pick 1 changes from Release-1-M119

* 3df423a5b8de from chromium

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2023-11-14 15:24:05 -05:00
trop[bot]
fe0a54f729 fix: chrome.action API registration (#40512)
* fix: chrome.action API registration

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

* fix: browser_action implemented_in

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

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-11-13 12:57:04 +01:00
trop[bot]
6799879694 feat: keyboard.lock() should use permissions helper (#40458)
feat: keyboard.lock should use permissions helper

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-11-09 10:41:39 -08:00
trop[bot]
696087f29c docs: fix hid-device-{added|removed|revoked} event types (#40476)
docs: fix hid-device-{added|removed|revoked} types

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-11-08 12:36:29 -08:00
100 changed files with 5493 additions and 816 deletions

View File

@@ -80,12 +80,14 @@ executors:
machine: true
linux-arm:
resource_class: electronjs/linux-arm
machine: true
resource_class: electronjs/aks-linux-arm-test
docker:
- image: ghcr.io/electron/test:arm32v7-b0dee37de023a8d8a15bb8916325b54a4aebfb0c
linux-arm64:
resource_class: electronjs/linux-arm64
machine: true
resource_class: electronjs/aks-linux-arm-test
docker:
- image: ghcr.io/electron/test:arm64v8-b0dee37de023a8d8a15bb8916325b54a4aebfb0c
# The config expects the following environment variables to be set:
# - "SLACK_WEBHOOK" Slack hook URL to send notifications.
@@ -255,6 +257,10 @@ step-depot-tools-get: &step-depot-tools-get
name: Get depot tools
command: |
git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
cd depot_tools
git fetch --depth 1 origin f76550541c751f956ef9287f2695a6c8a74bf709
git checkout f76550541c751f956ef9287f2695a6c8a74bf709
cd ..
if [ "`uname`" == "Darwin" ]; then
# remove ninjalog_uploader_wrapper.py from autoninja since we don't use it and it causes problems
sed -i '' '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
@@ -1663,17 +1669,15 @@ commands:
export LLVM_SYMBOLIZER_PATH=$PWD/third_party/llvm-build/Release+Asserts/bin/llvm-symbolizer
export MOCHA_TIMEOUT=180000
echo "Piping output to ASAN_SYMBOLIZE ($ASAN_SYMBOLIZE)"
(cd electron && (circleci tests glob "spec/*-spec.ts" | circleci tests run --command="xargs node script/yarn test --runners=main --trace-uncaught --enable-logging --files" --split-by=timings 2>&1)) | $ASAN_SYMBOLIZE
(cd electron && (circleci tests glob "spec/*-spec.ts" | xargs -I@ -P4 bash -c "echo $(pwd)/@" | circleci tests run --command="xargs node script/yarn test --runners=main --trace-uncaught --enable-logging --files" --split-by=timings 2>&1)) | $ASAN_SYMBOLIZE
else
if [ "$TARGET_ARCH" == "arm" ] || [ "$TARGET_ARCH" == "arm64" ]; then
export ELECTRON_SKIP_NATIVE_MODULE_TESTS=true
(cd electron && node script/yarn test --runners=main --trace-uncaught --enable-logging)
else
if [ "$TARGET_ARCH" == "ia32" ]; then
npm_config_arch=x64 node electron/node_modules/dugite/script/download-git.js
fi
(cd electron && (circleci tests glob "spec/*-spec.ts" | circleci tests run --command="xargs node script/yarn test --runners=main --trace-uncaught --enable-logging --files" --split-by=timings))
fi
if [ "$TARGET_ARCH" == "ia32" ]; then
npm_config_arch=x64 node electron/node_modules/dugite/script/download-git.js
fi
(cd electron && (circleci tests glob "spec/*-spec.ts" | xargs -I@ -P4 bash -c "echo $(pwd)/@" | circleci tests run --command="xargs node script/yarn test --runners=main --trace-uncaught --enable-logging --files" --split-by=timings))
fi
- store_test_results:
path: src/junit
@@ -2302,6 +2306,7 @@ jobs:
<<: *env-global
<<: *env-headless-testing
<<: *env-stack-dumping
parallelism: 3
steps:
- electron-tests:
artifact-key: linux-arm
@@ -2313,6 +2318,7 @@ jobs:
<<: *env-global
<<: *env-headless-testing
<<: *env-stack-dumping
parallelism: 3
steps:
- electron-tests:
artifact-key: linux-arm64

View File

@@ -92,6 +92,11 @@ for:
Remove-Item -Recurse -Force $pwd\build-tools
}
- git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
- ps: |
cd depot_tools
git fetch --depth 1 origin f76550541c751f956ef9287f2695a6c8a74bf709
git checkout f76550541c751f956ef9287f2695a6c8a74bf709
cd ..
- ps: New-Item -Name depot_tools\.disable_auto_update -ItemType File
- depot_tools\bootstrap\win_tools.bat
- ps: $env:PATH="$pwd\depot_tools;$env:PATH"

View File

@@ -90,6 +90,11 @@ for:
Remove-Item -Recurse -Force $pwd\build-tools
}
- git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
- ps: |
cd depot_tools
git fetch --depth 1 origin f76550541c751f956ef9287f2695a6c8a74bf709
git checkout f76550541c751f956ef9287f2695a6c8a74bf709
cd ..
- ps: New-Item -Name depot_tools\.disable_auto_update -ItemType File
- depot_tools\bootstrap\win_tools.bat
- ps: $env:PATH="$pwd\depot_tools;$env:PATH"

View File

@@ -266,7 +266,7 @@ Returns:
* `event` Event
* `details` Object
* `device` [HIDDevice[]](structures/hid-device.md)
* `device` [HIDDevice](structures/hid-device.md)
* `frame` [WebFrameMain](web-frame-main.md)
Emitted after `navigator.hid.requestDevice` has been called and
@@ -281,7 +281,7 @@ Returns:
* `event` Event
* `details` Object
* `device` [HIDDevice[]](structures/hid-device.md)
* `device` [HIDDevice](structures/hid-device.md)
* `frame` [WebFrameMain](web-frame-main.md)
Emitted after `navigator.hid.requestDevice` has been called and
@@ -296,7 +296,7 @@ Returns:
* `event` Event
* `details` Object
* `device` [HIDDevice[]](structures/hid-device.md)
* `device` [HIDDevice](structures/hid-device.md)
* `origin` string (optional) - The origin that the device has been revoked from.
Emitted after `HIDDevice.forget()` has been called. This event can be used
@@ -901,6 +901,7 @@ win.webContents.session.setCertificateVerifyProc((request, callback) => {
* `midiSysex` - Request the use of system exclusive messages in the [Web MIDI API](https://developer.mozilla.org/en-US/docs/Web/API/Web_MIDI_API).
* `notifications` - Request notification creation and the ability to display them in the user's system tray using the [Notifications API](https://developer.mozilla.org/en-US/docs/Web/API/notification)
* `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.
* `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.

View File

@@ -123,32 +123,19 @@ support via Electron's support for the [Chrome DevTools Protocol][] (CDP).
### Install dependencies
You can install Playwright through your preferred Node.js package manager. The Playwright team
recommends using the `PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD` environment variable to avoid
unnecessary browser downloads when testing an Electron app.
```sh npm2yarn
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm install --save-dev playwright
```
Playwright also comes with its own test runner, Playwright Test, which is built for end-to-end
testing. You can also install it as a dev dependency in your project:
You can install Playwright through your preferred Node.js package manager. It comes with its
own [test runner][playwright-intro], which is built for end-to-end testing:
```sh npm2yarn
npm install --save-dev @playwright/test
```
:::caution Dependencies
This tutorial was written `playwright@1.16.3` and `@playwright/test@1.16.3`. Check out
This tutorial was written with `@playwright/test@1.41.1`. Check out
[Playwright's releases][playwright-releases] page to learn about
changes that might affect the code below.
:::
:::info Using third-party test runners
If you're interested in using an alternative test runner (e.g. Jest or Mocha), check out
Playwright's [Third-Party Test Runner][playwright-test-runners] guide.
:::
### Write your tests
Playwright launches your app in development mode through the `_electron.launch` API.
@@ -156,8 +143,7 @@ To point this API to your Electron app, you can pass the path to your main proce
entry point (here, it is `main.js`).
```js {5} @ts-nocheck
const { _electron: electron } = require('playwright')
const { test } = require('@playwright/test')
const { test, _electron: electron } = require('@playwright/test')
test('launch app', async () => {
const electronApp = await electron.launch({ args: ['main.js'] })
@@ -169,9 +155,8 @@ test('launch app', async () => {
After that, you will access to an instance of Playwright's `ElectronApp` class. This
is a powerful class that has access to main process modules for example:
```js {6-11} @ts-nocheck
const { _electron: electron } = require('playwright')
const { test } = require('@playwright/test')
```js {5-10} @ts-nocheck
const { test, _electron: electron } = require('@playwright/test')
test('get isPackaged', async () => {
const electronApp = await electron.launch({ args: ['main.js'] })
@@ -190,8 +175,7 @@ It can also create individual [Page][playwright-page] objects from Electron Brow
For example, to grab the first BrowserWindow and save a screenshot:
```js {6-7} @ts-nocheck
const { _electron: electron } = require('playwright')
const { test } = require('@playwright/test')
const { test, _electron: electron } = require('@playwright/test')
test('save screenshot', async () => {
const electronApp = await electron.launch({ args: ['main.js'] })
@@ -202,12 +186,11 @@ test('save screenshot', async () => {
})
```
Putting all this together using the PlayWright Test runner, let's create a `example.spec.js`
Putting all this together using the Playwright test-runner, let's create a `example.spec.js`
test file with a single test and assertion:
```js title='example.spec.js' @ts-nocheck
const { _electron: electron } = require('playwright')
const { test, expect } = require('@playwright/test')
const { test, expect, _electron: electron } = require('@playwright/test')
test('example test', async () => {
const electronApp = await electron.launch({ args: ['.'] })
@@ -243,6 +226,7 @@ Running 1 test using 1 worker
:::info
Playwright Test will automatically run any files matching the `.*(test|spec)\.(js|ts|mjs)` regex.
You can customize this match in the [Playwright Test configuration options][playwright-test-config].
It also works with TypeScript out of the box.
:::
:::tip Further reading
@@ -400,10 +384,10 @@ test.after.always('cleanup', async t => {
[chrome-driver]: https://sites.google.com/chromium.org/driver/
[Puppeteer]: https://github.com/puppeteer/puppeteer
[playwright-intro]: https://playwright.dev/docs/intro
[playwright-electron]: https://playwright.dev/docs/api/class-electron/
[playwright-electronapplication]: https://playwright.dev/docs/api/class-electronapplication
[playwright-page]: https://playwright.dev/docs/api/class-page
[playwright-releases]: https://github.com/microsoft/playwright/releases
[playwright-releases]: https://playwright.dev/docs/release-notes
[playwright-test-config]: https://playwright.dev/docs/api/class-testconfig#test-config-test-match
[playwright-test-runners]: https://playwright.dev/docs/test-runners/
[Chrome DevTools Protocol]: https://chromedevtools.github.io/devtools-protocol/

View File

@@ -193,6 +193,8 @@ filenames = {
"shell/common/language_util_mac.mm",
"shell/common/mac/main_application_bundle.h",
"shell/common/mac/main_application_bundle.mm",
"shell/common/mac/codesign_util.cc",
"shell/common/mac/codesign_util.h",
"shell/common/node_bindings_mac.cc",
"shell/common/node_bindings_mac.h",
"shell/common/platform_util_mac.mm",

View File

@@ -1,3 +1,4 @@
cherry-pick-285c7712c506.patch
cherry-pick-2bf945775fe6.patch
cherry-pick-cafe56b591ed.patch
m120_translator_optimize_field-name-collision_check.patch
m120_translator_fail_compilation_if_too_many_struct_fields.patch
m120_translator_limit_private_variable_size_to_64kb.patch
m120_vulkan_don_t_crash_when_glcopyteximage2d_redefines_itself.patch

View File

@@ -1,153 +0,0 @@
From 285c7712c50654e3d7238b059c4631bc91285514 Mon Sep 17 00:00:00 2001
From: Shahbaz Youssefi <syoussefi@chromium.org>
Date: Thu, 13 Jul 2023 15:23:49 -0400
Subject: [PATCH] M116: Translator: Unconditionally limit variable sizes
... instead of just for WebGL. This is to avoid hitting driver bugs
that were prevented with this check for WebGL on a compromised renderer
that can create non-WebGL contexts.
Bug: chromium:1464682
Change-Id: I2b1c5a8c51f06225f5f850109d30778d97e574c7
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4717371
Reviewed-by: Roman Lavrov <romanl@google.com>
---
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
index 7b1ac4e..383feeb 100644
--- a/src/compiler/translator/Compiler.cpp
+++ b/src/compiler/translator/Compiler.cpp
@@ -397,9 +397,10 @@
bool TCompiler::shouldLimitTypeSizes() const
{
- // WebGL shaders limit the size of variables' types in shaders,
- // including arrays, structs and interface blocks.
- return IsWebGLBasedSpec(mShaderSpec);
+ // Prevent unrealistically large variable sizes in shaders. This works around driver bugs
+ // around int-size limits (such as 2GB). The limits are generously large enough that no real
+ // shader should ever hit it.
+ return true;
}
bool TCompiler::Init(const ShBuiltInResources &resources)
diff --git a/src/compiler/translator/ValidateTypeSizeLimitations.cpp b/src/compiler/translator/ValidateTypeSizeLimitations.cpp
index 2a033ad..19a4821 100644
--- a/src/compiler/translator/ValidateTypeSizeLimitations.cpp
+++ b/src/compiler/translator/ValidateTypeSizeLimitations.cpp
@@ -23,10 +23,10 @@
// Arbitrarily enforce that all types declared with a size in bytes of over 2 GB will cause
// compilation failure.
//
-// For local and global variables, the limit is much lower (1MB) as that much memory won't fit in
+// For local and global variables, the limit is much lower (16MB) as that much memory won't fit in
// the GPU registers anyway.
constexpr size_t kMaxVariableSizeInBytes = static_cast<size_t>(2) * 1024 * 1024 * 1024;
-constexpr size_t kMaxPrivateVariableSizeInBytes = static_cast<size_t>(1) * 1024 * 1024;
+constexpr size_t kMaxPrivateVariableSizeInBytes = static_cast<size_t>(16) * 1024 * 1024;
// Traverses intermediate tree to ensure that the shader does not
// exceed certain implementation-defined limits on the sizes of types.
diff --git a/src/compiler/translator/util.cpp b/src/compiler/translator/util.cpp
index a91f8b0..a866b25 100644
--- a/src/compiler/translator/util.cpp
+++ b/src/compiler/translator/util.cpp
@@ -282,6 +282,9 @@
return kBoolGLType[type.getNominalSize() - 1];
+ case EbtYuvCscStandardEXT:
+ return GL_UNSIGNED_INT;
+
case EbtSampler2D:
return GL_SAMPLER_2D;
case EbtSampler3D:
diff --git a/src/tests/gl_tests/WebGLCompatibilityTest.cpp b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
index 9ae56f5..a8d2ce4 100644
--- a/src/tests/gl_tests/WebGLCompatibilityTest.cpp
+++ b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
@@ -5284,8 +5284,8 @@
constexpr char kVSArrayTooLarge[] =
R"(varying vec4 color;
-// 1 MB / 32 aligned bytes per mat2 = 32768
-const int array_size = 32769;
+// 16 MB / 32 aligned bytes per mat2 = 524288
+const int array_size = 524289;
void main()
{
mat2 array[array_size];
@@ -5297,7 +5297,7 @@
constexpr char kVSArrayMuchTooLarge[] =
R"(varying vec4 color;
-const int array_size = 55600;
+const int array_size = 757000;
void main()
{
mat2 array[array_size];
@@ -5361,9 +5361,9 @@
constexpr char kTooLargeGlobalMemory1[] =
R"(precision mediump float;
-// 1 MB / 16 bytes per vec4 = 65536
-vec4 array[32768];
-vec4 array2[32769];
+// 16 MB / 16 bytes per vec4 = 1048576
+vec4 array[524288];
+vec4 array2[524289];
void main()
{
@@ -5376,9 +5376,9 @@
constexpr char kTooLargeGlobalMemory2[] =
R"(precision mediump float;
-// 1 MB / 16 bytes per vec4 = 65536
-vec4 array[32767];
-vec4 array2[32767];
+// 16 MB / 16 bytes per vec4 = 1048576
+vec4 array[524287];
+vec4 array2[524287];
vec4 x, y, z;
void main()
@@ -5392,12 +5392,12 @@
constexpr char kTooLargeGlobalAndLocalMemory1[] =
R"(precision mediump float;
-// 1 MB / 16 bytes per vec4 = 65536
-vec4 array[32768];
+// 16 MB / 16 bytes per vec4 = 1048576
+vec4 array[524288];
void main()
{
- vec4 array2[32769];
+ vec4 array2[524289];
if (array[0].x + array[1].x == 2.0)
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
else
@@ -5408,18 +5408,18 @@
constexpr char kTooLargeGlobalAndLocalMemory2[] =
R"(precision mediump float;
-// 1 MB / 16 bytes per vec4 = 65536
-vec4 array[32768];
+// 16 MB / 16 bytes per vec4 = 1048576
+vec4 array[524288];
float f()
{
- vec4 array2[16384];
+ vec4 array2[524288];
return array2[0].x;
}
float g()
{
- vec4 array3[16383];
+ vec4 array3[524287];
return array3[0].x;
}

View File

@@ -1,197 +0,0 @@
From 2bf945775fe634eb9e420c2263dae6043bbb5ece Mon Sep 17 00:00:00 2001
From: Shahbaz Youssefi <syoussefi@chromium.org>
Date: Fri, 14 Jul 2023 12:30:15 -0400
Subject: [PATCH] M116: Translator: Limit variable sizes vs uint overflow
Bug: chromium:1464680
Change-Id: Iee41a2da7a7a330e6cc4d6da59a6e9836ee9dd36
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4717372
Reviewed-by: Roman Lavrov <romanl@google.com>
---
diff --git a/src/compiler/translator/ValidateTypeSizeLimitations.cpp b/src/compiler/translator/ValidateTypeSizeLimitations.cpp
index 19a4821..f0ff9cb 100644
--- a/src/compiler/translator/ValidateTypeSizeLimitations.cpp
+++ b/src/compiler/translator/ValidateTypeSizeLimitations.cpp
@@ -7,6 +7,7 @@
#include "compiler/translator/ValidateTypeSizeLimitations.h"
#include "angle_gl.h"
+#include "common/mathutil.h"
#include "compiler/translator/Diagnostics.h"
#include "compiler/translator/Symbol.h"
#include "compiler/translator/SymbolTable.h"
@@ -113,7 +114,8 @@
void validateTotalPrivateVariableSize()
{
- if (mTotalPrivateVariablesSize > kMaxPrivateVariableSizeInBytes)
+ if (mTotalPrivateVariablesSize.ValueOrDefault(std::numeric_limits<size_t>::max()) >
+ kMaxPrivateVariableSizeInBytes)
{
mDiagnostics->error(
TSourceLoc{},
@@ -231,7 +233,7 @@
TDiagnostics *mDiagnostics;
std::vector<int> mLoopSymbolIds;
- size_t mTotalPrivateVariablesSize;
+ angle::base::CheckedNumeric<size_t> mTotalPrivateVariablesSize;
};
} // namespace
diff --git a/src/tests/gl_tests/WebGLCompatibilityTest.cpp b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
index a8d2ce4..542d49f 100644
--- a/src/tests/gl_tests/WebGLCompatibilityTest.cpp
+++ b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
@@ -5426,7 +5426,7 @@
float h()
{
vec4 value;
- float value2
+ float value2;
return value.x + value2;
}
@@ -5438,6 +5438,131 @@
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
})";
+ constexpr char kTooLargeGlobalMemoryOverflow[] =
+ R"(precision mediump float;
+
+// 16 MB / 16 bytes per vec4 = 1048576
+// Create 256 arrays so each is small, but the total overflows a 32-bit number
+vec4 array[1048576], array2[1048576], array3[1048576], array4[1048576], array5[1048576];
+vec4 array6[1048576], array7[1048576], array8[1048576], array9[1048576], array10[1048576];
+vec4 array11[1048576], array12[1048576], array13[1048576], array14[1048576], array15[1048576];
+vec4 array16[1048576], array17[1048576], array18[1048576], array19[1048576], array20[1048576];
+vec4 array21[1048576], array22[1048576], array23[1048576], array24[1048576], array25[1048576];
+vec4 array26[1048576], array27[1048576], array28[1048576], array29[1048576], array30[1048576];
+vec4 array31[1048576], array32[1048576], array33[1048576], array34[1048576], array35[1048576];
+vec4 array36[1048576], array37[1048576], array38[1048576], array39[1048576], array40[1048576];
+vec4 array41[1048576], array42[1048576], array43[1048576], array44[1048576], array45[1048576];
+vec4 array46[1048576], array47[1048576], array48[1048576], array49[1048576], array50[1048576];
+vec4 array51[1048576], array52[1048576], array53[1048576], array54[1048576], array55[1048576];
+vec4 array56[1048576], array57[1048576], array58[1048576], array59[1048576], array60[1048576];
+vec4 array61[1048576], array62[1048576], array63[1048576], array64[1048576], array65[1048576];
+vec4 array66[1048576], array67[1048576], array68[1048576], array69[1048576], array70[1048576];
+vec4 array71[1048576], array72[1048576], array73[1048576], array74[1048576], array75[1048576];
+vec4 array76[1048576], array77[1048576], array78[1048576], array79[1048576], array80[1048576];
+vec4 array81[1048576], array82[1048576], array83[1048576], array84[1048576], array85[1048576];
+vec4 array86[1048576], array87[1048576], array88[1048576], array89[1048576], array90[1048576];
+vec4 array91[1048576], array92[1048576], array93[1048576], array94[1048576], array95[1048576];
+vec4 array96[1048576], array97[1048576], array98[1048576], array99[1048576], array100[1048576];
+vec4 array101[1048576], array102[1048576], array103[1048576], array104[1048576], array105[1048576];
+vec4 array106[1048576], array107[1048576], array108[1048576], array109[1048576], array110[1048576];
+vec4 array111[1048576], array112[1048576], array113[1048576], array114[1048576], array115[1048576];
+vec4 array116[1048576], array117[1048576], array118[1048576], array119[1048576], array120[1048576];
+vec4 array121[1048576], array122[1048576], array123[1048576], array124[1048576], array125[1048576];
+vec4 array126[1048576], array127[1048576], array128[1048576], array129[1048576], array130[1048576];
+vec4 array131[1048576], array132[1048576], array133[1048576], array134[1048576], array135[1048576];
+vec4 array136[1048576], array137[1048576], array138[1048576], array139[1048576], array140[1048576];
+vec4 array141[1048576], array142[1048576], array143[1048576], array144[1048576], array145[1048576];
+vec4 array146[1048576], array147[1048576], array148[1048576], array149[1048576], array150[1048576];
+vec4 array151[1048576], array152[1048576], array153[1048576], array154[1048576], array155[1048576];
+vec4 array156[1048576], array157[1048576], array158[1048576], array159[1048576], array160[1048576];
+vec4 array161[1048576], array162[1048576], array163[1048576], array164[1048576], array165[1048576];
+vec4 array166[1048576], array167[1048576], array168[1048576], array169[1048576], array170[1048576];
+vec4 array171[1048576], array172[1048576], array173[1048576], array174[1048576], array175[1048576];
+vec4 array176[1048576], array177[1048576], array178[1048576], array179[1048576], array180[1048576];
+vec4 array181[1048576], array182[1048576], array183[1048576], array184[1048576], array185[1048576];
+vec4 array186[1048576], array187[1048576], array188[1048576], array189[1048576], array190[1048576];
+vec4 array191[1048576], array192[1048576], array193[1048576], array194[1048576], array195[1048576];
+vec4 array196[1048576], array197[1048576], array198[1048576], array199[1048576], array200[1048576];
+vec4 array201[1048576], array202[1048576], array203[1048576], array204[1048576], array205[1048576];
+vec4 array206[1048576], array207[1048576], array208[1048576], array209[1048576], array210[1048576];
+vec4 array211[1048576], array212[1048576], array213[1048576], array214[1048576], array215[1048576];
+vec4 array216[1048576], array217[1048576], array218[1048576], array219[1048576], array220[1048576];
+vec4 array221[1048576], array222[1048576], array223[1048576], array224[1048576], array225[1048576];
+vec4 array226[1048576], array227[1048576], array228[1048576], array229[1048576], array230[1048576];
+vec4 array231[1048576], array232[1048576], array233[1048576], array234[1048576], array235[1048576];
+vec4 array236[1048576], array237[1048576], array238[1048576], array239[1048576], array240[1048576];
+vec4 array241[1048576], array242[1048576], array243[1048576], array244[1048576], array245[1048576];
+vec4 array246[1048576], array247[1048576], array248[1048576], array249[1048576], array250[1048576];
+vec4 array251[1048576], array252[1048576], array253[1048576], array254[1048576], array255[1048576];
+vec4 array256[1048576];
+
+void main()
+{
+ float f = array[0].x; f += array2[0].x; f += array3[0].x; f += array4[0].x; f += array5[0].x;
+ f += array6[0].x; f += array7[0].x; f += array8[0].x; f += array9[0].x; f += array10[0].x;
+ f += array11[0].x; f += array12[0].x; f += array13[0].x; f += array14[0].x; f += array15[0].x;
+ f += array16[0].x; f += array17[0].x; f += array18[0].x; f += array19[0].x; f += array20[0].x;
+ f += array21[0].x; f += array22[0].x; f += array23[0].x; f += array24[0].x; f += array25[0].x;
+ f += array26[0].x; f += array27[0].x; f += array28[0].x; f += array29[0].x; f += array30[0].x;
+ f += array31[0].x; f += array32[0].x; f += array33[0].x; f += array34[0].x; f += array35[0].x;
+ f += array36[0].x; f += array37[0].x; f += array38[0].x; f += array39[0].x; f += array40[0].x;
+ f += array41[0].x; f += array42[0].x; f += array43[0].x; f += array44[0].x; f += array45[0].x;
+ f += array46[0].x; f += array47[0].x; f += array48[0].x; f += array49[0].x; f += array50[0].x;
+ f += array51[0].x; f += array52[0].x; f += array53[0].x; f += array54[0].x; f += array55[0].x;
+ f += array56[0].x; f += array57[0].x; f += array58[0].x; f += array59[0].x; f += array60[0].x;
+ f += array61[0].x; f += array62[0].x; f += array63[0].x; f += array64[0].x; f += array65[0].x;
+ f += array66[0].x; f += array67[0].x; f += array68[0].x; f += array69[0].x; f += array70[0].x;
+ f += array71[0].x; f += array72[0].x; f += array73[0].x; f += array74[0].x; f += array75[0].x;
+ f += array76[0].x; f += array77[0].x; f += array78[0].x; f += array79[0].x; f += array80[0].x;
+ f += array81[0].x; f += array82[0].x; f += array83[0].x; f += array84[0].x; f += array85[0].x;
+ f += array86[0].x; f += array87[0].x; f += array88[0].x; f += array89[0].x; f += array90[0].x;
+ f += array91[0].x; f += array92[0].x; f += array93[0].x; f += array94[0].x; f += array95[0].x;
+ f += array96[0].x; f += array97[0].x; f += array98[0].x; f += array99[0].x; f += array100[0].x;
+ f += array101[0].x; f += array102[0].x; f += array103[0].x; f += array104[0].x;
+ f += array105[0].x; f += array106[0].x; f += array107[0].x; f += array108[0].x;
+ f += array109[0].x; f += array110[0].x; f += array111[0].x; f += array112[0].x;
+ f += array113[0].x; f += array114[0].x; f += array115[0].x; f += array116[0].x;
+ f += array117[0].x; f += array118[0].x; f += array119[0].x; f += array120[0].x;
+ f += array121[0].x; f += array122[0].x; f += array123[0].x; f += array124[0].x;
+ f += array125[0].x; f += array126[0].x; f += array127[0].x; f += array128[0].x;
+ f += array129[0].x; f += array130[0].x; f += array131[0].x; f += array132[0].x;
+ f += array133[0].x; f += array134[0].x; f += array135[0].x; f += array136[0].x;
+ f += array137[0].x; f += array138[0].x; f += array139[0].x; f += array140[0].x;
+ f += array141[0].x; f += array142[0].x; f += array143[0].x; f += array144[0].x;
+ f += array145[0].x; f += array146[0].x; f += array147[0].x; f += array148[0].x;
+ f += array149[0].x; f += array150[0].x; f += array151[0].x; f += array152[0].x;
+ f += array153[0].x; f += array154[0].x; f += array155[0].x; f += array156[0].x;
+ f += array157[0].x; f += array158[0].x; f += array159[0].x; f += array160[0].x;
+ f += array161[0].x; f += array162[0].x; f += array163[0].x; f += array164[0].x;
+ f += array165[0].x; f += array166[0].x; f += array167[0].x; f += array168[0].x;
+ f += array169[0].x; f += array170[0].x; f += array171[0].x; f += array172[0].x;
+ f += array173[0].x; f += array174[0].x; f += array175[0].x; f += array176[0].x;
+ f += array177[0].x; f += array178[0].x; f += array179[0].x; f += array180[0].x;
+ f += array181[0].x; f += array182[0].x; f += array183[0].x; f += array184[0].x;
+ f += array185[0].x; f += array186[0].x; f += array187[0].x; f += array188[0].x;
+ f += array189[0].x; f += array190[0].x; f += array191[0].x; f += array192[0].x;
+ f += array193[0].x; f += array194[0].x; f += array195[0].x; f += array196[0].x;
+ f += array197[0].x; f += array198[0].x; f += array199[0].x; f += array200[0].x;
+ f += array201[0].x; f += array202[0].x; f += array203[0].x; f += array204[0].x;
+ f += array205[0].x; f += array206[0].x; f += array207[0].x; f += array208[0].x;
+ f += array209[0].x; f += array210[0].x; f += array211[0].x; f += array212[0].x;
+ f += array213[0].x; f += array214[0].x; f += array215[0].x; f += array216[0].x;
+ f += array217[0].x; f += array218[0].x; f += array219[0].x; f += array220[0].x;
+ f += array221[0].x; f += array222[0].x; f += array223[0].x; f += array224[0].x;
+ f += array225[0].x; f += array226[0].x; f += array227[0].x; f += array228[0].x;
+ f += array229[0].x; f += array230[0].x; f += array231[0].x; f += array232[0].x;
+ f += array233[0].x; f += array234[0].x; f += array235[0].x; f += array236[0].x;
+ f += array237[0].x; f += array238[0].x; f += array239[0].x; f += array240[0].x;
+ f += array241[0].x; f += array242[0].x; f += array243[0].x; f += array244[0].x;
+ f += array245[0].x; f += array246[0].x; f += array247[0].x; f += array248[0].x;
+ f += array249[0].x; f += array250[0].x; f += array251[0].x; f += array252[0].x;
+ f += array253[0].x; f += array254[0].x; f += array255[0].x; f += array256[0].x;
+ if (f == 2.0)
+ gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
+ else
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
+})";
+
GLuint program = CompileProgram(essl1_shaders::vs::Simple(), kTooLargeGlobalMemory1);
EXPECT_EQ(0u, program);
@@ -5449,6 +5574,9 @@
program = CompileProgram(essl1_shaders::vs::Simple(), kTooLargeGlobalAndLocalMemory2);
EXPECT_EQ(0u, program);
+
+ program = CompileProgram(essl1_shaders::vs::Simple(), kTooLargeGlobalMemoryOverflow);
+ EXPECT_EQ(0u, program);
}
// Linking should fail when corresponding vertex/fragment uniform blocks have different precision

View File

@@ -1,286 +0,0 @@
From cafe56b591edb77f041be70b58cac3a61565644a Mon Sep 17 00:00:00 2001
From: Geoff Lang <geofflang@chromium.org>
Date: Fri, 23 Jun 2023 14:46:28 -0400
Subject: [PATCH] M116: GL: Ensure all instanced attributes have a buffer with data
Apple OpenGL drivers sometimes crash when given an instanced draw with
a buffer that has never been given data.
It's not efficient to check if the attribute is both zero-sized and
instanced so just ensure that every time a zero-sized buffer is bound
to an attribute, it gets initialized with some data.
Bug: chromium:1456243
Change-Id: I66b7c7017843153db2df3bc50010cba765d03c5f
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4642048
Commit-Queue: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
(cherry picked from commit 4e6124dae892690204f8e5996aeaad14f45e0a97)
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4727452
---
diff --git a/include/platform/FeaturesGL_autogen.h b/include/platform/FeaturesGL_autogen.h
index aa0565c..2f6e094 100644
--- a/include/platform/FeaturesGL_autogen.h
+++ b/include/platform/FeaturesGL_autogen.h
@@ -501,6 +501,12 @@
"supportsShaderPixelLocalStorageEXT", FeatureCategory::OpenGLFeatures,
"Backend GL context supports EXT_shader_pixel_local_storage extension", &members,
"http://anglebug.com/7279"};
+
+ FeatureInfo ensureNonEmptyBufferIsBoundForDraw = {
+ "ensureNonEmptyBufferIsBoundForDraw", FeatureCategory::OpenGLFeatures,
+ "Apple OpenGL drivers crash when drawing with a zero-sized buffer bound using a non-zero "
+ "divisor.",
+ &members, "http://crbug.com/1456243"};
};
inline FeaturesGL::FeaturesGL() = default;
diff --git a/include/platform/gl_features.json b/include/platform/gl_features.json
index 032f29a..b358cea 100644
--- a/include/platform/gl_features.json
+++ b/include/platform/gl_features.json
@@ -699,6 +699,14 @@
"Backend GL context supports EXT_shader_pixel_local_storage extension"
],
"issue": "http://anglebug.com/7279"
+ },
+ {
+ "name": "ensure_non_empty_buffer_is_bound_for_draw",
+ "category": "Features",
+ "description": [
+ "Apple OpenGL drivers crash when drawing with a zero-sized buffer bound using a non-zero divisor."
+ ],
+ "issue": "http://crbug.com/1456243"
}
]
}
diff --git a/scripts/code_generation_hashes/ANGLE_features.json b/scripts/code_generation_hashes/ANGLE_features.json
index d4576c2..503001c 100644
--- a/scripts/code_generation_hashes/ANGLE_features.json
+++ b/scripts/code_generation_hashes/ANGLE_features.json
@@ -2,7 +2,7 @@
"include/platform/FeaturesD3D_autogen.h":
"9923fb44d0a6f31948d0c8f46ee1d9e2",
"include/platform/FeaturesGL_autogen.h":
- "a795a806d71b0e6d1f9e6d95c6e11971",
+ "fef16ab3946346a2a7d5b76bb39471a4",
"include/platform/FeaturesMtl_autogen.h":
"407426c8874de9295482ace9c94bd812",
"include/platform/FeaturesVk_autogen.h":
@@ -16,13 +16,13 @@
"include/platform/gen_features.py":
"062989f7a8f3ff3b383f98fc8908dc33",
"include/platform/gl_features.json":
- "3335055a70e35ebb7bf74c6d7c58897b",
+ "c9aead89696e7fd0c8bfe5c5ca85ca63",
"include/platform/mtl_features.json":
"c66d170e7a8eb3448030f4c423ed0133",
"include/platform/vk_features.json":
"416bbb28b9fa1a3c4ef141f243c0a9e6",
"util/angle_features_autogen.cpp":
- "73169f63c755192c3b4bd27d6f4096ca",
+ "288daaec490eb816883d744f108d74c9",
"util/angle_features_autogen.h":
- "7aa8120eb8f8fd335946b8c27074745d"
+ "daf25d3e4ffea143d1c082416513f7e7"
}
\ No newline at end of file
diff --git a/src/libANGLE/renderer/gl/BufferGL.cpp b/src/libANGLE/renderer/gl/BufferGL.cpp
index c99fd5d..9651838 100644
--- a/src/libANGLE/renderer/gl/BufferGL.cpp
+++ b/src/libANGLE/renderer/gl/BufferGL.cpp
@@ -296,6 +296,11 @@
return angle::Result::Continue;
}
+size_t BufferGL::getBufferSize() const
+{
+ return mBufferSize;
+}
+
GLuint BufferGL::getBufferID() const
{
return mBufferID;
diff --git a/src/libANGLE/renderer/gl/BufferGL.h b/src/libANGLE/renderer/gl/BufferGL.h
index 7b57594..fe9138e 100644
--- a/src/libANGLE/renderer/gl/BufferGL.h
+++ b/src/libANGLE/renderer/gl/BufferGL.h
@@ -56,6 +56,7 @@
bool primitiveRestartEnabled,
gl::IndexRange *outRange) override;
+ size_t getBufferSize() const;
GLuint getBufferID() const;
private:
diff --git a/src/libANGLE/renderer/gl/VertexArrayGL.cpp b/src/libANGLE/renderer/gl/VertexArrayGL.cpp
index dc981de..fda9099 100644
--- a/src/libANGLE/renderer/gl/VertexArrayGL.cpp
+++ b/src/libANGLE/renderer/gl/VertexArrayGL.cpp
@@ -646,6 +646,7 @@
angle::Result VertexArrayGL::updateAttribPointer(const gl::Context *context, size_t attribIndex)
{
+ const angle::FeaturesGL &features = GetFeaturesGL(context);
const VertexAttribute &attrib = mState.getVertexAttribute(attribIndex);
@@ -687,8 +688,16 @@
// is not NULL.
StateManagerGL *stateManager = GetStateManagerGL(context);
- GLuint bufferId = GetNativeBufferID(arrayBuffer);
+ BufferGL *bufferGL = GetImplAs<BufferGL>(arrayBuffer);
+ GLuint bufferId = bufferGL->getBufferID();
stateManager->bindBuffer(gl::BufferBinding::Array, bufferId);
+ if (features.ensureNonEmptyBufferIsBoundForDraw.enabled && bufferGL->getBufferSize() == 0)
+ {
+ constexpr uint32_t data = 0;
+ ANGLE_TRY(bufferGL->setData(context, gl::BufferBinding::Array, &data, sizeof(data),
+ gl::BufferUsage::StaticDraw));
+ ASSERT(bufferGL->getBufferSize() > 0);
+ }
ANGLE_TRY(callVertexAttribPointer(context, static_cast<GLuint>(attribIndex), attrib,
binding.getStride(), binding.getOffset()));
diff --git a/src/libANGLE/renderer/gl/renderergl_utils.cpp b/src/libANGLE/renderer/gl/renderergl_utils.cpp
index 6911247..ab2a608 100644
--- a/src/libANGLE/renderer/gl/renderergl_utils.cpp
+++ b/src/libANGLE/renderer/gl/renderergl_utils.cpp
@@ -2465,6 +2465,9 @@
// EXT_shader_pixel_local_storage
ANGLE_FEATURE_CONDITION(features, supportsShaderPixelLocalStorageEXT,
functions->hasGLESExtension("GL_EXT_shader_pixel_local_storage"));
+
+ // http://crbug.com/1456243
+ ANGLE_FEATURE_CONDITION(features, ensureNonEmptyBufferIsBoundForDraw, IsApple() || IsAndroid());
}
void InitializeFrontendFeatures(const FunctionsGL *functions, angle::FrontendFeatures *features)
diff --git a/src/tests/angle_end2end_tests_expectations.txt b/src/tests/angle_end2end_tests_expectations.txt
index 59ec7c2..44ff3e4 100644
--- a/src/tests/angle_end2end_tests_expectations.txt
+++ b/src/tests/angle_end2end_tests_expectations.txt
@@ -380,6 +380,7 @@
7294 WIN D3D11 : StateChangeTestES3.StencilWriteMask/* = SKIP
7316 WIN D3D11 : StateChangeTestES3.StencilTestAndFunc/* = SKIP
7329 WIN D3D11 : StateChangeTestES3.PrimitiveRestart/* = SKIP
+1456243 WIN D3D11 : WebGL2CompatibilityTest.DrawWithZeroSizedBuffer/* = SKIP
// Android
6095 ANDROID GLES : GLSLTest_ES3.InitGlobalComplexConstant/* = SKIP
diff --git a/src/tests/gl_tests/WebGLCompatibilityTest.cpp b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
index 7dc56cd..bd7ecd1 100644
--- a/src/tests/gl_tests/WebGLCompatibilityTest.cpp
+++ b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
@@ -1632,10 +1632,10 @@
constexpr GLuint kMaxIntAsGLuint = static_cast<GLuint>(std::numeric_limits<GLint>::max());
constexpr GLuint kIndexData[] = {
- kMaxIntAsGLuint,
- kMaxIntAsGLuint + 1,
- kMaxIntAsGLuint + 2,
- kMaxIntAsGLuint + 3,
+ kMaxIntAsGLuint,
+ kMaxIntAsGLuint + 1,
+ kMaxIntAsGLuint + 2,
+ kMaxIntAsGLuint + 3,
};
GLBuffer indexBuffer;
@@ -3687,8 +3687,8 @@
constexpr float readPixelsData[] = {-5000.0f, 0.0f, 0.0f, 1.0f};
const GLushort textureData[] = {
- gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
- gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
+ gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
+ gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
for (auto extension : FloatingPointTextureExtensions)
{
@@ -3748,8 +3748,8 @@
constexpr float readPixelsData[] = {7108.0f, -10.0f, 0.0f, 1.0f};
const GLushort textureData[] = {
- gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
- gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
+ gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
+ gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
for (auto extension : FloatingPointTextureExtensions)
{
@@ -3811,8 +3811,8 @@
constexpr float readPixelsData[] = {7000.0f, 100.0f, 33.0f, 1.0f};
const GLushort textureData[] = {
- gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
- gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
+ gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
+ gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
for (auto extension : FloatingPointTextureExtensions)
{
@@ -3874,8 +3874,8 @@
constexpr float readPixelsData[] = {7000.0f, 100.0f, 33.0f, -1.0f};
const GLushort textureData[] = {
- gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
- gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
+ gl::float32ToFloat16(readPixelsData[0]), gl::float32ToFloat16(readPixelsData[1]),
+ gl::float32ToFloat16(readPixelsData[2]), gl::float32ToFloat16(readPixelsData[3])};
for (auto extension : FloatingPointTextureExtensions)
{
@@ -5803,6 +5803,26 @@
}
}
+// Test for a mishandling of instanced vertex attributes with zero-sized buffers bound on Apple
+// OpenGL drivers.
+TEST_P(WebGL2CompatibilityTest, DrawWithZeroSizedBuffer)
+{
+ ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), essl3_shaders::fs::Red());
+ glUseProgram(program);
+
+ GLBuffer buffer;
+ glBindBuffer(GL_ARRAY_BUFFER, buffer);
+
+ GLint posLocation = glGetAttribLocation(program, essl3_shaders::PositionAttrib());
+ glEnableVertexAttribArray(posLocation);
+
+ glVertexAttribDivisor(posLocation, 1);
+ glVertexAttribPointer(posLocation, 1, GL_UNSIGNED_BYTE, GL_FALSE, 9,
+ reinterpret_cast<void *>(0x41424344));
+
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+}
+
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(WebGLCompatibilityTest);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WebGL2CompatibilityTest);
diff --git a/util/angle_features_autogen.cpp b/util/angle_features_autogen.cpp
index adb9610..a060dd2 100644
--- a/util/angle_features_autogen.cpp
+++ b/util/angle_features_autogen.cpp
@@ -118,6 +118,7 @@
{Feature::EnablePrecisionQualifiers, "enablePrecisionQualifiers"},
{Feature::EnablePreRotateSurfaces, "enablePreRotateSurfaces"},
{Feature::EnableProgramBinaryForCapture, "enableProgramBinaryForCapture"},
+ {Feature::EnsureNonEmptyBufferIsBoundForDraw, "ensureNonEmptyBufferIsBoundForDraw"},
{Feature::ExpandIntegerPowExpressions, "expandIntegerPowExpressions"},
{Feature::ExplicitlyEnablePerSampleShading, "explicitlyEnablePerSampleShading"},
{Feature::ExposeNonConformantExtensionsAndVersions, "exposeNonConformantExtensionsAndVersions"},
diff --git a/util/angle_features_autogen.h b/util/angle_features_autogen.h
index 3d8c47f..4064425 100644
--- a/util/angle_features_autogen.h
+++ b/util/angle_features_autogen.h
@@ -112,6 +112,7 @@
EnablePrecisionQualifiers,
EnablePreRotateSurfaces,
EnableProgramBinaryForCapture,
+ EnsureNonEmptyBufferIsBoundForDraw,
ExpandIntegerPowExpressions,
ExplicitlyEnablePerSampleShading,
ExposeNonConformantExtensionsAndVersions,

View File

@@ -0,0 +1,215 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shahbaz Youssefi <syoussefi@chromium.org>
Date: Thu, 30 Nov 2023 14:12:42 -0500
Subject: M120: Translator: Fail compilation if too many struct fields
If there are too many struct fields, SPIR-V cannot be produced (as it
has a hard limit of 16383 fields). The Nvidia GL driver has also been
observed to fail when there are too many fields.
Bug: chromium:1505009
Change-Id: I29fd61d180175e89e7db9ca8ba49ab07585b5f9a
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5143827
Reviewed-by: Cody Northrop <cnorthrop@google.com>
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index 7c90ea4f1d23a8af0cab1d44124eea021a27a16d..e174725beb764407185e471a9916ffd164493cd8 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -4726,6 +4726,8 @@ TIntermDeclaration *TParseContext::addInterfaceBlock(
const TVector<unsigned int> *arraySizes,
const TSourceLoc &arraySizesLine)
{
+ checkDoesNotHaveTooManyFields(blockName, fieldList, nameLine);
+
// Ensure there are no duplicate field names
checkDoesNotHaveDuplicateFieldNames(fieldList, nameLine);
@@ -6289,6 +6291,21 @@ void TParseContext::checkDoesNotHaveDuplicateFieldNames(const TFieldList *fields
}
}
+void TParseContext::checkDoesNotHaveTooManyFields(const ImmutableString &name,
+ const TFieldList *fields,
+ const TSourceLoc &location)
+{
+ // Check that there are not too many fields. SPIR-V has a limit of 16383 fields, and it would
+ // be reasonable to apply that limit to all outputs. For example, it was observed that 32768
+ // fields cause the Nvidia GL driver to fail compilation, so such a limit is not too specific to
+ // SPIR-V.
+ constexpr size_t kMaxFieldCount = 16383;
+ if (fields->size() > kMaxFieldCount)
+ {
+ error(location, "Too many fields in the struct (limit is 16383)", name);
+ }
+}
+
TFieldList *TParseContext::addStructFieldList(TFieldList *fields, const TSourceLoc &location)
{
return fields;
@@ -6392,6 +6409,8 @@ TTypeSpecifierNonArray TParseContext::addStructure(const TSourceLoc &structLine,
}
}
+ checkDoesNotHaveTooManyFields(structName, fieldList, structLine);
+
// Ensure there are no duplicate field names
checkDoesNotHaveDuplicateFieldNames(fieldList, structLine);
diff --git a/src/compiler/translator/ParseContext.h b/src/compiler/translator/ParseContext.h
index b63dbbadd146d1a004513823de72c89240a31929..c83b73271b557ed122668d7e655deae5aa23bc48 100644
--- a/src/compiler/translator/ParseContext.h
+++ b/src/compiler/translator/ParseContext.h
@@ -355,6 +355,9 @@ class TParseContext : angle::NonCopyable
const TVector<unsigned int> *arraySizes);
void checkDoesNotHaveDuplicateFieldNames(const TFieldList *fields, const TSourceLoc &location);
+ void checkDoesNotHaveTooManyFields(const ImmutableString &name,
+ const TFieldList *fields,
+ const TSourceLoc &location);
TFieldList *addStructFieldList(TFieldList *fields, const TSourceLoc &location);
TFieldList *combineStructFieldLists(TFieldList *processedFields,
const TFieldList *newlyAddedFields,
diff --git a/src/tests/compiler_tests/ExpressionLimit_test.cpp b/src/tests/compiler_tests/ExpressionLimit_test.cpp
index d399e1792d97edb76d5e0247e4166e094cecb7e5..e17eace1b4b9a4185d6833fb7895f5fd49ae7679 100644
--- a/src/tests/compiler_tests/ExpressionLimit_test.cpp
+++ b/src/tests/compiler_tests/ExpressionLimit_test.cpp
@@ -16,12 +16,6 @@ class ExpressionLimitTest : public testing::Test
static const int kMaxExpressionComplexity = 16;
static const int kMaxCallStackDepth = 16;
static const int kMaxFunctionParameters = 16;
- static const char *kExpressionTooComplex;
- static const char *kCallStackTooDeep;
- static const char *kHasRecursion;
- static const char *kTooManyParameters;
- static const char *kTooComplexSwitch;
- static const char *kGlobalVariableInit;
virtual void SetUp()
{
@@ -125,9 +119,7 @@ class ExpressionLimitTest : public testing::Test
GenerateDeepFunctionStack(length, &ss);
- ss << "void main() {\n"
- << " gl_FragColor = function" << length << "();\n"
- << "}";
+ ss << "void main() {\n" << " gl_FragColor = function" << length << "();\n" << "}";
return ss.str();
}
@@ -138,9 +130,7 @@ class ExpressionLimitTest : public testing::Test
GenerateDeepFunctionStack(length, &ss);
- ss << "void main() {\n"
- << " gl_FragColor = vec4(0,0,0,0);\n"
- << "}";
+ ss << "void main() {\n" << " gl_FragColor = vec4(0,0,0,0);\n" << "}";
return ss.str();
}
@@ -149,9 +139,7 @@ class ExpressionLimitTest : public testing::Test
{
std::stringstream ss;
- ss << "precision mediump float;\n"
- << "\n"
- << "float foo(";
+ ss << "precision mediump float;\n" << "\n" << "float foo(";
for (int i = 0; i < parameters; ++i)
{
ss << "float f" << i;
@@ -244,15 +232,13 @@ class ExpressionLimitTest : public testing::Test
ShBuiltInResources resources;
};
-const char *ExpressionLimitTest::kExpressionTooComplex = "Expression too complex";
-const char *ExpressionLimitTest::kCallStackTooDeep = "Call stack too deep";
-const char *ExpressionLimitTest::kHasRecursion =
- "Recursive function call in the following call chain";
-const char *ExpressionLimitTest::kTooManyParameters = "Function has too many parameters";
-const char *ExpressionLimitTest::kTooComplexSwitch =
- "too complex expressions inside a switch statement";
-const char *ExpressionLimitTest::kGlobalVariableInit =
- "global variable initializers must be constant expressions";
+constexpr char kExpressionTooComplex[] = "Expression too complex";
+constexpr char kCallStackTooDeep[] = "Call stack too deep";
+constexpr char kHasRecursion[] = "Recursive function call in the following call chain";
+constexpr char kTooManyParameters[] = "Function has too many parameters";
+constexpr char kTooComplexSwitch[] = "too complex expressions inside a switch statement";
+constexpr char kGlobalVariableInit[] = "global variable initializers must be constant expressions";
+constexpr char kTooManyFields[] = "Too many fields in the struct";
TEST_F(ExpressionLimitTest, ExpressionComplexity)
{
@@ -632,3 +618,31 @@ TEST_F(ExpressionLimitTest, NestingInsideGlobalInitializer)
compileOptions, nullptr));
sh::Destruct(compiler);
}
+
+TEST_F(ExpressionLimitTest, TooManyStructFields)
+{
+ ShShaderSpec spec = SH_WEBGL2_SPEC;
+ ShShaderOutput output = SH_ESSL_OUTPUT;
+ ShHandle compiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &resources);
+ ShCompileOptions compileOptions = {};
+
+ std::ostringstream fs;
+ fs << R"(#version 300 es
+precision highp float;
+struct TooManyFields
+{
+)";
+ for (uint32_t i = 0; i < (1 << 16); ++i)
+ {
+ fs << " float field" << i << ";\n";
+ }
+ fs << R"(};
+uniform B { TooManyFields s; };
+out vec4 color;
+void main() {
+ color = vec4(s.field0, 0.0, 0.0, 1.0);
+})";
+
+ EXPECT_TRUE(CheckShaderCompilation(compiler, fs.str().c_str(), compileOptions, kTooManyFields));
+ sh::Destruct(compiler);
+}
diff --git a/src/tests/gl_tests/GLSLTest.cpp b/src/tests/gl_tests/GLSLTest.cpp
index 9b42b6d9221366e9bc7b6263bf8e14b77ca7694d..46f8645e5a56e527223ea4657d14dbc8619cb631 100644
--- a/src/tests/gl_tests/GLSLTest.cpp
+++ b/src/tests/gl_tests/GLSLTest.cpp
@@ -18064,6 +18064,33 @@ void main() {
ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), fs.str().c_str());
}
+// Test that structs with too many fields are rejected. In SPIR-V, the instruction that defines the
+// struct lists the fields which means the length of the instruction is a function of the field
+// count. Since SPIR-V instruction sizes are limited to 16 bits, structs with more fields cannot be
+// represented.
+TEST_P(GLSLTest_ES3, TooManyFieldsInStruct)
+{
+ std::ostringstream fs;
+ fs << R"(#version 300 es
+precision highp float;
+struct TooManyFields
+{
+)";
+ for (uint32_t i = 0; i < (1 << 16); ++i)
+ {
+ fs << " float field" << i << ";\n";
+ }
+ fs << R"(};
+uniform B { TooManyFields s; };
+out vec4 color;
+void main() {
+ color = vec4(s.field0, 0.0, 0.0, 1.0);
+})";
+
+ GLuint shader = CompileShader(GL_FRAGMENT_SHADER, fs.str().c_str());
+ EXPECT_EQ(0u, shader);
+}
+
} // anonymous namespace
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(GLSLTest);

View File

@@ -0,0 +1,416 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shahbaz Youssefi <syoussefi@chromium.org>
Date: Thu, 30 Nov 2023 15:42:32 -0500
Subject: M120: Translator: Limit private variable size to 64KB
This is indirectly fixing an issue where passing large arrays in SPIR-V
such that an internal cast is needed (such as array inside interface
block copied to local varaible) causes an overflow of the instruction
length limit (in the absence of OpCopyLogical).
By limiting the size of private variables to 32KB, this limitation is
indirectly enforced. It was observed that all the test shaders added in
this CL fail on the Nvidia OpenGL drivers, so such a limit seems to be
reasonble.
Bug: chromium:1505009
Change-Id: I75a1e40a538120ffc69ae7edafbdba5830c6b0bb
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5143828
Reviewed-by: Cody Northrop <cnorthrop@google.com>
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
index 383feeb477d2445d5e599b39e125fe455169da08..8736b3dcfbcb43f9087b78224658a9680d7ee68c 100644
--- a/src/compiler/translator/Compiler.cpp
+++ b/src/compiler/translator/Compiler.cpp
@@ -770,11 +770,6 @@ bool TCompiler::checkAndSimplifyAST(TIntermBlock *root,
return false;
}
- if (shouldLimitTypeSizes() && !ValidateTypeSizeLimitations(root, &mSymbolTable, &mDiagnostics))
- {
- return false;
- }
-
if (!ValidateFragColorAndFragData(mShaderType, mShaderVersion, mSymbolTable, &mDiagnostics))
{
return false;
@@ -1046,6 +1041,13 @@ bool TCompiler::checkAndSimplifyAST(TIntermBlock *root,
return false;
}
+ // Run after RemoveUnreferencedVariables, validate that the shader does not have excessively
+ // large variables.
+ if (shouldLimitTypeSizes() && !ValidateTypeSizeLimitations(root, &mSymbolTable, &mDiagnostics))
+ {
+ return false;
+ }
+
// Built-in function emulation needs to happen after validateLimitations pass.
GetGlobalPoolAllocator()->lock();
initBuiltInFunctionEmulator(&mBuiltInFunctionEmulator, compileOptions);
diff --git a/src/compiler/translator/ValidateTypeSizeLimitations.cpp b/src/compiler/translator/ValidateTypeSizeLimitations.cpp
index f0ff9cb11ac39e62672285300c8f41641f12c617..8f02c65b5ec5fd20b8bcee2bc595cfb278f758b4 100644
--- a/src/compiler/translator/ValidateTypeSizeLimitations.cpp
+++ b/src/compiler/translator/ValidateTypeSizeLimitations.cpp
@@ -24,10 +24,11 @@ namespace
// Arbitrarily enforce that all types declared with a size in bytes of over 2 GB will cause
// compilation failure.
//
-// For local and global variables, the limit is much lower (16MB) as that much memory won't fit in
+// For local and global variables, the limit is much lower (64KB) as that much memory won't fit in
// the GPU registers anyway.
-constexpr size_t kMaxVariableSizeInBytes = static_cast<size_t>(2) * 1024 * 1024 * 1024;
-constexpr size_t kMaxPrivateVariableSizeInBytes = static_cast<size_t>(16) * 1024 * 1024;
+constexpr size_t kMaxVariableSizeInBytes = static_cast<size_t>(2) * 1024 * 1024 * 1024;
+constexpr size_t kMaxPrivateVariableSizeInBytes = static_cast<size_t>(64) * 1024;
+constexpr size_t kMaxTotalPrivateVariableSizeInBytes = static_cast<size_t>(16) * 1024 * 1024;
// Traverses intermediate tree to ensure that the shader does not
// exceed certain implementation-defined limits on the sizes of types.
@@ -70,43 +71,115 @@ class ValidateTypeSizeLimitationsTraverser : public TIntermTraverser
continue;
}
- const TType &variableType = asSymbol->getType();
-
- // Create a ShaderVariable from which to compute
- // (conservative) sizing information.
- ShaderVariable shaderVar;
- setCommonVariableProperties(variableType, variable, &shaderVar);
-
- // Compute the std140 layout of this variable, assuming
- // it's a member of a block (which it might not be).
- Std140BlockEncoder layoutEncoder;
- BlockEncoderVisitor visitor("", "", &layoutEncoder);
- // Since the size limit's arbitrary, it doesn't matter
- // whether the row-major layout is correctly determined.
- bool isRowMajorLayout = false;
- TraverseShaderVariable(shaderVar, isRowMajorLayout, &visitor);
- if (layoutEncoder.getCurrentOffset() > kMaxVariableSizeInBytes)
+ if (!validateVariableSize(variable, asSymbol->getLine()))
{
- error(asSymbol->getLine(),
- "Size of declared variable exceeds implementation-defined limit",
- asSymbol->getName());
return false;
}
+ }
+
+ return true;
+ }
+
+ void visitFunctionPrototype(TIntermFunctionPrototype *node) override
+ {
+ const TFunction *function = node->getFunction();
+ const size_t paramCount = function->getParamCount();
+
+ for (size_t paramIndex = 0; paramIndex < paramCount; ++paramIndex)
+ {
+ validateVariableSize(*function->getParam(paramIndex), node->getLine());
+ }
+ }
+
+ bool validateVariableSize(const TVariable &variable, const TSourceLoc &location)
+ {
+ const TType &variableType = variable.getType();
+
+ // Create a ShaderVariable from which to compute
+ // (conservative) sizing information.
+ ShaderVariable shaderVar;
+ setCommonVariableProperties(variableType, variable, &shaderVar);
+
+ // Compute the std140 layout of this variable, assuming
+ // it's a member of a block (which it might not be).
+ Std140BlockEncoder layoutEncoder;
+ BlockEncoderVisitor visitor("", "", &layoutEncoder);
+ // Since the size limit's arbitrary, it doesn't matter
+ // whether the row-major layout is correctly determined.
+ bool isRowMajorLayout = false;
+ TraverseShaderVariable(shaderVar, isRowMajorLayout, &visitor);
+ if (layoutEncoder.getCurrentOffset() > kMaxVariableSizeInBytes)
+ {
+ error(location, "Size of declared variable exceeds implementation-defined limit",
+ variable.name());
+ return false;
+ }
+
+ // Skip over struct declarations. As long as they are not used (or if they are used later
+ // in a less-restricted context (such as a UBO or SSBO)), they can be larger than
+ // kMaxPrivateVariableSizeInBytes.
+ if (variable.symbolType() == SymbolType::Empty && variableType.isStructSpecifier())
+ {
+ return true;
+ }
+
+ switch (variableType.getQualifier())
+ {
+ // List of all types that need to be limited (for example because they cause overflows
+ // in drivers, or create trouble for the SPIR-V gen as the number of an instruction's
+ // arguments cannot be more than 64KB (see OutputSPIRVTraverser::cast)).
+
+ // Local/global variables
+ case EvqTemporary:
+ case EvqGlobal:
+ case EvqConst:
+
+ // Function arguments
+ case EvqParamIn:
+ case EvqParamOut:
+ case EvqParamInOut:
+ case EvqParamConst:
+
+ // Varyings
+ case EvqVaryingIn:
+ case EvqVaryingOut:
+ case EvqSmoothOut:
+ case EvqFlatOut:
+ case EvqNoPerspectiveOut:
+ case EvqCentroidOut:
+ case EvqSampleOut:
+ case EvqNoPerspectiveCentroidOut:
+ case EvqNoPerspectiveSampleOut:
+ case EvqSmoothIn:
+ case EvqFlatIn:
+ case EvqNoPerspectiveIn:
+ case EvqCentroidIn:
+ case EvqNoPerspectiveCentroidIn:
+ case EvqNoPerspectiveSampleIn:
+ case EvqVertexOut:
+ case EvqFragmentIn:
+ case EvqGeometryIn:
+ case EvqGeometryOut:
+ case EvqPerVertexIn:
+ case EvqPerVertexOut:
+ case EvqPatchIn:
+ case EvqPatchOut:
+ case EvqTessControlIn:
+ case EvqTessControlOut:
+ case EvqTessEvaluationIn:
+ case EvqTessEvaluationOut:
- const bool isPrivate = variableType.getQualifier() == EvqTemporary ||
- variableType.getQualifier() == EvqGlobal ||
- variableType.getQualifier() == EvqConst;
- if (isPrivate)
- {
if (layoutEncoder.getCurrentOffset() > kMaxPrivateVariableSizeInBytes)
{
- error(asSymbol->getLine(),
+ error(location,
"Size of declared private variable exceeds implementation-defined limit",
- asSymbol->getName());
+ variable.name());
return false;
}
mTotalPrivateVariablesSize += layoutEncoder.getCurrentOffset();
- }
+ break;
+ default:
+ break;
}
return true;
@@ -115,7 +188,7 @@ class ValidateTypeSizeLimitationsTraverser : public TIntermTraverser
void validateTotalPrivateVariableSize()
{
if (mTotalPrivateVariablesSize.ValueOrDefault(std::numeric_limits<size_t>::max()) >
- kMaxPrivateVariableSizeInBytes)
+ kMaxTotalPrivateVariableSizeInBytes)
{
mDiagnostics->error(
TSourceLoc{},
diff --git a/src/tests/angle_end2end_tests_expectations.txt b/src/tests/angle_end2end_tests_expectations.txt
index 3d356609031820b92c230ac7ff836327b78ec834..cfa70eef00a1e8d67f9fbf07ee74928b55da8b92 100644
--- a/src/tests/angle_end2end_tests_expectations.txt
+++ b/src/tests/angle_end2end_tests_expectations.txt
@@ -111,6 +111,8 @@ b/273271471 WIN INTEL VULKAN : ShaderAlgorithmTest.rgb_to_hsl_vertex_shader/* =
7872 WIN INTEL OPENGL : VertexAttributeTest.AliasingMatrixAttribLocations/ES2_OpenGL = SKIP
7872 WIN INTEL OPENGL : VertexAttributeTest.ShortUnnormalized/ES2_OpenGL = SKIP
7872 WIN INTEL OPENGL : ViewportTest.DoubleWindowCentered/ES2_OpenGL = SKIP
+8441 WIN INTEL OPENGL : GLSLTest_ES3.LargeInterfaceBlockArray/* = SKIP
+8441 WIN INTEL OPENGL : GLSLTest_ES3.LargeInterfaceBlockNestedArray/* = SKIP
// Linux
6065 LINUX INTEL VULKAN : SimpleStateChangeTestES31.DrawThenUpdateUBOThenDrawThenDrawIndexed/* = SKIP
@@ -147,6 +149,10 @@ b/273271471 WIN INTEL VULKAN : ShaderAlgorithmTest.rgb_to_hsl_vertex_shader/* =
6977 LINUX NVIDIA OpenGL : MipmapTestES31.GenerateLowerMipsWithDraw/* = SKIP
7301 LINUX NVIDIA OpenGL : CopyTexImageTest.RGBAToRGB/ES2_OpenGL_EmulateCopyTexImage2DFromRenderbuffers/* = SKIP
7371 LINUX NVIDIA OpenGL : FramebufferTest_ES3.SurfaceDimensionsChangeAndFragCoord/* = SKIP
+8441 NVIDIA OPENGL : GLSLTest_ES3.LargeInterfaceBlockArray/* = SKIP
+8441 NVIDIA OPENGL : GLSLTest_ES3.LargeInterfaceBlockNestedArray/* = SKIP
+8441 NVIDIA GLES : GLSLTest_ES3.LargeInterfaceBlockArray/* = SKIP
+8441 NVIDIA GLES : GLSLTest_ES3.LargeInterfaceBlockNestedArray/* = SKIP
// Nvidia Vulkan
7236 NVIDIA VULKAN : GLSLTest_ES31.TessellationControlShaderMatrixCopyBug/* = SKIP
@@ -1046,6 +1052,8 @@ b/273271471 WIN INTEL VULKAN : ShaderAlgorithmTest.rgb_to_hsl_vertex_shader/* =
7389 MAC OPENGL : Texture2DTest.ManySupersedingTextureUpdates/* = SKIP
8437 MAC OPENGL : GLSLTest_ES3.LotsOfFieldsInStruct/* = SKIP
+8437 MAC OPENGL : GLSLTest_ES3.LargeInterfaceBlockArray/* = SKIP
+8437 MAC OPENGL : GLSLTest_ES3.LargeInterfaceBlockNestedArray/* = SKIP
// GL, GLES run into issues with cleanup
7495 WIN OpenGL : EGLMultiContextTest.ReuseUnterminatedDisplay/* = SKIP
diff --git a/src/tests/compiler_tests/RecordConstantPrecision_test.cpp b/src/tests/compiler_tests/RecordConstantPrecision_test.cpp
index 07923f991423f4ec1ff8cbe81fb822c2b526d149..9446576ac797c0e5db8f9c63d79adff744ea488e 100644
--- a/src/tests/compiler_tests/RecordConstantPrecision_test.cpp
+++ b/src/tests/compiler_tests/RecordConstantPrecision_test.cpp
@@ -141,11 +141,11 @@ TEST_F(RecordConstantPrecisionTest, HigherPrecisionConstantInIndex)
uniform mediump float u;
void main()
{
- const highp int a = 33000;
- mediump float b[34000];
+ const highp int a = 330;
+ mediump float b[340];
gl_FragColor = vec4(b[a]);
})";
compile(shaderString);
ASSERT_FALSE(foundInCode("const highp int s"));
- ASSERT_TRUE(foundInCode("b[33000]"));
+ ASSERT_TRUE(foundInCode("b[330]"));
}
diff --git a/src/tests/gl_tests/GLSLTest.cpp b/src/tests/gl_tests/GLSLTest.cpp
index 46f8645e5a56e527223ea4657d14dbc8619cb631..344539809b19db18b125a81791117177178de687 100644
--- a/src/tests/gl_tests/GLSLTest.cpp
+++ b/src/tests/gl_tests/GLSLTest.cpp
@@ -18091,6 +18091,138 @@ void main() {
EXPECT_EQ(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
+// length higher than can fit in SPIR-V.
+TEST_P(GLSLTest_ES3, LargeInterfaceBlockArrayPassedToFunction)
+{
+ constexpr char kFS[] = R"(#version 300 es
+precision highp float;
+uniform Large { float a[65536]; };
+float f(float b[65536])
+{
+ b[0] = 1.0;
+ return b[0] + b[1];
+}
+out vec4 color;
+void main() {
+ color = vec4(f(a), 0.0, 0.0, 1.0);
+})";
+
+ GLuint shader = CompileShader(GL_FRAGMENT_SHADER, kFS);
+ EXPECT_EQ(0u, shader);
+}
+
+// Make sure the shader in LargeInterfaceBlockArrayPassedToFunction works if the large local is
+// avoided.
+TEST_P(GLSLTest_ES3, LargeInterfaceBlockArray)
+{
+ int maxUniformBlockSize = 0;
+ glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize);
+ ANGLE_SKIP_TEST_IF(maxUniformBlockSize < 16384 * 4);
+
+ constexpr char kFS[] = R"(#version 300 es
+precision highp float;
+uniform Large { float a[16384]; };
+out vec4 color;
+void main() {
+ color = vec4(a[0], 0.0, 0.0, 1.0);
+})";
+
+ ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
+}
+
+// Similar to LargeInterfaceBlockArrayPassedToFunction, but the array is nested in a struct.
+TEST_P(GLSLTest_ES3, LargeInterfaceBlockNestedArrayPassedToFunction)
+{
+ constexpr char kFS[] = R"(#version 300 es
+precision highp float;
+struct S { float a[65536]; };
+uniform Large { S s; };
+float f(float b[65536])
+{
+ b[0] = 1.0;
+ return b[0] + b[1];
+}
+out vec4 color;
+void main() {
+ color = vec4(f(s.a), 0.0, 0.0, 1.0);
+})";
+
+ GLuint shader = CompileShader(GL_FRAGMENT_SHADER, kFS);
+ EXPECT_EQ(0u, shader);
+}
+
+// Make sure the shader in LargeInterfaceBlockNestedArrayPassedToFunction works if the large local
+// is avoided.
+TEST_P(GLSLTest_ES3, LargeInterfaceBlockNestedArray)
+{
+ int maxUniformBlockSize = 0;
+ glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &maxUniformBlockSize);
+ ANGLE_SKIP_TEST_IF(maxUniformBlockSize < 16384 * 4);
+
+ constexpr char kFS[] = R"(#version 300 es
+precision highp float;
+struct S { float a[16384]; };
+uniform Large { S s; };
+out vec4 color;
+void main() {
+ color = vec4(s.a[0], 0.0, 0.0, 1.0);
+})";
+
+ ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), kFS);
+}
+
+// Similar to LargeInterfaceBlockArrayPassedToFunction, but the large array is copied to a local
+// variable instead.
+TEST_P(GLSLTest_ES3, LargeInterfaceBlockArrayCopiedToLocal)
+{
+ constexpr char kFS[] = R"(#version 300 es
+precision highp float;
+uniform Large { float a[65536]; };
+out vec4 color;
+void main() {
+ float b[65536] = a;
+ color = vec4(b[0], 0.0, 0.0, 1.0);
+})";
+
+ GLuint shader = CompileShader(GL_FRAGMENT_SHADER, kFS);
+ EXPECT_EQ(0u, shader);
+}
+
+// Similar to LargeInterfaceBlockArrayCopiedToLocal, but the array is nested in a struct
+TEST_P(GLSLTest_ES3, LargeInterfaceBlockNestedArrayCopiedToLocal)
+{
+ constexpr char kFS[] = R"(#version 300 es
+precision highp float;
+struct S { float a[65536]; };
+uniform Large { S s; };
+out vec4 color;
+void main() {
+ S s2 = s;
+ color = vec4(s2.a[0], 0.0, 0.0, 1.0);
+})";
+
+ GLuint shader = CompileShader(GL_FRAGMENT_SHADER, kFS);
+ EXPECT_EQ(0u, shader);
+}
+
+// Test that too large varyings are rejected.
+TEST_P(GLSLTest_ES3, LargeArrayVarying)
+{
+ constexpr char kFS[] = R"(#version 300 es
+precision highp float;
+in float a[65536];
+out vec4 color;
+void main() {
+ color = vec4(a[0], 0.0, 0.0, 1.0);
+})";
+
+ GLuint shader = CompileShader(GL_FRAGMENT_SHADER, kFS);
+ EXPECT_EQ(0u, shader);
+}
+
} // anonymous namespace
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(GLSLTest);

View File

@@ -0,0 +1,180 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shahbaz Youssefi <syoussefi@chromium.org>
Date: Thu, 30 Nov 2023 13:53:00 -0500
Subject: M120: Translator: Optimize field-name-collision check
As each field of the struct was encountered, its name was linearly
checked against previously added fields. That's O(n^2).
The name collision check is now moved to when the struct is completely
defined, and is done with an unordered_map.
Bug: chromium:1505009
Change-Id: I3fbc23493e5a03e61b631af615cffaf9995fd566
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5143826
Reviewed-by: Cody Northrop <cnorthrop@google.com>
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index 28ac378cab6cb3812a43b6064733d7354ee694bc..7c90ea4f1d23a8af0cab1d44124eea021a27a16d 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -4726,6 +4726,9 @@ TIntermDeclaration *TParseContext::addInterfaceBlock(
const TVector<unsigned int> *arraySizes,
const TSourceLoc &arraySizesLine)
{
+ // Ensure there are no duplicate field names
+ checkDoesNotHaveDuplicateFieldNames(fieldList, nameLine);
+
const bool isGLPerVertex = blockName == "gl_PerVertex";
// gl_PerVertex is allowed to be redefined and therefore not reserved
if (!isGLPerVertex)
@@ -6269,28 +6272,25 @@ TDeclarator *TParseContext::parseStructArrayDeclarator(const ImmutableString &id
return new TDeclarator(identifier, arraySizes, loc);
}
-void TParseContext::checkDoesNotHaveDuplicateFieldName(const TFieldList::const_iterator begin,
- const TFieldList::const_iterator end,
- const ImmutableString &name,
- const TSourceLoc &location)
+void TParseContext::checkDoesNotHaveDuplicateFieldNames(const TFieldList *fields,
+ const TSourceLoc &location)
{
- for (auto fieldIter = begin; fieldIter != end; ++fieldIter)
+ TUnorderedMap<ImmutableString, uint32_t, ImmutableString::FowlerNollVoHash<sizeof(size_t)>>
+ fieldNames;
+ for (TField *field : *fields)
{
- if ((*fieldIter)->name() == name)
+ // Note: operator[] adds this name to the map if it doesn't already exist, and initializes
+ // its value to 0.
+ uint32_t count = ++fieldNames[field->name()];
+ if (count != 1)
{
- error(location, "duplicate field name in structure", name);
+ error(location, "Duplicate field name in structure", field->name());
}
}
}
TFieldList *TParseContext::addStructFieldList(TFieldList *fields, const TSourceLoc &location)
{
- for (TFieldList::const_iterator fieldIter = fields->begin(); fieldIter != fields->end();
- ++fieldIter)
- {
- checkDoesNotHaveDuplicateFieldName(fields->begin(), fieldIter, (*fieldIter)->name(),
- location);
- }
return fields;
}
@@ -6298,12 +6298,8 @@ TFieldList *TParseContext::combineStructFieldLists(TFieldList *processedFields,
const TFieldList *newlyAddedFields,
const TSourceLoc &location)
{
- for (TField *field : *newlyAddedFields)
- {
- checkDoesNotHaveDuplicateFieldName(processedFields->begin(), processedFields->end(),
- field->name(), location);
- processedFields->push_back(field);
- }
+ processedFields->insert(processedFields->end(), newlyAddedFields->begin(),
+ newlyAddedFields->end());
return processedFields;
}
@@ -6396,7 +6392,10 @@ TTypeSpecifierNonArray TParseContext::addStructure(const TSourceLoc &structLine,
}
}
- // ensure we do not specify any storage qualifiers on the struct members
+ // Ensure there are no duplicate field names
+ checkDoesNotHaveDuplicateFieldNames(fieldList, structLine);
+
+ // Ensure we do not specify any storage qualifiers on the struct members
for (unsigned int typeListIndex = 0; typeListIndex < fieldList->size(); typeListIndex++)
{
TField &field = *(*fieldList)[typeListIndex];
diff --git a/src/compiler/translator/ParseContext.h b/src/compiler/translator/ParseContext.h
index 9e1354ef816705fb512b40b329794e0282129807..b63dbbadd146d1a004513823de72c89240a31929 100644
--- a/src/compiler/translator/ParseContext.h
+++ b/src/compiler/translator/ParseContext.h
@@ -354,10 +354,7 @@ class TParseContext : angle::NonCopyable
const TSourceLoc &loc,
const TVector<unsigned int> *arraySizes);
- void checkDoesNotHaveDuplicateFieldName(const TFieldList::const_iterator begin,
- const TFieldList::const_iterator end,
- const ImmutableString &name,
- const TSourceLoc &location);
+ void checkDoesNotHaveDuplicateFieldNames(const TFieldList *fields, const TSourceLoc &location);
TFieldList *addStructFieldList(TFieldList *fields, const TSourceLoc &location);
TFieldList *combineStructFieldLists(TFieldList *processedFields,
const TFieldList *newlyAddedFields,
diff --git a/src/tests/angle_end2end_tests_expectations.txt b/src/tests/angle_end2end_tests_expectations.txt
index cadf4afaed84c10040b87c8936c4a0ebbfd6d514..3d356609031820b92c230ac7ff836327b78ec834 100644
--- a/src/tests/angle_end2end_tests_expectations.txt
+++ b/src/tests/angle_end2end_tests_expectations.txt
@@ -1045,6 +1045,8 @@ b/273271471 WIN INTEL VULKAN : ShaderAlgorithmTest.rgb_to_hsl_vertex_shader/* =
7389 SWIFTSHADER : Texture2DTest.ManySupersedingTextureUpdates/* = SKIP
7389 MAC OPENGL : Texture2DTest.ManySupersedingTextureUpdates/* = SKIP
+8437 MAC OPENGL : GLSLTest_ES3.LotsOfFieldsInStruct/* = SKIP
+
// GL, GLES run into issues with cleanup
7495 WIN OpenGL : EGLMultiContextTest.ReuseUnterminatedDisplay/* = SKIP
7495 WIN GLES : EGLMultiContextTest.ReuseUnterminatedDisplay/* = SKIP
diff --git a/src/tests/gl_tests/GLSLTest.cpp b/src/tests/gl_tests/GLSLTest.cpp
index 0d0d3b5468019b897af2487d72112fab829f47da..9b42b6d9221366e9bc7b6263bf8e14b77ca7694d 100644
--- a/src/tests/gl_tests/GLSLTest.cpp
+++ b/src/tests/gl_tests/GLSLTest.cpp
@@ -18020,6 +18020,50 @@ TEST_P(GLSLTest_ES31, ESSL31ExtensionMacros)
ASSERT_GL_NO_ERROR();
}
+// Test that Metal compiler doesn't inline non-const globals
+TEST_P(WebGLGLSLTest, InvalidGlobalsNotInlined)
+{
+ constexpr char kFS[] = R"(#version 100
+ precision highp float;
+ float v1 = 0.5;
+ float v2 = v1;
+
+ float f1() {
+ return v2;
+ }
+
+ void main() {
+ gl_FragColor = vec4(v1 + f1(),0.0,0.0, 1.0);
+ })";
+ ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), kFS);
+ ASSERT_GL_NO_ERROR();
+}
+
+// Test that a struct can have lots of fields. Regression test for an inefficient O(n^2) check for
+// fields having unique names.
+TEST_P(GLSLTest_ES3, LotsOfFieldsInStruct)
+{
+ std::ostringstream fs;
+ fs << R"(#version 300 es
+precision highp float;
+struct LotsOfFields
+{
+)";
+ // Note: 16383 is the SPIR-V limit for struct member count.
+ for (uint32_t i = 0; i < 16383; ++i)
+ {
+ fs << " float field" << i << ";\n";
+ }
+ fs << R"(};
+uniform B { LotsOfFields s; };
+out vec4 color;
+void main() {
+ color = vec4(s.field0, 0.0, 0.0, 1.0);
+})";
+
+ ANGLE_GL_PROGRAM(program, essl3_shaders::vs::Simple(), fs.str().c_str());
+}
+
} // anonymous namespace
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(GLSLTest);

View File

@@ -0,0 +1,135 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shahbaz Youssefi <syoussefi@chromium.org>
Date: Tue, 5 Dec 2023 13:36:53 -0500
Subject: M120: Vulkan: Don't crash when glCopyTexImage2D redefines itself
The Vulkan backend marks a level being redefined as such before doing
the copy. If a single-level texture was being redefined, it releases it
so it can be immediately reallocated. If the source of the copy is the
same texture, this causes a crash.
This can be properly supported by using a temp image to do the copy, but
that is not implemented in this change.
Bug: chromium:1501798
Change-Id: I3a902b1e9eec41afd385d9c75a8c95dc986070a8
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5143829
Reviewed-by: Cody Northrop <cnorthrop@google.com>
diff --git a/src/libANGLE/renderer/vulkan/TextureVk.cpp b/src/libANGLE/renderer/vulkan/TextureVk.cpp
index da27d3cfb0932408f14cd2fd6df88294f4b07363..885982b95e70f0c49f89b565fa0f3331333eaac1 100644
--- a/src/libANGLE/renderer/vulkan/TextureVk.cpp
+++ b/src/libANGLE/renderer/vulkan/TextureVk.cpp
@@ -723,8 +723,28 @@ angle::Result TextureVk::copyImage(const gl::Context *context,
gl::GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE);
const vk::Format &vkFormat = renderer->getFormat(internalFormatInfo.sizedInternalFormat);
+ // The texture level being redefined might be the same as the one bound to the framebuffer.
+ // This _could_ be supported by using a temp image before redefining the level (and potentially
+ // discarding the image). However, this is currently unimplemented.
+ FramebufferVk *framebufferVk = vk::GetImpl(source);
+ RenderTargetVk *colorReadRT = framebufferVk->getColorReadRenderTarget();
+ vk::ImageHelper *srcImage = &colorReadRT->getImageForCopy();
+ const bool isCubeMap = index.getType() == gl::TextureType::CubeMap;
+ gl::LevelIndex levelIndex(getNativeImageIndex(index).getLevelIndex());
+ const uint32_t layerIndex = index.hasLayer() ? index.getLayerIndex() : 0;
+ const uint32_t redefinedFace = isCubeMap ? layerIndex : 0;
+ const uint32_t sourceFace = isCubeMap ? colorReadRT->getLayerIndex() : 0;
+ const bool isSelfCopy = mImage == srcImage && levelIndex == colorReadRT->getLevelIndex() &&
+ redefinedFace == sourceFace;
+
ANGLE_TRY(redefineLevel(context, index, vkFormat, newImageSize));
+ if (isSelfCopy)
+ {
+ UNIMPLEMENTED();
+ return angle::Result::Continue;
+ }
+
return copySubImageImpl(context, index, gl::Offset(0, 0, 0), sourceArea, internalFormatInfo,
source);
}
@@ -1798,7 +1818,8 @@ angle::Result TextureVk::redefineLevel(const gl::Context *context,
mImage->getLevelCount() == 1 && mImage->getFirstAllocatedLevel() == levelIndexGL;
// If incompatible, and redefining the single-level image, release it so it can be
- // recreated immediately. This is an optimization to avoid an extra copy.
+ // recreated immediately. This is needed so that the texture can be reallocated with
+ // the correct format/size.
if (!isCompatibleRedefinition && isUpdateToSingleLevelImage)
{
releaseImage(contextVk);
diff --git a/src/tests/angle_end2end_tests_expectations.txt b/src/tests/angle_end2end_tests_expectations.txt
index cfa70eef00a1e8d67f9fbf07ee74928b55da8b92..8b4dac5beab0b8d884116147ba3e61f6133e92a9 100644
--- a/src/tests/angle_end2end_tests_expectations.txt
+++ b/src/tests/angle_end2end_tests_expectations.txt
@@ -29,6 +29,8 @@
6989 GLES : BlitFramebufferTestES31.OOBResolve/* = SKIP
7881 VULKAN : MultithreadingTestES3.UnsynchronizedTextureReads/* = SKIP
7881 VULKAN : MultithreadingTestES3.UnsynchronizedTextureReads2/* = SKIP
+// Incorrectly handled pretty much in all backends
+8446 : CopyTexImageTestES3.RedefineSameLevel/* = SKIP
6743 OPENGL : SimpleStateChangeTestES3.RespecifyBufferAfterBeginTransformFeedback/* = SKIP
6743 GLES : SimpleStateChangeTestES3.RespecifyBufferAfterBeginTransformFeedback/* = SKIP
diff --git a/src/tests/gl_tests/CopyTexImageTest.cpp b/src/tests/gl_tests/CopyTexImageTest.cpp
index 3d0cf40ab244a5463c2e4b3d53470d6f932e357b..d6949280ed301fc918e397dad26b9efec1c32f23 100644
--- a/src/tests/gl_tests/CopyTexImageTest.cpp
+++ b/src/tests/gl_tests/CopyTexImageTest.cpp
@@ -1262,6 +1262,56 @@ TEST_P(CopyTexImageTestES3, 3DSubImageDrawMismatchedTextureTypes)
glBindTexture(GL_TEXTURE_3D, 0);
}
+// Make sure a single-level texture can be redefined through glCopyTexImage2D from a framebuffer
+// bound to the same texture. Regression test for a bug in the Vulkan backend where the texture was
+// released before the copy.
+TEST_P(CopyTexImageTestES3, RedefineSameLevel)
+{
+ constexpr GLsizei kSize = 32;
+ constexpr GLsizei kHalfSize = kSize / 2;
+
+ // Create a single-level texture with four colors in different regions.
+ std::vector<GLColor> initData(kSize * kSize);
+ for (GLsizei y = 0; y < kSize; ++y)
+ {
+ const bool isTop = y < kHalfSize;
+ for (GLsizei x = 0; x < kSize; ++x)
+ {
+ const bool isLeft = x < kHalfSize;
+
+ GLColor color = isLeft && isTop ? GLColor::red
+ : isLeft && !isTop ? GLColor::green
+ : !isLeft && isTop ? GLColor::blue
+ : GLColor::yellow;
+ color.A = 123;
+ initData[y * kSize + x] = color;
+ }
+ }
+
+ GLTexture tex;
+ glBindTexture(GL_TEXTURE_2D, tex);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ initData.data());
+
+ // Bind the framebuffer to the same texture
+ GLFramebuffer framebuffer;
+ glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
+
+ // Redefine the texture
+ glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, kHalfSize / 2, kHalfSize / 2, kHalfSize, kHalfSize,
+ 0);
+
+ // Verify copy is done correctly.
+ ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
+
+ EXPECT_PIXEL_RECT_EQ(0, 0, kHalfSize / 2, kHalfSize / 2, GLColor::red);
+ EXPECT_PIXEL_RECT_EQ(kHalfSize / 2, 0, kHalfSize / 2, kHalfSize / 2, GLColor::blue);
+ EXPECT_PIXEL_RECT_EQ(0, kHalfSize / 2, kHalfSize / 2, kHalfSize / 2, GLColor::green);
+ EXPECT_PIXEL_RECT_EQ(kHalfSize / 2, kHalfSize / 2, kHalfSize / 2, kHalfSize / 2,
+ GLColor::yellow);
+}
+
ANGLE_INSTANTIATE_TEST(CopyTexImageTest,
ANGLE_ALL_TEST_PLATFORMS_ES2,
ES2_D3D11_PRESENT_PATH_FAST(),

View File

@@ -140,3 +140,27 @@ avoid_allocating_recordid_objects_in_elementtiming_and_lcp.patch
cherry-pick-80106e31c7ea.patch
gpu_use_load_program_shader_shm_count_on_drdc_thread.patch
crash_gpu_process_and_clear_shader_cache_when_skia_reports.patch
cherry-pick-3df423a5b8de.patch
scale_rects_properly_in_syncgetfirstrectforrange.patch
cherry-pick-9384cddc7705.patch
fix_restore_original_resize_performance_on_macos.patch
cherry-pick-3f45b1af5e41.patch
cherry-pick-e13061c50998.patch
cherry-pick-5fde415e06f9.patch
cherry-pick-8d607d3921b8.patch
cherry-pick-021598ea43c1.patch
cherry-pick-76340163a820.patch
cherry-pick-f15cfb9371c4.patch
cherry-pick-4ca62c7a8b88.patch
cherry-pick-5b2fddadaa12.patch
cherry-pick-50a1bddfca85.patch
reland_mojom_ts_generator_handle_empty_module_path_identically_to.patch
cherry-pick-c1cda70a433a.patch
cherry-pick-cc07a95bc309.patch
safely_crash_on_dangling_profile.patch
cherry-pick-ee0b8769f428.patch
cherry-pick-1f8bec968902.patch
cherry-pick-4a98f9e304be.patch
fix_racy_iterator_use_in_node_addconnection.patch
fix_a_crash_when_a_bmp_image_contains_an_unnecessary_eof_code.patch
m120_ipcz_fix_a_few_weak_asserts.patch

View File

@@ -0,0 +1,69 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Guido Urdaneta <guidou@chromium.org>
Date: Mon, 4 Dec 2023 23:00:41 +0000
Subject: Drop frames received on the wrong task runner
It can happen during transfer that a frame is posted from the
background media thread to the task runner of the old execution
context, which can lead to races and UAF.
This CL makes underlying sources drop frames received on the
wrong task runner to avoid the problem.
(cherry picked from commit 9d042e0d498356185fe9eb33c53b69fab33d06bf)
Bug: 1505708
Change-Id: I686228d88cb1c48bdf8c0b6bf85edd280a54300a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5077845
Commit-Queue: Guido Urdaneta <guidou@chromium.org>
Reviewed-by: Tony Herre <toprice@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1231802}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5082444
Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Auto-Submit: Guido Urdaneta <guidou@chromium.org>
Cr-Commit-Position: refs/branch-heads/6099@{#1370}
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_underlying_source.cc b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_underlying_source.cc
index b5a2f71bae81bba6e61d8f303d24a9df874ae885..4c7b0b982e3d314749e39178eb0fca706d11bd85 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_underlying_source.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_audio_underlying_source.cc
@@ -58,7 +58,15 @@ void RTCEncodedAudioUnderlyingSource::Trace(Visitor* visitor) const {
void RTCEncodedAudioUnderlyingSource::OnFrameFromSource(
std::unique_ptr<webrtc::TransformableAudioFrameInterface> webrtc_frame) {
- DCHECK(task_runner_->BelongsToCurrentThread());
+ // It can happen that a frame is posted to the task runner of the old
+ // execution context during a stream transfer to a new context.
+ // TODO(https://crbug.com/1506631): Make the state updates related to the
+ // transfer atomic and turn this into a DCHECK.
+ if (!task_runner_->BelongsToCurrentThread()) {
+ DVLOG(1) << "Dropped frame posted to incorrect task runner. This can "
+ "happen during transfer.";
+ return;
+ }
// If the source is canceled or there are too many queued frames,
// drop the new frame.
if (!disconnect_callback_ || !GetExecutionContext()) {
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_source.cc b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_source.cc
index 54ca7d1529b1772200c3691b56e847acc42d086d..8fb1d8460e289cd5e6764271f79dada7f121cb1b 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_source.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_source.cc
@@ -58,7 +58,15 @@ void RTCEncodedVideoUnderlyingSource::Trace(Visitor* visitor) const {
void RTCEncodedVideoUnderlyingSource::OnFrameFromSource(
std::unique_ptr<webrtc::TransformableVideoFrameInterface> webrtc_frame) {
- DCHECK(task_runner_->BelongsToCurrentThread());
+ // It can happen that a frame is posted to the task runner of the old
+ // execution context during a stream transfer to a new context.
+ // TODO(https://crbug.com/1506631): Make the state updates related to the
+ // transfer atomic and turn this into a DCHECK.
+ if (!task_runner_->BelongsToCurrentThread()) {
+ DVLOG(1) << "Dropped frame posted to incorrect task runner. This can "
+ "happen during transfer.";
+ return;
+ }
// If the source is canceled or there are too many queued frames,
// drop the new frame.
if (!disconnect_callback_ || !GetExecutionContext()) {

View File

@@ -0,0 +1,125 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Tsuyoshi Horo <horo@chromium.org>
Date: Wed, 24 Jan 2024 02:04:24 +0000
Subject: Fix UAF in SourceStreamToDataPipe
SourceStreamToDataPipe::ReadMore() is passing a callback with
Unretained(this) to net::SourceStream::Read(). But this callback may be
called even after the SourceStream is destructed. This is causing UAF
issue (crbug.com/1511085).
To solve this problem, this CL changes ReadMore() method to pass a
callback with a weak ptr of this.
(cherry picked from commit 6e36a69da1b73f9aea9c54bfbe6c5b9cb2c672a5)
Bug: 1511085
Change-Id: Idd4e34ff300ff5db2de1de7b303841c7db3a964a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5179746
Reviewed-by: Adam Rice <ricea@chromium.org>
Commit-Queue: Tsuyoshi Horo <horo@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1244526}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5231558
Reviewed-by: Kenichi Ishibashi <bashi@chromium.org>
Cr-Commit-Position: refs/branch-heads/6099@{#1860}
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
diff --git a/services/network/public/cpp/source_stream_to_data_pipe.cc b/services/network/public/cpp/source_stream_to_data_pipe.cc
index bfd85b1a00b216b52ae816ca29cb66ddabe20b6d..07afd58a40f92485ded07c535092a891c5140c7b 100644
--- a/services/network/public/cpp/source_stream_to_data_pipe.cc
+++ b/services/network/public/cpp/source_stream_to_data_pipe.cc
@@ -55,9 +55,9 @@ void SourceStreamToDataPipe::ReadMore() {
scoped_refptr<net::IOBuffer> buffer(
new network::NetToMojoIOBuffer(pending_write_.get()));
- int result = source_->Read(
- buffer.get(), base::checked_cast<int>(num_bytes),
- base::BindOnce(&SourceStreamToDataPipe::DidRead, base::Unretained(this)));
+ int result = source_->Read(buffer.get(), base::checked_cast<int>(num_bytes),
+ base::BindOnce(&SourceStreamToDataPipe::DidRead,
+ weak_factory_.GetWeakPtr()));
if (result != net::ERR_IO_PENDING)
DidRead(result);
diff --git a/services/network/public/cpp/source_stream_to_data_pipe_unittest.cc b/services/network/public/cpp/source_stream_to_data_pipe_unittest.cc
index 7061418c5141d936f04b1193c98e66efc5e72ac5..54159df39afa7cf6e2faa51da185dc034b923209 100644
--- a/services/network/public/cpp/source_stream_to_data_pipe_unittest.cc
+++ b/services/network/public/cpp/source_stream_to_data_pipe_unittest.cc
@@ -6,7 +6,9 @@
#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
+#include "base/test/bind.h"
#include "base/test/task_environment.h"
+#include "net/base/net_errors.h"
#include "net/filter/mock_source_stream.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
@@ -42,6 +44,33 @@ struct SourceStreamToDataPipeTestParam {
const ReadResultType read_result_type;
};
+class DummyPendingSourceStream : public net::SourceStream {
+ public:
+ DummyPendingSourceStream() : net::SourceStream(SourceStream::TYPE_NONE) {}
+ ~DummyPendingSourceStream() override = default;
+
+ DummyPendingSourceStream(const DummyPendingSourceStream&) = delete;
+ DummyPendingSourceStream& operator=(const DummyPendingSourceStream&) = delete;
+
+ // SourceStream implementation
+ int Read(net::IOBuffer* dest_buffer,
+ int buffer_size,
+ net::CompletionOnceCallback callback) override {
+ callback_ = std::move(callback);
+ return net::ERR_IO_PENDING;
+ }
+ std::string Description() const override { return ""; }
+ bool MayHaveMoreBytes() const override { return true; }
+
+ net::CompletionOnceCallback TakeCompletionCallback() {
+ CHECK(callback_);
+ return std::move(callback_);
+ }
+
+ private:
+ net::CompletionOnceCallback callback_;
+};
+
} // namespace
class SourceStreamToDataPipeTest
@@ -212,4 +241,33 @@ TEST_P(SourceStreamToDataPipeTest, MayHaveMoreBytes) {
EXPECT_EQ(ReadPipe(&output), net::OK);
EXPECT_EQ(output, message);
}
+
+TEST(SourceStreamToDataPipeCallbackTest, CompletionCallbackAfterDestructed) {
+ base::test::TaskEnvironment task_environment;
+
+ std::unique_ptr<DummyPendingSourceStream> source =
+ std::make_unique<DummyPendingSourceStream>();
+ DummyPendingSourceStream* source_ptr = source.get();
+ const MojoCreateDataPipeOptions data_pipe_options{
+ sizeof(MojoCreateDataPipeOptions), MOJO_CREATE_DATA_PIPE_FLAG_NONE, 1, 1};
+ mojo::ScopedDataPipeProducerHandle producer_end;
+ mojo::ScopedDataPipeConsumerHandle consumer_end;
+ CHECK_EQ(MOJO_RESULT_OK, mojo::CreateDataPipe(&data_pipe_options,
+ producer_end, consumer_end));
+
+ std::unique_ptr<SourceStreamToDataPipe> adapter =
+ std::make_unique<SourceStreamToDataPipe>(std::move(source),
+ std::move(producer_end));
+ bool callback_called = false;
+ adapter->Start(
+ base::BindLambdaForTesting([&](int result) { callback_called = true; }));
+ net::CompletionOnceCallback callback = source_ptr->TakeCompletionCallback();
+ adapter.reset();
+
+ // Test that calling `callback` after deleting `adapter` must not cause UAF
+ // (crbug.com/1511085).
+ std::move(callback).Run(net::ERR_FAILED);
+ EXPECT_FALSE(callback_called);
+}
+
} // namespace network

View File

@@ -0,0 +1,57 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Hongchan Choi <hongchan@chromium.org>
Date: Fri, 3 Nov 2023 16:39:55 +0000
Subject: Check context status before recreating platform destination
Changing the channel count in the RealtimeAudioDestinationHandler will
trigger the recreation of the platform destination. This in turn can
activate the audio rendering thread.
This CL adds a check to prevent this from happening after the handler
is garbage collected.
(cherry picked from commit 4997f2ba263ff7e1dbc7987dd3665459be14dffe)
Bug: 1497859
Test: Locally confirmed with ASAN
Change-Id: I5d2649f3fd3639779ae40b0ca4ef2fe305653421
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4995928
Commit-Queue: Hongchan Choi <hongchan@chromium.org>
Reviewed-by: Michael Wilson <mjwilson@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1217868}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5004961
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/branch-heads/5993@{#1520}
Cr-Branched-From: 511350718e646be62331ae9d7213d10ec320d514-refs/heads/main@{#1192594}
diff --git a/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_handler.cc b/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_handler.cc
index 6781dcff462db872d1f5a786aef0c89f43189100..2e4757d155800700b7c6a8b7cbf2e02250cfce65 100644
--- a/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_handler.cc
+++ b/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_handler.cc
@@ -118,12 +118,21 @@ void RealtimeAudioDestinationHandler::SetChannelCount(
uint32_t old_channel_count = ChannelCount();
AudioHandler::SetChannelCount(channel_count, exception_state);
- // Stop, re-create and start the destination to apply the new channel count.
- if (ChannelCount() != old_channel_count && !exception_state.HadException()) {
- StopPlatformDestination();
- CreatePlatformDestination();
- StartPlatformDestination();
+ // After the context is closed, changing channel count will be ignored
+ // because it will trigger the recreation of the platform destination. This
+ // in turn can activate the audio rendering thread.
+ AudioContext* context = static_cast<AudioContext*>(Context());
+ CHECK(context);
+ if (context->ContextState() == AudioContext::kClosed ||
+ ChannelCount() == old_channel_count ||
+ exception_state.HadException()) {
+ return;
}
+
+ // Stop, re-create and start the destination to apply the new channel count.
+ StopPlatformDestination();
+ CreatePlatformDestination();
+ StartPlatformDestination();
}
void RealtimeAudioDestinationHandler::StartRendering() {

View File

@@ -0,0 +1,48 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alvin Ji <alvinji@chromium.org>
Date: Mon, 13 Nov 2023 20:24:24 +0000
Subject: Check context status before creating new platform destination
RealtimeAudioDestinationHandler::SetSinkDescriptor creates new
destination platofrm without validating context status. This can
reactivate the audio rendering thread when AudioContext is already in
closed state.
(cherry picked from commit 0f9bb9a1083865d4e51059e588f27f729ab32753)
Bug: 1500856
Change-Id: If1fd531324b56fcdc38d315fd84d4cec577a14bc
Test: Locally confirmed with ASAN
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5021160
Reviewed-by: Alvin Ji <alvinji@chromium.org>
Commit-Queue: Alvin Ji <alvinji@chromium.org>
Reviewed-by: Hongchan Choi <hongchan@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1223168}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5026373
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Commit-Queue: Hongchan Choi <hongchan@chromium.org>
Cr-Commit-Position: refs/branch-heads/6099@{#607}
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
diff --git a/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_handler.cc b/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_handler.cc
index 2e4757d155800700b7c6a8b7cbf2e02250cfce65..c27eb3ac07f22a4cd1ae2f86da896d255a761292 100644
--- a/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_handler.cc
+++ b/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_handler.cc
@@ -405,6 +405,17 @@ void RealtimeAudioDestinationHandler::SetSinkDescriptor(
GetCallbackBufferSize()));
DCHECK(IsMainThread());
+ // After the context is closed, `SetSinkDescriptor` request will be ignored
+ // because it will trigger the recreation of the platform destination. This in
+ // turn can activate the audio rendering thread.
+ AudioContext* context = static_cast<AudioContext*>(Context());
+ CHECK(context);
+ if (context->ContextState() == AudioContext::kClosed) {
+ std::move(callback).Run(
+ media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL);
+ return;
+ }
+
// Create a pending AudioDestination to replace the current one.
scoped_refptr<AudioDestination> pending_platform_destination =
AudioDestination::Create(

View File

@@ -0,0 +1,67 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Peter=20Bostr=C3=B6m?= <pbos@chromium.org>
Date: Fri, 26 Jan 2024 19:37:57 +0000
Subject: Speculatively fix race in mojo ShutDownOnIOThread
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This acquires `write_lock_` before resetting handles used by WriteNoLock
(which is called under the same lock in another thread). We also set
`reject_writes_` to prevent future write attempts after shutdown. That
seems strictly more correct.
We also acquire `fds_to_close_lock_` before clearing the FDs.
I was unable to repro locally as content_browsertests just times out
in my local setup without reporting anything interesting. This seems
strictly more correct though.
(cherry picked from commit 9755d9d81e4a8cb5b4f76b23b761457479dbb06b)
Bug: 1519980
Change-Id: I96279936ca908ecb98eddd381df20d61597cba43
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5226127
Auto-Submit: Peter Boström <pbos@chromium.org>
Reviewed-by: Ken Rockot <rockot@google.com>
Commit-Queue: Ken Rockot <rockot@google.com>
Commit-Queue: Peter Boström <pbos@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1250580}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5239564
Cr-Commit-Position: refs/branch-heads/6099@{#1883}
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
diff --git a/mojo/core/channel_posix.cc b/mojo/core/channel_posix.cc
index 0a3596382d0e9a40c72bfb4ead6f0338a61253d6..eae6b0768463679b5043514dc5745da52b80ae10 100644
--- a/mojo/core/channel_posix.cc
+++ b/mojo/core/channel_posix.cc
@@ -246,16 +246,21 @@ void ChannelPosix::WaitForWriteOnIOThreadNoLock() {
void ChannelPosix::ShutDownOnIOThread() {
base::CurrentThread::Get()->RemoveDestructionObserver(this);
- read_watcher_.reset();
- write_watcher_.reset();
- if (leak_handle_) {
- std::ignore = socket_.release();
- } else {
- socket_.reset();
- }
+ {
+ base::AutoLock lock(write_lock_);
+ reject_writes_ = true;
+ read_watcher_.reset();
+ write_watcher_.reset();
+ if (leak_handle_) {
+ std::ignore = socket_.release();
+ } else {
+ socket_.reset();
+ }
#if BUILDFLAG(IS_IOS)
- fds_to_close_.clear();
+ base::AutoLock fd_lock(fds_to_close_lock_);
+ fds_to_close_.clear();
#endif
+ }
// May destroy the |this| if it was the last reference.
self_ = nullptr;

View File

@@ -0,0 +1,43 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Vasiliy Telezhnikov <vasilyt@chromium.org>
Date: Thu, 7 Dec 2023 16:56:57 +0000
Subject: Check for slugs count before deserializing Slugs in DrawSlugOp
Count is part of serialized data and while we never serialize values
less then 1, it can be any value when coming over IPC, we should check
that it's positive before substacting one.
(cherry picked from commit 0527e0d5b08a13d63f4f1eeefa1b86ecfd0cb63b)
Bug: 1506726
Change-Id: I244f50a682f2e852b22ba88f1e9cddddb0fdfcb9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5078779
Reviewed-by: Peng Huang <penghuang@chromium.org>
Commit-Queue: Vasiliy Telezhnikov <vasilyt@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1232013}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5096809
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/branch-heads/6099@{#1428}
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
diff --git a/cc/paint/paint_op.cc b/cc/paint/paint_op.cc
index ea103192096b1316f2a9a31cf3478e6dafe66788..5ff86b59f7b7b27e21bfdb95da637fed9cee0420 100644
--- a/cc/paint/paint_op.cc
+++ b/cc/paint/paint_op.cc
@@ -974,10 +974,12 @@ PaintOp* DrawSlugOp::Deserialize(PaintOpReader& reader, void* output) {
reader.Read(&op->flags);
unsigned int count = 0;
reader.Read(&count);
- reader.Read(&op->slug);
- op->extra_slugs.resize(count - 1);
- for (auto& extra_slug : op->extra_slugs) {
- reader.Read(&extra_slug);
+ if (count > 0) {
+ reader.Read(&op->slug);
+ op->extra_slugs.resize(count - 1);
+ for (auto& extra_slug : op->extra_slugs) {
+ reader.Read(&extra_slug);
+ }
}
return op;
}

View File

@@ -0,0 +1,117 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Austin Eng <enga@chromium.org>
Date: Tue, 19 Dec 2023 17:25:51 +0000
Subject: Use cross thread handles to bind args for async webgpu context
creation
(cherry picked from commit 542b278a0c1de7202f4bf5e3e5cbdc2dd6c337d4)
Fixed: 1506923
Change-Id: I174703cbd993471e3afb39c0cfa4cce2770755f7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5113019
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Stephen White <senorblanco@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1237179}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5133239
Cr-Commit-Position: refs/branch-heads/6099@{#1551}
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
diff --git a/third_party/blink/renderer/modules/webgpu/gpu.cc b/third_party/blink/renderer/modules/webgpu/gpu.cc
index dbe8ab27798ca1a9aa80f34cbfc88f52adfe3b84..9627347a3b495dffa20f3aa0cfbcaa524eced686 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu.cc
@@ -39,11 +39,13 @@
#include "third_party/blink/renderer/platform/graphics/gpu/dawn_control_client_holder.h"
#include "third_party/blink/renderer/platform/graphics/gpu/webgpu_callback.h"
#include "third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_util.h"
+#include "third_party/blink/renderer/platform/heap/cross_thread_handle.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/heap/thread_state.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
#include "third_party/blink/renderer/platform/privacy_budget/identifiability_digest_helpers.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
namespace blink {
@@ -300,9 +302,19 @@ void GPU::RequestAdapterImpl(ScriptState* script_state,
CreateWebGPUGraphicsContext3DProviderAsync(
execution_context->Url(),
execution_context->GetTaskRunner(TaskType::kWebGPU),
- WTF::BindOnce(
- [](GPU* gpu, ExecutionContext* execution_context,
+ CrossThreadBindOnce(
+ [](CrossThreadHandle<GPU> gpu_handle,
+ CrossThreadHandle<ExecutionContext> execution_context_handle,
std::unique_ptr<WebGraphicsContext3DProvider> context_provider) {
+ auto unwrap_gpu = MakeUnwrappingCrossThreadHandle(gpu_handle);
+ auto unwrap_execution_context =
+ MakeUnwrappingCrossThreadHandle(execution_context_handle);
+ if (!unwrap_gpu || !unwrap_execution_context) {
+ return;
+ }
+ auto* gpu = unwrap_gpu.GetOnCreationThread();
+ auto* execution_context =
+ unwrap_execution_context.GetOnCreationThread();
const KURL& url = execution_context->Url();
context_provider =
CheckContextProvider(url, std::move(context_provider));
@@ -324,7 +336,8 @@ void GPU::RequestAdapterImpl(ScriptState* script_state,
std::move(callback).Run();
}
},
- WrapPersistent(this), WrapPersistent(execution_context)));
+ MakeCrossThreadHandle(this),
+ MakeCrossThreadHandle(execution_context)));
return;
}
diff --git a/third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_util.cc b/third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_util.cc
index f859f3e62c54d26453a145321f697c5116c13348..3d9890b9b4a58a30a11e501fdb9297f4a57b601b 100644
--- a/third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_util.cc
+++ b/third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_util.cc
@@ -121,8 +121,8 @@ CreateWebGPUGraphicsContext3DProvider(const KURL& url) {
void CreateWebGPUGraphicsContext3DProviderAsync(
const KURL& url,
scoped_refptr<base::SingleThreadTaskRunner> current_thread_task_runner,
- base::OnceCallback<void(std::unique_ptr<WebGraphicsContext3DProvider>)>
- callback) {
+ WTF::CrossThreadOnceFunction<
+ void(std::unique_ptr<WebGraphicsContext3DProvider>)> callback) {
if (IsMainThread()) {
std::move(callback).Run(
Platform::Current()->CreateWebGPUGraphicsContext3DProvider(url));
@@ -140,8 +140,7 @@ void CreateWebGPUGraphicsContext3DProviderAsync(
AccessMainThreadForWebGraphicsContext3DProvider()),
FROM_HERE,
CrossThreadBindOnce(&CreateWebGPUGraphicsContextOnMainThreadAsync, url,
- current_thread_task_runner,
- CrossThreadBindOnce(std::move(callback))));
+ current_thread_task_runner, std::move(callback)));
}
}
diff --git a/third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_util.h b/third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_util.h
index 8fcab24bfec2c9b2e9edf9885b66de4f99949b35..8b785cc30acdfffed0f59eb53b073d0cdedc2151 100644
--- a/third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_util.h
+++ b/third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_util.h
@@ -10,6 +10,7 @@
#include "third_party/blink/public/platform/web_graphics_context_3d_provider.h"
#include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink {
@@ -42,8 +43,8 @@ CreateWebGPUGraphicsContext3DProvider(const KURL& url);
PLATFORM_EXPORT void CreateWebGPUGraphicsContext3DProviderAsync(
const KURL& url,
scoped_refptr<base::SingleThreadTaskRunner> current_thread_task_runner,
- base::OnceCallback<void(std::unique_ptr<WebGraphicsContext3DProvider>)>
- callback);
+ WTF::CrossThreadOnceFunction<
+ void(std::unique_ptr<WebGraphicsContext3DProvider>)> callback);
} // namespace blink

View File

@@ -0,0 +1,61 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Hongchan Choi <hongchan@chromium.org>
Date: Tue, 12 Dec 2023 02:34:29 +0000
Subject: Clamp the input value correctly before scheduling an AudioParam event
When the AudioParam value is set via the setter, it internally calls
the setValueAtTime() function to schedule the change. However, the
current code does not correctly clamp the value within the nominal
range. This CL fixes the problem.
(cherry picked from commit c97b506c1e32951dd39e11e453e1ecc29cc0b35c)
Bug: 1505086
Test: Locally confirmed with both negative and positive param values.
Change-Id: Ibb0aae168161af9ea95c5e11a929b3aa2c621c73
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5100625
Reviewed-by: Michael Wilson <mjwilson@chromium.org>
Commit-Queue: Hongchan Choi <hongchan@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1235028}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5112838
Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Auto-Submit: Hongchan Choi <hongchan@chromium.org>
Cr-Commit-Position: refs/branch-heads/6099@{#1497}
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
diff --git a/third_party/blink/renderer/modules/webaudio/audio_param.cc b/third_party/blink/renderer/modules/webaudio/audio_param.cc
index 8c7b9d07bb68ec51d21ea2132cc5ecbc39e5cd95..95a40d39c9214fd6555523bd7e7bd91e36d2c6c0 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_param.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_param.cc
@@ -120,12 +120,15 @@ void AudioParam::setValue(float value) {
void AudioParam::setValue(float value, ExceptionState& exception_state) {
WarnIfOutsideRange("value", value);
- // This is to signal any errors, if necessary, about conflicting
- // automations.
- setValueAtTime(value, Context()->currentTime(), exception_state);
- // This is to change the value so that an immediate query for the
- // value returns the expected values.
+ // Change the intrinsic value so that an immediate query for the value
+ // returns the value that the user code provided. It also clamps the value
+ // to the nominal range.
Handler().SetValue(value);
+
+ // Use the intrinsic value (after clamping) to schedule the actual
+ // automation event.
+ setValueAtTime(Handler().IntrinsicValue(), Context()->currentTime(),
+ exception_state);
}
float AudioParam::defaultValue() const {
diff --git a/third_party/blink/web_tests/webaudio/AudioParam/worklet-warnings-expected.txt b/third_party/blink/web_tests/webaudio/AudioParam/worklet-warnings-expected.txt
index 7bb2d0aec7feaed69424f209a2e3e031c7a9e512..ebe05a2c239d35be4729cc187aa77de6a44f5a41 100644
--- a/third_party/blink/web_tests/webaudio/AudioParam/worklet-warnings-expected.txt
+++ b/third_party/blink/web_tests/webaudio/AudioParam/worklet-warnings-expected.txt
@@ -1,5 +1,4 @@
CONSOLE WARNING: AudioWorkletNode("noise-generator").amplitude.value 99 outside nominal range [0, 1]; value will be clamped.
-CONSOLE WARNING: AudioWorkletNode("noise-generator").amplitude.setValueAtTime value 99 outside nominal range [0, 1]; value will be clamped.
CONSOLE WARNING: AudioWorkletNode("noise-generator").amplitude.setValueAtTime value -1 outside nominal range [0, 1]; value will be clamped.
CONSOLE WARNING: AudioWorkletNode("noise-generator").amplitude.linearRampToValueAtTime value 5 outside nominal range [0, 1]; value will be clamped.
This is a testharness.js-based test.

View File

@@ -0,0 +1,73 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Guido Urdaneta <guidou@chromium.org>
Date: Fri, 10 Nov 2023 20:46:57 +0000
Subject: Use KeepAlive to prevent lifetime race with audio delivery
(cherry picked from commit 186dad16ae69183f02730fb26d84e1d53f9f1b04)
Bug: 1497984
Change-Id: Ic22729b2ef9690203bbb09555d32238959e93a0f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5009864
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
Commit-Queue: Guido Urdaneta <guidou@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1221614}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5018212
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/branch-heads/6099@{#500}
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
diff --git a/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.cc b/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.cc
index f68c265271b48f92ff67a752cf2bedac183bd2fc..a53053b12925b6aaa4fb201e7de2c00d4203bb2a 100644
--- a/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.cc
+++ b/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.cc
@@ -142,12 +142,12 @@ bool MediaStreamAudioTrackUnderlyingSource::StartFrameDelivery() {
return false;
}
- if (added_to_track_) {
+ if (is_connected_to_track_) {
return true;
}
WebMediaStreamAudioSink::AddToAudioTrack(this, WebMediaStreamTrack(track_));
- added_to_track_ = true;
+ is_connected_to_track_ = this;
return true;
}
@@ -159,7 +159,7 @@ void MediaStreamAudioTrackUnderlyingSource::DisconnectFromTrack() {
WebMediaStreamAudioSink::RemoveFromAudioTrack(this,
WebMediaStreamTrack(track_));
- added_to_track_ = false;
+ is_connected_to_track_.Clear();
track_.Clear();
}
diff --git a/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.h b/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.h
index 334da29c2b210f92e9ee191275651406487601c3..4e7d22959dc8947c12d9ee2bb7acd814cc4db6b3 100644
--- a/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.h
+++ b/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.h
@@ -13,6 +13,7 @@
#include "third_party/blink/renderer/modules/breakout_box/transferred_frame_queue_underlying_source.h"
#include "third_party/blink/renderer/modules/modules_export.h"
#include "third_party/blink/renderer/platform/heap/prefinalizer.h"
+#include "third_party/blink/renderer/platform/heap/self_keep_alive.h"
namespace blink {
@@ -80,10 +81,13 @@ class MODULES_EXPORT MediaStreamAudioTrackUnderlyingSource
const Member<ScriptWrappable> media_stream_track_processor_;
Member<MediaStreamComponent> track_;
- bool added_to_track_ = false;
std::unique_ptr<AudioBufferPool> buffer_pool_;
+ // This prevents collection of this object while it is still connected to a
+ // platform MediaStreamTrack.
+ SelfKeepAlive<MediaStreamAudioTrackUnderlyingSource> is_connected_to_track_;
+
SEQUENCE_CHECKER(sequence_checker_);
};

View File

@@ -0,0 +1,37 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Paul Semel <paulsemel@chromium.org>
Date: Wed, 6 Dec 2023 15:52:56 +0000
Subject: ImageBitmapFactory: fix empty context dcheck
Approved by:
https://bugs.chromium.org/p/chromium/issues/detail?id=1502102#c34
(cherry picked from commit c4d2f15b8f97076c8fd0f9aa5814b94db698b75c)
Fixed: 1502102
Change-Id: Ib42d2897d62136ae835561bcf56884b5624060a5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5071252
Commit-Queue: Paul Semel <paulsemel@chromium.org>
Reviewed-by: Jean-Philippe Gravel <jpgravel@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1230617}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5088373
Auto-Submit: Arthur Sonzogni <arthursonzogni@google.com>
Reviewed-by: Paul Semel <paulsemel@chromium.org>
Cr-Commit-Position: refs/branch-heads/6099@{#1416}
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
diff --git a/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.cc b/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.cc
index 20d95536a945c67b9aba082c0ad1ff4aa46c240d..5028d3744619a14e23bba4006bf958478b5b53f8 100644
--- a/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.cc
+++ b/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_factories.cc
@@ -155,7 +155,9 @@ ScriptPromise ImageBitmapFactories::CreateImageBitmapFromBlob(
ImageBitmapSource* bitmap_source,
absl::optional<gfx::Rect> crop_rect,
const ImageBitmapOptions* options) {
- DCHECK(script_state->ContextIsValid());
+ if (!script_state->ContextIsValid()) {
+ return ScriptPromise();
+ }
// imageOrientation: 'from-image' will be used to replace imageOrientation:
// 'none'. Adding a deprecation warning when 'none' is called in

View File

@@ -0,0 +1,33 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Gustaf Ullberg <gustaf@chromium.org>
Date: Wed, 20 Dec 2023 16:59:29 +0000
Subject: WebRtcAudioSink: Stop on invalid configuration
(cherry picked from commit 340b7e300d380460a039a07b90f62d1febae9da5)
Bug: 1513170
Change-Id: Ia4ca55e9eafb81789b28b8b8c54e615ac28df633
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5136295
Reviewed-by: Harald Alvestrand <hta@chromium.org>
Commit-Queue: Gustaf Ullberg <gustaf@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1239233}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5136708
Owners-Override: Krishna Govind <govind@chromium.org>
Commit-Queue: Krishna Govind <govind@chromium.org>
Reviewed-by: Krishna Govind <govind@chromium.org>
Cr-Commit-Position: refs/branch-heads/6099@{#1566}
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
diff --git a/third_party/blink/renderer/platform/peerconnection/webrtc_audio_sink.cc b/third_party/blink/renderer/platform/peerconnection/webrtc_audio_sink.cc
index cd9f2edbf6ef456bd9389c697b921b41981e338d..209a2277056aeabca94bbd41ad7d4216798ad578 100644
--- a/third_party/blink/renderer/platform/peerconnection/webrtc_audio_sink.cc
+++ b/third_party/blink/renderer/platform/peerconnection/webrtc_audio_sink.cc
@@ -121,7 +121,7 @@ void WebRtcAudioSink::OnData(const media::AudioBus& audio_bus,
}
void WebRtcAudioSink::OnSetFormat(const media::AudioParameters& params) {
- DCHECK(params.IsValid());
+ CHECK(params.IsValid());
SendLogMessage(base::StringPrintf("OnSetFormat([label=%s] {params=[%s]})",
adapter_->label().c_str(),
params.AsHumanReadableString().c_str()));

View File

@@ -0,0 +1,42 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nidhi Jaju <nidhijaju@chromium.org>
Date: Wed, 8 Nov 2023 04:19:31 +0000
Subject: Make URLSearchParams persistent to avoid UaF
The URLSearchParams::Create() function returns an on-heap object, but it
can be garbage collected, so making it a persistent variable in
DidFetchDataLoadedString() mitigates the issue.
(cherry picked from commit 8b1bd7726a1394e2fe287f6a882822d8ee9d4e96)
Bug: 1497997
Change-Id: I4ae0f93fccc561cd8a088d3fa0bf2968bf298acf
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4996929
Reviewed-by: Adam Rice <ricea@chromium.org>
Commit-Queue: Nidhi Jaju <nidhijaju@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1218682}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5007484
Commit-Queue: Adam Rice <ricea@chromium.org>
Auto-Submit: Nidhi Jaju <nidhijaju@chromium.org>
Cr-Commit-Position: refs/branch-heads/5993@{#1546}
Cr-Branched-From: 511350718e646be62331ae9d7213d10ec320d514-refs/heads/main@{#1192594}
diff --git a/third_party/blink/renderer/core/fetch/body.cc b/third_party/blink/renderer/core/fetch/body.cc
index 86aac83becddb7aad0b8172311ccf2cd182bc7e6..4f396c124a1e33772e447e8f8000f31937a57fa6 100644
--- a/third_party/blink/renderer/core/fetch/body.cc
+++ b/third_party/blink/renderer/core/fetch/body.cc
@@ -135,8 +135,13 @@ class BodyFormDataConsumer final : public BodyConsumerBase {
void DidFetchDataLoadedString(const String& string) override {
auto* formData = MakeGarbageCollected<FormData>();
- for (const auto& pair : URLSearchParams::Create(string)->Params())
+ // URLSearchParams::Create() returns an on-heap object, but it can be
+ // garbage collected, so making it a persistent variable on the stack
+ // mitigates use-after-free scenarios. See crbug.com/1497997.
+ Persistent<URLSearchParams> search_params = URLSearchParams::Create(string);
+ for (const auto& pair : search_params->Params()) {
formData->append(pair.first, pair.second);
+ }
DidFetchDataLoadedFormData(formData);
}
};

View File

@@ -0,0 +1,31 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Mike Wasserman <msw@chromium.org>
Date: Thu, 21 Dec 2023 22:33:05 +0000
Subject: Speculative fix for UAF in
content::WebContentsImpl::ExitFullscreenMode
Bug: 1506535, 854815
Change-Id: Iace64d63f8cea2dbfbc761ad233db42451ec101c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5146875
Commit-Queue: John Abd-El-Malek <jam@chromium.org>
Auto-Submit: Mike Wasserman <msw@chromium.org>
Reviewed-by: John Abd-El-Malek <jam@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1240353}
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 69d07fb1eed22ffab2556107f3520b19a8f066f2..23f68b9f9c108fd74bcba15289c1a2082a53c486 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -3672,7 +3672,12 @@ void WebContentsImpl::ExitFullscreenMode(bool will_cause_resize) {
static_cast<RenderWidgetHostViewBase*>(view)->ExitFullscreenMode();
if (delegate_) {
+ // This may spin the message loop and destroy this object crbug.com/1506535
+ base::WeakPtr<WebContentsImpl> weak_ptr = weak_factory_.GetWeakPtr();
delegate_->ExitFullscreenModeForTab(this);
+ if (!weak_ptr) {
+ return;
+ }
if (keyboard_lock_widget_)
delegate_->CancelKeyboardLockRequest(this);

View File

@@ -0,0 +1,150 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Hongchan Choi <hongchan@chromium.org>
Date: Fri, 19 Jan 2024 19:17:18 +0000
Subject: Update rendering state of automatic pull nodes before graph rendering
In rare cases, the rendering fan out count of automatic pull node
does not match the main thread fan out count after recreating
a platform destination followed by disconnection.
This CL forces the update of the rendering state of automatic
pull nodes before graph rendering to make sure that fan out counts
are synchronized before executing the audio processing function call.
NOTE: This change makes 2 WPTs fail. The follow-up work is planned
to address them once this patch is merged.
(cherry picked from commit f4bffa09b46c21147431179e1e6dd2b27bc35fbc)
Bug: 1505080
Test: Locally confirmed that ASAN doesn't crash on all repro cases.
Change-Id: I6768cd8bc64525ea9d56a19b9c58439e9cdab9a8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5131958
Reviewed-by: Michael Wilson <mjwilson@chromium.org>
Commit-Queue: Hongchan Choi <hongchan@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1246718}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5214669
Auto-Submit: Hongchan Choi <hongchan@chromium.org>
Cr-Commit-Position: refs/branch-heads/6099@{#1833}
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
diff --git a/third_party/blink/renderer/modules/webaudio/analyser_handler.cc b/third_party/blink/renderer/modules/webaudio/analyser_handler.cc
index a3ef095cdeba50edc14b278cfc802a306e2719e8..3c885957ed5ef5f88de7c40c33160461391843fe 100644
--- a/third_party/blink/renderer/modules/webaudio/analyser_handler.cc
+++ b/third_party/blink/renderer/modules/webaudio/analyser_handler.cc
@@ -39,9 +39,14 @@ AnalyserHandler::~AnalyserHandler() {
}
void AnalyserHandler::Process(uint32_t frames_to_process) {
- AudioBus* output_bus = Output(0).Bus();
+ DCHECK(Context()->IsAudioThread());
- if (!IsInitialized()) {
+ // It's possible that output is not connected. Assign nullptr to indicate
+ // such case.
+ AudioBus* output_bus = Output(0).RenderingFanOutCount() > 0
+ ? Output(0).Bus() : nullptr;
+
+ if (!IsInitialized() && output_bus) {
output_bus->Zero();
return;
}
@@ -53,6 +58,11 @@ void AnalyserHandler::Process(uint32_t frames_to_process) {
// Analyser reflects the current input.
analyser_.WriteInput(input_bus.get(), frames_to_process);
+ // Subsequent steps require `output_bus` to be valid.
+ if (!output_bus) {
+ return;
+ }
+
if (!Input(0).IsConnected()) {
// No inputs, so clear the output, and propagate the silence hint.
output_bus->Zero();
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.cc b/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.cc
index 0bf86b7d659533e0acd9cd0c902c6dd68b51e1e6..903e8172d7c381da2e2cb8e9962ea601c76b375a 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_worklet_handler.cc
@@ -119,12 +119,14 @@ void AudioWorkletHandler::Process(uint32_t frames_to_process) {
return;
}
- // If the input is not connected, inform the processor with nullptr.
+ // If the input or the output is not connected, inform the processor with
+ // nullptr.
for (unsigned i = 0; i < NumberOfInputs(); ++i) {
inputs_[i] = Input(i).IsConnected() ? Input(i).Bus() : nullptr;
}
for (unsigned i = 0; i < NumberOfOutputs(); ++i) {
- outputs_[i] = WrapRefCounted(Output(i).Bus());
+ outputs_[i] = Output(i).RenderingFanOutCount() > 0
+ ? WrapRefCounted(Output(i).Bus()) : nullptr;
}
for (const auto& param_name : param_value_map_.Keys()) {
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet_processor.cc b/third_party/blink/renderer/modules/webaudio/audio_worklet_processor.cc
index 181dfa92723843d5ce9ae3e7399215870ac1dc80..c3c53d7a7099d67a6bb76df55a6c71965ca3bf02 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_worklet_processor.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_worklet_processor.cc
@@ -376,6 +376,12 @@ void AudioWorkletProcessor::CopyArrayBuffersToPort(
for (uint32_t bus_index = 0; bus_index < audio_port.size(); ++bus_index) {
const scoped_refptr<AudioBus>& audio_bus = audio_port[bus_index];
+
+ // nullptr indicates the output bus is not connected. Do not proceed.
+ if (!audio_bus) {
+ break;
+ }
+
for (uint32_t channel_index = 0;
channel_index < audio_bus->NumberOfChannels(); ++channel_index) {
auto backing_store = array_buffers[bus_index][channel_index]
diff --git a/third_party/blink/renderer/modules/webaudio/deferred_task_handler.cc b/third_party/blink/renderer/modules/webaudio/deferred_task_handler.cc
index fa1de8f37b9be681f7ac447bc3e3859e8909216d..4730383dafa957c2e84c009387d15d6fe479e5ba 100644
--- a/third_party/blink/renderer/modules/webaudio/deferred_task_handler.cc
+++ b/third_party/blink/renderer/modules/webaudio/deferred_task_handler.cc
@@ -172,6 +172,16 @@ void DeferredTaskHandler::UpdateAutomaticPullNodes() {
base::AutoTryLock try_locker(automatic_pull_handlers_lock_);
if (try_locker.is_acquired()) {
rendering_automatic_pull_handlers_.assign(automatic_pull_handlers_);
+
+ // In rare cases, it is possible for automatic pull nodes' output bus
+ // to become stale. Make sure update their rendering output counts.
+ // crbug.com/1505080.
+ for (auto& handler : rendering_automatic_pull_handlers_) {
+ for (unsigned i = 0; i < handler->NumberOfOutputs(); ++i) {
+ handler->Output(i).UpdateRenderingState();
+ }
+ }
+
automatic_pull_handlers_need_updating_ = false;
}
}
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-process-frozen-array.https.html b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-process-frozen-array.https.html
index 33627204a6f538eba77bd8346952404814e4affa..ce0cfa40b691d859d372c9e6da7ff54fe64bbbe1 100644
--- a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-process-frozen-array.https.html
+++ b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/audioworkletprocessor-process-frozen-array.https.html
@@ -43,7 +43,10 @@
if (actual.done)
task.done();
};
- sourceNode.connect(workletNode);
+ // To have valid ArrayBuffers for both input and output, we need
+ // both connections.
+ // See: https://github.com/WebAudio/web-audio-api/issues/2566
+ sourceNode.connect(workletNode).connect(context.destination);
sourceNode.start();
});
diff --git a/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/process-parameters.https-expected.txt b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/process-parameters.https-expected.txt
new file mode 100644
index 0000000000000000000000000000000000000000..fbac76d9b865bfdec552bf280e4a19ae1743ef4a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webaudio/the-audio-api/the-audioworklet-interface/process-parameters.https-expected.txt
@@ -0,0 +1,6 @@
+This is a testharness.js-based test.
+[PASS] 3 inputs; 0 outputs
+[FAIL] 0 inputs; 3 outputs
+ assert_equals: outputs[0].length expected 1 but got 0
+Harness: the test ran to completion.
+

View File

@@ -0,0 +1,116 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ken Rockot <rockot@google.com>
Date: Thu, 16 Nov 2023 23:44:43 +0000
Subject: Reland: Fix IPC Channel pipe teardown
This is a reland with the new test temporarily disabled on Android
until it can run without disrupting other tests.
(cherry picked from commit cd4c1f165c16c6d8161b5372ef7f61c715e01a42)
Fixed: 1494461
Change-Id: If1d83c2dce62020f78dd50abc460973759002a1a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5015115
Commit-Queue: Ken Rockot <rockot@google.com>
Reviewed-by: Robert Sesek <rsesek@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1221953}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5037764
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Auto-Submit: Ken Rockot <rockot@google.com>
Commit-Queue: Daniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/branch-heads/5993@{#1618}
Cr-Branched-From: 511350718e646be62331ae9d7213d10ec320d514-refs/heads/main@{#1192594}
diff --git a/ipc/ipc_mojo_bootstrap.cc b/ipc/ipc_mojo_bootstrap.cc
index 2ab03807d102d8f4e2a22119210d5cb669338c3b..5fa17e2ff108909a8987665dd21bc490118f1147 100644
--- a/ipc/ipc_mojo_bootstrap.cc
+++ b/ipc/ipc_mojo_bootstrap.cc
@@ -787,13 +787,12 @@ class ChannelAssociatedGroupController
// handle.
DCHECK(!endpoint->client());
DCHECK(endpoint->peer_closed());
- MarkClosedAndMaybeRemove(endpoint);
+ MarkClosed(endpoint);
} else {
- MarkPeerClosedAndMaybeRemove(endpoint);
+ MarkPeerClosed(endpoint);
}
}
-
- DCHECK(endpoints_.empty());
+ endpoints_.clear();
GetMemoryDumpProvider().RemoveController(this);
}
@@ -838,15 +837,19 @@ class ChannelAssociatedGroupController
base::AutoLock locker(lock_);
encountered_error_ = true;
+ std::vector<uint32_t> endpoints_to_remove;
std::vector<scoped_refptr<Endpoint>> endpoints_to_notify;
for (auto iter = endpoints_.begin(); iter != endpoints_.end();) {
Endpoint* endpoint = iter->second.get();
++iter;
- if (endpoint->client())
+ if (endpoint->client()) {
endpoints_to_notify.push_back(endpoint);
+ }
- MarkPeerClosedAndMaybeRemove(endpoint);
+ if (MarkPeerClosed(endpoint)) {
+ endpoints_to_remove.push_back(endpoint->id());
+ }
}
for (auto& endpoint : endpoints_to_notify) {
@@ -855,6 +858,10 @@ class ChannelAssociatedGroupController
if (endpoint->client())
NotifyEndpointOfError(endpoint.get(), false /* force_async */);
}
+
+ for (uint32_t id : endpoints_to_remove) {
+ endpoints_.erase(id);
+ }
}
void NotifyEndpointOfError(Endpoint* endpoint, bool force_async) {
@@ -893,19 +900,33 @@ class ChannelAssociatedGroupController
NotifyEndpointOfError(endpoint, false /* force_async */);
}
- void MarkClosedAndMaybeRemove(Endpoint* endpoint) {
+ // Marks `endpoint` as closed and returns true if and only if its peer was
+ // also already closed.
+ bool MarkClosed(Endpoint* endpoint) {
lock_.AssertAcquired();
endpoint->set_closed();
- if (endpoint->closed() && endpoint->peer_closed())
- endpoints_.erase(endpoint->id());
+ return endpoint->peer_closed();
}
- void MarkPeerClosedAndMaybeRemove(Endpoint* endpoint) {
+ // Marks `endpoint` as having a closed peer and returns true if and only if
+ // `endpoint` itself was also already closed.
+ bool MarkPeerClosed(Endpoint* endpoint) {
lock_.AssertAcquired();
endpoint->set_peer_closed();
endpoint->SignalSyncMessageEvent();
- if (endpoint->closed() && endpoint->peer_closed())
+ return endpoint->closed();
+ }
+
+ void MarkClosedAndMaybeRemove(Endpoint* endpoint) {
+ if (MarkClosed(endpoint)) {
endpoints_.erase(endpoint->id());
+ }
+ }
+
+ void MarkPeerClosedAndMaybeRemove(Endpoint* endpoint) {
+ if (MarkPeerClosed(endpoint)) {
+ endpoints_.erase(endpoint->id());
+ }
}
Endpoint* FindOrInsertEndpoint(mojo::InterfaceId id, bool* inserted) {

View File

@@ -0,0 +1,72 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Guido Urdaneta <guidou@chromium.org>
Date: Wed, 24 Jan 2024 18:40:01 +0000
Subject: Exit early from RTCPeerConnectionHandler
For certain operations that require a live client
(i.e., RTCPeerConnection, which is garbage collected),
PeerConnectionHandler keeps a pointer to the client on the stack
to prevent garbage collection.
In some cases, the client may have already been garbage collected
(the client is null). In that case, there is no point in doing the
operation and it should exit early to avoid UAF/crashes.
This CL adds early exit to the cases that do not already have it.
(cherry picked from commit 8755f76bec326c654370de6dd68eea693df74ede)
Bug: 1514777
Change-Id: I27e9541cfaa74d978799c03e2832a0980f9e5710
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5210359
Reviewed-by: Tomas Gunnarsson <tommi@chromium.org>
Commit-Queue: Guido Urdaneta <guidou@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1248826}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5233883
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Auto-Submit: Guido Urdaneta <guidou@chromium.org>
Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/branch-heads/6099@{#1867}
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc
index 76fa93800543ff134859c8fc0c0fa63123cf9772..9e5ce0572cfd1d2dd729e5f560b021aba05653f3 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc
@@ -1057,15 +1057,19 @@ bool RTCPeerConnectionHandler::Initialize(
WebLocalFrame* frame,
ExceptionState& exception_state) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
- DCHECK(frame);
DCHECK(dependency_factory_);
- frame_ = frame;
CHECK(!initialize_called_);
initialize_called_ = true;
// Prevent garbage collection of client_ during processing.
auto* client_on_stack = client_;
+ if (!client_on_stack) {
+ return false;
+ }
+
+ DCHECK(frame);
+ frame_ = frame;
peer_connection_tracker_ = PeerConnectionTracker::From(*frame);
configuration_ = server_configuration;
@@ -2312,10 +2316,13 @@ void RTCPeerConnectionHandler::OnIceCandidate(const String& sdp,
int sdp_mline_index,
int component,
int address_family) {
+ DCHECK(task_runner_->RunsTasksInCurrentSequence());
// In order to ensure that the RTCPeerConnection is not garbage collected
// from under the function, we keep a pointer to it on the stack.
auto* client_on_stack = client_;
- DCHECK(task_runner_->RunsTasksInCurrentSequence());
+ if (!client_on_stack) {
+ return;
+ }
TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnIceCandidateImpl");
// This line can cause garbage collection.
auto* platform_candidate = MakeGarbageCollected<RTCIceCandidatePlatform>(

View File

@@ -0,0 +1,181 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Kai Ninomiya <kainino@chromium.org>
Date: Thu, 7 Dec 2023 14:31:32 +0000
Subject: Fix reinit order in
ContextProviderCommandBuffer::BindToCurrentSequence
See comments for explanation.
(cherry picked from commit 7d8400ceb56db5fd97249f787251fe8b3928e6fd)
Bug: 1505632
Change-Id: I0f43821a9708af91303048332e9fae5e100deee5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5069480
Reviewed-by: Saifuddin Hitawala <hitawala@chromium.org>
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Brendon Tiszka <tiszka@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1230735}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5095795
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Commit-Queue: Saifuddin Hitawala <hitawala@chromium.org>
Auto-Submit: Kai Ninomiya <kainino@chromium.org>
Cr-Commit-Position: refs/branch-heads/6099@{#1424}
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
diff --git a/services/viz/public/cpp/gpu/context_provider_command_buffer.cc b/services/viz/public/cpp/gpu/context_provider_command_buffer.cc
index 5f0966ef839fae01ddadff64b9bde819dbfc7141..2bd94a0c94cd1aafe6ad21a8a7f2cb1f3afd8110 100644
--- a/services/viz/public/cpp/gpu/context_provider_command_buffer.cc
+++ b/services/viz/public/cpp/gpu/context_provider_command_buffer.cc
@@ -172,13 +172,13 @@ gpu::ContextResult ContextProviderCommandBuffer::BindToCurrentSequence() {
}
// The transfer buffer is used to serialize Dawn commands
- transfer_buffer_ =
+ auto transfer_buffer =
std::make_unique<gpu::TransferBuffer>(webgpu_helper.get());
// The WebGPUImplementation exposes the WebGPUInterface, as well as the
// gpu::ContextSupport interface.
auto webgpu_impl = std::make_unique<gpu::webgpu::WebGPUImplementation>(
- webgpu_helper.get(), transfer_buffer_.get(), command_buffer_.get());
+ webgpu_helper.get(), transfer_buffer.get(), command_buffer_.get());
bind_result_ = webgpu_impl->Initialize(memory_limits_);
if (bind_result_ != gpu::ContextResult::kSuccess) {
DLOG(ERROR) << "Failed to initialize WebGPUImplementation.";
@@ -190,8 +190,11 @@ gpu::ContextResult ContextProviderCommandBuffer::BindToCurrentSequence() {
std::string unique_context_name =
base::StringPrintf("%s-%p", type_name.c_str(), webgpu_impl.get());
+ // IMPORTANT: These hold raw_ptrs to each other, so must be set together.
+ // See note in the header (and keep it up to date if things change).
impl_ = webgpu_impl.get();
webgpu_interface_ = std::move(webgpu_impl);
+ transfer_buffer_ = std::move(transfer_buffer);
helper_ = std::move(webgpu_helper);
} else if (attributes_.enable_raster_interface &&
!attributes_.enable_gles2_interface &&
@@ -209,14 +212,14 @@ gpu::ContextResult ContextProviderCommandBuffer::BindToCurrentSequence() {
}
// The transfer buffer is used to copy resources between the client
// process and the GPU process.
- transfer_buffer_ =
+ auto transfer_buffer =
std::make_unique<gpu::TransferBuffer>(raster_helper.get());
// The RasterImplementation exposes the RasterInterface, as well as the
// gpu::ContextSupport interface.
DCHECK(channel_);
auto raster_impl = std::make_unique<gpu::raster::RasterImplementation>(
- raster_helper.get(), transfer_buffer_.get(),
+ raster_helper.get(), transfer_buffer.get(),
attributes_.bind_generates_resource,
attributes_.lose_context_when_out_of_memory, command_buffer_.get(),
channel_->image_decode_accelerator_proxy());
@@ -233,8 +236,11 @@ gpu::ContextResult ContextProviderCommandBuffer::BindToCurrentSequence() {
raster_impl->TraceBeginCHROMIUM("gpu_toplevel",
unique_context_name.c_str());
+ // IMPORTANT: These hold raw_ptrs to each other, so must be set together.
+ // See note in the header (and keep it up to date if things change).
impl_ = raster_impl.get();
raster_interface_ = std::move(raster_impl);
+ transfer_buffer_ = std::move(transfer_buffer);
helper_ = std::move(raster_helper);
} else {
// The GLES2 helper writes the command buffer protocol.
@@ -249,7 +255,7 @@ gpu::ContextResult ContextProviderCommandBuffer::BindToCurrentSequence() {
// The transfer buffer is used to copy resources between the client
// process and the GPU process.
- transfer_buffer_ =
+ auto transfer_buffer =
std::make_unique<gpu::TransferBuffer>(gles2_helper.get());
// The GLES2Implementation exposes the OpenGLES2 API, as well as the
@@ -262,13 +268,13 @@ gpu::ContextResult ContextProviderCommandBuffer::BindToCurrentSequence() {
// we only use it if grcontext_support was requested.
gles2_impl = std::make_unique<
skia_bindings::GLES2ImplementationWithGrContextSupport>(
- gles2_helper.get(), /*share_group=*/nullptr, transfer_buffer_.get(),
+ gles2_helper.get(), /*share_group=*/nullptr, transfer_buffer.get(),
attributes_.bind_generates_resource,
attributes_.lose_context_when_out_of_memory,
support_client_side_arrays, command_buffer_.get());
} else {
gles2_impl = std::make_unique<gpu::gles2::GLES2Implementation>(
- gles2_helper.get(), /*share_group=*/nullptr, transfer_buffer_.get(),
+ gles2_helper.get(), /*share_group=*/nullptr, transfer_buffer.get(),
attributes_.bind_generates_resource,
attributes_.lose_context_when_out_of_memory,
support_client_side_arrays, command_buffer_.get());
@@ -279,8 +285,11 @@ gpu::ContextResult ContextProviderCommandBuffer::BindToCurrentSequence() {
return bind_result_;
}
+ // IMPORTANT: These hold raw_ptrs to each other, so must be set together.
+ // See note in the header (and keep it up to date if things change).
impl_ = gles2_impl.get();
gles2_impl_ = std::move(gles2_impl);
+ transfer_buffer_ = std::move(transfer_buffer);
helper_ = std::move(gles2_helper);
}
@@ -314,6 +323,7 @@ gpu::ContextResult ContextProviderCommandBuffer::BindToCurrentSequence() {
switches::kEnableGpuClientTracing)) {
// This wraps the real GLES2Implementation and we should always use this
// instead when it's present.
+ // IMPORTANT: This holds a raw_ptr to gles2_impl_.
trace_impl_ = std::make_unique<gpu::gles2::GLES2TraceImplementation>(
gles2_impl_.get());
gl = trace_impl_.get();
diff --git a/services/viz/public/cpp/gpu/context_provider_command_buffer.h b/services/viz/public/cpp/gpu/context_provider_command_buffer.h
index 93fd2dbd47fc8aca19ac8baffe62911cdc9efb6c..78aaa2b759e350a7a8ed58273cf910ab91c235ea 100644
--- a/services/viz/public/cpp/gpu/context_provider_command_buffer.h
+++ b/services/viz/public/cpp/gpu/context_provider_command_buffer.h
@@ -159,19 +159,42 @@ class ContextProviderCommandBuffer
// associated shared images are destroyed.
std::unique_ptr<gpu::ClientSharedImageInterface> shared_image_interface_;
- base::Lock context_lock_; // Referenced by command_buffer_.
+ //////////////////////////////////////////////////////////////////////////////
+ // IMPORTANT NOTE: All of the objects in this block are part of a complex //
+ // graph of raw pointers (holder or pointee of various raw_ptrs). They are //
+ // defined in topological order: only later items point to earlier items. //
+ // - When writing any member, always ensure its pointers to earlier members
+ // are guaranteed to stay alive.
+ // - When clearing OR overwriting any member, always ensure objects that
+ // point to it have already been cleared.
+ // - The topological order of definitions guarantees that the
+ // destructors will be called in the correct order (bottom to top).
+ // - When overwriting multiple members, similarly do so in reverse order.
+ //
+ // Please note these comments are likely not to stay perfectly up-to-date.
+
+ base::Lock context_lock_;
+ // Points to the context_lock_ field of `this`.
std::unique_ptr<gpu::CommandBufferProxyImpl> command_buffer_;
+
+ // Points to command_buffer_.
std::unique_ptr<gpu::CommandBufferHelper> helper_;
+ // Points to helper_.
std::unique_ptr<gpu::TransferBuffer> transfer_buffer_;
+ // Points to transfer_buffer_, helper_, and command_buffer_.
std::unique_ptr<gpu::gles2::GLES2Implementation> gles2_impl_;
+ // Points to gles2_impl_.
std::unique_ptr<gpu::gles2::GLES2TraceImplementation> trace_impl_;
+ // Points to transfer_buffer_, helper_, and command_buffer_.
std::unique_ptr<gpu::raster::RasterInterface> raster_interface_;
+ // Points to transfer_buffer_, helper_, and command_buffer_.
std::unique_ptr<gpu::webgpu::WebGPUInterface> webgpu_interface_;
+ // This is an alias for gles2_impl_, raster_interface_, or webgpu_interface_.
+ raw_ptr<gpu::ImplementationBase> impl_ = nullptr;
- // Owned by one of gles2_impl_, raster_interface_, or webgpu_interface_. It
- // must be declared last and cleared first.
- raw_ptr<gpu::ImplementationBase> impl_;
+ // END IMPORTANT NOTE //
+ //////////////////////////////////////////////////////////////////////////////
std::unique_ptr<skia_bindings::GrContextForGLES2Interface> gr_context_;

View File

@@ -0,0 +1,108 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: John Stiles <johnstiles@google.com>
Date: Thu, 1 Feb 2024 20:40:55 +0000
Subject: Fix a crash when a BMP image contains an unnecessary EOF code.
Previously, this would try to perform color correction on a row
one past the end of the image data.
(cherry picked from commit 4bdd8d61bebbba9fab77fa86a8f66b305995199b)
Bug: 1521893
Change-Id: I425437005b9ef400138556705616095857d2cf0d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5241305
Auto-Submit: John Stiles <johnstiles@google.com>
Commit-Queue: John Stiles <johnstiles@google.com>
Reviewed-by: Peter Kasting <pkasting@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1253633}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5259699
Commit-Queue: Peter Kasting <pkasting@chromium.org>
Cr-Commit-Position: refs/branch-heads/6099@{#1915}
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
diff --git a/third_party/blink/renderer/platform/blink_platform_unittests_bundle_data.filelist b/third_party/blink/renderer/platform/blink_platform_unittests_bundle_data.filelist
index 74f34d801d7ad00a0b63731030fe32d9ed4e6595..48febaa9f2ea301d3928864d43ccb40f4f83d5c6 100644
--- a/third_party/blink/renderer/platform/blink_platform_unittests_bundle_data.filelist
+++ b/third_party/blink/renderer/platform/blink_platform_unittests_bundle_data.filelist
@@ -385,6 +385,7 @@
../../web_tests/images/resources/truncated.webp
../../web_tests/images/resources/truncated2.webp
../../web_tests/images/resources/twitter_favicon.ico
+../../web_tests/images/resources/unnecessary-eof.bmp
../../web_tests/images/resources/webp-animated-icc-xmp.webp
../../web_tests/images/resources/webp-animated-large.webp
../../web_tests/images/resources/webp-animated-no-blend.webp
diff --git a/third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_decoder_test.cc b/third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_decoder_test.cc
index a6e7353cd24ff4ec94f4ec068eaa94fa225f6537..287adb4410bfa91777f0def18e2cdf1bbbef1c25 100644
--- a/third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_decoder_test.cc
+++ b/third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_decoder_test.cc
@@ -98,6 +98,19 @@ TEST(BMPImageDecoderTest, crbug752898) {
decoder->DecodeFrameBufferAtIndex(0);
}
+// Verify that decoding an image with an unnecessary EOF marker does not crash.
+TEST(BMPImageDecoderTest, allowEOFWhenPastEndOfImage) {
+ static constexpr char kBmpFile[] = "/images/resources/unnecessary-eof.bmp";
+ scoped_refptr<SharedBuffer> data = ReadFile(kBmpFile);
+ ASSERT_TRUE(data.get());
+
+ std::unique_ptr<ImageDecoder> decoder = CreateBMPDecoder();
+ decoder->SetData(data.get(), true);
+ ImageFrame* frame = decoder->DecodeFrameBufferAtIndex(0);
+ EXPECT_EQ(ImageFrame::kFrameComplete, frame->GetStatus());
+ EXPECT_FALSE(decoder->Failed());
+}
+
class BMPImageDecoderCorpusTest : public ImageDecoderBaseTest {
public:
BMPImageDecoderCorpusTest() : ImageDecoderBaseTest("bmp") {}
diff --git a/third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_reader.cc b/third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_reader.cc
index 063e5385d7f66c8fb31941fe29dfe8dd5bcfb2e1..b40c8aa5c1fe514c933daa7ac5dc9791b73bf7e2 100644
--- a/third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_reader.cc
+++ b/third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_reader.cc
@@ -827,8 +827,10 @@ BMPImageReader::ProcessingResult BMPImageReader::ProcessRLEData() {
// the image.
const uint8_t count = ReadUint8(0);
const uint8_t code = ReadUint8(1);
- if ((count || (code != 1)) && PastEndOfImage(0))
+ const bool is_past_end_of_image = PastEndOfImage(0);
+ if ((count || (code != 1)) && is_past_end_of_image) {
return kFailure;
+ }
// Decode.
if (!count) {
@@ -849,7 +851,9 @@ BMPImageReader::ProcessingResult BMPImageReader::ProcessRLEData() {
(is_top_down_ ? (coord_.y() < (parent_->Size().height() - 1))
: (coord_.y() > 0)))
buffer_->SetHasAlpha(true);
- ColorCorrectCurrentRow();
+ if (!is_past_end_of_image) {
+ ColorCorrectCurrentRow();
+ }
// There's no need to move |coord_| here to trigger the caller
// to call SetPixelsChanged(). If the only thing that's changed
// is the alpha state, that will be properly written into the
@@ -1061,6 +1065,13 @@ void BMPImageReader::ColorCorrectCurrentRow() {
const ColorProfileTransform* const transform = parent_->ColorTransform();
if (!transform)
return;
+ int decoder_width = parent_->Size().width();
+ // Enforce 0 ≤ current row < bitmap height.
+ CHECK_GE(coord_.y(), 0);
+ CHECK_LT(coord_.y(), buffer_->Bitmap().height());
+ // Enforce decoder width == bitmap width exactly. (The bitmap rowbytes might
+ // add a bit of padding, but we are only converting one row at a time.)
+ CHECK_EQ(decoder_width, buffer_->Bitmap().width());
ImageFrame::PixelData* const row = buffer_->GetAddr(0, coord_.y());
const skcms_PixelFormat fmt = XformColorFormat();
const skcms_AlphaFormat alpha =
@@ -1069,7 +1080,7 @@ void BMPImageReader::ColorCorrectCurrentRow() {
: skcms_AlphaFormat_Unpremul;
const bool success =
skcms_Transform(row, fmt, alpha, transform->SrcProfile(), row, fmt, alpha,
- transform->DstProfile(), parent_->Size().width());
+ transform->DstProfile(), decoder_width);
DCHECK(success);
buffer_->SetPixelsChanged(true);
}

View File

@@ -0,0 +1,46 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Peter=20Bostr=C3=B6m?= <pbos@chromium.org>
Date: Thu, 1 Feb 2024 21:24:43 +0000
Subject: Fix racy iterator use in Node::AddConnection
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Before this fix an iterator to `connections_` which requires a lock
would be dereferenced outside an unlock operation because the `it` taken
from the map isn't understood as guarded by the same lock.
This takes a Ref<NodeLink> before unlocking which'll keep the link
reference alive even if `connections_` is concurrently modified and the
entry removed (or replaced).
(cherry picked from commit 1f2cbf5833d7f00d3fcbfd1f3ef0c1aff10c04cd)
Bug: 1523704
Change-Id: I6f6fe4e34ec2c8268d4e7f33965a13e3b10f9f92
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5254025
Commit-Queue: Peter Boström <pbos@chromium.org>
Reviewed-by: Ken Rockot <rockot@google.com>
Commit-Queue: Ken Rockot <rockot@google.com>
Auto-Submit: Peter Boström <pbos@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1254709}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5260163
Cr-Commit-Position: refs/branch-heads/6099@{#1916}
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
diff --git a/third_party/ipcz/src/ipcz/node.cc b/third_party/ipcz/src/ipcz/node.cc
index 695fda10a65d26239f68c36e10420b9e4955c0d7..d7a9c0a01a4bc1fd74182748756c9bb5c694688b 100644
--- a/third_party/ipcz/src/ipcz/node.cc
+++ b/third_party/ipcz/src/ipcz/node.cc
@@ -170,9 +170,10 @@ bool Node::AddConnection(const NodeName& remote_node_name,
// handling an incoming NodeConnector message, we can err on the side of
// caution (i.e. less re-entrancy in event handlers) by treating every
// case like an API call.
+ const Ref<NodeLink> link = it->second.link;
mutex_.Unlock();
const OperationContext context{OperationContext::kAPICall};
- DropConnection(context, *it->second.link);
+ DropConnection(context, *link);
mutex_.Lock();
}

View File

@@ -0,0 +1,25 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samuel Attard <marshallofsound@electronjs.org>
Date: Tue, 21 Nov 2023 15:03:21 -0800
Subject: fix: restore original resize performance on macOS
Reverts https://chromium-review.googlesource.com/c/chromium/src/+/3118293 which
fixed a android only regression but in the process regressed electron window
resize perf wildly on macOS.
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 94a726acd9a65fdddd0eed81f064d5f17d536aa3..b9ab65467ea02d5c4a5ece6708ee4a31c1c3963f 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -2198,9 +2198,8 @@ RenderWidgetHostImpl::GetWidgetInputHandler() {
void RenderWidgetHostImpl::NotifyScreenInfoChanged() {
// The resize message (which may not happen immediately) will carry with it
// the screen info as well as the new size (if the screen has changed scale
- // factor). Force sending the new visual properties even if there is one in
- // flight to ensure proper IPC ordering for features like the Fullscreen API.
- SynchronizeVisualPropertiesIgnoringPendingAck();
+ // factor).
+ SynchronizeVisualProperties();
// The device scale factor will be same for all the views contained by the
// primary main frame, so just set it once.

View File

@@ -0,0 +1,87 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ken Rockot <rockot@google.com>
Date: Tue, 30 Jan 2024 21:36:01 +0000
Subject: ipcz: Fix a few weak asserts
DriverMemory cloning should not weakly assert success, as it can fail in
real production scenarios. Now Clone() will return an invalid
DriverMemory object if it fails to duplicate the internal handle.
Existing callers of Clone() are already durable to an invalid output, so
this change results in graceful failures instead of undefined behavior.
This also replaces some weak asserts in DriverTransport creation with
hardening asserts. We may want to fail more gracefully if these end
up crashing a lot, but it seems unlikely.
(cherry picked from commit 4bd18c5a3a7a935716bbed197fba6d45a1122894)
Fixed: 1521571
Change-Id: Id764b33ead8bbba58e61b3270920c839479eaa4a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5240312
Commit-Queue: Ken Rockot <rockot@google.com>
Reviewed-by: Alex Gough <ajgo@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1252882}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5250958
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Auto-Submit: Ken Rockot <rockot@google.com>
Cr-Commit-Position: refs/branch-heads/6099@{#1905}
Cr-Branched-From: e6ee4500f7d6549a9ac1354f8d056da49ef406be-refs/heads/main@{#1217362}
diff --git a/third_party/ipcz/src/ipcz/driver_memory.cc b/third_party/ipcz/src/ipcz/driver_memory.cc
index f8761985b78409fdb5420456661b0d227030cc8f..3bdc3aaf52d166a7691b5f28ebc86cc47600f7cc 100644
--- a/third_party/ipcz/src/ipcz/driver_memory.cc
+++ b/third_party/ipcz/src/ipcz/driver_memory.cc
@@ -30,10 +30,11 @@ DriverMemory::DriverMemory(const IpczDriver& driver, size_t num_bytes)
: size_(num_bytes) {
ABSL_ASSERT(num_bytes > 0);
IpczDriverHandle handle;
- IpczResult result =
+ const IpczResult result =
driver.AllocateSharedMemory(num_bytes, IPCZ_NO_FLAGS, nullptr, &handle);
- ABSL_ASSERT(result == IPCZ_RESULT_OK);
- memory_ = DriverObject(driver, handle);
+ if (result == IPCZ_RESULT_OK) {
+ memory_ = DriverObject(driver, handle);
+ }
}
DriverMemory::DriverMemory(DriverMemory&& other) = default;
@@ -43,12 +44,14 @@ DriverMemory& DriverMemory::operator=(DriverMemory&& other) = default;
DriverMemory::~DriverMemory() = default;
DriverMemory DriverMemory::Clone() {
- ABSL_ASSERT(is_valid());
+ ABSL_HARDENING_ASSERT(is_valid());
IpczDriverHandle handle;
- IpczResult result = memory_.driver()->DuplicateSharedMemory(
+ const IpczResult result = memory_.driver()->DuplicateSharedMemory(
memory_.handle(), 0, nullptr, &handle);
- ABSL_ASSERT(result == IPCZ_RESULT_OK);
+ if (result != IPCZ_RESULT_OK) {
+ return DriverMemory();
+ }
return DriverMemory(DriverObject(*memory_.driver(), handle));
}
diff --git a/third_party/ipcz/src/ipcz/driver_transport.cc b/third_party/ipcz/src/ipcz/driver_transport.cc
index 096f1b3bed3cfbe0074b074edba21bcfceacd897..dbeb69a0a881a82c9360118a017942ec6eb920f8 100644
--- a/third_party/ipcz/src/ipcz/driver_transport.cc
+++ b/third_party/ipcz/src/ipcz/driver_transport.cc
@@ -68,14 +68,14 @@ DriverTransport::Pair DriverTransport::CreatePair(
IpczDriverHandle target_transport0 = IPCZ_INVALID_DRIVER_HANDLE;
IpczDriverHandle target_transport1 = IPCZ_INVALID_DRIVER_HANDLE;
if (transport0) {
- ABSL_ASSERT(transport1);
+ ABSL_HARDENING_ASSERT(transport1);
target_transport0 = transport0->driver_object().handle();
target_transport1 = transport1->driver_object().handle();
}
IpczResult result = driver.CreateTransports(
target_transport0, target_transport1, IPCZ_NO_FLAGS, nullptr,
&new_transport0, &new_transport1);
- ABSL_ASSERT(result == IPCZ_RESULT_OK);
+ ABSL_HARDENING_ASSERT(result == IPCZ_RESULT_OK);
auto first =
MakeRefCounted<DriverTransport>(DriverObject(driver, new_transport0));
auto second =

View File

@@ -0,0 +1,66 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Rebekah Potter <rbpotter@chromium.org>
Date: Fri, 15 Dec 2023 19:23:42 +0000
Subject: Reland mojom_ts_generator: Handle empty module path identically to
'/'
Reason for revert: Original change was reverted incorrectly.
Original change's description:
> Revert "mojom_ts_generator: Handle empty module path identically to '/'"
>
> This reverts commit 4d1f1115f0f70c7ff4493f64221fdf15810c5005.
>
> Reason for revert: The tree is down https://ci.chromium.org/ui/p/chromium/builders/ci/Linux%20Chromium%20OS%20ASan%20LSan%20Builder/82276/overview
>
> Original change's description:
> > mojom_ts_generator: Handle empty module path identically to '/'
> >
> > Fixes an issue with Python 3.11.2. Workaround originally proposed at
> > https://bugs.chromium.org/p/chromium/issues/detail?id=1422178#c4
> >
> > Bug: 1422178
> > Change-Id: I4f02cbd4a0aafbab1a7fef8a36d812f1621c75e4
> > Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5121571
> > Reviewed-by: Demetrios Papadopoulos <dpapad@chromium.org>
> > Commit-Queue: Rebekah Potter <rbpotter@chromium.org>
> > Cr-Commit-Position: refs/heads/main@{#1237792}
>
> Bug: 1422178
> Change-Id: Icb352e5b437deee34100d213bd9c1bc0cedaaaf4
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5124992
> Owners-Override: Shibalik Mohapatra <shibalik@chromium.org>
> Commit-Queue: Shibalik Mohapatra <shibalik@chromium.org>
> Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
> Cr-Commit-Position: refs/heads/main@{#1237835}
Bug: 1422178
Change-Id: I2486fca59de0b28efc38020de8cd3d01a56eca98
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5125915
Commit-Queue: Demetrios Papadopoulos <dpapad@chromium.org>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/heads/main@{#1238190}
diff --git a/mojo/public/tools/bindings/generators/mojom_ts_generator.py b/mojo/public/tools/bindings/generators/mojom_ts_generator.py
index d8e0cf30486690b5aa33906985642dc8f7f762f5..1c43796152811d020370aa0a42bc4fddf8b05c06 100644
--- a/mojo/public/tools/bindings/generators/mojom_ts_generator.py
+++ b/mojo/public/tools/bindings/generators/mojom_ts_generator.py
@@ -175,8 +175,10 @@ def _GetWebUiModulePath(module):
path. Otherwise, returned paths always end in a '/' and begin with either
`chrome://resources/` or a '/'."""
path = module.metadata.get('webui_module_path')
- if path is None or path == '/':
- return path
+ if path is None:
+ return None
+ if path == '' or path == '/':
+ return '/'
if _IsAbsoluteChromeResourcesPath(path):
return path.rstrip('/') + '/'
return '/{}/'.format(path.strip('/'))

View File

@@ -0,0 +1,55 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Bo Liu <boliu@chromium.org>
Date: Mon, 4 Dec 2023 15:01:22 +0000
Subject: Safely crash on dangling profile
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Bug: 1407197
Change-Id: Idcafd8f0ba2f980d06338e573489a3456e3823c1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5080603
Reviewed-by: Łukasz Anforowicz <lukasza@chromium.org>
Commit-Queue: Bo Liu <boliu@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1232704}
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 23f68b9f9c108fd74bcba15289c1a2082a53c486..4675791781d2452732cfe4ddc93bfdf3f6f8bb03 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -222,6 +222,11 @@ BASE_FEATURE(kBackNavigationPredictionMetrics,
"BackNavigationPredictionMetrics",
base::FEATURE_ENABLED_BY_DEFAULT);
+// Kill switch for crash immediately on dangling BrowserContext.
+BASE_FEATURE(kCrashOnDanglingBrowserContext,
+ "CrashOnDanglingBrowserContext",
+ base::FEATURE_ENABLED_BY_DEFAULT);
+
using LifecycleState = RenderFrameHost::LifecycleState;
using LifecycleStateImpl = RenderFrameHostImpl::LifecycleStateImpl;
@@ -940,11 +945,18 @@ class WebContentsOfBrowserContext : public base::SupportsUserData::Data {
env, web_contents_with_dangling_ptr_to_browser_context);
#endif // BUILDFLAG(IS_ANDROID)
- NOTREACHED()
- << "BrowserContext is getting destroyed without first closing all "
- << "WebContents (for more info see https://crbug.com/1376879#c44); "
- << "creator = " << creator;
- base::debug::DumpWithoutCrashing();
+ if (base::FeatureList::IsEnabled(kCrashOnDanglingBrowserContext)) {
+ LOG(FATAL)
+ << "BrowserContext is getting destroyed without first closing all "
+ << "WebContents (for more info see https://crbug.com/1376879#c44); "
+ << "creator = " << creator;
+ } else {
+ NOTREACHED()
+ << "BrowserContext is getting destroyed without first closing all "
+ << "WebContents (for more info see https://crbug.com/1376879#c44); "
+ << "creator = " << creator;
+ base::debug::DumpWithoutCrashing();
+ }
}
}

View File

@@ -0,0 +1,85 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Avi Drissman <avi@chromium.org>
Date: Wed, 27 Sep 2023 19:48:06 +0000
Subject: Scale rects properly in SyncGetFirstRectForRange
When dsf-for-zoom was enabled in https://crrev.com/c/2577963,
coordinates coming from Blink were changed to be pixels and not DIPs,
but the RenderWidgetHostViewMac::SyncGetFirstRectForRange() function
was never updated.
LocalFrameMojoHandler::GetFirstRectForRange() sometimes returned
physical pixels and sometimes DIPs. Because most functions in
RenderWidgetHostViewMac do coordinate conversion, fix
GetFirstRectForRange() to always return physical pixels, and make
GetDeviceScaleFactor() scale the returned value like the other
functions in RenderWidgetHostViewMac do.
Fixed: 1486615
Change-Id: I6d5c29b2020eca38d566f5f50ebc010a371f97a2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4894366
Code-Coverage: findit-for-me@appspot.gserviceaccount.com <findit-for-me@appspot.gserviceaccount.com>
Reviewed-by: Keren Zhu <kerenzhu@chromium.org>
Reviewed-by: Nate Chapin <japhet@chromium.org>
Reviewed-by: Dominic Farolino <dom@chromium.org>
Commit-Queue: Avi Drissman <avi@chromium.org>
Auto-Submit: Avi Drissman <avi@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1202056}
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm
index e995e9b652397a67ca0b89e107975ab04bae7725..e3762097cea0dc10c486f2150f18722363f8b788 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -75,6 +75,7 @@
#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/events/keycodes/dom/dom_keyboard_layout_map.h"
#include "ui/gfx/geometry/dip_util.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/mac/coordinate_conversion.h"
using blink::WebInputEvent;
@@ -2019,8 +2020,13 @@ void CombineTextNodesAndMakeCallback(SpeechCallback callback,
// https://crbug.com/121917
base::ScopedAllowBlocking allow_wait;
// TODO(thakis): Pipe |actualRange| through TextInputClientMac machinery.
- *rect = TextInputClientMac::GetInstance()->GetFirstRectForRange(
- GetFocusedWidget(), requested_range);
+ gfx::Rect blink_rect =
+ TextInputClientMac::GetInstance()->GetFirstRectForRange(
+ GetFocusedWidget(), requested_range);
+
+ // With zoom-for-dsf, RenderWidgetHost coordinate system is physical points,
+ // which means we have to scale the rect by the device scale factor.
+ *rect = gfx::ScaleToEnclosingRect(blink_rect, 1.f / GetDeviceScaleFactor());
}
return true;
}
diff --git a/third_party/blink/public/mojom/input/text_input_host.mojom b/third_party/blink/public/mojom/input/text_input_host.mojom
index e7440063084c347e380a61909029da6f710345b0..58a1960eedd544de1cbf1714457e7d4dc671293d 100644
--- a/third_party/blink/public/mojom/input/text_input_host.mojom
+++ b/third_party/blink/public/mojom/input/text_input_host.mojom
@@ -23,7 +23,8 @@ interface TextInputHost {
GotCharacterIndexAtPoint(uint32 index);
// Reply for GetFirstRectForRange from LocalFrame. It works in the same
- // manner as GetCharacterIndexAtPoint.
+ // manner as GetCharacterIndexAtPoint. The returned rect is in physical
+ // pixels.
// [EnableIf=is_mac]
GotFirstRectForRange(gfx.mojom.Rect rect);
};
diff --git a/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc b/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc
index e2cdf0c00cf165cbd8f7f2279ddffcd2b71c0fda..15a7a2720179638fe3b3885a8bfa969339e0eff4 100644
--- a/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc
@@ -957,9 +957,7 @@ void LocalFrameMojoHandler::GetFirstRectForRange(const gfx::Range& range) {
WebPluginContainerImpl* plugin_container = frame_->GetWebPluginContainer();
if (plugin_container) {
// Pepper-free PDF will reach here.
- FrameWidget* frame_widget = frame_->GetWidgetForLocalRoot();
- rect = frame_widget->BlinkSpaceToEnclosedDIPs(
- plugin_container->Plugin()->GetPluginCaretBounds());
+ rect = plugin_container->Plugin()->GetPluginCaretBounds();
} else {
// TODO(crbug.com/702990): Remove `pepper_has_caret` once pepper is removed.
bool pepper_has_caret = client->GetCaretBoundsFromFocusedPlugin(rect);

View File

@@ -11,6 +11,8 @@
"src/electron/patches/node": "src/third_party/electron_node",
"src/electron/patches/libavif": "src/third_party/libavif/src",
"src/electron/patches/nan": "src/third_party/nan",
"src/electron/patches/perfetto": "src/third_party/perfetto",
@@ -21,7 +23,13 @@
"src/electron/patches/ReactiveObjC": "src/third_party/squirrel.mac/vendor/ReactiveObjC",
"src/electron/patches/skia": "src/third_party/skia",
"src/electron/patches/webrtc": "src/third_party/webrtc",
"src/electron/patches/dawn": "src/third_party/dawn"
"src/electron/patches/dawn": "src/third_party/dawn",
"src/electron/patches/angle": "src/third_party/angle",
"src/electron/patches/sqlite": "src/third_party/sqlite/src"
}

3
patches/libavif/.patches Normal file
View File

@@ -0,0 +1,3 @@
remove_potential_out_of_bound_access_to_alphaitemindices.patch
do_not_store_potentially_invalid_pointers.patch
do_not_store_colorproperties_until_alpha_item_is_found.patch

View File

@@ -0,0 +1,31 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Vignesh Venkatasubramanian <vigneshv@google.com>
Date: Tue, 28 Nov 2023 08:44:22 -0800
Subject: Do not store colorproperties until alpha item is found
colorProperties could be pointing to a dangling pointer if
findAlphaItem() resizes the meta.items array.
Manual cherry-pick of PR #1808 into the chromium-m118 branch.
diff --git a/src/read.c b/src/read.c
index 73aa68eb0ad377e95038280fea1523dd909b6e87..ab490f6ddbd983321af8fae94cdf34dd32058160 100644
--- a/src/read.c
+++ b/src/read.c
@@ -3918,7 +3918,6 @@ avifResult avifDecoderReset(avifDecoder * decoder)
avifDiagnosticsPrintf(&decoder->diag, "Primary item not found");
return AVIF_RESULT_MISSING_IMAGE_ITEM;
}
- colorProperties = &colorItem->properties;
if (!memcmp(colorItem->type, "grid", 4)) {
avifROData readData;
AVIF_CHECKRES(avifDecoderItemRead(colorItem, decoder->io, &readData, 0, 0, data->diag));
@@ -3965,6 +3964,8 @@ avifResult avifDecoderReset(avifDecoder * decoder)
}
}
+ colorProperties = &colorItem->properties;
+
// Find Exif and/or XMP metadata, if any
AVIF_CHECKRES(avifDecoderFindMetadata(decoder, data->meta, decoder->image, colorItem->id));

View File

@@ -0,0 +1,68 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Vignesh Venkatasubramanian <vigneshv@google.com>
Date: Wed, 15 Nov 2023 15:22:49 -0800
Subject: Do not store potentially invalid pointers
Manual cherry-pick of PR #1757 into the chromium-m118 branch.
diff --git a/src/read.c b/src/read.c
index d8699bb1442645d358f13f1904d7fbb9237bb999..73aa68eb0ad377e95038280fea1523dd909b6e87 100644
--- a/src/read.c
+++ b/src/read.c
@@ -769,6 +769,8 @@ static void avifMetaDestroy(avifMeta * meta)
avifFree(meta);
}
+// CAUTION: This function could potentially resize the meta->items array thereby invalidating all existing pointers that are being
+// stored locally. So if this function is being called, exercise caution in the caller to not use invalid pointers.
static avifDecoderItem * avifMetaFindItem(avifMeta * meta, uint32_t itemID)
{
if (itemID == 0) {
@@ -3596,17 +3598,20 @@ static avifBool avifDecoderItemIsAlphaAux(avifDecoderItem * item, uint32_t color
return auxCProp && isAlphaURN(auxCProp->u.auxC.auxType);
}
-// Finds the alpha item whose parent item is colorItem and sets it in the alphaItem output parameter. Returns AVIF_RESULT_OK on
-// success. Note that *alphaItem can be NULL even if the return value is AVIF_RESULT_OK. If the colorItem is a grid and the alpha
-// item is represented as a set of auxl items to each color tile, then a fake item will be created and *isAlphaItemInInput will be
-// set to AVIF_FALSE. In this case, the alpha item merely exists to hold the locations of the alpha tile items. The data of this
-// item need not be read and the pixi property cannot be validated. Otherwise, *isAlphaItemInInput will be set to AVIF_TRUE when
-// *alphaItem is not NULL.
+// Finds the alpha item whose parent item is *colorItemPtr and sets it in the alphaItem output parameter. Returns AVIF_RESULT_OK
+// on success. Note that *alphaItem can be NULL even if the return value is AVIF_RESULT_OK. If the *colorItemPtr is a grid and the
+// alpha item is represented as a set of auxl items to each color tile, then a fake item will be created and *isAlphaItemInInput
+// will be set to AVIF_FALSE. In this case, the alpha item merely exists to hold the locations of the alpha tile items. The data
+// of this item need not be read and the pixi property cannot be validated. Otherwise, *isAlphaItemInInput will be set to
+// AVIF_TRUE when *alphaItem is not NULL. If the data->meta->items array is resized, then the value in *colorItemPtr could become
+// invalid. This function also resets *colorItemPtr to the right value if an alpha item was found and added to the data->meta->items
+// array.
static avifResult avifDecoderDataFindAlphaItem(avifDecoderData * data,
- avifDecoderItem * colorItem,
+ avifDecoderItem ** colorItemPtr,
avifDecoderItem ** alphaItem,
avifBool * isAlphaItemInInput)
{
+ const avifDecoderItem * colorItem = *colorItemPtr;
for (uint32_t itemIndex = 0; itemIndex < data->meta->items.count; ++itemIndex) {
avifDecoderItem * item = &data->meta->items.item[itemIndex];
if (avifDecoderItemShouldBeSkipped(item)) {
@@ -3682,6 +3687,10 @@ static avifResult avifDecoderDataFindAlphaItem(avifDecoderData * data,
*isAlphaItemInInput = AVIF_FALSE;
return AVIF_RESULT_OUT_OF_MEMORY;
}
+ // avifMetaFindItem() could invalidate all existing item pointers. So reset the colorItem pointers.
+ *colorItemPtr = &data->meta->items.item[colorItemIndex];
+ colorItem = *colorItemPtr;
+
memcpy((*alphaItem)->type, "grid", 4);
(*alphaItem)->width = colorItem->width;
(*alphaItem)->height = colorItem->height;
@@ -3931,7 +3940,7 @@ avifResult avifDecoderReset(avifDecoder * decoder)
avifBool isAlphaItemInInput;
avifDecoderItem * alphaItem;
- AVIF_CHECKRES(avifDecoderDataFindAlphaItem(data, colorItem, &alphaItem, &isAlphaItemInInput));
+ AVIF_CHECKRES(avifDecoderDataFindAlphaItem(data, &colorItem, &alphaItem, &isAlphaItemInInput));
avifCodecType alphaCodecType = AVIF_CODEC_TYPE_UNKNOWN;
if (alphaItem) {
if (!memcmp(alphaItem->type, "grid", 4)) {

View File

@@ -0,0 +1,78 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Vignesh Venkatasubramanian <vigneshv@google.com>
Date: Mon, 13 Nov 2023 19:39:10 -0800
Subject: Remove potential out of bound access to alphaItemIndices
It is possible to craft a file that has more alpha auxiliary items
than color items and trigger an out of bound access into
alphaItemIndices in the for loop.
Fix is to ensure that each color grid item has exactly one alpha
grid item. Also, ensure that there are exactly the same number of
color grids as informed in the grid config before trying to
find the alpha item.
Also, update a diagnostic error message to cover all cases (i.e.)
there can be more grids than necessary as well.
diff --git a/src/read.c b/src/read.c
index e4021898eb120828544afdf0f28cc0e5d4ede876..d8699bb1442645d358f13f1904d7fbb9237bb999 100644
--- a/src/read.c
+++ b/src/read.c
@@ -1417,7 +1417,7 @@ static avifBool avifDecoderGenerateImageGridTiles(avifDecoder * decoder, avifIma
if (tilesAvailable != grid->rows * grid->columns) {
avifDiagnosticsPrintf(&decoder->diag,
- "Grid image of dimensions %ux%u requires %u tiles, and only %u were found",
+ "Grid image of dimensions %ux%u requires %u tiles, but %u were found",
grid->columns,
grid->rows,
grid->rows * grid->columns,
@@ -3641,21 +3641,41 @@ static avifResult avifDecoderDataFindAlphaItem(avifDecoderData * data,
maxItemID = item->id;
}
if (item->dimgForID == colorItem->id) {
+ avifBool seenAlphaForCurrentItem = AVIF_FALSE;
for (uint32_t j = 0; j < colorItem->meta->items.count; ++j) {
avifDecoderItem * auxlItem = &colorItem->meta->items.item[j];
if (avifDecoderItemIsAlphaAux(auxlItem, item->id)) {
+ if (seenAlphaForCurrentItem || auxlItem->dimgForID != 0) {
+ // One of the following invalid cases:
+ // * Multiple items are claiming to be the alpha auxiliary of the current item.
+ // * Alpha auxiliary is dimg for another item.
+ avifFree(alphaItemIndices);
+ *isAlphaItemInInput = AVIF_FALSE;
+ return AVIF_RESULT_INVALID_IMAGE_GRID;
+ }
alphaItemIndices[alphaItemCount++] = j;
+ seenAlphaForCurrentItem = AVIF_TRUE;
}
}
+ if (!seenAlphaForCurrentItem) {
+ // No alpha auxiliary item was found for the current item. Treat this as an image without alpha.
+ avifFree(alphaItemIndices);
+ *isAlphaItemInInput = AVIF_FALSE;
+ return AVIF_RESULT_OK;
+ }
}
}
- if (alphaItemCount != colorItemCount) {
- // Not all the color items had an alpha auxiliary attached to it. Report this case as an image without alpha channel.
- avifFree(alphaItemIndices);
- *alphaItem = NULL;
- *isAlphaItemInInput = AVIF_FALSE;
- return AVIF_RESULT_OK;
+ assert(alphaItemCount == colorItemCount);
+
+ int colorItemIndex = -1;
+ for (uint32_t i = 0; i < data->meta->items.count; ++i) {
+ if (colorItem->id == data->meta->items.item[i].id) {
+ colorItemIndex = i;
+ break;
+ }
}
+ assert(colorItemIndex >= 0);
+
*alphaItem = avifMetaFindItem(colorItem->meta, maxItemID + 1);
if (*alphaItem == NULL) {
avifFree(alphaItemIndices);

View File

@@ -45,3 +45,5 @@ net_fix_crash_due_to_simultaneous_close_shutdown_on_js_stream.patch
net_use_asserts_in_js_socket_stream_to_catch_races_in_future.patch
lib_fix_broadcastchannel_initialization_location.patch
win_process_avoid_assert_after_spawning_store_app_4152.patch
fix_backport_avx_detection_fix_from_simdutf_3_2_9.patch
fix_avx_detection.patch

View File

@@ -0,0 +1,33 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samuel Attard <marshallofsound@electronjs.org>
Date: Wed, 15 Nov 2023 13:31:14 -0800
Subject: Fix AVX detection
The old/faulty code would try to use AVX/AVX2 if either the SSE bit or
the AVX bit were set in XCR0, but did not check if both bits were set.
In most cases, this still worked, but on some machines, enabling linux
kernel mitigations for the "gather data sampling" vulnerability results
in only the SSE bit but not the AVX bit being set, thus resulting in an
illegal instruction and crashing the application.
Fix this by checking that both bits are set.
Fixes: 4bbb590 ("Proper check of CPU's AVX2 feature support (with MSVC support)")
Signed-off-by: Pascal Ernster <git@hardfalcon.net>
Cherry-Picked from https://github.com/aklomp/base64/commit/9003f9b183327df80fda97aa82dfc8054e1d3dce
diff --git a/deps/base64/base64/lib/codec_choose.c b/deps/base64/base64/lib/codec_choose.c
index 6a07d6a74cc24f61cf2b16d13c075234d5c7e2a3..f4215f1ef9d42087ef6735e6817c714ecc43a0ca 100644
--- a/deps/base64/base64/lib/codec_choose.c
+++ b/deps/base64/base64/lib/codec_choose.c
@@ -194,7 +194,7 @@ codec_choose_x86 (struct codec *codec)
if (ecx & bit_XSAVE_XRSTORE) {
uint64_t xcr_mask;
xcr_mask = _xgetbv(_XCR_XFEATURE_ENABLED_MASK);
- if (xcr_mask & _XCR_XMM_AND_YMM_STATE_ENABLED_BY_OS) {
+ if ((xcr_mask & _XCR_XMM_AND_YMM_STATE_ENABLED_BY_OS) == _XCR_XMM_AND_YMM_STATE_ENABLED_BY_OS) { // check multiple bits at once
#if HAVE_AVX2
if (max_level >= 7) {
__cpuid_count(7, 0, eax, ebx, ecx, edx);

View File

@@ -0,0 +1,99 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Lemire <daniel@lemire.me>
Date: Fri, 12 May 2023 15:20:29 -0400
Subject: Fix: Backport AVX detection fix from simdutf 3.2.9
simdutf < 3.2.9 contains a flawed detection routine to decide whether
AVX and/or AVX2 can be used. In most cases, it works good enough, but
in some corner cases (combination of specific CPU model, microcode
version, operating system and OS configuration), that flawed detection
results in simdutf trying to use AVX/AVX2 although the OS doesn't allow
its use (for example as a mitigation measure against the "gather data
sampling" vulnerability), which then crashes the application with an
illegal instruction error.
This fix is only needed for node < 18.17.0, because later versions use
a simdutf version > 3.2.9.
Cherry-picked and backported from https://github.com/simdutf/simdutf/commit/55b107f609f5f63880db650a92861ae84cb10abe
Co-authored-by: Daniel Lemire <daniel@lemire.me>
Co-authored-by: easyaspi314 <easyaspi314@users.noreply.github.com>
Signed-off-by: Pascal Ernster <git@hardfalcon.net>
diff --git a/deps/simdutf/simdutf.h b/deps/simdutf/simdutf.h
index 80189d316cba8c9127b652da9e0bcb76d5b9eeb4..4e5ce1e26b6b803698e55436ce0c0ab358662c9e 100644
--- a/deps/simdutf/simdutf.h
+++ b/deps/simdutf/simdutf.h
@@ -706,6 +706,7 @@ namespace cpuid_bit {
// EAX = 0x01
constexpr uint32_t pclmulqdq = uint32_t(1) << 1; ///< @private bit 1 of ECX for EAX=0x1
constexpr uint32_t sse42 = uint32_t(1) << 20; ///< @private bit 20 of ECX for EAX=0x1
+ constexpr uint32_t osxsave = (uint32_t(1) << 26) | (uint32_t(1) << 27); ///< @private bits 26+27 of ECX for EAX=0x1
// EAX = 0x7f (Structured Extended Feature Flags), ECX = 0x00 (Sub-leaf)
// See: "Table 3-8. Information Returned by CPUID Instruction"
@@ -731,6 +732,10 @@ namespace cpuid_bit {
namespace edx {
constexpr uint32_t avx512vp2intersect = uint32_t(1) << 8;
}
+ namespace xcr0_bit {
+ constexpr uint64_t avx256_saved = uint64_t(1) << 2; ///< @private bit 2 = AVX
+ constexpr uint64_t avx512_saved = uint64_t(7) << 5; ///< @private bits 5,6,7 = opmask, ZMM_hi256, hi16_ZMM
+ }
}
}
@@ -740,7 +745,7 @@ static inline void cpuid(uint32_t *eax, uint32_t *ebx, uint32_t *ecx,
uint32_t *edx) {
#if defined(_MSC_VER)
int cpu_info[4];
- __cpuid(cpu_info, *eax);
+ __cpuidex(cpu_info, *eax, *ecx);
*eax = cpu_info[0];
*ebx = cpu_info[1];
*ecx = cpu_info[2];
@@ -758,6 +763,16 @@ static inline void cpuid(uint32_t *eax, uint32_t *ebx, uint32_t *ecx,
#endif
}
+static inline uint64_t xgetbv() {
+ #if defined(_MSC_VER)
+ return _xgetbv(0);
+ #else
+ uint32_t xcr0_lo, xcr0_hi;
+ asm volatile("xgetbv\n\t" : "=a" (xcr0_lo), "=d" (xcr0_hi) : "c" (0));
+ return xcr0_lo | ((uint64_t)xcr0_hi << 32);
+ #endif
+ }
+
static inline uint32_t detect_supported_architectures() {
uint32_t eax;
uint32_t ebx = 0;
@@ -777,6 +792,16 @@ static inline uint32_t detect_supported_architectures() {
host_isa |= instruction_set::PCLMULQDQ;
}
+ if ((ecx & cpuid_bit::osxsave) != cpuid_bit::osxsave) {
+ return host_isa;
+ }
+
+ // xgetbv for checking if the OS saves registers
+ uint64_t xcr0 = xgetbv();
+
+ if ((xcr0 & cpuid_bit::xcr0_bit::avx256_saved) == 0) {
+ return host_isa;
+ }
// ECX for EAX=0x7
eax = 0x7;
ecx = 0x0; // Sub-leaf = 0
@@ -790,6 +815,9 @@ static inline uint32_t detect_supported_architectures() {
if (ebx & cpuid_bit::ebx::bmi2) {
host_isa |= instruction_set::BMI2;
}
+ if (!((xcr0 & cpuid_bit::xcr0_bit::avx512_saved) == cpuid_bit::xcr0_bit::avx512_saved)) {
+ return host_isa;
+ }
if (ebx & cpuid_bit::ebx::avx512f) {
host_isa |= instruction_set::AVX512F;
}

View File

@@ -0,0 +1 @@
cherry-pick-971d6055e7b7.patch

View File

@@ -0,0 +1,142 @@
From 971d6055e7b78c474e2e734e55a2991fbb7ab665 Mon Sep 17 00:00:00 2001
From: Jordan Bayles <jophba@chromium.org>
Date: Mon, 30 Oct 2023 15:10:00 -0700
Subject: [PATCH] [Cast Streaming] fix heap use-after-free
This patch fixes a use after free, caused by using an iterator
after it has been invalidated by a call to std::map::erase().
Bug: 1491210
Change-Id: I0c546eb6474af82f052b89e819a4886a004270f0
Reviewed-on: https://chromium-review.googlesource.com/c/openscreen/+/4981212
Reviewed-by: Mark Foltz <mfoltz@chromium.org>
Commit-Queue: Jordan Bayles <jophba@chromium.org>
Reviewed-by: Muyao Xu <muyaoxu@google.com>
---
diff --git a/cast/streaming/statistics_analyzer.cc b/cast/streaming/statistics_analyzer.cc
index b0658f5..81d10c5 100644
--- a/cast/streaming/statistics_analyzer.cc
+++ b/cast/streaming/statistics_analyzer.cc
@@ -144,16 +144,22 @@
void StatisticsAnalyzer::RecordFrameLatencies(const FrameEvent& frame_event) {
FrameInfoMap& frame_infos = recent_frame_infos_.Get(frame_event.media_type);
+ // Event is too old, don't bother.
+ const bool map_is_full = frame_infos.size() == kMaxRecentFrameInfoMapSize;
+ if (map_is_full && frame_event.rtp_timestamp <= frame_infos.begin()->first) {
+ return;
+ }
+
auto it = frame_infos.find(frame_event.rtp_timestamp);
if (it == frame_infos.end()) {
+ if (map_is_full) {
+ frame_infos.erase(frame_infos.begin());
+ }
+
auto emplace_result =
frame_infos.emplace(frame_event.rtp_timestamp, FrameInfo{});
OSP_CHECK(emplace_result.second);
it = emplace_result.first;
-
- if (frame_infos.size() >= kMaxRecentFrameInfoMapSize) {
- frame_infos.erase(frame_infos.begin());
- }
}
switch (frame_event.type) {
diff --git a/cast/streaming/statistics_analyzer_unittest.cc b/cast/streaming/statistics_analyzer_unittest.cc
index 22313ce..be89474 100644
--- a/cast/streaming/statistics_analyzer_unittest.cc
+++ b/cast/streaming/statistics_analyzer_unittest.cc
@@ -635,4 +635,90 @@
(frame_interval_ms * num_events)));
}
+TEST_F(StatisticsAnalyzerTest, LotsOfEventsStillWorksProperly) {
+ constexpr std::array<StatisticsEventType, 5> kEventsToReport{
+ StatisticsEventType::kFrameCaptureBegin,
+ StatisticsEventType::kFrameCaptureEnd, StatisticsEventType::kFrameEncoded,
+ StatisticsEventType::kFrameAckSent, StatisticsEventType::kFramePlayedOut};
+ constexpr int kNumFrames = 1000;
+ constexpr int kNumEvents = kNumFrames * kEventsToReport.size();
+
+ constexpr std::array<int, 5> kFramePlayoutDelayDeltasMs{10, 14, 3, 40, 1};
+ constexpr std::array<int, 25> kTimestampOffsetsMs{
+ // clang-format off
+ 0, 13, 39, 278, 552, // Frame One.
+ 0, 14, 34, 239, 373, // Frame Two.
+ 0, 19, 29, 245, 389, // Frame Three.
+ 0, 17, 37, 261, 390, // Frame Four.
+ 0, 14, 44, 290, 440, // Frame Five.
+ // clang-format on
+ };
+
+ constexpr std::array<std::pair<StatisticType, double>, 7> kExpectedStats{{
+ {StatisticType::kNumLateFrames, 1000},
+ {StatisticType::kNumFramesCaptured, 1000},
+ {StatisticType::kAvgEndToEndLatencyMs, 428.8},
+ {StatisticType::kAvgCaptureLatencyMs, 15.4},
+ {StatisticType::kAvgFrameLatencyMs, 226},
+ {StatisticType::kAvgEncodeTimeMs, 21.2},
+ {StatisticType::kEnqueueFps, 40},
+ }};
+
+ constexpr std::array<std::pair<HistogramType, std::array<int, 30>>, 4>
+ kExpectedHistograms{
+ {{HistogramType::kCaptureLatencyMs, {0, 1000}},
+ {HistogramType::kEncodeTimeMs, {0, 200, 800}},
+ {HistogramType::kEndToEndLatencyMs,
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 200, 400, 0, 0, 200, 0, 0, 0, 0, 200
+
+ }},
+ {HistogramType::kFrameLatenessMs, {0, 800, 0, 200}}}};
+
+ // We don't check stats the first 49 times, only the last.
+ {
+ testing::InSequence s;
+ EXPECT_CALL(stats_client_, OnStatisticsUpdated(_)).Times(49);
+ EXPECT_CALL(stats_client_, OnStatisticsUpdated(_))
+ .WillOnce(Invoke([&](const SenderStats& stats) {
+ for (const auto& stat_pair : kExpectedStats) {
+ ExpectStatEq(stats.video_statistics, stat_pair.first,
+ stat_pair.second);
+ }
+ for (const auto& histogram_pair : kExpectedHistograms) {
+ ExpectHistoBuckets(stats.video_histograms, histogram_pair.first,
+ histogram_pair.second);
+ }
+ }));
+ }
+
+ analyzer_->ScheduleAnalysis();
+ RtpTimeTicks rtp_timestamp;
+ int current_event = 0;
+ for (int frame_id = 0; frame_id < kNumFrames; frame_id++) {
+ for (StatisticsEventType event_type : kEventsToReport) {
+ FrameEvent event(kDefaultFrameEvent);
+ event.type = event_type;
+ event.frame_id = FrameId(frame_id);
+ event.rtp_timestamp = rtp_timestamp;
+ event.timestamp =
+ fake_clock_.now() +
+ milliseconds(
+ kTimestampOffsetsMs[current_event % kTimestampOffsetsMs.size()]);
+ event.delay_delta = milliseconds(
+ kFramePlayoutDelayDeltasMs[frame_id %
+ kFramePlayoutDelayDeltasMs.size()]);
+ collector_->CollectFrameEvent(std::move(event));
+
+ current_event++;
+ }
+ fake_clock_.Advance(
+ milliseconds(kDefaultStatIntervalMs * kEventsToReport.size()));
+ rtp_timestamp += RtpTimeDelta::FromTicks(90);
+ }
+
+ fake_clock_.Advance(milliseconds(kDefaultStatsAnalysisIntervalMs -
+ (kDefaultStatIntervalMs * kNumEvents)));
+}
+
} // namespace openscreen::cast

1
patches/skia/.patches Normal file
View File

@@ -0,0 +1 @@
avoid_combining_extremely_large_meshes.patch

View File

@@ -0,0 +1,31 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: John Stiles <johnstiles@google.com>
Date: Fri, 24 Nov 2023 09:40:11 -0500
Subject: Avoid combining extremely large meshes.
Bug: chromium:1505053
Change-Id: I42f2ff872bbf054686ec7af0cc85ff63055fcfbf
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/782936
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
diff --git a/src/gpu/ganesh/ops/DrawMeshOp.cpp b/src/gpu/ganesh/ops/DrawMeshOp.cpp
index b2db7d873a2b2709b474c7a736b3142bc47e1889..fa35a6d72a6600c87ee22ece089c4c631de78ede 100644
--- a/src/gpu/ganesh/ops/DrawMeshOp.cpp
+++ b/src/gpu/ganesh/ops/DrawMeshOp.cpp
@@ -1000,10 +1000,13 @@ GrOp::CombineResult MeshOp::onCombineIfPossible(GrOp* t, SkArenaAlloc*, const Gr
return CombineResult::kCannotCombine;
}
+ if (fVertexCount > INT32_MAX - that->fVertexCount) {
+ return CombineResult::kCannotCombine;
+ }
if (SkToBool(fIndexCount) != SkToBool(that->fIndexCount)) {
return CombineResult::kCannotCombine;
}
- if (SkToBool(fIndexCount) && fVertexCount + that->fVertexCount > SkToInt(UINT16_MAX)) {
+ if (SkToBool(fIndexCount) && fVertexCount > UINT16_MAX - that->fVertexCount) {
return CombineResult::kCannotCombine;
}

1
patches/sqlite/.patches Normal file
View File

@@ -0,0 +1 @@
fix_a_spurious_misuse_of_aggregate_function_error_that_could_occur.patch

View File

@@ -0,0 +1,323 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: dan <Dan Kennedy>
Date: Thu, 2 Nov 2023 21:02:53 +0000
Subject: Fix a spurious "misuse of aggregate function" error that could occur
when an aggregate function was used within the FROM clause of a sub-select of
the select that owns the aggregate. e.g. "SELECT (SELECT x FROM (SELECT
sum(t1.a) AS x)) FROM t1". [forum:/forumpost/c9970a37ed | Forum post
c9970a37ed].
FossilOrigin-Name: 4470f657d2069972d02a00983252dec1f814d90c0d8d0906e320e955111e8c11
(cherry picked from commit 5e4233a9e48b124d4d342b757b34e4ae849f5cf8)
diff --git a/amalgamation/rename_exports.h b/amalgamation/rename_exports.h
index 1dd9873cd698b9708c1e0897e6f270b5dd4e20c1..3b9835c71a5117dfeb249f30d930047c8722962c 100644
--- a/amalgamation/rename_exports.h
+++ b/amalgamation/rename_exports.h
@@ -1,4 +1,4 @@
-// Copyright 2023 The Chromium Authors. All rights reserved.
+// Copyright 2024 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/amalgamation/sqlite3.c b/amalgamation/sqlite3.c
index 19637a9234893df86d3d7b12b16617bca56f36e4..3b0548b328bc750665c7d0a67302c5f6097fde4e 100644
--- a/amalgamation/sqlite3.c
+++ b/amalgamation/sqlite3.c
@@ -458,7 +458,7 @@ extern "C" {
*/
#define SQLITE_VERSION "3.42.0"
#define SQLITE_VERSION_NUMBER 3042000
-#define SQLITE_SOURCE_ID "2023-05-16 12:36:15 ec7dafdf189a95ffcd452db5e3b5370d8f7007c56a7dee464cc700fdd1027368"
+#define SQLITE_SOURCE_ID "2023-05-16 12:36:15 19c0cc92aaff58e70789b761d7dcd23bc81869624e3aafea35673b5c3939a6ff"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -18921,6 +18921,7 @@ struct NameContext {
int nRef; /* Number of names resolved by this context */
int nNcErr; /* Number of errors encountered while resolving names */
int ncFlags; /* Zero or more NC_* flags defined below */
+ int nNestedSelect; /* Number of nested selects using this NC */
Select *pWinSelect; /* SELECT statement for any window functions */
};
@@ -105274,11 +105275,12 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
while( pNC2
&& sqlite3ReferencesSrcList(pParse, pExpr, pNC2->pSrcList)==0
){
- pExpr->op2++;
+ pExpr->op2 += (1 + pNC2->nNestedSelect);
pNC2 = pNC2->pNext;
}
assert( pDef!=0 || IN_RENAME_OBJECT );
if( pNC2 && pDef ){
+ pExpr->op2 += pNC2->nNestedSelect;
assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg );
assert( SQLITE_FUNC_ANYORDER==NC_OrderAgg );
testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 );
@@ -105839,6 +105841,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
/* Recursively resolve names in all subqueries in the FROM clause
*/
+ if( pOuterNC ) pOuterNC->nNestedSelect++;
for(i=0; i<p->pSrc->nSrc; i++){
SrcItem *pItem = &p->pSrc->a[i];
if( pItem->pSelect && (pItem->pSelect->selFlags & SF_Resolved)==0 ){
@@ -105863,6 +105866,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
}
}
}
+ if( pOuterNC ) pOuterNC->nNestedSelect--;
/* Set up the local name-context to pass to sqlite3ResolveExprNames() to
** resolve the result-set expression list.
diff --git a/amalgamation/sqlite3.h b/amalgamation/sqlite3.h
index 820dbeeb157b79d3380e089f1fdd5862a4cab087..c3738817186bbfd60aa7d19a3327d6a4ca118bc3 100644
--- a/amalgamation/sqlite3.h
+++ b/amalgamation/sqlite3.h
@@ -148,7 +148,7 @@ extern "C" {
*/
#define SQLITE_VERSION "3.42.0"
#define SQLITE_VERSION_NUMBER 3042000
-#define SQLITE_SOURCE_ID "2023-05-16 12:36:15 ec7dafdf189a95ffcd452db5e3b5370d8f7007c56a7dee464cc700fdd1027368"
+#define SQLITE_SOURCE_ID "2023-05-16 12:36:15 19c0cc92aaff58e70789b761d7dcd23bc81869624e3aafea35673b5c3939a6ff"
/*
** CAPI3REF: Run-Time Library Version Numbers
diff --git a/amalgamation_dev/rename_exports.h b/amalgamation_dev/rename_exports.h
index 1dd9873cd698b9708c1e0897e6f270b5dd4e20c1..3b9835c71a5117dfeb249f30d930047c8722962c 100644
--- a/amalgamation_dev/rename_exports.h
+++ b/amalgamation_dev/rename_exports.h
@@ -1,4 +1,4 @@
-// Copyright 2023 The Chromium Authors. All rights reserved.
+// Copyright 2024 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/amalgamation_dev/sqlite3.c b/amalgamation_dev/sqlite3.c
index 36a6a8306fffaf38ff6d2feb6541c0eccd8df8fc..b10707a5fb419fc64694de2642371e43899022b8 100644
--- a/amalgamation_dev/sqlite3.c
+++ b/amalgamation_dev/sqlite3.c
@@ -458,7 +458,7 @@ extern "C" {
*/
#define SQLITE_VERSION "3.42.0"
#define SQLITE_VERSION_NUMBER 3042000
-#define SQLITE_SOURCE_ID "2023-05-16 12:36:15 ec7dafdf189a95ffcd452db5e3b5370d8f7007c56a7dee464cc700fdd1027368"
+#define SQLITE_SOURCE_ID "2023-05-16 12:36:15 19c0cc92aaff58e70789b761d7dcd23bc81869624e3aafea35673b5c3939a6ff"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -18934,6 +18934,7 @@ struct NameContext {
int nRef; /* Number of names resolved by this context */
int nNcErr; /* Number of errors encountered while resolving names */
int ncFlags; /* Zero or more NC_* flags defined below */
+ int nNestedSelect; /* Number of nested selects using this NC */
Select *pWinSelect; /* SELECT statement for any window functions */
};
@@ -105287,11 +105288,12 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
while( pNC2
&& sqlite3ReferencesSrcList(pParse, pExpr, pNC2->pSrcList)==0
){
- pExpr->op2++;
+ pExpr->op2 += (1 + pNC2->nNestedSelect);
pNC2 = pNC2->pNext;
}
assert( pDef!=0 || IN_RENAME_OBJECT );
if( pNC2 && pDef ){
+ pExpr->op2 += pNC2->nNestedSelect;
assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg );
assert( SQLITE_FUNC_ANYORDER==NC_OrderAgg );
testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 );
@@ -105852,6 +105854,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
/* Recursively resolve names in all subqueries in the FROM clause
*/
+ if( pOuterNC ) pOuterNC->nNestedSelect++;
for(i=0; i<p->pSrc->nSrc; i++){
SrcItem *pItem = &p->pSrc->a[i];
if( pItem->pSelect && (pItem->pSelect->selFlags & SF_Resolved)==0 ){
@@ -105876,6 +105879,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
}
}
}
+ if( pOuterNC ) pOuterNC->nNestedSelect--;
/* Set up the local name-context to pass to sqlite3ResolveExprNames() to
** resolve the result-set expression list.
diff --git a/amalgamation_dev/sqlite3.h b/amalgamation_dev/sqlite3.h
index 820dbeeb157b79d3380e089f1fdd5862a4cab087..c3738817186bbfd60aa7d19a3327d6a4ca118bc3 100644
--- a/amalgamation_dev/sqlite3.h
+++ b/amalgamation_dev/sqlite3.h
@@ -148,7 +148,7 @@ extern "C" {
*/
#define SQLITE_VERSION "3.42.0"
#define SQLITE_VERSION_NUMBER 3042000
-#define SQLITE_SOURCE_ID "2023-05-16 12:36:15 ec7dafdf189a95ffcd452db5e3b5370d8f7007c56a7dee464cc700fdd1027368"
+#define SQLITE_SOURCE_ID "2023-05-16 12:36:15 19c0cc92aaff58e70789b761d7dcd23bc81869624e3aafea35673b5c3939a6ff"
/*
** CAPI3REF: Run-Time Library Version Numbers
diff --git a/manifest b/manifest
index 0841fab32a918f21970cf1806a984261f1aaccfb..e7b2f86954fa8078cb3211b5e5cfcb319b50b6dc 100644
--- a/manifest
+++ b/manifest
@@ -634,14 +634,14 @@ F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7
F src/prepare.c 6350675966bd0e7ac3a464af9dbfe26db6f0d4237f4e1f1acdb17b12ad371e6e
F src/printf.c b9320cdbeca0b336c3f139fd36dd121e4167dd62b35fbe9ccaa9bab44c0af38d
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
-F src/resolve.c 3e53e02ce87c9582bd7e7d22f13f4094a271678d9dc72820fa257a2abb5e4032
+F src/resolve.c 9bcc9021a5b849ba8ccd2103147b75a3a98d885e00212b48672fe1ed8356338b
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
F src/select.c 738c3a3d6929f8be66c319bad17f6b297bd60a4eb14006075c48a28487dc7786
F src/shell.c.in a8971a2ae4adee5f0a73d7a6c095026e8a2958ff3e9f56887a014df07733ca0c
F src/sqlite.h.in c14a4471fcd897a03631ac7ad3d05505e895e7b6419ec5b96cae9bc4df7a9fc6
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h da473ce2b3d0ae407a6300c4a164589b9a6bfdbec9462688a8593ff16f3bb6e4
-F src/sqliteInt.h a3ced8b9ebc573189c87b69f24bf10d2b9cd3cefefaae52623a2fa79e6fdd408
+F src/sqliteInt.h 522f19804d86e193dbfd966cd0dd033e0f6ec092e60c3812ae066657fe152653
F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657
F src/status.c 160c445d7d28c984a0eae38c144f6419311ed3eace59b44ac6dafc20db4af749
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
@@ -731,7 +731,7 @@ F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867d
F test/affinity3.test f094773025eddf31135c7ad4cde722b7696f8eb07b97511f98585addf2a510a9
F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
F test/aggfault.test 777f269d0da5b0c2524c7ff6d99ae9a93db4f1b1839a914dd2a12e3035c29829
-F test/aggnested.test 7269d07ac879fce161cb26c8fabe65cba5715742fac8a1fccac570dcdaf28f00
+F test/aggnested.test e1977bdc0a154b99c139b879b78c46030aa6ee97fb06bf65d6784a536e25b743
F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87
F test/all.test 2ecb8bbd52416642e41c9081182a8df05d42c75637afd4488aace78cc4b69e13
F test/alter.test 313073774ab5c3f2ef1d3f0d03757c9d3a81284ae7e1b4a6ca34db088f886896
@@ -1920,7 +1920,7 @@ F test/win32heap.test 10fd891266bd00af68671e702317726375e5407561d859be1aa04696f2
F test/win32lock.test e0924eb8daac02bf80e9da88930747bd44dd9b230b7759fed927b1655b467c9c
F test/win32longpath.test 4baffc3acb2e5188a5e3a895b2b543ed09e62f7c72d713c1feebf76222fe9976
F test/win32nolock.test ac4f08811a562e45a5755e661f45ca85892bdbbc
-F test/window1.test 5ba48e9d33231e6ef16f21426bade9ccc52abf65a10587bff90a6c14fe174594
+F test/window1.test 95d0d3e43a54600beba759f9a9f4f4bf546a596b1a8cc3f70dd26bf22ce7e41a
F test/window2.tcl 492c125fa550cda1dd3555768a2303b3effbeceee215293adf8871efc25f1476
F test/window2.test e466a88bd626d66edc3d352d7d7e1d5531e0079b549ba44efb029d1fbff9fd3c
F test/window3.tcl acea6e86a4324a210fd608d06741010ca83ded9fde438341cb978c49928faf03
diff --git a/src/resolve.c b/src/resolve.c
index adfcc8dbe9cf41581a23cfc42a6d699bf86d384f..b453a5b456ea1e0db814e1bd13c3fbe706a19a38 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -1212,11 +1212,12 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
while( pNC2
&& sqlite3ReferencesSrcList(pParse, pExpr, pNC2->pSrcList)==0
){
- pExpr->op2++;
+ pExpr->op2 += (1 + pNC2->nNestedSelect);
pNC2 = pNC2->pNext;
}
assert( pDef!=0 || IN_RENAME_OBJECT );
if( pNC2 && pDef ){
+ pExpr->op2 += pNC2->nNestedSelect;
assert( SQLITE_FUNC_MINMAX==NC_MinMaxAgg );
assert( SQLITE_FUNC_ANYORDER==NC_OrderAgg );
testcase( (pDef->funcFlags & SQLITE_FUNC_MINMAX)!=0 );
@@ -1777,6 +1778,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
/* Recursively resolve names in all subqueries in the FROM clause
*/
+ if( pOuterNC ) pOuterNC->nNestedSelect++;
for(i=0; i<p->pSrc->nSrc; i++){
SrcItem *pItem = &p->pSrc->a[i];
if( pItem->pSelect && (pItem->pSelect->selFlags & SF_Resolved)==0 ){
@@ -1801,6 +1803,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
}
}
}
+ if( pOuterNC ) pOuterNC->nNestedSelect--;
/* Set up the local name-context to pass to sqlite3ResolveExprNames() to
** resolve the result-set expression list.
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 2c893770b04e06932b9c4405ff9b41a13aff68d0..ab94b56c638724a9de8ea2da49c944fb85a1923f 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -3332,6 +3332,7 @@ struct NameContext {
int nRef; /* Number of names resolved by this context */
int nNcErr; /* Number of errors encountered while resolving names */
int ncFlags; /* Zero or more NC_* flags defined below */
+ int nNestedSelect; /* Number of nested selects using this NC */
Select *pWinSelect; /* SELECT statement for any window functions */
};
diff --git a/test/aggnested.test b/test/aggnested.test
index 1b8b608803912d5d8b7a7562dd31ec4a46627da4..6599fbf90940e49ce3467c67b7c8800aa90b17c0 100644
--- a/test/aggnested.test
+++ b/test/aggnested.test
@@ -358,6 +358,60 @@ do_execsql_test 6.2.2 {
FROM t2 GROUP BY 'constant_string';
} {{}}
+#-------------------------------------------------------------------------
+reset_db
+
+do_execsql_test 7.0 {
+ CREATE TABLE invoice (
+ id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
+ amount DOUBLE PRECISION DEFAULT NULL,
+ name VARCHAR(100) DEFAULT NULL
+ );
+
+ INSERT INTO invoice (amount, name) VALUES
+ (4.0, 'Michael'), (15.0, 'Bara'), (4.0, 'Michael'), (6.0, 'John');
+}
+
+do_execsql_test 7.1 {
+ SELECT sum(amount), name
+ from invoice
+ group by name
+ having (select v > 6 from (select sum(amount) v) t)
+} {
+ 15.0 Bara
+ 8.0 Michael
+}
+
+do_execsql_test 7.2 {
+ SELECT (select 1 from (select sum(amount))) FROM invoice
+} {1}
+
+do_execsql_test 8.0 {
+ CREATE TABLE t1(x INT);
+ INSERT INTO t1 VALUES(100);
+ INSERT INTO t1 VALUES(20);
+ INSERT INTO t1 VALUES(3);
+ SELECT (SELECT y FROM (SELECT sum(x) AS y) AS t2 ) FROM t1;
+} {123}
+
+do_execsql_test 8.1 {
+ SELECT (
+ SELECT y FROM (
+ SELECT z AS y FROM (SELECT sum(x) AS z) AS t2
+ )
+ ) FROM t1;
+} {123}
+
+do_execsql_test 8.2 {
+ SELECT (
+ SELECT a FROM (
+ SELECT y AS a FROM (
+ SELECT z AS y FROM (SELECT sum(x) AS z) AS t2
+ )
+ )
+ ) FROM t1;
+} {123}
+
diff --git a/test/window1.test b/test/window1.test
index 783a739e3f1428f107932319a53e9cde91e79557..8044d43547718bb54b301c185adf60bf70ab1ae8 100644
--- a/test/window1.test
+++ b/test/window1.test
@@ -1881,7 +1881,7 @@ do_catchsql_test 57.3 {
SELECT max(y) OVER( ORDER BY (SELECT x FROM (SELECT sum(y) AS x FROM t1)))
)
FROM t3;
-} {1 {misuse of aggregate: sum()}}
+} {0 5}
# 2020-06-06 ticket 1f6f353b684fc708
reset_db

View File

@@ -4,3 +4,8 @@ fix_build_deprecated_attribute_for_older_msvc_versions.patch
fix_disable_implies_dcheck_for_node_stream_array_buffers.patch
chore_allow_customizing_microtask_policy_per_context.patch
cherry-pick-57d372c3e399.patch
merged_promises_async_stack_traces_fix_the_case_when_the_closure.patch
turboshaft_fix_structuraloptimization_because_of_ignored.patch
cherry-pick-389ea9be7d68.patch
cherry-pick-46cb67e3b296.patch
cherry-pick-78dd4b31847a.patch

View File

@@ -0,0 +1,341 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Toon Verwaest <verwaest@chromium.org>
Date: Thu, 11 Jan 2024 10:47:17 +0100
Subject: Drop fast last-property deletion
This interacts badly with other optimizations and isn't particularly
common.
Bug: chromium:1517354
Change-Id: I7adb51a8fc0ec47eaeb911ca2a4cbc517088e416
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5185340
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Auto-Submit: Toon Verwaest <verwaest@chromium.org>
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/main@{#91782}
diff --git a/src/runtime/runtime-object.cc b/src/runtime/runtime-object.cc
index 18ce25614edaae28f2dac7721bde4b4a83a45af6..f0483acadb8d1c9f3ea1bfbe258dc1a57b32ad99 100644
--- a/src/runtime/runtime-object.cc
+++ b/src/runtime/runtime-object.cc
@@ -72,184 +72,10 @@ MaybeHandle<Object> Runtime::HasProperty(Isolate* isolate,
: ReadOnlyRoots(isolate).false_value_handle();
}
-namespace {
-
-// This function sets the sentinel value in a deleted field. Thes sentinel has
-// to look like a proper standalone object because the slack tracking may
-// complete at any time. For this reason we use the filler map word.
-// If V8_MAP_PACKING is enabled, then the filler map word is a packed filler
-// map. Otherwise, the filler map word is the same as the filler map.
-inline void ClearField(Isolate* isolate, JSObject object, FieldIndex index) {
- if (index.is_inobject()) {
- MapWord filler_map_word =
- ReadOnlyRoots(isolate).one_pointer_filler_map_word();
-#ifndef V8_MAP_PACKING
- DCHECK_EQ(filler_map_word.ToMap(),
- ReadOnlyRoots(isolate).one_pointer_filler_map());
-#endif
- int offset = index.offset();
- TaggedField<MapWord>::Release_Store(object, offset, filler_map_word);
- } else {
- object.property_array().set(
- index.outobject_array_index(),
- ReadOnlyRoots(isolate).one_pointer_filler_map());
- }
-}
-
-void GeneralizeAllTransitionsToFieldAsMutable(Isolate* isolate, Handle<Map> map,
- Handle<Name> name) {
- InternalIndex descriptor(map->NumberOfOwnDescriptors());
-
- Handle<Map> target_maps[kPropertyAttributesCombinationsCount];
- int target_maps_count = 0;
-
- // Collect all outgoing field transitions.
- {
- DisallowGarbageCollection no_gc;
- TransitionsAccessor transitions(isolate, *map);
- transitions.ForEachTransitionTo(
- *name,
- [&](Map target) {
- DCHECK_EQ(descriptor, target.LastAdded());
- DCHECK_EQ(*name, target.GetLastDescriptorName(isolate));
- PropertyDetails details = target.GetLastDescriptorDetails(isolate);
- // Currently, we track constness only for fields.
- if (details.kind() == PropertyKind::kData &&
- details.constness() == PropertyConstness::kConst) {
- target_maps[target_maps_count++] = handle(target, isolate);
- }
- DCHECK_IMPLIES(details.kind() == PropertyKind::kAccessor,
- details.constness() == PropertyConstness::kConst);
- },
- &no_gc);
- CHECK_LE(target_maps_count, kPropertyAttributesCombinationsCount);
- }
-
- for (int i = 0; i < target_maps_count; i++) {
- Handle<Map> target = target_maps[i];
- PropertyDetails details =
- target->instance_descriptors(isolate).GetDetails(descriptor);
- Handle<FieldType> field_type(
- target->instance_descriptors(isolate).GetFieldType(descriptor),
- isolate);
- MapUpdater::GeneralizeField(isolate, target, descriptor,
- PropertyConstness::kMutable,
- details.representation(), field_type);
- DCHECK_EQ(PropertyConstness::kMutable, target->instance_descriptors(isolate)
- .GetDetails(descriptor)
- .constness());
- }
-}
-
-bool DeleteObjectPropertyFast(Isolate* isolate, Handle<JSReceiver> receiver,
- Handle<Object> raw_key) {
- // This implements a special case for fast property deletion: when the
- // last property in an object is deleted, then instead of normalizing
- // the properties, we can undo the last map transition, with a few
- // prerequisites:
- // (1) The receiver must be a regular object and the key a unique name.
- Handle<Map> receiver_map(receiver->map(), isolate);
- if (receiver_map->IsSpecialReceiverMap()) return false;
- DCHECK(receiver_map->IsJSObjectMap());
-
- if (!raw_key->IsUniqueName()) return false;
- Handle<Name> key = Handle<Name>::cast(raw_key);
- // (2) The property to be deleted must be the last property.
- int nof = receiver_map->NumberOfOwnDescriptors();
- if (nof == 0) return false;
- InternalIndex descriptor(nof - 1);
- Handle<DescriptorArray> descriptors(
- receiver_map->instance_descriptors(isolate), isolate);
- if (descriptors->GetKey(descriptor) != *key) return false;
- // (3) The property to be deleted must be deletable.
- PropertyDetails details = descriptors->GetDetails(descriptor);
- if (!details.IsConfigurable()) return false;
- // (4) The map must have a back pointer.
- Handle<Object> backpointer(receiver_map->GetBackPointer(), isolate);
- if (!backpointer->IsMap()) return false;
- Handle<Map> parent_map = Handle<Map>::cast(backpointer);
- // (5) The last transition must have been caused by adding a property
- // (and not any kind of special transition).
- if (parent_map->NumberOfOwnDescriptors() != nof - 1) return false;
-
- // Preconditions successful. No more bailouts after this point.
-
- // Zap the property to avoid keeping objects alive. Zapping is not necessary
- // for properties stored in the descriptor array.
- if (details.location() == PropertyLocation::kField) {
- DisallowGarbageCollection no_gc;
-
- // Invalidate slots manually later in case we delete an in-object tagged
- // property. In this case we might later store an untagged value in the
- // recorded slot.
- isolate->heap()->NotifyObjectLayoutChange(*receiver, no_gc,
- InvalidateRecordedSlots::kNo);
- FieldIndex index =
- FieldIndex::ForPropertyIndex(*receiver_map, details.field_index());
- // Special case deleting the last out-of object property.
- if (!index.is_inobject() && index.outobject_array_index() == 0) {
- DCHECK(!parent_map->HasOutOfObjectProperties());
- // Clear out the properties backing store.
- receiver->SetProperties(ReadOnlyRoots(isolate).empty_fixed_array());
- } else {
- ClearField(isolate, JSObject::cast(*receiver), index);
- if (index.is_inobject()) {
- // We need to clear the recorded slot in this case because in-object
- // slack tracking might not be finished. This ensures that we don't
- // have recorded slots in free space.
- isolate->heap()->ClearRecordedSlot(*receiver,
- receiver->RawField(index.offset()));
- }
- }
- }
- // If the {receiver_map} was marked stable before, then there could be
- // optimized code that depends on the assumption that no object that
- // reached this {receiver_map} transitions away from it without triggering
- // the "deoptimize dependent code" mechanism.
- receiver_map->NotifyLeafMapLayoutChange(isolate);
- // Finally, perform the map rollback.
- receiver->set_map(*parent_map, kReleaseStore);
-#if VERIFY_HEAP
- if (v8_flags.verify_heap) {
- receiver->HeapObjectVerify(isolate);
- receiver->property_array().PropertyArrayVerify(isolate);
- }
-#endif
-
- // If the {descriptor} was "const" so far, we need to update the
- // {receiver_map} here, otherwise we could get the constants wrong, i.e.
- //
- // o.x = 1;
- // [change o.x's attributes or reconfigure property kind]
- // delete o.x;
- // o.x = 2;
- //
- // could trick V8 into thinking that `o.x` is still 1 even after the second
- // assignment.
-
- // Step 1: Migrate object to an up-to-date shape.
- if (parent_map->is_deprecated()) {
- JSObject::MigrateInstance(isolate, Handle<JSObject>::cast(receiver));
- parent_map = handle(receiver->map(), isolate);
- }
-
- // Step 2: Mark outgoing transitions from the up-to-date version of the
- // parent_map to same property name of any kind or attributes as mutable.
- // Also migrate object to the up-to-date map to make the object shapes
- // converge sooner.
- GeneralizeAllTransitionsToFieldAsMutable(isolate, parent_map, key);
-
- return true;
-}
-
-} // namespace
-
Maybe<bool> Runtime::DeleteObjectProperty(Isolate* isolate,
Handle<JSReceiver> receiver,
Handle<Object> key,
LanguageMode language_mode) {
- if (DeleteObjectPropertyFast(isolate, receiver, key)) return Just(true);
-
bool success = false;
PropertyKey lookup_key(isolate, key, &success);
if (!success) return Nothing<bool>();
diff --git a/test/cctest/test-field-type-tracking.cc b/test/cctest/test-field-type-tracking.cc
index 34e3db375bfd34f5f2f31090e766593d2102a26c..9ed4871db490761415c38468855e740239c3c201 100644
--- a/test/cctest/test-field-type-tracking.cc
+++ b/test/cctest/test-field-type-tracking.cc
@@ -3027,126 +3027,10 @@ TEST(RepresentationPredicatesAreInSync) {
}
}
-TEST(DeletePropertyGeneralizesConstness) {
- CcTest::InitializeVM();
- v8::HandleScope scope(CcTest::isolate());
- Isolate* isolate = CcTest::i_isolate();
- Handle<FieldType> any_type = FieldType::Any(isolate);
-
- // Create a map with some properties.
- Handle<Map> initial_map = Map::Create(isolate, kPropCount + 3);
- Handle<Map> map = initial_map;
- for (int i = 0; i < kPropCount; i++) {
- Handle<String> name = CcTest::MakeName("prop", i);
- map = Map::CopyWithField(isolate, map, name, any_type, NONE,
- PropertyConstness::kConst, Representation::Smi(),
- INSERT_TRANSITION)
- .ToHandleChecked();
- }
- Handle<Map> parent_map = map;
- CHECK(!map->is_deprecated());
-
- Handle<String> name_x = CcTest::MakeString("x");
- Handle<String> name_y = CcTest::MakeString("y");
-
- map = Map::CopyWithField(isolate, parent_map, name_x, any_type, NONE,
- PropertyConstness::kConst, Representation::Smi(),
- INSERT_TRANSITION)
- .ToHandleChecked();
-
- // Create an object, initialize its properties and add a couple of clones.
- Handle<JSObject> object1 = isolate->factory()->NewJSObjectFromMap(map);
- for (int i = 0; i < kPropCount; i++) {
- FieldIndex index = FieldIndex::ForDescriptor(*map, InternalIndex(i));
- object1->FastPropertyAtPut(index, Smi::FromInt(i));
- }
- Handle<JSObject> object2 = isolate->factory()->CopyJSObject(object1);
-
- CHECK(!map->is_deprecated());
- CHECK(!parent_map->is_deprecated());
-
- // Transition to Double must deprecate m1.
- CHECK(!Representation::Smi().CanBeInPlaceChangedTo(Representation::Double()));
-
- // Reconfigure one of the first properties to make the whole transition tree
- // deprecated (including |parent_map| and |map|).
- Handle<Map> new_map =
- ReconfigureProperty(isolate, map, InternalIndex(0), PropertyKind::kData,
- NONE, Representation::Double(), any_type);
- CHECK(map->is_deprecated());
- CHECK(parent_map->is_deprecated());
- CHECK(!new_map->is_deprecated());
- // The "x" property is still kConst.
- CHECK_EQ(new_map->GetLastDescriptorDetails(isolate).constness(),
- PropertyConstness::kConst);
-
- Handle<Map> new_parent_map = Map::Update(isolate, parent_map);
- CHECK(!new_parent_map->is_deprecated());
-
- // |new_parent_map| must have exactly one outgoing transition to |new_map|.
- {
- TransitionsAccessor ta(isolate, *new_parent_map);
- CHECK_EQ(ta.NumberOfTransitions(), 1);
- CHECK_EQ(ta.GetTarget(0), *new_map);
- }
-
- // Deletion of the property from |object1| must migrate it to |new_parent_map|
- // which is an up-to-date version of the |parent_map|. The |new_map|'s "x"
- // property should be marked as mutable.
- CHECK_EQ(object1->map(isolate), *map);
- CHECK(Runtime::DeleteObjectProperty(isolate, object1, name_x,
- LanguageMode::kSloppy)
- .ToChecked());
- CHECK_EQ(object1->map(isolate), *new_parent_map);
- CHECK_EQ(new_map->GetLastDescriptorDetails(isolate).constness(),
- PropertyConstness::kMutable);
-
- // Now add transitions to "x" and "y" properties from |new_parent_map|.
- std::vector<Handle<Map>> transitions;
- Handle<Object> value = handle(Smi::FromInt(0), isolate);
- for (int i = 0; i < kPropertyAttributesCombinationsCount; i++) {
- auto attributes = PropertyAttributesFromInt(i);
-
- Handle<Map> tmp;
- // Add some transitions to "x" and "y".
- tmp = Map::TransitionToDataProperty(isolate, new_parent_map, name_x, value,
- attributes, PropertyConstness::kConst,
- StoreOrigin::kNamed);
- CHECK(!tmp->map(isolate).is_dictionary_map());
- transitions.push_back(tmp);
-
- tmp = Map::TransitionToDataProperty(isolate, new_parent_map, name_y, value,
- attributes, PropertyConstness::kConst,
- StoreOrigin::kNamed);
- CHECK(!tmp->map(isolate).is_dictionary_map());
- transitions.push_back(tmp);
- }
-
- // Deletion of the property from |object2| must migrate it to |new_parent_map|
- // which is an up-to-date version of the |parent_map|.
- // All outgoing transitions from |new_map| that add "x" must be marked as
- // mutable, transitions to other properties must remain const.
- CHECK_EQ(object2->map(isolate), *map);
- CHECK(Runtime::DeleteObjectProperty(isolate, object2, name_x,
- LanguageMode::kSloppy)
- .ToChecked());
- CHECK_EQ(object2->map(isolate), *new_parent_map);
- for (Handle<Map> m : transitions) {
- if (m->GetLastDescriptorName(isolate) == *name_x) {
- CHECK_EQ(m->GetLastDescriptorDetails(isolate).constness(),
- PropertyConstness::kMutable);
-
- } else {
- CHECK_EQ(m->GetLastDescriptorDetails(isolate).constness(),
- PropertyConstness::kConst);
- }
- }
-}
-
-#define CHECK_SAME(object, rep, expected) \
- CHECK_EQ(object->FitsRepresentation(rep, true), \
- object->FitsRepresentation(rep, false)); \
- CHECK_EQ(object->FitsRepresentation(rep, true), expected)
+#define CHECK_SAME(object, rep, expected) \
+ CHECK_EQ(Object::FitsRepresentation(*object, rep, true), \
+ Object::FitsRepresentation(*object, rep, false)); \
+ CHECK_EQ(Object::FitsRepresentation(*object, rep, true), expected)
TEST(CheckFitsRepresentationPredicate) {
CcTest::InitializeVM();

View File

@@ -0,0 +1,46 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Dominik=20Inf=C3=BChr?= <dinfuehr@chromium.org>
Date: Mon, 18 Dec 2023 09:15:00 +0100
Subject: Install BytecodeArray last in SharedFunctionInfo
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Maglev assumes that when a SharedFunctionInfo has a BytecodeArray,
then it should also have FeedbackMetadata. However, this may not
hold with concurrent compilation when the SharedFunctionInfo is
re-compiled after being flushed. Here the BytecodeArray was installed
on the SFI before the FeedbackMetadata and a concurrent thread could
observe the BytecodeArray but not the FeedbackMetadata.
Drive-by: Reset the age field before setting the BytecodeArray as
well. This ensures that the concurrent marker will not observe the
old age for the new BytecodeArray.
Bug: chromium:1507412
Change-Id: I8855ed7ecc50c4a47d2c89043d62ac053858bc75
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5125960
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Commit-Queue: Dominik Inführ <dinfuehr@chromium.org>
Cr-Commit-Position: refs/heads/main@{#91568}
diff --git a/src/codegen/compiler.cc b/src/codegen/compiler.cc
index 19dd1cb14137a6681d771eccf36d0c6f80654696..4ccde99354235d926bb89807b57107509ebd34c7 100644
--- a/src/codegen/compiler.cc
+++ b/src/codegen/compiler.cc
@@ -688,12 +688,12 @@ void InstallUnoptimizedCode(UnoptimizedCompilationInfo* compilation_info,
}
#endif // V8_ENABLE_WEBASSEMBLY
- shared_info->set_bytecode_array(*compilation_info->bytecode_array());
- shared_info->set_age(0);
-
Handle<FeedbackMetadata> feedback_metadata = FeedbackMetadata::New(
isolate, compilation_info->feedback_vector_spec());
shared_info->set_feedback_metadata(*feedback_metadata, kReleaseStore);
+
+ shared_info->set_age(0);
+ shared_info->set_bytecode_array(*compilation_info->bytecode_array());
} else {
#if V8_ENABLE_WEBASSEMBLY
DCHECK(compilation_info->has_asm_wasm_data());

View File

@@ -0,0 +1,27 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Leszek Swirski <leszeks@chromium.org>
Date: Mon, 8 Jan 2024 11:13:58 +0100
Subject: Fix allocation folding in derived constructors
Bug: v8:7700
Change-Id: Ia33724d39d1397c7d47c36d14071abce6ed4b0fc
Fixed: chromium:1515930
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5173470
Commit-Queue: Patrick Thier <pthier@chromium.org>
Reviewed-by: Patrick Thier <pthier@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Auto-Submit: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#91709}
diff --git a/src/maglev/maglev-graph-builder.cc b/src/maglev/maglev-graph-builder.cc
index abe20c562f2791f10193e053d2691fdf95924485..7902a5ec0db6c3559d7594ea5061f49ba41d6bc2 100644
--- a/src/maglev/maglev-graph-builder.cc
+++ b/src/maglev/maglev-graph-builder.cc
@@ -5381,6 +5381,7 @@ void MaglevGraphBuilder::VisitFindNonDefaultConstructorOrConstruct() {
FastObject(new_target_function->AsJSFunction(), zone(),
broker()),
AllocationType::kYoung);
+ ClearCurrentRawAllocation();
} else {
object = BuildCallBuiltin<Builtin::kFastNewObject>(
{GetConstant(current_function), new_target});

View File

@@ -0,0 +1,75 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marja=20H=C3=B6ltt=C3=A4?= <marja@chromium.org>
Date: Tue, 14 Nov 2023 14:45:27 +0100
Subject: Merged: [promises, async stack traces] Fix the case when the closure
has run
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
We were using the closure pointing to NativeContext as a marker that the
closure has run, but async stack trace code was confused about it.
(cherry picked from commit bde3d360097607f36cd1d17cbe8412b84eae0a7f)
Bug: chromium:1501326
Change-Id: I30d438f3b2e3fdd7562ea9a79dde4561ce9b0083
Cr-Original-Commit-Position: refs/heads/main@{#90949}
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5110982
Commit-Queue: Marja Hölttä <marja@chromium.org>
Reviewed-by: Shu-yu Guo <syg@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Auto-Submit: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/branch-heads/12.0@{#18}
Cr-Branched-From: ed7b4caf1fb8184ad9e24346c84424055d4d430a-refs/heads/12.0.267@{#1}
Cr-Branched-From: 210e75b19db4352c9b78dce0bae11c2dc3077df4-refs/heads/main@{#90651}
diff --git a/src/execution/isolate.cc b/src/execution/isolate.cc
index 3db3d7ed372b722de1b24a39093ddefc45d6963c..5942abb480b69935d14d1c6ef06d1f4e954275a2 100644
--- a/src/execution/isolate.cc
+++ b/src/execution/isolate.cc
@@ -1013,7 +1013,13 @@ void CaptureAsyncStackTrace(Isolate* isolate, Handle<JSPromise> promise,
isolate);
builder->AppendPromiseCombinatorFrame(function, combinator);
- // Now peak into the Promise.all() resolve element context to
+ if (context->IsNativeContext()) {
+ // NativeContext is used as a marker that the closure was already
+ // called. We can't access the reject element context any more.
+ return;
+ }
+
+ // Now peek into the Promise.all() resolve element context to
// find the promise capability that's being resolved when all
// the concurrent promises resolve.
int const index =
@@ -1032,7 +1038,13 @@ void CaptureAsyncStackTrace(Isolate* isolate, Handle<JSPromise> promise,
context->native_context().promise_all_settled(), isolate);
builder->AppendPromiseCombinatorFrame(function, combinator);
- // Now peak into the Promise.allSettled() resolve element context to
+ if (context->IsNativeContext()) {
+ // NativeContext is used as a marker that the closure was already
+ // called. We can't access the reject element context any more.
+ return;
+ }
+
+ // Now peek into the Promise.allSettled() resolve element context to
// find the promise capability that's being resolved when all
// the concurrent promises resolve.
int const index =
@@ -1050,7 +1062,13 @@ void CaptureAsyncStackTrace(Isolate* isolate, Handle<JSPromise> promise,
isolate);
builder->AppendPromiseCombinatorFrame(function, combinator);
- // Now peak into the Promise.any() reject element context to
+ if (context->IsNativeContext()) {
+ // NativeContext is used as a marker that the closure was already
+ // called. We can't access the reject element context any more.
+ return;
+ }
+
+ // Now peek into the Promise.any() reject element context to
// find the promise capability that's being resolved when any of
// the concurrent promises resolve.
int const index = PromiseBuiltins::kPromiseAnyRejectElementCapabilitySlot;

View File

@@ -0,0 +1,113 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Pedro Pontes <pepontes@microsoft.com>
Date: Fri, 5 Jan 2024 05:04:35 -0800
Subject: Fix StructuralOptimization because of ignored side-effects
Side-effects in the 1st else block were not taken into account.
Drive-by: minor cleanups to StructuralOptimizationReducer.
Bug: v8:12783
Change-Id: I9666bae56c1e9f026567e8e3f0fcbad3836e8297
Fixed: chromium:1509576
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/5104648
Commit-Queue: Nico Hartmann <nicohartmann@chromium.org>
Auto-Submit: Darius Mercadier <dmercadier@chromium.org>
Reviewed-by: Nico Hartmann <nicohartmann@chromium.org>
Cr-Commit-Position: refs/heads/main@{#91432}
diff --git a/src/compiler/turboshaft/structural-optimization-reducer.h b/src/compiler/turboshaft/structural-optimization-reducer.h
index bf5a49361d884367cb3048005cbe599b59a1af2d..364e5adbbfe9ec56d03e0cb0e04c8ce6f9d3f4f1 100644
--- a/src/compiler/turboshaft/structural-optimization-reducer.h
+++ b/src/compiler/turboshaft/structural-optimization-reducer.h
@@ -80,7 +80,7 @@ namespace v8::internal::compiler::turboshaft {
template <class Next>
class StructuralOptimizationReducer : public Next {
public:
- using Next::Asm;
+ TURBOSHAFT_REDUCER_BOILERPLATE()
OpIndex ReduceInputGraphBranch(OpIndex input_index, const BranchOp& branch) {
LABEL_BLOCK(no_change) {
@@ -100,6 +100,13 @@ class StructuralOptimizationReducer : public Next {
OpIndex switch_var = OpIndex::Invalid();
while (true) {
+ // The "false" destination will be inlined before the switch is emitted,
+ // so it should only contain pure operations.
+ if (!ContainsOnlyPureOps(current_branch->if_false, Asm().input_graph())) {
+ TRACE("\t [break] End of only-pure-ops cascade reached.\n");
+ break;
+ }
+
// If we encounter a condition that is not equality, we can't turn it
// into a switch case.
const EqualOp* equal = Asm()
@@ -164,13 +171,6 @@ class StructuralOptimizationReducer : public Next {
// Iterate to the next if_false block in the cascade.
current_branch = &maybe_branch.template Cast<BranchOp>();
-
- // As long as the else blocks contain only pure ops, we can keep
- // traversing the if-else cascade.
- if (!ContainsOnlyPureOps(current_branch->if_false, Asm().input_graph())) {
- TRACE("\t [break] End of only-pure-ops cascade reached.\n");
- break;
- }
}
// Probably better to keep short if-else cascades as they are.
@@ -186,7 +186,7 @@ class StructuralOptimizationReducer : public Next {
InlineAllOperationsWithoutLast(block);
}
- TRACE("[reduce] Successfully emit a Switch with %z cases.", cases.size());
+ TRACE("[reduce] Successfully emit a Switch with %zu cases.", cases.size());
// The last current_if_true block that ends the cascade becomes the default
// case.
diff --git a/test/mjsunit/compiler/regress-crbug-1509576.js b/test/mjsunit/compiler/regress-crbug-1509576.js
new file mode 100644
index 0000000000000000000000000000000000000000..f538296edc4dd1c430a2cec6f88fda82273b10e8
--- /dev/null
+++ b/test/mjsunit/compiler/regress-crbug-1509576.js
@@ -0,0 +1,39 @@
+// Copyright 2023 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function escape(s) { }
+
+function f(i) {
+ let str = "";
+ escape(str);
+
+ // This "if (i == 3)" should not be merged into the subsequent switch, because
+ // there is a side-effect in between.
+ if (i == 3) {
+ // This will trigger a deopt
+ str += "("
+ }
+
+ str += "function";
+
+ switch (i) {
+ case -10:
+ escape(str);
+ case 1:
+ case 3:
+ }
+
+ // This `eval` creates some kind of closure of the function inside the
+ // function, not sure how that works exactly, but it's needed to repro :D
+ eval();
+
+ return str;
+}
+
+%PrepareFunctionForOptimization(f);
+assertEquals(f(0), "function");
+%OptimizeFunctionOnNextCall(f);
+assertEquals(f(3), "(function");

View File

@@ -5,3 +5,4 @@ pipewire_capturer_increase_buffer_size_to_avoid_buffer_overflow.patch
prevent_sdp_munging_of_duplicate_ssrcs.patch
fix_check_pipewire_init_before_creating_generic_capturer.patch
pipewire_capturer_make_restore_tokens_re-usable_more_than_one_time.patch
tighten_som_dchecks_to_checks_in_vp9_packetization.patch

View File

@@ -0,0 +1,103 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Erik=20Spr=C3=A5ng?= <sprang@webrtc.org>
Date: Fri, 19 Jan 2024 16:59:01 +0100
Subject: Tighten som DCHECKs to CHECKs in VP9 packetization.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
(cherry picked from commit 6a992129fb0dede4a8fbdaf5de43abaf43c20299)
No-Try: True
Bug: chromium:1518991, chromium:1518994
Change-Id: I47f68ba6aaf4874fd952332bf213e3a1e0389268
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/335241
Auto-Submit: Erik Språng <sprang@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Cr-Original-Commit-Position: refs/heads/main@{#41580}
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/338640
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Commit-Queue: Erik Språng <sprang@webrtc.org>
Cr-Commit-Position: refs/branch-heads/6167@{#6}
Cr-Branched-From: ece5cb83715dea85617114b6d4e981fdee2623ba-refs/heads/main@{#41315}
diff --git a/modules/rtp_rtcp/source/rtp_format_vp9.cc b/modules/rtp_rtcp/source/rtp_format_vp9.cc
index 15e059e85c8968c8ed72efa6b17ac998b5597f45..9ad4aa97c34aabe761739045662adc6374e3dc69 100644
--- a/modules/rtp_rtcp/source/rtp_format_vp9.cc
+++ b/modules/rtp_rtcp/source/rtp_format_vp9.cc
@@ -94,8 +94,8 @@ size_t RefIndicesLength(const RTPVideoHeaderVP9& hdr) {
if (!hdr.inter_pic_predicted || !hdr.flexible_mode)
return 0;
- RTC_DCHECK_GT(hdr.num_ref_pics, 0U);
- RTC_DCHECK_LE(hdr.num_ref_pics, kMaxVp9RefPics);
+ RTC_CHECK_GT(hdr.num_ref_pics, 0U);
+ RTC_CHECK_LE(hdr.num_ref_pics, kMaxVp9RefPics);
return hdr.num_ref_pics;
}
@@ -123,9 +123,9 @@ size_t SsDataLength(const RTPVideoHeaderVP9& hdr) {
if (!hdr.ss_data_available)
return 0;
- RTC_DCHECK_GT(hdr.num_spatial_layers, 0U);
- RTC_DCHECK_LE(hdr.num_spatial_layers, kMaxVp9NumberOfSpatialLayers);
- RTC_DCHECK_LE(hdr.gof.num_frames_in_gof, kMaxVp9FramesInGof);
+ RTC_CHECK_GT(hdr.num_spatial_layers, 0U);
+ RTC_CHECK_LE(hdr.num_spatial_layers, kMaxVp9NumberOfSpatialLayers);
+ RTC_CHECK_LE(hdr.gof.num_frames_in_gof, kMaxVp9FramesInGof);
size_t length = 1; // V
if (hdr.spatial_layer_resolution_present) {
length += 4 * hdr.num_spatial_layers; // Y
@@ -136,7 +136,7 @@ size_t SsDataLength(const RTPVideoHeaderVP9& hdr) {
// N_G
length += hdr.gof.num_frames_in_gof; // T, U, R
for (size_t i = 0; i < hdr.gof.num_frames_in_gof; ++i) {
- RTC_DCHECK_LE(hdr.gof.num_ref_pics[i], kMaxVp9RefPics);
+ RTC_CHECK_LE(hdr.gof.num_ref_pics[i], kMaxVp9RefPics);
length += hdr.gof.num_ref_pics[i]; // R times
}
return length;
@@ -248,9 +248,9 @@ bool WriteRefIndices(const RTPVideoHeaderVP9& vp9,
// +-+-+-+-+-+-+-+-+ -| -|
//
bool WriteSsData(const RTPVideoHeaderVP9& vp9, rtc::BitBufferWriter* writer) {
- RTC_DCHECK_GT(vp9.num_spatial_layers, 0U);
- RTC_DCHECK_LE(vp9.num_spatial_layers, kMaxVp9NumberOfSpatialLayers);
- RTC_DCHECK_LE(vp9.gof.num_frames_in_gof, kMaxVp9FramesInGof);
+ RTC_CHECK_GT(vp9.num_spatial_layers, 0U);
+ RTC_CHECK_LE(vp9.num_spatial_layers, kMaxVp9NumberOfSpatialLayers);
+ RTC_CHECK_LE(vp9.gof.num_frames_in_gof, kMaxVp9FramesInGof);
bool g_bit = vp9.gof.num_frames_in_gof > 0;
RETURN_FALSE_ON_ERROR(writer->WriteBits(vp9.num_spatial_layers - 1, 3));
@@ -288,6 +288,8 @@ bool WriteSsData(const RTPVideoHeaderVP9& vp9, rtc::BitBufferWriter* writer) {
// current API to invoke SVC is not flexible enough.
RTPVideoHeaderVP9 RemoveInactiveSpatialLayers(
const RTPVideoHeaderVP9& original_header) {
+ RTC_CHECK_LE(original_header.num_spatial_layers,
+ kMaxVp9NumberOfSpatialLayers);
RTPVideoHeaderVP9 hdr(original_header);
if (original_header.first_active_layer == 0)
return hdr;
@@ -314,7 +316,7 @@ RtpPacketizerVp9::RtpPacketizerVp9(rtc::ArrayView<const uint8_t> payload,
header_size_(PayloadDescriptorLengthMinusSsData(hdr_)),
first_packet_extra_header_size_(SsDataLength(hdr_)),
remaining_payload_(payload) {
- RTC_DCHECK_EQ(hdr_.first_active_layer, 0);
+ RTC_CHECK_EQ(hdr_.first_active_layer, 0);
limits.max_payload_len -= header_size_;
limits.first_packet_reduction_len += first_packet_extra_header_size_;
@@ -357,8 +359,8 @@ bool RtpPacketizerVp9::NextPacket(RtpPacketToSend* packet) {
// Ensure end_of_picture is always set on top spatial layer when it is not
// dropped.
- RTC_DCHECK(hdr_.spatial_idx < hdr_.num_spatial_layers - 1 ||
- hdr_.end_of_picture);
+ RTC_CHECK(hdr_.spatial_idx < hdr_.num_spatial_layers - 1 ||
+ hdr_.end_of_picture);
packet->SetMarker(layer_end && hdr_.end_of_picture);
return true;

View File

@@ -99,7 +99,7 @@ const getNoteFromClerk = async (ghKey) => {
const CLERK_LOGIN = 'release-clerk[bot]';
const CLERK_NO_NOTES = '**No Release Notes**';
const PERSIST_LEAD = '**Release Notes Persisted**\n\n';
const PERSIST_LEAD = '**Release Notes Persisted**';
const QUOTE_LEAD = '> ';
for (const comment of comments.data.reverse()) {
@@ -130,6 +130,8 @@ const getNoteFromClerk = async (ghKey) => {
.trim();
}
}
console.warn(`WARN: no notes found in ${buildPullURL(ghKey)}`);
};
/**

View File

@@ -13,6 +13,7 @@
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/containers/fixed_flat_set.h"
#include "base/environment.h"
#include "base/feature_list.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -20,6 +21,7 @@
#include "base/task/thread_pool/thread_pool_instance.h"
#include "content/public/common/content_switches.h"
#include "electron/electron_version.h"
#include "electron/fuses.h"
#include "gin/array_buffer.h"
#include "gin/public/isolate_holder.h"
#include "gin/v8_initializer.h"
@@ -29,19 +31,23 @@
#include "shell/common/gin_helper/dictionary.h"
#include "shell/common/node_bindings.h"
#include "shell/common/node_includes.h"
#include "shell/common/node_util.h"
#if BUILDFLAG(IS_WIN)
#include "chrome/child/v8_crashpad_support_win.h"
#endif
#if BUILDFLAG(IS_LINUX)
#include "base/environment.h"
#include "base/posix/global_descriptors.h"
#include "base/strings/string_number_conversions.h"
#include "components/crash/core/app/crash_switches.h" // nogncheck
#include "content/public/common/content_descriptors.h"
#endif
#if BUILDFLAG(IS_MAC)
#include "shell/common/mac/codesign_util.h"
#endif
#if !IS_MAS_BUILD()
#include "components/crash/core/app/crashpad.h" // nogncheck
#include "shell/app/electron_crash_reporter_client.h"
@@ -76,6 +82,23 @@ void ExitIfContainsDisallowedFlags(const std::vector<std::string>& argv) {
}
}
#if BUILDFLAG(IS_MAC)
// A list of node envs that may be used to inject scripts.
const char* kHijackableEnvs[] = {"NODE_OPTIONS", "NODE_REPL_EXTERNAL_MODULE"};
// Return true if there is any env in kHijackableEnvs.
bool UnsetHijackableEnvs(base::Environment* env) {
bool has = false;
for (const char* name : kHijackableEnvs) {
if (env->HasVar(name)) {
env->UnSetVar(name);
has = true;
}
}
return has;
}
#endif
#if IS_MAS_BUILD()
void SetCrashKeyStub(const std::string& key, const std::string& value) {}
void ClearCrashKeyStub(const std::string& key) {}
@@ -100,12 +123,36 @@ int NodeMain(int argc, char* argv[]) {
exit(1);
}
auto os_env = base::Environment::Create();
bool node_options_enabled = electron::fuses::IsNodeOptionsEnabled();
if (!node_options_enabled) {
os_env->UnSetVar("NODE_OPTIONS");
}
#if BUILDFLAG(IS_MAC)
if (!ProcessSignatureIsSameWithCurrentApp(getppid())) {
// On macOS, it is forbidden to run sandboxed app with custom arguments
// from another app, i.e. args are discarded in following call:
// exec("Sandboxed.app", ["--custom-args-will-be-discarded"])
// However it is possible to bypass the restriction by abusing the node mode
// of Electron apps:
// exec("Electron.app", {env: {ELECTRON_RUN_AS_NODE: "1",
// NODE_OPTIONS: "--require 'bad.js'"}})
// To prevent Electron apps from being used to work around macOS security
// restrictions, when the parent process is not part of the app bundle, all
// environment variables that may be used to inject scripts are removed.
if (UnsetHijackableEnvs(os_env.get())) {
LOG(ERROR) << "Node.js environment variables are disabled because this "
"process is invoked by other apps.";
}
}
#endif // BUILDFLAG(IS_MAC)
#if BUILDFLAG(IS_WIN)
v8_crashpad_support::SetUp();
#endif
#if BUILDFLAG(IS_LINUX)
auto os_env = base::Environment::Create();
std::string fd_string, pid_string;
if (os_env->GetVar("CRASHDUMP_SIGNAL_FD", &fd_string) &&
os_env->GetVar("CRASHPAD_HANDLER_PID", &pid_string)) {

View File

@@ -1531,11 +1531,10 @@ void WebContents::FindReply(content::WebContents* web_contents,
Emit("found-in-page", result.GetHandle());
}
void WebContents::RequestExclusivePointerAccess(
content::WebContents* web_contents,
bool user_gesture,
bool last_unlocked_by_target,
bool allowed) {
void WebContents::OnRequestToLockMouse(content::WebContents* web_contents,
bool user_gesture,
bool last_unlocked_by_target,
bool allowed) {
if (allowed) {
exclusive_access_manager_.mouse_lock_controller()->RequestToLockMouse(
web_contents, user_gesture, last_unlocked_by_target);
@@ -1552,7 +1551,7 @@ void WebContents::RequestToLockMouse(content::WebContents* web_contents,
WebContentsPermissionHelper::FromWebContents(web_contents);
permission_helper->RequestPointerLockPermission(
user_gesture, last_unlocked_by_target,
base::BindOnce(&WebContents::RequestExclusivePointerAccess,
base::BindOnce(&WebContents::OnRequestToLockMouse,
base::Unretained(this)));
}
@@ -1560,10 +1559,24 @@ void WebContents::LostMouseLock() {
exclusive_access_manager_.mouse_lock_controller()->LostMouseLock();
}
void WebContents::OnRequestKeyboardLock(content::WebContents* web_contents,
bool esc_key_locked,
bool allowed) {
if (allowed) {
exclusive_access_manager_.keyboard_lock_controller()->RequestKeyboardLock(
web_contents, esc_key_locked);
} else {
web_contents->GotResponseToKeyboardLockRequest(false);
}
}
void WebContents::RequestKeyboardLock(content::WebContents* web_contents,
bool esc_key_locked) {
exclusive_access_manager_.keyboard_lock_controller()->RequestKeyboardLock(
web_contents, esc_key_locked);
auto* permission_helper =
WebContentsPermissionHelper::FromWebContents(web_contents);
permission_helper->RequestKeyboardLockPermission(
esc_key_locked, base::BindOnce(&WebContents::OnRequestKeyboardLock,
base::Unretained(this)));
}
void WebContents::CancelKeyboardLockRequest(

View File

@@ -571,14 +571,17 @@ class WebContents : public ExclusiveAccessContext,
const gfx::Rect& selection_rect,
int active_match_ordinal,
bool final_update) override;
void RequestExclusivePointerAccess(content::WebContents* web_contents,
bool user_gesture,
bool last_unlocked_by_target,
bool allowed);
void OnRequestToLockMouse(content::WebContents* web_contents,
bool user_gesture,
bool last_unlocked_by_target,
bool allowed);
void RequestToLockMouse(content::WebContents* web_contents,
bool user_gesture,
bool last_unlocked_by_target) override;
void LostMouseLock() override;
void OnRequestKeyboardLock(content::WebContents* web_contents,
bool esc_key_locked,
bool allowed);
void RequestKeyboardLock(content::WebContents* web_contents,
bool esc_key_locked) override;
void CancelKeyboardLockRequest(content::WebContents* web_contents) override;

View File

@@ -80,6 +80,7 @@
#include "base/environment.h"
#include "chrome/browser/ui/views/dark_mode_manager_linux.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/dbus/bluez_dbus_manager.h"
#include "device/bluetooth/dbus/dbus_bluez_manager_wrapper_linux.h"
#include "electron/electron_gtk_stubs.h"
#include "ui/base/cursor/cursor_factory.h"
@@ -513,7 +514,8 @@ void ElectronBrowserMainParts::PostCreateMainMessageLoop() {
ui::OzonePlatform::GetInstance()->PostCreateMainMessageLoop(
std::move(shutdown_cb),
content::GetUIThreadTaskRunner({content::BrowserTaskType::kUserInput}));
bluez::DBusBluezManagerWrapperLinux::Initialize();
if (!bluez::BluezDBusManager::IsInitialized())
bluez::DBusBluezManagerWrapperLinux::Initialize();
// Set up crypt config. This needs to be done before anything starts the
// network service, as the raw encryption key needs to be shared with the

View File

@@ -11,6 +11,7 @@ assert(enable_extensions,
function_registration("api_registration") {
sources = [
"//electron/shell/common/extensions/api/action.json",
"//electron/shell/common/extensions/api/extension.json",
"//electron/shell/common/extensions/api/resources_private.idl",
"//electron/shell/common/extensions/api/scripting.idl",

View File

@@ -11,7 +11,9 @@
#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "base/logging.h"
#include "device/bluetooth/dbus/bluez_dbus_manager.h"
#include "device/bluetooth/dbus/bluez_dbus_thread_manager.h"
#include "device/bluetooth/dbus/dbus_bluez_manager_wrapper_linux.h"
namespace {
@@ -34,6 +36,9 @@ PowerObserverLinux::PowerObserverLinux(
base::PowerSuspendObserver* suspend_observer)
: suspend_observer_(suspend_observer),
lock_owner_name_(GetExecutableBaseName()) {
if (!bluez::BluezDBusManager::IsInitialized())
bluez::DBusBluezManagerWrapperLinux::Initialize();
auto* bus = bluez::BluezDBusThreadManager::Get()->GetSystemBus();
if (!bus) {
LOG(WARNING) << "Failed to get system bus connection";

View File

@@ -512,6 +512,8 @@ void NativeWindowMac::Show() {
}
void NativeWindowMac::ShowInactive() {
set_wants_to_be_visible(true);
// Reattach the window to the parent to actually show it.
if (parent())
InternalSetParentWindow(parent(), true);

View File

@@ -644,11 +644,16 @@ void NativeWindowViews::Unmaximize() {
if (transparent()) {
SetBounds(restore_bounds_, false);
NotifyWindowUnmaximize();
UpdateThickFrame();
return;
}
#endif
widget()->Restore();
#if BUILDFLAG(IS_WIN)
UpdateThickFrame();
#endif
}
}
@@ -681,6 +686,10 @@ void NativeWindowViews::Minimize() {
void NativeWindowViews::Restore() {
widget()->Restore();
#if BUILDFLAG(IS_WIN)
UpdateThickFrame();
#endif
}
bool NativeWindowViews::IsMinimized() {
@@ -831,12 +840,13 @@ void NativeWindowViews::SetResizable(bool resizable) {
extensions::SizeConstraints(content_size, content_size));
}
}
#if BUILDFLAG(IS_WIN)
if (has_frame() && thick_frame_)
FlipWindowStyle(GetAcceleratedWidget(), resizable, WS_THICKFRAME);
#endif
resizable_ = resizable;
SetCanResize(resizable_);
#if BUILDFLAG(IS_WIN)
UpdateThickFrame();
#endif
}
bool NativeWindowViews::MoveAbove(const std::string& sourceId) {
@@ -1563,6 +1573,22 @@ void NativeWindowViews::SetIcon(const gfx::ImageSkia& icon) {
}
#endif
#if BUILDFLAG(IS_WIN)
void NativeWindowViews::UpdateThickFrame() {
if (!thick_frame_)
return;
if (IsMaximized() && !transparent()) {
// For maximized window add thick frame always, otherwise it will be removed
// in HWNDMessageHandler::SizeConstraintsChanged() which will result in
// maximized window bounds change.
FlipWindowStyle(GetAcceleratedWidget(), true, WS_THICKFRAME);
} else if (has_frame()) {
FlipWindowStyle(GetAcceleratedWidget(), resizable_, WS_THICKFRAME);
}
}
#endif
void NativeWindowViews::OnWidgetActivationChanged(views::Widget* changed_widget,
bool active) {
if (changed_widget != widget())

View File

@@ -187,6 +187,8 @@ class NativeWindowViews : public NativeWindow,
void set_overlay_symbol_color(SkColor color) {
overlay_symbol_color_ = color;
}
void UpdateThickFrame();
#endif
private:

View File

@@ -30,6 +30,16 @@ void ElectronDesktopNativeWidgetAura::InitNativeWidget(
views::DesktopNativeWidgetAura::InitNativeWidget(std::move(params));
}
#if BUILDFLAG(IS_WIN)
void ElectronDesktopNativeWidgetAura::OnSizeConstraintsChanged() {
views::DesktopNativeWidgetAura::OnSizeConstraintsChanged();
// OnSizeConstraintsChanged can remove thick frame depending from
// resizable state, so add it if needed.
native_window_view_->UpdateThickFrame();
}
#endif
void ElectronDesktopNativeWidgetAura::Activate() {
// Activate can cause the focused window to be blurred so only
// call when the window being activated is visible. This prevents

View File

@@ -27,6 +27,9 @@ class ElectronDesktopNativeWidgetAura : public views::DesktopNativeWidgetAura {
// views::DesktopNativeWidgetAura:
void InitNativeWidget(views::Widget::InitParams params) override;
#if BUILDFLAG(IS_WIN)
void OnSizeConstraintsChanged() override;
#endif
// internal::NativeWidgetPrivate:
void Activate() override;

View File

@@ -253,6 +253,15 @@ void WebContentsPermissionHelper::RequestPointerLockPermission(
user_gesture);
}
void WebContentsPermissionHelper::RequestKeyboardLockPermission(
bool esc_key_locked,
base::OnceCallback<void(content::WebContents*, bool, bool)> callback) {
RequestPermission(
web_contents_->GetPrimaryMainFrame(),
static_cast<blink::PermissionType>(PermissionType::KEYBOARD_LOCK),
base::BindOnce(std::move(callback), web_contents_, esc_key_locked));
}
void WebContentsPermissionHelper::RequestOpenExternalPermission(
content::RenderFrameHost* requesting_frame,
base::OnceCallback<void(bool)> callback,

View File

@@ -31,7 +31,8 @@ class WebContentsPermissionHelper
OPEN_EXTERNAL,
SERIAL,
HID,
USB
USB,
KEYBOARD_LOCK
};
// Asynchronous Requests
@@ -44,6 +45,9 @@ class WebContentsPermissionHelper
bool last_unlocked_by_target,
base::OnceCallback<void(content::WebContents*, bool, bool, bool)>
callback);
void RequestKeyboardLockPermission(
bool esc_key_locked,
base::OnceCallback<void(content::WebContents*, bool, bool)> callback);
void RequestWebNotificationPermission(
content::RenderFrameHost* requesting_frame,
base::OnceCallback<void(bool)> callback);

View File

@@ -38,6 +38,7 @@ group("extensions_features") {
generated_json_strings("generated_api_json_strings") {
sources = [
"action.json",
"browser_action.json",
"extension.json",
"resources_private.idl",
"scripting.idl",

View File

@@ -1,4 +1,17 @@
{
"action": {
"dependencies": ["manifest:action"],
"contexts": ["blessed_extension"]
},
"action.isEnabled": {
"channel": "stable"
},
"action.getBadgeTextColor": {
"channel": "stable"
},
"action.setBadgeTextColor": {
"channel": "stable"
},
"tabs": {
"channel": "stable",
"extension_types": ["extension"],

View File

@@ -7,6 +7,11 @@
// well as feature.h, simple_feature.h, and feature_provider.h.
{
"action": {
"channel": "stable",
"extension_types": ["extension"],
"min_manifest_version": 3
},
"author": {
"channel": "stable",
"extension_types": "all"

View File

@@ -6,7 +6,7 @@
"namespace": "action",
"description": "Use the <code>chrome.action</code> API to control the extension's icon in the Google Chrome toolbar.",
"compiler_options": {
"implemented_in": "shell/browser/extensions/api/extension_action/extension_action_api.h"
"implemented_in": "electron/shell/browser/extensions/api/extension_action/extension_action_api.h"
},
"types": [
{

View File

@@ -0,0 +1,370 @@
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
[
{
"namespace": "browserAction",
"description": "Use browser actions to put icons in the main Google Chrome toolbar, to the right of the address bar. In addition to its <a href='browserAction#icon'>icon</a>, a browser action can have a <a href='browserAction#tooltip'>tooltip</a>, a <a href='browserAction#badge'>badge</a>, and a <a href='browserAction#popups'>popup</a>.",
"compiler_options": {
"implemented_in": "electron/shell/browser/extensions/api/extension_action/extension_action_api.h"
},
"types": [
{
"id": "ColorArray",
"type": "array",
"items": {
"type": "integer",
"minimum": 0,
"maximum": 255
},
"minItems": 4,
"maxItems": 4
},
{
"id": "ImageDataType",
"type": "object",
"isInstanceOf": "ImageData",
"additionalProperties": {
"type": "any"
},
"description": "Pixel data for an image. Must be an ImageData object; for example, from a <code>canvas</code> element."
},
{
"id": "TabDetails",
"type": "object",
"properties": {
"tabId": {
"type": "integer",
"optional": true,
"minimum": 0,
"description": "The ID of the tab to query state for. If no tab is specified, the non-tab-specific state is returned."
}
}
}
],
"functions": [
{
"name": "setTitle",
"type": "function",
"description": "Sets the title of the browser action. This title appears in the tooltip.",
"parameters": [
{
"name": "details",
"type": "object",
"properties": {
"title": {
"type": "string",
"description": "The string the browser action should display when moused over."
},
"tabId": {
"type": "integer",
"optional": true,
"description": "Limits the change to when a particular tab is selected. Automatically resets when the tab is closed."
}
}
}
],
"returns_async": {
"name": "callback",
"parameters": [],
"optional": true
}
},
{
"name": "getTitle",
"type": "function",
"description": "Gets the title of the browser action.",
"parameters": [
{
"name": "details",
"$ref": "TabDetails"
}
],
"returns_async": {
"name": "callback",
"parameters": [
{
"name": "result",
"type": "string"
}
]
}
},
{
"name": "setIcon",
"type": "function",
"description": "Sets the icon for the browser action. The icon can be specified as the path to an image file, as the pixel data from a canvas element, or as a dictionary of one of those. Either the <code>path</code> or the <code>imageData</code> property must be specified.",
"parameters": [
{
"name": "details",
"type": "object",
"properties": {
"imageData": {
"choices": [
{
"$ref": "ImageDataType"
},
{
"type": "object",
"additionalProperties": {
"type": "any"
}
}
],
"optional": true,
"description": "Either an ImageData object or a dictionary {size -> ImageData} representing an icon to be set. If the icon is specified as a dictionary, the image used is chosen depending on the screen's pixel density. If the number of image pixels that fit into one screen space unit equals <code>scale</code>, then an image with size <code>scale</code> * n is selected, where <i>n</i> is the size of the icon in the UI. At least one image must be specified. Note that 'details.imageData = foo' is equivalent to 'details.imageData = {'16': foo}'"
},
"path": {
"choices": [
{
"type": "string"
},
{
"type": "object",
"additionalProperties": {
"type": "any"
}
}
],
"optional": true,
"description": "Either a relative image path or a dictionary {size -> relative image path} pointing to an icon to be set. If the icon is specified as a dictionary, the image used is chosen depending on the screen's pixel density. If the number of image pixels that fit into one screen space unit equals <code>scale</code>, then an image with size <code>scale</code> * n is selected, where <i>n</i> is the size of the icon in the UI. At least one image must be specified. Note that 'details.path = foo' is equivalent to 'details.path = {'16': foo}'"
},
"tabId": {
"type": "integer",
"optional": true,
"description": "Limits the change to when a particular tab is selected. Automatically resets when the tab is closed."
}
}
}
],
"returns_async": {
"name": "callback",
"optional": true,
"parameters": []
}
},
{
"name": "setPopup",
"type": "function",
"description": "Sets the HTML document to be opened as a popup when the user clicks the browser action icon.",
"parameters": [
{
"name": "details",
"type": "object",
"properties": {
"tabId": {
"type": "integer",
"optional": true,
"minimum": 0,
"description": "Limits the change to when a particular tab is selected. Automatically resets when the tab is closed."
},
"popup": {
"type": "string",
"description": "The relative path to the HTML file to show in a popup. If set to the empty string (<code>''</code>), no popup is shown."
}
}
}
],
"returns_async": {
"name": "callback",
"parameters": [],
"optional": true
}
},
{
"name": "getPopup",
"type": "function",
"description": "Gets the HTML document that is set as the popup for this browser action.",
"parameters": [
{
"name": "details",
"$ref": "TabDetails"
}
],
"returns_async": {
"name": "callback",
"parameters": [
{
"name": "result",
"type": "string"
}
]
}
},
{
"name": "setBadgeText",
"type": "function",
"description": "Sets the badge text for the browser action. The badge is displayed on top of the icon.",
"parameters": [
{
"name": "details",
"type": "object",
"properties": {
"text": {
"type": "string",
"optional": true,
"description": "Any number of characters can be passed, but only about four can fit into the space. If an empty string (<code>''</code>) is passed, the badge text is cleared. If <code>tabId</code> is specified and <code>text</code> is null, the text for the specified tab is cleared and defaults to the global badge text."
},
"tabId": {
"type": "integer",
"optional": true,
"description": "Limits the change to when a particular tab is selected. Automatically resets when the tab is closed."
}
}
}
],
"returns_async": {
"name": "callback",
"parameters": [],
"optional": true
}
},
{
"name": "getBadgeText",
"type": "function",
"description": "Gets the badge text of the browser action. If no tab is specified, the non-tab-specific badge text is returned.",
"parameters": [
{
"name": "details",
"$ref": "TabDetails"
}
],
"returns_async": {
"name": "callback",
"parameters": [
{
"name": "result",
"type": "string"
}
]
}
},
{
"name": "setBadgeBackgroundColor",
"type": "function",
"description": "Sets the background color for the badge.",
"parameters": [
{
"name": "details",
"type": "object",
"properties": {
"color": {
"description": "An array of four integers in the range 0-255 that make up the RGBA color of the badge. Can also be a string with a CSS hex color value; for example, <code>#FF0000</code> or <code>#F00</code> (red). Renders colors at full opacity.",
"choices": [
{
"type": "string"
},
{
"$ref": "ColorArray"
}
]
},
"tabId": {
"type": "integer",
"optional": true,
"description": "Limits the change to when a particular tab is selected. Automatically resets when the tab is closed."
}
}
}
],
"returns_async": {
"name": "callback",
"parameters": [],
"optional": true
}
},
{
"name": "getBadgeBackgroundColor",
"type": "function",
"description": "Gets the background color of the browser action.",
"parameters": [
{
"name": "details",
"$ref": "TabDetails"
}
],
"returns_async": {
"name": "callback",
"parameters": [
{
"name": "result",
"$ref": "ColorArray"
}
]
}
},
{
"name": "enable",
"type": "function",
"description": "Enables the browser action for a tab. Defaults to enabled.",
"parameters": [
{
"type": "integer",
"optional": true,
"name": "tabId",
"minimum": 0,
"description": "The ID of the tab for which to modify the browser action."
}
],
"returns_async": {
"name": "callback",
"parameters": [],
"optional": true
}
},
{
"name": "disable",
"type": "function",
"description": "Disables the browser action for a tab.",
"parameters": [
{
"type": "integer",
"optional": true,
"name": "tabId",
"minimum": 0,
"description": "The ID of the tab for which to modify the browser action."
}
],
"returns_async": {
"name": "callback",
"parameters": [],
"optional": true
}
},
{
"name": "openPopup",
"type": "function",
"description": "Opens the extension popup window in the active window but does not grant tab permissions.",
"nodoc": true,
"parameters": [],
"returns_async": {
"name": "callback",
"parameters": [
{
"name": "popupView",
"type": "object",
"optional": true,
"description": "JavaScript 'window' object for the popup window if it was succesfully opened.",
"additionalProperties": {
"type": "any"
}
}
]
}
}
],
"events": [
{
"name": "onClicked",
"type": "function",
"description": "Fired when a browser action icon is clicked. Does not fire if the browser action has a popup.",
"parameters": [
{
"name": "tab",
"$ref": "tabs.Tab"
}
]
}
]
}
]

View File

@@ -249,6 +249,8 @@ v8::Local<v8::Value> Converter<blink::PermissionType>::ToV8(
switch (static_cast<PermissionType>(val)) {
case PermissionType::POINTER_LOCK:
return StringToV8(isolate, "pointerLock");
case PermissionType::KEYBOARD_LOCK:
return StringToV8(isolate, "keyboardLock");
case PermissionType::FULLSCREEN:
return StringToV8(isolate, "fullscreen");
case PermissionType::OPEN_EXTERNAL:

View File

@@ -0,0 +1,113 @@
// Copyright 2023 Microsoft, Inc.
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "shell/common/mac/codesign_util.h"
#include "base/mac/foundation_util.h"
#include "base/mac/mac_logging.h"
#include "base/mac/scoped_cftyperef.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include <Security/Security.h>
namespace electron {
absl::optional<bool> IsUnsignedOrAdHocSigned(SecCodeRef code) {
base::ScopedCFTypeRef<SecStaticCodeRef> static_code;
OSStatus status = SecCodeCopyStaticCode(code, kSecCSDefaultFlags,
static_code.InitializeInto());
if (status == errSecCSUnsigned) {
return true;
}
if (status != errSecSuccess) {
OSSTATUS_LOG(ERROR, status) << "SecCodeCopyStaticCode";
return absl::optional<bool>();
}
// Copy the signing info from the SecStaticCodeRef.
base::ScopedCFTypeRef<CFDictionaryRef> signing_info;
status =
SecCodeCopySigningInformation(static_code.get(), kSecCSSigningInformation,
signing_info.InitializeInto());
if (status != errSecSuccess) {
OSSTATUS_LOG(ERROR, status) << "SecCodeCopySigningInformation";
return absl::optional<bool>();
}
// Look up the code signing flags. If the flags are absent treat this as
// unsigned. This decision is consistent with the StaticCode source:
// https://github.com/apple-oss-distributions/Security/blob/Security-60157.40.30.0.1/OSX/libsecurity_codesigning/lib/StaticCode.cpp#L2270
CFNumberRef signing_info_flags =
base::mac::GetValueFromDictionary<CFNumberRef>(signing_info.get(),
kSecCodeInfoFlags);
if (!signing_info_flags) {
return true;
}
// Using a long long to extract the value from the CFNumberRef to be
// consistent with how it was packed by Security.framework.
// https://github.com/apple-oss-distributions/Security/blob/Security-60157.40.30.0.1/OSX/libsecurity_utilities/lib/cfutilities.h#L262
long long flags;
if (!CFNumberGetValue(signing_info_flags, kCFNumberLongLongType, &flags)) {
LOG(ERROR) << "CFNumberGetValue";
return absl::optional<bool>();
}
if (static_cast<uint32_t>(flags) & kSecCodeSignatureAdhoc) {
return true;
}
return false;
}
bool ProcessSignatureIsSameWithCurrentApp(pid_t pid) {
// Get and check the code signature of current app.
base::ScopedCFTypeRef<SecCodeRef> self_code;
OSStatus status =
SecCodeCopySelf(kSecCSDefaultFlags, self_code.InitializeInto());
if (status != errSecSuccess) {
OSSTATUS_LOG(ERROR, status) << "SecCodeCopyGuestWithAttributes";
return false;
}
absl::optional<bool> not_signed = IsUnsignedOrAdHocSigned(self_code.get());
if (!not_signed.has_value()) {
// Error happened.
return false;
}
if (not_signed.value()) {
// Current app is not signed.
return true;
}
// Get the code signature of process.
base::ScopedCFTypeRef<CFNumberRef> process_cf(
CFNumberCreate(nullptr, kCFNumberIntType, &pid));
const void* attribute_keys[] = {kSecGuestAttributePid};
const void* attribute_values[] = {process_cf.get()};
base::ScopedCFTypeRef<CFDictionaryRef> attributes(CFDictionaryCreate(
nullptr, attribute_keys, attribute_values, std::size(attribute_keys),
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
base::ScopedCFTypeRef<SecCodeRef> process_code;
status = SecCodeCopyGuestWithAttributes(nullptr, attributes.get(),
kSecCSDefaultFlags,
process_code.InitializeInto());
if (status != errSecSuccess) {
OSSTATUS_LOG(ERROR, status) << "SecCodeCopyGuestWithAttributes";
return false;
}
// Get the requirement of current app's code signature.
base::ScopedCFTypeRef<SecRequirementRef> self_requirement;
status = SecCodeCopyDesignatedRequirement(self_code.get(), kSecCSDefaultFlags,
self_requirement.InitializeInto());
if (status != errSecSuccess) {
OSSTATUS_LOG(ERROR, status) << "SecCodeCopyDesignatedRequirement";
return false;
}
DCHECK(self_requirement.get());
// Check whether the process meets the signature requirement of current app.
status = SecCodeCheckValidity(process_code.get(), kSecCSDefaultFlags,
self_requirement.get());
if (status != errSecSuccess && status != errSecCSReqFailed) {
OSSTATUS_LOG(ERROR, status) << "SecCodeCheckValidity";
return false;
}
return status == errSecSuccess;
}
} // namespace electron

View File

@@ -0,0 +1,24 @@
// Copyright 2023 Microsoft, Inc.
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef SHELL_COMMON_MAC_CODESIGN_UTIL_H_
#define SHELL_COMMON_MAC_CODESIGN_UTIL_H_
#include <unistd.h>
namespace electron {
// Given a pid, return true if the process has the same code signature with
// with current app.
// This API returns true if current app is not signed or ad-hoc signed, because
// checking code signature is meaningless in this case, and failing the
// signature check would break some features with unsigned binary (for example,
// process.send stops working in processes created by child_process.fork, due
// to the NODE_CHANNEL_ID env getting removed).
bool ProcessSignatureIsSameWithCurrentApp(pid_t pid);
} // namespace electron
#endif // SHELL_COMMON_MAC_CODESIGN_UTIL_H_

View File

@@ -218,8 +218,11 @@ void ErrorMessageListener(v8::Local<v8::Message> message,
// Analogous to node/lib/internal/process/execution.js#L176-L180
if (env->async_hooks()->fields()[node::AsyncHooks::kAfter]) {
while (env->async_hooks()->fields()[node::AsyncHooks::kStackLength]) {
node::AsyncWrap::EmitAfter(env, env->execution_async_id());
env->async_hooks()->pop_async_context(env->execution_async_id());
double id = env->execution_async_id();
// Do not call EmitAfter for asyncId 0.
if (id != 0)
node::AsyncWrap::EmitAfter(env, id);
env->async_hooks()->pop_async_context(id);
}
}

View File

@@ -7,6 +7,7 @@
#include <vector>
#include "build/build_config.h"
#include "v8/include/v8.h"
namespace node {

View File

@@ -21,6 +21,7 @@
#include "base/posix/eintr_wrapper.h"
#include "base/process/kill.h"
#include "base/process/launch.h"
#include "base/strings/escape.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_restrictions.h"
#include "components/dbus/thread_linux/dbus_thread_linux.h"
@@ -216,8 +217,9 @@ class ShowItemHelper {
dbus::MessageWriter writer(&show_items_call);
writer.AppendArrayOfStrings(
{"file://" + full_path.value()}); // List of file(s) to highlight.
writer.AppendString({}); // startup-id
{"file://" + base::EscapePath(
full_path.value())}); // List of file(s) to highlight.
writer.AppendString({}); // startup-id
ShowItemUsingBusCall(&show_items_call, full_path);
}

View File

@@ -3,36 +3,26 @@ import * as cp from 'child_process';
import * as http from 'http';
import * as express from 'express';
import * as fs from 'fs-extra';
import * as os from 'os';
import * as path from 'path';
import * as psList from 'ps-list';
import { AddressInfo } from 'net';
import { ifdescribe, ifit } from './lib/spec-helpers';
import { copyApp, getCodesignIdentity, shouldRunCodesignTests, signApp, spawn, withTempDirectory } from './lib/codesign-helpers';
import * as uuid from 'uuid';
import { systemPreferences } from 'electron';
const features = process._linkedBinding('electron_common_features');
const fixturesPath = path.resolve(__dirname, 'fixtures');
// We can only test the auto updater on darwin non-component builds
ifdescribe(process.platform === 'darwin' && !(process.env.CI && process.arch === 'arm64') && !process.mas && !features.isComponentBuild())('autoUpdater behavior', function () {
ifdescribe(shouldRunCodesignTests)('autoUpdater behavior', function () {
this.timeout(120000);
let identity = '';
beforeEach(function () {
const result = cp.spawnSync(path.resolve(__dirname, '../script/codesign/get-trusted-identity.sh'));
if (result.status !== 0 || result.stdout.toString().trim().length === 0) {
// Per https://circleci.com/docs/2.0/env-vars:
// CIRCLE_PR_NUMBER is only present on forked PRs
if (process.env.CI && !process.env.CIRCLE_PR_NUMBER) {
throw new Error('No valid signing identity available to run autoUpdater specs');
}
const result = getCodesignIdentity();
if (result === null) {
this.skip();
} else {
identity = result.stdout.toString().trim();
identity = result;
}
});
@@ -40,59 +30,6 @@ ifdescribe(process.platform === 'darwin' && !(process.env.CI && process.arch ===
expect(identity).to.be.a('string').with.lengthOf.at.least(1);
});
const copyApp = async (newDir: string, fixture = 'initial') => {
const appBundlePath = path.resolve(process.execPath, '../../..');
const newPath = path.resolve(newDir, 'Electron.app');
cp.spawnSync('cp', ['-R', appBundlePath, path.dirname(newPath)]);
const appDir = path.resolve(newPath, 'Contents/Resources/app');
await fs.mkdirp(appDir);
await fs.copy(path.resolve(fixturesPath, 'auto-update', fixture), appDir);
const plistPath = path.resolve(newPath, 'Contents', 'Info.plist');
await fs.writeFile(
plistPath,
(await fs.readFile(plistPath, 'utf8')).replace('<key>BuildMachineOSBuild</key>', `<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict><key>BuildMachineOSBuild</key>`)
);
return newPath;
};
const spawn = (cmd: string, args: string[], opts: any = {}) => {
let out = '';
const child = cp.spawn(cmd, args, opts);
child.stdout.on('data', (chunk: Buffer) => {
out += chunk.toString();
});
child.stderr.on('data', (chunk: Buffer) => {
out += chunk.toString();
});
return new Promise<{ code: number, out: string }>((resolve) => {
child.on('exit', (code, signal) => {
expect(signal).to.equal(null);
resolve({
code: code!,
out
});
});
});
};
const signApp = (appPath: string) => {
return spawn('codesign', ['-s', identity, '--deep', '--force', appPath]);
};
const launchApp = (appPath: string, args: string[] = []) => {
return spawn(path.resolve(appPath, 'Contents/MacOS/Electron'), args);
};
@@ -107,17 +44,6 @@ ifdescribe(process.platform === 'darwin' && !(process.env.CI && process.arch ===
return activeShipIts;
};
const withTempDirectory = async (fn: (dir: string) => Promise<void>, autoCleanUp = true) => {
const dir = await fs.mkdtemp(path.resolve(os.tmpdir(), 'electron-update-spec-'));
try {
await fn(dir);
} finally {
if (autoCleanUp) {
cp.spawnSync('rm', ['-r', dir]);
}
}
};
const logOnError = (what: any, fn: () => void) => {
try {
fn();
@@ -143,7 +69,7 @@ ifdescribe(process.platform === 'darwin' && !(process.env.CI && process.arch ===
appPJPath,
(await fs.readFile(appPJPath, 'utf8')).replace('1.0.0', version)
);
await signApp(secondAppPath);
await signApp(secondAppPath, identity);
await mutateAppPostSign?.mutate(secondAppPath);
updateZipPath = path.resolve(dir, 'update.zip');
await spawn('zip', ['-0', '-r', '--symlinks', updateZipPath, './'], {
@@ -175,7 +101,7 @@ ifdescribe(process.platform === 'darwin' && !(process.env.CI && process.arch ===
it('should cleanly set the feed URL when the app is signed', async () => {
await withTempDirectory(async (dir) => {
const appPath = await copyApp(dir);
await signApp(appPath);
await signApp(appPath, identity);
const launchResult = await launchApp(appPath, ['http://myupdate']);
expect(launchResult.code).to.equal(0);
expect(launchResult.out).to.include('Feed URL Set: http://myupdate');
@@ -216,7 +142,7 @@ ifdescribe(process.platform === 'darwin' && !(process.env.CI && process.arch ===
it('should hit the update endpoint when checkForUpdates is called', async () => {
await withTempDirectory(async (dir) => {
const appPath = await copyApp(dir, 'check');
await signApp(appPath);
await signApp(appPath, identity);
server.get('/update-check', (req, res) => {
res.status(204).send();
});
@@ -233,7 +159,7 @@ ifdescribe(process.platform === 'darwin' && !(process.env.CI && process.arch ===
it('should hit the update endpoint with customer headers when checkForUpdates is called', async () => {
await withTempDirectory(async (dir) => {
const appPath = await copyApp(dir, 'check-with-headers');
await signApp(appPath);
await signApp(appPath, identity);
server.get('/update-check', (req, res) => {
res.status(204).send();
});
@@ -250,7 +176,7 @@ ifdescribe(process.platform === 'darwin' && !(process.env.CI && process.arch ===
it('should hit the download endpoint when an update is available and error if the file is bad', async () => {
await withTempDirectory(async (dir) => {
const appPath = await copyApp(dir, 'update');
await signApp(appPath);
await signApp(appPath, identity);
server.get('/update-file', (req, res) => {
res.status(500).send('This is not a file');
});
@@ -286,7 +212,7 @@ ifdescribe(process.platform === 'darwin' && !(process.env.CI && process.arch ===
}, fn: (appPath: string, zipPath: string) => Promise<void>) => {
await withTempDirectory(async (dir) => {
const appPath = await copyApp(dir, opts.startFixture);
await signApp(appPath);
await signApp(appPath, identity);
const updateZipPath = await getOrCreateUpdateZipPath(opts.nextVersion, opts.endFixture, opts.mutateAppPostSign);

View File

@@ -1131,6 +1131,34 @@ describe('BrowserWindow module', () => {
await shown;
expect(w.isMaximized()).to.equal(true);
});
ifit(process.platform === 'darwin')('should attach child window to parent', async () => {
const wShow = once(w, 'show');
w.show();
await wShow;
const c = new BrowserWindow({ show: false, parent: w });
const cShow = once(c, 'show');
c.showInactive();
await cShow;
// verifying by checking that the child tracks the parent's visibility
const minimized = once(w, 'minimize');
w.minimize();
await minimized;
expect(w.isVisible()).to.be.false('parent is visible');
expect(c.isVisible()).to.be.false('child is visible');
const restored = once(w, 'restore');
w.restore();
await restored;
expect(w.isVisible()).to.be.true('parent is visible');
expect(c.isVisible()).to.be.true('child is visible');
closeWindow(c);
});
});
describe('BrowserWindow.focus()', () => {
@@ -5075,6 +5103,55 @@ describe('BrowserWindow module', () => {
w.setContentSize(10, 10);
expectBoundsEqual(w.getContentSize(), [10, 10]);
});
ifit(process.platform === 'win32')('do not change window with frame bounds when maximized', () => {
const w = new BrowserWindow({
show: true,
frame: true,
thickFrame: true
});
expect(w.isResizable()).to.be.true('resizable');
w.maximize();
expect(w.isMaximized()).to.be.true('maximized');
const bounds = w.getBounds();
w.setResizable(false);
expectBoundsEqual(w.getBounds(), bounds);
w.setResizable(true);
expectBoundsEqual(w.getBounds(), bounds);
});
ifit(process.platform === 'win32')('do not change window without frame bounds when maximized', () => {
const w = new BrowserWindow({
show: true,
frame: false,
thickFrame: true
});
expect(w.isResizable()).to.be.true('resizable');
w.maximize();
expect(w.isMaximized()).to.be.true('maximized');
const bounds = w.getBounds();
w.setResizable(false);
expectBoundsEqual(w.getBounds(), bounds);
w.setResizable(true);
expectBoundsEqual(w.getBounds(), bounds);
});
ifit(process.platform === 'win32')('do not change window transparent without frame bounds when maximized', () => {
const w = new BrowserWindow({
show: true,
frame: false,
thickFrame: true,
transparent: true
});
expect(w.isResizable()).to.be.true('resizable');
w.maximize();
expect(w.isMaximized()).to.be.true('maximized');
const bounds = w.getBounds();
w.setResizable(false);
expectBoundsEqual(w.getBounds(), bounds);
w.setResizable(true);
expectBoundsEqual(w.getBounds(), bounds);
});
});
describe('loading main frame state', () => {

View File

@@ -71,7 +71,7 @@ ifdescribe(!(['arm', 'arm64'].includes(process.arch)) || (process.platform !== '
// If the `categoryFilter` param above is not respected
// the file size will be above 50KB.
const fileSizeInKiloBytes = getFileSizeInKiloBytes(outputFilePath);
const expectedMaximumFileSize = 10; // Depends on a platform.
const expectedMaximumFileSize = 50; // Depends on a platform.
expect(fileSizeInKiloBytes).to.be.above(0,
`the trace output file is empty, check "${outputFilePath}"`);

View File

@@ -5,7 +5,6 @@ import * as Busboy from 'busboy';
import * as path from 'path';
import { ifdescribe, ifit, defer, startRemoteControlApp, repeatedly, listen } from './lib/spec-helpers';
import { app } from 'electron/main';
import { crashReporter } from 'electron/common';
import { EventEmitter } from 'events';
import * as fs from 'fs';
import * as uuid from 'uuid';
@@ -583,16 +582,20 @@ ifdescribe(!isLinuxOnArm && !process.mas && !process.env.DISABLE_CRASH_REPORTER_
});
describe('start() option validation', () => {
it('requires that the submitURL option be specified', () => {
expect(() => {
it('requires that the submitURL option be specified', async () => {
const { remotely } = await startRemoteControlApp();
await expect(remotely(() => {
const { crashReporter } = require('electron');
crashReporter.start({} as any);
}).to.throw('submitURL must be specified when uploadToServer is true');
})).to.be.rejectedWith('submitURL must be specified when uploadToServer is true');
});
it('allows the submitURL option to be omitted when uploadToServer is false', () => {
expect(() => {
it('allows the submitURL option to be omitted when uploadToServer is false', async () => {
const { remotely } = await startRemoteControlApp();
await expect(remotely(() => {
const { crashReporter } = require('electron');
crashReporter.start({ uploadToServer: false } as any);
}).not.to.throw();
})).to.be.fulfilled();
});
it('can be called twice', async () => {

View File

@@ -9,6 +9,7 @@ import { setImmediate } from 'timers/promises';
const fixturesPath = path.resolve(__dirname, 'fixtures', 'api', 'utility-process');
const isWindowsOnArm = process.platform === 'win32' && process.arch === 'arm64';
const isWindows32Bit = process.platform === 'win32' && process.arch === 'ia32';
describe('utilityProcess module', () => {
describe('UtilityProcess constructor', () => {
@@ -57,14 +58,14 @@ describe('utilityProcess module', () => {
expect(code).to.equal(0);
});
it('emits \'exit\' when child process crashes', async () => {
ifit(!isWindows32Bit)('emits \'exit\' when child process crashes', async () => {
const child = utilityProcess.fork(path.join(fixturesPath, 'crash.js'));
// Do not check for exit code in this case,
// SIGSEGV code can be 139 or 11 across our different CI pipeline.
await once(child, 'exit');
});
it('emits \'exit\' corresponding to the child process', async () => {
ifit(!isWindows32Bit)('emits \'exit\' corresponding to the child process', async () => {
const child1 = utilityProcess.fork(path.join(fixturesPath, 'endless.js'));
await once(child1, 'spawn');
const child2 = utilityProcess.fork(path.join(fixturesPath, 'crash.js'));
@@ -88,7 +89,7 @@ describe('utilityProcess module', () => {
});
describe('app \'child-process-gone\' event', () => {
it('with default serviceName', async () => {
ifit(!isWindows32Bit)('with default serviceName', async () => {
utilityProcess.fork(path.join(fixturesPath, 'crash.js'));
const [, details] = await once(app, 'child-process-gone') as [any, Electron.Details];
expect(details.type).to.equal('Utility');
@@ -97,7 +98,7 @@ describe('utilityProcess module', () => {
expect(details.reason).to.be.oneOf(['crashed', 'abnormal-exit']);
});
it('with custom serviceName', async () => {
ifit(!isWindows32Bit)('with custom serviceName', async () => {
utilityProcess.fork(path.join(fixturesPath, 'crash.js'), [], { serviceName: 'Hello World!' });
const [, details] = await once(app, 'child-process-gone') as [any, Electron.Details];
expect(details.type).to.equal('Utility');

View File

@@ -897,6 +897,65 @@ describe('chrome extensions', () => {
});
});
// chrome.action is not supported in Electron. These tests only ensure
// it does not explode.
describe('chrome.action', () => {
let customSession: Session;
let w = null as unknown as BrowserWindow;
before(async () => {
customSession = session.fromPartition(`persist:${uuid.v4()}`);
await customSession.loadExtension(path.join(fixtures, 'extensions', 'chrome-action-fail'));
});
beforeEach(() => {
w = new BrowserWindow({
show: false,
webPreferences: {
session: customSession
}
});
});
afterEach(closeAllWindows);
it('isEnabled', async () => {
await w.loadURL(url);
const message = { method: 'isEnabled' };
w.webContents.executeJavaScript(`window.postMessage('${JSON.stringify(message)}', '*')`);
const [, , responseString] = await once(w.webContents, 'console-message');
const response = JSON.parse(responseString);
expect(response).to.equal(false);
});
it('setIcon', async () => {
await w.loadURL(url);
const message = { method: 'setIcon' };
w.webContents.executeJavaScript(`window.postMessage('${JSON.stringify(message)}', '*')`);
const [, , responseString] = await once(w.webContents, 'console-message');
const response = JSON.parse(responseString);
expect(response).to.equal(null);
});
it('getBadgeText', async () => {
await w.loadURL(url);
const message = { method: 'getBadgeText' };
w.webContents.executeJavaScript(`window.postMessage('${JSON.stringify(message)}', '*')`);
const [, , responseString] = await once(w.webContents, 'console-message');
const response = JSON.parse(responseString);
expect(response).to.equal('');
});
});
describe('chrome.tabs', () => {
let customSession: Session;
let w = null as unknown as BrowserWindow;

View File

@@ -0,0 +1,25 @@
const { execFileSync } = require('node:child_process');
const path = require('node:path');
const fixtures = path.resolve(__dirname, '..');
const failJs = path.join(fixtures, 'module', 'fail.js');
const env = {
ELECTRON_RUN_AS_NODE: 'true',
// Process will exit with 1 if NODE_OPTIONS is accepted.
NODE_OPTIONS: `--require "${failJs}"`,
// Try bypassing the check with NODE_REPL_EXTERNAL_MODULE.
NODE_REPL_EXTERNAL_MODULE: failJs
};
// Provide a lower cased NODE_OPTIONS in case some code ignores case sensitivity
// when reading NODE_OPTIONS.
env.node_options = env.NODE_OPTIONS;
try {
execFileSync(process.argv[2],
['--require', path.join(fixtures, 'module', 'noop.js')],
{ env, stdio: 'inherit' });
process.exit(0);
} catch (error) {
console.log('NODE_OPTIONS passed to child');
process.exit(1);
}

View File

@@ -0,0 +1,28 @@
/* global chrome */
const handleRequest = async (request, sender, sendResponse) => {
const { method } = request;
const tabId = sender.tab.id;
switch (method) {
case 'isEnabled': {
chrome.action.isEnabled(tabId).then(sendResponse);
break;
}
case 'setIcon': {
chrome.action.setIcon({ tabId, imageData: {} }).then(sendResponse);
break;
}
case 'getBadgeText': {
chrome.action.getBadgeText({ tabId }).then(sendResponse);
break;
}
}
};
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
handleRequest(request, sender, sendResponse);
return true;
});

View File

@@ -0,0 +1,30 @@
/* global chrome */
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
sendResponse(request);
});
const testMap = {
isEnabled () {
chrome.runtime.sendMessage({ method: 'isEnabled' }, response => {
console.log(JSON.stringify(response));
});
},
setIcon () {
chrome.runtime.sendMessage({ method: 'setIcon' }, response => {
console.log(JSON.stringify(response));
});
},
getBadgeText () {
chrome.runtime.sendMessage({ method: 'getBadgeText' }, response => {
console.log(JSON.stringify(response));
});
}
};
const dispatchTest = (event) => {
const { method, args = [] } = JSON.parse(event.data);
testMap[method](...args);
};
window.addEventListener('message', dispatchTest, false);

View File

@@ -0,0 +1,19 @@
{
"name": "Action popup demo",
"version": "1.0",
"manifest_version": 3,
"background": {
"service_worker": "background.js"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["main.js"],
"run_at": "document_start"
}
],
"action": {
"default_title": "Click Me",
"default_popup": "popup.html"
}
}

View File

@@ -0,0 +1,9 @@
<html>
<body>
<script type="text/javascript" charset="utf-8">
console.log('b');
</script>
</body>
</html>

View File

@@ -0,0 +1,99 @@
import * as cp from 'node:child_process';
import * as fs from 'fs-extra';
import * as os from 'node:os';
import * as path from 'node:path';
import { expect } from 'chai';
const features = process._linkedBinding('electron_common_features');
const fixturesPath = path.resolve(__dirname, '..', 'fixtures');
export const shouldRunCodesignTests =
process.platform === 'darwin' &&
!(process.env.CI && process.arch === 'arm64') &&
!process.mas &&
!features.isComponentBuild();
let identity: string | null;
export function getCodesignIdentity () {
if (identity === undefined) {
const result = cp.spawnSync(path.resolve(__dirname, '../../script/codesign/get-trusted-identity.sh'));
if (result.status !== 0 || result.stdout.toString().trim().length === 0) {
// Per https://circleci.com/docs/2.0/env-vars:
// CIRCLE_PR_NUMBER is only present on forked PRs
if (process.env.CI && !process.env.CIRCLE_PR_NUMBER) {
throw new Error('No valid signing identity available to run autoUpdater specs');
}
identity = null;
} else {
identity = result.stdout.toString().trim();
}
}
return identity;
}
export async function copyApp (newDir: string, fixture: string | null = 'initial') {
const appBundlePath = path.resolve(process.execPath, '../../..');
const newPath = path.resolve(newDir, 'Electron.app');
cp.spawnSync('cp', ['-R', appBundlePath, path.dirname(newPath)]);
if (fixture) {
const appDir = path.resolve(newPath, 'Contents/Resources/app');
await fs.mkdirp(appDir);
await fs.copy(path.resolve(fixturesPath, 'auto-update', fixture), appDir);
}
const plistPath = path.resolve(newPath, 'Contents', 'Info.plist');
await fs.writeFile(
plistPath,
(await fs.readFile(plistPath, 'utf8')).replace('<key>BuildMachineOSBuild</key>', `<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict><key>BuildMachineOSBuild</key>`)
);
return newPath;
};
export function spawn (cmd: string, args: string[], opts: any = {}) {
let out = '';
const child = cp.spawn(cmd, args, opts);
child.stdout.on('data', (chunk: Buffer) => {
out += chunk.toString();
});
child.stderr.on('data', (chunk: Buffer) => {
out += chunk.toString();
});
return new Promise<{ code: number, out: string }>((resolve) => {
child.on('exit', (code, signal) => {
expect(signal).to.equal(null);
resolve({
code: code!,
out
});
});
});
};
export function signApp (appPath: string, identity: string) {
return spawn('codesign', ['-s', identity, '--deep', '--force', appPath]);
};
export async function withTempDirectory (fn: (dir: string) => Promise<void>, autoCleanUp = true) {
const dir = await fs.mkdtemp(path.resolve(os.tmpdir(), 'electron-update-spec-'));
try {
await fn(dir);
} finally {
if (autoCleanUp) {
cp.spawnSync('rm', ['-r', dir]);
}
}
};

View File

@@ -29,13 +29,19 @@ export const closeWindow = async (
await ensureWindowIsClosed(window);
if (assertNotWindows) {
const windows = BrowserWindow.getAllWindows();
try {
expect(windows).to.have.lengthOf(0);
} finally {
for (const win of windows) {
await ensureWindowIsClosed(win);
}
let windows = BrowserWindow.getAllWindows();
if (windows.length > 0) {
setTimeout(async () => {
// Wait until next tick to assert that all windows have been closed.
windows = BrowserWindow.getAllWindows();
try {
expect(windows).to.have.lengthOf(0);
} finally {
for (const win of windows) {
await ensureWindowIsClosed(win);
}
}
});
}
}
};

View File

@@ -1,9 +1,10 @@
import { expect } from 'chai';
import * as childProcess from 'child_process';
import * as fs from 'fs';
import * as fs from 'fs-extra';
import * as path from 'path';
import * as util from 'util';
import { getRemoteContext, ifdescribe, ifit, itremote, useRemoteContext } from './lib/spec-helpers';
import { copyApp, getCodesignIdentity, shouldRunCodesignTests, signApp, spawn, withTempDirectory } from './lib/codesign-helpers';
import { webContents } from 'electron/main';
import { EventEmitter } from 'stream';
import { once } from 'events';
@@ -660,6 +661,66 @@ describe('node feature', () => {
});
});
ifdescribe(shouldRunCodesignTests)('NODE_OPTIONS in signed app', function () {
let identity = '';
beforeEach(function () {
const result = getCodesignIdentity();
if (result === null) {
this.skip();
} else {
identity = result;
}
});
const script = path.join(fixtures, 'api', 'fork-with-node-options.js');
const nodeOptionsWarning = 'Node.js environment variables are disabled because this process is invoked by other apps';
it('is disabled when invoked by other apps in ELECTRON_RUN_AS_NODE mode', async () => {
await withTempDirectory(async (dir) => {
const appPath = await copyApp(dir);
await signApp(appPath, identity);
// Invoke Electron by using the system node binary as middle layer, so
// the check of NODE_OPTIONS will think the process is started by other
// apps.
const { code, out } = await spawn('node', [script, path.join(appPath, 'Contents/MacOS/Electron')]);
expect(code).to.equal(0);
expect(out).to.include(nodeOptionsWarning);
});
});
it('is disabled when invoked by alien binary in app bundle in ELECTRON_RUN_AS_NODE mode', async function () {
await withTempDirectory(async (dir) => {
const appPath = await copyApp(dir);
await signApp(appPath, identity);
// Find system node and copy it to app bundle.
const nodePath = process.env.PATH?.split(path.delimiter).find(dir => fs.existsSync(path.join(dir, 'node')));
if (!nodePath) {
this.skip();
return;
}
const alienBinary = path.join(appPath, 'Contents/MacOS/node');
await fs.copy(path.join(nodePath, 'node'), alienBinary);
// Try to execute electron app from the alien node in app bundle.
const { code, out } = await spawn(alienBinary, [script, path.join(appPath, 'Contents/MacOS/Electron')]);
expect(code).to.equal(0);
expect(out).to.include(nodeOptionsWarning);
});
});
it('is respected when invoked from self', async () => {
await withTempDirectory(async (dir) => {
const appPath = await copyApp(dir, null);
await signApp(appPath, identity);
const appExePath = path.join(appPath, 'Contents/MacOS/Electron');
const { code, out } = await spawn(appExePath, [script, appExePath]);
expect(code).to.equal(1);
expect(out).to.not.include(nodeOptionsWarning);
expect(out).to.include('NODE_OPTIONS passed to child');
});
});
});
ifdescribe(features.isRunAsNodeEnabled())('Node.js cli flags', () => {
let child: childProcess.ChildProcessWithoutNullStreams;
let exitPromise: Promise<any[]>;
@@ -868,16 +929,23 @@ describe('node feature', () => {
});
it('performs microtask checkpoint correctly', (done) => {
let timer : NodeJS.Timeout;
const listener = () => {
done(new Error('catch block is delayed to next tick'));
};
const f3 = async () => {
return new Promise((resolve, reject) => {
timer = setTimeout(listener);
reject(new Error('oops'));
});
};
process.once('unhandledRejection', () => done('catch block is delayed to next tick'));
setTimeout(() => {
f3().catch(() => done());
f3().catch(() => {
clearTimeout(timer);
done();
});
});
});
});