mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b782e259b | ||
|
|
b2047d710c | ||
|
|
10b2baea43 | ||
|
|
454990a201 | ||
|
|
10b49ffa12 | ||
|
|
dc0fc78fac | ||
|
|
1aafc2ae38 | ||
|
|
595e25a270 | ||
|
|
7fe5925c94 | ||
|
|
c4b0ff4994 | ||
|
|
abdb9157c3 | ||
|
|
30e1be9150 | ||
|
|
5b48fa0318 | ||
|
|
be1c22ecab | ||
|
|
2c822ce4ac | ||
|
|
f4041c10cf | ||
|
|
60c84cbd77 | ||
|
|
523fa39765 | ||
|
|
d368492bfd | ||
|
|
3c269d74c9 | ||
|
|
5bbcc22b8d | ||
|
|
9abb7fb7e3 | ||
|
|
364390e039 | ||
|
|
b59963cf04 | ||
|
|
7a026ed3dc | ||
|
|
75b7a858ac | ||
|
|
1ba3da738b | ||
|
|
def64aba17 | ||
|
|
d5e1edf244 | ||
|
|
53d9cdbaf0 | ||
|
|
08ae619c5d |
@@ -54,7 +54,7 @@ executors:
|
||||
type: enum
|
||||
enum: ["macos.x86.medium.gen2", "large"]
|
||||
macos:
|
||||
xcode: 13.3.0
|
||||
xcode: 13.4.1
|
||||
resource_class: << parameters.size >>
|
||||
|
||||
# Electron Runners
|
||||
@@ -245,14 +245,27 @@ step-depot-tools-get: &step-depot-tools-get
|
||||
sed -i '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja
|
||||
# Remove swift-format dep from cipd on macOS until we send a patch upstream.
|
||||
cd depot_tools
|
||||
patch gclient.py -R \<<'EOF'
|
||||
676,677c676
|
||||
< packages = dep_value.get('packages', [])
|
||||
< for package in (x for x in packages if "infra/3pp/tools/swift-format" not in x.get('package')):
|
||||
---
|
||||
> for package in dep_value.get('packages', []):
|
||||
cat > gclient.diff \<< 'EOF'
|
||||
diff --git a/gclient.py b/gclient.py
|
||||
index 3a9c5c6..f222043 100755
|
||||
--- a/gclient.py
|
||||
+++ b/gclient.py
|
||||
@@ -712,7 +712,8 @@ class Dependency(gclient_utils.WorkItem, DependencySettings):
|
||||
|
||||
if dep_type == 'cipd':
|
||||
cipd_root = self.GetCipdRoot()
|
||||
- for package in dep_value.get('packages', []):
|
||||
+ packages = dep_value.get('packages', [])
|
||||
+ for package in (x for x in packages if "infra/3pp/tools/swift-format" not in x.get('package')):
|
||||
deps_to_add.append(
|
||||
CipdDependency(
|
||||
parent=self,
|
||||
EOF
|
||||
git apply --3way gclient.diff
|
||||
fi
|
||||
# Ensure depot_tools does not update.
|
||||
test -d depot_tools && cd depot_tools
|
||||
touch .disable_auto_update
|
||||
|
||||
step-depot-tools-add-to-path: &step-depot-tools-add-to-path
|
||||
run:
|
||||
@@ -274,7 +287,7 @@ step-gclient-sync: &step-gclient-sync
|
||||
ELECTRON_USE_THREE_WAY_MERGE_FOR_PATCHES=1 gclient sync --with_branch_heads --with_tags
|
||||
if [ "$IS_RELEASE" != "true" ]; then
|
||||
# Re-export all the patches to check if there were changes.
|
||||
python src/electron/script/export_all_patches.py src/electron/patches/config.json
|
||||
python3 src/electron/script/export_all_patches.py src/electron/patches/config.json
|
||||
cd src/electron
|
||||
git update-index --refresh || true
|
||||
if ! git diff-index --quiet HEAD --; then
|
||||
@@ -328,8 +341,8 @@ step-setup-goma-for-build: &step-setup-goma-for-build
|
||||
mkdir third_party
|
||||
node -e "require('./src/utils/goma.js').downloadAndPrepare({ gomaOneForAll: true })"
|
||||
export GOMA_FALLBACK_ON_AUTH_FAILURE=true
|
||||
third_party/goma/goma_ctl.py ensure_start
|
||||
if [ ! -z "$RAW_GOMA_AUTH" ] && [ "`third_party/goma/goma_auth.py info`" != "Login as Fermi Planck" ]; then
|
||||
python3 third_party/goma/goma_ctl.py ensure_start
|
||||
if [ ! -z "$RAW_GOMA_AUTH" ] && [ "`python3 third_party/goma/goma_auth.py info`" != "Login as Fermi Planck" ]; then
|
||||
echo "WARNING!!!!!! Goma authentication is incorrect; please update Goma auth token."
|
||||
exit 1
|
||||
fi
|
||||
@@ -357,14 +370,14 @@ step-restore-brew-cache: &step-restore-brew-cache
|
||||
- /usr/local/Cellar/gnu-tar
|
||||
- /usr/local/bin/gtar
|
||||
keys:
|
||||
- v6-brew-cache-{{ arch }}
|
||||
- v7-brew-cache-{{ arch }}
|
||||
|
||||
step-save-brew-cache: &step-save-brew-cache
|
||||
save_cache:
|
||||
paths:
|
||||
- /usr/local/Cellar/gnu-tar
|
||||
- /usr/local/bin/gtar
|
||||
key: v6-brew-cache-{{ arch }}
|
||||
key: v7-brew-cache-{{ arch }}
|
||||
name: Persisting brew cache
|
||||
|
||||
step-get-more-space-on-mac: &step-get-more-space-on-mac
|
||||
@@ -667,9 +680,9 @@ step-verify-mksnapshot: &step-verify-mksnapshot
|
||||
if [ "$IS_ASAN" != "1" ]; then
|
||||
cd src
|
||||
if [ "$TARGET_ARCH" == "arm" ] || [ "$TARGET_ARCH" == "arm64" ]; then
|
||||
python electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default --snapshot-files-dir $PWD/cross-arch-snapshots
|
||||
python3 electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default --snapshot-files-dir $PWD/cross-arch-snapshots
|
||||
else
|
||||
python electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default
|
||||
python3 electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -679,7 +692,7 @@ step-verify-chromedriver: &step-verify-chromedriver
|
||||
command: |
|
||||
if [ "$IS_ASAN" != "1" ]; then
|
||||
cd src
|
||||
python electron/script/verify-chromedriver.py --source-root "$PWD" --build-dir out/Default
|
||||
python3 electron/script/verify-chromedriver.py --source-root "$PWD" --build-dir out/Default
|
||||
fi
|
||||
|
||||
step-setup-linux-for-headless-testing: &step-setup-linux-for-headless-testing
|
||||
@@ -805,7 +818,7 @@ step-maybe-cross-arch-snapshot: &step-maybe-cross-arch-snapshot
|
||||
elif [ "`uname`" == "Darwin" ]; then
|
||||
cp "out/Default/$MKSNAPSHOT_PATH/libffmpeg.dylib" out/Default
|
||||
fi
|
||||
python electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default --create-snapshot-only
|
||||
python3 electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default --create-snapshot-only
|
||||
mkdir cross-arch-snapshots
|
||||
cp out/Default-mksnapshot-test/*.bin cross-arch-snapshots
|
||||
# Clean up so that ninja does not get confused
|
||||
@@ -962,7 +975,6 @@ step-ts-compile: &step-ts-compile
|
||||
# List of all steps.
|
||||
steps-electron-gn-check: &steps-electron-gn-check
|
||||
steps:
|
||||
- install-python2-mac
|
||||
- *step-setup-goma-for-build
|
||||
- checkout-from-cache
|
||||
- *step-setup-env-for-build
|
||||
@@ -981,31 +993,6 @@ steps-electron-ts-compile-for-doc-change: &steps-electron-ts-compile-for-doc-cha
|
||||
|
||||
# Command Aliases
|
||||
commands:
|
||||
install-python2-mac:
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v2.7.18-python-cache-{{ arch }}
|
||||
name: Restore python cache
|
||||
- run:
|
||||
name: Install python2 on macos
|
||||
command: |
|
||||
if [ "`uname`" == "Darwin" ] && [ "$IS_ELECTRON_RUNNER" != "1" ]; then
|
||||
if [ ! -f "python-downloads/python-2.7.18-macosx10.9.pkg" ]; then
|
||||
mkdir python-downloads
|
||||
echo 'Downloading Python 2.7.18'
|
||||
curl -O https://dev-cdn.electronjs.org/python/python-2.7.18-macosx10.9.pkg
|
||||
mv python-2.7.18-macosx10.9.pkg python-downloads
|
||||
else
|
||||
echo 'Using Python install from cache'
|
||||
fi
|
||||
sudo installer -pkg python-downloads/python-2.7.18-macosx10.9.pkg -target /
|
||||
fi
|
||||
- save_cache:
|
||||
paths:
|
||||
- python-downloads
|
||||
key: v2.7.18-python-cache-{{ arch }}
|
||||
name: Persisting python cache
|
||||
maybe-restore-portaled-src-cache:
|
||||
parameters:
|
||||
halt-if-successful:
|
||||
@@ -1302,7 +1289,6 @@ commands:
|
||||
- run: rm -rf src/electron
|
||||
- *step-restore-brew-cache
|
||||
- *step-install-gnutar-on-mac
|
||||
- install-python2-mac
|
||||
- *step-save-brew-cache
|
||||
- when:
|
||||
condition: << parameters.build >>
|
||||
@@ -1463,7 +1449,6 @@ commands:
|
||||
- *step-setup-linux-for-headless-testing
|
||||
- *step-restore-brew-cache
|
||||
- *step-fix-known-hosts-linux
|
||||
- install-python2-mac
|
||||
- *step-install-signing-cert-on-mac
|
||||
|
||||
- run:
|
||||
@@ -1573,7 +1558,6 @@ commands:
|
||||
- *step-depot-tools-get
|
||||
- *step-depot-tools-add-to-path
|
||||
- *step-restore-brew-cache
|
||||
- install-python2-mac
|
||||
- *step-get-more-space-on-mac
|
||||
- when:
|
||||
condition: << parameters.checkout >>
|
||||
|
||||
@@ -83,6 +83,8 @@ for:
|
||||
Remove-Item -Recurse -Force $pwd\build-tools
|
||||
}
|
||||
- git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||
- 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"
|
||||
- ps: >-
|
||||
if (Test-Path -Path "$pwd\src\electron") {
|
||||
@@ -176,6 +178,30 @@ for:
|
||||
7z a pdb.zip out\Default\*.pdb
|
||||
}
|
||||
- python3 electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip electron/script/zip_manifests/dist_zip.win.%TARGET_ARCH%.manifest
|
||||
- ps: |
|
||||
cd C:\projects\src
|
||||
$missing_artifacts = $false
|
||||
if ($env:SHOULD_SKIP_ARTIFACT_VALIDATION -eq 'true') {
|
||||
Write-warning "Skipping artifact validation for doc-only PR"
|
||||
} else {
|
||||
$artifacts_to_validate = 'dist.zip','windows_toolchain_profile.json','shell_browser_ui_unittests.exe','chromedriver.zip','ffmpeg.zip','node_headers.zip','mksnapshot.zip','electron.lib','hunspell_dictionaries.zip'
|
||||
foreach($artifact_name in $artifacts_to_validate) {
|
||||
if ($artifact_name -eq 'ffmpeg.zip') {
|
||||
$artifact_file = "out\ffmpeg\ffmpeg.zip"
|
||||
} elseif ($artifact_name -eq 'node_headers.zip') {
|
||||
$artifact_file = $artifact_name
|
||||
} else {
|
||||
$artifact_file = "out\Default\$artifact_name"
|
||||
}
|
||||
if (-not(Test-Path $artifact_file)) {
|
||||
Write-warning "$artifact_name is missing and cannot be added to artifacts"
|
||||
$missing_artifacts = $true
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($missing_artifacts) {
|
||||
throw "Build failed due to missing artifacts"
|
||||
}
|
||||
|
||||
deploy_script:
|
||||
- cd electron
|
||||
@@ -201,7 +227,7 @@ for:
|
||||
- if exist node_headers.zip (appveyor-retry appveyor PushArtifact node_headers.zip)
|
||||
- if exist out\Default\mksnapshot.zip (appveyor-retry appveyor PushArtifact out\Default\mksnapshot.zip)
|
||||
- if exist out\Default\hunspell_dictionaries.zip (appveyor-retry appveyor PushArtifact out\Default\hunspell_dictionaries.zip)
|
||||
- if exist out\Default\electron.lib (appveyor-retry appveyor PushArtifact out\Default\electron.lib)
|
||||
- if exist out\Default\electron.lib (appveyor-retry appveyor PushArtifact out\Default\electron.lib)
|
||||
- ps: >-
|
||||
if ((Test-Path "pdb.zip") -And ($env:GN_CONFIG -ne 'release')) {
|
||||
appveyor-retry appveyor PushArtifact pdb.zip
|
||||
@@ -232,7 +258,7 @@ for:
|
||||
# Download build artifacts
|
||||
$apiUrl = 'https://ci.appveyor.com/api'
|
||||
$build_info = Invoke-RestMethod -Method Get -Uri "$apiUrl/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/builds/$env:APPVEYOR_BUILD_ID"
|
||||
$artifacts_to_download = @('dist.zip','ffmpeg.zip','node_headers.zip','pdb.zip','electron.lib')
|
||||
$artifacts_to_download = @('dist.zip','ffmpeg.zip','node_headers.zip','electron.lib')
|
||||
foreach ($job in $build_info.build.jobs) {
|
||||
if ($job.name -eq "Build Arm on X64 Windows") {
|
||||
$jobId = $job.jobId
|
||||
@@ -244,10 +270,13 @@ for:
|
||||
}
|
||||
Invoke-RestMethod -Method Get -Uri "$apiUrl/buildjobs/$jobId/artifacts/$artifact_name" -OutFile $outfile
|
||||
}
|
||||
# Uncomment the following lines to download the pdb.zip to show real stacktraces when crashes happen during testing
|
||||
# Invoke-RestMethod -Method Get -Uri "$apiUrl/buildjobs/$jobId/artifacts/pdb.zip" -OutFile pdb.zip
|
||||
# 7z x -y -osrc pdb.zip
|
||||
}
|
||||
}
|
||||
- ps: |
|
||||
$out_default_zips = @('dist.zip','pdb.zip')
|
||||
$out_default_zips = @('dist.zip')
|
||||
foreach($zip_name in $out_default_zips) {
|
||||
7z x -y -osrc\out\Default $zip_name
|
||||
}
|
||||
|
||||
31
appveyor.yml
31
appveyor.yml
@@ -81,6 +81,8 @@ for:
|
||||
Remove-Item -Recurse -Force $pwd\build-tools
|
||||
}
|
||||
- git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
|
||||
- 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"
|
||||
- ps: >-
|
||||
if (Test-Path -Path "$pwd\src\electron") {
|
||||
@@ -174,6 +176,30 @@ for:
|
||||
7z a pdb.zip out\Default\*.pdb
|
||||
}
|
||||
- python3 electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip electron/script/zip_manifests/dist_zip.win.%TARGET_ARCH%.manifest
|
||||
- ps: |
|
||||
cd C:\projects\src
|
||||
$missing_artifacts = $false
|
||||
if ($env:SHOULD_SKIP_ARTIFACT_VALIDATION -eq 'true') {
|
||||
Write-warning "Skipping artifact validation for doc-only PR"
|
||||
} else {
|
||||
$artifacts_to_validate = 'dist.zip','windows_toolchain_profile.json','shell_browser_ui_unittests.exe','chromedriver.zip','ffmpeg.zip','node_headers.zip','mksnapshot.zip','electron.lib','hunspell_dictionaries.zip'
|
||||
foreach($artifact_name in $artifacts_to_validate) {
|
||||
if ($artifact_name -eq 'ffmpeg.zip') {
|
||||
$artifact_file = "out\ffmpeg\ffmpeg.zip"
|
||||
} elseif ($artifact_name -eq 'node_headers.zip') {
|
||||
$artifact_file = $artifact_name
|
||||
} else {
|
||||
$artifact_file = "out\Default\$artifact_name"
|
||||
}
|
||||
if (-not(Test-Path $artifact_file)) {
|
||||
Write-warning "$artifact_name is missing and cannot be added to artifacts"
|
||||
$missing_artifacts = $true
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($missing_artifacts) {
|
||||
throw "Build failed due to missing artifacts"
|
||||
}
|
||||
|
||||
deploy_script:
|
||||
- cd electron
|
||||
@@ -199,7 +225,7 @@ for:
|
||||
- if exist node_headers.zip (appveyor-retry appveyor PushArtifact node_headers.zip)
|
||||
- if exist out\Default\mksnapshot.zip (appveyor-retry appveyor PushArtifact out\Default\mksnapshot.zip)
|
||||
- if exist out\Default\hunspell_dictionaries.zip (appveyor-retry appveyor PushArtifact out\Default\hunspell_dictionaries.zip)
|
||||
- if exist out\Default\electron.lib (appveyor-retry appveyor PushArtifact out\Default\electron.lib)
|
||||
- if exist out\Default\electron.lib (appveyor-retry appveyor PushArtifact out\Default\electron.lib)
|
||||
- ps: >-
|
||||
if ((Test-Path "pdb.zip") -And ($env:GN_CONFIG -ne 'release')) {
|
||||
appveyor-retry appveyor PushArtifact pdb.zip
|
||||
@@ -240,6 +266,9 @@ for:
|
||||
}
|
||||
Invoke-RestMethod -Method Get -Uri "$apiUrl/buildjobs/$jobId/artifacts/$artifact_name" -OutFile $outfile
|
||||
}
|
||||
# Uncomment the following lines to download the pdb.zip to show real stacktraces when crashes happen during testing
|
||||
# Invoke-RestMethod -Method Get -Uri "$apiUrl/buildjobs/$jobId/artifacts/pdb.zip" -OutFile pdb.zip
|
||||
# 7z x -y -osrc pdb.zip
|
||||
}
|
||||
}
|
||||
- ps: |
|
||||
|
||||
@@ -223,10 +223,10 @@ expanding and collapsing the dialog.
|
||||
* `browserWindow` [BrowserWindow](browser-window.md) (optional)
|
||||
* `options` Object
|
||||
* `message` string - Content of the message box.
|
||||
* `type` string (optional) - Can be `"none"`, `"info"`, `"error"`, `"question"` or
|
||||
`"warning"`. On Windows, `"question"` displays the same icon as `"info"`, unless
|
||||
you set an icon using the `"icon"` option. On macOS, both `"warning"` and
|
||||
`"error"` display the same warning icon.
|
||||
* `type` string (optional) - Can be `none`, `info`, `error`, `question` or
|
||||
`warning`. On Windows, `question` displays the same icon as `info`, unless
|
||||
you set an icon using the `icon` option. On macOS, both `warning` and
|
||||
`error` display the same warning icon.
|
||||
* `buttons` string[] (optional) - Array of texts for buttons. On Windows, an empty array
|
||||
will result in one button labeled "OK".
|
||||
* `defaultId` Integer (optional) - Index of the button in the buttons array which will
|
||||
@@ -266,10 +266,10 @@ If `browserWindow` is not shown dialog will not be attached to it. In such case
|
||||
* `browserWindow` [BrowserWindow](browser-window.md) (optional)
|
||||
* `options` Object
|
||||
* `message` string - Content of the message box.
|
||||
* `type` string (optional) - Can be `"none"`, `"info"`, `"error"`, `"question"` or
|
||||
`"warning"`. On Windows, `"question"` displays the same icon as `"info"`, unless
|
||||
you set an icon using the `"icon"` option. On macOS, both `"warning"` and
|
||||
`"error"` display the same warning icon.
|
||||
* `type` string (optional) - Can be `none`, `info`, `error`, `question` or
|
||||
`warning`. On Windows, `question` displays the same icon as `info`, unless
|
||||
you set an icon using the `icon` option. On macOS, both `warning` and
|
||||
`error` display the same warning icon.
|
||||
* `buttons` string[] (optional) - Array of texts for buttons. On Windows, an empty array
|
||||
will result in one button labeled "OK".
|
||||
* `defaultId` Integer (optional) - Index of the button in the buttons array which will
|
||||
|
||||
@@ -6,7 +6,7 @@ Process: [Main](../glossary.md#main-process)
|
||||
|
||||
```javascript
|
||||
const { systemPreferences } = require('electron')
|
||||
console.log(systemPreferences.isDarkMode())
|
||||
console.log(systemPreferences.isAeroGlassEnabled())
|
||||
```
|
||||
|
||||
## Events
|
||||
@@ -47,12 +47,6 @@ Returns:
|
||||
|
||||
## Methods
|
||||
|
||||
### `systemPreferences.isDarkMode()` _macOS_ _Windows_ _Deprecated_
|
||||
|
||||
Returns `boolean` - Whether the system is in Dark Mode.
|
||||
|
||||
**Deprecated:** Should use the new [`nativeTheme.shouldUseDarkColors`](native-theme.md#nativethemeshouldusedarkcolors-readonly) API.
|
||||
|
||||
### `systemPreferences.isSwipeTrackingFromScrollEventsEnabled()` _macOS_
|
||||
|
||||
Returns `boolean` - Whether the Swipe between pages setting is on.
|
||||
@@ -356,18 +350,6 @@ Returns `string` - The standard system color formatted as `#RRGGBBAA`.
|
||||
|
||||
Returns one of several standard system colors that automatically adapt to vibrancy and changes in accessibility settings like 'Increase contrast' and 'Reduce transparency'. See [Apple Documentation](https://developer.apple.com/design/human-interface-guidelines/macos/visual-design/color#system-colors) for more details.
|
||||
|
||||
### `systemPreferences.isInvertedColorScheme()` _Windows_ _Deprecated_
|
||||
|
||||
Returns `boolean` - `true` if an inverted color scheme (a high contrast color scheme with light text and dark backgrounds) is active, `false` otherwise.
|
||||
|
||||
**Deprecated:** Should use the new [`nativeTheme.shouldUseInvertedColorScheme`](native-theme.md#nativethemeshoulduseinvertedcolorscheme-macos-windows-readonly) API.
|
||||
|
||||
### `systemPreferences.isHighContrastColorScheme()` _macOS_ _Windows_ _Deprecated_
|
||||
|
||||
Returns `boolean` - `true` if a high contrast theme is active, `false` otherwise.
|
||||
|
||||
**Deprecated:** Should use the new [`nativeTheme.shouldUseHighContrastColors`](native-theme.md#nativethemeshouldusehighcontrastcolors-macos-windows-readonly) API.
|
||||
|
||||
### `systemPreferences.getEffectiveAppearance()` _macOS_
|
||||
|
||||
Returns `string` - Can be `dark`, `light` or `unknown`.
|
||||
|
||||
@@ -184,6 +184,8 @@ page is loaded, use the `setUserAgent` method to change the user agent.
|
||||
A `boolean`. When this attribute is present the guest page will have web security disabled.
|
||||
Web security is enabled by default.
|
||||
|
||||
This value can only be modified before the first navigation.
|
||||
|
||||
### `partition`
|
||||
|
||||
```html
|
||||
|
||||
@@ -154,6 +154,39 @@ webContents.setWindowOpenHandler((details) => {
|
||||
})
|
||||
```
|
||||
|
||||
### Removed: `<webview>` `new-window` event
|
||||
|
||||
The `new-window` event of `<webview>` has been removed. There is no direct replacement.
|
||||
|
||||
```js
|
||||
// Removed in Electron 22
|
||||
webview.addEventListener('new-window', (event) => {})
|
||||
```
|
||||
|
||||
```javascript fiddle='docs/fiddles/ipc/webview-new-window'
|
||||
// Replace with
|
||||
|
||||
// main.js
|
||||
mainWindow.webContents.on('did-attach-webview', (event, wc) => {
|
||||
wc.setWindowOpenHandler((details) => {
|
||||
mainWindow.webContents.send('webview-new-window', wc.id, details)
|
||||
return { action: 'deny' }
|
||||
})
|
||||
})
|
||||
|
||||
// preload.js
|
||||
const { ipcRenderer } = require('electron')
|
||||
ipcRenderer.on('webview-new-window', (e, webContentsId, details) => {
|
||||
console.log('webview-new-window', webContentsId, details)
|
||||
document.getElementById('webview').dispatchEvent(new Event('new-window'))
|
||||
})
|
||||
|
||||
// renderer.js
|
||||
document.getElementById('webview').addEventListener('new-window', () => {
|
||||
console.log('got new-window event')
|
||||
})
|
||||
```
|
||||
|
||||
### Deprecated: BrowserWindow `scroll-touch-*` events
|
||||
|
||||
The `scroll-touch-begin`, `scroll-touch-end` and `scroll-touch-edge` events on
|
||||
|
||||
3
docs/fiddles/ipc/webview-new-window/child.html
Normal file
3
docs/fiddles/ipc/webview-new-window/child.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<body>
|
||||
<a href="child.html" target="_blank">new window</a>
|
||||
</body>
|
||||
4
docs/fiddles/ipc/webview-new-window/index.html
Normal file
4
docs/fiddles/ipc/webview-new-window/index.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<body>
|
||||
<webview id=webview src="child.html" allowpopups></webview>
|
||||
<script src="renderer.js"></script>
|
||||
</body>
|
||||
51
docs/fiddles/ipc/webview-new-window/main.js
Normal file
51
docs/fiddles/ipc/webview-new-window/main.js
Normal file
@@ -0,0 +1,51 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
const path = require('path')
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
const mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
preload: path.join(__dirname, 'preload.js'),
|
||||
webviewTag: true
|
||||
}
|
||||
})
|
||||
|
||||
mainWindow.webContents.on('did-attach-webview', (event, wc) => {
|
||||
wc.setWindowOpenHandler((details) => {
|
||||
mainWindow.webContents.send('webview-new-window', wc.id, details)
|
||||
return { action: 'deny' }
|
||||
})
|
||||
})
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
// Open the DevTools.
|
||||
// mainWindow.webContents.openDevTools()
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(() => {
|
||||
createWindow()
|
||||
|
||||
app.on('activate', function () {
|
||||
// On macOS it's common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
||||
})
|
||||
})
|
||||
|
||||
// Quit when all windows are closed, except on macOS. There, it's common
|
||||
// for applications and their menu bar to stay active until the user quits
|
||||
// explicitly with Cmd + Q.
|
||||
app.on('window-all-closed', function () {
|
||||
if (process.platform !== 'darwin') app.quit()
|
||||
})
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
// code. You can also put them in separate files and require them here.
|
||||
6
docs/fiddles/ipc/webview-new-window/preload.js
Normal file
6
docs/fiddles/ipc/webview-new-window/preload.js
Normal file
@@ -0,0 +1,6 @@
|
||||
const { ipcRenderer } = require('electron')
|
||||
const webview = document.getElementById('webview')
|
||||
ipcRenderer.on('webview-new-window', (e, webContentsId, details) => {
|
||||
console.log('webview-new-window', webContentsId, details)
|
||||
webview.dispatchEvent(new Event('new-window'))
|
||||
})
|
||||
4
docs/fiddles/ipc/webview-new-window/renderer.js
Normal file
4
docs/fiddles/ipc/webview-new-window/renderer.js
Normal file
@@ -0,0 +1,4 @@
|
||||
const webview = document.getElementById('webview')
|
||||
webview.addEventListener('new-window', () => {
|
||||
console.log('got new-window event')
|
||||
})
|
||||
@@ -1,3 +1,4 @@
|
||||
fix_rename_webswapcgllayer_to_webswapcgllayerchromium.patch
|
||||
cherry-pick-6da1a8953313.patch
|
||||
cherry-pick-aed05b609629.patch
|
||||
cherry-pick-d0ee0197ddff.patch
|
||||
|
||||
214
patches/angle/cherry-pick-d0ee0197ddff.patch
Normal file
214
patches/angle/cherry-pick-d0ee0197ddff.patch
Normal file
@@ -0,0 +1,214 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
Date: Wed, 3 May 2023 13:41:36 -0400
|
||||
Subject: WebGL: Limit total size of private data
|
||||
|
||||
... not just individual arrays.
|
||||
|
||||
Bug: chromium:1431761
|
||||
Change-Id: I721e29aeceeaf12c3f6a67b668abffb8dfbc89b0
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4503753
|
||||
Reviewed-by: Kenneth Russell <kbr@chromium.org>
|
||||
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
|
||||
|
||||
diff --git a/src/compiler/translator/ValidateTypeSizeLimitations.cpp b/src/compiler/translator/ValidateTypeSizeLimitations.cpp
|
||||
index c9607db74b53487950d31f6a56d55f3e834556a0..a05e857d7111528ad7f21799e3825b9d3f488dd3 100644
|
||||
--- a/src/compiler/translator/ValidateTypeSizeLimitations.cpp
|
||||
+++ b/src/compiler/translator/ValidateTypeSizeLimitations.cpp
|
||||
@@ -23,6 +23,7 @@ namespace
|
||||
// Arbitrarily enforce that types - even local variables' - declared
|
||||
// with a size in bytes of over 2 GB will cause compilation failure.
|
||||
constexpr size_t kMaxTypeSizeInBytes = static_cast<size_t>(2) * 1024 * 1024 * 1024;
|
||||
+constexpr size_t kMaxPrivateVariableSizeInBytes = static_cast<size_t>(1) * 1024 * 1024;
|
||||
|
||||
// Traverses intermediate tree to ensure that the shader does not
|
||||
// exceed certain implementation-defined limits on the sizes of types.
|
||||
@@ -31,7 +32,9 @@ class ValidateTypeSizeLimitationsTraverser : public TIntermTraverser
|
||||
{
|
||||
public:
|
||||
ValidateTypeSizeLimitationsTraverser(TSymbolTable *symbolTable, TDiagnostics *diagnostics)
|
||||
- : TIntermTraverser(true, false, false, symbolTable), mDiagnostics(diagnostics)
|
||||
+ : TIntermTraverser(true, false, false, symbolTable),
|
||||
+ mDiagnostics(diagnostics),
|
||||
+ mTotalPrivateVariablesSize(0)
|
||||
{
|
||||
ASSERT(diagnostics);
|
||||
}
|
||||
@@ -85,11 +88,37 @@ class ValidateTypeSizeLimitationsTraverser : public TIntermTraverser
|
||||
asSymbol->getName());
|
||||
return false;
|
||||
}
|
||||
+
|
||||
+ const bool isPrivate = variableType.getQualifier() == EvqTemporary ||
|
||||
+ variableType.getQualifier() == EvqGlobal ||
|
||||
+ variableType.getQualifier() == EvqConst;
|
||||
+ if (isPrivate)
|
||||
+ {
|
||||
+ if (layoutEncoder.getCurrentOffset() > kMaxPrivateVariableSizeInBytes)
|
||||
+ {
|
||||
+ error(asSymbol->getLine(),
|
||||
+ "Size of declared private variable exceeds implementation-defined limit",
|
||||
+ asSymbol->getName());
|
||||
+ return false;
|
||||
+ }
|
||||
+ mTotalPrivateVariablesSize += layoutEncoder.getCurrentOffset();
|
||||
+ }
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
+ void validateTotalPrivateVariableSize()
|
||||
+ {
|
||||
+ if (mTotalPrivateVariablesSize > kMaxPrivateVariableSizeInBytes)
|
||||
+ {
|
||||
+ mDiagnostics->error(
|
||||
+ TSourceLoc{},
|
||||
+ "Total size of declared private variables exceeds implementation-defined limit",
|
||||
+ "");
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
private:
|
||||
void error(TSourceLoc loc, const char *reason, const ImmutableString &token)
|
||||
{
|
||||
@@ -198,6 +227,8 @@ class ValidateTypeSizeLimitationsTraverser : public TIntermTraverser
|
||||
|
||||
TDiagnostics *mDiagnostics;
|
||||
std::vector<int> mLoopSymbolIds;
|
||||
+
|
||||
+ size_t mTotalPrivateVariablesSize;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -208,6 +239,7 @@ bool ValidateTypeSizeLimitations(TIntermNode *root,
|
||||
{
|
||||
ValidateTypeSizeLimitationsTraverser validate(symbolTable, diagnostics);
|
||||
root->traverse(&validate);
|
||||
+ validate.validateTotalPrivateVariableSize();
|
||||
return diagnostics->numErrors() == 0;
|
||||
}
|
||||
|
||||
diff --git a/src/tests/gl_tests/WebGLCompatibilityTest.cpp b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
|
||||
index 7dc56cddbc63add1aca6fca3bfd031f3da8d04fc..64287af5834607f6819f1197e2eed1a56f712ffe 100644
|
||||
--- a/src/tests/gl_tests/WebGLCompatibilityTest.cpp
|
||||
+++ b/src/tests/gl_tests/WebGLCompatibilityTest.cpp
|
||||
@@ -5271,11 +5271,12 @@ TEST_P(WebGLCompatibilityTest, ValidateArraySizes)
|
||||
// fairly small array.
|
||||
constexpr char kVSArrayOK[] =
|
||||
R"(varying vec4 color;
|
||||
-const int array_size = 1000;
|
||||
+const int array_size = 500;
|
||||
void main()
|
||||
{
|
||||
mat2 array[array_size];
|
||||
- if (array[0][0][0] == 2.0)
|
||||
+ mat2 array2[array_size];
|
||||
+ if (array[0][0][0] + array2[0][0][0] == 2.0)
|
||||
color = vec4(0.0, 1.0, 0.0, 1.0);
|
||||
else
|
||||
color = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
@@ -5353,6 +5354,103 @@ void main()
|
||||
EXPECT_EQ(0u, program);
|
||||
}
|
||||
|
||||
+// Reject attempts to allocate too much private memory.
|
||||
+// This is an implementation-defined limit - crbug.com/1431761.
|
||||
+TEST_P(WebGLCompatibilityTest, ValidateTotalPrivateSize)
|
||||
+{
|
||||
+ constexpr char kTooLargeGlobalMemory1[] =
|
||||
+ R"(precision mediump float;
|
||||
+
|
||||
+// 1 MB / 16 bytes per vec4 = 65536
|
||||
+vec4 array[32768];
|
||||
+vec4 array2[32769];
|
||||
+
|
||||
+void main()
|
||||
+{
|
||||
+ if (array[0].x + array[1].x == 0.)
|
||||
+ gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
||||
+ else
|
||||
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
+})";
|
||||
+
|
||||
+ constexpr char kTooLargeGlobalMemory2[] =
|
||||
+ R"(precision mediump float;
|
||||
+
|
||||
+// 1 MB / 16 bytes per vec4 = 65536
|
||||
+vec4 array[32767];
|
||||
+vec4 array2[32767];
|
||||
+vec4 x, y, z;
|
||||
+
|
||||
+void main()
|
||||
+{
|
||||
+ if (array[0].x + array[1].x == x.w + y.w + z.w)
|
||||
+ gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
|
||||
+ else
|
||||
+ gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
+})";
|
||||
+
|
||||
+ constexpr char kTooLargeGlobalAndLocalMemory1[] =
|
||||
+ R"(precision mediump float;
|
||||
+
|
||||
+// 1 MB / 16 bytes per vec4 = 65536
|
||||
+vec4 array[32768];
|
||||
+
|
||||
+void main()
|
||||
+{
|
||||
+ vec4 array2[32769];
|
||||
+ if (array[0].x + array[1].x == 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);
|
||||
+})";
|
||||
+
|
||||
+ // Note: The call stack is not taken into account for the purposes of total memory calculation.
|
||||
+ constexpr char kTooLargeGlobalAndLocalMemory2[] =
|
||||
+ R"(precision mediump float;
|
||||
+
|
||||
+// 1 MB / 16 bytes per vec4 = 65536
|
||||
+vec4 array[32768];
|
||||
+
|
||||
+float f()
|
||||
+{
|
||||
+ vec4 array2[16384];
|
||||
+ return array2[0].x;
|
||||
+}
|
||||
+
|
||||
+float g()
|
||||
+{
|
||||
+ vec4 array3[16383];
|
||||
+ return array3[0].x;
|
||||
+}
|
||||
+
|
||||
+float h()
|
||||
+{
|
||||
+ vec4 value;
|
||||
+ float value2
|
||||
+ return value.x + value2;
|
||||
+}
|
||||
+
|
||||
+void main()
|
||||
+{
|
||||
+ if (array[0].x + f() + g() + h() == 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);
|
||||
+
|
||||
+ program = CompileProgram(essl1_shaders::vs::Simple(), kTooLargeGlobalMemory2);
|
||||
+ EXPECT_EQ(0u, program);
|
||||
+
|
||||
+ program = CompileProgram(essl1_shaders::vs::Simple(), kTooLargeGlobalAndLocalMemory1);
|
||||
+ EXPECT_EQ(0u, program);
|
||||
+
|
||||
+ program = CompileProgram(essl1_shaders::vs::Simple(), kTooLargeGlobalAndLocalMemory2);
|
||||
+ EXPECT_EQ(0u, program);
|
||||
+}
|
||||
+
|
||||
// Linking should fail when corresponding vertex/fragment uniform blocks have different precision
|
||||
// qualifiers.
|
||||
TEST_P(WebGL2CompatibilityTest, UniformBlockPrecisionMismatch)
|
||||
@@ -140,3 +140,15 @@ merge_m112_remove_the_second_weakptrfactory_from.patch
|
||||
merge_m112_check_spdyproxyclientsocket_is_alive_after_write.patch
|
||||
check_callback_availability_in.patch
|
||||
m112_cherry_pick_libxml_cve_fix.patch
|
||||
m112_fix_scopedobservation_uaf_in.patch
|
||||
cherry-pick-48785f698b1c.patch
|
||||
cherry-pick-675562695049.patch
|
||||
cherry-pick-ea1cd76358e0.patch
|
||||
m114_merge_fix_a_crash_caused_by_calling_trace_event.patch
|
||||
mojoipcz_copy_incoming_messages_early.patch
|
||||
base_do_not_use_va_args_twice_in_asprintf.patch
|
||||
cherry-pick-85beff6fd302.patch
|
||||
m114_webcodecs_fix_crash_when_changing_temporal_layer_count_in_av1.patch
|
||||
cherry-pick-933b9fad3a53.patch
|
||||
cherry-pick-b03973561862.patch
|
||||
cherry-pick-c60a1ab717c7.patch
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benoit Lize <lizeb@chromium.org>
|
||||
Date: Fri, 9 Jun 2023 17:59:08 +0000
|
||||
Subject: Do not use va_args twice in asprintf()
|
||||
|
||||
(cherry picked from commit 3cff0cb19a6d01cbdd9932f43dabaaeda9c0330a)
|
||||
|
||||
Bug: 1450536
|
||||
Change-Id: Ib34d96935278869a63897f9a1c66afc98865d90f
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4579347
|
||||
Reviewed-by: Egor Pasko <pasko@chromium.org>
|
||||
Commit-Queue: Benoit Lize <lizeb@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1151796}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4604070
|
||||
Reviewed-by: Michael Thiessen <mthiesse@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/5735@{#1224}
|
||||
Cr-Branched-From: 2f562e4ddbaf79a3f3cb338b4d1bd4398d49eb67-refs/heads/main@{#1135570}
|
||||
|
||||
diff --git a/base/allocator/partition_allocator/shim/allocator_shim_override_linker_wrapped_symbols.h b/base/allocator/partition_allocator/shim/allocator_shim_override_linker_wrapped_symbols.h
|
||||
index 621873126602463a09efca1bf1548ed10910d323..de2af6d7d54e254b9e7b8264b53d30a338fb13e8 100644
|
||||
--- a/base/allocator/partition_allocator/shim/allocator_shim_override_linker_wrapped_symbols.h
|
||||
+++ b/base/allocator/partition_allocator/shim/allocator_shim_override_linker_wrapped_symbols.h
|
||||
@@ -123,13 +123,21 @@ SHIM_ALWAYS_EXPORT char* __wrap_getcwd(char* buffer, size_t size) {
|
||||
SHIM_ALWAYS_EXPORT int __wrap_vasprintf(char** strp,
|
||||
const char* fmt,
|
||||
va_list va_args) {
|
||||
+ // There are cases where we need to use the list of arguments twice, namely
|
||||
+ // when the original buffer is too small. It is not allowed to walk the list
|
||||
+ // twice, so make a copy for the second invocation of vsnprintf().
|
||||
+ va_list va_args_copy;
|
||||
+ va_copy(va_args_copy, va_args);
|
||||
+
|
||||
constexpr int kInitialSize = 128;
|
||||
*strp = static_cast<char*>(
|
||||
malloc(kInitialSize)); // Our malloc() doesn't return nullptr.
|
||||
|
||||
int actual_size = vsnprintf(*strp, kInitialSize, fmt, va_args);
|
||||
- if (actual_size < 0)
|
||||
+ if (actual_size < 0) {
|
||||
+ va_end(va_args_copy);
|
||||
return actual_size;
|
||||
+ }
|
||||
*strp =
|
||||
static_cast<char*>(realloc(*strp, static_cast<size_t>(actual_size + 1)));
|
||||
|
||||
@@ -139,9 +147,14 @@ SHIM_ALWAYS_EXPORT int __wrap_vasprintf(char** strp,
|
||||
//
|
||||
// This is very lightly used in Chromium in practice, see crbug.com/116558 for
|
||||
// details.
|
||||
- if (actual_size >= kInitialSize)
|
||||
- return vsnprintf(*strp, static_cast<size_t>(actual_size + 1), fmt, va_args);
|
||||
-
|
||||
+ if (actual_size >= kInitialSize) {
|
||||
+ int ret = vsnprintf(*strp, static_cast<size_t>(actual_size + 1), fmt,
|
||||
+ va_args_copy);
|
||||
+ va_end(va_args_copy);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ va_end(va_args_copy);
|
||||
return actual_size;
|
||||
}
|
||||
|
||||
diff --git a/base/allocator/partition_allocator/shim/allocator_shim_unittest.cc b/base/allocator/partition_allocator/shim/allocator_shim_unittest.cc
|
||||
index 59b4a2c915caa192346f3fa342c5a2852a2f7b9b..1f3d5956b198ddf89cdf6951739ef68a29a74936 100644
|
||||
--- a/base/allocator/partition_allocator/shim/allocator_shim_unittest.cc
|
||||
+++ b/base/allocator/partition_allocator/shim/allocator_shim_unittest.cc
|
||||
@@ -726,6 +726,28 @@ TEST_F(AllocatorShimTest, InterceptVasprintf) {
|
||||
// Should not crash.
|
||||
}
|
||||
|
||||
+TEST_F(AllocatorShimTest, InterceptLongVasprintf) {
|
||||
+ char* str = nullptr;
|
||||
+ const char* lorem_ipsum =
|
||||
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. "
|
||||
+ "Suspendisse lectus tortor, dignissim sit amet, adipiscing nec, "
|
||||
+ "ultricies sed, dolor. Cras elementum ultrices diam. Maecenas ligula "
|
||||
+ "massa, varius a, semper congue, euismod non, mi. Proin porttitor, orci "
|
||||
+ "nec nonummy molestie, enim est eleifend mi, non fermentum diam nisl sit "
|
||||
+ "amet erat. Duis semper. Duis arcu massa, scelerisque vitae, consequat "
|
||||
+ "in, pretium a, enim. Pellentesque congue. Ut in risus volutpat libero "
|
||||
+ "pharetra tempor. Cras vestibulum bibendum augue. Praesent egestas leo "
|
||||
+ "in pede. Praesent blandit odio eu enim. Pellentesque sed dui ut augue "
|
||||
+ "blandit sodales. Vestibulum ante ipsum primis in faucibus orci luctus "
|
||||
+ "et ultrices posuere cubilia Curae; Aliquam nibh. Mauris ac mauris sed "
|
||||
+ "pede pellentesque fermentum. Maecenas adipiscing ante non diam sodales "
|
||||
+ "hendrerit.";
|
||||
+ int err = asprintf(&str, "%s", lorem_ipsum);
|
||||
+ EXPECT_EQ(err, static_cast<int>(strlen(lorem_ipsum)));
|
||||
+ EXPECT_TRUE(str);
|
||||
+ free(str);
|
||||
+}
|
||||
+
|
||||
#endif // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
|
||||
|
||||
#endif // BUILDFLAG(IS_ANDROID)
|
||||
107
patches/chromium/cherry-pick-48785f698b1c.patch
Normal file
107
patches/chromium/cherry-pick-48785f698b1c.patch
Normal file
@@ -0,0 +1,107 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Arthur Sonzogni <arthursonzogni@chromium.org>
|
||||
Date: Tue, 2 May 2023 09:40:37 +0000
|
||||
Subject: Avoid buffer overflow read in HFSReadNextNonIgnorableCodePoint
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Unicode codepoints goes beyond 0xFFFF.
|
||||
|
||||
It exists upper and lower case characters there: `𞤡 `vs `𞥃`.
|
||||
|
||||
The buffer overflow occurred when using the lookup table:
|
||||
```
|
||||
lower_case_table[codepoint >> 8]
|
||||
```
|
||||
|
||||
Bug: 1425115
|
||||
Fixed: 1425115
|
||||
Change-Id: I679da02dbe570283a68176fbd3c0c620caa4f9ce
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4481260
|
||||
Reviewed-by: Alexander Timin <altimin@chromium.org>
|
||||
Commit-Queue: Arthur Sonzogni <arthursonzogni@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#1138234}
|
||||
|
||||
diff --git a/base/files/file_path.cc b/base/files/file_path.cc
|
||||
index a43c09317da96332584286fdb67284b2bedd753f..3a7cca6fad051816d6d018857c8039594c51ec65 100644
|
||||
--- a/base/files/file_path.cc
|
||||
+++ b/base/files/file_path.cc
|
||||
@@ -775,7 +775,7 @@ int FilePath::CompareIgnoreCase(StringPieceType string1,
|
||||
#elif BUILDFLAG(IS_APPLE)
|
||||
// Mac OS X specific implementation of file string comparisons.
|
||||
|
||||
-// cf. http://developer.apple.com/mac/library/technotes/tn/tn1150.html#UnicodeSubtleties
|
||||
+// cf. https://developer.apple.com/library/archive/technotes/tn/tn1150.html#UnicodeSubtleties
|
||||
//
|
||||
// "When using CreateTextEncoding to create a text encoding, you should set
|
||||
// the TextEncodingBase to kTextEncodingUnicodeV2_0, set the
|
||||
@@ -801,11 +801,12 @@ int FilePath::CompareIgnoreCase(StringPieceType string1,
|
||||
// Ignored characters are mapped to zero.
|
||||
//
|
||||
// cf. downloadable file linked in
|
||||
-// http://developer.apple.com/mac/library/technotes/tn/tn1150.html#StringComparisonAlgorithm
|
||||
+// https://developer.apple.com/library/archive/technotes/tn/tn1150.html#Downloads
|
||||
|
||||
namespace {
|
||||
|
||||
-const UInt16 lower_case_table[] = {
|
||||
+// clang-format off
|
||||
+const UInt16 lower_case_table[11 * 256] = {
|
||||
// High-byte indices ( == 0 iff no case mapping and no ignorables )
|
||||
|
||||
/* 0 */ 0x0100, 0x0200, 0x0000, 0x0300, 0x0400, 0x0500, 0x0000, 0x0000,
|
||||
@@ -1191,11 +1192,12 @@ const UInt16 lower_case_table[] = {
|
||||
/* F */ 0xFFF0, 0xFFF1, 0xFFF2, 0xFFF3, 0xFFF4, 0xFFF5, 0xFFF6, 0xFFF7,
|
||||
0xFFF8, 0xFFF9, 0xFFFA, 0xFFFB, 0xFFFC, 0xFFFD, 0xFFFE, 0xFFFF,
|
||||
};
|
||||
+// clang-format on
|
||||
|
||||
-// Returns the next non-ignorable codepoint within string starting from the
|
||||
-// position indicated by index, or zero if there are no more.
|
||||
-// The passed-in index is automatically advanced as the characters in the input
|
||||
-// HFS-decomposed UTF-8 strings are read.
|
||||
+// Returns the next non-ignorable codepoint within `string` starting from the
|
||||
+// position indicated by `index`, or zero if there are no more.
|
||||
+// The passed-in `index` is automatically advanced as the characters in the
|
||||
+// input HFS-decomposed UTF-8 strings are read.
|
||||
inline base_icu::UChar32 HFSReadNextNonIgnorableCodepoint(const char* string,
|
||||
size_t length,
|
||||
size_t* index) {
|
||||
@@ -1206,12 +1208,16 @@ inline base_icu::UChar32 HFSReadNextNonIgnorableCodepoint(const char* string,
|
||||
CBU8_NEXT(reinterpret_cast<const uint8_t*>(string), *index, length,
|
||||
codepoint);
|
||||
DCHECK_GT(codepoint, 0);
|
||||
- if (codepoint > 0) {
|
||||
+
|
||||
+ // Note: Here, there are no lower case conversion implemented in the
|
||||
+ // Supplementary Multilingual Plane (codepoint > 0xFFFF).
|
||||
+
|
||||
+ if (codepoint > 0 && codepoint <= 0xFFFF) {
|
||||
// Check if there is a subtable for this upper byte.
|
||||
int lookup_offset = lower_case_table[codepoint >> 8];
|
||||
if (lookup_offset != 0)
|
||||
codepoint = lower_case_table[lookup_offset + (codepoint & 0x00FF)];
|
||||
- // Note: codepoint1 may be again 0 at this point if the character was
|
||||
+ // Note: `codepoint` may be again 0 at this point if the character was
|
||||
// an ignorable.
|
||||
}
|
||||
}
|
||||
diff --git a/base/files/file_path_unittest.cc b/base/files/file_path_unittest.cc
|
||||
index 3cfdcbe445c1f6e0d66e3798927131f94759fb3c..08c3e75b7e1ad55f5f81aed80f80081115f8f49c 100644
|
||||
--- a/base/files/file_path_unittest.cc
|
||||
+++ b/base/files/file_path_unittest.cc
|
||||
@@ -1195,6 +1195,13 @@ TEST_F(FilePathTest, CompareIgnoreCase) {
|
||||
{{FPL("K\u0301U\u032DO\u0304\u0301N"), FPL("\u1E31\u1E77\u1E53n")}, 0},
|
||||
{{FPL("k\u0301u\u032Do\u0304\u0301n"), FPL("\u1E30\u1E76\u1E52n")}, 0},
|
||||
{{FPL("k\u0301u\u032Do\u0304\u0302n"), FPL("\u1E30\u1E76\u1E52n")}, 1},
|
||||
+
|
||||
+ // Codepoints > 0xFFFF
|
||||
+ // Here, we compare the `Adlam Letter Shu` in its capital and small version.
|
||||
+ {{FPL("\U0001E921"), FPL("\U0001E943")}, -1},
|
||||
+ {{FPL("\U0001E943"), FPL("\U0001E921")}, 1},
|
||||
+ {{FPL("\U0001E921"), FPL("\U0001E921")}, 0},
|
||||
+ {{FPL("\U0001E943"), FPL("\U0001E943")}, 0},
|
||||
#endif
|
||||
};
|
||||
|
||||
142
patches/chromium/cherry-pick-675562695049.patch
Normal file
142
patches/chromium/cherry-pick-675562695049.patch
Normal file
@@ -0,0 +1,142 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Rakina Zata Amni <rakina@chromium.org>
|
||||
Date: Mon, 15 May 2023 03:21:49 +0000
|
||||
Subject: Return after ReadyCommitNavigation call in CommitErrorPage if it
|
||||
deletes NavigationRequest
|
||||
|
||||
NavigationRequest::ReadyToCommitNavigation() can cause deletion of the
|
||||
NavigationRequest, so callers should check for that possibility after
|
||||
calling the function. A caller in CommitErrorPage is missing that
|
||||
check, which this CL adds, along with a regression test.
|
||||
|
||||
(cherry picked from commit 42db806805ef2be64ee92803d3a784631b2a7df0)
|
||||
|
||||
Bug: 1444360
|
||||
Change-Id: I3964da4909a6709b7730d25d6497b19c098f4f21
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4520493
|
||||
Commit-Queue: Charlie Reis <creis@chromium.org>
|
||||
Reviewed-by: Charlie Reis <creis@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1143298}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4531446
|
||||
Reviewed-by: Prudhvikumar Bommana <pbommana@google.com>
|
||||
Commit-Queue: Rakina Zata Amni <rakina@chromium.org>
|
||||
Commit-Queue: Prudhvikumar Bommana <pbommana@google.com>
|
||||
Owners-Override: Prudhvikumar Bommana <pbommana@google.com>
|
||||
Cr-Commit-Position: refs/branch-heads/5735@{#607}
|
||||
Cr-Branched-From: 2f562e4ddbaf79a3f3cb338b4d1bd4398d49eb67-refs/heads/main@{#1135570}
|
||||
|
||||
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
|
||||
index fd95d91a9a4efbfbbcfb117d9f2129b1b1c95011..c3f1bb989c30bf00750404995d080c3b8ee0e1c6 100644
|
||||
--- a/content/browser/renderer_host/navigation_request.cc
|
||||
+++ b/content/browser/renderer_host/navigation_request.cc
|
||||
@@ -5034,7 +5034,13 @@ void NavigationRequest::CommitErrorPage(
|
||||
}
|
||||
}
|
||||
|
||||
+ base::WeakPtr<NavigationRequest> weak_self(weak_factory_.GetWeakPtr());
|
||||
ReadyToCommitNavigation(true /* is_error */);
|
||||
+ // The caller above might result in the deletion of `this`. Return immediately
|
||||
+ // if so.
|
||||
+ if (!weak_self) {
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
PopulateDocumentTokenForCrossDocumentNavigation();
|
||||
// Use a separate cache shard, and no cookies, for error pages.
|
||||
diff --git a/content/browser/renderer_host/navigation_request_browsertest.cc b/content/browser/renderer_host/navigation_request_browsertest.cc
|
||||
index 1213eb485a25a183ca23643941ae97ee6cfb596f..837af410e31d90769cb7e5d0f9c0bb9abf3035df 100644
|
||||
--- a/content/browser/renderer_host/navigation_request_browsertest.cc
|
||||
+++ b/content/browser/renderer_host/navigation_request_browsertest.cc
|
||||
@@ -44,6 +44,7 @@
|
||||
#include "content/public/test/prerender_test_util.h"
|
||||
#include "content/public/test/test_frame_navigation_observer.h"
|
||||
#include "content/public/test/test_navigation_observer.h"
|
||||
+#include "content/public/test/test_service.mojom.h"
|
||||
#include "content/public/test/test_utils.h"
|
||||
#include "content/public/test/url_loader_interceptor.h"
|
||||
#include "content/shell/browser/shell.h"
|
||||
@@ -4032,4 +4033,84 @@ IN_PROC_BROWSER_TEST_P(NavigationRequestMPArchBrowserTest,
|
||||
}
|
||||
}
|
||||
|
||||
+// Tests that when trying to commit an error page for a failed navigation, but
|
||||
+// the renderer process of the, the navigation won't commit and won't crash.
|
||||
+// Regression test for https://crbug.com/1444360.
|
||||
+IN_PROC_BROWSER_TEST_F(NavigationRequestBrowserTest,
|
||||
+ RendererCrashedBeforeCommitErrorPage) {
|
||||
+ // Navigate to `url_a` first.
|
||||
+ GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html"));
|
||||
+ ASSERT_TRUE(NavigateToURL(shell(), url_a));
|
||||
+
|
||||
+ // Set up an URLLoaderInterceptor which will cause future navigations to fail.
|
||||
+ auto url_loader_interceptor = std::make_unique<URLLoaderInterceptor>(
|
||||
+ base::BindRepeating([](URLLoaderInterceptor::RequestParams* params) {
|
||||
+ network::URLLoaderCompletionStatus status;
|
||||
+ status.error_code = net::ERR_NOT_IMPLEMENTED;
|
||||
+ params->client->OnComplete(status);
|
||||
+ return true;
|
||||
+ }));
|
||||
+
|
||||
+ // Do a navigation to `url_b1` that will fail and commit an error page. This
|
||||
+ // is important so that the next error page navigation won't need to create a
|
||||
+ // speculative RenderFrameHost (unless RenderDocument is enabled) and won't
|
||||
+ // get cancelled earlier than commit time due to speculative RFH deletion.
|
||||
+ GURL url_b1(embedded_test_server()->GetURL("b.com", "/title1.html"));
|
||||
+ EXPECT_FALSE(NavigateToURL(shell(), url_b1));
|
||||
+ EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), url_b1);
|
||||
+ EXPECT_TRUE(
|
||||
+ shell()->web_contents()->GetPrimaryMainFrame()->IsErrorDocument());
|
||||
+
|
||||
+ // For the next navigation, set up a throttle that will be used to wait for
|
||||
+ // WillFailRequest() and then defer the navigation, so that we can crash the
|
||||
+ // error page process first.
|
||||
+ TestNavigationThrottleInstaller installer(
|
||||
+ shell()->web_contents(),
|
||||
+ NavigationThrottle::PROCEED /* will_start_result */,
|
||||
+ NavigationThrottle::PROCEED /* will_redirect_result */,
|
||||
+ NavigationThrottle::DEFER /* will_fail_result */,
|
||||
+ NavigationThrottle::PROCEED /* will_process_result */,
|
||||
+ NavigationThrottle::PROCEED /* will_commit_without_url_loader_result */);
|
||||
+
|
||||
+ // Start a navigation to `url_b2` that will also fail, but before it commits
|
||||
+ // an error page, cause the error page process to crash.
|
||||
+ GURL url_b2(embedded_test_server()->GetURL("b.com", "/title2.html"));
|
||||
+ TestNavigationManager manager(shell()->web_contents(), url_b2);
|
||||
+ shell()->LoadURL(url_b2);
|
||||
+ EXPECT_TRUE(manager.WaitForRequestStart());
|
||||
+
|
||||
+ // Resume the navigation and wait for WillFailRequest(). After this point, we
|
||||
+ // will have picked the final RenderFrameHost & RenderProcessHost for the
|
||||
+ // failed navigation.
|
||||
+ manager.ResumeNavigation();
|
||||
+ installer.WaitForThrottleWillFail();
|
||||
+
|
||||
+ // Kill the error page process. This will cause for the navigation to `url_b2`
|
||||
+ // to return early in `NavigationRequest::ReadyToCommitNavigation()` and not
|
||||
+ // commit a new error page.
|
||||
+ RenderProcessHost* process_to_kill =
|
||||
+ manager.GetNavigationHandle()->GetRenderFrameHost()->GetProcess();
|
||||
+ ASSERT_TRUE(process_to_kill->IsInitializedAndNotDead());
|
||||
+ {
|
||||
+ // Trigger a renderer kill by calling DoSomething() which will cause a bad
|
||||
+ // message to be reported.
|
||||
+ RenderProcessHostBadIpcMessageWaiter kill_waiter(process_to_kill);
|
||||
+ mojo::Remote<mojom::TestService> service;
|
||||
+ process_to_kill->BindReceiver(service.BindNewPipeAndPassReceiver());
|
||||
+ service->DoSomething(base::DoNothing());
|
||||
+ EXPECT_EQ(bad_message::RPH_MOJO_PROCESS_ERROR, kill_waiter.Wait());
|
||||
+ }
|
||||
+ ASSERT_FALSE(process_to_kill->IsInitializedAndNotDead());
|
||||
+
|
||||
+ // Resume the navigation, which won't commit.
|
||||
+ if (!ShouldCreateNewHostForAllFrames()) {
|
||||
+ installer.navigation_throttle()->ResumeNavigation();
|
||||
+ }
|
||||
+ EXPECT_TRUE(manager.WaitForNavigationFinished());
|
||||
+ EXPECT_FALSE(WaitForLoadStop(shell()->web_contents()));
|
||||
+
|
||||
+ // The tab stayed at `url_b1` as the `url_b2` navigation didn't commit.
|
||||
+ EXPECT_EQ(shell()->web_contents()->GetLastCommittedURL(), url_b1);
|
||||
+}
|
||||
+
|
||||
} // namespace content
|
||||
215
patches/chromium/cherry-pick-85beff6fd302.patch
Normal file
215
patches/chromium/cherry-pick-85beff6fd302.patch
Normal file
@@ -0,0 +1,215 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Kevin McNee <mcnee@chromium.org>
|
||||
Date: Wed, 14 Jun 2023 01:10:19 +0000
|
||||
Subject: M114: Don't recursively destroy guests when clearing unattached
|
||||
guests
|
||||
|
||||
Don't recursively destroy guests when clearing unattached guests
|
||||
|
||||
When an embedder process is destroyed, we also destroy any unattached
|
||||
guests associated with that process. This is currently done with a
|
||||
single call to `owned_guests_.erase`. However, it's possible that two
|
||||
unattached guests could have an opener relationship, which causes the
|
||||
destruction of the opener guest to also destroy the other guest, during
|
||||
the call to `erase`, which is unsafe.
|
||||
|
||||
We now separate the steps of erasing `owned_guests_` and destroying the
|
||||
guests, to avoid this recursive guest destruction.
|
||||
|
||||
This also fixes the WaitForNumGuestsCreated test method to not
|
||||
return prematurely.
|
||||
|
||||
(cherry picked from commit 6345e7871e8197af92f9c6158b06c6e197f87945)
|
||||
|
||||
Bug: 1450397
|
||||
Change-Id: Ifef5ec9ff3a1e6952ff56ec279e29e8522625ac0
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4589949
|
||||
Commit-Queue: Kevin McNee <mcnee@chromium.org>
|
||||
Auto-Submit: Kevin McNee <mcnee@chromium.org>
|
||||
Reviewed-by: James Maclean <wjmaclean@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1153396}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4611152
|
||||
Commit-Queue: James Maclean <wjmaclean@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/5735@{#1292}
|
||||
Cr-Branched-From: 2f562e4ddbaf79a3f3cb338b4d1bd4398d49eb67-refs/heads/main@{#1135570}
|
||||
|
||||
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
|
||||
index 3748f8119bf1d4f37635bdb4fb87d825881de7f0..00f0bcb19ae291e5389284f98ee922562f116496 100644
|
||||
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
|
||||
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
|
||||
@@ -2779,6 +2779,22 @@ IN_PROC_BROWSER_TEST_P(WebViewNewWindowTest,
|
||||
EXPECT_TRUE(content::NavigateToURLFromRenderer(guest2, coop_url));
|
||||
}
|
||||
|
||||
+// This test creates a situation where we have two unattached webviews which
|
||||
+// have an opener relationship, and ensures that we can shutdown safely. See
|
||||
+// https://crbug.com/1450397.
|
||||
+IN_PROC_BROWSER_TEST_P(WebViewNewWindowTest, DestroyOpenerBeforeAttachment) {
|
||||
+ TestHelper("testDestroyOpenerBeforeAttachment", "web_view/newwindow",
|
||||
+ NEEDS_TEST_SERVER);
|
||||
+ GetGuestViewManager()->WaitForNumGuestsCreated(2);
|
||||
+
|
||||
+ content::RenderProcessHost* embedder_rph =
|
||||
+ GetEmbedderWebContents()->GetPrimaryMainFrame()->GetProcess();
|
||||
+ content::RenderProcessHostWatcher kill_observer(
|
||||
+ embedder_rph, content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
|
||||
+ EXPECT_TRUE(embedder_rph->Shutdown(content::RESULT_CODE_KILLED));
|
||||
+ kill_observer.Wait();
|
||||
+}
|
||||
+
|
||||
IN_PROC_BROWSER_TEST_P(WebViewTest, ContextMenuInspectElement) {
|
||||
LoadAppWithGuest("web_view/context_menus/basic");
|
||||
content::RenderFrameHost* guest_rfh = GetGuestRenderFrameHost();
|
||||
diff --git a/chrome/test/data/extensions/platform_apps/web_view/newwindow/embedder.js b/chrome/test/data/extensions/platform_apps/web_view/newwindow/embedder.js
|
||||
index 900911f4963d23d74225868dce01326ba533f63a..4dd25d8849b0b13957ab7fa2912c0a158d3cd244 100644
|
||||
--- a/chrome/test/data/extensions/platform_apps/web_view/newwindow/embedder.js
|
||||
+++ b/chrome/test/data/extensions/platform_apps/web_view/newwindow/embedder.js
|
||||
@@ -34,6 +34,9 @@ embedder.setUp_ = function(config) {
|
||||
embedder.guestWithLinkURL = embedder.baseGuestURL +
|
||||
'/extensions/platform_apps/web_view/newwindow' +
|
||||
'/guest_with_link.html';
|
||||
+ embedder.guestOpenOnLoadURL = embedder.baseGuestURL +
|
||||
+ '/extensions/platform_apps/web_view/newwindow' +
|
||||
+ '/guest_opener_open_on_load.html';
|
||||
};
|
||||
|
||||
/** @private */
|
||||
@@ -652,6 +655,24 @@ function testNewWindowDeferredAttachmentIndefinitely() {
|
||||
embedder.setUpNewWindowRequest_(webview, 'guest.html', '', testName);
|
||||
}
|
||||
|
||||
+// This is not a test in and of itself, but a means of creating a webview that
|
||||
+// is left in an unattached state while its opener webview is also in an
|
||||
+// unattached state, so that the C++ side can test it in that state.
|
||||
+function testDestroyOpenerBeforeAttachment() {
|
||||
+ embedder.test.succeed();
|
||||
+
|
||||
+ let webview = new WebView();
|
||||
+ webview.src = embedder.guestOpenOnLoadURL;
|
||||
+ document.body.appendChild(webview);
|
||||
+
|
||||
+ // By spinning forever here, we prevent `webview` from completing the
|
||||
+ // attachment process. But since the guest is still created and it calls
|
||||
+ // window.open, we have a situation where two unattached webviews have an
|
||||
+ // opener relationship. The C++ side will test that we can shutdown safely in
|
||||
+ // this case.
|
||||
+ while (true) {}
|
||||
+}
|
||||
+
|
||||
embedder.test.testList = {
|
||||
'testNewWindowAttachAfterOpenerDestroyed':
|
||||
testNewWindowAttachAfterOpenerDestroyed,
|
||||
@@ -675,7 +696,9 @@ embedder.test.testList = {
|
||||
testNewWindowWebViewNameTakesPrecedence,
|
||||
'testNewWindowAndUpdateOpener': testNewWindowAndUpdateOpener,
|
||||
'testNewWindowDeferredAttachmentIndefinitely':
|
||||
- testNewWindowDeferredAttachmentIndefinitely
|
||||
+ testNewWindowDeferredAttachmentIndefinitely,
|
||||
+ 'testDestroyOpenerBeforeAttachment':
|
||||
+ testDestroyOpenerBeforeAttachment
|
||||
};
|
||||
|
||||
onload = function() {
|
||||
diff --git a/chrome/test/data/extensions/platform_apps/web_view/newwindow/guest_opener_open_on_load.html b/chrome/test/data/extensions/platform_apps/web_view/newwindow/guest_opener_open_on_load.html
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..e961feb3c6487066801adf414bf4a2746c50a3f6
|
||||
--- /dev/null
|
||||
+++ b/chrome/test/data/extensions/platform_apps/web_view/newwindow/guest_opener_open_on_load.html
|
||||
@@ -0,0 +1,13 @@
|
||||
+<!--
|
||||
+Copyright 2023 The Chromium Authors
|
||||
+Use of this source code is governed by a BSD-style license that can be
|
||||
+found in the LICENSE file.
|
||||
+-->
|
||||
+<html>
|
||||
+<body>
|
||||
+<script>
|
||||
+ // A guest that opens a new window on load.
|
||||
+ window.open('guest.html');
|
||||
+</script>
|
||||
+</body>
|
||||
+</html>
|
||||
diff --git a/components/guest_view/browser/guest_view_manager.cc b/components/guest_view/browser/guest_view_manager.cc
|
||||
index 94867bbd2ea58908b52474c3923354852c070aed..24199000741b29bcbe25a695090b2de3be894af2 100644
|
||||
--- a/components/guest_view/browser/guest_view_manager.cc
|
||||
+++ b/components/guest_view/browser/guest_view_manager.cc
|
||||
@@ -324,7 +324,20 @@ void GuestViewManager::RemoveGuest(int guest_instance_id) {
|
||||
|
||||
void GuestViewManager::EmbedderProcessDestroyed(int embedder_process_id) {
|
||||
embedders_observed_.erase(embedder_process_id);
|
||||
+
|
||||
+ // We can't just call std::multimap::erase here because destroying a guest
|
||||
+ // could trigger the destruction of another guest which is also owned by
|
||||
+ // `owned_guests_`. Recursively calling std::multimap::erase is unsafe (see
|
||||
+ // https://crbug.com/1450397). So we take ownership of all of the guests that
|
||||
+ // will be destroyed before erasing the entries from the map.
|
||||
+ std::vector<std::unique_ptr<GuestViewBase>> guests_to_destroy;
|
||||
+ const auto destroy_range = owned_guests_.equal_range(embedder_process_id);
|
||||
+ for (auto it = destroy_range.first; it != destroy_range.second; ++it) {
|
||||
+ guests_to_destroy.push_back(std::move(it->second));
|
||||
+ }
|
||||
owned_guests_.erase(embedder_process_id);
|
||||
+ guests_to_destroy.clear();
|
||||
+
|
||||
CallViewDestructionCallbacks(embedder_process_id);
|
||||
}
|
||||
|
||||
diff --git a/components/guest_view/browser/test_guest_view_manager.cc b/components/guest_view/browser/test_guest_view_manager.cc
|
||||
index b1835691dfd8e7699575c26d4cb38b2247f9c9bc..69f4161746f756fdc022a20c23f44f593c09a6d6 100644
|
||||
--- a/components/guest_view/browser/test_guest_view_manager.cc
|
||||
+++ b/components/guest_view/browser/test_guest_view_manager.cc
|
||||
@@ -36,7 +36,6 @@ TestGuestViewManager::TestGuestViewManager(
|
||||
num_guests_created_(0),
|
||||
expected_num_guests_created_(0),
|
||||
num_views_garbage_collected_(0),
|
||||
- waiting_for_guests_created_(false),
|
||||
waiting_for_attach_(nullptr) {}
|
||||
|
||||
TestGuestViewManager::~TestGuestViewManager() = default;
|
||||
@@ -127,14 +126,15 @@ GuestViewBase* TestGuestViewManager::WaitForNextGuestViewCreated() {
|
||||
}
|
||||
|
||||
void TestGuestViewManager::WaitForNumGuestsCreated(size_t count) {
|
||||
- if (count == num_guests_created_)
|
||||
+ if (count == num_guests_created_) {
|
||||
return;
|
||||
+ }
|
||||
|
||||
- waiting_for_guests_created_ = true;
|
||||
expected_num_guests_created_ = count;
|
||||
|
||||
num_created_run_loop_ = std::make_unique<base::RunLoop>();
|
||||
num_created_run_loop_->Run();
|
||||
+ num_created_run_loop_ = nullptr;
|
||||
}
|
||||
|
||||
void TestGuestViewManager::WaitUntilAttached(GuestViewBase* guest_view) {
|
||||
@@ -179,13 +179,11 @@ void TestGuestViewManager::AddGuest(int guest_instance_id,
|
||||
created_run_loop_->Quit();
|
||||
|
||||
++num_guests_created_;
|
||||
- if (!waiting_for_guests_created_ &&
|
||||
- num_guests_created_ != expected_num_guests_created_) {
|
||||
- return;
|
||||
- }
|
||||
|
||||
- if (num_created_run_loop_)
|
||||
+ if (num_created_run_loop_ &&
|
||||
+ num_guests_created_ == expected_num_guests_created_) {
|
||||
num_created_run_loop_->Quit();
|
||||
+ }
|
||||
}
|
||||
|
||||
void TestGuestViewManager::AttachGuest(int embedder_process_id,
|
||||
diff --git a/components/guest_view/browser/test_guest_view_manager.h b/components/guest_view/browser/test_guest_view_manager.h
|
||||
index dfb9f9001ed3324b507f5478391ad3640ebeeae9..f12db0cf32ef03c1e4dacc68b782e01e698cbcdb 100644
|
||||
--- a/components/guest_view/browser/test_guest_view_manager.h
|
||||
+++ b/components/guest_view/browser/test_guest_view_manager.h
|
||||
@@ -119,7 +119,6 @@ class TestGuestViewManager : public GuestViewManager {
|
||||
size_t num_guests_created_;
|
||||
size_t expected_num_guests_created_;
|
||||
int num_views_garbage_collected_;
|
||||
- bool waiting_for_guests_created_;
|
||||
|
||||
// Tracks the life time of the GuestView's main FrameTreeNode. The main FTN
|
||||
// has the same lifesspan as the GuestView.
|
||||
404
patches/chromium/cherry-pick-933b9fad3a53.patch
Normal file
404
patches/chromium/cherry-pick-933b9fad3a53.patch
Normal file
@@ -0,0 +1,404 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Ken Rockot <rockot@google.com>
|
||||
Date: Fri, 9 Jun 2023 07:49:02 +0000
|
||||
Subject: Reland "ipcz: Refactor FragmentDescriptor decode"
|
||||
|
||||
This is a reland of commit 17dd18d1f2194089b8433e0ca334c81343b591e2
|
||||
|
||||
Original change's description:
|
||||
> ipcz: Refactor FragmentDescriptor decode
|
||||
>
|
||||
> Funnels untrusted FragmentDescriptor mapping through a new
|
||||
> Fragment::MappedFromDescriptor helper. See the linked bug
|
||||
> for more details.
|
||||
>
|
||||
> Fixed: 1450899
|
||||
> Change-Id: I4c7751b9f4299da4a13c0becc1b889160a0c6e66
|
||||
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4599218
|
||||
> Reviewed-by: Daniel Cheng <dcheng@chromium.org>
|
||||
> Commit-Queue: Ken Rockot <rockot@google.com>
|
||||
> Cr-Commit-Position: refs/heads/main@{#1155133}
|
||||
|
||||
Change-Id: I86ee9118a30dea59d837c377a1f751b20a85a3c3
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4602794
|
||||
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
|
||||
Commit-Queue: Ken Rockot <rockot@google.com>
|
||||
Cr-Commit-Position: refs/heads/main@{#1155397}
|
||||
|
||||
diff --git a/third_party/ipcz/src/BUILD.gn b/third_party/ipcz/src/BUILD.gn
|
||||
index 94177b5ec335bcfa28ba47eb0e9887c991073946..5dda0f2f806936d9bd6c986afd20ec5b53e06c28 100644
|
||||
--- a/third_party/ipcz/src/BUILD.gn
|
||||
+++ b/third_party/ipcz/src/BUILD.gn
|
||||
@@ -212,6 +212,7 @@ ipcz_source_set("impl") {
|
||||
"ipcz/application_object.h",
|
||||
"ipcz/block_allocator.h",
|
||||
"ipcz/box.h",
|
||||
+ "ipcz/buffer_id.h",
|
||||
"ipcz/buffer_pool.h",
|
||||
"ipcz/driver_memory.h",
|
||||
"ipcz/driver_memory_mapping.h",
|
||||
@@ -254,7 +255,6 @@ ipcz_source_set("impl") {
|
||||
"ipcz/block_allocator_pool.cc",
|
||||
"ipcz/block_allocator_pool.h",
|
||||
"ipcz/box.cc",
|
||||
- "ipcz/buffer_id.h",
|
||||
"ipcz/buffer_pool.cc",
|
||||
"ipcz/driver_memory.cc",
|
||||
"ipcz/driver_memory_mapping.cc",
|
||||
@@ -376,6 +376,7 @@ ipcz_source_set("ipcz_tests_sources") {
|
||||
"ipcz/driver_memory_test.cc",
|
||||
"ipcz/driver_object_test.cc",
|
||||
"ipcz/driver_transport_test.cc",
|
||||
+ "ipcz/fragment_test.cc",
|
||||
"ipcz/message_test.cc",
|
||||
"ipcz/node_connector_test.cc",
|
||||
"ipcz/node_link_memory_test.cc",
|
||||
diff --git a/third_party/ipcz/src/ipcz/block_allocator_pool.cc b/third_party/ipcz/src/ipcz/block_allocator_pool.cc
|
||||
index bd464f897d1fcbde03941ee334d0e1706bf59868..1b9d50b2c77c046d815a94d7760328c8b379ecab 100644
|
||||
--- a/third_party/ipcz/src/ipcz/block_allocator_pool.cc
|
||||
+++ b/third_party/ipcz/src/ipcz/block_allocator_pool.cc
|
||||
@@ -86,7 +86,7 @@ Fragment BlockAllocatorPool::Allocate() {
|
||||
FragmentDescriptor descriptor(
|
||||
entry->buffer_id, checked_cast<uint32_t>(offset),
|
||||
checked_cast<uint32_t>(allocator.block_size()));
|
||||
- return Fragment(descriptor, block);
|
||||
+ return Fragment::FromDescriptorUnsafe(descriptor, block);
|
||||
}
|
||||
|
||||
// Allocation from the active allocator failed. Try another if available.
|
||||
diff --git a/third_party/ipcz/src/ipcz/buffer_pool.cc b/third_party/ipcz/src/ipcz/buffer_pool.cc
|
||||
index 6881346d8f8532f070e5121da16f064ae4a9bdaf..27b23049848967f29f81b10ba4f8fa4ead14d2e2 100644
|
||||
--- a/third_party/ipcz/src/ipcz/buffer_pool.cc
|
||||
+++ b/third_party/ipcz/src/ipcz/buffer_pool.cc
|
||||
@@ -26,15 +26,11 @@ Fragment BufferPool::GetFragment(const FragmentDescriptor& descriptor) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
auto it = mappings_.find(descriptor.buffer_id());
|
||||
if (it == mappings_.end()) {
|
||||
- return Fragment(descriptor, nullptr);
|
||||
+ return Fragment::PendingFromDescriptor(descriptor);
|
||||
}
|
||||
|
||||
auto& [id, mapping] = *it;
|
||||
- if (descriptor.end() > mapping.bytes().size()) {
|
||||
- return {};
|
||||
- }
|
||||
-
|
||||
- return Fragment(descriptor, mapping.address_at(descriptor.offset()));
|
||||
+ return Fragment::MappedFromDescriptor(descriptor, mapping);
|
||||
}
|
||||
|
||||
bool BufferPool::AddBlockBuffer(
|
||||
diff --git a/third_party/ipcz/src/ipcz/buffer_pool_test.cc b/third_party/ipcz/src/ipcz/buffer_pool_test.cc
|
||||
index a009ffe1c20ade013a19b51eceee4faf334eb591..bff66c452a3e2c38b0f208cca1fa1a082f1ee871 100644
|
||||
--- a/third_party/ipcz/src/ipcz/buffer_pool_test.cc
|
||||
+++ b/third_party/ipcz/src/ipcz/buffer_pool_test.cc
|
||||
@@ -194,9 +194,11 @@ TEST_F(BufferPoolTest, BasicBlockAllocation) {
|
||||
pool.GetTotalBlockCapacity(kBlockSize));
|
||||
|
||||
// We can't free something that isn't a valid allocation.
|
||||
- EXPECT_FALSE(pool.FreeBlock(Fragment{{}, nullptr}));
|
||||
- EXPECT_FALSE(pool.FreeBlock(Fragment{{BufferId{1000}, 0, 1}, nullptr}));
|
||||
- EXPECT_FALSE(pool.FreeBlock(Fragment{{BufferId{0}, 0, 1}, bytes0.data()}));
|
||||
+ EXPECT_FALSE(pool.FreeBlock(Fragment::FromDescriptorUnsafe({}, nullptr)));
|
||||
+ EXPECT_FALSE(pool.FreeBlock(
|
||||
+ Fragment::FromDescriptorUnsafe({BufferId{1000}, 0, 1}, nullptr)));
|
||||
+ EXPECT_FALSE(pool.FreeBlock(
|
||||
+ Fragment::FromDescriptorUnsafe({BufferId{0}, 0, 1}, bytes0.data())));
|
||||
|
||||
// Allocate all available capacity.
|
||||
std::vector<Fragment> fragments;
|
||||
diff --git a/third_party/ipcz/src/ipcz/fragment.cc b/third_party/ipcz/src/ipcz/fragment.cc
|
||||
index 651d1c2fca5fe4fb69cdf61c6062bd8804ebf704..2ef4ed8dcfa0a56a73975a0b7dcc3f86bf5a83a0 100644
|
||||
--- a/third_party/ipcz/src/ipcz/fragment.cc
|
||||
+++ b/third_party/ipcz/src/ipcz/fragment.cc
|
||||
@@ -6,10 +6,38 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
+#include "ipcz/driver_memory_mapping.h"
|
||||
+#include "ipcz/fragment_descriptor.h"
|
||||
#include "third_party/abseil-cpp/absl/base/macros.h"
|
||||
+#include "util/safe_math.h"
|
||||
|
||||
namespace ipcz {
|
||||
|
||||
+// static
|
||||
+Fragment Fragment::MappedFromDescriptor(const FragmentDescriptor& descriptor,
|
||||
+ DriverMemoryMapping& mapping) {
|
||||
+ if (descriptor.is_null()) {
|
||||
+ return {};
|
||||
+ }
|
||||
+
|
||||
+ const uint32_t end = SaturatedAdd(descriptor.offset(), descriptor.size());
|
||||
+ if (end > mapping.bytes().size()) {
|
||||
+ return {};
|
||||
+ }
|
||||
+ return Fragment{descriptor, mapping.address_at(descriptor.offset())};
|
||||
+}
|
||||
+
|
||||
+// static
|
||||
+Fragment Fragment::PendingFromDescriptor(const FragmentDescriptor& descriptor) {
|
||||
+ return Fragment{descriptor, nullptr};
|
||||
+}
|
||||
+
|
||||
+// static
|
||||
+Fragment Fragment::FromDescriptorUnsafe(const FragmentDescriptor& descriptor,
|
||||
+ void* base_address) {
|
||||
+ return Fragment{descriptor, base_address};
|
||||
+}
|
||||
+
|
||||
Fragment::Fragment(const FragmentDescriptor& descriptor, void* address)
|
||||
: descriptor_(descriptor), address_(address) {
|
||||
// If `address` is non-null, the descriptor must also be. Note that the
|
||||
diff --git a/third_party/ipcz/src/ipcz/fragment.h b/third_party/ipcz/src/ipcz/fragment.h
|
||||
index c0151fdcf4b418680172a29d1c0d28b58a5807cd..de65f087b0bc27fd59ab88e23130d5ce0d345a8a 100644
|
||||
--- a/third_party/ipcz/src/ipcz/fragment.h
|
||||
+++ b/third_party/ipcz/src/ipcz/fragment.h
|
||||
@@ -14,21 +14,32 @@
|
||||
|
||||
namespace ipcz {
|
||||
|
||||
+class DriverMemoryMapping;
|
||||
+
|
||||
// Represents a span of memory located within the shared memory regions owned by
|
||||
// a NodeLinkMemory, via BufferPool. This is essentially a FragmentDescriptor
|
||||
// plus the actual mapped address of the given buffer and offset.
|
||||
struct Fragment {
|
||||
constexpr Fragment() = default;
|
||||
|
||||
- // Constructs a new Fragment over `descriptor`, mapped to `address`. If
|
||||
- // `address` is null, the Fragment is considered "pending" -- it has a
|
||||
- // potentially valid descriptor, but could not be resolved to a mapped address
|
||||
- // yet (e.g. because the relevant BufferPool doesn't have the identified
|
||||
- // buffer mapped yet.)
|
||||
- Fragment(const FragmentDescriptor& descriptor, void* address);
|
||||
Fragment(const Fragment&);
|
||||
Fragment& operator=(const Fragment&);
|
||||
|
||||
+ // Returns a new concrete Fragment corresponding to `descriptor` within the
|
||||
+ // context of `mapping`. This validates that the fragment's bounds fall within
|
||||
+ // the bounds of `mapping`. If `descriptor` was null or validation fails, this
|
||||
+ // returns a null Fragment.
|
||||
+ static Fragment MappedFromDescriptor(const FragmentDescriptor& descriptor,
|
||||
+ DriverMemoryMapping& mapping);
|
||||
+
|
||||
+ // Returns a pending Fragment corresponding to `descriptor`.
|
||||
+ static Fragment PendingFromDescriptor(const FragmentDescriptor& descriptor);
|
||||
+
|
||||
+ // Returns a Fragment corresponding to `descriptor`, with the starting address
|
||||
+ // already mapped to `address`.
|
||||
+ static Fragment FromDescriptorUnsafe(const FragmentDescriptor& descriptor,
|
||||
+ void* address);
|
||||
+
|
||||
// A null fragment is a fragment with a null descriptor, meaning it does not
|
||||
// reference a valid buffer ID.
|
||||
bool is_null() const { return descriptor_.is_null(); }
|
||||
@@ -66,6 +77,13 @@ struct Fragment {
|
||||
}
|
||||
|
||||
private:
|
||||
+ // Constructs a new Fragment over `descriptor`, mapped to `address`. If
|
||||
+ // `address` is null, the Fragment is considered "pending" -- it has a
|
||||
+ // potentially valid descriptor, but could not be resolved to a mapped address
|
||||
+ // yet (e.g. because the relevant BufferPool doesn't have the identified
|
||||
+ // buffer mapped yet.)
|
||||
+ Fragment(const FragmentDescriptor& descriptor, void* address);
|
||||
+
|
||||
FragmentDescriptor descriptor_;
|
||||
|
||||
// The actual mapped address corresponding to `descriptor_`.
|
||||
diff --git a/third_party/ipcz/src/ipcz/fragment_descriptor.h b/third_party/ipcz/src/ipcz/fragment_descriptor.h
|
||||
index b247215fd5e5f7c69e521416614465b0321f5d83..aeaa7da9c82761854948d009e7f245c9c9d042c7 100644
|
||||
--- a/third_party/ipcz/src/ipcz/fragment_descriptor.h
|
||||
+++ b/third_party/ipcz/src/ipcz/fragment_descriptor.h
|
||||
@@ -39,7 +39,6 @@ struct IPCZ_ALIGN(8) FragmentDescriptor {
|
||||
BufferId buffer_id() const { return buffer_id_; }
|
||||
uint32_t offset() const { return offset_; }
|
||||
uint32_t size() const { return size_; }
|
||||
- uint32_t end() const { return offset_ + size_; }
|
||||
|
||||
private:
|
||||
// Identifies the shared memory buffer in which the memory resides. This ID is
|
||||
diff --git a/third_party/ipcz/src/ipcz/fragment_test.cc b/third_party/ipcz/src/ipcz/fragment_test.cc
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..e6b6baa6cb2f1fbdfb89d87d644f63681c797c01
|
||||
--- /dev/null
|
||||
+++ b/third_party/ipcz/src/ipcz/fragment_test.cc
|
||||
@@ -0,0 +1,102 @@
|
||||
+// Copyright 2023 The Chromium Authors
|
||||
+// Use of this source code is governed by a BSD-style license that can be
|
||||
+// found in the LICENSE file.
|
||||
+
|
||||
+#include "ipcz/fragment.h"
|
||||
+
|
||||
+#include <algorithm>
|
||||
+#include <cstring>
|
||||
+#include <limits>
|
||||
+#include <string>
|
||||
+#include <utility>
|
||||
+
|
||||
+#include "ipcz/buffer_id.h"
|
||||
+#include "ipcz/driver_memory.h"
|
||||
+#include "ipcz/driver_memory_mapping.h"
|
||||
+#include "reference_drivers/sync_reference_driver.h"
|
||||
+#include "testing/gtest/include/gtest/gtest.h"
|
||||
+
|
||||
+namespace ipcz {
|
||||
+namespace {
|
||||
+
|
||||
+const IpczDriver& kTestDriver = reference_drivers::kSyncReferenceDriver;
|
||||
+
|
||||
+using FragmentTest = testing::Test;
|
||||
+
|
||||
+TEST_F(FragmentTest, FromDescriptorUnsafe) {
|
||||
+ char kBuffer[] = "Hello, world!";
|
||||
+
|
||||
+ Fragment f = Fragment::FromDescriptorUnsafe({BufferId{0}, 1, 4}, kBuffer + 1);
|
||||
+ EXPECT_FALSE(f.is_null());
|
||||
+ EXPECT_FALSE(f.is_pending());
|
||||
+ EXPECT_EQ(1u, f.offset());
|
||||
+ EXPECT_EQ(4u, f.size());
|
||||
+ EXPECT_EQ("ello", std::string(f.bytes().begin(), f.bytes().end()));
|
||||
+
|
||||
+ f = Fragment::FromDescriptorUnsafe({BufferId{0}, 7, 6}, kBuffer + 7);
|
||||
+ EXPECT_FALSE(f.is_null());
|
||||
+ EXPECT_FALSE(f.is_pending());
|
||||
+ EXPECT_EQ(7u, f.offset());
|
||||
+ EXPECT_EQ(6u, f.size());
|
||||
+ EXPECT_EQ("world!", std::string(f.bytes().begin(), f.bytes().end()));
|
||||
+}
|
||||
+
|
||||
+TEST_F(FragmentTest, PendingFromDescriptor) {
|
||||
+ Fragment f = Fragment::PendingFromDescriptor({BufferId{0}, 5, 42});
|
||||
+ EXPECT_TRUE(f.is_pending());
|
||||
+ EXPECT_FALSE(f.is_null());
|
||||
+ EXPECT_EQ(5u, f.offset());
|
||||
+ EXPECT_EQ(42u, f.size());
|
||||
+
|
||||
+ f = Fragment::PendingFromDescriptor({kInvalidBufferId, 0, 0});
|
||||
+ EXPECT_TRUE(f.is_null());
|
||||
+ EXPECT_FALSE(f.is_pending());
|
||||
+}
|
||||
+
|
||||
+TEST_F(FragmentTest, NullMappedFromDescriptor) {
|
||||
+ constexpr size_t kDataSize = 32;
|
||||
+ DriverMemory memory(kTestDriver, kDataSize);
|
||||
+ auto mapping = memory.Map();
|
||||
+
|
||||
+ Fragment f =
|
||||
+ Fragment::MappedFromDescriptor({kInvalidBufferId, 0, 0}, mapping);
|
||||
+ EXPECT_TRUE(f.is_null());
|
||||
+}
|
||||
+
|
||||
+TEST_F(FragmentTest, InvalidMappedFromDescriptor) {
|
||||
+ constexpr size_t kDataSize = 32;
|
||||
+ DriverMemory memory(kTestDriver, kDataSize);
|
||||
+ auto mapping = memory.Map();
|
||||
+
|
||||
+ Fragment f;
|
||||
+
|
||||
+ // Offset out of bounds
|
||||
+ f = Fragment::MappedFromDescriptor({BufferId{0}, kDataSize, 1}, mapping);
|
||||
+ EXPECT_TRUE(f.is_null());
|
||||
+
|
||||
+ // Tail out of bounds
|
||||
+ f = Fragment::MappedFromDescriptor({BufferId{0}, 0, kDataSize + 5}, mapping);
|
||||
+ EXPECT_TRUE(f.is_null());
|
||||
+
|
||||
+ // Tail overflow
|
||||
+ f = Fragment::MappedFromDescriptor(
|
||||
+ {BufferId{0}, std::numeric_limits<uint32_t>::max(), 2}, mapping);
|
||||
+ EXPECT_TRUE(f.is_null());
|
||||
+}
|
||||
+
|
||||
+TEST_F(FragmentTest, ValidMappedFromDescriptor) {
|
||||
+ const char kData[] = "0123456789abcdef";
|
||||
+ DriverMemory memory(kTestDriver, std::size(kData));
|
||||
+ auto mapping = memory.Map();
|
||||
+ memcpy(mapping.bytes().data(), kData, std::size(kData));
|
||||
+
|
||||
+ Fragment f = Fragment::MappedFromDescriptor({BufferId{0}, 2, 11}, mapping);
|
||||
+ EXPECT_FALSE(f.is_null());
|
||||
+ EXPECT_FALSE(f.is_pending());
|
||||
+ EXPECT_EQ(2u, f.offset());
|
||||
+ EXPECT_EQ(11u, f.size());
|
||||
+ EXPECT_EQ("23456789abc", std::string(f.bytes().begin(), f.bytes().end()));
|
||||
+}
|
||||
+
|
||||
+} // namespace
|
||||
+} // namespace ipcz
|
||||
diff --git a/third_party/ipcz/src/ipcz/node_link_memory.cc b/third_party/ipcz/src/ipcz/node_link_memory.cc
|
||||
index b4715bca8b59c1a53fa4777510c75c7aca1cdf9d..f70a6b1aee08d749a6266d3cb88f9d12f4e1f281 100644
|
||||
--- a/third_party/ipcz/src/ipcz/node_link_memory.cc
|
||||
+++ b/third_party/ipcz/src/ipcz/node_link_memory.cc
|
||||
@@ -259,8 +259,9 @@ FragmentRef<RouterLinkState> NodeLinkMemory::GetInitialRouterLinkState(
|
||||
FragmentDescriptor descriptor(kPrimaryBufferId,
|
||||
ToOffset(state, primary_buffer_memory_.data()),
|
||||
sizeof(RouterLinkState));
|
||||
- return FragmentRef<RouterLinkState>(RefCountedFragment::kUnmanagedRef,
|
||||
- Fragment(descriptor, state));
|
||||
+ return FragmentRef<RouterLinkState>(
|
||||
+ RefCountedFragment::kUnmanagedRef,
|
||||
+ Fragment::FromDescriptorUnsafe(descriptor, state));
|
||||
}
|
||||
|
||||
Fragment NodeLinkMemory::GetFragment(const FragmentDescriptor& descriptor) {
|
||||
diff --git a/third_party/ipcz/src/ipcz/ref_counted_fragment_test.cc b/third_party/ipcz/src/ipcz/ref_counted_fragment_test.cc
|
||||
index d5a2243a693597e43f87f116f80599fde383cb59..220c3556a261c5caab7194114af4cf375d9af683 100644
|
||||
--- a/third_party/ipcz/src/ipcz/ref_counted_fragment_test.cc
|
||||
+++ b/third_party/ipcz/src/ipcz/ref_counted_fragment_test.cc
|
||||
@@ -64,7 +64,8 @@ TEST_F(RefCountedFragmentTest, SimpleRef) {
|
||||
|
||||
FragmentRef<TestObject> ref(
|
||||
RefCountedFragment::kUnmanagedRef,
|
||||
- Fragment(FragmentDescriptor(BufferId(0), 0, sizeof(object)), &object));
|
||||
+ Fragment::FromDescriptorUnsafe(
|
||||
+ FragmentDescriptor(BufferId(0), 0, sizeof(object)), &object));
|
||||
EXPECT_EQ(1, object.ref_count_for_testing());
|
||||
ref.reset();
|
||||
EXPECT_EQ(0, object.ref_count_for_testing());
|
||||
@@ -75,7 +76,8 @@ TEST_F(RefCountedFragmentTest, Copy) {
|
||||
|
||||
FragmentRef<TestObject> ref1(
|
||||
RefCountedFragment::kUnmanagedRef,
|
||||
- Fragment(FragmentDescriptor(BufferId(0), 0, sizeof(object1)), &object1));
|
||||
+ Fragment::FromDescriptorUnsafe(
|
||||
+ FragmentDescriptor(BufferId(0), 0, sizeof(object1)), &object1));
|
||||
EXPECT_EQ(1, object1.ref_count_for_testing());
|
||||
|
||||
FragmentRef<TestObject> other1 = ref1;
|
||||
@@ -88,7 +90,8 @@ TEST_F(RefCountedFragmentTest, Copy) {
|
||||
TestObject object2;
|
||||
auto ref2 = FragmentRef<TestObject>(
|
||||
RefCountedFragment::kUnmanagedRef,
|
||||
- Fragment(FragmentDescriptor(BufferId(0), 0, sizeof(object2)), &object2));
|
||||
+ Fragment::FromDescriptorUnsafe(
|
||||
+ FragmentDescriptor(BufferId(0), 0, sizeof(object2)), &object2));
|
||||
EXPECT_EQ(1, object1.ref_count_for_testing());
|
||||
EXPECT_EQ(1, object2.ref_count_for_testing());
|
||||
ref2 = ref1;
|
||||
@@ -115,7 +118,8 @@ TEST_F(RefCountedFragmentTest, Move) {
|
||||
|
||||
FragmentRef<TestObject> ref1(
|
||||
RefCountedFragment::kUnmanagedRef,
|
||||
- Fragment(FragmentDescriptor(BufferId(0), 0, sizeof(object1)), &object1));
|
||||
+ Fragment::FromDescriptorUnsafe(
|
||||
+ FragmentDescriptor(BufferId(0), 0, sizeof(object1)), &object1));
|
||||
EXPECT_EQ(1, ref1.ref_count_for_testing());
|
||||
|
||||
FragmentRef<TestObject> other1 = std::move(ref1);
|
||||
@@ -133,10 +137,12 @@ TEST_F(RefCountedFragmentTest, Move) {
|
||||
TestObject object3;
|
||||
FragmentRef<TestObject> ref2(
|
||||
RefCountedFragment::kUnmanagedRef,
|
||||
- Fragment(FragmentDescriptor(BufferId(0), 0, sizeof(object2)), &object2));
|
||||
+ Fragment::FromDescriptorUnsafe(
|
||||
+ FragmentDescriptor(BufferId(0), 0, sizeof(object2)), &object2));
|
||||
FragmentRef<TestObject> ref3(
|
||||
RefCountedFragment::kUnmanagedRef,
|
||||
- Fragment(FragmentDescriptor(BufferId(0), 0, sizeof(object3)), &object3));
|
||||
+ Fragment::FromDescriptorUnsafe(
|
||||
+ FragmentDescriptor(BufferId(0), 0, sizeof(object3)), &object3));
|
||||
|
||||
EXPECT_FALSE(ref2.is_null());
|
||||
EXPECT_TRUE(ref2.is_addressable());
|
||||
119
patches/chromium/cherry-pick-b03973561862.patch
Normal file
119
patches/chromium/cherry-pick-b03973561862.patch
Normal file
@@ -0,0 +1,119 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tommi <tommi@chromium.org>
|
||||
Date: Wed, 5 Jul 2023 10:55:53 +0000
|
||||
Subject: Make RTCDataChannel's channel and observer pointers const.
|
||||
|
||||
This allows channel properties to be queried while the RTCDataChannel
|
||||
instance exists and avoids potential null deref after entering the
|
||||
kClosed state.
|
||||
|
||||
(cherry picked from commit 08d5ad011f53a1995bfccef6728bfa62541f7608)
|
||||
|
||||
Bug: 1456567, 1457421
|
||||
Change-Id: I4747f9c00804b35711667d7320ec6188f20910c4
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4663082
|
||||
Commit-Queue: Tomas Gunnarsson <tommi@chromium.org>
|
||||
Reviewed-by: Elad Alon <eladalon@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1165406}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4665530
|
||||
Cr-Commit-Position: refs/branch-heads/5845@{#300}
|
||||
Cr-Branched-From: 5a5dff63a4a4c63b9b18589819bebb2566c85443-refs/heads/main@{#1160321}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.cc b/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.cc
|
||||
index 78d28d60822f4ce206d869846235352224378076..91c20cbcc5042373964d57545177ff06074db564 100644
|
||||
--- a/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.cc
|
||||
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.cc
|
||||
@@ -228,11 +228,12 @@ RTCDataChannel::Observer::Observer(
|
||||
scoped_refptr<webrtc::DataChannelInterface> channel)
|
||||
: main_thread_(main_thread),
|
||||
blink_channel_(blink_channel),
|
||||
- webrtc_channel_(channel) {}
|
||||
+ webrtc_channel_(std::move(channel)) {
|
||||
+ CHECK(webrtc_channel_.get());
|
||||
+}
|
||||
|
||||
RTCDataChannel::Observer::~Observer() {
|
||||
DCHECK(!blink_channel_) << "Reference to blink channel hasn't been released.";
|
||||
- DCHECK(!webrtc_channel_.get()) << "Unregister hasn't been called.";
|
||||
}
|
||||
|
||||
const scoped_refptr<webrtc::DataChannelInterface>&
|
||||
@@ -242,13 +243,8 @@ RTCDataChannel::Observer::channel() const {
|
||||
|
||||
void RTCDataChannel::Observer::Unregister() {
|
||||
DCHECK(main_thread_->BelongsToCurrentThread());
|
||||
+ webrtc_channel_->UnregisterObserver();
|
||||
blink_channel_ = nullptr;
|
||||
- if (webrtc_channel_.get()) {
|
||||
- webrtc_channel_->UnregisterObserver();
|
||||
- // Now that we're guaranteed to not get further OnStateChange callbacks,
|
||||
- // it's safe to release our reference to the channel.
|
||||
- webrtc_channel_ = nullptr;
|
||||
- }
|
||||
}
|
||||
|
||||
void RTCDataChannel::Observer::OnStateChange() {
|
||||
@@ -302,7 +298,7 @@ void RTCDataChannel::Observer::OnMessageImpl(
|
||||
|
||||
RTCDataChannel::RTCDataChannel(
|
||||
ExecutionContext* context,
|
||||
- scoped_refptr<webrtc::DataChannelInterface> channel,
|
||||
+ scoped_refptr<webrtc::DataChannelInterface> data_channel,
|
||||
RTCPeerConnectionHandler* peer_connection_handler)
|
||||
: ExecutionContextLifecycleObserver(context),
|
||||
state_(webrtc::DataChannelInterface::kConnecting),
|
||||
@@ -317,7 +313,7 @@ RTCDataChannel::RTCDataChannel(
|
||||
observer_(base::MakeRefCounted<Observer>(
|
||||
context->GetTaskRunner(TaskType::kNetworking),
|
||||
this,
|
||||
- channel)),
|
||||
+ std::move(data_channel))),
|
||||
signaling_thread_(peer_connection_handler->signaling_thread()) {
|
||||
DCHECK(peer_connection_handler);
|
||||
|
||||
@@ -340,7 +336,7 @@ RTCDataChannel::RTCDataChannel(
|
||||
observer_, state_),
|
||||
"RegisterObserverAndGetStateUpdate");
|
||||
|
||||
- IncrementCounters(*channel.get());
|
||||
+ IncrementCounters(*(observer_->channel()).get());
|
||||
}
|
||||
|
||||
RTCDataChannel::~RTCDataChannel() = default;
|
||||
@@ -689,9 +685,8 @@ void RTCDataChannel::Dispose() {
|
||||
if (stopped_)
|
||||
return;
|
||||
|
||||
- // Clears the weak persistent reference to this on-heap object.
|
||||
+ // Clear the weak persistent reference to this on-heap object.
|
||||
observer_->Unregister();
|
||||
- observer_ = nullptr;
|
||||
}
|
||||
|
||||
void RTCDataChannel::ScheduleDispatchEvent(Event* event) {
|
||||
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.h b/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.h
|
||||
index 21bb39382ac0c6acbf984ffbda5f6a4e6c863432..6959b8b1e3a0b586be68cb4a8d0389b7926b98fe 100644
|
||||
--- a/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.h
|
||||
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_data_channel.h
|
||||
@@ -152,7 +152,7 @@ class MODULES_EXPORT RTCDataChannel final
|
||||
|
||||
const scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
|
||||
WeakPersistent<RTCDataChannel> blink_channel_;
|
||||
- scoped_refptr<webrtc::DataChannelInterface> webrtc_channel_;
|
||||
+ const scoped_refptr<webrtc::DataChannelInterface> webrtc_channel_;
|
||||
};
|
||||
|
||||
void OnStateChange(webrtc::DataChannelInterface::DataState state);
|
||||
@@ -195,7 +195,11 @@ class MODULES_EXPORT RTCDataChannel final
|
||||
unsigned buffered_amount_;
|
||||
bool stopped_;
|
||||
bool closed_from_owner_;
|
||||
- scoped_refptr<Observer> observer_;
|
||||
+ // Keep the `observer_` reference const to make it clear that we don't want
|
||||
+ // to free the underlying channel (or callback observer) until the
|
||||
+ // `RTCDataChannel` instance goes away. This allows properties to be queried
|
||||
+ // after the state reaches `kClosed`.
|
||||
+ const scoped_refptr<Observer> observer_;
|
||||
scoped_refptr<base::SingleThreadTaskRunner> signaling_thread_;
|
||||
THREAD_CHECKER(thread_checker_);
|
||||
};
|
||||
187
patches/chromium/cherry-pick-c60a1ab717c7.patch
Normal file
187
patches/chromium/cherry-pick-c60a1ab717c7.patch
Normal file
@@ -0,0 +1,187 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Taylor Bergquist <tbergquist@chromium.org>
|
||||
Date: Tue, 11 Jul 2023 01:32:22 +0000
|
||||
Subject: Fix UAF when exiting a nested run loop in
|
||||
TabDragContextImpl::OnGestureEvent.
|
||||
|
||||
OnGestureEvent may call ContinueDrag, which may run a nested run loop. After the nested run loop returns, multiple seconds of time may have passed, and the world may be in a very different state; in particular, the window that contains this TabDragContext may have closed.
|
||||
|
||||
This CL checks if this has happened, and returns early in that case.
|
||||
|
||||
(cherry picked from commit 63d6b8ba8126b16215d33670df8c67dcbc6c9bef)
|
||||
|
||||
Bug: 1453465
|
||||
Change-Id: I6095c0afeb5aa5f422717f1bbd93b96175e52afa
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4657527
|
||||
Reviewed-by: Darryl James <dljames@chromium.org>
|
||||
Commit-Queue: Taylor Bergquist <tbergquist@chromium.org>
|
||||
Code-Coverage: Findit <findit-for-me@appspot.gserviceaccount.com>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1164449}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4676126
|
||||
Reviewed-by: Shibalik Mohapatra <shibalik@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/5845@{#410}
|
||||
Cr-Branched-From: 5a5dff63a4a4c63b9b18589819bebb2566c85443-refs/heads/main@{#1160321}
|
||||
|
||||
diff --git a/chrome/browser/ui/views/tabs/fake_tab_slot_controller.cc b/chrome/browser/ui/views/tabs/fake_tab_slot_controller.cc
|
||||
index d1f5a96ed729fde1224f596212f49e386fc6f170..c80536b0d4601c68ce279dfa122f38b39b13fb72 100644
|
||||
--- a/chrome/browser/ui/views/tabs/fake_tab_slot_controller.cc
|
||||
+++ b/chrome/browser/ui/views/tabs/fake_tab_slot_controller.cc
|
||||
@@ -43,6 +43,12 @@ bool FakeTabSlotController::IsFocusInTabs() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
+TabSlotController::Liveness FakeTabSlotController::ContinueDrag(
|
||||
+ views::View* view,
|
||||
+ const ui::LocatedEvent& event) {
|
||||
+ return Liveness::kAlive;
|
||||
+}
|
||||
+
|
||||
bool FakeTabSlotController::EndDrag(EndDragReason reason) {
|
||||
return false;
|
||||
}
|
||||
diff --git a/chrome/browser/ui/views/tabs/fake_tab_slot_controller.h b/chrome/browser/ui/views/tabs/fake_tab_slot_controller.h
|
||||
index 25f1c66d131189ebec2711b49f7f0c141f2c06d2..98dab21cfe2e3ecb88f70cac3868fb30828658be 100644
|
||||
--- a/chrome/browser/ui/views/tabs/fake_tab_slot_controller.h
|
||||
+++ b/chrome/browser/ui/views/tabs/fake_tab_slot_controller.h
|
||||
@@ -60,8 +60,8 @@ class FakeTabSlotController : public TabSlotController {
|
||||
TabSlotView* source,
|
||||
const ui::LocatedEvent& event,
|
||||
const ui::ListSelectionModel& original_selection) override {}
|
||||
- void ContinueDrag(views::View* view, const ui::LocatedEvent& event) override {
|
||||
- }
|
||||
+ Liveness ContinueDrag(views::View* view,
|
||||
+ const ui::LocatedEvent& event) override;
|
||||
bool EndDrag(EndDragReason reason) override;
|
||||
Tab* GetTabAt(const gfx::Point& point) override;
|
||||
const Tab* GetAdjacentTab(const Tab* tab, int offset) override;
|
||||
diff --git a/chrome/browser/ui/views/tabs/tab_slot_controller.h b/chrome/browser/ui/views/tabs/tab_slot_controller.h
|
||||
index f729425995ffd1ee6926ef953417d2e81a1b527b..c57760f30ae515cf5ee7a021e07c8d049082e371 100644
|
||||
--- a/chrome/browser/ui/views/tabs/tab_slot_controller.h
|
||||
+++ b/chrome/browser/ui/views/tabs/tab_slot_controller.h
|
||||
@@ -49,6 +49,8 @@ class TabSlotController {
|
||||
kEvent
|
||||
};
|
||||
|
||||
+ enum class Liveness { kAlive, kDeleted };
|
||||
+
|
||||
virtual const ui::ListSelectionModel& GetSelectionModel() const = 0;
|
||||
|
||||
// Returns the tab at |index|.
|
||||
@@ -126,9 +128,10 @@ class TabSlotController {
|
||||
const ui::LocatedEvent& event,
|
||||
const ui::ListSelectionModel& original_selection) = 0;
|
||||
|
||||
- // Continues dragging a Tab.
|
||||
- virtual void ContinueDrag(views::View* view,
|
||||
- const ui::LocatedEvent& event) = 0;
|
||||
+ // Continues dragging a Tab. May enter a nested event loop - returns
|
||||
+ // Liveness::kDeleted if `this` was destroyed during this nested event loop,
|
||||
+ // and Liveness::kAlive if `this` is still alive.
|
||||
+ virtual Liveness ContinueDrag(views::View* view, const ui::LocatedEvent& event) = 0;
|
||||
|
||||
// Ends dragging a Tab. Returns whether the tab has been destroyed.
|
||||
virtual bool EndDrag(EndDragReason reason) = 0;
|
||||
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
|
||||
index 0a9ffa81d06d4bb284e8aa51758fbafc9e1b6644..cb82dc62aee1970d50a91f9692208b7303333d1d 100644
|
||||
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
|
||||
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
|
||||
@@ -186,7 +186,7 @@ class TabStrip::TabDragContextImpl : public TabDragContext,
|
||||
}
|
||||
|
||||
bool OnMouseDragged(const ui::MouseEvent& event) override {
|
||||
- ContinueDrag(this, event);
|
||||
+ (void)ContinueDrag(this, event);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -197,6 +197,7 @@ class TabStrip::TabDragContextImpl : public TabDragContext,
|
||||
void OnMouseCaptureLost() override { EndDrag(END_DRAG_CAPTURE_LOST); }
|
||||
|
||||
void OnGestureEvent(ui::GestureEvent* event) override {
|
||||
+ Liveness tabstrip_alive = Liveness::kAlive;
|
||||
switch (event->type()) {
|
||||
case ui::ET_GESTURE_SCROLL_END:
|
||||
case ui::ET_SCROLL_FLING_START:
|
||||
@@ -210,7 +211,8 @@ class TabStrip::TabDragContextImpl : public TabDragContext,
|
||||
}
|
||||
|
||||
case ui::ET_GESTURE_SCROLL_UPDATE:
|
||||
- ContinueDrag(this, *event);
|
||||
+ // N.B. !! ContinueDrag may enter a nested run loop !!
|
||||
+ tabstrip_alive = ContinueDrag(this, *event);
|
||||
break;
|
||||
|
||||
case ui::ET_GESTURE_TAP_DOWN:
|
||||
@@ -222,6 +224,12 @@ class TabStrip::TabDragContextImpl : public TabDragContext,
|
||||
}
|
||||
event->SetHandled();
|
||||
|
||||
+ // If tabstrip was destroyed (during ContinueDrag above), return early to
|
||||
+ // avoid UAF below.
|
||||
+ if (tabstrip_alive == Liveness::kDeleted) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
// TabDragContext gets event capture as soon as a drag session begins, which
|
||||
// precludes TabStrip from ever getting events like tap or long tap. Forward
|
||||
// this on to TabStrip so it can respond to those events.
|
||||
@@ -310,20 +318,20 @@ class TabStrip::TabDragContextImpl : public TabDragContext,
|
||||
std::move(drag_controller_set_callback_).Run(drag_controller_.get());
|
||||
}
|
||||
|
||||
- void ContinueDrag(views::View* view, const ui::LocatedEvent& event) {
|
||||
- if (drag_controller_.get() &&
|
||||
- drag_controller_->event_source() == EventSourceFromEvent(event)) {
|
||||
- gfx::Point screen_location(event.location());
|
||||
- views::View::ConvertPointToScreen(view, &screen_location);
|
||||
+ Liveness ContinueDrag(views::View* view, const ui::LocatedEvent& event) {
|
||||
+ if (!drag_controller_.get() ||
|
||||
+ drag_controller_->event_source() != EventSourceFromEvent(event)) {
|
||||
+ return Liveness::kAlive;
|
||||
+ }
|
||||
|
||||
- // Note: |tab_strip_| can be destroyed during drag, also destroying
|
||||
- // |this|.
|
||||
- base::WeakPtr<TabDragContext> weak_ptr(weak_factory_.GetWeakPtr());
|
||||
- drag_controller_->Drag(screen_location);
|
||||
+ gfx::Point screen_location(event.location());
|
||||
+ views::View::ConvertPointToScreen(view, &screen_location);
|
||||
|
||||
- if (!weak_ptr)
|
||||
- return;
|
||||
- }
|
||||
+ // Note: `tab_strip_` can be destroyed during drag, also destroying `this`.
|
||||
+ base::WeakPtr<TabDragContext> weak_ptr(weak_factory_.GetWeakPtr());
|
||||
+ drag_controller_->Drag(screen_location);
|
||||
+
|
||||
+ return weak_ptr ? Liveness::kAlive : Liveness::kDeleted;
|
||||
}
|
||||
|
||||
bool EndDrag(EndDragReason reason) {
|
||||
@@ -1607,8 +1615,10 @@ void TabStrip::MaybeStartDrag(
|
||||
drag_context_->MaybeStartDrag(source, event, original_selection);
|
||||
}
|
||||
|
||||
-void TabStrip::ContinueDrag(views::View* view, const ui::LocatedEvent& event) {
|
||||
- drag_context_->ContinueDrag(view, event);
|
||||
+TabSlotController::Liveness TabStrip::ContinueDrag(
|
||||
+ views::View* view,
|
||||
+ const ui::LocatedEvent& event) {
|
||||
+ return drag_context_->ContinueDrag(view, event);
|
||||
}
|
||||
|
||||
bool TabStrip::EndDrag(EndDragReason reason) {
|
||||
diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h
|
||||
index c542581822cabc26b41ab8619fd73cb15c7f8524..682a44d3d9ad10aecc28e542c0cea0c323ee0c85 100644
|
||||
--- a/chrome/browser/ui/views/tabs/tab_strip.h
|
||||
+++ b/chrome/browser/ui/views/tabs/tab_strip.h
|
||||
@@ -278,7 +278,8 @@ class TabStrip : public views::View,
|
||||
TabSlotView* source,
|
||||
const ui::LocatedEvent& event,
|
||||
const ui::ListSelectionModel& original_selection) override;
|
||||
- void ContinueDrag(views::View* view, const ui::LocatedEvent& event) override;
|
||||
+ Liveness ContinueDrag(views::View* view,
|
||||
+ const ui::LocatedEvent& event) override;
|
||||
bool EndDrag(EndDragReason reason) override;
|
||||
Tab* GetTabAt(const gfx::Point& point) override;
|
||||
const Tab* GetAdjacentTab(const Tab* tab, int offset) override;
|
||||
200
patches/chromium/cherry-pick-ea1cd76358e0.patch
Normal file
200
patches/chromium/cherry-pick-ea1cd76358e0.patch
Normal file
@@ -0,0 +1,200 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Kevin McNee <mcnee@chromium.org>
|
||||
Date: Tue, 23 May 2023 15:46:16 +0000
|
||||
Subject: M114: Compute all webview find options before cloning them
|
||||
|
||||
Compute all webview find options before cloning them
|
||||
|
||||
In WebViewFindHelper::Find, we're cloning the find options before we've
|
||||
set the value for `new_session`. For requests that are part of the same
|
||||
session, in WebViewFindHelper::FindReply, we're using the incorrect
|
||||
value for `new_session` and we're destroying the FindInfo for what we
|
||||
think is a previous session but is actually for the request we're
|
||||
currently processing.
|
||||
|
||||
We now fully compute the options before cloning them.
|
||||
|
||||
(cherry picked from commit bb8e17b942b8b1de0a58b2dce34197e00a3b6525)
|
||||
|
||||
Bug: 1443401
|
||||
Change-Id: Ife6747aedabaf74f9a4855a173349ffe612b6f95
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4533923
|
||||
Reviewed-by: James Maclean <wjmaclean@chromium.org>
|
||||
Commit-Queue: James Maclean <wjmaclean@chromium.org>
|
||||
Auto-Submit: Kevin McNee <mcnee@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1145265}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4556646
|
||||
Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Cr-Commit-Position: refs/branch-heads/5735@{#941}
|
||||
Cr-Branched-From: 2f562e4ddbaf79a3f3cb338b4d1bd4398d49eb67-refs/heads/main@{#1135570}
|
||||
|
||||
diff --git a/chrome/browser/apps/guest_view/web_view_browsertest.cc b/chrome/browser/apps/guest_view/web_view_browsertest.cc
|
||||
index cebe56b9e79cbe0e5a58f73e68faf1b93b17ce5c..3748f8119bf1d4f37635bdb4fb87d825881de7f0 100644
|
||||
--- a/chrome/browser/apps/guest_view/web_view_browsertest.cc
|
||||
+++ b/chrome/browser/apps/guest_view/web_view_browsertest.cc
|
||||
@@ -3888,6 +3888,11 @@ IN_PROC_BROWSER_TEST_P(WebViewTest, Shim_testFindInMultipleWebViews) {
|
||||
TestHelper("testFindInMultipleWebViews", "web_view/shim", NO_TEST_SERVER);
|
||||
}
|
||||
|
||||
+IN_PROC_BROWSER_TEST_F(WebViewTest, Shim_TestFindAfterTerminate) {
|
||||
+ content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes;
|
||||
+ TestHelper("testFindAfterTerminate", "web_view/shim", NO_TEST_SERVER);
|
||||
+}
|
||||
+
|
||||
IN_PROC_BROWSER_TEST_P(WebViewTest, Shim_TestLoadDataAPI) {
|
||||
TestHelper("testLoadDataAPI", "web_view/shim", NEEDS_TEST_SERVER);
|
||||
|
||||
diff --git a/chrome/test/data/extensions/platform_apps/web_view/shim/main.js b/chrome/test/data/extensions/platform_apps/web_view/shim/main.js
|
||||
index 5ed4f0223346b01d83cc04c8cda6c0e92e1a72e3..4a1543d1751cc817a511594d0123deacc0e61ebb 100644
|
||||
--- a/chrome/test/data/extensions/platform_apps/web_view/shim/main.js
|
||||
+++ b/chrome/test/data/extensions/platform_apps/web_view/shim/main.js
|
||||
@@ -2859,6 +2859,20 @@ function testFindInMultipleWebViews() {
|
||||
});
|
||||
}
|
||||
|
||||
+function testFindAfterTerminate() {
|
||||
+ let webview = new WebView();
|
||||
+ webview.src = 'data:text/html,<body><iframe></iframe></body>';
|
||||
+ webview.addEventListener('loadstop', () => {
|
||||
+ webview.find('A');
|
||||
+ webview.terminate();
|
||||
+ webview.find('B', {'backward': true});
|
||||
+ webview.find('B', {'backward': true}, (results) => {
|
||||
+ embedder.test.succeed();
|
||||
+ });
|
||||
+ });
|
||||
+ document.body.appendChild(webview);
|
||||
+}
|
||||
+
|
||||
function testLoadDataAPI() {
|
||||
var webview = new WebView();
|
||||
webview.src = 'about:blank';
|
||||
@@ -3600,6 +3614,7 @@ embedder.test.testList = {
|
||||
'testFindAPI': testFindAPI,
|
||||
'testFindAPI_findupdate': testFindAPI_findupdate,
|
||||
'testFindInMultipleWebViews': testFindInMultipleWebViews,
|
||||
+ 'testFindAfterTerminate': testFindAfterTerminate,
|
||||
'testLoadDataAPI': testLoadDataAPI,
|
||||
'testLoadDataAPIAccessibleResources': testLoadDataAPIAccessibleResources,
|
||||
'testResizeEvents': testResizeEvents,
|
||||
diff --git a/extensions/browser/guest_view/web_view/web_view_find_helper.cc b/extensions/browser/guest_view/web_view/web_view_find_helper.cc
|
||||
index 1e9148687f6871dff8a394cce53771e443775679..37630dc2f0a6365bbf33e765f4d126e2962fbb2a 100644
|
||||
--- a/extensions/browser/guest_view/web_view/web_view_find_helper.cc
|
||||
+++ b/extensions/browser/guest_view/web_view/web_view_find_helper.cc
|
||||
@@ -36,12 +36,12 @@ void WebViewFindHelper::CancelAllFindSessions() {
|
||||
|
||||
void WebViewFindHelper::DispatchFindUpdateEvent(bool canceled,
|
||||
bool final_update) {
|
||||
- DCHECK(find_update_event_.get());
|
||||
+ CHECK(find_update_event_);
|
||||
base::Value::Dict args;
|
||||
find_update_event_->PrepareResults(args);
|
||||
args.Set(webview::kFindCanceled, canceled);
|
||||
args.Set(webview::kFindFinalUpdate, final_update);
|
||||
- DCHECK(webview_guest_);
|
||||
+ CHECK(webview_guest_);
|
||||
webview_guest_->DispatchEventToView(std::make_unique<GuestViewEvent>(
|
||||
webview::kEventFindReply, std::move(args)));
|
||||
}
|
||||
@@ -94,6 +94,17 @@ void WebViewFindHelper::Find(
|
||||
// Need a new request_id for each new find request.
|
||||
++current_find_request_id_;
|
||||
|
||||
+ if (current_find_session_) {
|
||||
+ const std::u16string& current_search_text =
|
||||
+ current_find_session_->search_text();
|
||||
+ bool current_match_case = current_find_session_->options()->match_case;
|
||||
+ options->new_session = current_search_text.empty() ||
|
||||
+ current_search_text != search_text ||
|
||||
+ current_match_case != options->match_case;
|
||||
+ } else {
|
||||
+ options->new_session = true;
|
||||
+ }
|
||||
+
|
||||
// Stores the find request information by request_id so that its callback
|
||||
// function can be called when the find results are available.
|
||||
std::pair<FindInfoMap::iterator, bool> insert_result =
|
||||
@@ -102,32 +113,19 @@ void WebViewFindHelper::Find(
|
||||
base::MakeRefCounted<FindInfo>(current_find_request_id_, search_text,
|
||||
options.Clone(), find_function)));
|
||||
// No duplicate insertions.
|
||||
- DCHECK(insert_result.second);
|
||||
-
|
||||
- blink::mojom::FindOptionsPtr full_options =
|
||||
- insert_result.first->second->options().Clone();
|
||||
-
|
||||
- if (current_find_session_) {
|
||||
- const std::u16string& current_search_text =
|
||||
- current_find_session_->search_text();
|
||||
- bool current_match_case = current_find_session_->options()->match_case;
|
||||
- full_options->new_session = current_search_text.empty() ||
|
||||
- current_search_text != search_text ||
|
||||
- current_match_case != options->match_case;
|
||||
- } else {
|
||||
- full_options->new_session = true;
|
||||
- }
|
||||
+ CHECK(insert_result.second);
|
||||
|
||||
// Link find requests that are a part of the same find session.
|
||||
- if (!full_options->new_session && current_find_session_) {
|
||||
- DCHECK(current_find_request_id_ != current_find_session_->request_id());
|
||||
+ if (!options->new_session && current_find_session_) {
|
||||
+ CHECK(current_find_request_id_ != current_find_session_->request_id());
|
||||
current_find_session_->AddFindNextRequest(
|
||||
insert_result.first->second->AsWeakPtr());
|
||||
}
|
||||
|
||||
// Update the current find session, if necessary.
|
||||
- if (full_options->new_session)
|
||||
+ if (options->new_session) {
|
||||
current_find_session_ = insert_result.first->second;
|
||||
+ }
|
||||
|
||||
// Handle the empty |search_text| case internally.
|
||||
if (search_text.empty()) {
|
||||
@@ -137,7 +135,7 @@ void WebViewFindHelper::Find(
|
||||
}
|
||||
|
||||
guest_web_contents->Find(current_find_request_id_, search_text,
|
||||
- std::move(full_options), /*skip_delay=*/true);
|
||||
+ std::move(options), /*skip_delay=*/true);
|
||||
}
|
||||
|
||||
void WebViewFindHelper::FindReply(int request_id,
|
||||
@@ -152,14 +150,14 @@ void WebViewFindHelper::FindReply(int request_id,
|
||||
return;
|
||||
|
||||
// This find request must be a part of an existing find session.
|
||||
- DCHECK(current_find_session_);
|
||||
+ CHECK(current_find_session_);
|
||||
|
||||
WebViewFindHelper::FindInfo* find_info = find_iterator->second.get();
|
||||
// Handle canceled find requests.
|
||||
if (find_info->options()->new_session &&
|
||||
find_info_map_.begin()->first < request_id) {
|
||||
- DCHECK_NE(current_find_session_->request_id(),
|
||||
- find_info_map_.begin()->first);
|
||||
+ CHECK_NE(current_find_session_->request_id(),
|
||||
+ find_info_map_.begin()->first);
|
||||
if (find_update_event_)
|
||||
DispatchFindUpdateEvent(true /* canceled */, true /* final_update */);
|
||||
EndFindSession(find_info_map_.begin()->first, true /* canceled */);
|
||||
@@ -174,11 +172,12 @@ void WebViewFindHelper::FindReply(int request_id,
|
||||
// Aggregate the find results.
|
||||
find_info->AggregateResults(number_of_matches, selection_rect,
|
||||
active_match_ordinal, final_update);
|
||||
- find_update_event_->AggregateResults(number_of_matches, selection_rect,
|
||||
- active_match_ordinal, final_update);
|
||||
-
|
||||
- // Propagate incremental results to the |findupdate| event.
|
||||
- DispatchFindUpdateEvent(false /* canceled */, final_update);
|
||||
+ if (find_update_event_) {
|
||||
+ find_update_event_->AggregateResults(number_of_matches, selection_rect,
|
||||
+ active_match_ordinal, final_update);
|
||||
+ // Propagate incremental results to the |findupdate| event.
|
||||
+ DispatchFindUpdateEvent(false /* canceled */, final_update);
|
||||
+ }
|
||||
|
||||
// Call the callback functions of completed find requests.
|
||||
if (final_update)
|
||||
@@ -82,7 +82,7 @@ index 33ca7a53dfb6d2c9e3a33f0065a3acd806e82e01..9fdf2e8ff0056ff407015b914c6b03eb
|
||||
const Source& GetSource(int index) const override;
|
||||
DesktopMediaList::Type GetMediaListType() const override;
|
||||
diff --git a/chrome/browser/media/webrtc/native_desktop_media_list.cc b/chrome/browser/media/webrtc/native_desktop_media_list.cc
|
||||
index 836f7683b77b3b28f33984f27649d675ddddd5b7..84135d3cf983c88fc165a0fc012200e5132a52ff 100644
|
||||
index 836f7683b77b3b28f33984f27649d675ddddd5b7..18f795dd77754e115aa66a7404a2e4075372bc5f 100644
|
||||
--- a/chrome/browser/media/webrtc/native_desktop_media_list.cc
|
||||
+++ b/chrome/browser/media/webrtc/native_desktop_media_list.cc
|
||||
@@ -141,7 +141,7 @@ BOOL CALLBACK AllHwndCollector(HWND hwnd, LPARAM param) {
|
||||
@@ -94,17 +94,20 @@ index 836f7683b77b3b28f33984f27649d675ddddd5b7..84135d3cf983c88fc165a0fc012200e5
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
@@ -451,6 +451,9 @@ void NativeDesktopMediaList::Worker::RefreshNextThumbnail() {
|
||||
@@ -451,6 +451,12 @@ void NativeDesktopMediaList::Worker::RefreshNextThumbnail() {
|
||||
FROM_HERE,
|
||||
base::BindOnce(&NativeDesktopMediaList::UpdateNativeThumbnailsFinished,
|
||||
media_list_));
|
||||
+
|
||||
+ // This call is necessary to release underlying OS screen capture mechanisms.
|
||||
+ capturer_.reset();
|
||||
+ // Skip if the source list is delegated, as the source list window will be active.
|
||||
+ if (!capturer_->GetDelegatedSourceListController()) {
|
||||
+ capturer_.reset();
|
||||
+ }
|
||||
}
|
||||
|
||||
void NativeDesktopMediaList::Worker::OnCaptureResult(
|
||||
@@ -823,6 +826,11 @@ void NativeDesktopMediaList::RefreshForVizFrameSinkWindows(
|
||||
@@ -823,6 +829,11 @@ void NativeDesktopMediaList::RefreshForVizFrameSinkWindows(
|
||||
FROM_HERE, base::BindOnce(&Worker::RefreshThumbnails,
|
||||
base::Unretained(worker_.get()),
|
||||
std::move(native_ids), thumbnail_size_));
|
||||
|
||||
43
patches/chromium/m112_fix_scopedobservation_uaf_in.patch
Normal file
43
patches/chromium/m112_fix_scopedobservation_uaf_in.patch
Normal file
@@ -0,0 +1,43 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Keren Zhu <kerenzhu@chromium.org>
|
||||
Date: Mon, 24 Apr 2023 15:36:21 +0000
|
||||
Subject: Fix ScopedObservation UaF in
|
||||
BubbleDialogDelegate::AnchorWidgetObserver
|
||||
|
||||
A ScopedObservation can outlive the aura::Window it observes, leading to
|
||||
a use-after-free error in ~ScopedObservation(). The problem occurs in
|
||||
BubbleDialogDelegate::AnchorWidgetObserver. This fix listens for
|
||||
OnWindowDestroying() and resets the observation to prevent the UaF.
|
||||
|
||||
(cherry picked from commit 72bd6a1018548ee63a2ec06d6c7714d3a8cdf8a8)
|
||||
|
||||
Bug: 1423360
|
||||
Change-Id: I742b4624b2664dea3fd97db7b399fcd15e45c8fe
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4455016
|
||||
Code-Coverage: Findit <findit-for-me@appspot.gserviceaccount.com>
|
||||
Reviewed-by: Elly Fong-Jones <ellyjones@chromium.org>
|
||||
Commit-Queue: Keren Zhu <kerenzhu@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1133511}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4466947
|
||||
Reviewed-by: Allen Bauer <kylixrd@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/5615@{#1353}
|
||||
Cr-Branched-From: 9c6408ef696e83a9936b82bbead3d41c93c82ee4-refs/heads/main@{#1109224}
|
||||
|
||||
diff --git a/ui/views/bubble/bubble_dialog_delegate_view.cc b/ui/views/bubble/bubble_dialog_delegate_view.cc
|
||||
index 83c8a188d455b0db143b4747ef79d8d72d7717ca..0fca4fa9786ae405cc9f9198f21a2aaae66f748d 100644
|
||||
--- a/ui/views/bubble/bubble_dialog_delegate_view.cc
|
||||
+++ b/ui/views/bubble/bubble_dialog_delegate_view.cc
|
||||
@@ -320,6 +320,13 @@ class BubbleDialogDelegate::AnchorWidgetObserver : public WidgetObserver,
|
||||
owner_->OnAnchorBoundsChanged();
|
||||
}
|
||||
}
|
||||
+
|
||||
+ // If the native window is closed by the OS, OnWidgetDestroying() won't
|
||||
+ // fire. Instead, OnWindowDestroying() will fire before aura::Window
|
||||
+ // destruction. See //docs/ui/views/widget_destruction.md.
|
||||
+ void OnWindowDestroying(aura::Window* window) override {
|
||||
+ window_observation_.Reset();
|
||||
+ }
|
||||
#endif
|
||||
|
||||
private:
|
||||
@@ -0,0 +1,38 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Maggie Chen <magchen@chromium.org>
|
||||
Date: Thu, 18 May 2023 00:20:34 +0000
|
||||
Subject: Fix a crash caused by calling TRACE_EVENT
|
||||
|
||||
Now use literal constant for TRACE_EVENT. Passing a pointer instead of
|
||||
string content to TRACE_EVENT causes a crash in ScopedTracer.
|
||||
|
||||
(cherry picked from commit 6f2e587807aff2306309025db1c15fc59290eb6f)
|
||||
|
||||
Bug: 1444195
|
||||
Change-Id: I02aa1148d61e7596e9293ffc866135e99991e42e
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4522164
|
||||
Reviewed-by: Sunny Sachanandani <sunnyps@chromium.org>
|
||||
Commit-Queue: Maggie Chen <magchen@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1144352}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4544885
|
||||
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
|
||||
Cr-Commit-Position: refs/branch-heads/5735@{#749}
|
||||
Cr-Branched-From: 2f562e4ddbaf79a3f3cb338b4d1bd4398d49eb67-refs/heads/main@{#1135570}
|
||||
|
||||
diff --git a/ui/gl/swap_chain_presenter.cc b/ui/gl/swap_chain_presenter.cc
|
||||
index 54a8dfdd931a22c5acfe3613204ea3a89b842d13..1e76a1a655d0f9de1dd218ad4025a6210ceafc57 100644
|
||||
--- a/ui/gl/swap_chain_presenter.cc
|
||||
+++ b/ui/gl/swap_chain_presenter.cc
|
||||
@@ -1698,10 +1698,8 @@ bool SwapChainPresenter::ReallocateSwapChain(
|
||||
}
|
||||
}
|
||||
if (!use_yuv_swap_chain) {
|
||||
- std::ostringstream trace_event_stream;
|
||||
- trace_event_stream << "SwapChainPresenter::ReallocateSwapChain::"
|
||||
- << DxgiFormatToString(swap_chain_format);
|
||||
- TRACE_EVENT0("gpu", trace_event_stream.str().c_str());
|
||||
+ TRACE_EVENT1("gpu", "SwapChainPresenter::ReallocateSwapChain::BGRA",
|
||||
+ "format", DxgiFormatToString(swap_chain_format));
|
||||
|
||||
desc.Format = swap_chain_format;
|
||||
desc.Flags = DXGI_SWAP_CHAIN_FLAG_FULLSCREEN_VIDEO;
|
||||
@@ -0,0 +1,99 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Eugene Zemtsov <eugene@chromium.org>
|
||||
Date: Wed, 21 Jun 2023 17:57:52 +0000
|
||||
Subject: webcodecs: Fix crash when changing temporal layer count in AV1
|
||||
encoder
|
||||
|
||||
(cherry picked from commit f312efac1b90117729e8961b58c643fc0eae1fbd)
|
||||
|
||||
Bug: 1447568
|
||||
Change-Id: I4ecb02ed956707571573a65ade17fdffe676b502
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4554300
|
||||
Auto-Submit: Eugene Zemtsov <eugene@chromium.org>
|
||||
Commit-Queue: Dale Curtis <dalecurtis@chromium.org>
|
||||
Reviewed-by: Dale Curtis <dalecurtis@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#1148041}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4610718
|
||||
Cr-Commit-Position: refs/branch-heads/5735@{#1360}
|
||||
Cr-Branched-From: 2f562e4ddbaf79a3f3cb338b4d1bd4398d49eb67-refs/heads/main@{#1135570}
|
||||
|
||||
diff --git a/media/video/av1_video_encoder.cc b/media/video/av1_video_encoder.cc
|
||||
index b5a075a8986cea0a07ce588330c4c0fa6e9ef593..73b072f05522c88248fc228f91fd61f18e23c352 100644
|
||||
--- a/media/video/av1_video_encoder.cc
|
||||
+++ b/media/video/av1_video_encoder.cc
|
||||
@@ -118,6 +118,7 @@ EncoderStatus SetUpAomConfig(const VideoEncoder::Options& opts,
|
||||
svc_params = {};
|
||||
svc_params.framerate_factor[0] = 1;
|
||||
svc_params.number_spatial_layers = 1;
|
||||
+ svc_params.number_temporal_layers = 1;
|
||||
if (opts.scalability_mode.has_value()) {
|
||||
switch (opts.scalability_mode.value()) {
|
||||
case SVCScalabilityMode::kL1T2:
|
||||
diff --git a/media/video/software_video_encoder_test.cc b/media/video/software_video_encoder_test.cc
|
||||
index 19d16a443e616303de0b7264eeaabaa9520b4c97..9fd17dbc726f949eccd3f4ed8a9fee4414623c0f 100644
|
||||
--- a/media/video/software_video_encoder_test.cc
|
||||
+++ b/media/video/software_video_encoder_test.cc
|
||||
@@ -610,6 +610,63 @@ TEST_P(SVCVideoEncoderTest, EncodeClipTemporalSvc) {
|
||||
}
|
||||
}
|
||||
|
||||
+TEST_P(SVCVideoEncoderTest, ChangeLayers) {
|
||||
+ VideoEncoder::Options options;
|
||||
+ options.frame_size = gfx::Size(640, 480);
|
||||
+ options.bitrate = Bitrate::ConstantBitrate(1000000u); // 1Mbps
|
||||
+ options.framerate = 25;
|
||||
+ options.scalability_mode = GetParam().scalability_mode;
|
||||
+ std::vector<scoped_refptr<VideoFrame>> frames_to_encode;
|
||||
+
|
||||
+ std::vector<VideoEncoderOutput> chunks;
|
||||
+ size_t total_frames_count = 80;
|
||||
+
|
||||
+ // Encoder all frames with 3 temporal layers and put all outputs in |chunks|
|
||||
+ auto frame_duration = base::Seconds(1.0 / options.framerate.value());
|
||||
+
|
||||
+ VideoEncoder::OutputCB encoder_output_cb = base::BindLambdaForTesting(
|
||||
+ [&](VideoEncoderOutput output,
|
||||
+ absl::optional<VideoEncoder::CodecDescription> desc) {
|
||||
+ chunks.push_back(std::move(output));
|
||||
+ });
|
||||
+
|
||||
+ encoder_->Initialize(profile_, options, /*info_cb=*/base::DoNothing(),
|
||||
+ std::move(encoder_output_cb),
|
||||
+ ValidatingStatusCB(/* quit_run_loop_on_call */ true));
|
||||
+ RunUntilQuit();
|
||||
+
|
||||
+ uint32_t color = 0x964050;
|
||||
+ for (auto frame_index = 0u; frame_index < total_frames_count; frame_index++) {
|
||||
+ auto timestamp = frame_index * frame_duration;
|
||||
+
|
||||
+ const bool reconfigure = (frame_index == total_frames_count / 2);
|
||||
+ if (reconfigure) {
|
||||
+ encoder_->Flush(ValidatingStatusCB(/* quit_run_loop_on_call */ true));
|
||||
+ RunUntilQuit();
|
||||
+
|
||||
+ // Ask encoder to change SVC mode, empty output callback
|
||||
+ // means the encoder should keep the old one.
|
||||
+ options.scalability_mode = SVCScalabilityMode::kL1T1;
|
||||
+ encoder_->ChangeOptions(
|
||||
+ options, VideoEncoder::OutputCB(),
|
||||
+ ValidatingStatusCB(/* quit_run_loop_on_call */ true));
|
||||
+ RunUntilQuit();
|
||||
+ }
|
||||
+
|
||||
+ auto frame =
|
||||
+ CreateFrame(options.frame_size, pixel_format_, timestamp, color);
|
||||
+ color = (color << 1) + frame_index;
|
||||
+ frames_to_encode.push_back(frame);
|
||||
+ encoder_->Encode(frame, VideoEncoder::EncodeOptions(false),
|
||||
+ ValidatingStatusCB(/* quit_run_loop_on_call */ true));
|
||||
+ RunUntilQuit();
|
||||
+ }
|
||||
+
|
||||
+ encoder_->Flush(ValidatingStatusCB(/* quit_run_loop_on_call */ true));
|
||||
+ RunUntilQuit();
|
||||
+ EXPECT_EQ(chunks.size(), total_frames_count);
|
||||
+}
|
||||
+
|
||||
TEST_P(H264VideoEncoderTest, ReconfigureWithResize) {
|
||||
VideoEncoder::Options options;
|
||||
gfx::Size size1(320, 200), size2(400, 240);
|
||||
51
patches/chromium/mojoipcz_copy_incoming_messages_early.patch
Normal file
51
patches/chromium/mojoipcz_copy_incoming_messages_early.patch
Normal file
@@ -0,0 +1,51 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Ken Rockot <rockot@google.com>
|
||||
Date: Mon, 3 Apr 2023 19:43:13 +0000
|
||||
Subject: MojoIpcz: Copy incoming messages early
|
||||
|
||||
Fixed: 1429720
|
||||
Change-Id: Id6cb7269d3a3e9118cc6ff1579b56e18bf911c07
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4390758
|
||||
Commit-Queue: Ken Rockot <rockot@google.com>
|
||||
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#1125510}
|
||||
|
||||
diff --git a/mojo/core/ipcz_driver/mojo_message.cc b/mojo/core/ipcz_driver/mojo_message.cc
|
||||
index 6194c0c2da8292b8229972eadf9fd6fa56ef0c86..b8372a6281ddcaf0990f55856a9e815fb9d78195 100644
|
||||
--- a/mojo/core/ipcz_driver/mojo_message.cc
|
||||
+++ b/mojo/core/ipcz_driver/mojo_message.cc
|
||||
@@ -112,23 +112,20 @@ void MojoMessage::SetParcel(ScopedIpczHandle parcel) {
|
||||
|
||||
// We always pass a parcel object in, so Begin/EndGet() must always succeed.
|
||||
DCHECK_EQ(result, IPCZ_RESULT_OK);
|
||||
+ if (num_bytes > 0) {
|
||||
+ data_storage_.reset(
|
||||
+ static_cast<uint8_t*>(base::AllocNonScannable(num_bytes)));
|
||||
+ memcpy(data_storage_.get(), data, num_bytes);
|
||||
+ } else {
|
||||
+ data_storage_.reset();
|
||||
+ }
|
||||
+ data_ = {data_storage_.get(), num_bytes};
|
||||
+ data_storage_size_ = num_bytes;
|
||||
|
||||
- // Grab only the handles.
|
||||
handles_.resize(num_handles);
|
||||
- result = GetIpczAPI().EndGet(parcel_.get(), 0, num_handles, IPCZ_NO_FLAGS,
|
||||
- nullptr, handles_.data());
|
||||
- DCHECK_EQ(result, IPCZ_RESULT_OK);
|
||||
-
|
||||
- // Now start a new two-phase get, which we'll leave active indefinitely for
|
||||
- // `data_` to reference.
|
||||
- result = GetIpczAPI().BeginGet(parcel_.get(), IPCZ_NO_FLAGS, nullptr, &data,
|
||||
- &num_bytes, &num_handles);
|
||||
+ result = GetIpczAPI().EndGet(parcel_.get(), num_bytes, num_handles,
|
||||
+ IPCZ_NO_FLAGS, nullptr, handles_.data());
|
||||
DCHECK_EQ(result, IPCZ_RESULT_OK);
|
||||
-
|
||||
- DCHECK_EQ(0u, num_handles);
|
||||
- data_ = base::make_span(static_cast<uint8_t*>(const_cast<void*>(data)),
|
||||
- num_bytes);
|
||||
-
|
||||
if (!FixUpDataPipeHandles(handles_)) {
|
||||
// The handle list was malformed. Although this is a validation error, it
|
||||
// is not safe to trigger MojoNotifyBadMessage from within MojoReadMessage,
|
||||
@@ -25,5 +25,9 @@
|
||||
|
||||
"src/electron/patches/webrtc": "src/third_party/webrtc",
|
||||
|
||||
"src/electron/patches/skia": "src/third_party/skia"
|
||||
"src/electron/patches/skia": "src/third_party/skia",
|
||||
|
||||
"src/electron/patches/dawn": "src/third_party/dawn",
|
||||
|
||||
"src/electron/patches/pdfium": "src/third_party/pdfium"
|
||||
}
|
||||
|
||||
1
patches/dawn/.patches
Normal file
1
patches/dawn/.patches
Normal file
@@ -0,0 +1 @@
|
||||
change_d3d12_descriptor_allocator_to_invalidate_submitted_descriptors.patch
|
||||
@@ -0,0 +1,42 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Brandon Jones <brandon1.jones@intel.com>
|
||||
Date: Fri, 5 May 2023 18:02:42 +0000
|
||||
Subject: Change D3D12 Descriptor Allocator To Invalidate Submitted Descriptors
|
||||
|
||||
Changes D3D12 descriptor allocator to invalidate existing descriptors
|
||||
after the descriptor heap was submitted for use. This fixes a
|
||||
synchonization issue where stale descriptors were seen as valid because
|
||||
command list execution ran long.
|
||||
|
||||
Bug: dawn:1701
|
||||
Bug: chromium:1442263
|
||||
No-Try: true
|
||||
Change-Id: Ibfd450b3be6cf91d66e8dce4ffd19ecf1a37f7f5
|
||||
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/129920
|
||||
Kokoro: Kokoro <noreply+kokoro@google.com>
|
||||
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
|
||||
Commit-Queue: Brandon1 Jones <brandon1.jones@intel.com>
|
||||
(cherry picked from commit df6cb236493da101dad79fe50d4e6df0d5d1e915)
|
||||
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/131508
|
||||
Kokoro: Austin Eng <enga@chromium.org>
|
||||
Reviewed-by: Austin Eng <enga@chromium.org>
|
||||
|
||||
diff --git a/src/dawn/native/d3d12/ShaderVisibleDescriptorAllocatorD3D12.cpp b/src/dawn/native/d3d12/ShaderVisibleDescriptorAllocatorD3D12.cpp
|
||||
index fe99a63ac9d2d082c2c23eb7940a733a9d13846a..aedb28ad58a0a972879f07a6037499f901fcf04a 100644
|
||||
--- a/src/dawn/native/d3d12/ShaderVisibleDescriptorAllocatorD3D12.cpp
|
||||
+++ b/src/dawn/native/d3d12/ShaderVisibleDescriptorAllocatorD3D12.cpp
|
||||
@@ -237,9 +237,11 @@ bool ShaderVisibleDescriptorAllocator::IsLastShaderVisibleHeapInLRUForTesting()
|
||||
|
||||
bool ShaderVisibleDescriptorAllocator::IsAllocationStillValid(
|
||||
const GPUDescriptorHeapAllocation& allocation) const {
|
||||
- // Consider valid if allocated for the pending submit and the shader visible heaps
|
||||
- // have not switched over.
|
||||
- return (allocation.GetLastUsageSerial() > mDevice->GetCompletedCommandSerial() &&
|
||||
+ // Descriptor allocations are only valid for the serial they were created for and are
|
||||
+ // re-allocated every submit. For this reason, we view any descriptors allocated prior to the
|
||||
+ // pending submit as invalid. We must also verify the descriptor heap has not switched (because
|
||||
+ // a larger descriptor heap was needed).
|
||||
+ return (allocation.GetLastUsageSerial() == mDevice->GetPendingCommandSerial() &&
|
||||
allocation.GetHeapSerial() == mHeapSerial);
|
||||
}
|
||||
|
||||
@@ -55,3 +55,4 @@ allow_embedder_to_control_codegenerationfromstringscallback.patch
|
||||
cherry-pick-09ae62b.patch
|
||||
lib_fix_broadcastchannel_initialization_location.patch
|
||||
src_allow_optional_isolation_termination_in_node.patch
|
||||
fix_do_not_resolve_electron_entrypoints.patch
|
||||
|
||||
47
patches/node/fix_do_not_resolve_electron_entrypoints.patch
Normal file
47
patches/node/fix_do_not_resolve_electron_entrypoints.patch
Normal file
@@ -0,0 +1,47 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samuel Attard <marshallofsound@electronjs.org>
|
||||
Date: Wed, 26 Jul 2023 17:03:15 -0700
|
||||
Subject: fix: do not resolve electron entrypoints
|
||||
|
||||
This wastes fs cycles and can result in strange behavior if this path actually exists on disk
|
||||
|
||||
diff --git a/lib/internal/modules/run_main.js b/lib/internal/modules/run_main.js
|
||||
index 5a50d5d6afab6e6648f72a1c0efa1df4cd80bcd9..ebc9999358ccf16689dc02322eb1aeb86355f39b 100644
|
||||
--- a/lib/internal/modules/run_main.js
|
||||
+++ b/lib/internal/modules/run_main.js
|
||||
@@ -3,6 +3,7 @@
|
||||
const {
|
||||
ObjectCreate,
|
||||
StringPrototypeEndsWith,
|
||||
+ StringPrototypeStartsWith,
|
||||
} = primordials;
|
||||
const CJSLoader = require('internal/modules/cjs/loader');
|
||||
const { Module, toRealPath, readPackageScope } = CJSLoader;
|
||||
@@ -13,6 +14,13 @@ const {
|
||||
} = require('internal/modules/esm/handle_process_exit');
|
||||
|
||||
function resolveMainPath(main) {
|
||||
+ // For built-in modules used as the main entry point we _never_
|
||||
+ // want to waste cycles resolving them to file paths on disk
|
||||
+ // that actually might exist
|
||||
+ if (typeof main === 'string' && StringPrototypeStartsWith(main, 'electron/js2c')) {
|
||||
+ return main;
|
||||
+ }
|
||||
+
|
||||
// Note extension resolution for the main entry point can be deprecated in a
|
||||
// future major.
|
||||
// Module._findPath is monkey-patchable here.
|
||||
@@ -28,6 +36,13 @@ function resolveMainPath(main) {
|
||||
}
|
||||
|
||||
function shouldUseESMLoader(mainPath) {
|
||||
+ // For built-in modules used as the main entry point we _never_
|
||||
+ // want to waste cycles resolving them to file paths on disk
|
||||
+ // that actually might exist
|
||||
+ if (typeof mainPath === 'string' && StringPrototypeStartsWith(mainPath, 'electron/js2c')) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
/**
|
||||
* @type {string[]} userLoaders A list of custom loaders registered by the user
|
||||
* (or an empty list when none have been registered).
|
||||
3
patches/pdfium/.patches
Normal file
3
patches/pdfium/.patches
Normal file
@@ -0,0 +1,3 @@
|
||||
m114_observe_cpwl_combobox_across_all_on_methods.patch
|
||||
m114_observe_widget_across_setoptionselection_calls.patch
|
||||
m114_always_check_return_code_from_cpwl_combobox_setpopup.patch
|
||||
@@ -0,0 +1,236 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tom Sepez <tsepez@chromium.org>
|
||||
Date: Fri, 19 May 2023 18:41:31 +0000
|
||||
Subject: Always check return code from CPWL_ComboBox::SetPopup().
|
||||
|
||||
Operation must not continue when false is returned.
|
||||
|
||||
Bug: chromium:1444238
|
||||
Change-Id: Ic8c29653ac185ac80b6248203649ce05d0e10f06
|
||||
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/107390
|
||||
Commit-Queue: Tom Sepez <tsepez@chromium.org>
|
||||
Reviewed-by: Lei Zhang <thestig@chromium.org>
|
||||
(cherry picked from commit 3eb3c4d77d4f9372f77aa4895b85a1d4e4755c89)
|
||||
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/107812
|
||||
|
||||
diff --git a/fpdfsdk/pwl/cpwl_combo_box.cpp b/fpdfsdk/pwl/cpwl_combo_box.cpp
|
||||
index 4cda2135433b07d641d773f184034b0f3dee7e58..f9a8550da29e7a7afca757167af257d95a67bd9f 100644
|
||||
--- a/fpdfsdk/pwl/cpwl_combo_box.cpp
|
||||
+++ b/fpdfsdk/pwl/cpwl_combo_box.cpp
|
||||
@@ -400,7 +400,9 @@ bool CPWL_ComboBox::OnChar(uint16_t nChar, Mask<FWL_EVENTFLAG> nFlag) {
|
||||
// options.
|
||||
switch (nChar) {
|
||||
case pdfium::ascii::kReturn:
|
||||
- SetPopup(!IsPopup());
|
||||
+ if (!SetPopup(!IsPopup())) {
|
||||
+ return false;
|
||||
+ }
|
||||
SetSelectText();
|
||||
return true;
|
||||
case pdfium::ascii::kSpace:
|
||||
@@ -408,7 +410,9 @@ bool CPWL_ComboBox::OnChar(uint16_t nChar, Mask<FWL_EVENTFLAG> nFlag) {
|
||||
// editable
|
||||
if (!HasFlag(PCBS_ALLOWCUSTOMTEXT)) {
|
||||
if (!IsPopup()) {
|
||||
- SetPopup(/*bPopUp=*/true);
|
||||
+ if (!SetPopup(/*bPopUp=*/true)) {
|
||||
+ return false;
|
||||
+ }
|
||||
SetSelectText();
|
||||
}
|
||||
return true;
|
||||
@@ -438,7 +442,7 @@ bool CPWL_ComboBox::OnChar(uint16_t nChar, Mask<FWL_EVENTFLAG> nFlag) {
|
||||
|
||||
void CPWL_ComboBox::NotifyLButtonDown(CPWL_Wnd* child, const CFX_PointF& pos) {
|
||||
if (child == m_pButton) {
|
||||
- SetPopup(!m_bPopup);
|
||||
+ (void)SetPopup(!m_bPopup);
|
||||
// Note, |this| may no longer be viable at this point. If more work needs to
|
||||
// be done, check the return value of SetPopup().
|
||||
}
|
||||
@@ -451,7 +455,7 @@ void CPWL_ComboBox::NotifyLButtonUp(CPWL_Wnd* child, const CFX_PointF& pos) {
|
||||
SetSelectText();
|
||||
SelectAllText();
|
||||
m_pEdit->SetFocus();
|
||||
- SetPopup(false);
|
||||
+ (void)SetPopup(false);
|
||||
// Note, |this| may no longer be viable at this point. If more work needs to
|
||||
// be done, check the return value of SetPopup().
|
||||
}
|
||||
diff --git a/fpdfsdk/pwl/cpwl_combo_box.h b/fpdfsdk/pwl/cpwl_combo_box.h
|
||||
index 480da52d7a65538dee190e2a609215f9c424bb38..b1ac3d9e8ac29e9433330ff86df7ef4b71a3fabd 100644
|
||||
--- a/fpdfsdk/pwl/cpwl_combo_box.h
|
||||
+++ b/fpdfsdk/pwl/cpwl_combo_box.h
|
||||
@@ -64,7 +64,7 @@ class CPWL_ComboBox final : public CPWL_Wnd {
|
||||
void CreateListBox(const CreateParams& cp);
|
||||
|
||||
// Returns |true| iff this instance is still allocated.
|
||||
- bool SetPopup(bool bPopup);
|
||||
+ [[nodiscard]] bool SetPopup(bool bPopup);
|
||||
|
||||
UnownedPtr<CPWL_Edit> m_pEdit;
|
||||
UnownedPtr<CPWL_CBButton> m_pButton;
|
||||
diff --git a/testing/resources/javascript/xfa_specific/bug_1444238.evt b/testing/resources/javascript/xfa_specific/bug_1444238.evt
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..adca35aa0d756e76eb395c5d60ba41b86c3d0090
|
||||
--- /dev/null
|
||||
+++ b/testing/resources/javascript/xfa_specific/bug_1444238.evt
|
||||
@@ -0,0 +1,3 @@
|
||||
+mousedown,left,91,539
|
||||
+mouseup,left,91,539
|
||||
+charcode,32
|
||||
diff --git a/testing/resources/javascript/xfa_specific/bug_1444238.in b/testing/resources/javascript/xfa_specific/bug_1444238.in
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..675178c9446b0181c3633a4b5c9bc664bb4c127d
|
||||
--- /dev/null
|
||||
+++ b/testing/resources/javascript/xfa_specific/bug_1444238.in
|
||||
@@ -0,0 +1,149 @@
|
||||
+{{header}}
|
||||
+{{object 1 0}} <<
|
||||
+ /Type /Catalog
|
||||
+ /Pages 2 0 R
|
||||
+ /AcroForm 4 0 R
|
||||
+ /OpenAction 40 0 R
|
||||
+>>
|
||||
+endobj
|
||||
+{{object 2 0}} <<
|
||||
+ /Type /Pages
|
||||
+ /Count 2
|
||||
+ /Kids [
|
||||
+ 32 0 R
|
||||
+ 34 0 R
|
||||
+ ]
|
||||
+>>
|
||||
+endobj
|
||||
+% Forms
|
||||
+{{object 4 0}} <<
|
||||
+ /XFA 43 0 R
|
||||
+ /Fields [
|
||||
+ 10 0 R
|
||||
+ 11 0 R
|
||||
+ ]
|
||||
+>>
|
||||
+endobj
|
||||
+% Fields
|
||||
+{{object 10 0}} <<
|
||||
+ /Type /Annot
|
||||
+ /Subtype /Widget
|
||||
+ /FT /Tx
|
||||
+ /T (MyField5)
|
||||
+ /V (myfield_5)
|
||||
+ /Rect [0 500 600 600]
|
||||
+>>
|
||||
+% Fields
|
||||
+{{object 11 0}} <<
|
||||
+ /T (MyField3)
|
||||
+ /Parent 4 0 R
|
||||
+ /Kids [12 0 R]
|
||||
+ /Opt [(a) (b) (c) (d)]
|
||||
+ /V [(a) (b) (c)]
|
||||
+>>
|
||||
+endobj
|
||||
+% Fields
|
||||
+{{object 12 0}} <<
|
||||
+ /Type /Annot
|
||||
+ /Subtype /Widget
|
||||
+ /FT /Ch
|
||||
+ /Ff 131072
|
||||
+ /Parent 11 0 R
|
||||
+ /Kids [13 0 R]
|
||||
+>>
|
||||
+endobj
|
||||
+% Fields
|
||||
+{{object 13 0}} <<
|
||||
+ /Type /Annot
|
||||
+ /Subtype /Widget
|
||||
+ /Parent 12 0 R
|
||||
+ /Rect [0 400 600 600]
|
||||
+>>
|
||||
+endobj
|
||||
+% Fields
|
||||
+{{object 14 0}} <<
|
||||
+ /Type /Annot
|
||||
+ /Subtype /Widget
|
||||
+ /Parent 12 0 R
|
||||
+ /Rect [100 400 500 500]
|
||||
+>>
|
||||
+endobj
|
||||
+% Page number 2.
|
||||
+{{object 32 0}} <<
|
||||
+ /Type /Page
|
||||
+ /Parent 2 0 R
|
||||
+ /MediaBox [0 0 612 792]
|
||||
+ /Annots [13 0 R]
|
||||
+
|
||||
+>>
|
||||
+endobj
|
||||
+{{object 34 0}} <<
|
||||
+ /Type /Page
|
||||
+ /Parent 2 0 R
|
||||
+ /MediaBox [0 0 612 792]
|
||||
+ /Annots [10 0 R]
|
||||
+>>
|
||||
+endobj
|
||||
+% Document JS Action
|
||||
+{{object 40 0}} <<
|
||||
+ /Type /Action
|
||||
+ /S /JavaScript
|
||||
+ /JS 41 0 R
|
||||
+>>
|
||||
+endobj
|
||||
+% JS program to exexute
|
||||
+{{object 41 0}} <<
|
||||
+>>
|
||||
+stream
|
||||
+var f5 = this.getField("MyField5");
|
||||
+var f3 = this.getField("MyField3");
|
||||
+f3.setFocus();
|
||||
+this.__defineGetter__("pageNum",function o(){f5.setFocus(); f3.borderStyle="dashed"; f3.setFocus();});
|
||||
+endstream
|
||||
+endobj
|
||||
+{{object 43 0}} <<
|
||||
+ {{streamlen}}
|
||||
+>>
|
||||
+stream
|
||||
+<?xml version="1.0" encoding="UTF-8"?>
|
||||
+<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
|
||||
+<config></config>
|
||||
+<template xmlns="http://www.xfa.org/schema/xfa-template/2.8/">
|
||||
+ <subform layout="tb" locale="en_US">
|
||||
+ <pageSet>
|
||||
+ <pageArea id="Page1" name="Page1">
|
||||
+ <contentArea h="268.939mm" w="203.2mm" x="6.35mm" y="6.35mm"/>
|
||||
+ <medium long="792pt" short="612pt" stock="default"/>
|
||||
+ </pageArea>
|
||||
+ </pageSet>
|
||||
+ <field h="9.0001mm" name="MyField3" w="47.625mm" x="120mm" y="120mm">
|
||||
+ <ui>
|
||||
+ <choiceList open="onEntry">
|
||||
+ <border>
|
||||
+ <edge/>
|
||||
+ </border>
|
||||
+ </choiceList>
|
||||
+ </ui>
|
||||
+ <items save="1">
|
||||
+ <text>apples</text>
|
||||
+ <text>bananas</text>
|
||||
+ <text>pears</text>
|
||||
+ </items>
|
||||
+ <value>
|
||||
+ <text>apples</text>
|
||||
+ </value>
|
||||
+ <event activity="preOpen">
|
||||
+ <script contentType="application/x-javascript">
|
||||
+ var aa = this.pageNum;
|
||||
+ </script>
|
||||
+ </event>
|
||||
+ </field>
|
||||
+ </subform>
|
||||
+</template>
|
||||
+</xdp:xdp>
|
||||
+endstream
|
||||
+endobj
|
||||
+{{xref}}
|
||||
+{{trailer}}
|
||||
+{{startxref}}
|
||||
+%%EOF
|
||||
@@ -0,0 +1,213 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tom Sepez <tsepez@chromium.org>
|
||||
Date: Fri, 19 May 2023 20:05:10 +0000
|
||||
Subject: Observe CPWL_ComboBox across all On* methods
|
||||
|
||||
Bug: chromium:1445426
|
||||
Change-Id: I1d7ebf66fe170ca016c27a0df3ac4574e75c763c
|
||||
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/107650
|
||||
Reviewed-by: Lei Zhang <thestig@chromium.org>
|
||||
Commit-Queue: Tom Sepez <tsepez@chromium.org>
|
||||
(cherry picked from commit 29c665ea4c61b089746c3f502c30fcb5f4b11486)
|
||||
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/107811
|
||||
|
||||
diff --git a/fpdfsdk/pwl/cpwl_combo_box.cpp b/fpdfsdk/pwl/cpwl_combo_box.cpp
|
||||
index dde76521a7c15070c1245938063830a003986a69..4cda2135433b07d641d773f184034b0f3dee7e58 100644
|
||||
--- a/fpdfsdk/pwl/cpwl_combo_box.cpp
|
||||
+++ b/fpdfsdk/pwl/cpwl_combo_box.cpp
|
||||
@@ -339,31 +339,42 @@ bool CPWL_ComboBox::OnKeyDown(FWL_VKEYCODE nKeyCode,
|
||||
if (!m_pEdit)
|
||||
return false;
|
||||
|
||||
+ ObservedPtr<CPWL_Wnd> thisObserved(this);
|
||||
m_nSelectItem = -1;
|
||||
|
||||
switch (nKeyCode) {
|
||||
case FWL_VKEY_Up:
|
||||
if (m_pList->GetCurSel() > 0) {
|
||||
- if (GetFillerNotify()->OnPopupPreOpen(GetAttachedData(), nFlag))
|
||||
+ if (GetFillerNotify()->OnPopupPreOpen(GetAttachedData(), nFlag) ||
|
||||
+ !thisObserved) {
|
||||
return false;
|
||||
- if (GetFillerNotify()->OnPopupPostOpen(GetAttachedData(), nFlag))
|
||||
+ }
|
||||
+ if (GetFillerNotify()->OnPopupPostOpen(GetAttachedData(), nFlag) ||
|
||||
+ !thisObserved) {
|
||||
return false;
|
||||
+ }
|
||||
if (m_pList->IsMovementKey(nKeyCode)) {
|
||||
- if (m_pList->OnMovementKeyDown(nKeyCode, nFlag))
|
||||
+ if (m_pList->OnMovementKeyDown(nKeyCode, nFlag) || !thisObserved) {
|
||||
return false;
|
||||
+ }
|
||||
SetSelectText();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
case FWL_VKEY_Down:
|
||||
if (m_pList->GetCurSel() < m_pList->GetCount() - 1) {
|
||||
- if (GetFillerNotify()->OnPopupPreOpen(GetAttachedData(), nFlag))
|
||||
+ if (GetFillerNotify()->OnPopupPreOpen(GetAttachedData(), nFlag) ||
|
||||
+ !thisObserved) {
|
||||
return false;
|
||||
- if (GetFillerNotify()->OnPopupPostOpen(GetAttachedData(), nFlag))
|
||||
+ }
|
||||
+ if (GetFillerNotify()->OnPopupPostOpen(GetAttachedData(), nFlag) ||
|
||||
+ !thisObserved) {
|
||||
return false;
|
||||
+ }
|
||||
if (m_pList->IsMovementKey(nKeyCode)) {
|
||||
- if (m_pList->OnMovementKeyDown(nKeyCode, nFlag))
|
||||
+ if (m_pList->OnMovementKeyDown(nKeyCode, nFlag) || !thisObserved) {
|
||||
return false;
|
||||
+ }
|
||||
SetSelectText();
|
||||
}
|
||||
}
|
||||
@@ -411,10 +422,15 @@ bool CPWL_ComboBox::OnChar(uint16_t nChar, Mask<FWL_EVENTFLAG> nFlag) {
|
||||
if (HasFlag(PCBS_ALLOWCUSTOMTEXT))
|
||||
return m_pEdit->OnChar(nChar, nFlag);
|
||||
|
||||
- if (GetFillerNotify()->OnPopupPreOpen(GetAttachedData(), nFlag))
|
||||
+ ObservedPtr<CPWL_Wnd> thisObserved(this);
|
||||
+ if (GetFillerNotify()->OnPopupPreOpen(GetAttachedData(), nFlag) ||
|
||||
+ !thisObserved) {
|
||||
return false;
|
||||
- if (GetFillerNotify()->OnPopupPostOpen(GetAttachedData(), nFlag))
|
||||
+ }
|
||||
+ if (GetFillerNotify()->OnPopupPostOpen(GetAttachedData(), nFlag) ||
|
||||
+ !thisObserved) {
|
||||
return false;
|
||||
+ }
|
||||
if (!m_pList->IsChar(nChar, nFlag))
|
||||
return false;
|
||||
return m_pList->OnCharNotify(nChar, nFlag);
|
||||
diff --git a/testing/resources/javascript/bug_1445426.evt b/testing/resources/javascript/bug_1445426.evt
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..265e85b0471b33509568238ccae30d2395b4b4ab
|
||||
--- /dev/null
|
||||
+++ b/testing/resources/javascript/bug_1445426.evt
|
||||
@@ -0,0 +1,3 @@
|
||||
+mousedown,left,202,697
|
||||
+mouseup,left,202,697
|
||||
+keycode,40
|
||||
diff --git a/testing/resources/javascript/bug_1445426.in b/testing/resources/javascript/bug_1445426.in
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..1483da72f5759e9f2c8fdb538d5c6fa0cd1611c5
|
||||
--- /dev/null
|
||||
+++ b/testing/resources/javascript/bug_1445426.in
|
||||
@@ -0,0 +1,114 @@
|
||||
+{{header}}
|
||||
+{{object 1 0}} <<
|
||||
+ /Type /Catalog
|
||||
+ /Pages 2 0 R
|
||||
+ /AcroForm 4 0 R
|
||||
+ /OpenAction 40 0 R
|
||||
+>>
|
||||
+endobj
|
||||
+{{object 2 0}} <<
|
||||
+ /Type /Pages
|
||||
+ /Count 2
|
||||
+ /Kids [
|
||||
+ 32 0 R
|
||||
+ 34 0 R
|
||||
+ ]
|
||||
+>>
|
||||
+endobj
|
||||
+% Forms
|
||||
+{{object 4 0}} <<
|
||||
+ /Fields [
|
||||
+ 10 0 R
|
||||
+ 11 0 R
|
||||
+ ]
|
||||
+>>
|
||||
+endobj
|
||||
+% Fields
|
||||
+{{object 10 0}} <<
|
||||
+ /Type /Annot
|
||||
+ /Subtype /Widget
|
||||
+ /FT /Tx
|
||||
+ /T (Field_TextEdit)
|
||||
+ /Rect [0 0 612 792]
|
||||
+>>
|
||||
+{{object 11 0}} <<
|
||||
+ /T (Field_ComboBox)
|
||||
+ /Parent 4 0 R
|
||||
+ /Kids [12 0 R]
|
||||
+ /Opt [(a) (b) (c) (d)]
|
||||
+ /V [(a)]
|
||||
+>>
|
||||
+endobj
|
||||
+{{object 12 0}} <<
|
||||
+ /Type /Annot
|
||||
+ /Subtype /Widget
|
||||
+ /FT /Ch
|
||||
+ /Ff 131072
|
||||
+ /Parent 11 0 R
|
||||
+ /Kids [13 0 R]
|
||||
+>>
|
||||
+endobj
|
||||
+{{object 13 0}} <<
|
||||
+ /Parent 12 0 R
|
||||
+ /Type /Annot
|
||||
+ /Subtype /Widget
|
||||
+ /Rect [0 0 612 792]
|
||||
+ /AA << /K 20 0 R >>
|
||||
+>>
|
||||
+endobj
|
||||
+% Pages
|
||||
+{{object 32 0}} <<
|
||||
+ /Type /Page
|
||||
+ /Parent 2 0 R
|
||||
+ /MediaBox [0 0 612 792]
|
||||
+ /Annots [13 0 R]
|
||||
+
|
||||
+>>
|
||||
+endobj
|
||||
+{{object 34 0}} <<
|
||||
+ /Type /Page
|
||||
+ /Parent 2 0 R
|
||||
+ /MediaBox [0 0 612 792]
|
||||
+ /Annots [10 0 R]
|
||||
+>>
|
||||
+endobj
|
||||
+% Document JS Action
|
||||
+{{object 40 0}} <<
|
||||
+ /Type /Action
|
||||
+ /S /JavaScript
|
||||
+ /JS 41 0 R
|
||||
+>>
|
||||
+endobj
|
||||
+% JS program to exexute
|
||||
+{{object 41 0}} <<
|
||||
+ {{streamlen}}
|
||||
+>>
|
||||
+stream
|
||||
+var field_text = this.getField("Field_TextEdit");
|
||||
+var field_combobox = this.getField("Field_ComboBox");
|
||||
+field_combobox.setFocus();
|
||||
+this.__defineGetter__("filesize", function new_getter(){
|
||||
+ field_text.setFocus();
|
||||
+ field_combobox.borderStyle="dashed";
|
||||
+ field_combobox.setFocus();
|
||||
+ });
|
||||
+endstream
|
||||
+endobj
|
||||
+% OpenAction action
|
||||
+{{object 20 0}} <<
|
||||
+ /S /JavaScript
|
||||
+ /JS 21 0 R
|
||||
+>>
|
||||
+endobj
|
||||
+% JS program to exexute
|
||||
+{{object 21 0}} <<
|
||||
+ {{streamlen}}
|
||||
+>>
|
||||
+stream
|
||||
+var t = this.filesize;
|
||||
+endstream
|
||||
+endobj
|
||||
+{{xref}}
|
||||
+{{trailer}}
|
||||
+{{startxref}}
|
||||
+%%EOF
|
||||
@@ -0,0 +1,40 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tom Sepez <tsepez@chromium.org>
|
||||
Date: Thu, 18 May 2023 18:37:17 +0000
|
||||
Subject: Observe widget across SetOptionSelection() calls.
|
||||
|
||||
Call may re-enter JavaScript.
|
||||
|
||||
Bug: chromium:1444581
|
||||
Change-Id: Id7a2f17b3b81f822ca8f4496ac08c19b7794c48a
|
||||
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/107394
|
||||
Commit-Queue: Tom Sepez <tsepez@chromium.org>
|
||||
Reviewed-by: Lei Zhang <thestig@chromium.org>
|
||||
(cherry picked from commit a9ff918a86d700c3bdf9b5820faed35490c0cd25)
|
||||
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/107735
|
||||
Auto-Submit: Tom Sepez <tsepez@chromium.org>
|
||||
|
||||
diff --git a/fpdfsdk/formfiller/cffl_listbox.cpp b/fpdfsdk/formfiller/cffl_listbox.cpp
|
||||
index ea119ec093c748c6c8bfb7b3c31b4ae97f959908..31134bb1e576003cc377eb90a61898f8097f080c 100644
|
||||
--- a/fpdfsdk/formfiller/cffl_listbox.cpp
|
||||
+++ b/fpdfsdk/formfiller/cffl_listbox.cpp
|
||||
@@ -116,11 +116,18 @@ void CFFL_ListBox::SaveData(const CPDFSDK_PageView* pPageView) {
|
||||
}
|
||||
if (m_pWidget->GetFieldFlags() & pdfium::form_flags::kChoiceMultiSelect) {
|
||||
for (int32_t i = 0, sz = pListBox->GetCount(); i < sz; i++) {
|
||||
- if (pListBox->IsItemSelected(i))
|
||||
+ if (pListBox->IsItemSelected(i)) {
|
||||
m_pWidget->SetOptionSelection(i);
|
||||
+ if (!observed_box) {
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
} else {
|
||||
m_pWidget->SetOptionSelection(pListBox->GetCurSel());
|
||||
+ if (!observed_box) {
|
||||
+ return;
|
||||
+ }
|
||||
}
|
||||
ObservedPtr<CPDFSDK_Widget> observed_widget(m_pWidget);
|
||||
ObservedPtr<CFFL_ListBox> observed_this(this);
|
||||
@@ -10,3 +10,13 @@ force_cppheapcreateparams_to_be_noncopyable.patch
|
||||
chore_allow_customizing_microtask_policy_per_context.patch
|
||||
cherry-pick-c605df24af3c.patch
|
||||
cherry-pick-f4b66ae451c2.patch
|
||||
cherry-pick-2c8a019f39d2.patch
|
||||
cherry-pick-bb90b9cfcbca.patch
|
||||
merged_ic_fix_store_handler_selection_for_arguments_objects.patch
|
||||
cherry-pick-73af1a19a901.patch
|
||||
cherry-pick-3b0607d14060.patch
|
||||
cherry-pick-9c6dfc733fce.patch
|
||||
cherry-pick-2e76270cf65e.patch
|
||||
utf-8_q_shared-struct_20fix_20using_20shared_20objects_20as.patch
|
||||
merged_runtime_set_instance_prototypes_directly_on_maps.patch
|
||||
merged_compiler_stackcheck_can_have_side_effects.patch
|
||||
|
||||
300
patches/v8/cherry-pick-2c8a019f39d2.patch
Normal file
300
patches/v8/cherry-pick-2c8a019f39d2.patch
Normal file
@@ -0,0 +1,300 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shu-yu Guo <syg@chromium.org>
|
||||
Date: Wed, 26 Apr 2023 10:56:03 -0700
|
||||
Subject: Fix clobbered register in global Unicode special case
|
||||
|
||||
Bug: chromium:1439691
|
||||
Change-Id: I53f22f484b226b5ad3eb9ffef8a9f44fe962beba
|
||||
Fixed: chromium:1439691
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4477629
|
||||
Reviewed-by: Jakob Linke <jgruber@chromium.org>
|
||||
Commit-Queue: Shu-yu Guo <syg@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#87288}
|
||||
|
||||
diff --git a/src/regexp/arm/regexp-macro-assembler-arm.cc b/src/regexp/arm/regexp-macro-assembler-arm.cc
|
||||
index 2658068b6f94b97f024b1400c8c0b20eefdc5143..5de110c8495ef5bd261df92ca8f459c5f0cc7e5b 100644
|
||||
--- a/src/regexp/arm/regexp-macro-assembler-arm.cc
|
||||
+++ b/src/regexp/arm/regexp-macro-assembler-arm.cc
|
||||
@@ -877,19 +877,18 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
|
||||
__ add(r2, r2, Operand(num_saved_registers_ * kPointerSize));
|
||||
__ str(r2, MemOperand(frame_pointer(), kRegisterOutput));
|
||||
|
||||
- // Prepare r0 to initialize registers with its value in the next run.
|
||||
- __ ldr(r0, MemOperand(frame_pointer(), kStringStartMinusOne));
|
||||
-
|
||||
// Restore the original regexp stack pointer value (effectively, pop the
|
||||
// stored base pointer).
|
||||
PopRegExpBasePointer(backtrack_stackpointer(), r2);
|
||||
|
||||
+ Label reload_string_start_minus_one;
|
||||
+
|
||||
if (global_with_zero_length_check()) {
|
||||
// Special case for zero-length matches.
|
||||
// r4: capture start index
|
||||
__ cmp(current_input_offset(), r4);
|
||||
// Not a zero-length match, restart.
|
||||
- __ b(ne, &load_char_start_regexp);
|
||||
+ __ b(ne, &reload_string_start_minus_one);
|
||||
// Offset from the end is zero if we already reached the end.
|
||||
__ cmp(current_input_offset(), Operand::Zero());
|
||||
__ b(eq, &exit_label_);
|
||||
@@ -901,6 +900,11 @@ Handle<HeapObject> RegExpMacroAssemblerARM::GetCode(Handle<String> source) {
|
||||
if (global_unicode()) CheckNotInSurrogatePair(0, &advance);
|
||||
}
|
||||
|
||||
+ __ bind(&reload_string_start_minus_one);
|
||||
+ // Prepare r0 to initialize registers with its value in the next run.
|
||||
+ // Must be immediately before the jump to avoid clobbering.
|
||||
+ __ ldr(r0, MemOperand(frame_pointer(), kStringStartMinusOne));
|
||||
+
|
||||
__ b(&load_char_start_regexp);
|
||||
} else {
|
||||
__ mov(r0, Operand(SUCCESS));
|
||||
diff --git a/src/regexp/ia32/regexp-macro-assembler-ia32.cc b/src/regexp/ia32/regexp-macro-assembler-ia32.cc
|
||||
index 600234542042ce9a06ceb3b415fece83f6f271bf..6c3df5da7d6c28619902b20419c9cf437325c1d1 100644
|
||||
--- a/src/regexp/ia32/regexp-macro-assembler-ia32.cc
|
||||
+++ b/src/regexp/ia32/regexp-macro-assembler-ia32.cc
|
||||
@@ -915,19 +915,18 @@ Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
|
||||
__ add(Operand(ebp, kRegisterOutput),
|
||||
Immediate(num_saved_registers_ * kSystemPointerSize));
|
||||
|
||||
- // Prepare eax to initialize registers with its value in the next run.
|
||||
- __ mov(eax, Operand(ebp, kStringStartMinusOne));
|
||||
-
|
||||
// Restore the original regexp stack pointer value (effectively, pop the
|
||||
// stored base pointer).
|
||||
PopRegExpBasePointer(backtrack_stackpointer(), ebx);
|
||||
|
||||
+ Label reload_string_start_minus_one;
|
||||
+
|
||||
if (global_with_zero_length_check()) {
|
||||
// Special case for zero-length matches.
|
||||
// edx: capture start index
|
||||
__ cmp(edi, edx);
|
||||
// Not a zero-length match, restart.
|
||||
- __ j(not_equal, &load_char_start_regexp);
|
||||
+ __ j(not_equal, &reload_string_start_minus_one);
|
||||
// edi (offset from the end) is zero if we already reached the end.
|
||||
__ test(edi, edi);
|
||||
__ j(zero, &exit_label_, Label::kNear);
|
||||
@@ -941,6 +940,12 @@ Handle<HeapObject> RegExpMacroAssemblerIA32::GetCode(Handle<String> source) {
|
||||
}
|
||||
if (global_unicode()) CheckNotInSurrogatePair(0, &advance);
|
||||
}
|
||||
+
|
||||
+ __ bind(&reload_string_start_minus_one);
|
||||
+ // Prepare eax to initialize registers with its value in the next run.
|
||||
+ // Must be immediately before the jump to avoid clobbering.
|
||||
+ __ mov(eax, Operand(ebp, kStringStartMinusOne));
|
||||
+
|
||||
__ jmp(&load_char_start_regexp);
|
||||
} else {
|
||||
__ mov(eax, Immediate(SUCCESS));
|
||||
diff --git a/src/regexp/loong64/regexp-macro-assembler-loong64.cc b/src/regexp/loong64/regexp-macro-assembler-loong64.cc
|
||||
index 35fd95bd0f2d210419b4057ced6e16ffd5aec051..d5c52b4134ccbfecef85328e181dae1bbda7bf63 100644
|
||||
--- a/src/regexp/loong64/regexp-macro-assembler-loong64.cc
|
||||
+++ b/src/regexp/loong64/regexp-macro-assembler-loong64.cc
|
||||
@@ -850,18 +850,17 @@ Handle<HeapObject> RegExpMacroAssemblerLOONG64::GetCode(Handle<String> source) {
|
||||
__ Add_d(a2, a2, num_saved_registers_ * kIntSize);
|
||||
__ St_d(a2, MemOperand(frame_pointer(), kRegisterOutput));
|
||||
|
||||
- // Prepare a0 to initialize registers with its value in the next run.
|
||||
- __ Ld_d(a0, MemOperand(frame_pointer(), kStringStartMinusOne));
|
||||
-
|
||||
// Restore the original regexp stack pointer value (effectively, pop the
|
||||
// stored base pointer).
|
||||
PopRegExpBasePointer(backtrack_stackpointer(), a2);
|
||||
|
||||
+ Label reload_string_start_minus_one;
|
||||
+
|
||||
if (global_with_zero_length_check()) {
|
||||
// Special case for zero-length matches.
|
||||
// t3: capture start index
|
||||
// Not a zero-length match, restart.
|
||||
- __ Branch(&load_char_start_regexp, ne, current_input_offset(),
|
||||
+ __ Branch(&reload_string_start_minus_one, ne, current_input_offset(),
|
||||
Operand(t3));
|
||||
// Offset from the end is zero if we already reached the end.
|
||||
__ Branch(&exit_label_, eq, current_input_offset(),
|
||||
@@ -874,6 +873,11 @@ Handle<HeapObject> RegExpMacroAssemblerLOONG64::GetCode(Handle<String> source) {
|
||||
if (global_unicode()) CheckNotInSurrogatePair(0, &advance);
|
||||
}
|
||||
|
||||
+ __ bind(&reload_string_start_minus_one);
|
||||
+ // Prepare a0 to initialize registers with its value in the next run.
|
||||
+ // Must be immediately before the jump to avoid clobbering.
|
||||
+ __ Ld_d(a0, MemOperand(frame_pointer(), kStringStartMinusOne));
|
||||
+
|
||||
__ Branch(&load_char_start_regexp);
|
||||
} else {
|
||||
__ li(a0, Operand(SUCCESS));
|
||||
diff --git a/src/regexp/mips64/regexp-macro-assembler-mips64.cc b/src/regexp/mips64/regexp-macro-assembler-mips64.cc
|
||||
index 456e166adefc72b7bcaa9245798f3885c2a4c2e7..6ee4c709cf96f68a32a0b3c1ebdc42817293bf29 100644
|
||||
--- a/src/regexp/mips64/regexp-macro-assembler-mips64.cc
|
||||
+++ b/src/regexp/mips64/regexp-macro-assembler-mips64.cc
|
||||
@@ -898,19 +898,18 @@ Handle<HeapObject> RegExpMacroAssemblerMIPS::GetCode(Handle<String> source) {
|
||||
__ Daddu(a2, a2, num_saved_registers_ * kIntSize);
|
||||
__ Sd(a2, MemOperand(frame_pointer(), kRegisterOutput));
|
||||
|
||||
- // Prepare a0 to initialize registers with its value in the next run.
|
||||
- __ Ld(a0, MemOperand(frame_pointer(), kStringStartMinusOne));
|
||||
-
|
||||
// Restore the original regexp stack pointer value (effectively, pop the
|
||||
// stored base pointer).
|
||||
PopRegExpBasePointer(backtrack_stackpointer(), a2);
|
||||
|
||||
+ Label reload_string_start_minus_one;
|
||||
+
|
||||
if (global_with_zero_length_check()) {
|
||||
// Special case for zero-length matches.
|
||||
// t3: capture start index
|
||||
// Not a zero-length match, restart.
|
||||
- __ Branch(
|
||||
- &load_char_start_regexp, ne, current_input_offset(), Operand(t3));
|
||||
+ __ Branch(&reload_string_start_minus_one, ne, current_input_offset(),
|
||||
+ Operand(t3));
|
||||
// Offset from the end is zero if we already reached the end.
|
||||
__ Branch(&exit_label_, eq, current_input_offset(),
|
||||
Operand(zero_reg));
|
||||
@@ -922,6 +921,11 @@ Handle<HeapObject> RegExpMacroAssemblerMIPS::GetCode(Handle<String> source) {
|
||||
if (global_unicode()) CheckNotInSurrogatePair(0, &advance);
|
||||
}
|
||||
|
||||
+ __ bind(&reload_string_start_minus_one);
|
||||
+ // Prepare a0 to initialize registers with its value in the next run.
|
||||
+ // Must be immediately before the jump to avoid clobbering.
|
||||
+ __ Ld(a0, MemOperand(frame_pointer(), kStringStartMinusOne));
|
||||
+
|
||||
__ Branch(&load_char_start_regexp);
|
||||
} else {
|
||||
__ li(v0, Operand(SUCCESS));
|
||||
diff --git a/src/regexp/riscv/regexp-macro-assembler-riscv.cc b/src/regexp/riscv/regexp-macro-assembler-riscv.cc
|
||||
index c8f3eb551e05805003d30a1786acdd9aab96d906..7f79b1e02b145e56ac49d231f31555039c959c05 100644
|
||||
--- a/src/regexp/riscv/regexp-macro-assembler-riscv.cc
|
||||
+++ b/src/regexp/riscv/regexp-macro-assembler-riscv.cc
|
||||
@@ -869,18 +869,17 @@ Handle<HeapObject> RegExpMacroAssemblerRISCV::GetCode(Handle<String> source) {
|
||||
__ AddWord(a2, a2, num_saved_registers_ * kIntSize);
|
||||
__ StoreWord(a2, MemOperand(frame_pointer(), kRegisterOutput));
|
||||
|
||||
- // Prepare a0 to initialize registers with its value in the next run.
|
||||
- __ LoadWord(a0, MemOperand(frame_pointer(), kStringStartMinusOne));
|
||||
-
|
||||
// Restore the original regexp stack pointer value (effectively, pop the
|
||||
// stored base pointer).
|
||||
PopRegExpBasePointer(backtrack_stackpointer(), a2);
|
||||
|
||||
+ Label reload_string_start_minus_one;
|
||||
+
|
||||
if (global_with_zero_length_check()) {
|
||||
// Special case for zero-length matches.
|
||||
// s3: capture start index
|
||||
// Not a zero-length match, restart.
|
||||
- __ Branch(&load_char_start_regexp, ne, current_input_offset(),
|
||||
+ __ Branch(&reload_string_start_minus_one, ne, current_input_offset(),
|
||||
Operand(s3));
|
||||
// Offset from the end is zero if we already reached the end.
|
||||
__ Branch(&exit_label_, eq, current_input_offset(),
|
||||
@@ -893,6 +892,12 @@ Handle<HeapObject> RegExpMacroAssemblerRISCV::GetCode(Handle<String> source) {
|
||||
if (global_unicode()) CheckNotInSurrogatePair(0, &advance);
|
||||
}
|
||||
|
||||
+ __ bind(&reload_string_start_minus_one);
|
||||
+ // Prepare a0 to initialize registers with its value in the next run.
|
||||
+ // Must be immediately before the jump to avoid clobbering.
|
||||
+ __ LoadWord(a0,
|
||||
+ MemOperand(frame_pointer(), kStringStartMinusOneOffset));
|
||||
+
|
||||
__ Branch(&load_char_start_regexp);
|
||||
} else {
|
||||
__ li(a0, Operand(SUCCESS));
|
||||
diff --git a/src/regexp/s390/regexp-macro-assembler-s390.cc b/src/regexp/s390/regexp-macro-assembler-s390.cc
|
||||
index a61bc379ba6c265ecb0c5cd7aa8d7a2e35ca6c1e..de184b95862e7f2e64d69cff6b60d866eb212f36 100644
|
||||
--- a/src/regexp/s390/regexp-macro-assembler-s390.cc
|
||||
+++ b/src/regexp/s390/regexp-macro-assembler-s390.cc
|
||||
@@ -947,19 +947,18 @@ Handle<HeapObject> RegExpMacroAssemblerS390::GetCode(Handle<String> source) {
|
||||
__ AddS64(r4, Operand(num_saved_registers_ * kIntSize));
|
||||
__ StoreU64(r4, MemOperand(frame_pointer(), kRegisterOutput));
|
||||
|
||||
- // Prepare r2 to initialize registers with its value in the next run.
|
||||
- __ LoadU64(r2, MemOperand(frame_pointer(), kStringStartMinusOne));
|
||||
-
|
||||
// Restore the original regexp stack pointer value (effectively, pop the
|
||||
// stored base pointer).
|
||||
PopRegExpBasePointer(backtrack_stackpointer(), r4);
|
||||
|
||||
+ Label reload_string_start_minus_one;
|
||||
+
|
||||
if (global_with_zero_length_check()) {
|
||||
// Special case for zero-length matches.
|
||||
// r6: capture start index
|
||||
__ CmpS64(current_input_offset(), r6);
|
||||
// Not a zero-length match, restart.
|
||||
- __ bne(&load_char_start_regexp);
|
||||
+ __ bne(&reload_string_start_minus_one);
|
||||
// Offset from the end is zero if we already reached the end.
|
||||
__ CmpS64(current_input_offset(), Operand::Zero());
|
||||
__ beq(&exit_label_);
|
||||
@@ -970,6 +969,11 @@ Handle<HeapObject> RegExpMacroAssemblerS390::GetCode(Handle<String> source) {
|
||||
if (global_unicode()) CheckNotInSurrogatePair(0, &advance);
|
||||
}
|
||||
|
||||
+ __ bind(&reload_string_start_minus_one);
|
||||
+ // Prepare r2 to initialize registers with its value in the next run.
|
||||
+ // Must be immediately before the jump to avoid clobbering.
|
||||
+ __ LoadU64(r2, MemOperand(frame_pointer(), kStringStartMinusOne));
|
||||
+
|
||||
__ b(&load_char_start_regexp);
|
||||
} else {
|
||||
__ mov(r2, Operand(SUCCESS));
|
||||
diff --git a/src/regexp/x64/regexp-macro-assembler-x64.cc b/src/regexp/x64/regexp-macro-assembler-x64.cc
|
||||
index 89fd2e34f1296113c43f16896d8f35d741782709..7c59534aa46c4c1c6fed151d7dad13070d133f47 100644
|
||||
--- a/src/regexp/x64/regexp-macro-assembler-x64.cc
|
||||
+++ b/src/regexp/x64/regexp-macro-assembler-x64.cc
|
||||
@@ -951,19 +951,18 @@ Handle<HeapObject> RegExpMacroAssemblerX64::GetCode(Handle<String> source) {
|
||||
__ addq(Operand(rbp, kRegisterOutput),
|
||||
Immediate(num_saved_registers_ * kIntSize));
|
||||
|
||||
- // Prepare rax to initialize registers with its value in the next run.
|
||||
- __ movq(rax, Operand(rbp, kStringStartMinusOne));
|
||||
-
|
||||
// Restore the original regexp stack pointer value (effectively, pop the
|
||||
// stored base pointer).
|
||||
PopRegExpBasePointer(backtrack_stackpointer(), kScratchRegister);
|
||||
|
||||
+ Label reload_string_start_minus_one;
|
||||
+
|
||||
if (global_with_zero_length_check()) {
|
||||
// Special case for zero-length matches.
|
||||
// rdx: capture start index
|
||||
__ cmpq(rdi, rdx);
|
||||
// Not a zero-length match, restart.
|
||||
- __ j(not_equal, &load_char_start_regexp);
|
||||
+ __ j(not_equal, &reload_string_start_minus_one);
|
||||
// rdi (offset from the end) is zero if we already reached the end.
|
||||
__ testq(rdi, rdi);
|
||||
__ j(zero, &exit_label_, Label::kNear);
|
||||
@@ -978,6 +977,11 @@ Handle<HeapObject> RegExpMacroAssemblerX64::GetCode(Handle<String> source) {
|
||||
if (global_unicode()) CheckNotInSurrogatePair(0, &advance);
|
||||
}
|
||||
|
||||
+ __ bind(&reload_string_start_minus_one);
|
||||
+ // Prepare rax to initialize registers with its value in the next run.
|
||||
+ // Must be immediately before the jump to avoid clobbering.
|
||||
+ __ movq(rax, Operand(rbp, kStringStartMinusOne));
|
||||
+
|
||||
__ jmp(&load_char_start_regexp);
|
||||
} else {
|
||||
__ Move(rax, SUCCESS);
|
||||
diff --git a/test/mjsunit/regress/regress-crbug-1439691.js b/test/mjsunit/regress/regress-crbug-1439691.js
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..6c55835535ab4f42ef0446abf863986962df9e9b
|
||||
--- /dev/null
|
||||
+++ b/test/mjsunit/regress/regress-crbug-1439691.js
|
||||
@@ -0,0 +1,7 @@
|
||||
+// 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.
|
||||
+
|
||||
+function f0() {
|
||||
+}
|
||||
+/(?!(a))\1/gudyi[Symbol.replace]("f\uD83D\uDCA9ba\u2603", f0);
|
||||
45
patches/v8/cherry-pick-2e76270cf65e.patch
Normal file
45
patches/v8/cherry-pick-2e76270cf65e.patch
Normal file
@@ -0,0 +1,45 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shu-yu Guo <syg@chromium.org>
|
||||
Date: Mon, 5 Jun 2023 16:05:52 -0700
|
||||
Subject: Merged: Check for encoding when appending in string builder
|
||||
|
||||
Fixed: chromium:1450114
|
||||
(cherry picked from commit a7e2bef27b72f187a7dcdf95714df686f56d9e0b)
|
||||
|
||||
Change-Id: I5838383b6b12d137e84c8a36863ef88000e85c76
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4604652
|
||||
Reviewed-by: Igor Sheludko <ishell@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/11.4@{#41}
|
||||
Cr-Branched-From: 8a8a1e7086dacc426965d3875914efa66663c431-refs/heads/11.4.183@{#1}
|
||||
Cr-Branched-From: 5483d8e816e0bbce865cbbc3fa0ab357e6330bab-refs/heads/main@{#87241}
|
||||
|
||||
diff --git a/src/strings/string-builder.cc b/src/strings/string-builder.cc
|
||||
index 9d1e3a95746b47b99c15f18ec593549d79e10b8c..c7e98e55763aba2d64f4070e25759489f850f589 100644
|
||||
--- a/src/strings/string-builder.cc
|
||||
+++ b/src/strings/string-builder.cc
|
||||
@@ -306,12 +306,21 @@ bool IncrementalStringBuilder::CanAppendByCopy(Handle<String> string) {
|
||||
void IncrementalStringBuilder::AppendStringByCopy(Handle<String> string) {
|
||||
DCHECK(CanAppendByCopy(string));
|
||||
|
||||
- Handle<SeqOneByteString> part =
|
||||
- Handle<SeqOneByteString>::cast(current_part());
|
||||
{
|
||||
DisallowGarbageCollection no_gc;
|
||||
- String::WriteToFlat(*string, part->GetChars(no_gc) + current_index_, 0,
|
||||
- string->length());
|
||||
+ if (encoding_ == String::ONE_BYTE_ENCODING) {
|
||||
+ String::WriteToFlat(
|
||||
+ *string,
|
||||
+ Handle<SeqOneByteString>::cast(current_part())->GetChars(no_gc) +
|
||||
+ current_index_,
|
||||
+ 0, string->length());
|
||||
+ } else {
|
||||
+ String::WriteToFlat(
|
||||
+ *string,
|
||||
+ Handle<SeqTwoByteString>::cast(current_part())->GetChars(no_gc) +
|
||||
+ current_index_,
|
||||
+ 0, string->length());
|
||||
+ }
|
||||
}
|
||||
current_index_ += string->length();
|
||||
DCHECK(current_index_ <= part_length_);
|
||||
186
patches/v8/cherry-pick-3b0607d14060.patch
Normal file
186
patches/v8/cherry-pick-3b0607d14060.patch
Normal file
@@ -0,0 +1,186 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Igor Sheludko <ishell@chromium.org>
|
||||
Date: Wed, 17 May 2023 13:47:36 +0200
|
||||
Subject: Merged: [runtime] Remove redundant calls to GetPropertyAttributes
|
||||
|
||||
... when defining properties in favour of CheckIfCanDefine.
|
||||
|
||||
Drive-by: move JSReceiver::CheckIfCanDefine to
|
||||
JSObject::CheckIfCanDefineAsConfigurable and fix handling of
|
||||
absent properties.
|
||||
|
||||
Bug: chromium:1443452
|
||||
(cherry picked from commit e98baa3526426c0219bb0474028ca301b8bd0677)
|
||||
|
||||
Change-Id: Ia1fd617778be608accee99dcee37f7d1ce3460b8
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4545762
|
||||
Commit-Queue: Igor Sheludko <ishell@chromium.org>
|
||||
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/11.4@{#22}
|
||||
Cr-Branched-From: 8a8a1e7086dacc426965d3875914efa66663c431-refs/heads/11.4.183@{#1}
|
||||
Cr-Branched-From: 5483d8e816e0bbce865cbbc3fa0ab357e6330bab-refs/heads/main@{#87241}
|
||||
|
||||
diff --git a/src/ic/ic.cc b/src/ic/ic.cc
|
||||
index 93939fa4702922f58e8e5bcc019e569f42ab198e..1190b3dedfabee414fb49038e31b3cf2bbce68ee 100644
|
||||
--- a/src/ic/ic.cc
|
||||
+++ b/src/ic/ic.cc
|
||||
@@ -1816,14 +1816,14 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
|
||||
// been thrown if the private field already exists in the object.
|
||||
if (IsAnyDefineOwn() && !name->IsPrivateName() && !object->IsJSProxy() &&
|
||||
!Handle<JSObject>::cast(object)->HasNamedInterceptor()) {
|
||||
- Maybe<bool> can_define = JSReceiver::CheckIfCanDefine(
|
||||
+ Maybe<bool> can_define = JSObject::CheckIfCanDefineAsConfigurable(
|
||||
isolate(), &it, value, Nothing<ShouldThrow>());
|
||||
MAYBE_RETURN_NULL(can_define);
|
||||
if (!can_define.FromJust()) {
|
||||
return isolate()->factory()->undefined_value();
|
||||
}
|
||||
- // Restart the lookup iterator updated by CheckIfCanDefine() for
|
||||
- // UpdateCaches() to handle access checks.
|
||||
+ // Restart the lookup iterator updated by CheckIfCanDefineAsConfigurable()
|
||||
+ // for UpdateCaches() to handle access checks.
|
||||
if (use_ic && object->IsAccessCheckNeeded()) {
|
||||
it.Restart();
|
||||
}
|
||||
diff --git a/src/objects/js-objects.cc b/src/objects/js-objects.cc
|
||||
index 39cc83aacb5caf0791ce70212695f5016a22f274..b3f7db7bd984e8524689c3060bfd0674840fa63b 100644
|
||||
--- a/src/objects/js-objects.cc
|
||||
+++ b/src/objects/js-objects.cc
|
||||
@@ -243,27 +243,6 @@ Maybe<bool> JSReceiver::CheckPrivateNameStore(LookupIterator* it,
|
||||
return Just(true);
|
||||
}
|
||||
|
||||
-// static
|
||||
-Maybe<bool> JSReceiver::CheckIfCanDefine(Isolate* isolate, LookupIterator* it,
|
||||
- Handle<Object> value,
|
||||
- Maybe<ShouldThrow> should_throw) {
|
||||
- if (it->IsFound()) {
|
||||
- Maybe<PropertyAttributes> attributes = GetPropertyAttributes(it);
|
||||
- MAYBE_RETURN(attributes, Nothing<bool>());
|
||||
- if ((attributes.FromJust() & DONT_DELETE) != 0) {
|
||||
- RETURN_FAILURE(
|
||||
- isolate, GetShouldThrow(isolate, should_throw),
|
||||
- NewTypeError(MessageTemplate::kRedefineDisallowed, it->GetName()));
|
||||
- }
|
||||
- } else if (!JSObject::IsExtensible(
|
||||
- Handle<JSObject>::cast(it->GetReceiver()))) {
|
||||
- RETURN_FAILURE(
|
||||
- isolate, GetShouldThrow(isolate, should_throw),
|
||||
- NewTypeError(MessageTemplate::kDefineDisallowed, it->GetName()));
|
||||
- }
|
||||
- return Just(true);
|
||||
-}
|
||||
-
|
||||
namespace {
|
||||
|
||||
bool HasExcludedProperty(
|
||||
@@ -3643,7 +3622,7 @@ Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
|
||||
|
||||
if (semantics == EnforceDefineSemantics::kDefine) {
|
||||
it->Restart();
|
||||
- Maybe<bool> can_define = JSReceiver::CheckIfCanDefine(
|
||||
+ Maybe<bool> can_define = JSObject::CheckIfCanDefineAsConfigurable(
|
||||
it->isolate(), it, value, should_throw);
|
||||
if (can_define.IsNothing() || !can_define.FromJust()) {
|
||||
return can_define;
|
||||
@@ -4072,17 +4051,16 @@ Maybe<bool> JSObject::CreateDataProperty(LookupIterator* it,
|
||||
Handle<Object> value,
|
||||
Maybe<ShouldThrow> should_throw) {
|
||||
DCHECK(it->GetReceiver()->IsJSObject());
|
||||
- MAYBE_RETURN(JSReceiver::GetPropertyAttributes(it), Nothing<bool>());
|
||||
Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(it->GetReceiver());
|
||||
Isolate* isolate = receiver->GetIsolate();
|
||||
|
||||
- Maybe<bool> can_define =
|
||||
- JSReceiver::CheckIfCanDefine(isolate, it, value, should_throw);
|
||||
+ Maybe<bool> can_define = JSObject::CheckIfCanDefineAsConfigurable(
|
||||
+ isolate, it, value, should_throw);
|
||||
if (can_define.IsNothing() || !can_define.FromJust()) {
|
||||
return can_define;
|
||||
}
|
||||
|
||||
- RETURN_ON_EXCEPTION_VALUE(it->isolate(),
|
||||
+ RETURN_ON_EXCEPTION_VALUE(isolate,
|
||||
DefineOwnPropertyIgnoreAttributes(it, value, NONE),
|
||||
Nothing<bool>());
|
||||
|
||||
@@ -4708,19 +4686,42 @@ MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
|
||||
return it.factory()->undefined_value();
|
||||
}
|
||||
|
||||
- CHECK(GetPropertyAttributes(&it).IsJust());
|
||||
-
|
||||
- // ES5 forbids turning a property into an accessor if it's not
|
||||
- // configurable. See 8.6.1 (Table 5).
|
||||
- if (it.IsFound() && !it.IsConfigurable()) {
|
||||
- return it.factory()->undefined_value();
|
||||
- }
|
||||
+ Maybe<bool> can_define = JSObject::CheckIfCanDefineAsConfigurable(
|
||||
+ isolate, &it, info, Nothing<ShouldThrow>());
|
||||
+ MAYBE_RETURN_NULL(can_define);
|
||||
+ if (!can_define.FromJust()) return it.factory()->undefined_value();
|
||||
|
||||
it.TransitionToAccessorPair(info, attributes);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
+// static
|
||||
+Maybe<bool> JSObject::CheckIfCanDefineAsConfigurable(
|
||||
+ Isolate* isolate, LookupIterator* it, Handle<Object> value,
|
||||
+ Maybe<ShouldThrow> should_throw) {
|
||||
+ DCHECK(it->GetReceiver()->IsJSObject());
|
||||
+ if (it->IsFound()) {
|
||||
+ Maybe<PropertyAttributes> attributes = GetPropertyAttributes(it);
|
||||
+ MAYBE_RETURN(attributes, Nothing<bool>());
|
||||
+ if (attributes.FromJust() != ABSENT) {
|
||||
+ if ((attributes.FromJust() & DONT_DELETE) != 0) {
|
||||
+ RETURN_FAILURE(
|
||||
+ isolate, GetShouldThrow(isolate, should_throw),
|
||||
+ NewTypeError(MessageTemplate::kRedefineDisallowed, it->GetName()));
|
||||
+ }
|
||||
+ return Just(true);
|
||||
+ }
|
||||
+ // Property does not exist, check object extensibility.
|
||||
+ }
|
||||
+ if (!JSObject::IsExtensible(Handle<JSObject>::cast(it->GetReceiver()))) {
|
||||
+ RETURN_FAILURE(
|
||||
+ isolate, GetShouldThrow(isolate, should_throw),
|
||||
+ NewTypeError(MessageTemplate::kDefineDisallowed, it->GetName()));
|
||||
+ }
|
||||
+ return Just(true);
|
||||
+}
|
||||
+
|
||||
Object JSObject::SlowReverseLookup(Object value) {
|
||||
if (HasFastProperties()) {
|
||||
DescriptorArray descs = map().instance_descriptors();
|
||||
diff --git a/src/objects/js-objects.h b/src/objects/js-objects.h
|
||||
index ff96bd4be2ff8d2fe03f75b6bca35a744e2084af..5e7326eb1c99115829c358cd4069e1f6835f972b 100644
|
||||
--- a/src/objects/js-objects.h
|
||||
+++ b/src/objects/js-objects.h
|
||||
@@ -167,12 +167,6 @@ class JSReceiver : public TorqueGeneratedJSReceiver<JSReceiver, HeapObject> {
|
||||
V8_WARN_UNUSED_RESULT static Maybe<bool> CheckPrivateNameStore(
|
||||
LookupIterator* it, bool is_define);
|
||||
|
||||
- // Check if a data property can be created on the object. It will fail with
|
||||
- // an error when it cannot.
|
||||
- V8_WARN_UNUSED_RESULT static Maybe<bool> CheckIfCanDefine(
|
||||
- Isolate* isolate, LookupIterator* it, Handle<Object> value,
|
||||
- Maybe<ShouldThrow> should_throw);
|
||||
-
|
||||
// ES6 7.3.4 (when passed kDontThrow)
|
||||
V8_WARN_UNUSED_RESULT static Maybe<bool> CreateDataProperty(
|
||||
Isolate* isolate, Handle<JSReceiver> object, Handle<Name> key,
|
||||
@@ -545,6 +539,12 @@ class JSObject : public TorqueGeneratedJSObject<JSObject, JSReceiver> {
|
||||
Handle<JSObject> object, Handle<Name> name, Handle<AccessorInfo> info,
|
||||
PropertyAttributes attributes);
|
||||
|
||||
+ // Check if a data property can be created on the object. It will fail with
|
||||
+ // an error when it cannot.
|
||||
+ V8_WARN_UNUSED_RESULT static Maybe<bool> CheckIfCanDefineAsConfigurable(
|
||||
+ Isolate* isolate, LookupIterator* it, Handle<Object> value,
|
||||
+ Maybe<ShouldThrow> should_throw);
|
||||
+
|
||||
// The result must be checked first for exceptions. If there's no exception,
|
||||
// the output parameter |done| indicates whether the interceptor has a result
|
||||
// or not.
|
||||
257
patches/v8/cherry-pick-73af1a19a901.patch
Normal file
257
patches/v8/cherry-pick-73af1a19a901.patch
Normal file
@@ -0,0 +1,257 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Igor Sheludko <ishell@chromium.org>
|
||||
Date: Thu, 1 Jun 2023 10:59:39 +0200
|
||||
Subject: Merged: [lookup] Robustify LookupIterator against own lookups
|
||||
|
||||
... on non-JSReceiver objects.
|
||||
|
||||
Bug: chromium:1447430
|
||||
(cherry picked from commit 515f187ba067ee4a99fdf5198cca2c97abd342fd)
|
||||
|
||||
Change-Id: Ib9382d90ce19d6b55ee0b236dd299ded03ade04d
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4575069
|
||||
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
|
||||
Commit-Queue: Igor Sheludko <ishell@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/11.4@{#35}
|
||||
Cr-Branched-From: 8a8a1e7086dacc426965d3875914efa66663c431-refs/heads/11.4.183@{#1}
|
||||
Cr-Branched-From: 5483d8e816e0bbce865cbbc3fa0ab357e6330bab-refs/heads/main@{#87241}
|
||||
|
||||
diff --git a/src/objects/lookup-inl.h b/src/objects/lookup-inl.h
|
||||
index 44b8f9502e32a9a6fbbe60ebc5f8e0d184411b8f..782698bd7c488f5570288119e49784e16a93ddd2 100644
|
||||
--- a/src/objects/lookup-inl.h
|
||||
+++ b/src/objects/lookup-inl.h
|
||||
@@ -167,7 +167,7 @@ Handle<Name> PropertyKey::GetName(Isolate* isolate) {
|
||||
}
|
||||
|
||||
Handle<Name> LookupIterator::name() const {
|
||||
- DCHECK(!IsElement(*holder_));
|
||||
+ DCHECK_IMPLIES(!holder_.is_null(), !IsElement(*holder_));
|
||||
return name_;
|
||||
}
|
||||
|
||||
@@ -257,6 +257,7 @@ void LookupIterator::UpdateProtector() {
|
||||
}
|
||||
|
||||
InternalIndex LookupIterator::descriptor_number() const {
|
||||
+ DCHECK(!holder_.is_null());
|
||||
DCHECK(!IsElement(*holder_));
|
||||
DCHECK(has_property_);
|
||||
DCHECK(holder_->HasFastProperties(isolate_));
|
||||
@@ -264,6 +265,7 @@ InternalIndex LookupIterator::descriptor_number() const {
|
||||
}
|
||||
|
||||
InternalIndex LookupIterator::dictionary_entry() const {
|
||||
+ DCHECK(!holder_.is_null());
|
||||
DCHECK(!IsElement(*holder_));
|
||||
DCHECK(has_property_);
|
||||
DCHECK(!holder_->HasFastProperties(isolate_));
|
||||
@@ -278,13 +280,14 @@ LookupIterator::Configuration LookupIterator::ComputeConfiguration(
|
||||
}
|
||||
|
||||
// static
|
||||
-Handle<JSReceiver> LookupIterator::GetRoot(Isolate* isolate,
|
||||
- Handle<Object> lookup_start_object,
|
||||
- size_t index) {
|
||||
+MaybeHandle<JSReceiver> LookupIterator::GetRoot(
|
||||
+ Isolate* isolate, Handle<Object> lookup_start_object, size_t index,
|
||||
+ Configuration configuration) {
|
||||
if (lookup_start_object->IsJSReceiver(isolate)) {
|
||||
return Handle<JSReceiver>::cast(lookup_start_object);
|
||||
}
|
||||
- return GetRootForNonJSReceiver(isolate, lookup_start_object, index);
|
||||
+ return GetRootForNonJSReceiver(isolate, lookup_start_object, index,
|
||||
+ configuration);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
diff --git a/src/objects/lookup.cc b/src/objects/lookup.cc
|
||||
index 7c6f6c4a350fec92a3cc0a48a14c0b92f8d6021d..ce1502b859c0cce77fc054488e401ac82a073a7d 100644
|
||||
--- a/src/objects/lookup.cc
|
||||
+++ b/src/objects/lookup.cc
|
||||
@@ -42,27 +42,20 @@ PropertyKey::PropertyKey(Isolate* isolate, Handle<Object> key, bool* success) {
|
||||
}
|
||||
}
|
||||
|
||||
-LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
|
||||
- Handle<Name> name, Handle<Map> transition_map,
|
||||
- PropertyDetails details, bool has_property)
|
||||
- : configuration_(DEFAULT),
|
||||
- state_(TRANSITION),
|
||||
- has_property_(has_property),
|
||||
- interceptor_state_(InterceptorState::kUninitialized),
|
||||
- property_details_(details),
|
||||
- isolate_(isolate),
|
||||
- name_(name),
|
||||
- transition_(transition_map),
|
||||
- receiver_(receiver),
|
||||
- lookup_start_object_(receiver),
|
||||
- index_(kInvalidIndex) {
|
||||
- holder_ = GetRoot(isolate, lookup_start_object_);
|
||||
-}
|
||||
-
|
||||
template <bool is_element>
|
||||
void LookupIterator::Start() {
|
||||
// GetRoot might allocate if lookup_start_object_ is a string.
|
||||
- holder_ = GetRoot(isolate_, lookup_start_object_, index_);
|
||||
+ MaybeHandle<JSReceiver> maybe_holder =
|
||||
+ GetRoot(isolate_, lookup_start_object_, index_, configuration_);
|
||||
+ if (!maybe_holder.ToHandle(&holder_)) {
|
||||
+ // This is an attempt to perform an own property lookup on a non-JSReceiver
|
||||
+ // that doesn't have any properties.
|
||||
+ DCHECK(!lookup_start_object_->IsJSReceiver());
|
||||
+ DCHECK(!check_prototype_chain());
|
||||
+ has_property_ = false;
|
||||
+ state_ = NOT_FOUND;
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
{
|
||||
DisallowGarbageCollection no_gc;
|
||||
@@ -135,19 +128,27 @@ template void LookupIterator::RestartInternal<true>(InterceptorState);
|
||||
template void LookupIterator::RestartInternal<false>(InterceptorState);
|
||||
|
||||
// static
|
||||
-Handle<JSReceiver> LookupIterator::GetRootForNonJSReceiver(
|
||||
- Isolate* isolate, Handle<Object> lookup_start_object, size_t index) {
|
||||
- // Strings are the only objects with properties (only elements) directly on
|
||||
- // the wrapper. Hence we can skip generating the wrapper for all other cases.
|
||||
- if (lookup_start_object->IsString(isolate) &&
|
||||
- index <
|
||||
- static_cast<size_t>(String::cast(*lookup_start_object).length())) {
|
||||
- // TODO(verwaest): Speed this up. Perhaps use a cached wrapper on the native
|
||||
- // context, ensuring that we don't leak it into JS?
|
||||
- Handle<JSFunction> constructor = isolate->string_function();
|
||||
- Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
|
||||
- Handle<JSPrimitiveWrapper>::cast(result)->set_value(*lookup_start_object);
|
||||
- return result;
|
||||
+MaybeHandle<JSReceiver> LookupIterator::GetRootForNonJSReceiver(
|
||||
+ Isolate* isolate, Handle<Object> lookup_start_object, size_t index,
|
||||
+ Configuration configuration) {
|
||||
+ // Strings are the only non-JSReceiver objects with properties (only elements
|
||||
+ // and 'length') directly on the wrapper. Hence we can skip generating
|
||||
+ // the wrapper for all other cases.
|
||||
+ bool own_property_lookup = (configuration & kPrototypeChain) == 0;
|
||||
+ if (lookup_start_object->IsString(isolate)) {
|
||||
+ if (own_property_lookup ||
|
||||
+ index <
|
||||
+ static_cast<size_t>(String::cast(*lookup_start_object).length())) {
|
||||
+ // TODO(verwaest): Speed this up. Perhaps use a cached wrapper on the
|
||||
+ // native context, ensuring that we don't leak it into JS?
|
||||
+ Handle<JSFunction> constructor = isolate->string_function();
|
||||
+ Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
|
||||
+ Handle<JSPrimitiveWrapper>::cast(result)->set_value(*lookup_start_object);
|
||||
+ return result;
|
||||
+ }
|
||||
+ } else if (own_property_lookup) {
|
||||
+ // Signal that the lookup will not find anything.
|
||||
+ return {};
|
||||
}
|
||||
Handle<HeapObject> root(
|
||||
lookup_start_object->GetPrototypeChainRootMap(isolate).prototype(isolate),
|
||||
@@ -901,6 +902,7 @@ Handle<Object> LookupIterator::FetchValue(
|
||||
}
|
||||
|
||||
bool LookupIterator::CanStayConst(Object value) const {
|
||||
+ DCHECK(!holder_.is_null());
|
||||
DCHECK(!IsElement(*holder_));
|
||||
DCHECK(holder_->HasFastProperties(isolate_));
|
||||
DCHECK_EQ(PropertyLocation::kField, property_details_.location());
|
||||
@@ -934,6 +936,7 @@ bool LookupIterator::CanStayConst(Object value) const {
|
||||
}
|
||||
|
||||
bool LookupIterator::DictCanStayConst(Object value) const {
|
||||
+ DCHECK(!holder_.is_null());
|
||||
DCHECK(!IsElement(*holder_));
|
||||
DCHECK(!holder_->HasFastProperties(isolate_));
|
||||
DCHECK(!holder_->IsJSGlobalObject());
|
||||
@@ -980,6 +983,7 @@ int LookupIterator::GetAccessorIndex() const {
|
||||
|
||||
FieldIndex LookupIterator::GetFieldIndex() const {
|
||||
DCHECK(has_property_);
|
||||
+ DCHECK(!holder_.is_null());
|
||||
DCHECK(holder_->HasFastProperties(isolate_));
|
||||
DCHECK_EQ(PropertyLocation::kField, property_details_.location());
|
||||
DCHECK(!IsElement(*holder_));
|
||||
@@ -987,6 +991,7 @@ FieldIndex LookupIterator::GetFieldIndex() const {
|
||||
}
|
||||
|
||||
Handle<PropertyCell> LookupIterator::GetPropertyCell() const {
|
||||
+ DCHECK(!holder_.is_null());
|
||||
DCHECK(!IsElement(*holder_));
|
||||
Handle<JSGlobalObject> holder = GetHolder<JSGlobalObject>();
|
||||
return handle(holder->global_dictionary(isolate_, kAcquireLoad)
|
||||
diff --git a/src/objects/lookup.h b/src/objects/lookup.h
|
||||
index 9adee79b3028c53e6481a07316d74aed616f01bd..ef90316295c98d51b61c118cf331731f991d93d0 100644
|
||||
--- a/src/objects/lookup.h
|
||||
+++ b/src/objects/lookup.h
|
||||
@@ -214,11 +214,6 @@ class V8_EXPORT_PRIVATE LookupIterator final {
|
||||
Handle<Object> lookup_start_object,
|
||||
Configuration configuration);
|
||||
|
||||
- // For |ForTransitionHandler|.
|
||||
- LookupIterator(Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
|
||||
- Handle<Map> transition_map, PropertyDetails details,
|
||||
- bool has_property);
|
||||
-
|
||||
static void InternalUpdateProtector(Isolate* isolate, Handle<Object> receiver,
|
||||
Handle<Name> name);
|
||||
|
||||
@@ -278,12 +273,12 @@ class V8_EXPORT_PRIVATE LookupIterator final {
|
||||
Configuration configuration,
|
||||
Handle<Name> name);
|
||||
|
||||
- static Handle<JSReceiver> GetRootForNonJSReceiver(
|
||||
- Isolate* isolate, Handle<Object> lookup_start_object,
|
||||
- size_t index = kInvalidIndex);
|
||||
- static inline Handle<JSReceiver> GetRoot(Isolate* isolate,
|
||||
- Handle<Object> lookup_start_object,
|
||||
- size_t index = kInvalidIndex);
|
||||
+ static MaybeHandle<JSReceiver> GetRootForNonJSReceiver(
|
||||
+ Isolate* isolate, Handle<Object> lookup_start_object, size_t index,
|
||||
+ Configuration configuration);
|
||||
+ static inline MaybeHandle<JSReceiver> GetRoot(
|
||||
+ Isolate* isolate, Handle<Object> lookup_start_object, size_t index,
|
||||
+ Configuration configuration);
|
||||
|
||||
State NotFound(JSReceiver const holder) const;
|
||||
|
||||
diff --git a/test/mjsunit/regress/regress-crbug-1447430.js b/test/mjsunit/regress/regress-crbug-1447430.js
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..c7bb3e72e3af1b9f8c2fa82faeeb2d813fe6ab3c
|
||||
--- /dev/null
|
||||
+++ b/test/mjsunit/regress/regress-crbug-1447430.js
|
||||
@@ -0,0 +1,34 @@
|
||||
+// 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
|
||||
+
|
||||
+var s = %CreatePrivateSymbol('x');
|
||||
+
|
||||
+(function TestSmi() {
|
||||
+ function f(o, p) {
|
||||
+ o[p] = 153;
|
||||
+ }
|
||||
+ (1).__proto__[s] = 42;
|
||||
+ %PrepareFunctionForOptimization(f);
|
||||
+ assertEquals(f(42, s), undefined);
|
||||
+}());
|
||||
+
|
||||
+(function TestString() {
|
||||
+ function f(o, p) {
|
||||
+ o[p] = 153;
|
||||
+ }
|
||||
+ ('xyz').__proto__[s] = 42;
|
||||
+ %PrepareFunctionForOptimization(f);
|
||||
+ assertEquals(f('abc', s), undefined);
|
||||
+}());
|
||||
+
|
||||
+(function TestSymbol() {
|
||||
+ function f(o, p) {
|
||||
+ o[p] = 153;
|
||||
+ }
|
||||
+ Symbol('xyz').__proto__[s] = 42;
|
||||
+ %PrepareFunctionForOptimization(f);
|
||||
+ assertEquals(f(Symbol('abc'), s), undefined);
|
||||
+}());
|
||||
150
patches/v8/cherry-pick-9c6dfc733fce.patch
Normal file
150
patches/v8/cherry-pick-9c6dfc733fce.patch
Normal file
@@ -0,0 +1,150 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Igor Sheludko <ishell@chromium.org>
|
||||
Date: Tue, 16 May 2023 16:01:49 +0200
|
||||
Subject: Merged: [runtime] Fix handling of interceptors
|
||||
|
||||
Drive-by: simplify creation of LookupIterator copies.
|
||||
|
||||
Bug: chromium:1440695
|
||||
(cherry picked from commit d125c7329f6e22af4523de3c55de3a22f168acc9)
|
||||
|
||||
Change-Id: I58416531b9af3456f53264566ec1eb7457328f94
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4545763
|
||||
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
|
||||
Commit-Queue: Igor Sheludko <ishell@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/11.4@{#23}
|
||||
Cr-Branched-From: 8a8a1e7086dacc426965d3875914efa66663c431-refs/heads/11.4.183@{#1}
|
||||
Cr-Branched-From: 5483d8e816e0bbce865cbbc3fa0ab357e6330bab-refs/heads/main@{#87241}
|
||||
|
||||
diff --git a/src/objects/js-objects.cc b/src/objects/js-objects.cc
|
||||
index b3f7db7bd984e8524689c3060bfd0674840fa63b..8cc8af6c221a90cc6a6201faa46738ec80ffccdb 100644
|
||||
--- a/src/objects/js-objects.cc
|
||||
+++ b/src/objects/js-objects.cc
|
||||
@@ -3633,10 +3633,8 @@ Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes(
|
||||
// own property without the interceptor.
|
||||
Isolate* isolate = it->isolate();
|
||||
Handle<Object> receiver = it->GetReceiver();
|
||||
- LookupIterator::Configuration c = LookupIterator::OWN_SKIP_INTERCEPTOR;
|
||||
- LookupIterator own_lookup =
|
||||
- it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c)
|
||||
- : LookupIterator(isolate, receiver, it->name(), c);
|
||||
+ LookupIterator own_lookup(isolate, receiver, it->GetKey(),
|
||||
+ LookupIterator::OWN_SKIP_INTERCEPTOR);
|
||||
return JSObject::DefineOwnPropertyIgnoreAttributes(
|
||||
&own_lookup, value, attributes, should_throw, handling, semantics,
|
||||
store_origin);
|
||||
diff --git a/src/objects/lookup-inl.h b/src/objects/lookup-inl.h
|
||||
index 782698bd7c488f5570288119e49784e16a93ddd2..35eaed8ffbc23248c33230868f428bc192c5b790 100644
|
||||
--- a/src/objects/lookup-inl.h
|
||||
+++ b/src/objects/lookup-inl.h
|
||||
@@ -130,6 +130,29 @@ PropertyKey::PropertyKey(Isolate* isolate, double index) {
|
||||
#endif
|
||||
}
|
||||
|
||||
+PropertyKey::PropertyKey(Isolate* isolate, Handle<Name> name, size_t index)
|
||||
+ : name_(name), index_(index) {
|
||||
+ DCHECK_IMPLIES(index_ == LookupIterator::kInvalidIndex, !name_.is_null());
|
||||
+#if V8_TARGET_ARCH_32_BIT
|
||||
+ DCHECK_IMPLIES(index_ != LookupIterator::kInvalidIndex,
|
||||
+ index_ <= JSObject::kMaxElementIndex);
|
||||
+#endif
|
||||
+#if DEBUG
|
||||
+ if (index_ != LookupIterator::kInvalidIndex && !name_.is_null()) {
|
||||
+ // If both valid index and name are given then the name is a string
|
||||
+ // representation of the same index.
|
||||
+ size_t integer_index;
|
||||
+ CHECK(name_->AsIntegerIndex(&integer_index));
|
||||
+ CHECK_EQ(index_, integer_index);
|
||||
+ } else if (index_ == LookupIterator::kInvalidIndex) {
|
||||
+ // If only name is given it must not be a string representing an integer
|
||||
+ // index.
|
||||
+ size_t integer_index;
|
||||
+ CHECK(!name_->AsIntegerIndex(&integer_index));
|
||||
+ }
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
PropertyKey::PropertyKey(Isolate* isolate, Handle<Name> name) {
|
||||
if (name->AsIntegerIndex(&index_)) {
|
||||
name_ = name;
|
||||
@@ -179,6 +202,10 @@ Handle<Name> LookupIterator::GetName() {
|
||||
return name_;
|
||||
}
|
||||
|
||||
+PropertyKey LookupIterator::GetKey() const {
|
||||
+ return PropertyKey(isolate_, name_, index_);
|
||||
+}
|
||||
+
|
||||
bool LookupIterator::IsElement(JSReceiver object) const {
|
||||
return index_ <= JSObject::kMaxElementIndex ||
|
||||
(index_ != kInvalidIndex &&
|
||||
diff --git a/src/objects/lookup.h b/src/objects/lookup.h
|
||||
index ef90316295c98d51b61c118cf331731f991d93d0..5d2d926b7e3dcecf8529f7d1c1e919033d9faa7f 100644
|
||||
--- a/src/objects/lookup.h
|
||||
+++ b/src/objects/lookup.h
|
||||
@@ -36,6 +36,11 @@ class PropertyKey {
|
||||
inline Handle<Name> GetName(Isolate* isolate);
|
||||
|
||||
private:
|
||||
+ friend LookupIterator;
|
||||
+
|
||||
+ // Shortcut for constructing PropertyKey from an active LookupIterator.
|
||||
+ inline PropertyKey(Isolate* isolate, Handle<Name> name, size_t index);
|
||||
+
|
||||
Handle<Name> name_;
|
||||
size_t index_;
|
||||
};
|
||||
@@ -108,6 +113,9 @@ class V8_EXPORT_PRIVATE LookupIterator final {
|
||||
return static_cast<uint32_t>(index_);
|
||||
}
|
||||
|
||||
+ // Helper method for creating a copy of of the iterator.
|
||||
+ inline PropertyKey GetKey() const;
|
||||
+
|
||||
// Returns true if this LookupIterator has an index in the range
|
||||
// [0, size_t::max).
|
||||
bool IsElement() const { return index_ != kInvalidIndex; }
|
||||
diff --git a/src/objects/objects.cc b/src/objects/objects.cc
|
||||
index 01d826c43bf9ec8bb28aba0e59fd3fa8f5700bac..b57c68073e401bb34796689013213791d40af10a 100644
|
||||
--- a/src/objects/objects.cc
|
||||
+++ b/src/objects/objects.cc
|
||||
@@ -2668,11 +2668,8 @@ Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
|
||||
|
||||
// Note, the callers rely on the fact that this code is redoing the full own
|
||||
// lookup from scratch.
|
||||
- LookupIterator::Configuration c = LookupIterator::OWN;
|
||||
- LookupIterator own_lookup =
|
||||
- it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c)
|
||||
- : LookupIterator(isolate, receiver, it->name(), c);
|
||||
-
|
||||
+ LookupIterator own_lookup(isolate, receiver, it->GetKey(),
|
||||
+ LookupIterator::OWN);
|
||||
for (; own_lookup.IsFound(); own_lookup.Next()) {
|
||||
switch (own_lookup.state()) {
|
||||
case LookupIterator::ACCESS_CHECK:
|
||||
@@ -2709,6 +2706,8 @@ Maybe<bool> Object::SetSuperProperty(LookupIterator* it, Handle<Object> value,
|
||||
JSReceiver::GetOwnPropertyDescriptor(&own_lookup, &desc);
|
||||
MAYBE_RETURN(owned, Nothing<bool>());
|
||||
if (!owned.FromJust()) {
|
||||
+ // |own_lookup| might become outdated at this point anyway.
|
||||
+ own_lookup.Restart();
|
||||
if (!CheckContextualStoreToJSGlobalObject(&own_lookup,
|
||||
should_throw)) {
|
||||
return Nothing<bool>();
|
||||
diff --git a/test/unittests/api/interceptor-unittest.cc b/test/unittests/api/interceptor-unittest.cc
|
||||
index 635bf6a0b72f8d49591be333b1314846c9c47269..416f9bd1eb4c59160eb03031e6011ae02dcf021e 100644
|
||||
--- a/test/unittests/api/interceptor-unittest.cc
|
||||
+++ b/test/unittests/api/interceptor-unittest.cc
|
||||
@@ -174,8 +174,10 @@ TEST_F(InterceptorLoggingTest, DispatchTest) {
|
||||
EXPECT_EQ(Run("obj.foo"), "named getter");
|
||||
EXPECT_EQ(Run("obj[42]"), "indexed getter");
|
||||
|
||||
- EXPECT_EQ(Run("obj.foo = null"), "named setter, named descriptor");
|
||||
- EXPECT_EQ(Run("obj[42] = null"), "indexed setter, indexed descriptor");
|
||||
+ EXPECT_EQ(Run("obj.foo = null"),
|
||||
+ "named setter, named descriptor, named query");
|
||||
+ EXPECT_EQ(Run("obj[42] = null"),
|
||||
+ "indexed setter, indexed descriptor, indexed query");
|
||||
|
||||
EXPECT_EQ(Run("Object.getOwnPropertyDescriptor(obj, 'foo')"),
|
||||
"named descriptor");
|
||||
362
patches/v8/cherry-pick-bb90b9cfcbca.patch
Normal file
362
patches/v8/cherry-pick-bb90b9cfcbca.patch
Normal file
@@ -0,0 +1,362 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Igor Sheludko <ishell@chromium.org>
|
||||
Date: Thu, 27 Apr 2023 11:11:32 +0200
|
||||
Subject: Merged: [api] Fix v8::Object::SetAccessorProperty
|
||||
|
||||
... by using JavaScript spec compliant JSReceiver::DefineOwnProperty.
|
||||
|
||||
Drive-by:
|
||||
- cleanup comments in include/v8-object.h, insert links to
|
||||
respective pages of https://tc39.es/ecma262/ when referencing spec,
|
||||
- rename JSObject::DefineAccessor() to
|
||||
JSObject::DefineOwnAccessorIgnoreAttributes().
|
||||
|
||||
Bug: chromium:1433211
|
||||
(cherry picked from commit b8020e1973d7d3a50b17c076cd948f079e59f9e5)
|
||||
|
||||
Change-Id: Ia4e0389e99b5a79987f59ca2a11ee7867b0c97e2
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4502585
|
||||
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
|
||||
Commit-Queue: Igor Sheludko <ishell@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/11.2@{#47}
|
||||
Cr-Branched-From: 755511a138609ac5939449a8ac615c15603a4454-refs/heads/11.2.214@{#1}
|
||||
Cr-Branched-From: e6b1ccefb0f0f1ff8d310578878130dc53d73749-refs/heads/main@{#86014}
|
||||
|
||||
diff --git a/include/v8-object.h b/include/v8-object.h
|
||||
index d7332ba0c88d12e8086f56117631dfb3e1e514b4..dfeda2d39431d481dbeab6698c3d3e7f02a1b19c 100644
|
||||
--- a/include/v8-object.h
|
||||
+++ b/include/v8-object.h
|
||||
@@ -247,13 +247,16 @@ class V8_EXPORT Object : public Value {
|
||||
V8_WARN_UNUSED_RESULT Maybe<bool> Set(Local<Context> context, uint32_t index,
|
||||
Local<Value> value);
|
||||
|
||||
- // Implements CreateDataProperty (ECMA-262, 7.3.4).
|
||||
- //
|
||||
- // Defines a configurable, writable, enumerable property with the given value
|
||||
- // on the object unless the property already exists and is not configurable
|
||||
- // or the object is not extensible.
|
||||
- //
|
||||
- // Returns true on success.
|
||||
+ /**
|
||||
+ * Implements CreateDataProperty(O, P, V), see
|
||||
+ * https://tc39.es/ecma262/#sec-createdataproperty.
|
||||
+ *
|
||||
+ * Defines a configurable, writable, enumerable property with the given value
|
||||
+ * on the object unless the property already exists and is not configurable
|
||||
+ * or the object is not extensible.
|
||||
+ *
|
||||
+ * Returns true on success.
|
||||
+ */
|
||||
V8_WARN_UNUSED_RESULT Maybe<bool> CreateDataProperty(Local<Context> context,
|
||||
Local<Name> key,
|
||||
Local<Value> value);
|
||||
@@ -261,29 +264,35 @@ class V8_EXPORT Object : public Value {
|
||||
uint32_t index,
|
||||
Local<Value> value);
|
||||
|
||||
- // Implements DefineOwnProperty.
|
||||
- //
|
||||
- // In general, CreateDataProperty will be faster, however, does not allow
|
||||
- // for specifying attributes.
|
||||
- //
|
||||
- // Returns true on success.
|
||||
+ /**
|
||||
+ * Implements [[DefineOwnProperty]] for data property case, see
|
||||
+ * https://tc39.es/ecma262/#table-essential-internal-methods.
|
||||
+ *
|
||||
+ * In general, CreateDataProperty will be faster, however, does not allow
|
||||
+ * for specifying attributes.
|
||||
+ *
|
||||
+ * Returns true on success.
|
||||
+ */
|
||||
V8_WARN_UNUSED_RESULT Maybe<bool> DefineOwnProperty(
|
||||
Local<Context> context, Local<Name> key, Local<Value> value,
|
||||
PropertyAttribute attributes = None);
|
||||
|
||||
- // Implements Object.DefineProperty(O, P, Attributes), see Ecma-262 19.1.2.4.
|
||||
- //
|
||||
- // The defineProperty function is used to add an own property or
|
||||
- // update the attributes of an existing own property of an object.
|
||||
- //
|
||||
- // Both data and accessor descriptors can be used.
|
||||
- //
|
||||
- // In general, CreateDataProperty is faster, however, does not allow
|
||||
- // for specifying attributes or an accessor descriptor.
|
||||
- //
|
||||
- // The PropertyDescriptor can change when redefining a property.
|
||||
- //
|
||||
- // Returns true on success.
|
||||
+ /**
|
||||
+ * Implements Object.defineProperty(O, P, Attributes), see
|
||||
+ * https://tc39.es/ecma262/#sec-object.defineproperty.
|
||||
+ *
|
||||
+ * The defineProperty function is used to add an own property or
|
||||
+ * update the attributes of an existing own property of an object.
|
||||
+ *
|
||||
+ * Both data and accessor descriptors can be used.
|
||||
+ *
|
||||
+ * In general, CreateDataProperty is faster, however, does not allow
|
||||
+ * for specifying attributes or an accessor descriptor.
|
||||
+ *
|
||||
+ * The PropertyDescriptor can change when redefining a property.
|
||||
+ *
|
||||
+ * Returns true on success.
|
||||
+ */
|
||||
V8_WARN_UNUSED_RESULT Maybe<bool> DefineProperty(
|
||||
Local<Context> context, Local<Name> key, PropertyDescriptor& descriptor);
|
||||
|
||||
@@ -302,14 +311,15 @@ class V8_EXPORT Object : public Value {
|
||||
Local<Context> context, Local<Value> key);
|
||||
|
||||
/**
|
||||
- * Returns Object.getOwnPropertyDescriptor as per ES2016 section 19.1.2.6.
|
||||
+ * Implements Object.getOwnPropertyDescriptor(O, P), see
|
||||
+ * https://tc39.es/ecma262/#sec-object.getownpropertydescriptor.
|
||||
*/
|
||||
V8_WARN_UNUSED_RESULT MaybeLocal<Value> GetOwnPropertyDescriptor(
|
||||
Local<Context> context, Local<Name> key);
|
||||
|
||||
/**
|
||||
- * Object::Has() calls the abstract operation HasProperty(O, P) described
|
||||
- * in ECMA-262, 7.3.10. Has() returns
|
||||
+ * Object::Has() calls the abstract operation HasProperty(O, P), see
|
||||
+ * https://tc39.es/ecma262/#sec-hasproperty. Has() returns
|
||||
* true, if the object has the property, either own or on the prototype chain.
|
||||
* Interceptors, i.e., PropertyQueryCallbacks, are called if present.
|
||||
*
|
||||
@@ -347,7 +357,7 @@ class V8_EXPORT Object : public Value {
|
||||
|
||||
void SetAccessorProperty(Local<Name> name, Local<Function> getter,
|
||||
Local<Function> setter = Local<Function>(),
|
||||
- PropertyAttribute attribute = None,
|
||||
+ PropertyAttribute attributes = None,
|
||||
AccessControl settings = DEFAULT);
|
||||
|
||||
/**
|
||||
diff --git a/src/api/api-natives.cc b/src/api/api-natives.cc
|
||||
index d0b298723423e9ad4d151c463dcdde09d2400336..9f664a755e4b04d935d29b1be796a81ac3fe0c07 100644
|
||||
--- a/src/api/api-natives.cc
|
||||
+++ b/src/api/api-natives.cc
|
||||
@@ -96,10 +96,10 @@ MaybeHandle<Object> DefineAccessorProperty(Isolate* isolate,
|
||||
Handle<CodeT> trampoline = BUILTIN_CODE(isolate, DebugBreakTrampoline);
|
||||
Handle<JSFunction>::cast(setter)->set_code(*trampoline);
|
||||
}
|
||||
- RETURN_ON_EXCEPTION(
|
||||
- isolate,
|
||||
- JSObject::DefineAccessor(object, name, getter, setter, attributes),
|
||||
- Object);
|
||||
+ RETURN_ON_EXCEPTION(isolate,
|
||||
+ JSObject::DefineOwnAccessorIgnoreAttributes(
|
||||
+ object, name, getter, setter, attributes),
|
||||
+ Object);
|
||||
return object;
|
||||
}
|
||||
|
||||
diff --git a/src/api/api.cc b/src/api/api.cc
|
||||
index d790bc0fd1b42a6b8107712d5c171751f83e5727..fbdbe4b5c7166e4dc1b2ad7b01aa911beed7f69c 100644
|
||||
--- a/src/api/api.cc
|
||||
+++ b/src/api/api.cc
|
||||
@@ -5061,7 +5061,7 @@ Maybe<bool> Object::SetAccessor(Local<Context> context, Local<Name> name,
|
||||
|
||||
void Object::SetAccessorProperty(Local<Name> name, Local<Function> getter,
|
||||
Local<Function> setter,
|
||||
- PropertyAttribute attribute,
|
||||
+ PropertyAttribute attributes,
|
||||
AccessControl settings) {
|
||||
// TODO(verwaest): Remove |settings|.
|
||||
DCHECK_EQ(v8::DEFAULT, settings);
|
||||
@@ -5073,9 +5073,20 @@ void Object::SetAccessorProperty(Local<Name> name, Local<Function> getter,
|
||||
i::Handle<i::Object> getter_i = v8::Utils::OpenHandle(*getter);
|
||||
i::Handle<i::Object> setter_i = v8::Utils::OpenHandle(*setter, true);
|
||||
if (setter_i.is_null()) setter_i = i_isolate->factory()->null_value();
|
||||
- i::JSObject::DefineAccessor(i::Handle<i::JSObject>::cast(self),
|
||||
- v8::Utils::OpenHandle(*name), getter_i, setter_i,
|
||||
- static_cast<i::PropertyAttributes>(attribute));
|
||||
+
|
||||
+ i::PropertyDescriptor desc;
|
||||
+ desc.set_enumerable(!(attributes & v8::DontEnum));
|
||||
+ desc.set_configurable(!(attributes & v8::DontDelete));
|
||||
+ desc.set_get(getter_i);
|
||||
+ desc.set_set(setter_i);
|
||||
+
|
||||
+ i::Handle<i::Name> name_i = v8::Utils::OpenHandle(*name);
|
||||
+ // DefineOwnProperty might still throw if the receiver is a JSProxy and it
|
||||
+ // might fail if the receiver is non-extensible or already has this property
|
||||
+ // as non-configurable.
|
||||
+ Maybe<bool> success = i::JSReceiver::DefineOwnProperty(
|
||||
+ i_isolate, self, name_i, &desc, Just(i::kDontThrow));
|
||||
+ USE(success);
|
||||
}
|
||||
|
||||
Maybe<bool> Object::SetNativeDataProperty(
|
||||
diff --git a/src/init/bootstrapper.cc b/src/init/bootstrapper.cc
|
||||
index 3f5050e824c09ee2577dbd8471ac6b1bcc20755e..f7fdf90f0baeb3dd3516c565bb5e05fc7e8da550 100644
|
||||
--- a/src/init/bootstrapper.cc
|
||||
+++ b/src/init/bootstrapper.cc
|
||||
@@ -631,7 +631,9 @@ V8_NOINLINE void SimpleInstallGetterSetter(Isolate* isolate,
|
||||
Handle<JSFunction> setter =
|
||||
SimpleCreateFunction(isolate, setter_name, call_setter, 1, true);
|
||||
|
||||
- JSObject::DefineAccessor(base, name, getter, setter, DONT_ENUM).Check();
|
||||
+ JSObject::DefineOwnAccessorIgnoreAttributes(base, name, getter, setter,
|
||||
+ DONT_ENUM)
|
||||
+ .Check();
|
||||
}
|
||||
|
||||
void SimpleInstallGetterSetter(Isolate* isolate, Handle<JSObject> base,
|
||||
@@ -655,7 +657,8 @@ V8_NOINLINE Handle<JSFunction> SimpleInstallGetter(Isolate* isolate,
|
||||
|
||||
Handle<Object> setter = isolate->factory()->undefined_value();
|
||||
|
||||
- JSObject::DefineAccessor(base, property_name, getter, setter, DONT_ENUM)
|
||||
+ JSObject::DefineOwnAccessorIgnoreAttributes(base, property_name, getter,
|
||||
+ setter, DONT_ENUM)
|
||||
.Check();
|
||||
|
||||
return getter;
|
||||
diff --git a/src/objects/js-objects.cc b/src/objects/js-objects.cc
|
||||
index 59c9f966036fdd3640b06b2d6962fc9994ab3c31..39cc83aacb5caf0791ce70212695f5016a22f274 100644
|
||||
--- a/src/objects/js-objects.cc
|
||||
+++ b/src/objects/js-objects.cc
|
||||
@@ -1519,7 +1519,8 @@ Maybe<bool> JSReceiver::ValidateAndApplyPropertyDescriptor(
|
||||
? desc->set()
|
||||
: Handle<Object>::cast(isolate->factory()->null_value()));
|
||||
MaybeHandle<Object> result =
|
||||
- JSObject::DefineAccessor(it, getter, setter, desc->ToAttributes());
|
||||
+ JSObject::DefineOwnAccessorIgnoreAttributes(it, getter, setter,
|
||||
+ desc->ToAttributes());
|
||||
if (result.is_null()) return Nothing<bool>();
|
||||
}
|
||||
}
|
||||
@@ -1703,8 +1704,8 @@ Maybe<bool> JSReceiver::ValidateAndApplyPropertyDescriptor(
|
||||
: current->has_set()
|
||||
? current->set()
|
||||
: Handle<Object>::cast(isolate->factory()->null_value()));
|
||||
- MaybeHandle<Object> result =
|
||||
- JSObject::DefineAccessor(it, getter, setter, attrs);
|
||||
+ MaybeHandle<Object> result = JSObject::DefineOwnAccessorIgnoreAttributes(
|
||||
+ it, getter, setter, attrs);
|
||||
if (result.is_null()) return Nothing<bool>();
|
||||
}
|
||||
}
|
||||
@@ -4638,22 +4639,19 @@ bool JSObject::HasEnumerableElements() {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
-MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
|
||||
- Handle<Name> name,
|
||||
- Handle<Object> getter,
|
||||
- Handle<Object> setter,
|
||||
- PropertyAttributes attributes) {
|
||||
+MaybeHandle<Object> JSObject::DefineOwnAccessorIgnoreAttributes(
|
||||
+ Handle<JSObject> object, Handle<Name> name, Handle<Object> getter,
|
||||
+ Handle<Object> setter, PropertyAttributes attributes) {
|
||||
Isolate* isolate = object->GetIsolate();
|
||||
|
||||
PropertyKey key(isolate, name);
|
||||
LookupIterator it(isolate, object, key, LookupIterator::OWN_SKIP_INTERCEPTOR);
|
||||
- return DefineAccessor(&it, getter, setter, attributes);
|
||||
+ return DefineOwnAccessorIgnoreAttributes(&it, getter, setter, attributes);
|
||||
}
|
||||
|
||||
-MaybeHandle<Object> JSObject::DefineAccessor(LookupIterator* it,
|
||||
- Handle<Object> getter,
|
||||
- Handle<Object> setter,
|
||||
- PropertyAttributes attributes) {
|
||||
+MaybeHandle<Object> JSObject::DefineOwnAccessorIgnoreAttributes(
|
||||
+ LookupIterator* it, Handle<Object> getter, Handle<Object> setter,
|
||||
+ PropertyAttributes attributes) {
|
||||
Isolate* isolate = it->isolate();
|
||||
|
||||
it->UpdateProtector();
|
||||
diff --git a/src/objects/js-objects.h b/src/objects/js-objects.h
|
||||
index 06489c2b7bae61ecadbd8f020060e86ef50e11b6..ff96bd4be2ff8d2fe03f75b6bca35a744e2084af 100644
|
||||
--- a/src/objects/js-objects.h
|
||||
+++ b/src/objects/js-objects.h
|
||||
@@ -531,13 +531,14 @@ class JSObject : public TorqueGeneratedJSObject<JSObject, JSReceiver> {
|
||||
GetPropertyAttributesWithFailedAccessCheck(LookupIterator* it);
|
||||
|
||||
// Defines an AccessorPair property on the given object.
|
||||
- V8_EXPORT_PRIVATE static MaybeHandle<Object> DefineAccessor(
|
||||
- Handle<JSObject> object, Handle<Name> name, Handle<Object> getter,
|
||||
- Handle<Object> setter, PropertyAttributes attributes);
|
||||
- static MaybeHandle<Object> DefineAccessor(LookupIterator* it,
|
||||
- Handle<Object> getter,
|
||||
- Handle<Object> setter,
|
||||
- PropertyAttributes attributes);
|
||||
+ V8_EXPORT_PRIVATE static MaybeHandle<Object>
|
||||
+ DefineOwnAccessorIgnoreAttributes(Handle<JSObject> object, Handle<Name> name,
|
||||
+ Handle<Object> getter,
|
||||
+ Handle<Object> setter,
|
||||
+ PropertyAttributes attributes);
|
||||
+ static MaybeHandle<Object> DefineOwnAccessorIgnoreAttributes(
|
||||
+ LookupIterator* it, Handle<Object> getter, Handle<Object> setter,
|
||||
+ PropertyAttributes attributes);
|
||||
|
||||
// Defines an AccessorInfo property on the given object.
|
||||
V8_WARN_UNUSED_RESULT static MaybeHandle<Object> SetAccessor(
|
||||
diff --git a/src/runtime/runtime-object.cc b/src/runtime/runtime-object.cc
|
||||
index 5255ee26807ab13e93935b6c6d513184a12da7cd..f10e4649c6d078c3120063d53e54f4126b2d2fd5 100644
|
||||
--- a/src/runtime/runtime-object.cc
|
||||
+++ b/src/runtime/runtime-object.cc
|
||||
@@ -1109,7 +1109,8 @@ RUNTIME_FUNCTION(Runtime_DefineAccessorPropertyUnchecked) {
|
||||
auto attrs = PropertyAttributesFromInt(args.smi_value_at(4));
|
||||
|
||||
RETURN_FAILURE_ON_EXCEPTION(
|
||||
- isolate, JSObject::DefineAccessor(obj, name, getter, setter, attrs));
|
||||
+ isolate, JSObject::DefineOwnAccessorIgnoreAttributes(obj, name, getter,
|
||||
+ setter, attrs));
|
||||
return ReadOnlyRoots(isolate).undefined_value();
|
||||
}
|
||||
|
||||
@@ -1215,8 +1216,8 @@ RUNTIME_FUNCTION(Runtime_DefineGetterPropertyUnchecked) {
|
||||
|
||||
RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate,
|
||||
- JSObject::DefineAccessor(object, name, getter,
|
||||
- isolate->factory()->null_value(), attrs));
|
||||
+ JSObject::DefineOwnAccessorIgnoreAttributes(
|
||||
+ object, name, getter, isolate->factory()->null_value(), attrs));
|
||||
return ReadOnlyRoots(isolate).undefined_value();
|
||||
}
|
||||
|
||||
@@ -1360,8 +1361,8 @@ RUNTIME_FUNCTION(Runtime_DefineSetterPropertyUnchecked) {
|
||||
|
||||
RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate,
|
||||
- JSObject::DefineAccessor(object, name, isolate->factory()->null_value(),
|
||||
- setter, attrs));
|
||||
+ JSObject::DefineOwnAccessorIgnoreAttributes(
|
||||
+ object, name, isolate->factory()->null_value(), setter, attrs));
|
||||
return ReadOnlyRoots(isolate).undefined_value();
|
||||
}
|
||||
|
||||
diff --git a/src/sandbox/testing.cc b/src/sandbox/testing.cc
|
||||
index fead4aa222ceb81d76f6dfec7e7797e337e7ba94..aab72a18015bf7ac1d0949e9497e85d9d089b4b8 100644
|
||||
--- a/src/sandbox/testing.cc
|
||||
+++ b/src/sandbox/testing.cc
|
||||
@@ -156,7 +156,8 @@ void InstallGetter(Isolate* isolate, Handle<JSObject> object,
|
||||
Handle<String> property_name = factory->NewStringFromAsciiChecked(name);
|
||||
Handle<JSFunction> getter = CreateFunc(isolate, func, property_name, false);
|
||||
Handle<Object> setter = factory->null_value();
|
||||
- JSObject::DefineAccessor(object, property_name, getter, setter, FROZEN);
|
||||
+ JSObject::DefineOwnAccessorIgnoreAttributes(object, property_name, getter,
|
||||
+ setter, FROZEN);
|
||||
}
|
||||
|
||||
void InstallFunction(Isolate* isolate, Handle<JSObject> holder,
|
||||
diff --git a/test/cctest/test-code-stub-assembler.cc b/test/cctest/test-code-stub-assembler.cc
|
||||
index c012e62016aca3a83975cd91216860ea9dc3d311..4c3402c7deec768931d07488cbbb79a0a7a7dd23 100644
|
||||
--- a/test/cctest/test-code-stub-assembler.cc
|
||||
+++ b/test/cctest/test-code-stub-assembler.cc
|
||||
@@ -1178,7 +1178,9 @@ void AddProperties(Handle<JSObject> object, Handle<Name> names[],
|
||||
Handle<AccessorPair> pair = Handle<AccessorPair>::cast(value);
|
||||
Handle<Object> getter(pair->getter(), isolate);
|
||||
Handle<Object> setter(pair->setter(), isolate);
|
||||
- JSObject::DefineAccessor(object, names[i], getter, setter, NONE).Check();
|
||||
+ JSObject::DefineOwnAccessorIgnoreAttributes(object, names[i], getter,
|
||||
+ setter, NONE)
|
||||
+ .Check();
|
||||
} else {
|
||||
JSObject::AddProperty(isolate, object, names[i], value, NONE);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Tebbi <tebbi@chromium.org>
|
||||
Date: Tue, 13 Jun 2023 17:08:59 +0200
|
||||
Subject: Merged: [compiler] StackCheck can have side effects
|
||||
|
||||
Bug: chromium:1452137
|
||||
(cherry picked from commit e548943e473b020fdc1de6e5543ca31b24d8b7f9)
|
||||
|
||||
Change-Id: Ibd7c9b02efd12341b452e4c34a635a58a817649f
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4637129
|
||||
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
|
||||
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
|
||||
Auto-Submit: Tobias Tebbi <tebbi@chromium.org>
|
||||
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/11.4@{#49}
|
||||
Cr-Branched-From: 8a8a1e7086dacc426965d3875914efa66663c431-refs/heads/11.4.183@{#1}
|
||||
Cr-Branched-From: 5483d8e816e0bbce865cbbc3fa0ab357e6330bab-refs/heads/main@{#87241}
|
||||
|
||||
diff --git a/src/compiler/js-operator.cc b/src/compiler/js-operator.cc
|
||||
index b72fe0a6669f6dfd7962f890017451d3fdc3f215..bace3a4647e14a8a3387fcffcd05195e9d11f926 100644
|
||||
--- a/src/compiler/js-operator.cc
|
||||
+++ b/src/compiler/js-operator.cc
|
||||
@@ -1396,7 +1396,7 @@ const Operator* JSOperatorBuilder::CloneObject(FeedbackSource const& feedback,
|
||||
const Operator* JSOperatorBuilder::StackCheck(StackCheckKind kind) {
|
||||
return zone()->New<Operator1<StackCheckKind>>( // --
|
||||
IrOpcode::kJSStackCheck, // opcode
|
||||
- Operator::kNoWrite, // properties
|
||||
+ Operator::kNoProperties, // properties
|
||||
"JSStackCheck", // name
|
||||
0, 1, 1, 0, 1, 2, // counts
|
||||
kind); // parameter
|
||||
@@ -0,0 +1,122 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Igor Sheludko <ishell@chromium.org>
|
||||
Date: Fri, 2 Jun 2023 18:13:01 +0200
|
||||
Subject: Merged: [ic] Fix store handler selection for arguments objects
|
||||
|
||||
Drive-by: fix printing of handlers in --trace-feedback-updates mode.
|
||||
|
||||
(cherry picked from commit e144f3b71e64e01d6ffd247eb15ca1ff56f6287b)
|
||||
|
||||
Bug: chromium:1450481
|
||||
Change-Id: Ifbb97d694b8520584df0610aad30805713b29c00
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4584889
|
||||
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
|
||||
Commit-Queue: Igor Sheludko <ishell@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/10.9@{#32}
|
||||
Cr-Branched-From: 8ade6bf1fa237ad30dd9a05cc6ffe548131699e8-refs/heads/10.9.194@{#1}
|
||||
Cr-Branched-From: 9ff2515271f11cab783f0e82678ae0b925d77dd0-refs/heads/main@{#84164}
|
||||
|
||||
diff --git a/src/diagnostics/objects-printer.cc b/src/diagnostics/objects-printer.cc
|
||||
index b763468f58f8f0be294af50188dd69b99c9428dc..e4e206f2b52095c95ac4c667f32f0620c753967c 100644
|
||||
--- a/src/diagnostics/objects-printer.cc
|
||||
+++ b/src/diagnostics/objects-printer.cc
|
||||
@@ -1324,8 +1324,18 @@ void FeedbackNexus::Print(std::ostream& os) {
|
||||
case FeedbackSlotKind::kSetKeyedStrict: {
|
||||
os << InlineCacheState2String(ic_state());
|
||||
if (ic_state() == InlineCacheState::MONOMORPHIC) {
|
||||
- os << "\n " << Brief(GetFeedback()) << ": ";
|
||||
- StoreHandler::PrintHandler(GetFeedbackExtra().GetHeapObjectOrSmi(), os);
|
||||
+ HeapObject feedback = GetFeedback().GetHeapObject();
|
||||
+ HeapObject feedback_extra = GetFeedbackExtra().GetHeapObject();
|
||||
+ if (feedback.IsName()) {
|
||||
+ os << " with name " << Brief(feedback);
|
||||
+ WeakFixedArray array = WeakFixedArray::cast(feedback_extra);
|
||||
+ os << "\n " << Brief(array.Get(0)) << ": ";
|
||||
+ Object handler = array.Get(1).GetHeapObjectOrSmi();
|
||||
+ StoreHandler::PrintHandler(handler, os);
|
||||
+ } else {
|
||||
+ os << "\n " << Brief(feedback) << ": ";
|
||||
+ StoreHandler::PrintHandler(feedback_extra, os);
|
||||
+ }
|
||||
} else if (ic_state() == InlineCacheState::POLYMORPHIC) {
|
||||
WeakFixedArray array =
|
||||
WeakFixedArray::cast(GetFeedback().GetHeapObject());
|
||||
diff --git a/src/ic/handler-configuration.cc b/src/ic/handler-configuration.cc
|
||||
index ece15ff24b9066158c85524ed0087f6804feb61c..ca49ed91db7b667fe3154a309e78130a9efe6d99 100644
|
||||
--- a/src/ic/handler-configuration.cc
|
||||
+++ b/src/ic/handler-configuration.cc
|
||||
@@ -593,8 +593,11 @@ void StoreHandler::PrintHandler(Object handler, std::ostream& os) {
|
||||
os << ", validity cell = ";
|
||||
store_handler.validity_cell().ShortPrint(os);
|
||||
os << ")" << std::endl;
|
||||
+ } else if (handler.IsMap()) {
|
||||
+ os << "StoreHandler(field transition to " << Brief(handler) << ")"
|
||||
+ << std::endl;
|
||||
} else {
|
||||
- os << "StoreHandler(<unexpected>)(" << Brief(handler) << ")";
|
||||
+ os << "StoreHandler(<unexpected>)(" << Brief(handler) << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/ic/ic.cc b/src/ic/ic.cc
|
||||
index 0447e017fbedae66eac2ad9637d53121a008f5b0..93939fa4702922f58e8e5bcc019e569f42ab198e 100644
|
||||
--- a/src/ic/ic.cc
|
||||
+++ b/src/ic/ic.cc
|
||||
@@ -2300,10 +2300,18 @@ Handle<Object> KeyedStoreIC::StoreElementHandler(
|
||||
receiver_map->has_sealed_elements() ||
|
||||
receiver_map->has_nonextensible_elements() ||
|
||||
receiver_map->has_typed_array_or_rab_gsab_typed_array_elements()) {
|
||||
+ // TODO(jgruber): Update counter name.
|
||||
TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreFastElementStub);
|
||||
- code = StoreHandler::StoreFastElementBuiltin(isolate(), store_mode);
|
||||
- if (receiver_map->has_typed_array_or_rab_gsab_typed_array_elements()) {
|
||||
- return code;
|
||||
+ if (receiver_map->IsJSArgumentsObjectMap() &&
|
||||
+ receiver_map->has_fast_packed_elements()) {
|
||||
+ // Allow fast behaviour for in-bounds stores while making it miss and
|
||||
+ // properly handle the out of bounds store case.
|
||||
+ code = StoreHandler::StoreFastElementBuiltin(isolate(), STANDARD_STORE);
|
||||
+ } else {
|
||||
+ code = StoreHandler::StoreFastElementBuiltin(isolate(), store_mode);
|
||||
+ if (receiver_map->has_typed_array_or_rab_gsab_typed_array_elements()) {
|
||||
+ return code;
|
||||
+ }
|
||||
}
|
||||
} else if (IsStoreInArrayLiteralIC()) {
|
||||
// TODO(jgruber): Update counter name.
|
||||
@@ -2314,7 +2322,7 @@ Handle<Object> KeyedStoreIC::StoreElementHandler(
|
||||
TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_StoreElementStub);
|
||||
DCHECK(DICTIONARY_ELEMENTS == receiver_map->elements_kind() ||
|
||||
receiver_map->has_frozen_elements());
|
||||
- code = StoreHandler::StoreSlow(isolate(), store_mode);
|
||||
+ return StoreHandler::StoreSlow(isolate(), store_mode);
|
||||
}
|
||||
|
||||
if (IsAnyDefineOwn() || IsStoreInArrayLiteralIC()) return code;
|
||||
diff --git a/src/objects/map-inl.h b/src/objects/map-inl.h
|
||||
index a83a060337739878f258c50d8013d5ba6c2262d8..723a961521f26cdad66a484f39037f94109e2cac 100644
|
||||
--- a/src/objects/map-inl.h
|
||||
+++ b/src/objects/map-inl.h
|
||||
@@ -590,6 +590,10 @@ bool Map::has_fast_elements() const {
|
||||
return IsFastElementsKind(elements_kind());
|
||||
}
|
||||
|
||||
+bool Map::has_fast_packed_elements() const {
|
||||
+ return IsFastPackedElementsKind(elements_kind());
|
||||
+}
|
||||
+
|
||||
bool Map::has_sloppy_arguments_elements() const {
|
||||
return IsSloppyArgumentsElementsKind(elements_kind());
|
||||
}
|
||||
diff --git a/src/objects/map.h b/src/objects/map.h
|
||||
index 6914a51150f4235386f5dca7af0d8103bc64f9e2..8311850f82bc32b794873689789c510376f67233 100644
|
||||
--- a/src/objects/map.h
|
||||
+++ b/src/objects/map.h
|
||||
@@ -422,6 +422,7 @@ class Map : public TorqueGeneratedMap<Map, HeapObject> {
|
||||
inline bool has_fast_smi_or_object_elements() const;
|
||||
inline bool has_fast_double_elements() const;
|
||||
inline bool has_fast_elements() const;
|
||||
+ inline bool has_fast_packed_elements() const;
|
||||
inline bool has_sloppy_arguments_elements() const;
|
||||
inline bool has_fast_sloppy_arguments_elements() const;
|
||||
inline bool has_fast_string_wrapper_elements() const;
|
||||
@@ -0,0 +1,44 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Toon Verwaest <verwaest@chromium.org>
|
||||
Date: Fri, 16 Jun 2023 17:13:52 +0200
|
||||
Subject: Merged: [runtime] Set instance prototypes directly on maps
|
||||
|
||||
Bug: chromium:1452137
|
||||
(cherry picked from commit c7c447735f762f6d6d0878e229371797845ef4ab)
|
||||
|
||||
Change-Id: I611c41f942e2e51f3c4b4f1d119c18410617188e
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4637888
|
||||
Commit-Queue: Igor Sheludko <ishell@chromium.org>
|
||||
Auto-Submit: Igor Sheludko <ishell@chromium.org>
|
||||
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
|
||||
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/11.4@{#47}
|
||||
Cr-Branched-From: 8a8a1e7086dacc426965d3875914efa66663c431-refs/heads/11.4.183@{#1}
|
||||
Cr-Branched-From: 5483d8e816e0bbce865cbbc3fa0ab357e6330bab-refs/heads/main@{#87241}
|
||||
|
||||
diff --git a/src/objects/js-function.cc b/src/objects/js-function.cc
|
||||
index 54aec3861bbfdf956740a6c5d3bd5a6721a95a3f..2aa0710bc39d7bfbf55ae8ab2707d2be55cbb6b0 100644
|
||||
--- a/src/objects/js-function.cc
|
||||
+++ b/src/objects/js-function.cc
|
||||
@@ -673,6 +673,10 @@ void SetInstancePrototype(Isolate* isolate, Handle<JSFunction> function,
|
||||
// At that point, a new initial map is created and the prototype is put
|
||||
// into the initial map where it belongs.
|
||||
function->set_prototype_or_initial_map(*value, kReleaseStore);
|
||||
+ if (value->IsJSObjectThatCanBeTrackedAsPrototype()) {
|
||||
+ // Optimize as prototype to detach it from its transition tree.
|
||||
+ JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value));
|
||||
+ }
|
||||
} else {
|
||||
Handle<Map> new_map =
|
||||
Map::Copy(isolate, initial_map, "SetInstancePrototype");
|
||||
@@ -798,8 +802,10 @@ void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
|
||||
Handle<HeapObject> prototype;
|
||||
if (function->has_instance_prototype()) {
|
||||
prototype = handle(function->instance_prototype(), isolate);
|
||||
+ map->set_prototype(*prototype);
|
||||
} else {
|
||||
prototype = isolate->factory()->NewFunctionPrototype(function);
|
||||
+ Map::SetPrototype(isolate, map, prototype);
|
||||
}
|
||||
DCHECK(map->has_fast_object_elements());
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Pedro Pontes <pepontes@microsoft.com>
|
||||
Date: Thu, 29 Jun 2023 01:14:35 -0700
|
||||
Subject: Fix using shared objects as prototypes more (Partial backport)
|
||||
|
||||
The previous fix from
|
||||
https://chromium-review.googlesource.com/c/v8/v8/+/4086127 was
|
||||
insufficient. It prevented shared objects from being optimized as
|
||||
prototypes, but callers of OptimizeAsPrototype also assume that all
|
||||
JSObjects can track prototype users via prototype_info on the map.
|
||||
|
||||
This CL attempts a broader fix where shared objects are not considered
|
||||
optimizable as prototypes at all. When used as a prototype, shared
|
||||
objects are treated like non-JSObjects (e.g. JSProxy, WasmObject).
|
||||
|
||||
Bug: chromium:1401295, v8:12547
|
||||
Change-Id: I9886e9ccac9e597e7dd34a09083a096ff4e3bf16
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4112150
|
||||
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
|
||||
Commit-Queue: Shu-yu Guo <syg@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/main@{#84916}
|
||||
|
||||
diff --git a/src/objects/heap-object.h b/src/objects/heap-object.h
|
||||
index 2e4ad85766d95a081f6a59488c07971710aa082f..e1473ae473eda5ad5aeda075331ef0c549cba724 100644
|
||||
--- a/src/objects/heap-object.h
|
||||
+++ b/src/objects/heap-object.h
|
||||
@@ -119,6 +119,8 @@ class HeapObject : public Object {
|
||||
STRUCT_LIST(DECL_STRUCT_PREDICATE)
|
||||
#undef DECL_STRUCT_PREDICATE
|
||||
|
||||
+ V8_INLINE bool IsJSObjectThatCanBeTrackedAsPrototype() const;
|
||||
+
|
||||
// Converts an address to a HeapObject pointer.
|
||||
static inline HeapObject FromAddress(Address address) {
|
||||
DCHECK_TAG_ALIGNED(address);
|
||||
diff --git a/src/objects/objects-inl.h b/src/objects/objects-inl.h
|
||||
index 36ddbfb6a1e35ff142e0b81b6b182aa166ce6204..f2108a8a61792dc3c440a8aa507319277fc780c1 100644
|
||||
--- a/src/objects/objects-inl.h
|
||||
+++ b/src/objects/objects-inl.h
|
||||
@@ -84,6 +84,11 @@ bool Object::InSharedWritableHeap() const {
|
||||
return IsHeapObject() && HeapObject::cast(*this).InSharedWritableHeap();
|
||||
}
|
||||
|
||||
+bool Object::IsJSObjectThatCanBeTrackedAsPrototype() const {
|
||||
+ return IsHeapObject() &&
|
||||
+ HeapObject::cast(*this).IsJSObjectThatCanBeTrackedAsPrototype();
|
||||
+}
|
||||
+
|
||||
#define IS_TYPE_FUNCTION_DEF(type_) \
|
||||
bool Object::Is##type_() const { \
|
||||
return IsHeapObject() && HeapObject::cast(*this).Is##type_(); \
|
||||
@@ -190,6 +195,13 @@ bool HeapObject::InSharedWritableHeap() const {
|
||||
return BasicMemoryChunk::FromHeapObject(*this)->InSharedHeap();
|
||||
}
|
||||
|
||||
+bool HeapObject::IsJSObjectThatCanBeTrackedAsPrototype() const {
|
||||
+ // Do not optimize objects in the shared heap because it is not
|
||||
+ // threadsafe. Objects in the shared heap have fixed layouts and their maps
|
||||
+ // never change.
|
||||
+ return IsJSObject() && !InSharedWritableHeap();
|
||||
+}
|
||||
+
|
||||
bool HeapObject::IsNullOrUndefined(Isolate* isolate) const {
|
||||
return IsNullOrUndefined(ReadOnlyRoots(isolate));
|
||||
}
|
||||
diff --git a/src/objects/objects.h b/src/objects/objects.h
|
||||
index 2fa31a912c75a832cc0e051dfd54f4cd1ac50a79..fb02858b48507ef4c358a3b254c24ef95b366ee4 100644
|
||||
--- a/src/objects/objects.h
|
||||
+++ b/src/objects/objects.h
|
||||
@@ -341,6 +341,8 @@ class Object : public TaggedImpl<HeapObjectReferenceType::STRONG, Address> {
|
||||
bool IsWasmObject(Isolate* = nullptr) const { return false; }
|
||||
#endif
|
||||
|
||||
+ V8_INLINE bool IsJSObjectThatCanBeTrackedAsPrototype() const;
|
||||
+
|
||||
enum class Conversion { kToNumber, kToNumeric };
|
||||
|
||||
#define DECL_STRUCT_PREDICATE(NAME, Name, name) \
|
||||
@@ -1 +1,5 @@
|
||||
fix_fallback_to_x11_capturer_on_wayland.patch
|
||||
m114_move_transceiver_iteration_loop_over_to_the_signaling_thread.patch
|
||||
m114_sdp_reject_duplicate_ssrcs_in_ssrc-groups.patch
|
||||
pipewire_capturer_fix_fcntl_call_when_duplicating_a_file_descriptor.patch
|
||||
pipewire_capturer_increase_buffer_size_to_avoid_buffer_overflow.patch
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tommi <tommi@webrtc.org>
|
||||
Date: Thu, 1 Jun 2023 16:08:52 +0200
|
||||
Subject: Move transceiver iteration loop over to the signaling thread.
|
||||
|
||||
This is required for ReportTransportStats since iterating over the
|
||||
transceiver list from the network thread is not safe.
|
||||
|
||||
(cherry picked from commit dba22d31909298161318e00d43a80cdb0abc940f)
|
||||
|
||||
No-Try: true
|
||||
Bug: chromium:1446274, webrtc:12692
|
||||
Change-Id: I7c514df9f029112c4b1da85826af91217850fb26
|
||||
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/307340
|
||||
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
|
||||
Commit-Queue: Tomas Gunnarsson <tommi@webrtc.org>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#40197}
|
||||
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/308001
|
||||
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
|
||||
Cr-Commit-Position: refs/branch-heads/5735@{#3}
|
||||
Cr-Branched-From: df7df199abd619e75b9f1d9a7e12fc3f3f748775-refs/heads/main@{#39949}
|
||||
|
||||
diff --git a/pc/peer_connection.cc b/pc/peer_connection.cc
|
||||
index 5de77fee9d2e5c76438b8612f29afc067bd02c13..7333bd59b99a618339413f0647562ed5ff5841d6 100644
|
||||
--- a/pc/peer_connection.cc
|
||||
+++ b/pc/peer_connection.cc
|
||||
@@ -727,9 +727,6 @@ JsepTransportController* PeerConnection::InitializeTransportController_n(
|
||||
transport_controller_->SubscribeIceConnectionState(
|
||||
[this](cricket::IceConnectionState s) {
|
||||
RTC_DCHECK_RUN_ON(network_thread());
|
||||
- if (s == cricket::kIceConnectionConnected) {
|
||||
- ReportTransportStats();
|
||||
- }
|
||||
signaling_thread()->PostTask(
|
||||
SafeTask(signaling_thread_safety_.flag(), [this, s]() {
|
||||
RTC_DCHECK_RUN_ON(signaling_thread());
|
||||
@@ -2390,6 +2387,20 @@ void PeerConnection::OnTransportControllerConnectionState(
|
||||
case cricket::kIceConnectionConnected:
|
||||
RTC_LOG(LS_INFO) << "Changing to ICE connected state because "
|
||||
"all transports are writable.";
|
||||
+ {
|
||||
+ std::vector<RtpTransceiverProxyRefPtr> transceivers;
|
||||
+ if (ConfiguredForMedia()) {
|
||||
+ transceivers = rtp_manager()->transceivers()->List();
|
||||
+ }
|
||||
+
|
||||
+ network_thread()->PostTask(
|
||||
+ SafeTask(network_thread_safety_,
|
||||
+ [this, transceivers = std::move(transceivers)] {
|
||||
+ RTC_DCHECK_RUN_ON(network_thread());
|
||||
+ ReportTransportStats(std::move(transceivers));
|
||||
+ }));
|
||||
+ }
|
||||
+
|
||||
SetIceConnectionState(PeerConnectionInterface::kIceConnectionConnected);
|
||||
NoteUsageEvent(UsageEvent::ICE_STATE_CONNECTED);
|
||||
break;
|
||||
@@ -2730,20 +2741,18 @@ void PeerConnection::OnTransportControllerGatheringState(
|
||||
}
|
||||
|
||||
// Runs on network_thread().
|
||||
-void PeerConnection::ReportTransportStats() {
|
||||
+void PeerConnection::ReportTransportStats(
|
||||
+ std::vector<RtpTransceiverProxyRefPtr> transceivers) {
|
||||
TRACE_EVENT0("webrtc", "PeerConnection::ReportTransportStats");
|
||||
rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
|
||||
std::map<std::string, std::set<cricket::MediaType>>
|
||||
media_types_by_transport_name;
|
||||
- if (ConfiguredForMedia()) {
|
||||
- for (const auto& transceiver :
|
||||
- rtp_manager()->transceivers()->UnsafeList()) {
|
||||
- if (transceiver->internal()->channel()) {
|
||||
- std::string transport_name(
|
||||
- transceiver->internal()->channel()->transport_name());
|
||||
- media_types_by_transport_name[transport_name].insert(
|
||||
- transceiver->media_type());
|
||||
- }
|
||||
+ for (const auto& transceiver : transceivers) {
|
||||
+ if (transceiver->internal()->channel()) {
|
||||
+ std::string transport_name(
|
||||
+ transceiver->internal()->channel()->transport_name());
|
||||
+ media_types_by_transport_name[transport_name].insert(
|
||||
+ transceiver->media_type());
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/pc/peer_connection.h b/pc/peer_connection.h
|
||||
index 39a240da4f3e601e8eea1a61dcab75369e51ac05..7f150822e9f224680fc4649a46f319ed97f9a171 100644
|
||||
--- a/pc/peer_connection.h
|
||||
+++ b/pc/peer_connection.h
|
||||
@@ -567,7 +567,8 @@ class PeerConnection : public PeerConnectionInternal,
|
||||
|
||||
// Invoked when TransportController connection completion is signaled.
|
||||
// Reports stats for all transports in use.
|
||||
- void ReportTransportStats() RTC_RUN_ON(network_thread());
|
||||
+ void ReportTransportStats(std::vector<RtpTransceiverProxyRefPtr> transceivers)
|
||||
+ RTC_RUN_ON(network_thread());
|
||||
|
||||
// Gather the usage of IPv4/IPv6 as best connection.
|
||||
static void ReportBestConnectionState(const cricket::TransportStats& stats);
|
||||
diff --git a/pc/peer_connection_integrationtest.cc b/pc/peer_connection_integrationtest.cc
|
||||
index 7fa94527f1002b6a3d17b9aa45211e51a51d7544..c12cbd4fcac2b110d875a1371d29ad54f48c8d71 100644
|
||||
--- a/pc/peer_connection_integrationtest.cc
|
||||
+++ b/pc/peer_connection_integrationtest.cc
|
||||
@@ -1836,6 +1836,10 @@ TEST_P(PeerConnectionIntegrationTest,
|
||||
EXPECT_EQ_WAIT(webrtc::PeerConnectionInterface::kIceConnectionConnected,
|
||||
callee()->ice_connection_state(), kDefaultTimeout);
|
||||
|
||||
+ // Part of reporting the stats will occur on the network thread, so flush it
|
||||
+ // before checking NumEvents.
|
||||
+ SendTask(network_thread(), [] {});
|
||||
+
|
||||
EXPECT_METRIC_EQ(1, webrtc::metrics::NumEvents(
|
||||
"WebRTC.PeerConnection.CandidatePairType_UDP",
|
||||
webrtc::kIceCandidatePairHostNameHostName));
|
||||
@@ -1964,6 +1968,10 @@ TEST_P(PeerConnectionIntegrationIceStatesTest, MAYBE_VerifyBestConnection) {
|
||||
EXPECT_EQ_WAIT(webrtc::PeerConnectionInterface::kIceConnectionConnected,
|
||||
callee()->ice_connection_state(), kDefaultTimeout);
|
||||
|
||||
+ // Part of reporting the stats will occur on the network thread, so flush it
|
||||
+ // before checking NumEvents.
|
||||
+ SendTask(network_thread(), [] {});
|
||||
+
|
||||
// TODO(bugs.webrtc.org/9456): Fix it.
|
||||
const int num_best_ipv4 = webrtc::metrics::NumEvents(
|
||||
"WebRTC.PeerConnection.IPMetrics", webrtc::kBestConnections_IPv4);
|
||||
@@ -0,0 +1,79 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Philipp Hancke <phancke@microsoft.com>
|
||||
Date: Thu, 15 Jun 2023 07:21:56 +0200
|
||||
Subject: sdp: reject duplicate ssrcs in ssrc-groups
|
||||
|
||||
while not really covered by
|
||||
https://www.rfc-editor.org/rfc/rfc5576.html#section-4.2
|
||||
and using the same SSRC for RTX and primary payload may work
|
||||
since payload type demuxing *could* be used is not a good idea.
|
||||
This also applies to flexfec's FEC-FR.
|
||||
|
||||
For the nonstandard SIM ssrc-group duplicates make no sense.
|
||||
This rejects duplicates for unknown ssrc-groups as well.
|
||||
|
||||
BUG=chromium:1454860
|
||||
|
||||
(cherry picked from commit 6a38a3eb38f732b89ca0d8e36c43a434670c4ef5)
|
||||
|
||||
No-Try: true
|
||||
Change-Id: I3e86101dbd5d6c4099f2fdb7b4a52d5cd0809c5f
|
||||
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/308820
|
||||
Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
|
||||
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
|
||||
Commit-Queue: Philipp Hancke <phancke@microsoft.com>
|
||||
Cr-Original-Commit-Position: refs/heads/main@{#40292}
|
||||
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/309601
|
||||
Cr-Commit-Position: refs/branch-heads/5735@{#4}
|
||||
Cr-Branched-From: df7df199abd619e75b9f1d9a7e12fc3f3f748775-refs/heads/main@{#39949}
|
||||
|
||||
diff --git a/pc/webrtc_sdp.cc b/pc/webrtc_sdp.cc
|
||||
index 69fa62ca37ff6e86524f707dcd8abe51688fea25..707e7cbadb2391eda609608b75ae50c9e30bac58 100644
|
||||
--- a/pc/webrtc_sdp.cc
|
||||
+++ b/pc/webrtc_sdp.cc
|
||||
@@ -3506,6 +3506,11 @@ bool ParseSsrcGroupAttribute(absl::string_view line,
|
||||
if (!GetValueFromString(line, fields[i], &ssrc, error)) {
|
||||
return false;
|
||||
}
|
||||
+ // Reject duplicates. While not forbidden by RFC 5576,
|
||||
+ // they don't make sense.
|
||||
+ if (absl::c_linear_search(ssrcs, ssrc)) {
|
||||
+ return ParseFailed(line, "Duplicate SSRC in ssrc-group", error);
|
||||
+ }
|
||||
ssrcs.push_back(ssrc);
|
||||
}
|
||||
ssrc_groups->push_back(SsrcGroup(semantics, ssrcs));
|
||||
diff --git a/pc/webrtc_sdp_unittest.cc b/pc/webrtc_sdp_unittest.cc
|
||||
index 9f1cfc9c96aac958c0bec6a48c636b22ac319219..2e15fadb3b6e9784845993b162ee6fe058962b35 100644
|
||||
--- a/pc/webrtc_sdp_unittest.cc
|
||||
+++ b/pc/webrtc_sdp_unittest.cc
|
||||
@@ -4980,3 +4980,29 @@ TEST_F(WebRtcSdpTest, ParseIgnoreUnknownSsrcSpecificAttribute) {
|
||||
SdpParseError error;
|
||||
ASSERT_TRUE(webrtc::SdpDeserialize(sdp, &output, &error));
|
||||
}
|
||||
+
|
||||
+TEST_F(WebRtcSdpTest, RejectDuplicateSsrcInSsrcGroup) {
|
||||
+ std::string sdp =
|
||||
+ "v=0\r\n"
|
||||
+ "o=- 0 3 IN IP4 127.0.0.1\r\n"
|
||||
+ "s=-\r\n"
|
||||
+ "t=0 0\r\n"
|
||||
+ "a=group:BUNDLE 0\r\n"
|
||||
+ "a=fingerprint:sha-1 "
|
||||
+ "4A:AD:B9:B1:3F:82:18:3B:54:02:12:DF:3E:5D:49:6B:19:E5:7C:AB\r\n"
|
||||
+ "a=setup:actpass\r\n"
|
||||
+ "a=ice-ufrag:ETEn\r\n"
|
||||
+ "a=ice-pwd:OtSK0WpNtpUjkY4+86js7Z/l\r\n"
|
||||
+ "m=video 9 UDP/TLS/RTP/SAVPF 96 97\r\n"
|
||||
+ "c=IN IP4 0.0.0.0\r\n"
|
||||
+ "a=rtcp-mux\r\n"
|
||||
+ "a=sendonly\r\n"
|
||||
+ "a=mid:0\r\n"
|
||||
+ "a=rtpmap:96 VP8/90000\r\n"
|
||||
+ "a=rtpmap:97 rtx/90000\r\n"
|
||||
+ "a=fmtp:97 apt=96\r\n"
|
||||
+ "a=ssrc-group:FID 1234 1234\r\n"
|
||||
+ "a=ssrc:1234 cname:test\r\n";
|
||||
+ JsepSessionDescription jdesc(kDummyType);
|
||||
+ EXPECT_FALSE(SdpDeserialize(sdp, &jdesc));
|
||||
+}
|
||||
@@ -0,0 +1,29 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jan Grulich <grulja@gmail.com>
|
||||
Date: Fri, 12 May 2023 20:59:06 +0200
|
||||
Subject: PipeWire capturer: fix fcntl call when duplicating a file descriptor
|
||||
|
||||
The fcntl() call has variable arguments, therefore we need to pass 0 to
|
||||
specify there are no other arguments for this call, otherwise we might
|
||||
end up with an argument that is random garbage.
|
||||
|
||||
Bug: webrtc:15174
|
||||
Change-Id: I34f16a942d80913b667d8ade7eed557b0233be01
|
||||
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/305120
|
||||
Reviewed-by: Alexander Cooper <alcooper@chromium.org>
|
||||
Commit-Queue: Jan Grulich <grulja@gmail.com>
|
||||
Cr-Commit-Position: refs/heads/main@{#40060}
|
||||
|
||||
diff --git a/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc b/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc
|
||||
index 71bde9b21234e789a84cd3617df054d9a4604992..4e79ecd36982c15219bf4d3d2e337e2157359e88 100644
|
||||
--- a/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc
|
||||
+++ b/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc
|
||||
@@ -432,7 +432,7 @@ bool SharedScreenCastStreamPrivate::StartScreenCastStream(
|
||||
|
||||
if (fd >= 0) {
|
||||
pw_core_ = pw_context_connect_fd(
|
||||
- pw_context_, fcntl(fd, F_DUPFD_CLOEXEC), nullptr, 0);
|
||||
+ pw_context_, fcntl(fd, F_DUPFD_CLOEXEC, 0), nullptr, 0);
|
||||
} else {
|
||||
pw_core_ = pw_context_connect(pw_context_, nullptr, 0);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jan Grulich <grulja@gmail.com>
|
||||
Date: Mon, 10 Jul 2023 10:07:38 +0200
|
||||
Subject: PipeWire capturer: increase buffer size to avoid buffer overflow
|
||||
|
||||
Recently added framerate option can cause a buffer overflow and make
|
||||
PipeWire to fail on negotiation, which effectively makes screen sharing
|
||||
not to work.
|
||||
|
||||
Bug: webrtc:15346
|
||||
Change-Id: I4a68e26c8f85ca287b06a25da500b6a7009e075f
|
||||
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/311541
|
||||
Reviewed-by: Alexander Cooper <alcooper@chromium.org>
|
||||
Commit-Queue: Jan Grulich <grulja@gmail.com>
|
||||
Cr-Commit-Position: refs/heads/main@{#40413}
|
||||
|
||||
diff --git a/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc b/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc
|
||||
index 4e79ecd36982c15219bf4d3d2e337e2157359e88..a95007b34a8cd19cfac83bd26530b0c1b7eb368a 100644
|
||||
--- a/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc
|
||||
+++ b/modules/desktop_capture/linux/wayland/shared_screencast_stream.cc
|
||||
@@ -263,7 +263,7 @@ void SharedScreenCastStreamPrivate::OnStreamParamChanged(
|
||||
|
||||
that->stream_size_ = DesktopSize(width, height);
|
||||
|
||||
- uint8_t buffer[1024] = {};
|
||||
+ uint8_t buffer[2048] = {};
|
||||
auto builder = spa_pod_builder{buffer, sizeof(buffer)};
|
||||
|
||||
// Setup buffers and meta header for new format.
|
||||
@@ -348,7 +348,7 @@ void SharedScreenCastStreamPrivate::OnRenegotiateFormat(void* data, uint64_t) {
|
||||
{
|
||||
PipeWireThreadLoopLock thread_loop_lock(that->pw_main_loop_);
|
||||
|
||||
- uint8_t buffer[2048] = {};
|
||||
+ uint8_t buffer[4096] = {};
|
||||
|
||||
spa_pod_builder builder = spa_pod_builder{buffer, sizeof(buffer)};
|
||||
|
||||
@@ -464,7 +464,7 @@ bool SharedScreenCastStreamPrivate::StartScreenCastStream(
|
||||
|
||||
pw_stream_add_listener(pw_stream_, &spa_stream_listener_,
|
||||
&pw_stream_events_, this);
|
||||
- uint8_t buffer[2048] = {};
|
||||
+ uint8_t buffer[4096] = {};
|
||||
|
||||
spa_pod_builder builder = spa_pod_builder{buffer, sizeof(buffer)};
|
||||
|
||||
@@ -77,7 +77,7 @@ async function validateReleaseAssets (release, validatingRelease) {
|
||||
} else {
|
||||
await verifyShasumsForRemoteFiles(downloadUrls)
|
||||
.catch(err => {
|
||||
console.log(`${fail} error verifyingShasums`, err);
|
||||
console.error(`${fail} error verifyingShasums`, err);
|
||||
});
|
||||
}
|
||||
const azRemoteFiles = azRemoteFilesForVersion(release.tag_name);
|
||||
@@ -90,7 +90,7 @@ function check (condition, statement, exitIfFail = false) {
|
||||
console.log(`${pass} ${statement}`);
|
||||
} else {
|
||||
failureCount++;
|
||||
console.log(`${fail} ${statement}`);
|
||||
console.error(`${fail} ${statement}`);
|
||||
if (exitIfFail) process.exit(1);
|
||||
}
|
||||
}
|
||||
@@ -212,7 +212,7 @@ function runScript (scriptName, scriptArgs, cwd) {
|
||||
try {
|
||||
return execSync(scriptCommand, scriptOptions);
|
||||
} catch (err) {
|
||||
console.log(`${fail} Error running ${scriptName}`, err);
|
||||
console.error(`${fail} Error running ${scriptName}`, err);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
@@ -266,7 +266,8 @@ async function createReleaseShasums (release) {
|
||||
repo: targetRepo,
|
||||
asset_id: existingAssets[0].id
|
||||
}).catch(err => {
|
||||
console.log(`${fail} Error deleting ${fileName} on GitHub:`, err);
|
||||
console.error(`${fail} Error deleting ${fileName} on GitHub:`, err);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
console.log(`Creating and uploading the release ${fileName}.`);
|
||||
@@ -292,7 +293,7 @@ async function uploadShasumFile (filePath, fileName, releaseId) {
|
||||
data: fs.createReadStream(filePath),
|
||||
name: fileName
|
||||
}).catch(err => {
|
||||
console.log(`${fail} Error uploading ${filePath} to GitHub:`, err);
|
||||
console.error(`${fail} Error uploading ${filePath} to GitHub:`, err);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
@@ -301,13 +302,13 @@ function saveShaSumFile (checksums, fileName) {
|
||||
return new Promise((resolve, reject) => {
|
||||
temp.open(fileName, (err, info) => {
|
||||
if (err) {
|
||||
console.log(`${fail} Could not create ${fileName} file`);
|
||||
console.error(`${fail} Could not create ${fileName} file`);
|
||||
process.exit(1);
|
||||
} else {
|
||||
fs.writeFileSync(info.fd, checksums);
|
||||
fs.close(info.fd, (err) => {
|
||||
if (err) {
|
||||
console.log(`${fail} Could close ${fileName} file`);
|
||||
console.error(`${fail} Could close ${fileName} file`);
|
||||
process.exit(1);
|
||||
}
|
||||
resolve(info.path);
|
||||
@@ -333,7 +334,7 @@ async function publishRelease (release) {
|
||||
draft: false,
|
||||
make_latest: makeLatest ? 'true' : 'false'
|
||||
}).catch(err => {
|
||||
console.log(`${fail} Error publishing release:`, err);
|
||||
console.error(`${fail} Error publishing release:`, err);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
@@ -351,13 +352,17 @@ async function makeRelease (releaseToValidate) {
|
||||
} else {
|
||||
let draftRelease = await getDraftRelease();
|
||||
uploadNodeShasums();
|
||||
uploadIndexJson();
|
||||
|
||||
await createReleaseShasums(draftRelease);
|
||||
|
||||
// Fetch latest version of release before verifying
|
||||
draftRelease = await getDraftRelease(pkgVersion, true);
|
||||
await validateReleaseAssets(draftRelease);
|
||||
// index.json goes live once uploaded so do these uploads as
|
||||
// late as possible to reduce the chances it contains a release
|
||||
// which fails to publish. It has to be done before the final
|
||||
// publish to ensure there aren't published releases not contained
|
||||
// in index.json, which causes other problems in downstream projects
|
||||
uploadIndexJson();
|
||||
await publishRelease(draftRelease);
|
||||
console.log(`${pass} SUCCESS!!! Release has been published. Please run ` +
|
||||
'"npm run publish-to-npm" to publish release to npm.');
|
||||
@@ -403,7 +408,7 @@ async function verifyDraftGitHubReleaseAssets (release) {
|
||||
|
||||
return { url: response.headers.location, file: asset.name };
|
||||
})).catch(err => {
|
||||
console.log(`${fail} Error downloading files from GitHub`, err);
|
||||
console.error(`${fail} Error downloading files from GitHub`, err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ def main():
|
||||
chromedriver_name = {
|
||||
'darwin': 'chromedriver',
|
||||
'win32': 'chromedriver.exe',
|
||||
'linux': 'chromedriver',
|
||||
'linux2': 'chromedriver'
|
||||
}
|
||||
|
||||
|
||||
@@ -78,15 +78,20 @@ void StopTracing(gin_helper::Promise<base::FilePath> promise,
|
||||
}
|
||||
},
|
||||
std::move(promise), *file_path);
|
||||
if (file_path) {
|
||||
|
||||
auto* instance = TracingController::GetInstance();
|
||||
if (!instance->IsTracing()) {
|
||||
std::move(resolve_or_reject)
|
||||
.Run(absl::make_optional(
|
||||
"Failed to stop tracing - no trace in progress"));
|
||||
} else if (file_path) {
|
||||
auto split_callback = base::SplitOnceCallback(std::move(resolve_or_reject));
|
||||
auto endpoint = TracingController::CreateFileEndpoint(
|
||||
*file_path,
|
||||
base::BindOnce(std::move(split_callback.first), absl::nullopt));
|
||||
if (!TracingController::GetInstance()->StopTracing(endpoint)) {
|
||||
if (!instance->StopTracing(endpoint)) {
|
||||
std::move(split_callback.second)
|
||||
.Run(absl::make_optional(
|
||||
"Failed to stop tracing (was a trace in progress?)"));
|
||||
.Run(absl::make_optional("Failed to stop tracing"));
|
||||
}
|
||||
} else {
|
||||
std::move(resolve_or_reject)
|
||||
|
||||
@@ -181,6 +181,41 @@ DesktopCapturer::DesktopCapturer(v8::Isolate* isolate) {}
|
||||
|
||||
DesktopCapturer::~DesktopCapturer() = default;
|
||||
|
||||
DesktopCapturer::DesktopListListener::DesktopListListener(
|
||||
OnceCallback update_callback,
|
||||
OnceCallback failure_callback,
|
||||
bool skip_thumbnails)
|
||||
: update_callback_(std::move(update_callback)),
|
||||
failure_callback_(std::move(failure_callback)),
|
||||
have_thumbnail_(skip_thumbnails) {}
|
||||
|
||||
DesktopCapturer::DesktopListListener::~DesktopListListener() = default;
|
||||
|
||||
void DesktopCapturer::DesktopListListener::OnDelegatedSourceListSelection() {
|
||||
if (have_thumbnail_) {
|
||||
std::move(update_callback_).Run();
|
||||
} else {
|
||||
have_selection_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
void DesktopCapturer::DesktopListListener::OnSourceThumbnailChanged(int index) {
|
||||
if (have_selection_) {
|
||||
// This is called every time a thumbnail is refreshed. Reset variable to
|
||||
// ensure that the callback is not run again.
|
||||
have_selection_ = false;
|
||||
|
||||
// PipeWire returns a single source, so index is not relevant.
|
||||
std::move(update_callback_).Run();
|
||||
} else {
|
||||
have_thumbnail_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
void DesktopCapturer::DesktopListListener::OnDelegatedSourceListDismissed() {
|
||||
std::move(failure_callback_).Run();
|
||||
}
|
||||
|
||||
void DesktopCapturer::StartHandling(bool capture_window,
|
||||
bool capture_screen,
|
||||
const gfx::Size& thumbnail_size,
|
||||
@@ -212,11 +247,22 @@ void DesktopCapturer::StartHandling(bool capture_window,
|
||||
window_capturer_ = std::make_unique<NativeDesktopMediaList>(
|
||||
DesktopMediaList::Type::kWindow, std::move(capturer));
|
||||
window_capturer_->SetThumbnailSize(thumbnail_size);
|
||||
window_capturer_->Update(
|
||||
base::BindOnce(&DesktopCapturer::UpdateSourcesList,
|
||||
weak_ptr_factory_.GetWeakPtr(),
|
||||
window_capturer_.get()),
|
||||
/* refresh_thumbnails = */ true);
|
||||
|
||||
OnceCallback update_callback = base::BindOnce(
|
||||
&DesktopCapturer::UpdateSourcesList, weak_ptr_factory_.GetWeakPtr(),
|
||||
window_capturer_.get());
|
||||
|
||||
if (window_capturer_->IsSourceListDelegated()) {
|
||||
OnceCallback failure_callback = base::BindOnce(
|
||||
&DesktopCapturer::HandleFailure, weak_ptr_factory_.GetWeakPtr());
|
||||
window_listener_ = std::make_unique<DesktopListListener>(
|
||||
std::move(update_callback), std::move(failure_callback),
|
||||
thumbnail_size.IsEmpty());
|
||||
window_capturer_->StartUpdating(window_listener_.get());
|
||||
} else {
|
||||
window_capturer_->Update(std::move(update_callback),
|
||||
/* refresh_thumbnails = */ true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,11 +272,22 @@ void DesktopCapturer::StartHandling(bool capture_window,
|
||||
screen_capturer_ = std::make_unique<NativeDesktopMediaList>(
|
||||
DesktopMediaList::Type::kScreen, std::move(capturer));
|
||||
screen_capturer_->SetThumbnailSize(thumbnail_size);
|
||||
screen_capturer_->Update(
|
||||
base::BindOnce(&DesktopCapturer::UpdateSourcesList,
|
||||
weak_ptr_factory_.GetWeakPtr(),
|
||||
screen_capturer_.get()),
|
||||
/* refresh_thumbnails = */ true);
|
||||
|
||||
OnceCallback update_callback = base::BindOnce(
|
||||
&DesktopCapturer::UpdateSourcesList, weak_ptr_factory_.GetWeakPtr(),
|
||||
screen_capturer_.get());
|
||||
|
||||
if (screen_capturer_->IsSourceListDelegated()) {
|
||||
OnceCallback failure_callback = base::BindOnce(
|
||||
&DesktopCapturer::HandleFailure, weak_ptr_factory_.GetWeakPtr());
|
||||
screen_listener_ = std::make_unique<DesktopListListener>(
|
||||
std::move(update_callback), std::move(failure_callback),
|
||||
thumbnail_size.IsEmpty());
|
||||
screen_capturer_->StartUpdating(screen_listener_.get());
|
||||
} else {
|
||||
screen_capturer_->Update(std::move(update_callback),
|
||||
/* refresh_thumbnails = */ true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -270,12 +327,7 @@ void DesktopCapturer::UpdateSourcesList(DesktopMediaList* list) {
|
||||
// |media_list_sources|.
|
||||
if (!webrtc::DxgiDuplicatorController::Instance()->GetDeviceNames(
|
||||
&device_names)) {
|
||||
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
gin_helper::CallMethod(this, "_onerror", "Failed to get sources.");
|
||||
|
||||
Unpin();
|
||||
|
||||
HandleFailure();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -325,6 +377,14 @@ void DesktopCapturer::UpdateSourcesList(DesktopMediaList* list) {
|
||||
}
|
||||
}
|
||||
|
||||
void DesktopCapturer::HandleFailure() {
|
||||
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
gin_helper::CallMethod(this, "_onerror", "Failed to get sources.");
|
||||
|
||||
Unpin();
|
||||
}
|
||||
|
||||
// static
|
||||
gin::Handle<DesktopCapturer> DesktopCapturer::Create(v8::Isolate* isolate) {
|
||||
auto handle = gin::CreateHandle(isolate, new DesktopCapturer(isolate));
|
||||
|
||||
@@ -62,8 +62,37 @@ class DesktopCapturer : public gin::Wrappable<DesktopCapturer>,
|
||||
void OnDelegatedSourceListDismissed() override {}
|
||||
|
||||
private:
|
||||
void UpdateSourcesList(DesktopMediaList* list);
|
||||
using OnceCallback = base::OnceClosure;
|
||||
|
||||
class DesktopListListener : public DesktopMediaListObserver {
|
||||
public:
|
||||
DesktopListListener(OnceCallback update_callback,
|
||||
OnceCallback failure_callback,
|
||||
bool skip_thumbnails);
|
||||
~DesktopListListener() override;
|
||||
|
||||
protected:
|
||||
void OnSourceAdded(int index) override {}
|
||||
void OnSourceRemoved(int index) override {}
|
||||
void OnSourceMoved(int old_index, int new_index) override {}
|
||||
void OnSourceNameChanged(int index) override {}
|
||||
void OnSourceThumbnailChanged(int index) override;
|
||||
void OnSourcePreviewChanged(size_t index) override {}
|
||||
void OnDelegatedSourceListSelection() override;
|
||||
void OnDelegatedSourceListDismissed() override;
|
||||
|
||||
private:
|
||||
OnceCallback update_callback_;
|
||||
OnceCallback failure_callback_;
|
||||
bool have_selection_ = false;
|
||||
bool have_thumbnail_ = false;
|
||||
};
|
||||
|
||||
void UpdateSourcesList(DesktopMediaList* list);
|
||||
void HandleFailure();
|
||||
|
||||
std::unique_ptr<DesktopListListener> window_listener_;
|
||||
std::unique_ptr<DesktopListListener> screen_listener_;
|
||||
std::unique_ptr<DesktopMediaList> window_capturer_;
|
||||
std::unique_ptr<DesktopMediaList> screen_capturer_;
|
||||
std::vector<DesktopCapturer::Source> captured_sources_;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "content/public/browser/render_widget_host_view.h"
|
||||
#include "shell/browser/api/electron_api_web_contents.h"
|
||||
#include "shell/browser/javascript_environment.h"
|
||||
#include "shell/browser/native_browser_view.h"
|
||||
#include "shell/browser/native_window.h"
|
||||
|
||||
namespace electron {
|
||||
@@ -36,7 +37,11 @@ void AutofillDriver::ShowAutofillPopup(
|
||||
v8::HandleScope scope(isolate);
|
||||
auto* web_contents = api::WebContents::From(
|
||||
content::WebContents::FromRenderFrameHost(render_frame_host_));
|
||||
if (!web_contents || !web_contents->owner_window())
|
||||
if (!web_contents)
|
||||
return;
|
||||
|
||||
auto* owner_window = web_contents->owner_window();
|
||||
if (!owner_window)
|
||||
return;
|
||||
|
||||
auto* embedder = web_contents->embedder();
|
||||
@@ -55,9 +60,23 @@ void AutofillDriver::ShowAutofillPopup(
|
||||
embedder_frame_host = embedder->web_contents()->GetPrimaryMainFrame();
|
||||
}
|
||||
|
||||
// Ensure that if the WebContents belongs to a BrowserView,
|
||||
// the popup is positioned relative to the BrowserView's bounds.
|
||||
for (NativeBrowserView* bv : owner_window->browser_views()) {
|
||||
auto* iwc = bv->GetInspectableWebContents();
|
||||
if (!iwc)
|
||||
continue;
|
||||
|
||||
auto* awc = api::WebContents::From(iwc->GetWebContents());
|
||||
if (awc == web_contents) {
|
||||
auto bv_origin = bv->GetBounds().origin();
|
||||
popup_bounds.Offset(gfx::Vector2dF(bv_origin.x(), bv_origin.y()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
autofill_popup_->CreateView(render_frame_host_, embedder_frame_host, osr,
|
||||
web_contents->owner_window()->content_view(),
|
||||
popup_bounds);
|
||||
owner_window->content_view(), popup_bounds);
|
||||
autofill_popup_->SetItems(values, labels);
|
||||
}
|
||||
|
||||
|
||||
@@ -152,6 +152,9 @@ class NativeWindow : public base::SupportsUserData,
|
||||
virtual std::string GetAlwaysOnTopLevel() = 0;
|
||||
virtual void SetActive(bool is_key) = 0;
|
||||
virtual bool IsActive() const = 0;
|
||||
virtual void RemoveChildWindow(NativeWindow* child) = 0;
|
||||
virtual void AttachChildren() = 0;
|
||||
virtual void DetachChildren() = 0;
|
||||
#endif
|
||||
|
||||
// Ability to augment the window title for the screen readers.
|
||||
@@ -382,6 +385,10 @@ class NativeWindow : public base::SupportsUserData,
|
||||
|
||||
int32_t window_id() const { return next_id_; }
|
||||
|
||||
void add_child_window(NativeWindow* child) {
|
||||
child_windows_.push_back(child);
|
||||
}
|
||||
|
||||
int NonClientHitTest(const gfx::Point& point);
|
||||
void AddDraggableRegionProvider(DraggableRegionProvider* provider);
|
||||
void RemoveDraggableRegionProvider(DraggableRegionProvider* provider);
|
||||
@@ -422,6 +429,8 @@ class NativeWindow : public base::SupportsUserData,
|
||||
FullScreenTransitionType fullscreen_transition_type_ =
|
||||
FullScreenTransitionType::NONE;
|
||||
|
||||
std::list<NativeWindow*> child_windows_;
|
||||
|
||||
private:
|
||||
std::unique_ptr<views::Widget> widget_;
|
||||
|
||||
|
||||
@@ -154,6 +154,12 @@ class NativeWindowMac : public NativeWindow,
|
||||
void NotifyWindowLeaveFullScreen() override;
|
||||
void SetActive(bool is_key) override;
|
||||
bool IsActive() const override;
|
||||
// Remove the specified child window without closing it.
|
||||
void RemoveChildWindow(NativeWindow* child) override;
|
||||
// Attach child windows, if the window is visible.
|
||||
void AttachChildren() override;
|
||||
// Detach window from parent without destroying it.
|
||||
void DetachChildren() override;
|
||||
|
||||
void NotifyWindowWillEnterFullScreen();
|
||||
void NotifyWindowWillLeaveFullScreen();
|
||||
|
||||
@@ -473,14 +473,7 @@ void NativeWindowMac::Hide() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Hide all children of the current window before hiding the window.
|
||||
// components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm
|
||||
// expects this when window visibility changes.
|
||||
if ([window_ childWindows]) {
|
||||
for (NSWindow* child in [window_ childWindows]) {
|
||||
[child orderOut:nil];
|
||||
}
|
||||
}
|
||||
DetachChildren();
|
||||
|
||||
// Detach the window from the parent before.
|
||||
if (parent())
|
||||
@@ -600,6 +593,37 @@ bool NativeWindowMac::HandleDeferredClose() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void NativeWindowMac::RemoveChildWindow(NativeWindow* child) {
|
||||
child_windows_.remove_if([&child](NativeWindow* w) { return (w == child); });
|
||||
|
||||
[window_ removeChildWindow:child->GetNativeWindow().GetNativeNSWindow()];
|
||||
}
|
||||
|
||||
void NativeWindowMac::AttachChildren() {
|
||||
for (auto* child : child_windows_) {
|
||||
auto* child_nswindow = child->GetNativeWindow().GetNativeNSWindow();
|
||||
if ([child_nswindow parentWindow] == window_)
|
||||
continue;
|
||||
|
||||
// Attaching a window as a child window resets its window level, so
|
||||
// save and restore it afterwards.
|
||||
NSInteger level = window_.level;
|
||||
[window_ addChildWindow:child_nswindow ordered:NSWindowAbove];
|
||||
[window_ setLevel:level];
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowMac::DetachChildren() {
|
||||
DCHECK(child_windows_.size() == [[window_ childWindows] count]);
|
||||
|
||||
// Hide all children before hiding/minimizing the window.
|
||||
// NativeWidgetNSWindowBridge::NotifyVisibilityChangeDown()
|
||||
// will DCHECK otherwise.
|
||||
for (auto* child : child_windows_) {
|
||||
[child->GetNativeWindow().GetNativeNSWindow() orderOut:nil];
|
||||
}
|
||||
}
|
||||
|
||||
void NativeWindowMac::SetFullScreen(bool fullscreen) {
|
||||
if (!has_frame() && !HasStyleMask(NSWindowStyleMaskTitled))
|
||||
return;
|
||||
@@ -1765,18 +1789,12 @@ void NativeWindowMac::InternalSetParentWindow(NativeWindow* parent,
|
||||
|
||||
// Remove current parent window.
|
||||
if ([window_ parentWindow])
|
||||
[[window_ parentWindow] removeChildWindow:window_];
|
||||
parent->RemoveChildWindow(this);
|
||||
|
||||
// Set new parent window.
|
||||
// Note that this method will force the window to become visible.
|
||||
if (parent && attach) {
|
||||
// Attaching a window as a child window resets its window level, so
|
||||
// save and restore it afterwards.
|
||||
NSInteger level = window_.level;
|
||||
[parent->GetNativeWindow().GetNativeNSWindow()
|
||||
addChildWindow:window_
|
||||
ordered:NSWindowAbove];
|
||||
[window_ setLevel:level];
|
||||
parent->add_child_window(this);
|
||||
parent->AttachChildren();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -718,10 +718,14 @@ void NativeWindowViews::SetFullScreen(bool fullscreen) {
|
||||
gfx::Rect());
|
||||
|
||||
// Auto-hide menubar when in fullscreen.
|
||||
if (fullscreen)
|
||||
if (fullscreen) {
|
||||
menu_bar_visible_before_fullscreen_ = IsMenuBarVisible();
|
||||
SetMenuBarVisibility(false);
|
||||
else
|
||||
SetMenuBarVisibility(!IsMenuBarAutoHide());
|
||||
} else {
|
||||
SetMenuBarVisibility(!IsMenuBarAutoHide() &&
|
||||
menu_bar_visible_before_fullscreen_);
|
||||
menu_bar_visible_before_fullscreen_ = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -771,6 +775,10 @@ gfx::Size NativeWindowViews::GetContentSize() {
|
||||
}
|
||||
|
||||
gfx::Rect NativeWindowViews::GetNormalBounds() {
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
if (IsMaximized() && transparent())
|
||||
return restore_bounds_;
|
||||
#endif
|
||||
return widget()->GetRestoredBounds();
|
||||
}
|
||||
|
||||
|
||||
@@ -322,6 +322,9 @@ class NativeWindowViews : public NativeWindow,
|
||||
// Handles unhandled keyboard messages coming back from the renderer process.
|
||||
std::unique_ptr<views::UnhandledKeyboardEventHandler> keyboard_event_handler_;
|
||||
|
||||
// Whether the menubar is visible before the window enters fullscreen
|
||||
bool menu_bar_visible_before_fullscreen_ = false;
|
||||
|
||||
// Whether the window should be enabled based on user calls to SetEnabled()
|
||||
bool is_enabled_ = true;
|
||||
// How many modal children this window has;
|
||||
|
||||
@@ -239,6 +239,7 @@ using FullScreenTransitionState =
|
||||
level_ = [window level];
|
||||
shell_->SetWindowLevel(NSNormalWindowLevel);
|
||||
shell_->UpdateWindowOriginalFrame();
|
||||
shell_->DetachChildren();
|
||||
}
|
||||
|
||||
- (void)windowDidMiniaturize:(NSNotification*)notification {
|
||||
@@ -248,6 +249,7 @@ using FullScreenTransitionState =
|
||||
|
||||
- (void)windowDidDeminiaturize:(NSNotification*)notification {
|
||||
[super windowDidDeminiaturize:notification];
|
||||
shell_->AttachChildren();
|
||||
shell_->SetWindowLevel(level_);
|
||||
shell_->NotifyWindowRestore();
|
||||
}
|
||||
|
||||
@@ -153,6 +153,7 @@ void WinCaptionButtonContainer::UpdateButtons() {
|
||||
|
||||
const bool minimizable = frame_view_->window()->IsMinimizable();
|
||||
minimize_button_->SetEnabled(minimizable);
|
||||
minimize_button_->SetVisible(minimizable);
|
||||
|
||||
// In touch mode, windows cannot be taken out of fullscreen or tiled mode, so
|
||||
// the maximize/restore button should be disabled.
|
||||
|
||||
@@ -63,7 +63,7 @@ void ElectronRenderFrameObserver::DidClearWindowObject() {
|
||||
// Check DidInstallConditionalFeatures below for the background.
|
||||
auto* web_frame =
|
||||
static_cast<blink::WebLocalFrameImpl*>(render_frame_->GetWebFrame());
|
||||
if (has_delayed_node_initialization_ && web_frame->Opener() &&
|
||||
if (has_delayed_node_initialization_ &&
|
||||
!web_frame->IsOnInitialEmptyDocument()) {
|
||||
v8::Isolate* isolate = blink::MainThreadIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
@@ -1476,6 +1476,23 @@ describe('BrowserWindow module', () => {
|
||||
expect(w.isFullScreen()).to.equal(true);
|
||||
});
|
||||
|
||||
it('checks normal bounds for maximized transparent window', async () => {
|
||||
w.destroy();
|
||||
w = new BrowserWindow({
|
||||
transparent: true,
|
||||
show: false
|
||||
});
|
||||
w.show();
|
||||
|
||||
const bounds = w.getNormalBounds();
|
||||
|
||||
const maximize = emittedOnce(w, 'maximize');
|
||||
w.maximize();
|
||||
await maximize;
|
||||
|
||||
expectBoundsEqual(w.getNormalBounds(), bounds);
|
||||
});
|
||||
|
||||
it('does not change size for a frameless window with min size', async () => {
|
||||
w.destroy();
|
||||
w = new BrowserWindow({
|
||||
@@ -4220,11 +4237,13 @@ describe('BrowserWindow module', () => {
|
||||
const c = new BrowserWindow({ show: false, parent: w });
|
||||
expect(c.getParentWindow()).to.equal(w);
|
||||
});
|
||||
|
||||
it('adds window to child windows of parent', () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
const c = new BrowserWindow({ show: false, parent: w });
|
||||
expect(w.getChildWindows()).to.deep.equal([c]);
|
||||
});
|
||||
|
||||
it('removes from child windows of parent when window is closed', async () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
const c = new BrowserWindow({ show: false, parent: w });
|
||||
@@ -4236,6 +4255,59 @@ describe('BrowserWindow module', () => {
|
||||
expect(w.getChildWindows().length).to.equal(0);
|
||||
});
|
||||
|
||||
ifit(process.platform === 'darwin')('child window matches visibility when visibility changes', async () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
const c = new BrowserWindow({ show: false, parent: w });
|
||||
|
||||
const wShow = emittedOnce(w, 'show');
|
||||
const cShow = emittedOnce(c, 'show');
|
||||
|
||||
w.show();
|
||||
c.show();
|
||||
|
||||
await Promise.all([wShow, cShow]);
|
||||
|
||||
const minimized = emittedOnce(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 = emittedOnce(w, 'restore');
|
||||
w.restore();
|
||||
await restored;
|
||||
|
||||
expect(w.isVisible()).to.be.true('parent is visible');
|
||||
expect(c.isVisible()).to.be.true('child is visible');
|
||||
});
|
||||
|
||||
ifit(process.platform === 'darwin')('matches child window visibility when visibility changes', async () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
const c = new BrowserWindow({ show: false, parent: w });
|
||||
|
||||
const wShow = emittedOnce(w, 'show');
|
||||
const cShow = emittedOnce(c, 'show');
|
||||
|
||||
w.show();
|
||||
c.show();
|
||||
|
||||
await Promise.all([wShow, cShow]);
|
||||
|
||||
const minimized = emittedOnce(c, 'minimize');
|
||||
c.minimize();
|
||||
await minimized;
|
||||
|
||||
expect(c.isVisible()).to.be.false('child is visible');
|
||||
|
||||
const restored = emittedOnce(c, 'restore');
|
||||
c.restore();
|
||||
await restored;
|
||||
|
||||
expect(w.isVisible()).to.be.true('parent is visible');
|
||||
expect(c.isVisible()).to.be.true('child is visible');
|
||||
});
|
||||
|
||||
it('closes a grandchild window when a middle child window is destroyed', (done) => {
|
||||
const w = new BrowserWindow();
|
||||
|
||||
@@ -4846,6 +4918,48 @@ describe('BrowserWindow module', () => {
|
||||
});
|
||||
});
|
||||
|
||||
ifdescribe(process.platform !== 'darwin')('when fullscreen state is changed', () => {
|
||||
it('correctly remembers state prior to fullscreen change', async () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
expect(w.isMenuBarVisible()).to.be.true('isMenuBarVisible');
|
||||
w.setMenuBarVisibility(false);
|
||||
expect(w.isMenuBarVisible()).to.be.false('isMenuBarVisible');
|
||||
|
||||
const enterFS = emittedOnce(w, 'enter-full-screen');
|
||||
w.setFullScreen(true);
|
||||
await enterFS;
|
||||
expect(w.fullScreen).to.be.true('not fullscreen');
|
||||
|
||||
const exitFS = emittedOnce(w, 'leave-full-screen');
|
||||
w.setFullScreen(false);
|
||||
await exitFS;
|
||||
expect(w.fullScreen).to.be.false('not fullscreen');
|
||||
|
||||
expect(w.isMenuBarVisible()).to.be.false('isMenuBarVisible');
|
||||
});
|
||||
|
||||
it('correctly remembers state prior to fullscreen change with autoHide', async () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
expect(w.autoHideMenuBar).to.be.false('autoHideMenuBar');
|
||||
w.autoHideMenuBar = true;
|
||||
expect(w.autoHideMenuBar).to.be.true('autoHideMenuBar');
|
||||
w.setMenuBarVisibility(false);
|
||||
expect(w.isMenuBarVisible()).to.be.false('isMenuBarVisible');
|
||||
|
||||
const enterFS = emittedOnce(w, 'enter-full-screen');
|
||||
w.setFullScreen(true);
|
||||
await enterFS;
|
||||
expect(w.fullScreen).to.be.true('not fullscreen');
|
||||
|
||||
const exitFS = emittedOnce(w, 'leave-full-screen');
|
||||
w.setFullScreen(false);
|
||||
await exitFS;
|
||||
expect(w.fullScreen).to.be.false('not fullscreen');
|
||||
|
||||
expect(w.isMenuBarVisible()).to.be.false('isMenuBarVisible');
|
||||
});
|
||||
});
|
||||
|
||||
ifdescribe(process.platform === 'darwin')('fullscreenable state', () => {
|
||||
it('with functions', () => {
|
||||
it('can be set with fullscreenable constructor option', () => {
|
||||
|
||||
@@ -113,7 +113,7 @@ ifdescribe(!(['arm', 'arm64', 'ia32'].includes(process.arch)))('contentTracing',
|
||||
});
|
||||
|
||||
it('rejects if no trace is happening', async () => {
|
||||
await expect(contentTracing.stopRecording()).to.be.rejected();
|
||||
await expect(contentTracing.stopRecording()).to.be.rejectedWith('Failed to stop tracing - no trace in progress');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ describe('dialog module', () => {
|
||||
|
||||
it('throws errors when the options are invalid', () => {
|
||||
expect(() => {
|
||||
dialog.showMessageBox(undefined as any, { type: 'not-a-valid-type', message: '' });
|
||||
dialog.showMessageBox(undefined as any, { type: 'not-a-valid-type' as any, message: '' });
|
||||
}).to.throw(/Invalid message box type/);
|
||||
|
||||
expect(() => {
|
||||
|
||||
@@ -1147,6 +1147,23 @@ describe('chromium features', () => {
|
||||
expect(eventData).to.equal('size: 350 450');
|
||||
});
|
||||
|
||||
it('loads preload script after setting opener to null', async () => {
|
||||
const w = new BrowserWindow({ show: false });
|
||||
w.webContents.setWindowOpenHandler(() => ({
|
||||
action: 'allow',
|
||||
overrideBrowserWindowOptions: {
|
||||
webPreferences: {
|
||||
preload: path.join(fixturesPath, 'module', 'preload.js')
|
||||
}
|
||||
}
|
||||
}));
|
||||
w.loadURL('about:blank');
|
||||
w.webContents.executeJavaScript('window.child = window.open(); child.opener = null');
|
||||
const [, { webContents }] = await emittedOnce(app, 'browser-window-created');
|
||||
const [,, message] = await emittedOnce(webContents, 'console-message');
|
||||
expect(message).to.equal('{"require":"function","module":"undefined","process":"object","Buffer":"function"}');
|
||||
});
|
||||
|
||||
it('disables the <webview> tag when it is disabled on the parent window', async () => {
|
||||
const windowUrl = url.pathToFileURL(path.join(fixturesPath, 'pages', 'window-opener-no-webview-tag.html'));
|
||||
windowUrl.searchParams.set('p', `${fixturesPath}/pages/window-opener-webview.html`);
|
||||
|
||||
@@ -506,6 +506,24 @@ dialog.showOpenDialog(win3, {
|
||||
console.log(ret)
|
||||
})
|
||||
|
||||
// variants without browserWindow
|
||||
dialog.showMessageBox({ message: 'test', type: 'warning' })
|
||||
dialog.showMessageBoxSync({ message: 'test', type: 'error' })
|
||||
|
||||
// @ts-expect-error Invalid type value
|
||||
dialog.showMessageBox({ message: 'test', type: 'foo' })
|
||||
// @ts-expect-error Invalid type value
|
||||
dialog.showMessageBoxSync({ message: 'test', type: 'foo' })
|
||||
|
||||
// variants with browserWindow
|
||||
dialog.showMessageBox(win3, { message: 'test', type: 'question' })
|
||||
dialog.showMessageBoxSync(win3, { message: 'test', type: 'info' })
|
||||
|
||||
// @ts-expect-error Invalid type value
|
||||
dialog.showMessageBox(win3, { message: 'test', type: 'foo' })
|
||||
// @ts-expect-error Invalid type value
|
||||
dialog.showMessageBoxSync(win3, { message: 'test', type: 'foo' })
|
||||
|
||||
// global-shortcut
|
||||
// https://github.com/electron/electron/blob/master/docs/api/global-shortcut.md
|
||||
|
||||
|
||||
@@ -527,13 +527,13 @@
|
||||
universal-user-agent "^6.0.0"
|
||||
|
||||
"@octokit/request@^6.0.0":
|
||||
version "6.2.2"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/request/-/request-6.2.2.tgz#a2ba5ac22bddd5dcb3f539b618faa05115c5a255"
|
||||
integrity sha512-6VDqgj0HMc2FUX2awIs+sM6OwLgwHvAi4KCK3mT2H2IKRt6oH9d0fej5LluF5mck1lRR/rFWN0YIDSYXYSylbw==
|
||||
version "6.2.5"
|
||||
resolved "https://registry.yarnpkg.com/@octokit/request/-/request-6.2.5.tgz#7beef1065042998f7455973ef3f818e7b84d6ec2"
|
||||
integrity sha512-z83E8UIlPNaJUsXpjD8E0V5o/5f+vJJNbNcBwVZsX3/vC650U41cOkTLjq4PKk9BYonQGOnx7N17gvLyNjgGcQ==
|
||||
dependencies:
|
||||
"@octokit/endpoint" "^7.0.0"
|
||||
"@octokit/request-error" "^3.0.0"
|
||||
"@octokit/types" "^8.0.0"
|
||||
"@octokit/types" "^9.0.0"
|
||||
is-plain-object "^5.0.0"
|
||||
node-fetch "^2.6.7"
|
||||
universal-user-agent "^6.0.0"
|
||||
|
||||
Reference in New Issue
Block a user