mirror of
https://github.com/electron/electron.git
synced 2026-02-26 03:01:17 -05:00
Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
763729c9ef | ||
|
|
bc7b2a3589 | ||
|
|
13908747ab | ||
|
|
0ebe40354e | ||
|
|
e16d9f99e6 | ||
|
|
682b27f606 | ||
|
|
0b94b5b86f | ||
|
|
0c3113a4c5 | ||
|
|
5917fe9143 | ||
|
|
8638667c66 | ||
|
|
2c7c8b2d44 | ||
|
|
9c7f63cc9c | ||
|
|
6cdb2fb3af | ||
|
|
0d99c8a222 | ||
|
|
783f23bfdb | ||
|
|
9ba6477dcb | ||
|
|
24c06a45ef | ||
|
|
8e074bc1d0 | ||
|
|
eb2173846b | ||
|
|
1813586545 | ||
|
|
d47906c855 | ||
|
|
aa688f9a45 | ||
|
|
4cfc4bf074 | ||
|
|
a0af9e0e3c | ||
|
|
f2ce1ce1b4 | ||
|
|
af61c40ee0 | ||
|
|
917664c68b | ||
|
|
ead3de1ac5 | ||
|
|
44bf2a7a6a | ||
|
|
0337b2c9f5 | ||
|
|
fe0a54f729 | ||
|
|
6799879694 | ||
|
|
696087f29c |
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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/
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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,
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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(),
|
||||
@@ -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
|
||||
|
||||
69
patches/chromium/cherry-pick-021598ea43c1.patch
Normal file
69
patches/chromium/cherry-pick-021598ea43c1.patch
Normal 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()) {
|
||||
125
patches/chromium/cherry-pick-1f8bec968902.patch
Normal file
125
patches/chromium/cherry-pick-1f8bec968902.patch
Normal 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
|
||||
57
patches/chromium/cherry-pick-3df423a5b8de.patch
Normal file
57
patches/chromium/cherry-pick-3df423a5b8de.patch
Normal 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() {
|
||||
48
patches/chromium/cherry-pick-3f45b1af5e41.patch
Normal file
48
patches/chromium/cherry-pick-3f45b1af5e41.patch
Normal 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(
|
||||
67
patches/chromium/cherry-pick-4a98f9e304be.patch
Normal file
67
patches/chromium/cherry-pick-4a98f9e304be.patch
Normal 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;
|
||||
43
patches/chromium/cherry-pick-4ca62c7a8b88.patch
Normal file
43
patches/chromium/cherry-pick-4ca62c7a8b88.patch
Normal 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;
|
||||
}
|
||||
117
patches/chromium/cherry-pick-50a1bddfca85.patch
Normal file
117
patches/chromium/cherry-pick-50a1bddfca85.patch
Normal 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
|
||||
|
||||
61
patches/chromium/cherry-pick-5b2fddadaa12.patch
Normal file
61
patches/chromium/cherry-pick-5b2fddadaa12.patch
Normal 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.
|
||||
73
patches/chromium/cherry-pick-5fde415e06f9.patch
Normal file
73
patches/chromium/cherry-pick-5fde415e06f9.patch
Normal 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_);
|
||||
};
|
||||
|
||||
37
patches/chromium/cherry-pick-76340163a820.patch
Normal file
37
patches/chromium/cherry-pick-76340163a820.patch
Normal 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
|
||||
33
patches/chromium/cherry-pick-8d607d3921b8.patch
Normal file
33
patches/chromium/cherry-pick-8d607d3921b8.patch
Normal 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()));
|
||||
42
patches/chromium/cherry-pick-9384cddc7705.patch
Normal file
42
patches/chromium/cherry-pick-9384cddc7705.patch
Normal 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);
|
||||
}
|
||||
};
|
||||
31
patches/chromium/cherry-pick-c1cda70a433a.patch
Normal file
31
patches/chromium/cherry-pick-c1cda70a433a.patch
Normal 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);
|
||||
150
patches/chromium/cherry-pick-cc07a95bc309.patch
Normal file
150
patches/chromium/cherry-pick-cc07a95bc309.patch
Normal 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.
|
||||
+
|
||||
116
patches/chromium/cherry-pick-e13061c50998.patch
Normal file
116
patches/chromium/cherry-pick-e13061c50998.patch
Normal 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) {
|
||||
72
patches/chromium/cherry-pick-ee0b8769f428.patch
Normal file
72
patches/chromium/cherry-pick-ee0b8769f428.patch
Normal 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>(
|
||||
181
patches/chromium/cherry-pick-f15cfb9371c4.patch
Normal file
181
patches/chromium/cherry-pick-f15cfb9371c4.patch
Normal 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_;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
87
patches/chromium/m120_ipcz_fix_a_few_weak_asserts.patch
Normal file
87
patches/chromium/m120_ipcz_fix_a_few_weak_asserts.patch
Normal 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 =
|
||||
@@ -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('/'))
|
||||
55
patches/chromium/safely_crash_on_dangling_profile.patch
Normal file
55
patches/chromium/safely_crash_on_dangling_profile.patch
Normal 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();
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
@@ -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
3
patches/libavif/.patches
Normal 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
|
||||
@@ -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));
|
||||
|
||||
@@ -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)) {
|
||||
@@ -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);
|
||||
@@ -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
|
||||
|
||||
33
patches/node/fix_avx_detection.patch
Normal file
33
patches/node/fix_avx_detection.patch
Normal 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);
|
||||
@@ -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;
|
||||
}
|
||||
1
patches/openscreen/.patches
Normal file
1
patches/openscreen/.patches
Normal file
@@ -0,0 +1 @@
|
||||
cherry-pick-971d6055e7b7.patch
|
||||
142
patches/openscreen/cherry-pick-971d6055e7b7.patch
Normal file
142
patches/openscreen/cherry-pick-971d6055e7b7.patch
Normal 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
1
patches/skia/.patches
Normal file
@@ -0,0 +1 @@
|
||||
avoid_combining_extremely_large_meshes.patch
|
||||
31
patches/skia/avoid_combining_extremely_large_meshes.patch
Normal file
31
patches/skia/avoid_combining_extremely_large_meshes.patch
Normal 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
1
patches/sqlite/.patches
Normal file
@@ -0,0 +1 @@
|
||||
fix_a_spurious_misuse_of_aggregate_function_error_that_could_occur.patch
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
341
patches/v8/cherry-pick-389ea9be7d68.patch
Normal file
341
patches/v8/cherry-pick-389ea9be7d68.patch
Normal 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();
|
||||
46
patches/v8/cherry-pick-46cb67e3b296.patch
Normal file
46
patches/v8/cherry-pick-46cb67e3b296.patch
Normal 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());
|
||||
27
patches/v8/cherry-pick-78dd4b31847a.patch
Normal file
27
patches/v8/cherry-pick-78dd4b31847a.patch
Normal 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});
|
||||
@@ -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;
|
||||
@@ -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");
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
@@ -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)}`);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -187,6 +187,8 @@ class NativeWindowViews : public NativeWindow,
|
||||
void set_overlay_symbol_color(SkColor color) {
|
||||
overlay_symbol_color_ = color;
|
||||
}
|
||||
|
||||
void UpdateThickFrame();
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"],
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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": [
|
||||
{
|
||||
|
||||
370
shell/common/extensions/api/browser_action.json
Normal file
370
shell/common/extensions/api/browser_action.json
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -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:
|
||||
|
||||
113
shell/common/mac/codesign_util.cc
Normal file
113
shell/common/mac/codesign_util.cc
Normal 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
|
||||
24
shell/common/mac/codesign_util.h
Normal file
24
shell/common/mac/codesign_util.h
Normal 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_
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "build/build_config.h"
|
||||
#include "v8/include/v8.h"
|
||||
|
||||
namespace node {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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', () => {
|
||||
|
||||
@@ -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}"`);
|
||||
|
||||
@@ -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 () => {
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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;
|
||||
|
||||
25
spec/fixtures/api/fork-with-node-options.js
vendored
Normal file
25
spec/fixtures/api/fork-with-node-options.js
vendored
Normal 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);
|
||||
}
|
||||
28
spec/fixtures/extensions/chrome-action-fail/background.js
vendored
Normal file
28
spec/fixtures/extensions/chrome-action-fail/background.js
vendored
Normal 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;
|
||||
});
|
||||
30
spec/fixtures/extensions/chrome-action-fail/main.js
vendored
Normal file
30
spec/fixtures/extensions/chrome-action-fail/main.js
vendored
Normal 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);
|
||||
19
spec/fixtures/extensions/chrome-action-fail/manifest.json
vendored
Normal file
19
spec/fixtures/extensions/chrome-action-fail/manifest.json
vendored
Normal 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"
|
||||
}
|
||||
}
|
||||
9
spec/fixtures/extensions/chrome-action-fail/popup.html
vendored
Normal file
9
spec/fixtures/extensions/chrome-action-fail/popup.html
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
<html>
|
||||
|
||||
<body>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
console.log('b');
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
99
spec/lib/codesign-helpers.ts
Normal file
99
spec/lib/codesign-helpers.ts
Normal 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]);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user