Compare commits

..

20 Commits

Author SHA1 Message Date
trop[bot]
e2dac668c6 fix: crashed events deprecation (#40119)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2023-10-06 09:50:19 -04:00
Pedro Pontes
54dee45d47 chore: cherry-pick 2 changes from Release-1-M117 (#40080)
* chore: [22-x-y] cherry-pick 2 changes from Release-1-M117

* b0ad701a609a from v8
* b11e7d07a6f4 from chromium

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2023-10-05 21:09:06 -04:00
Samuel Attard
1c1c13234f chore: cherry-pick 3fbd1dca6a4d from libvpx (#40026)
* chore: cherry-pick 3fbd1dca6a4d from libvpx

* build: update patches config

* chore: update patches
2023-09-28 03:32:33 -07:00
trop[bot]
d892c2b1c8 build: fixup autoninja (#39899)
chore: set GOMA_DIR for autoninja

(cherry picked from commit 94f24bde4d)
(cherry picked from commit 90c1f6e1cb8d22d94dd01791dc4b9c3e0a7e86fc)

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2023-09-18 20:36:11 -04:00
trop[bot]
6132e80a4f build: run on circle hosts for forks (#39865)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Samuel Attard <samuel.r.attard@gmail.com>
2023-09-14 14:55:16 -04:00
Samuel Attard
a953199af3 build: use aks backed runners for linux builds (#39838)
* build: use aks backed runners for linux builds (#39403)

* build: test aks runner

* build: stress test

* build: use super-large nodes for publish jobs

* build: try using aks for everything...

* build: shared host not great

* build: clean up

* build: apparently tests dont run in kube infra?

* build: do not change test size

* ci: fixup known hosts for linux publish (#39437)

* ci: fixup known hosts for linux publish

* build: use 2023 known hosts

* build: use rebuilt docker image

* Revert "build: use rebuilt docker image"

This reverts commit f9506a9cc0.

---------

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

---------

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2023-09-12 16:52:15 -07:00
Samuel Attard
056eacf1ce chore: cherry-pick b2eab7500a18 from chromium (#39827)
* chore: cherry-pick b2eab7500a18 from chromium

* chore: update patches

---------

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2023-09-12 11:44:10 -07:00
trop[bot]
5f8ef81277 fix: ensure app load is limited to real asar files when appropriate (#39811)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Samuel Attard <marshallofsound@electronjs.org>
2023-09-11 14:12:58 -07:00
Pedro Pontes
4995c9ee97 chore: cherry-pick 1 changes from Release-3-M116 (#39758)
chore: [22-x-y] cherry-pick 1 changes from Release-3-M116

* 038530c94a06 from v8
2023-09-11 13:05:12 -04:00
trop[bot]
e29cdacb13 build: fix depot_tools patch application (#39751)
build: fix depot_tools patch application (cherry picked from commit 34b79c15c2)

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-09-06 20:09:18 -04:00
Pedro Pontes
b58903d195 chore: cherry-pick 1 changes from Release-2-M116 (#39689)
* chore: [22-x-y] cherry-pick 1 changes from Release-2-M116

* 35c06406a658 from chromium

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2023-09-05 10:16:31 +02:00
Pedro Pontes
33f9dce7c2 chore: cherry-pick 2 changes from Release-1-M116 (#39648)
* chore: [22-x-y] cherry-pick 2 changes from Release-1-M116

* 1939f7b78eda from chromium
* e4669a74888d from angle

* chore: [22-x-y] cherry-pick missing changes from Release-1-M116

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2023-08-28 15:18:56 +09:00
John Kleinschmidt
4938ca50f0 ci: explicitly use python3 to start goma (#39652)
ci: explicitly use python3 to start goma (#39650)

* ci: explicitly use python3 to start goma

* ci: explicitly use python3 for goma

(cherry picked from commit 83760bd5c6)
2023-08-24 23:19:08 -04:00
trop[bot]
e940852250 fix: use tiled edges to calculate frame inset sizes in Linux (#39568)
Adapt to the window frame size calculation changes in CL 3970920 by
setting the inset sizes to 0 for tiled edges.

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Athul Iddya <athul@iddya.com>
2023-08-21 17:03:25 +09:00
Pedro Pontes
2598dc0ce6 chore: cherry-pick 5 changes from Release-0-M116 (#39559)
* chore: [22-x-y] cherry-pick 3 changes from Release-0-M116

* 8ff63d378f2c from v8
* 5486190be556 from angle
* d671b099a57d from v8

* chore: cherry-pick missing changes

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2023-08-21 11:43:12 +09:00
trop[bot]
2dee8783cc fix: avoid package.json check on built-in modules (#39425)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Samuel Attard <marshallofsound@electronjs.org>
2023-08-09 19:03:08 +02:00
John Kleinschmidt
b026a66172 ci: fix hang when validating AppVeyor artifacts (#39398)
ci: fix hang when validating AppVeyor artifacts (#39362)

(cherry picked from commit 1eb6e45a36)
(cherry picked from commit dc7b42edbb)
2023-08-07 16:56:16 -04:00
Keeley Hammond
7a4948bd80 chore: cherry-pick 4 changes from Release-0-M115 (#39269) 2023-08-02 17:51:43 +02:00
trop[bot]
878f18474e fix: do not resolve electron entrypoints on disk (#39248)
* fix: do not resolve electron entrypoints on disk

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

* chore: fixup .patches file after trop

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Samuel Attard <marshallofsound@electronjs.org>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2023-07-27 12:57:21 -07:00
trop[bot]
bbe9d8b8c9 ci: fail appveyor build if artifacts are missing (#39218)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2023-07-25 11:57:03 +02:00
43 changed files with 2629 additions and 50 deletions

View File

@@ -65,6 +65,9 @@ jobs:
curl -fLSs https://raw.githubusercontent.com/CircleCI-Public/circleci-cli/master/install.sh | DESTDIR=$CIRCLECI_BINARY bash
node build.js
name: Pack config.yml
- run:
name: Set params
command: node .circleci/config/params.js
- continuation/continue:
configuration_path: .circleci/config-staging/built.yml
parameters: /tmp/pipeline-parameters.json

View File

@@ -34,6 +34,11 @@ parameters:
type: enum
default: all
enum: ["all", "osx-x64", "osx-arm64", "mas-x64", "mas-arm64"]
large-linux-executor:
type: enum
default: electronjs/aks-linux-large
enum: ["electronjs/aks-linux-large", "2xlarge"]
# Executors
executors:
@@ -42,7 +47,9 @@ executors:
size:
description: "Docker executor size"
type: enum
enum: ["medium", "xlarge", "2xlarge"]
# aks-linux-large === 32 core
# 2xlarge should not be used directly, use the pipeline param instead
enum: ["medium", "xlarge", "electronjs/aks-linux-large", "2xlarge"]
docker:
- image: ghcr.io/electron/build:e6bebd08a51a0d78ec23e5b3fd7e7c0846412328
resource_class: << parameters.size >>
@@ -245,19 +252,19 @@ step-depot-tools-get: &step-depot-tools-get
cd depot_tools
cat > gclient.diff \<< 'EOF'
diff --git a/gclient.py b/gclient.py
index 3a9c5c6..f222043 100755
index c305c248..e6e0fbdc 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,
@@ -735,7 +735,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,
name=name,
EOF
git apply --3way gclient.diff
fi
@@ -345,7 +352,7 @@ step-setup-goma-for-build: &step-setup-goma-for-build
exit 1
fi
echo 'export GN_GOMA_FILE='`node -e "console.log(require('./src/utils/goma.js').gnFilePath)"` >> $BASH_ENV
echo 'export LOCAL_GOMA_DIR='`node -e "console.log(require('./src/utils/goma.js').dir)"` >> $BASH_ENV
echo 'export GOMA_DIR='`node -e "console.log(require('./src/utils/goma.js').dir)"` >> $BASH_ENV
echo 'export GOMA_FALLBACK_ON_AUTH_FAILURE=true' >> $BASH_ENV
cd ..
touch "${TMPDIR:=/tmp}"/.goma-ready
@@ -774,8 +781,8 @@ step-show-goma-stats: &step-show-goma-stats
command: |
set +e
set +o pipefail
$LOCAL_GOMA_DIR/goma_ctl.py stat
$LOCAL_GOMA_DIR/diagnose_goma_log.py
$GOMA_DIR/goma_ctl.py stat
$GOMA_DIR/diagnose_goma_log.py
true
when: always
background: true
@@ -1481,6 +1488,7 @@ commands:
- *step-minimize-workspace-size-from-checkout
- *step-fix-sync
- *step-setup-env-for-build
- *step-fix-known-hosts-linux
- *step-setup-goma-for-build
- *step-wait-for-goma
- *step-gn-gen-default
@@ -1586,7 +1594,7 @@ jobs:
linux-x64-testing:
executor:
name: linux-docker
size: xlarge
size: << pipeline.parameters.large-linux-executor >>
environment:
<<: *env-global
<<: *env-testing-build
@@ -1601,7 +1609,7 @@ jobs:
linux-x64-testing-asan:
executor:
name: linux-docker
size: 2xlarge
size: << pipeline.parameters.large-linux-executor >>
environment:
<<: *env-global
<<: *env-testing-build
@@ -1643,7 +1651,7 @@ jobs:
linux-x64-publish:
executor:
name: linux-docker
size: 2xlarge
size: << pipeline.parameters.large-linux-executor >>
environment:
<<: *env-linux-2xlarge-release
<<: *env-release-build
@@ -1665,7 +1673,7 @@ jobs:
linux-arm-testing:
executor:
name: linux-docker
size: 2xlarge
size: << pipeline.parameters.large-linux-executor >>
environment:
<<: *env-global
<<: *env-arm
@@ -1683,7 +1691,7 @@ jobs:
linux-arm-publish:
executor:
name: linux-docker
size: 2xlarge
size: << pipeline.parameters.large-linux-executor >>
environment:
<<: *env-linux-2xlarge-release
<<: *env-arm
@@ -1707,7 +1715,7 @@ jobs:
linux-arm64-testing:
executor:
name: linux-docker
size: 2xlarge
size: << pipeline.parameters.large-linux-executor >>
environment:
<<: *env-global
<<: *env-arm64
@@ -1736,7 +1744,7 @@ jobs:
linux-arm64-publish:
executor:
name: linux-docker
size: 2xlarge
size: << pipeline.parameters.large-linux-executor >>
environment:
<<: *env-linux-2xlarge-release
<<: *env-arm64

View File

@@ -0,0 +1,11 @@
const fs = require('fs');
const PARAMS_PATH = '/tmp/pipeline-parameters.json';
const content = JSON.parse(fs.readFileSync(PARAMS_PATH, 'utf-8'));
// Choose resource class for linux hosts
const currentBranch = process.env.CIRCLE_BRANCH || '';
content['large-linux-executor'] = /^pull\/[0-9-]+$/.test(currentBranch) ? '2xlarge' : 'electronjs/aks-linux-large';
fs.writeFileSync(PARAMS_PATH, JSON.stringify(content));

View File

@@ -3,5 +3,6 @@
set -e
mkdir -p ~/.ssh
echo "|1|B3r+7aO0/x90IdefihIjxIoJrrk=|OJddGDfhbuLFc1bUyy84hhIw57M= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
|1|rGlEvW55DtzNZp+pzw9gvyOyKi4=|LLWr+7qlkAlw3YGGVfLHHxB/kR0= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==" >> ~/.ssh/known_hosts
echo "github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl
github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=
github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk=" >> ~/.ssh/known_hosts

View File

@@ -107,7 +107,7 @@ for:
- ps: .\src\electron\script\start-goma.ps1 -gomaDir $env:LOCAL_GOMA_DIR
- ps: >-
if (Test-Path 'env:RAW_GOMA_AUTH') {
$goma_login = python $env:LOCAL_GOMA_DIR\goma_auth.py info
$goma_login = python3 $env:LOCAL_GOMA_DIR\goma_auth.py info
if ($goma_login -eq 'Login as Fermi Planck') {
Write-warning "Goma authentication is correct";
} else {
@@ -157,7 +157,7 @@ for:
- ninja -C out/Default electron:hunspell_dictionaries_zip
- ninja -C out/Default electron:electron_chromedriver_zip
- ninja -C out/Default third_party/electron_node:headers
- python %LOCAL_GOMA_DIR%\goma_ctl.py stat
- python3 %LOCAL_GOMA_DIR%\goma_ctl.py stat
- ps: >-
Get-CimInstance -Namespace root\cimv2 -Class Win32_product | Select vendor, description, @{l='install_location';e='InstallLocation'}, @{l='install_date';e='InstallDate'}, @{l='install_date_2';e='InstallDate2'}, caption, version, name, @{l='sku_number';e='SKUNumber'} | ConvertTo-Json | Out-File -Encoding utf8 -FilePath .\installed_software.json
- python3 electron/build/profile_toolchain.py --output-json=out/Default/windows_toolchain_profile.json
@@ -178,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
@@ -203,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
@@ -234,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
@@ -246,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
}

View File

@@ -105,7 +105,7 @@ for:
- ps: .\src\electron\script\start-goma.ps1 -gomaDir $env:LOCAL_GOMA_DIR
- ps: >-
if (Test-Path 'env:RAW_GOMA_AUTH') {
$goma_login = python $env:LOCAL_GOMA_DIR\goma_auth.py info
$goma_login = python3 $env:LOCAL_GOMA_DIR\goma_auth.py info
if ($goma_login -eq 'Login as Fermi Planck') {
Write-warning "Goma authentication is correct";
} else {
@@ -155,7 +155,7 @@ for:
- ninja -C out/Default electron:hunspell_dictionaries_zip
- ninja -C out/Default electron:electron_chromedriver_zip
- ninja -C out/Default third_party/electron_node:headers
- python %LOCAL_GOMA_DIR%\goma_ctl.py stat
- pytho3 %LOCAL_GOMA_DIR%\goma_ctl.py stat
- ps: >-
Get-CimInstance -Namespace root\cimv2 -Class Win32_product | Select vendor, description, @{l='install_location';e='InstallLocation'}, @{l='install_date';e='InstallDate'}, @{l='install_date_2';e='InstallDate2'}, caption, version, name, @{l='sku_number';e='SKUNumber'} | ConvertTo-Json | Out-File -Encoding utf8 -FilePath .\installed_software.json
- python3 electron/build/profile_toolchain.py --output-json=out/Default/windows_toolchain_profile.json
@@ -176,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
@@ -201,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
@@ -242,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: |

View File

@@ -27,7 +27,7 @@ const cachedArchives = new Map<string, NodeJS.AsarArchive>();
const getOrCreateArchive = (archivePath: string) => {
const isCached = cachedArchives.has(archivePath);
if (isCached) {
return cachedArchives.get(archivePath);
return cachedArchives.get(archivePath)!;
}
try {
@@ -39,6 +39,8 @@ const getOrCreateArchive = (archivePath: string) => {
}
};
process._getOrCreateArchive = getOrCreateArchive;
const asarRe = /\.asar/i;
// Separate asar package's path from full path.

View File

@@ -114,5 +114,11 @@ for (const name of events) {
}
// Deprecation.
deprecate.event(app, 'gpu-process-crashed', 'child-process-gone');
deprecate.event(app, 'renderer-process-crashed', 'render-process-gone');
deprecate.event(app, 'gpu-process-crashed', 'child-process-gone', () => {
// the old event is still emitted by App::OnGpuProcessCrashed()
return undefined;
});
deprecate.event(app, 'renderer-process-crashed', 'render-process-gone', (event: Electron.Event, webContents: Electron.WebContents, details: Electron.RenderProcessGoneDetails) => {
return [event, webContents, details.reason === 'killed'];
});

View File

@@ -656,8 +656,8 @@ WebContents.prototype._init = function () {
ipcMain.emit(channel, event, message);
});
this.on('crashed', (event, ...args) => {
app.emit('renderer-process-crashed', event, this, ...args);
deprecate.event(this, 'crashed', 'render-process-gone', (event: Electron.Event, details: Electron.RenderProcessGoneDetails) => {
return [event, details.reason === 'killed'];
});
this.on('render-process-gone', (event, details) => {

View File

@@ -84,11 +84,20 @@ const v8Util = process._linkedBinding('electron_common_v8_util');
let packagePath = null;
let packageJson = null;
const searchPaths: string[] = v8Util.getHiddenValue(global, 'appSearchPaths');
const searchPathsOnlyLoadASAR: boolean = v8Util.getHiddenValue(global, 'appSearchPathsOnlyLoadASAR');
// Borrow the _getOrCreateArchive asar helper
const getOrCreateArchive = process._getOrCreateArchive;
delete process._getOrCreateArchive;
if (process.resourcesPath) {
for (packagePath of searchPaths) {
try {
packagePath = path.join(process.resourcesPath, packagePath);
if (searchPathsOnlyLoadASAR) {
if (!getOrCreateArchive?.(packagePath)) {
continue;
}
}
packageJson = Module._load(path.join(packagePath, 'package.json'));
break;
} catch {

View File

@@ -66,14 +66,17 @@ export function renameFunction<T extends Function> (fn: T, newName: string): T {
}
// change the name of an event
export function event (emitter: NodeJS.EventEmitter, oldName: string, newName: string) {
export function event (emitter: NodeJS.EventEmitter, oldName: string, newName: string, transformer: (...args: any[]) => any[] | undefined = (...args) => args) {
const warn = newName.startsWith('-') /* internal event */
? warnOnce(`${oldName} event`)
: warnOnce(`${oldName} event`, `${newName} event`);
return emitter.on(newName, function (this: NodeJS.EventEmitter, ...args) {
if (this.listenerCount(oldName) !== 0) {
warn();
this.emit(oldName, ...args);
const transformedArgs = transformer(...args);
if (transformedArgs) {
this.emit(oldName, ...transformedArgs);
}
}
});
}

View File

@@ -4,3 +4,4 @@ cherry-pick-ce029c91a662.patch
cherry-pick-aed05b609629.patch
translator_limit_the_size_of_private_variables_in_webgl_shaders.patch
webgl_limit_total_size_of_private_data.patch
cherry-pick-5486190be556.patch

View File

@@ -0,0 +1,41 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Geoff Lang <geofflang@chromium.org>
Date: Fri, 21 Jul 2023 13:45:52 -0400
Subject: Fix read size validation for RGBX formats.
GL_RGBX8_ANGLE is the only format where the upload format is 3-channel
RGB, whilethe download format is 4-channel RGBX. As such, the internal
format corresponding to format+type expects 3-byte input/output. The
format is fixed here for readPixels to output 4 bytes per pixel.
Bug: chromium:1458046
Change-Id: Iec737ed64bade003cfab50dc5f595eb4875e81e4
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4706957
Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
(cherry picked from commit 430a4f559cbc2bcd5d026e8b36ee46ddd80e9651)
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4765136
Commit-Queue: Daniel Yip <danielyip@google.com>
Auto-Submit: Daniel Yip <danielyip@google.com>
(cherry picked from commit 4a372ad49ceddea6c13f79adb212a777ec770a66)
diff --git a/src/libANGLE/formatutils.cpp b/src/libANGLE/formatutils.cpp
index 4014953311976b0f1ae2d1842e8fced75ffecfc9..6c8d3680b7a8bb78894120ca6cac7882827a98e4 100644
--- a/src/libANGLE/formatutils.cpp
+++ b/src/libANGLE/formatutils.cpp
@@ -1710,7 +1710,15 @@ const InternalFormat &GetInternalFormatInfo(GLenum internalFormat, GLenum type)
GLuint InternalFormat::computePixelBytes(GLenum formatType) const
{
const auto &typeInfo = GetTypeInfo(formatType);
- GLuint components = typeInfo.specialInterpretation ? 1u : componentCount;
+ GLuint components = componentCount;
+ if (sizedInternalFormat == GL_RGBX8_ANGLE)
+ {
+ components = 4;
+ }
+ else if (typeInfo.specialInterpretation)
+ {
+ components = 1;
+ }
return components * typeInfo.bytes;
}

View File

@@ -166,3 +166,10 @@ m114_merge_fix_a_crash_caused_by_calling_trace_event.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
networkcontext_don_t_access_url_loader_factories_during_destruction.patch
don_t_keep_pointer_to_popped_stack_memory_for_has.patch
cherry-pick-35c06406a658.patch
cherry-pick-b11e7d07a6f4.patch

View File

@@ -0,0 +1,162 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Guido Urdaneta <guidou@chromium.org>
Date: Thu, 24 Aug 2023 11:12:43 +0000
Subject: Handle object destruction in MediaStreamDeviceObserver
MSDO executes some callbacks that can result in the destruction of
MSDO upon an external event such as removing a media device or the
user revoking permission.
This CL adds code to detect this condition and prevent further
processing that would result in UAF. It also removes some invalid
DCHECKs.
Drive-by: minor style fixes
(cherry picked from commit 7337133682ab0404b753c563dde2ae2b1dc13171)
Bug: 1472492, b/296997707
Change-Id: I76f019bb110e7d9cca276444bc23a7e43114d2cc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4798398
Reviewed-by: Palak Agarwal <agpalak@chromium.org>
Commit-Queue: Guido Urdaneta <guidou@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1186452}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4810035
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/branch-heads/5845@{#1586}
Cr-Branched-From: 5a5dff63a4a4c63b9b18589819bebb2566c85443-refs/heads/main@{#1160321}
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_device_observer.cc b/third_party/blink/renderer/modules/mediastream/media_stream_device_observer.cc
index c553b70b3b3be78a1d6636037009210bc280e02e..ece0caa8dbeaadf8f2a78bfb5c76e6db6023f1b5 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_device_observer.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_device_observer.cc
@@ -37,11 +37,11 @@ MediaStreamDeviceObserver::MediaStreamDeviceObserver(LocalFrame* frame) {
if (frame) {
frame->GetInterfaceRegistry()->AddInterface(WTF::BindRepeating(
&MediaStreamDeviceObserver::BindMediaStreamDeviceObserverReceiver,
- WTF::Unretained(this)));
+ weak_factory_.GetWeakPtr()));
}
}
-MediaStreamDeviceObserver::~MediaStreamDeviceObserver() {}
+MediaStreamDeviceObserver::~MediaStreamDeviceObserver() = default;
MediaStreamDevices MediaStreamDeviceObserver::GetNonScreenCaptureDevices() {
MediaStreamDevices video_devices;
@@ -70,13 +70,21 @@ void MediaStreamDeviceObserver::OnDeviceStopped(
}
for (Stream& stream : it->value) {
- if (IsAudioInputMediaType(device.type))
+ if (IsAudioInputMediaType(device.type)) {
RemoveStreamDeviceFromArray(device, &stream.audio_devices);
- else
+ } else {
RemoveStreamDeviceFromArray(device, &stream.video_devices);
-
- if (stream.on_device_stopped_cb)
+ }
+ if (stream.on_device_stopped_cb) {
+ // Running `stream.on_device_stopped_cb` can destroy `this`. Use a weak
+ // pointer to detect that condition, and stop processing if it happens.
+ base::WeakPtr<MediaStreamDeviceObserver> weak_this =
+ weak_factory_.GetWeakPtr();
stream.on_device_stopped_cb.Run(device);
+ if (!weak_this) {
+ return;
+ }
+ }
}
// |it| could have already been invalidated in the function call above. So we
@@ -85,8 +93,9 @@ void MediaStreamDeviceObserver::OnDeviceStopped(
// iterator from |label_stream_map_| (https://crbug.com/616884). Future work
// needs to be done to resolve this re-entrancy issue.
it = label_stream_map_.find(label);
- if (it == label_stream_map_.end())
+ if (it == label_stream_map_.end()) {
return;
+ }
Vector<Stream>& streams = it->value;
auto* stream_it = streams.begin();
@@ -122,8 +131,16 @@ void MediaStreamDeviceObserver::OnDeviceChanged(
DCHECK_EQ(1u, it->value.size());
Stream* stream = &it->value[0];
- if (stream->on_device_changed_cb)
+ if (stream->on_device_changed_cb) {
+ // Running `stream->on_device_changed_cb` can destroy `this`. Use a weak
+ // pointer to detect that condition, and stop processing if it happens.
+ base::WeakPtr<MediaStreamDeviceObserver> weak_this =
+ weak_factory_.GetWeakPtr();
stream->on_device_changed_cb.Run(old_device, new_device);
+ if (!weak_this) {
+ return;
+ }
+ }
// Update device list only for device changing. Removing device will be
// handled in its own callback.
@@ -278,9 +295,9 @@ void MediaStreamDeviceObserver::RemoveStreamDevice(
streams_to_remove.push_back(entry.key);
}
}
- DCHECK(device_found);
- for (const String& label : streams_to_remove)
+ for (const String& label : streams_to_remove) {
label_stream_map_.erase(label);
+ }
}
base::UnguessableToken MediaStreamDeviceObserver::GetAudioSessionId(
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_device_observer.h b/third_party/blink/renderer/modules/mediastream/media_stream_device_observer.h
index 55aba2c4e5bd046a008590436ed8eefa4f099d5c..c5a8b5b1e31011f5d2f9f2064cabb10a74c25bf7 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_device_observer.h
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_device_observer.h
@@ -116,6 +116,7 @@ class MODULES_EXPORT MediaStreamDeviceObserver
using LabelStreamMap = HashMap<String, Vector<Stream>>;
LabelStreamMap label_stream_map_;
+ base::WeakPtrFactory<MediaStreamDeviceObserver> weak_factory_{this};
};
} // namespace blink
diff --git a/third_party/blink/renderer/platform/exported/mediastream/web_platform_media_stream_source.cc b/third_party/blink/renderer/platform/exported/mediastream/web_platform_media_stream_source.cc
index be69e8c9741faf0728022ff1cc89ccf8d89a0629..b9f5e9c86537dace6f42e4c92ac255990eb910f7 100644
--- a/third_party/blink/renderer/platform/exported/mediastream/web_platform_media_stream_source.cc
+++ b/third_party/blink/renderer/platform/exported/mediastream/web_platform_media_stream_source.cc
@@ -31,10 +31,12 @@ void WebPlatformMediaStreamSource::StopSource() {
void WebPlatformMediaStreamSource::FinalizeStopSource() {
DCHECK(task_runner_->BelongsToCurrentThread());
- if (!stop_callback_.is_null())
+ if (!stop_callback_.is_null()) {
std::move(stop_callback_).Run(Owner());
- if (Owner())
+ }
+ if (Owner()) {
Owner().SetReadyState(WebMediaStreamSource::kReadyStateEnded);
+ }
}
void WebPlatformMediaStreamSource::SetSourceMuted(bool is_muted) {
@@ -42,8 +44,9 @@ void WebPlatformMediaStreamSource::SetSourceMuted(bool is_muted) {
// Although this change is valid only if the ready state isn't already Ended,
// there's code further along (like in MediaStreamTrack) which filters
// that out already.
- if (!Owner())
+ if (!Owner()) {
return;
+ }
Owner().SetReadyState(is_muted ? WebMediaStreamSource::kReadyStateMuted
: WebMediaStreamSource::kReadyStateLive);
}
@@ -72,7 +75,6 @@ void WebPlatformMediaStreamSource::SetStopCallback(
void WebPlatformMediaStreamSource::ResetSourceStoppedCallback() {
DCHECK(task_runner_->BelongsToCurrentThread());
- DCHECK(!stop_callback_.is_null());
stop_callback_.Reset();
}

View 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 8b98d75aaa8f6d4df22c872cb9261381647256eb..7dabb9e9d4f3b0c00ce0acbcb2b7ff0e6085fc58 100644
--- a/third_party/ipcz/src/BUILD.gn
+++ b/third_party/ipcz/src/BUILD.gn
@@ -210,6 +210,7 @@ ipcz_source_set("impl") {
"ipcz/api_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",
@@ -253,7 +254,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 0cfadfa02aa4b7058e04c3b0255412a0d11aed87..9f920faf31748a6c4213045e31331af2a865bb4f 100644
--- a/third_party/ipcz/src/ipcz/node_link_memory.cc
+++ b/third_party/ipcz/src/ipcz/node_link_memory.cc
@@ -278,8 +278,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());

View 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_);
};

View File

@@ -0,0 +1,40 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lei Zhang <thestig@chromium.org>
Date: Wed, 13 Sep 2023 23:32:40 +0000
Subject: M117: Check for object destruction in PdfViewWebPlugin::UpdateFocus()
PdfViewWebPlugin::UpdateFocus() can potentially triggers its own
destruction. Add a check for this and bail out.
(cherry picked from commit cacf485a202b342526374d444375b80a044add76)
Bug: 1480184
Change-Id: I5e7760ed541a2bffb9dd1ebeb522f10650049033
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4852346
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Code-Coverage: findit-for-me@appspot.gserviceaccount.com <findit-for-me@appspot.gserviceaccount.com>
Commit-Queue: Lei Zhang <thestig@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1194210}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4863395
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/branch-heads/5938@{#1286}
Cr-Branched-From: 2b50cb4bcc2318034581a816714d9535dc38966d-refs/heads/main@{#1181205}
diff --git a/pdf/pdf_view_web_plugin.cc b/pdf/pdf_view_web_plugin.cc
index cdedca1425dd5be31b2d0b5220d0e050d0b0fb59..b14777df757c8c9b3e5474e7f0f73fe316bfee58 100644
--- a/pdf/pdf_view_web_plugin.cc
+++ b/pdf/pdf_view_web_plugin.cc
@@ -519,7 +519,13 @@ void PdfViewWebPlugin::UpdateFocus(bool focused,
if (has_focus_ != focused) {
engine_->UpdateFocus(focused);
client_->UpdateTextInputState();
+
+ // Make sure `this` is still alive after the UpdateSelectionBounds() call.
+ auto weak_this = weak_factory_.GetWeakPtr();
client_->UpdateSelectionBounds();
+ if (!weak_this) {
+ return;
+ }
}
has_focus_ = focused;

View 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 94d27ec3ab22f7afb5e265fdcee662e48f36c00e..81348ceb4a415f789dd384988a54662ec3c3d0e0 100644
--- a/chrome/browser/ui/views/tabs/fake_tab_slot_controller.cc
+++ b/chrome/browser/ui/views/tabs/fake_tab_slot_controller.cc
@@ -45,6 +45,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 ebbae9b19a8f9534e3a86d2bf28875418a7be80d..4795c222651af3a7146a8bf12e824a1480cdbfae 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 6a43f963a22917b9e9b861d3619d9804851dfb5b..d412ad6d5d9a95aa5d635fae5232eddfa87132ae 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 f2f18c7f21bc249b95dece091716fcb6872b0c12..22a4b6b761058f44cbea029bbc52dd4071e111e9 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -174,7 +174,7 @@ class TabStrip::TabDragContextImpl : public TabDragContext,
}
bool OnMouseDragged(const ui::MouseEvent& event) override {
- ContinueDrag(this, event);
+ (void)ContinueDrag(this, event);
return true;
}
@@ -185,6 +185,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:
@@ -198,7 +199,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:
@@ -210,6 +212,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.
@@ -295,20 +303,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) {
@@ -1573,8 +1581,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 fce93e7d993434ce1e99c7cbca71c1391798c1a4..de6f20bb978c32d635b4f8b75841c148996df2c6 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;

View File

@@ -0,0 +1,84 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Rune Lillesveen <futhark@chromium.org>
Date: Tue, 15 Aug 2023 15:04:39 +0000
Subject: Don't keep pointer to popped stack memory for :has()
The sibling_features pass into UpdateFeaturesFromCombinator may be
initialized to last_compound_in_adjacent_chain_features if null. The
outer while loop in
AddFeaturesToInvalidationSetsForLogicalCombinationInHas() could then
reference to the last_compound_in_adjacent_chain_features which is
popped from the stack on every outer iteration. That caused an ASAN
failure for reading stack memory that had been popped.
Instead make sure each inner iteration restarts with the same
sibling_features pointer, which seems to have been the intent here.
(cherry picked from commit 5e213507a2f0d6e3c96904a710407b01493670bd)
Bug: 1470477
Change-Id: I260c93016f8ab0d165e4b29ca1aea810bede5b97
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4759326
Commit-Queue: Rune Lillesveen <futhark@chromium.org>
Reviewed-by: Anders Hartvoll Ruud <andruud@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1181365}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4777251
Cr-Commit-Position: refs/branch-heads/5845@{#1482}
Cr-Branched-From: 5a5dff63a4a4c63b9b18589819bebb2566c85443-refs/heads/main@{#1160321}
diff --git a/third_party/blink/renderer/core/css/rule_feature_set.cc b/third_party/blink/renderer/core/css/rule_feature_set.cc
index ec7356285d7fa45b7d9c1701be484a121c2a0017..9cb6084b7fca4fc6ff2edd8defadf8fabf2899b5 100644
--- a/third_party/blink/renderer/core/css/rule_feature_set.cc
+++ b/third_party/blink/renderer/core/css/rule_feature_set.cc
@@ -1227,6 +1227,7 @@ void RuleFeatureSet::AddFeaturesToInvalidationSetsForLogicalCombinationInHas(
descendant_features);
const CSSSelector* compound_in_logical_combination = complex;
+ InvalidationSetFeatures* inner_sibling_features = sibling_features;
InvalidationSetFeatures last_compound_in_adjacent_chain_features;
while (compound_in_logical_combination) {
AddFeaturesToInvalidationSetsForLogicalCombinationInHasContext context(
@@ -1238,14 +1239,14 @@ void RuleFeatureSet::AddFeaturesToInvalidationSetsForLogicalCombinationInHas(
last_in_compound =
SkipAddingAndGetLastInCompoundForLogicalCombinationInHas(
compound_in_logical_combination, compound_containing_has,
- sibling_features, descendant_features, previous_combinator,
- add_features_method);
+ inner_sibling_features, descendant_features,
+ previous_combinator, add_features_method);
} else {
last_in_compound =
AddFeaturesAndGetLastInCompoundForLogicalCombinationInHas(
compound_in_logical_combination, compound_containing_has,
- sibling_features, descendant_features, previous_combinator,
- add_features_method);
+ inner_sibling_features, descendant_features,
+ previous_combinator, add_features_method);
}
if (!last_in_compound)
@@ -1259,7 +1260,7 @@ void RuleFeatureSet::AddFeaturesToInvalidationSetsForLogicalCombinationInHas(
? CSSSelector::kIndirectAdjacent
: previous_combinator,
context.last_compound_in_adjacent_chain,
- last_compound_in_adjacent_chain_features, sibling_features,
+ last_compound_in_adjacent_chain_features, inner_sibling_features,
descendant_features);
}
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/has-sibling-chrome-crash.html b/third_party/blink/web_tests/external/wpt/css/selectors/has-sibling-chrome-crash.html
new file mode 100644
index 0000000000000000000000000000000000000000..0306e3e39272c321fc3539aa582b4e239ffe2fa1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/selectors/has-sibling-chrome-crash.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<title>CSS Selectors Test: Chrome crash issue 1470477</title>
+<link rel="help" href="https://crbug.com/1470477">
+<style>
+ :has(> :where(label:first-child + [a="a"]:only-of-type,
+ [a="a"]:only-of-type + label:last-child)) label:last-child {
+ margin-inline: 1em;
+ }
+</style>
+<p>PASS if this tests does not crash</p>

View File

@@ -0,0 +1,93 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Adam Rice <ricea@chromium.org>
Date: Tue, 8 Aug 2023 08:48:51 +0000
Subject: NetworkContext: Don't access url_loader_factories_ during destruction
Move the contents of `url_loader_factories_` to a temporary variable in
the destructor of network::NetworkContext so that re-entrant calls to
DestroyURLLoaderFactory() don't happen after it has started being
destroyed.
BUG=1465833
(cherry picked from commit e579b20308290df03f045c5d0ccb852d96b24ce3)
Change-Id: I476f0865256bdcba4ec934688597e69991968f84
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4733351
Reviewed-by: Kenichi Ishibashi <bashi@chromium.org>
Commit-Queue: Adam Rice <ricea@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1177648}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4756334
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Auto-Submit: Adam Rice <ricea@chromium.org>
Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/branch-heads/5845@{#1252}
Cr-Branched-From: 5a5dff63a4a4c63b9b18589819bebb2566c85443-refs/heads/main@{#1160321}
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index 6dc46954b070795de082d8542f8bae56d7b52dd4..2b12040f5ef2b7fd466a9b6d92e75faea8bd1808 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -712,6 +712,8 @@ NetworkContext::NetworkContext(
}
NetworkContext::~NetworkContext() {
+ is_destructing_ = true;
+
// May be nullptr in tests.
if (network_service_)
network_service_->DeregisterNetworkContext(this);
@@ -775,6 +777,12 @@ NetworkContext::~NetworkContext() {
}
}
#endif // BUILDFLAG(IS_DIRECTORY_TRANSFER_REQUIRED)
+
+ // Clear `url_loader_factories_` before deleting the contents, as it can
+ // result in re-entrant calls to DestroyURLLoaderFactory().
+ std::set<std::unique_ptr<cors::CorsURLLoaderFactory>,
+ base::UniquePtrComparator>
+ url_loader_factories = std::move(url_loader_factories_);
}
// static
@@ -993,6 +1001,9 @@ void NetworkContext::DisableQuic() {
void NetworkContext::DestroyURLLoaderFactory(
cors::CorsURLLoaderFactory* url_loader_factory) {
+ if (is_destructing_) {
+ return;
+ }
auto it = url_loader_factories_.find(url_loader_factory);
DCHECK(it != url_loader_factories_.end());
url_loader_factories_.erase(it);
diff --git a/services/network/network_context.h b/services/network/network_context.h
index 402a9de330140e78f14dbfae204f4c637803fcef..9e4db6927a42308b7ac30455f27ad97b92e2b0c3 100644
--- a/services/network/network_context.h
+++ b/services/network/network_context.h
@@ -915,6 +915,10 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
// DCHECKs on APIs used by external callers.
bool require_network_isolation_key_ = false;
+ // True once the destructor has been called. Used to guard against re-entrant
+ // calls to DestroyURLLoaderFactory().
+ bool is_destructing_ = false;
+
// Indicating whether
// https://fetch.spec.whatwg.org/#cors-non-wildcard-request-header-name is
// supported.
@@ -923,13 +927,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
// CorsURLLoaderFactory assumes that fields owned by the NetworkContext always
// live longer than the factory. Therefore we want the factories to be
- // destroyed before other fields above. In particular:
- // - This must be below |url_request_context_| so that the URLRequestContext
- // outlives all the URLLoaderFactories and URLLoaders that depend on it;
- // for the same reason, it must also be below |network_context_|.
- // - This must be below |loader_count_per_process_| that is touched by
- // CorsURLLoaderFactory::DestroyURLLoader (see also
- // https://crbug.com/1174943).
+ // destroyed before other fields above. This is accomplished by explicitly
+ // clearing `url_loader_factories_` in the destructor.
std::set<std::unique_ptr<cors::CorsURLLoaderFactory>,
base::UniquePtrComparator>
url_loader_factories_;

View File

@@ -29,5 +29,9 @@
"src/electron/patches/dawn": "src/third_party/dawn",
"src/electron/patches/webrtc": "src/third_party/webrtc"
"src/electron/patches/webrtc": "src/third_party/webrtc",
"src/electron/patches/libwebp": "src/third_party/libwebp/src",
"src/electron/patches/libvpx": "src/third_party/libvpx/source/libvpx"
}

1
patches/libvpx/.patches Normal file
View File

@@ -0,0 +1 @@
cherry-pick-3fbd1dca6a4d.patch

View File

@@ -0,0 +1,27 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: James Zern <jzern@google.com>
Date: Mon, 25 Sep 2023 18:55:59 -0700
Subject: VP8: disallow thread count changes
Currently allocations are done at encoder creation time. Going from
threaded to non-threaded would cause a crash.
Bug: chromium:1486441
Change-Id: Ie301c2a70847dff2f0daae408fbef1e4d42e73d4
diff --git a/vp8/encoder/onyx_if.c b/vp8/encoder/onyx_if.c
index 94fb6e256e8f4f1077aa6e2aef84e3bc7070da0f..f68339d2b4f4b2ca654a835cc56c537fb5e7d260 100644
--- a/vp8/encoder/onyx_if.c
+++ b/vp8/encoder/onyx_if.c
@@ -1443,6 +1443,11 @@ void vp8_change_config(VP8_COMP *cpi, VP8_CONFIG *oxcf) {
last_h = cpi->oxcf.Height;
prev_number_of_layers = cpi->oxcf.number_of_layers;
+ if (cpi->initial_width) {
+ // TODO(https://crbug.com/1486441): Allow changing thread counts; the
+ // allocation is done once in vp8_create_compressor().
+ oxcf->multi_threaded = cpi->oxcf.multi_threaded;
+ }
cpi->oxcf = *oxcf;
switch (cpi->oxcf.Mode) {

1
patches/libwebp/.patches Normal file
View File

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

View File

@@ -0,0 +1,353 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Vincent Rabaud <vrabaud@google.com>
Date: Thu, 7 Sep 2023 21:16:03 +0200
Subject: Fix OOB write in BuildHuffmanTable.
First, BuildHuffmanTable is called to check if the data is valid.
If it is and the table is not big enough, more memory is allocated.
This will make sure that valid (but unoptimized because of unbalanced
codes) streams are still decodable.
Bug: chromium:1479274
Change-Id: I31c36dbf3aa78d35ecf38706b50464fd3d375741
(cherry picked from commit 902bc9190331343b2017211debcec8d2ab87e17a)
(cherry picked from commit 2af26267cdfcb63a88e5c74a85927a12d6ca1d76)
diff --git a/src/dec/vp8l_dec.c b/src/dec/vp8l_dec.c
index 13480551282eca71560641a68c632e13acd3cd79..186b0b2f826a17a4889299a90a068725d06be4f3 100644
--- a/src/dec/vp8l_dec.c
+++ b/src/dec/vp8l_dec.c
@@ -253,11 +253,11 @@ static int ReadHuffmanCodeLengths(
int symbol;
int max_symbol;
int prev_code_len = DEFAULT_CODE_LENGTH;
- HuffmanCode table[1 << LENGTHS_TABLE_BITS];
+ HuffmanTables tables;
- if (!VP8LBuildHuffmanTable(table, LENGTHS_TABLE_BITS,
- code_length_code_lengths,
- NUM_CODE_LENGTH_CODES)) {
+ if (!VP8LHuffmanTablesAllocate(1 << LENGTHS_TABLE_BITS, &tables) ||
+ !VP8LBuildHuffmanTable(&tables, LENGTHS_TABLE_BITS,
+ code_length_code_lengths, NUM_CODE_LENGTH_CODES)) {
goto End;
}
@@ -277,7 +277,7 @@ static int ReadHuffmanCodeLengths(
int code_len;
if (max_symbol-- == 0) break;
VP8LFillBitWindow(br);
- p = &table[VP8LPrefetchBits(br) & LENGTHS_TABLE_MASK];
+ p = &tables.curr_segment->start[VP8LPrefetchBits(br) & LENGTHS_TABLE_MASK];
VP8LSetBitPos(br, br->bit_pos_ + p->bits);
code_len = p->value;
if (code_len < kCodeLengthLiterals) {
@@ -300,6 +300,7 @@ static int ReadHuffmanCodeLengths(
ok = 1;
End:
+ VP8LHuffmanTablesDeallocate(&tables);
if (!ok) dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
return ok;
}
@@ -307,7 +308,8 @@ static int ReadHuffmanCodeLengths(
// 'code_lengths' is pre-allocated temporary buffer, used for creating Huffman
// tree.
static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
- int* const code_lengths, HuffmanCode* const table) {
+ int* const code_lengths,
+ HuffmanTables* const table) {
int ok = 0;
int size = 0;
VP8LBitReader* const br = &dec->br_;
@@ -362,8 +364,7 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
VP8LMetadata* const hdr = &dec->hdr_;
uint32_t* huffman_image = NULL;
HTreeGroup* htree_groups = NULL;
- HuffmanCode* huffman_tables = NULL;
- HuffmanCode* huffman_table = NULL;
+ HuffmanTables* huffman_tables = &hdr->huffman_tables_;
int num_htree_groups = 1;
int num_htree_groups_max = 1;
int max_alphabet_size = 0;
@@ -372,6 +373,10 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
int* mapping = NULL;
int ok = 0;
+ // Check the table has been 0 initialized (through InitMetadata).
+ assert(huffman_tables->root.start == NULL);
+ assert(huffman_tables->curr_segment == NULL);
+
if (allow_recursion && VP8LReadBits(br, 1)) {
// use meta Huffman codes.
const int huffman_precision = VP8LReadBits(br, 3) + 2;
@@ -434,16 +439,15 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
code_lengths = (int*)WebPSafeCalloc((uint64_t)max_alphabet_size,
sizeof(*code_lengths));
- huffman_tables = (HuffmanCode*)WebPSafeMalloc(num_htree_groups * table_size,
- sizeof(*huffman_tables));
htree_groups = VP8LHtreeGroupsNew(num_htree_groups);
- if (htree_groups == NULL || code_lengths == NULL || huffman_tables == NULL) {
+ if (htree_groups == NULL || code_lengths == NULL ||
+ !VP8LHuffmanTablesAllocate(num_htree_groups * table_size,
+ huffman_tables)) {
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
goto Error;
}
- huffman_table = huffman_tables;
for (i = 0; i < num_htree_groups_max; ++i) {
// If the index "i" is unused in the Huffman image, just make sure the
// coefficients are valid but do not store them.
@@ -468,19 +472,20 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
int max_bits = 0;
for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
int alphabet_size = kAlphabetSize[j];
- htrees[j] = huffman_table;
if (j == 0 && color_cache_bits > 0) {
alphabet_size += (1 << color_cache_bits);
}
- size = ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_table);
+ size =
+ ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_tables);
+ htrees[j] = huffman_tables->curr_segment->curr_table;
if (size == 0) {
goto Error;
}
if (is_trivial_literal && kLiteralMap[j] == 1) {
- is_trivial_literal = (huffman_table->bits == 0);
+ is_trivial_literal = (htrees[j]->bits == 0);
}
- total_size += huffman_table->bits;
- huffman_table += size;
+ total_size += htrees[j]->bits;
+ huffman_tables->curr_segment->curr_table += size;
if (j <= ALPHA) {
int local_max_bits = code_lengths[0];
int k;
@@ -515,14 +520,13 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
hdr->huffman_image_ = huffman_image;
hdr->num_htree_groups_ = num_htree_groups;
hdr->htree_groups_ = htree_groups;
- hdr->huffman_tables_ = huffman_tables;
Error:
WebPSafeFree(code_lengths);
WebPSafeFree(mapping);
if (!ok) {
WebPSafeFree(huffman_image);
- WebPSafeFree(huffman_tables);
+ VP8LHuffmanTablesDeallocate(huffman_tables);
VP8LHtreeGroupsFree(htree_groups);
}
return ok;
@@ -1358,7 +1362,7 @@ static void ClearMetadata(VP8LMetadata* const hdr) {
assert(hdr != NULL);
WebPSafeFree(hdr->huffman_image_);
- WebPSafeFree(hdr->huffman_tables_);
+ VP8LHuffmanTablesDeallocate(&hdr->huffman_tables_);
VP8LHtreeGroupsFree(hdr->htree_groups_);
VP8LColorCacheClear(&hdr->color_cache_);
VP8LColorCacheClear(&hdr->saved_color_cache_);
@@ -1673,7 +1677,7 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
if (dec == NULL) return 0;
- assert(dec->hdr_.huffman_tables_ != NULL);
+ assert(dec->hdr_.huffman_tables_.root.start != NULL);
assert(dec->hdr_.htree_groups_ != NULL);
assert(dec->hdr_.num_htree_groups_ > 0);
diff --git a/src/dec/vp8li_dec.h b/src/dec/vp8li_dec.h
index 72b2e861208447f45e5ee12eac57b9c36ff2cd31..32540a4b88a05cc74b88f11da3f143e83be81c9c 100644
--- a/src/dec/vp8li_dec.h
+++ b/src/dec/vp8li_dec.h
@@ -51,7 +51,7 @@ typedef struct {
uint32_t* huffman_image_;
int num_htree_groups_;
HTreeGroup* htree_groups_;
- HuffmanCode* huffman_tables_;
+ HuffmanTables huffman_tables_;
} VP8LMetadata;
typedef struct VP8LDecoder VP8LDecoder;
diff --git a/src/utils/huffman_utils.c b/src/utils/huffman_utils.c
index 0cba0fbb7d4f3a945cf9f9909a3e4c1b96ec92da..9efd6283ac30210fb7450250f855cbd1d75f55ec 100644
--- a/src/utils/huffman_utils.c
+++ b/src/utils/huffman_utils.c
@@ -177,21 +177,24 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
if (num_open < 0) {
return 0;
}
- if (root_table == NULL) continue;
for (; count[len] > 0; --count[len]) {
HuffmanCode code;
if ((key & mask) != low) {
- table += table_size;
+ if (root_table != NULL) table += table_size;
table_bits = NextTableBitSize(count, len, root_bits);
table_size = 1 << table_bits;
total_size += table_size;
low = key & mask;
- root_table[low].bits = (uint8_t)(table_bits + root_bits);
- root_table[low].value = (uint16_t)((table - root_table) - low);
+ if (root_table != NULL) {
+ root_table[low].bits = (uint8_t)(table_bits + root_bits);
+ root_table[low].value = (uint16_t)((table - root_table) - low);
+ }
+ }
+ if (root_table != NULL) {
+ code.bits = (uint8_t)(len - root_bits);
+ code.value = (uint16_t)sorted[symbol++];
+ ReplicateValue(&table[key >> root_bits], step, table_size, code);
}
- code.bits = (uint8_t)(len - root_bits);
- code.value = (uint16_t)sorted[symbol++];
- ReplicateValue(&table[key >> root_bits], step, table_size, code);
key = GetNextKey(key, len);
}
}
@@ -211,25 +214,83 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
((1 << MAX_CACHE_BITS) + NUM_LITERAL_CODES + NUM_LENGTH_CODES)
// Cut-off value for switching between heap and stack allocation.
#define SORTED_SIZE_CUTOFF 512
-int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
+int VP8LBuildHuffmanTable(HuffmanTables* const root_table, int root_bits,
const int code_lengths[], int code_lengths_size) {
- int total_size;
+ const int total_size =
+ BuildHuffmanTable(NULL, root_bits, code_lengths, code_lengths_size, NULL);
assert(code_lengths_size <= MAX_CODE_LENGTHS_SIZE);
- if (root_table == NULL) {
- total_size = BuildHuffmanTable(NULL, root_bits,
- code_lengths, code_lengths_size, NULL);
- } else if (code_lengths_size <= SORTED_SIZE_CUTOFF) {
+ if (total_size == 0 || root_table == NULL) return total_size;
+
+ if (root_table->curr_segment->curr_table + total_size >=
+ root_table->curr_segment->start + root_table->curr_segment->size) {
+ // If 'root_table' does not have enough memory, allocate a new segment.
+ // The available part of root_table->curr_segment is left unused because we
+ // need a contiguous buffer.
+ const int segment_size = root_table->curr_segment->size;
+ struct HuffmanTablesSegment* next =
+ (HuffmanTablesSegment*)WebPSafeMalloc(1, sizeof(*next));
+ if (next == NULL) return 0;
+ // Fill the new segment.
+ // We need at least 'total_size' but if that value is small, it is better to
+ // allocate a big chunk to prevent more allocations later. 'segment_size' is
+ // therefore chosen (any other arbitrary value could be chosen).
+ next->size = total_size > segment_size ? total_size : segment_size;
+ next->start =
+ (HuffmanCode*)WebPSafeMalloc(next->size, sizeof(*next->start));
+ if (next->start == NULL) {
+ WebPSafeFree(next);
+ return 0;
+ }
+ next->curr_table = next->start;
+ next->next = NULL;
+ // Point to the new segment.
+ root_table->curr_segment->next = next;
+ root_table->curr_segment = next;
+ }
+ if (code_lengths_size <= SORTED_SIZE_CUTOFF) {
// use local stack-allocated array.
uint16_t sorted[SORTED_SIZE_CUTOFF];
- total_size = BuildHuffmanTable(root_table, root_bits,
- code_lengths, code_lengths_size, sorted);
- } else { // rare case. Use heap allocation.
+ BuildHuffmanTable(root_table->curr_segment->curr_table, root_bits,
+ code_lengths, code_lengths_size, sorted);
+ } else { // rare case. Use heap allocation.
uint16_t* const sorted =
(uint16_t*)WebPSafeMalloc(code_lengths_size, sizeof(*sorted));
if (sorted == NULL) return 0;
- total_size = BuildHuffmanTable(root_table, root_bits,
- code_lengths, code_lengths_size, sorted);
+ BuildHuffmanTable(root_table->curr_segment->curr_table, root_bits,
+ code_lengths, code_lengths_size, sorted);
WebPSafeFree(sorted);
}
return total_size;
}
+
+int VP8LHuffmanTablesAllocate(int size, HuffmanTables* huffman_tables) {
+ // Have 'segment' point to the first segment for now, 'root'.
+ HuffmanTablesSegment* const root = &huffman_tables->root;
+ huffman_tables->curr_segment = root;
+ // Allocate root.
+ root->start = (HuffmanCode*)WebPSafeMalloc(size, sizeof(*root->start));
+ if (root->start == NULL) return 0;
+ root->curr_table = root->start;
+ root->next = NULL;
+ root->size = size;
+ return 1;
+}
+
+void VP8LHuffmanTablesDeallocate(HuffmanTables* const huffman_tables) {
+ HuffmanTablesSegment *current, *next;
+ if (huffman_tables == NULL) return;
+ // Free the root node.
+ current = &huffman_tables->root;
+ next = current->next;
+ WebPSafeFree(current->start);
+ current->start = NULL;
+ current->next = NULL;
+ current = next;
+ // Free the following nodes.
+ while (current != NULL) {
+ next = current->next;
+ WebPSafeFree(current->start);
+ WebPSafeFree(current);
+ current = next;
+ }
+}
diff --git a/src/utils/huffman_utils.h b/src/utils/huffman_utils.h
index 13b7ad1ac40c5316f5506d9b4cbf5039c9fd5600..98415c532895374ea28fc1dc5c9a15c751ea9ba0 100644
--- a/src/utils/huffman_utils.h
+++ b/src/utils/huffman_utils.h
@@ -43,6 +43,29 @@ typedef struct {
// or non-literal symbol otherwise
} HuffmanCode32;
+// Contiguous memory segment of HuffmanCodes.
+typedef struct HuffmanTablesSegment {
+ HuffmanCode* start;
+ // Pointer to where we are writing into the segment. Starts at 'start' and
+ // cannot go beyond 'start' + 'size'.
+ HuffmanCode* curr_table;
+ // Pointer to the next segment in the chain.
+ struct HuffmanTablesSegment* next;
+ int size;
+} HuffmanTablesSegment;
+
+// Chained memory segments of HuffmanCodes.
+typedef struct HuffmanTables {
+ HuffmanTablesSegment root;
+ // Currently processed segment. At first, this is 'root'.
+ HuffmanTablesSegment* curr_segment;
+} HuffmanTables;
+
+// Allocates a HuffmanTables with 'size' contiguous HuffmanCodes. Returns 0 on
+// memory allocation error, 1 otherwise.
+int VP8LHuffmanTablesAllocate(int size, HuffmanTables* huffman_tables);
+void VP8LHuffmanTablesDeallocate(HuffmanTables* const huffman_tables);
+
#define HUFFMAN_PACKED_BITS 6
#define HUFFMAN_PACKED_TABLE_SIZE (1u << HUFFMAN_PACKED_BITS)
@@ -78,9 +101,7 @@ void VP8LHtreeGroupsFree(HTreeGroup* const htree_groups);
// the huffman table.
// Returns built table size or 0 in case of error (invalid tree or
// memory error).
-// If root_table is NULL, it returns 0 if a lookup cannot be built, something
-// > 0 otherwise (but not the table size).
-int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
+int VP8LBuildHuffmanTable(HuffmanTables* const root_table, int root_bits,
const int code_lengths[], int code_lengths_size);
#ifdef __cplusplus

View File

@@ -55,3 +55,4 @@ chore_enable_c_17_for_native_modules.patch
enable_crashpad_linux_node_processes.patch
cherry-pick-09ae62b.patch
allow_embedder_to_control_codegenerationfromstringscallback.patch
fix_do_not_resolve_electron_entrypoints.patch

View 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).

View File

@@ -1,2 +1,3 @@
enforce_program_stack_limits_on_function_parameters.patch
enforce_size_limits_on_struct_and_array_declarations.patch
enforce_an_upper_limit_of_715_million_path_verbs_in_skpath.patch

View File

@@ -0,0 +1,118 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: John Stiles <johnstiles@google.com>
Date: Thu, 3 Aug 2023 13:33:52 -0400
Subject: Enforce an upper limit of 715 million path verbs in SkPath.
Bug: chromium:1464215
Change-Id: Iedb7d73fc80de5ffb881b664dd77314cc2c6b108
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/735316
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: John Stiles <johnstiles@google.com>
diff --git a/relnotes/path_715M.md b/relnotes/path_715M.md
new file mode 100644
index 0000000000000000000000000000000000000000..7be9a40f1fc5b4f6432c490725b05d536d497fb1
--- /dev/null
+++ b/relnotes/path_715M.md
@@ -0,0 +1 @@
+SkPath now enforces an upper limit of 715 million path verbs.
diff --git a/src/core/SkPath.cpp b/src/core/SkPath.cpp
index 7caac5ca6f05d89a2986c3eea432eedcd201203f..1a9279784b5b7bab3e0ca6dad9d1fd49a9038965 100644
--- a/src/core/SkPath.cpp
+++ b/src/core/SkPath.cpp
@@ -27,6 +27,7 @@
#include "src/pathops/SkPathOpsPoint.h"
#include <cmath>
+#include <limits.h>
#include <utility>
struct SkPath_Storage_Equivalent {
@@ -3401,43 +3402,52 @@ bool SkPath::IsCubicDegenerate(const SkPoint& p1, const SkPoint& p2,
SkPathVerbAnalysis sk_path_analyze_verbs(const uint8_t vbs[], int verbCount) {
SkPathVerbAnalysis info = {false, 0, 0, 0};
-
bool needMove = true;
bool invalid = false;
- for (int i = 0; i < verbCount; ++i) {
- switch ((SkPathVerb)vbs[i]) {
- case SkPathVerb::kMove:
- needMove = false;
- info.points += 1;
- break;
- case SkPathVerb::kLine:
- invalid |= needMove;
- info.segmentMask |= kLine_SkPathSegmentMask;
- info.points += 1;
- break;
- case SkPathVerb::kQuad:
- invalid |= needMove;
- info.segmentMask |= kQuad_SkPathSegmentMask;
- info.points += 2;
- break;
- case SkPathVerb::kConic:
- invalid |= needMove;
- info.segmentMask |= kConic_SkPathSegmentMask;
- info.points += 2;
- info.weights += 1;
- break;
- case SkPathVerb::kCubic:
- invalid |= needMove;
- info.segmentMask |= kCubic_SkPathSegmentMask;
- info.points += 3;
- break;
- case SkPathVerb::kClose:
- invalid |= needMove;
- needMove = true;
- break;
- default:
- invalid = true;
- break;
+
+ if (verbCount >= (INT_MAX / 3)) {
+ // A path with an extremely high number of quad, conic or cubic verbs could cause
+ // `info.points` to overflow. To prevent against this, we reject extremely large paths. This
+ // check is conservative and assumes the worst case (in particular, it assumes that every
+ // verb consumes 3 points, which would only happen for a path composed entirely of cubics).
+ // This limits us to 700 million verbs, which is large enough for any reasonable use case.
+ invalid = true;
+ } else {
+ for (int i = 0; i < verbCount; ++i) {
+ switch ((SkPathVerb)vbs[i]) {
+ case SkPathVerb::kMove:
+ needMove = false;
+ info.points += 1;
+ break;
+ case SkPathVerb::kLine:
+ invalid |= needMove;
+ info.segmentMask |= kLine_SkPathSegmentMask;
+ info.points += 1;
+ break;
+ case SkPathVerb::kQuad:
+ invalid |= needMove;
+ info.segmentMask |= kQuad_SkPathSegmentMask;
+ info.points += 2;
+ break;
+ case SkPathVerb::kConic:
+ invalid |= needMove;
+ info.segmentMask |= kConic_SkPathSegmentMask;
+ info.points += 2;
+ info.weights += 1;
+ break;
+ case SkPathVerb::kCubic:
+ invalid |= needMove;
+ info.segmentMask |= kCubic_SkPathSegmentMask;
+ info.points += 3;
+ break;
+ case SkPathVerb::kClose:
+ invalid |= needMove;
+ needMove = true;
+ break;
+ default:
+ invalid = true;
+ break;
+ }
}
}
info.valid = !invalid;

View File

@@ -25,3 +25,10 @@ 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
promise_allsettled_mark_values_array_as_cow.patch
merged_builtins_clear_fixedarray_slot_in_promise_builtins.patch
merged_compiler_check_for_read-only_property_on.patch
shared-struct_fix_for-in_enumeration.patch
merged_squashed_multiple_commits.patch
cherry-pick-038530c94a06.patch
cherry-pick-b0ad701a609a.patch

View File

@@ -0,0 +1,49 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Tobias Tebbi <tebbi@chromium.org>
Date: Wed, 30 Aug 2023 10:59:48 +0200
Subject: Merged: [turbofan] Growing a non-JSArray packed elements kind makes
it holey
Bug: chromium:1473247
(cherry picked from commit ae7dc61652805bc8e2b060d53b2b6da7cf846b6f)
Change-Id: I5268513bc91ca0cc18e3e2115244c0b090afa0da
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4831892
Auto-Submit: Leszek Swirski <leszeks@chromium.org>
Owners-Override: Leszek Swirski <leszeks@chromium.org>
Commit-Queue: Darius Mercadier <dmercadier@chromium.org>
Reviewed-by: Darius Mercadier <dmercadier@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/branch-heads/11.6@{#34}
Cr-Branched-From: e29c028f391389a7a60ee37097e3ca9e396d6fa4-refs/heads/11.6.189@{#3}
Cr-Branched-From: 95cbef20e2aa556a1ea75431a48b36c4de6b9934-refs/heads/main@{#88340}
diff --git a/src/compiler/js-native-context-specialization.cc b/src/compiler/js-native-context-specialization.cc
index 31b6d2dd0944a4d541947c773b175f86d24c86f6..72d97098c60e78b53cfa2356eabdc54f3eafc133 100644
--- a/src/compiler/js-native-context-specialization.cc
+++ b/src/compiler/js-native-context-specialization.cc
@@ -3628,15 +3628,21 @@ JSNativeContextSpecialization::BuildElementAccess(
// the (potential) backing store growth would normalize and thus
// the elements kind of the {receiver} would change to slow mode.
//
- // For PACKED_*_ELEMENTS the {index} must be within the range
+ // For JSArray PACKED_*_ELEMENTS the {index} must be within the range
// [0,length+1[ to be valid. In case {index} equals {length},
// the {receiver} will be extended, but kept packed.
+ //
+ // Non-JSArray PACKED_*_ELEMENTS always grow by adding holes because they
+ // lack the magical length property, which requires a map transition.
+ // So we can assume that this did not happen if we did not see this map.
Node* limit =
IsHoleyElementsKind(elements_kind)
? graph()->NewNode(simplified()->NumberAdd(), elements_length,
jsgraph()->Constant(JSObject::kMaxGap))
- : graph()->NewNode(simplified()->NumberAdd(), length,
- jsgraph()->OneConstant());
+ : receiver_is_jsarray
+ ? graph()->NewNode(simplified()->NumberAdd(), length,
+ jsgraph()->OneConstant())
+ : elements_length;
index = effect = graph()->NewNode(
simplified()->CheckBounds(
FeedbackSource(), CheckBoundsFlag::kConvertStringAndMinusZero),

View File

@@ -0,0 +1,56 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shu-yu Guo <syg@chromium.org>
Date: Wed, 6 Sep 2023 17:36:38 -0700
Subject: Merged: [builtins] Clear FixedArray slot in Promise builtins
(cherry picked from commit f1884222ad56734e56d80f9707e0e8279af9049e)
Bug: chromium:1479104
Change-Id: Iddc16d8add4dc6bf6f55f537da44770bea6f4bc3
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4862980
Auto-Submit: Shu-yu Guo <syg@chromium.org>
Reviewed-by: Adam Klein <adamk@chromium.org>
Commit-Queue: Adam Klein <adamk@chromium.org>
Cr-Commit-Position: refs/branch-heads/11.6@{#36}
Cr-Branched-From: e29c028f391389a7a60ee37097e3ca9e396d6fa4-refs/heads/11.6.189@{#3}
Cr-Branched-From: 95cbef20e2aa556a1ea75431a48b36c4de6b9934-refs/heads/main@{#88340}
diff --git a/src/builtins/promise-any.tq b/src/builtins/promise-any.tq
index 45bafac0e6b09143b69b21a7292f9ed6b9c46239..d531d57a375ba33bf11ccf698da5918f1e25f38c 100644
--- a/src/builtins/promise-any.tq
+++ b/src/builtins/promise-any.tq
@@ -106,9 +106,10 @@ PromiseAnyRejectElementClosure(
const index = identityHash - 1;
// 6. Let errors be F.[[Errors]].
- let errors = *ContextSlot(
+ let errorsRef:&FixedArray = ContextSlot(
context,
PromiseAnyRejectElementContextSlots::kPromiseAnyRejectElementErrorsSlot);
+ let errors = *errorsRef;
// 7. Let promiseCapability be F.[[Capability]].
@@ -134,10 +135,7 @@ PromiseAnyRejectElementClosure(
IntPtrMax(SmiUntag(remainingElementsCount) - 1, index + 1);
if (newCapacity > errors.length_intptr) deferred {
errors = ExtractFixedArray(errors, 0, errors.length_intptr, newCapacity);
- *ContextSlot(
- context,
- PromiseAnyRejectElementContextSlots::
- kPromiseAnyRejectElementErrorsSlot) = errors;
+ *errorsRef = errors;
}
errors.objects[index] = value;
@@ -155,6 +153,10 @@ PromiseAnyRejectElementClosure(
// b. Set error.[[AggregateErrors]] to errors.
const error = ConstructAggregateError(errors);
+
+ // After this point, errors escapes to user code. Clear the slot.
+ *errorsRef = kEmptyFixedArray;
+
// c. Return ? Call(promiseCapability.[[Reject]], undefined, « error »).
const capability = *ContextSlot(
context,

View File

@@ -0,0 +1,126 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shu-yu Guo <syg@chromium.org>
Date: Wed, 2 Aug 2023 17:41:03 -0700
Subject: Merged: [builtins] Clear FixedArray slot in Promise builtins
Fixed: chromium:1468943
(cherry picked from commit a84849ed718932b94dc877bb44a2d38eb8a0aef9)
Change-Id: Ia2b181c373c15bd1840e2a1572c0e930cddcd788
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4753495
Commit-Queue: Adam Klein <adamk@chromium.org>
Reviewed-by: Adam Klein <adamk@chromium.org>
Auto-Submit: Shu-yu Guo <syg@chromium.org>
Cr-Commit-Position: refs/branch-heads/11.6@{#28}
Cr-Branched-From: e29c028f391389a7a60ee37097e3ca9e396d6fa4-refs/heads/11.6.189@{#3}
Cr-Branched-From: 95cbef20e2aa556a1ea75431a48b36c4de6b9934-refs/heads/main@{#88340}
diff --git a/src/builtins/promise-all-element-closure.tq b/src/builtins/promise-all-element-closure.tq
index db3fb0134cf5bf0065174153171ef44a726a6fff..036e3c7b7473eae98f39a6da4472e826420086c8 100644
--- a/src/builtins/promise-all-element-closure.tq
+++ b/src/builtins/promise-all-element-closure.tq
@@ -175,11 +175,22 @@ transitioning macro PromiseAllResolveElementClosure<F: type>(
*NativeContextSlot(
nativeContext, ContextSlot::JS_ARRAY_PACKED_ELEMENTS_MAP_INDEX);
- // If resolve and reject handlers close over values to keep track of whether
- // an input promise is already settled, mark the values array as COW before
- // letting it escape to user code.
- if (hasResolveAndRejectClosures) MakeFixedArrayCOW(values);
-
+ // After this point, values escapes to user code.
+ //
+ // If resolve and reject handlers close over values to keep track of
+ // whether an input promise is already settled, mark the values array as
+ // COW. The original values array is still needed to guard against resolve
+ // or reject being called multiple times for an element.
+ //
+ // Otherwise, clear the slot.
+ if (hasResolveAndRejectClosures) {
+ MakeFixedArrayCOW(values);
+ } else {
+ *ContextSlot(
+ promiseContext,
+ PromiseAllResolveElementContextSlots::
+ kPromiseAllResolveElementValuesSlot) = kEmptyFixedArray;
+ }
const valuesArray = NewJSArray(arrayMap, values);
Call(promiseContext, resolve, Undefined, valuesArray);
}
diff --git a/src/builtins/promise-all.tq b/src/builtins/promise-all.tq
index 4d131abb44b7593d3e361d1d2f971380ee91850c..7205279526fa9edd93f154feb9694c22cae68606 100644
--- a/src/builtins/promise-all.tq
+++ b/src/builtins/promise-all.tq
@@ -278,15 +278,16 @@ Reject(JSAny) {
check(remainingElementsCount >= 0);
+ const valuesRef:&FixedArray = ContextSlot(
+ resolveElementContext,
+ PromiseAllResolveElementContextSlots::
+ kPromiseAllResolveElementValuesSlot);
+ const values = *valuesRef;
+
if (remainingElementsCount > 0) {
// Pre-allocate the backing store for the {values} to the desired
// capacity. We may already have elements in "values" - this happens
// when the Thenable calls the resolve callback immediately.
- const valuesRef:&FixedArray = ContextSlot(
- resolveElementContext,
- PromiseAllResolveElementContextSlots::
- kPromiseAllResolveElementValuesSlot);
- const values = *valuesRef;
// 'index' is a 1-based index and incremented after every Promise. Later we
// use 'values' as a 0-based array, so capacity 'index - 1' is enough.
const newCapacity = SmiUntag(index) - 1;
@@ -301,19 +302,23 @@ Reject(JSAny) {
// Let valuesArray be CreateArrayFromList(values).
// Perform ? Call(resultCapability.[[Resolve]], undefined,
// « valuesArray »).
-
- const values: FixedArray = *ContextSlot(
- resolveElementContext,
- PromiseAllResolveElementContextSlots::
- kPromiseAllResolveElementValuesSlot);
const arrayMap =
*NativeContextSlot(
nativeContext, ContextSlot::JS_ARRAY_PACKED_ELEMENTS_MAP_INDEX);
+ // After this point, values escapes to user code.
+ //
// If resolve and reject handlers close over values to keep track of
// whether an input promise is already settled, mark the values array as
- // COW before letting it escape to user code.
- if (hasResolveAndRejectClosures) MakeFixedArrayCOW(values);
+ // COW. The original values array is still needed to guard against resolve
+ // or reject being called multiple times for an element.
+ //
+ // Otherwise, clear the slot.
+ if (hasResolveAndRejectClosures) {
+ MakeFixedArrayCOW(values);
+ } else {
+ *valuesRef = kEmptyFixedArray;
+ }
const valuesArray = NewJSArray(arrayMap, values);
Call(nativeContext, UnsafeCast<JSAny>(resolve), Undefined, valuesArray);
diff --git a/src/builtins/promise-any.tq b/src/builtins/promise-any.tq
index 7e707e649f11bc946a6d1173180d7293fe94d8ce..45bafac0e6b09143b69b21a7292f9ed6b9c46239 100644
--- a/src/builtins/promise-any.tq
+++ b/src/builtins/promise-any.tq
@@ -313,10 +313,14 @@ Reject(JSAny) {
// We may already have elements in "errors" - this happens when the
// Thenable calls the reject callback immediately.
- const errors: FixedArray = *ContextSlot(
+ const errorsRef:&FixedArray = ContextSlot(
rejectElementContext,
PromiseAnyRejectElementContextSlots::
kPromiseAnyRejectElementErrorsSlot);
+ const errors: FixedArray = *errorsRef;
+
+ // After this point, errors escapes to user code. Clear the slot.
+ *errorsRef = kEmptyFixedArray;
check(errors.length == index - 1);
const error = ConstructAggregateError(errors);

View File

@@ -0,0 +1,31 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Tobias Tebbi <tebbi@chromium.org>
Date: Tue, 13 Jun 2023 11:50:11 +0200
Subject: Merged: [compiler] check for read-only property on
AccessMode::kDefine
(cherry picked from commit 95eda07ddbc1839e39b3d1ff5db329c0ceb6dfaa)
Change-Id: Ic5799a32e7c312e41cd0a7e1e6073a235414d56f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4665588
Auto-Submit: Tobias Tebbi <tebbi@chromium.org>
Reviewed-by: Darius Mercadier <dmercadier@chromium.org>
Commit-Queue: Darius Mercadier <dmercadier@chromium.org>
Cr-Commit-Position: refs/branch-heads/11.4@{#53}
Cr-Branched-From: 8a8a1e7086dacc426965d3875914efa66663c431-refs/heads/11.4.183@{#1}
Cr-Branched-From: 5483d8e816e0bbce865cbbc3fa0ab357e6330bab-refs/heads/main@{#87241}
diff --git a/src/compiler/access-info.cc b/src/compiler/access-info.cc
index 7c35df243af97d0fe7ae5b25bd31b01afe1d1e6b..b464581f27535207493c6854b4447bab4cbb3a5f 100644
--- a/src/compiler/access-info.cc
+++ b/src/compiler/access-info.cc
@@ -758,8 +758,7 @@ PropertyAccessInfo AccessInfoFactory::ComputePropertyAccessInfo(
}
if (index.is_found()) {
- if (access_mode == AccessMode::kStore ||
- access_mode == AccessMode::kStoreInLiteral) {
+ if (IsAnyStore(access_mode)) {
DCHECK(!map.is_dictionary_map());
// Don't bother optimizing stores to read-only properties.

View File

@@ -0,0 +1,51 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Samuel=20Gro=C3=9F?= <saelo@chromium.org>
Date: Thu, 17 Aug 2023 09:10:19 +0000
Subject: Merged: Squashed multiple commits.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Merged: [runtime] Recreate enum cache on map update
Revision: 1c623f9ff6e077be1c66f155485ea4005ddb6574
Merged: [runtime] Don't try to create empty enum cache.
Revision: 5516e06237c9f0013121f47319e8c253c896d52d
BUG=chromium:1470668,chromium:1472317
R=tebbi@chromium.org
Change-Id: I31d5491aba663661ba68bb55631747a195ed084e
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4788990
Commit-Queue: Samuel Groß <saelo@chromium.org>
Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/branch-heads/11.6@{#32}
Cr-Branched-From: e29c028f391389a7a60ee37097e3ca9e396d6fa4-refs/heads/11.6.189@{#3}
Cr-Branched-From: 95cbef20e2aa556a1ea75431a48b36c4de6b9934-refs/heads/main@{#88340}
diff --git a/src/objects/map-updater.cc b/src/objects/map-updater.cc
index be6568aac4730d08601e883b80092bbd6ee8081a..2ebfc84d3e326abf2602a1af8309024a46cb9c9d 100644
--- a/src/objects/map-updater.cc
+++ b/src/objects/map-updater.cc
@@ -11,6 +11,7 @@
#include "src/execution/isolate.h"
#include "src/handles/handles.h"
#include "src/objects/field-type.h"
+#include "src/objects/keys.h"
#include "src/objects/objects-inl.h"
#include "src/objects/objects.h"
#include "src/objects/property-details.h"
@@ -1035,6 +1036,13 @@ MapUpdater::State MapUpdater::ConstructNewMap() {
// the new descriptors to maintain descriptors sharing invariant.
split_map->ReplaceDescriptors(isolate_, *new_descriptors);
+ // If the old descriptors had an enum cache, make sure the new ones do too.
+ if (old_descriptors_->enum_cache().keys().length() > 0 &&
+ new_map->NumberOfEnumerableProperties() > 0) {
+ FastKeyAccumulator::InitializeFastPropertyEnumCache(
+ isolate_, new_map, new_map->NumberOfEnumerableProperties());
+ }
+
if (has_integrity_level_transition_) {
target_map_ = new_map;
state_ = kAtIntegrityLevelSource;

View File

@@ -0,0 +1,105 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shu-yu Guo <syg@chromium.org>
Date: Thu, 27 Oct 2022 18:02:55 -0700
Subject: Mark values array as COW
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Bug: chromium:1377790
Change-Id: I36bb9e35ca7ecaaa7ed4605f1a19293bc662f341
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3988925
Auto-Submit: Shu-yu Guo <syg@chromium.org>
Reviewed-by: Marja Hölttä <marja@chromium.org>
Commit-Queue: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/main@{#83969}
diff --git a/src/builtins/promise-all-element-closure.tq b/src/builtins/promise-all-element-closure.tq
index 24b9cfb346e022a0ad80f7712b249d1c38ae562d..db3fb0134cf5bf0065174153171ef44a726a6fff 100644
--- a/src/builtins/promise-all-element-closure.tq
+++ b/src/builtins/promise-all-element-closure.tq
@@ -174,6 +174,12 @@ transitioning macro PromiseAllResolveElementClosure<F: type>(
const arrayMap =
*NativeContextSlot(
nativeContext, ContextSlot::JS_ARRAY_PACKED_ELEMENTS_MAP_INDEX);
+
+ // If resolve and reject handlers close over values to keep track of whether
+ // an input promise is already settled, mark the values array as COW before
+ // letting it escape to user code.
+ if (hasResolveAndRejectClosures) MakeFixedArrayCOW(values);
+
const valuesArray = NewJSArray(arrayMap, values);
Call(promiseContext, resolve, Undefined, valuesArray);
}
diff --git a/src/builtins/promise-all.tq b/src/builtins/promise-all.tq
index 29c468ed3eb34f9f348f115b8b6a77174e708bcc..4d131abb44b7593d3e361d1d2f971380ee91850c 100644
--- a/src/builtins/promise-all.tq
+++ b/src/builtins/promise-all.tq
@@ -138,7 +138,8 @@ transitioning macro PerformPromiseAll<F1: type, F2: type>(
nativeContext: NativeContext, iter: iterator::IteratorRecord,
constructor: Constructor, capability: PromiseCapability,
promiseResolveFunction: JSAny, createResolveElementFunctor: F1,
- createRejectElementFunctor: F2): JSAny labels
+ createRejectElementFunctor: F2,
+ hasResolveAndRejectClosures: constexpr bool): JSAny labels
Reject(JSAny) {
const promise = capability.promise;
const resolve = capability.resolve;
@@ -308,6 +309,12 @@ Reject(JSAny) {
const arrayMap =
*NativeContextSlot(
nativeContext, ContextSlot::JS_ARRAY_PACKED_ELEMENTS_MAP_INDEX);
+
+ // If resolve and reject handlers close over values to keep track of
+ // whether an input promise is already settled, mark the values array as
+ // COW before letting it escape to user code.
+ if (hasResolveAndRejectClosures) MakeFixedArrayCOW(values);
+
const valuesArray = NewJSArray(arrayMap, values);
Call(nativeContext, UnsafeCast<JSAny>(resolve), Undefined, valuesArray);
}
@@ -319,7 +326,8 @@ Reject(JSAny) {
transitioning macro GeneratePromiseAll<F1: type, F2: type>(
implicit context: Context)(
receiver: JSAny, iterable: JSAny, createResolveElementFunctor: F1,
- createRejectElementFunctor: F2, message: constexpr string): JSAny {
+ createRejectElementFunctor: F2, message: constexpr string,
+ hasResolveAndRejectClosures: constexpr bool): JSAny {
const nativeContext = LoadNativeContext(context);
// Let C be the this value.
// If Type(C) is not Object, throw a TypeError exception.
@@ -352,7 +360,8 @@ transitioning macro GeneratePromiseAll<F1: type, F2: type>(
// IfAbruptRejectPromise(result, promiseCapability).
return PerformPromiseAll(
nativeContext, i, constructor, capability, promiseResolveFunction,
- createResolveElementFunctor, createRejectElementFunctor)
+ createResolveElementFunctor, createRejectElementFunctor,
+ hasResolveAndRejectClosures)
otherwise Reject;
} catch (e, _message) deferred {
goto Reject(e);
@@ -368,7 +377,7 @@ transitioning javascript builtin PromiseAll(
js-implicit context: Context, receiver: JSAny)(iterable: JSAny): JSAny {
return GeneratePromiseAll(
receiver, iterable, PromiseAllResolveElementFunctor{},
- PromiseAllRejectElementFunctor{}, 'Promise.all');
+ PromiseAllRejectElementFunctor{}, 'Promise.all', false);
}
// ES#sec-promise.allsettled
@@ -377,7 +386,7 @@ transitioning javascript builtin PromiseAllSettled(
js-implicit context: Context, receiver: JSAny)(iterable: JSAny): JSAny {
return GeneratePromiseAll(
receiver, iterable, PromiseAllSettledResolveElementFunctor{},
- PromiseAllSettledRejectElementFunctor{}, 'Promise.allSettled');
+ PromiseAllSettledRejectElementFunctor{}, 'Promise.allSettled', true);
}
extern macro PromiseAllResolveElementSharedFunConstant(): SharedFunctionInfo;
@@ -385,4 +394,6 @@ extern macro PromiseAllSettledRejectElementSharedFunConstant():
SharedFunctionInfo;
extern macro PromiseAllSettledResolveElementSharedFunConstant():
SharedFunctionInfo;
+
+extern macro MakeFixedArrayCOW(FixedArray): void;
}

View File

@@ -0,0 +1,359 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shu-yu Guo <syg@chromium.org>
Date: Thu, 3 Nov 2022 08:48:39 -0700
Subject: Fix for-in enumeration
for-in enumeration creates an EnumCache, which is currently incorrectly
allocated in the per-thread heap. This CL preallocates the enum cache at
SharedStructType-creation time.
Also drive-by fixes typos in the enum cache code.
Bug: v8:12547, chromium:1379616
Change-Id: I1930f88844eca5ccfeebd8dfdcce4ad0bd80ee38
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3997701
Commit-Queue: Shu-yu Guo <syg@chromium.org>
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/main@{#84047}
diff --git a/src/builtins/builtins-struct.cc b/src/builtins/builtins-struct.cc
index a0d75e72086592283070d8014cd043ef3bab1ff5..e0b3831cdc69c1c0acb2ec24925adc310303856e 100644
--- a/src/builtins/builtins-struct.cc
+++ b/src/builtins/builtins-struct.cc
@@ -94,6 +94,16 @@ BUILTIN(SharedStructTypeConstructor) {
// to it.
instance_map->set_constructor_or_back_pointer(*factory->null_value());
+ // Pre-create the enum cache in the shared space, as otherwise for-in
+ // enumeration will incorrectly create an enum cache in the per-thread heap.
+ if (num_properties == 0) {
+ instance_map->SetEnumLength(0);
+ } else {
+ FastKeyAccumulator::InitializeFastPropertyEnumCache(
+ isolate, instance_map, num_properties, AllocationType::kSharedOld);
+ DCHECK_EQ(num_properties, instance_map->EnumLength());
+ }
+
return *constructor;
}
diff --git a/src/heap/factory.cc b/src/heap/factory.cc
index bcb2f6475ec357cb34f923c51e279641c644957d..d1285ab16f4113acd5cdee154f7b1ef133fd8e14 100644
--- a/src/heap/factory.cc
+++ b/src/heap/factory.cc
@@ -415,9 +415,13 @@ Handle<PrototypeInfo> Factory::NewPrototypeInfo() {
}
Handle<EnumCache> Factory::NewEnumCache(Handle<FixedArray> keys,
- Handle<FixedArray> indices) {
- auto result =
- NewStructInternal<EnumCache>(ENUM_CACHE_TYPE, AllocationType::kOld);
+ Handle<FixedArray> indices,
+ AllocationType allocation) {
+ DCHECK(allocation == AllocationType::kOld ||
+ allocation == AllocationType::kSharedOld);
+ DCHECK_EQ(allocation == AllocationType::kSharedOld,
+ keys->InSharedHeap() && indices->InSharedHeap());
+ auto result = NewStructInternal<EnumCache>(ENUM_CACHE_TYPE, allocation);
DisallowGarbageCollection no_gc;
result.set_keys(*keys);
result.set_indices(*indices);
diff --git a/src/heap/factory.h b/src/heap/factory.h
index 6c9cc2d4d8ed1e9c7e14ccb35f6ad61dfa850cfa..748a3f91c881d8bdc723a4f21fcb6adfe6d3876e 100644
--- a/src/heap/factory.h
+++ b/src/heap/factory.h
@@ -183,8 +183,9 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
Handle<PrototypeInfo> NewPrototypeInfo();
// Create a new EnumCache struct.
- Handle<EnumCache> NewEnumCache(Handle<FixedArray> keys,
- Handle<FixedArray> indices);
+ Handle<EnumCache> NewEnumCache(
+ Handle<FixedArray> keys, Handle<FixedArray> indices,
+ AllocationType allocation = AllocationType::kOld);
// Create a new Tuple2 struct.
Handle<Tuple2> NewTuple2(Handle<Object> value1, Handle<Object> value2,
diff --git a/src/objects/descriptor-array.h b/src/objects/descriptor-array.h
index 5db091cbfe166a683f3c43273aece6d3d802d448..178e6d03af4be4512fc40257365437482be654eb 100644
--- a/src/objects/descriptor-array.h
+++ b/src/objects/descriptor-array.h
@@ -65,10 +65,10 @@ class DescriptorArray
void ClearEnumCache();
inline void CopyEnumCacheFrom(DescriptorArray array);
- static void InitializeOrChangeEnumCache(Handle<DescriptorArray> descriptors,
- Isolate* isolate,
- Handle<FixedArray> keys,
- Handle<FixedArray> indices);
+ static void InitializeOrChangeEnumCache(
+ Handle<DescriptorArray> descriptors, Isolate* isolate,
+ Handle<FixedArray> keys, Handle<FixedArray> indices,
+ AllocationType allocation_if_initialize);
// Accessors for fetching instance descriptor at descriptor number.
inline Name GetKey(InternalIndex descriptor_number) const;
diff --git a/src/objects/keys.cc b/src/objects/keys.cc
index ac21fbf9c3d2d22bbd7049a620849e25d1257b4d..a0796864f1ecc6f1f32ca50635b9cb55cd04d7db 100644
--- a/src/objects/keys.cc
+++ b/src/objects/keys.cc
@@ -312,7 +312,7 @@ void TrySettingEmptyEnumCache(JSReceiver object) {
map.SetEnumLength(0);
}
-bool CheckAndInitalizeEmptyEnumCache(JSReceiver object) {
+bool CheckAndInitializeEmptyEnumCache(JSReceiver object) {
if (object.map().EnumLength() == kInvalidEnumCacheSentinel) {
TrySettingEmptyEnumCache(object);
}
@@ -342,7 +342,7 @@ void FastKeyAccumulator::Prepare() {
only_own_has_simple_elements_ = false;
}
}
- bool has_no_properties = CheckAndInitalizeEmptyEnumCache(current);
+ bool has_no_properties = CheckAndInitializeEmptyEnumCache(current);
if (has_no_properties) continue;
last_prototype = current;
has_empty_prototype_ = false;
@@ -368,7 +368,7 @@ Handle<FixedArray> ReduceFixedArrayTo(Isolate* isolate,
return isolate->factory()->CopyFixedArrayUpTo(array, length);
}
-// Initializes and directly returns the enume cache. Users of this function
+// Initializes and directly returns the enum cache. Users of this function
// have to make sure to never directly leak the enum cache.
Handle<FixedArray> GetFastEnumPropertyKeys(Isolate* isolate,
Handle<JSObject> object) {
@@ -398,51 +398,8 @@ Handle<FixedArray> GetFastEnumPropertyKeys(Isolate* isolate,
return ReduceFixedArrayTo(isolate, keys, enum_length);
}
- Handle<DescriptorArray> descriptors =
- Handle<DescriptorArray>(map->instance_descriptors(isolate), isolate);
- isolate->counters()->enum_cache_misses()->Increment();
-
- // Create the keys array.
- int index = 0;
- bool fields_only = true;
- keys = isolate->factory()->NewFixedArray(enum_length);
- for (InternalIndex i : map->IterateOwnDescriptors()) {
- DisallowGarbageCollection no_gc;
- PropertyDetails details = descriptors->GetDetails(i);
- if (details.IsDontEnum()) continue;
- Object key = descriptors->GetKey(i);
- if (key.IsSymbol()) continue;
- keys->set(index, key);
- if (details.location() != PropertyLocation::kField) fields_only = false;
- index++;
- }
- DCHECK_EQ(index, keys->length());
-
- // Optionally also create the indices array.
- Handle<FixedArray> indices = isolate->factory()->empty_fixed_array();
- if (fields_only) {
- indices = isolate->factory()->NewFixedArray(enum_length);
- index = 0;
- for (InternalIndex i : map->IterateOwnDescriptors()) {
- DisallowGarbageCollection no_gc;
- PropertyDetails details = descriptors->GetDetails(i);
- if (details.IsDontEnum()) continue;
- Object key = descriptors->GetKey(i);
- if (key.IsSymbol()) continue;
- DCHECK_EQ(PropertyKind::kData, details.kind());
- DCHECK_EQ(PropertyLocation::kField, details.location());
- FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
- indices->set(index, Smi::FromInt(field_index.GetLoadByFieldIndex()));
- index++;
- }
- DCHECK_EQ(index, indices->length());
- }
-
- DescriptorArray::InitializeOrChangeEnumCache(descriptors, isolate, keys,
- indices);
- if (map->OnlyHasSimpleProperties()) map->SetEnumLength(enum_length);
-
- return keys;
+ return FastKeyAccumulator::InitializeFastPropertyEnumCache(isolate, map,
+ enum_length);
}
template <bool fast_properties>
@@ -451,7 +408,6 @@ MaybeHandle<FixedArray> GetOwnKeysWithElements(Isolate* isolate,
GetKeysConversion convert,
bool skip_indices) {
Handle<FixedArray> keys;
- ElementsAccessor* accessor = object->GetElementsAccessor();
if (fast_properties) {
keys = GetFastEnumPropertyKeys(isolate, object);
} else {
@@ -463,6 +419,7 @@ MaybeHandle<FixedArray> GetOwnKeysWithElements(Isolate* isolate,
if (skip_indices) {
result = keys;
} else {
+ ElementsAccessor* accessor = object->GetElementsAccessor(isolate);
result = accessor->PrependElementIndices(isolate, object, keys, convert,
ONLY_ENUMERABLE);
}
@@ -518,7 +475,7 @@ MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysFast(
if (enum_length == kInvalidEnumCacheSentinel) {
Handle<FixedArray> keys;
// Try initializing the enum cache and return own properties.
- if (GetOwnKeysWithUninitializedEnumCache().ToHandle(&keys)) {
+ if (GetOwnKeysWithUninitializedEnumLength().ToHandle(&keys)) {
if (v8_flags.trace_for_in_enumerate) {
PrintF("| strings=%d symbols=0 elements=0 || prototypes>=1 ||\n",
keys->length());
@@ -534,10 +491,70 @@ MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysFast(
skip_indices_);
}
+// static
+Handle<FixedArray> FastKeyAccumulator::InitializeFastPropertyEnumCache(
+ Isolate* isolate, Handle<Map> map, int enum_length,
+ AllocationType allocation) {
+ DCHECK_EQ(kInvalidEnumCacheSentinel, map->EnumLength());
+ DCHECK_GT(enum_length, 0);
+ DCHECK_EQ(enum_length, map->NumberOfEnumerableProperties());
+ DCHECK(!map->is_dictionary_map());
+
+ Handle<DescriptorArray> descriptors =
+ Handle<DescriptorArray>(map->instance_descriptors(isolate), isolate);
+
+ // The enum cache should have been a hit if the number of enumerable
+ // properties is fewer than what's already in the cache.
+ DCHECK_LT(descriptors->enum_cache().keys().length(), enum_length);
+ isolate->counters()->enum_cache_misses()->Increment();
+
+ // Create the keys array.
+ int index = 0;
+ bool fields_only = true;
+ Handle<FixedArray> keys =
+ isolate->factory()->NewFixedArray(enum_length, allocation);
+ for (InternalIndex i : map->IterateOwnDescriptors()) {
+ DisallowGarbageCollection no_gc;
+ PropertyDetails details = descriptors->GetDetails(i);
+ if (details.IsDontEnum()) continue;
+ Object key = descriptors->GetKey(i);
+ if (key.IsSymbol()) continue;
+ keys->set(index, key);
+ if (details.location() != PropertyLocation::kField) fields_only = false;
+ index++;
+ }
+ DCHECK_EQ(index, keys->length());
+
+ // Optionally also create the indices array.
+ Handle<FixedArray> indices = isolate->factory()->empty_fixed_array();
+ if (fields_only) {
+ indices = isolate->factory()->NewFixedArray(enum_length, allocation);
+ index = 0;
+ for (InternalIndex i : map->IterateOwnDescriptors()) {
+ DisallowGarbageCollection no_gc;
+ PropertyDetails details = descriptors->GetDetails(i);
+ if (details.IsDontEnum()) continue;
+ Object key = descriptors->GetKey(i);
+ if (key.IsSymbol()) continue;
+ DCHECK_EQ(PropertyKind::kData, details.kind());
+ DCHECK_EQ(PropertyLocation::kField, details.location());
+ FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
+ indices->set(index, Smi::FromInt(field_index.GetLoadByFieldIndex()));
+ index++;
+ }
+ DCHECK_EQ(index, indices->length());
+ }
+
+ DescriptorArray::InitializeOrChangeEnumCache(descriptors, isolate, keys,
+ indices, allocation);
+ if (map->OnlyHasSimpleProperties()) map->SetEnumLength(enum_length);
+ return keys;
+}
+
MaybeHandle<FixedArray>
-FastKeyAccumulator::GetOwnKeysWithUninitializedEnumCache() {
+FastKeyAccumulator::GetOwnKeysWithUninitializedEnumLength() {
Handle<JSObject> object = Handle<JSObject>::cast(receiver_);
- // Uninitalized enum cache
+ // Uninitialized enum length
Map map = object->map();
if (object->elements() != ReadOnlyRoots(isolate_).empty_fixed_array() &&
object->elements() !=
diff --git a/src/objects/keys.h b/src/objects/keys.h
index 4497f1211a42fc6dafc906ea9076f7c44995ac4a..031c407620b6af91ef4eb4453f1415c2a608211b 100644
--- a/src/objects/keys.h
+++ b/src/objects/keys.h
@@ -174,7 +174,7 @@ class KeyAccumulator final {
};
// The FastKeyAccumulator handles the cases where there are no elements on the
-// prototype chain and forwords the complex/slow cases to the normal
+// prototype chain and forwards the complex/slow cases to the normal
// KeyAccumulator. This significantly speeds up the cases where the OWN_ONLY
// case where we do not have to walk the prototype chain.
class FastKeyAccumulator {
@@ -200,6 +200,19 @@ class FastKeyAccumulator {
MaybeHandle<FixedArray> GetKeys(
GetKeysConversion convert = GetKeysConversion::kKeepNumbers);
+ // Initialize the the enum cache for a map with all of the following:
+ // - uninitialized enum length
+ // - fast properties (i.e. !is_dictionary_map())
+ // - has >0 enumerable own properties
+ //
+ // The number of enumerable properties is passed in as an optimization, for
+ // when the caller has already computed it.
+ //
+ // Returns the keys.
+ static Handle<FixedArray> InitializeFastPropertyEnumCache(
+ Isolate* isolate, Handle<Map> map, int enum_length,
+ AllocationType allocation = AllocationType::kOld);
+
private:
void Prepare();
MaybeHandle<FixedArray> GetKeysFast(GetKeysConversion convert);
@@ -207,7 +220,7 @@ class FastKeyAccumulator {
MaybeHandle<FixedArray> GetKeysWithPrototypeInfoCache(
GetKeysConversion convert);
- MaybeHandle<FixedArray> GetOwnKeysWithUninitializedEnumCache();
+ MaybeHandle<FixedArray> GetOwnKeysWithUninitializedEnumLength();
bool MayHaveElements(JSReceiver receiver);
bool TryPrototypeInfoCache(Handle<JSReceiver> receiver);
diff --git a/src/objects/objects.cc b/src/objects/objects.cc
index a7e1833f730e6e5869cd4925cca6dc908859000c..4a90a9ba970bffc78e38cad6e9e7e9053466a138 100644
--- a/src/objects/objects.cc
+++ b/src/objects/objects.cc
@@ -4448,10 +4448,12 @@ void DescriptorArray::Replace(InternalIndex index, Descriptor* descriptor) {
// static
void DescriptorArray::InitializeOrChangeEnumCache(
Handle<DescriptorArray> descriptors, Isolate* isolate,
- Handle<FixedArray> keys, Handle<FixedArray> indices) {
+ Handle<FixedArray> keys, Handle<FixedArray> indices,
+ AllocationType allocation_if_initialize) {
EnumCache enum_cache = descriptors->enum_cache();
if (enum_cache == ReadOnlyRoots(isolate).empty_enum_cache()) {
- enum_cache = *isolate->factory()->NewEnumCache(keys, indices);
+ enum_cache = *isolate->factory()->NewEnumCache(keys, indices,
+ allocation_if_initialize);
descriptors->set_enum_cache(enum_cache);
} else {
enum_cache.set_keys(*keys);
diff --git a/test/mjsunit/shared-memory/shared-struct-surface.js b/test/mjsunit/shared-memory/shared-struct-surface.js
index 55a08ccec2a56ee9c0df5fa9a778fe22d6e7e1fb..301a8a114df16262d3ce1e228f951eb911593116 100644
--- a/test/mjsunit/shared-memory/shared-struct-surface.js
+++ b/test/mjsunit/shared-memory/shared-struct-surface.js
@@ -76,3 +76,15 @@ let S = new SharedStructType(['field']);
assertEquals(1, entries.length);
assertArrayEquals(['field', 42], entries[0]);
})();
+
+(function TestForIn() {
+ let fieldNames = [];
+ for (let i = 0; i < 512; i++) {
+ fieldNames.push('field' + i);
+ }
+ let S2 = new SharedStructType(fieldNames);
+ let s = new S2();
+ let propNames = [];
+ for (let prop in s) propNames.push(prop);
+ assertArrayEquals(propNames, fieldNames);
+})();

View File

@@ -1,6 +1,6 @@
param([string]$gomaDir=$PWD)
$cmdPath = Join-Path -Path $gomaDir -ChildPath "goma_ctl.py"
Start-Process -FilePath cmd -ArgumentList "/C", "python", "$cmdPath", "ensure_start"
$cmdPath = Join-Path -Path $gomaDir -ChildPath "goma_ctl.py"
Start-Process -FilePath cmd -ArgumentList "/C", "python3", "$cmdPath", "ensure_start"
$timedOut = $false; $waitTime = 0; $waitIncrement = 5; $timeout=120;
Do { sleep $waitIncrement; $timedOut = (($waitTime+=$waitIncrement) -gt $timeout); iex "$gomaDir\gomacc.exe port 2" > $null; } Until(($LASTEXITCODE -eq 0) -or $timedOut)
if ($timedOut) {

View File

@@ -1641,13 +1641,6 @@ void WebContents::RenderViewDeleted(content::RenderViewHost* render_view_host) {
void WebContents::PrimaryMainFrameRenderProcessGone(
base::TerminationStatus status) {
auto weak_this = GetWeakPtr();
Emit("crashed", status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED);
// User might destroy WebContents in the crashed event.
if (!weak_this || !web_contents())
return;
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
v8::HandleScope handle_scope(isolate);
gin_helper::Dictionary details = gin_helper::Dictionary::CreateEmpty(isolate);

View File

@@ -150,7 +150,13 @@ void ClientFrameViewLinux::Init(NativeWindowViews* window,
}
gfx::Insets ClientFrameViewLinux::GetBorderDecorationInsets() const {
return frame_provider_->GetFrameThicknessDip();
const auto insets = frame_provider_->GetFrameThicknessDip();
// We shouldn't draw frame decorations for the tiled edges.
// See https://wayland.app/protocols/xdg-shell#xdg_toplevel:enum:state
return gfx::Insets::TLBR(tiled_edges().top ? 0 : insets.top(),
tiled_edges().left ? 0 : insets.left(),
tiled_edges().bottom ? 0 : insets.bottom(),
tiled_edges().right ? 0 : insets.right());
}
gfx::Insets ClientFrameViewLinux::GetInputInsets() const {

View File

@@ -521,6 +521,13 @@ node::Environment* NodeBindings::CreateEnvironment(
electron::fuses::IsOnlyLoadAppFromAsarEnabled()
? app_asar_search_paths
: search_paths));
context->Global()->SetPrivate(
context,
v8::Private::ForApi(
isolate, gin::ConvertToV8(isolate, "appSearchPathsOnlyLoadASAR")
.As<v8::String>()),
gin::ConvertToV8(isolate,
electron::fuses::IsOnlyLoadAppFromAsarEnabled()));
}
base::FilePath resources_path = GetResourcesPath();

View File

@@ -252,6 +252,7 @@ declare namespace NodeJS {
// Additional properties
_firstFileName?: string;
_serviceStartupScript: string;
_getOrCreateArchive?: (path: string) => NodeJS.AsarArchive | null;
helperExecPath: string;
mainModule?: NodeJS.Module | undefined;