diff --git a/.circleci/config/base.yml b/.circleci/config/base.yml index 36bc437ae70d0..ae8213d497386 100644 --- a/.circleci/config/base.yml +++ b/.circleci/config/base.yml @@ -236,6 +236,11 @@ step-depot-tools-get: &step-depot-tools-get name: Get depot tools command: | git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git + cd depot_tools + git fetch --depth 1 origin b7d8efd8bee494f4cfacacc19cf50fc4d4be3900 + git checkout b7d8efd8bee494f4cfacacc19cf50fc4d4be3900 + touch .disable_auto_update + cd .. if [ "`uname`" == "Darwin" ]; then # remove ninjalog_uploader_wrapper.py from autoninja since we don't use it and it causes problems sed -i '' '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja @@ -455,7 +460,7 @@ step-delete-git-directories: &step-delete-git-directories command: | if [ "`uname`" == "Darwin" ]; then cd src - ( find . -type d -name ".git" -not -path "./third_party/angle/*" -not -path "./third_party/dawn/*" ) | xargs rm -rf + ( find . -type d -name ".git" -not -path "./third_party/angle/*" -not -path "./third_party/dawn/*" -not -path "./electron/*" ) | xargs rm -rf fi # On macOS the yarn install command during gclient sync was run on a linux @@ -813,7 +818,7 @@ step-maybe-zip-symbols: &step-maybe-zip-symbols cd src export BUILD_PATH="$PWD/out/Default" ninja -C out/Default electron:licenses - ninja -C out/Default electron:electron_version + ninja -C out/Default electron:electron_version_file DELETE_DSYMS_AFTER_ZIP=1 electron/script/zip-symbols.py -b $BUILD_PATH step-maybe-cross-arch-snapshot: &step-maybe-cross-arch-snapshot @@ -873,12 +878,12 @@ step-touch-sync-done: &step-touch-sync-done step-maybe-restore-src-cache: &step-maybe-restore-src-cache restore_cache: keys: - - v14-src-cache-{{ checksum "src/electron/.depshash" }} + - v16-src-cache-{{ checksum "src/electron/.depshash" }} name: Restoring src cache step-maybe-restore-src-cache-marker: &step-maybe-restore-src-cache-marker restore_cache: keys: - - v14-src-cache-marker-{{ checksum "src/electron/.depshash" }} + - v16-src-cache-marker-{{ checksum "src/electron/.depshash" }} name: Restoring src cache marker # Restore exact or closest git cache based on the hash of DEPS and .circle-sync-done @@ -893,14 +898,6 @@ step-maybe-restore-git-cache: &step-maybe-restore-git-cache - v1-git-cache-{{ checksum "src/electron/.circle-sync-done" }} name: Conditionally restoring git cache -step-restore-out-cache: &step-restore-out-cache - restore_cache: - paths: - - ./src/out/Default - keys: - - v10-out-cache-{{ checksum "src/electron/.depshash" }}-{{ checksum "src/electron/.depshash-target" }} - name: Restoring out cache - step-set-git-cache-path: &step-set-git-cache-path run: name: Set GIT_CACHE_PATH to make gclient to use the cache @@ -918,13 +915,6 @@ step-save-git-cache: &step-save-git-cache key: v1-git-cache-{{ checksum "src/electron/.circle-sync-done" }}-{{ checksum "src/electron/DEPS" }} name: Persisting git cache -step-save-out-cache: &step-save-out-cache - save_cache: - paths: - - ./src/out/Default - key: v10-out-cache-{{ checksum "src/electron/.depshash" }}-{{ checksum "src/electron/.depshash-target" }} - name: Persisting out cache - step-run-electron-only-hooks: &step-run-electron-only-hooks run: name: Run Electron Only Hooks @@ -954,13 +944,16 @@ step-minimize-workspace-size-from-checkout: &step-minimize-workspace-size-from-c rm -rf third_party/electron_node/deps/openssl rm -rf third_party/electron_node/deps/v8 rm -rf chrome/test/data/xr/webvr_info + rm -rf src/third_party/angle/third_party/VK-GL-CTS/src + rm -rf src/third_party/swift-toolchain + rm -rf src/third_party/swiftshader/tests/regres/testlists # Save the src cache based on the deps hash step-save-src-cache: &step-save-src-cache save_cache: paths: - /var/portal - key: v14-src-cache-{{ checksum "/var/portal/src/electron/.depshash" }} + key: v16-src-cache-{{ checksum "/var/portal/src/electron/.depshash" }} name: Persisting src cache step-make-src-cache-marker: &step-make-src-cache-marker run: @@ -970,7 +963,7 @@ step-save-src-cache-marker: &step-save-src-cache-marker save_cache: paths: - .src-cache-marker - key: v14-src-cache-marker-{{ checksum "/var/portal/src/electron/.depshash" }} + key: v16-src-cache-marker-{{ checksum "/var/portal/src/electron/.depshash" }} step-maybe-early-exit-no-doc-change: &step-maybe-early-exit-no-doc-change run: @@ -1294,9 +1287,6 @@ commands: build: type: boolean default: true - use-out-cache: - type: boolean - default: true restore-src-cache: type: boolean default: true @@ -1419,10 +1409,6 @@ commands: - *step-delete-git-directories # Electron app - - when: - condition: << parameters.use-out-cache >> - steps: - - *step-restore-out-cache - *step-gn-gen-default - *step-electron-build - *step-maybe-electron-dist-strip @@ -1465,22 +1451,6 @@ commands: condition: << parameters.build >> steps: - move_and_store_all_artifacts - - run: - name: Remove the big things on macOS, this seems to be better on average - command: | - if [ "`uname`" == "Darwin" ]; then - mkdir -p src/out/Default - cd src/out/Default - find . -type f -size +50M -delete - mkdir -p gen/electron - cd gen/electron - # These files do not seem to like being in a cache, let us remove them - find . -type f -name '*_pkg_info' -delete - fi - - when: - condition: << parameters.use-out-cache >> - steps: - - *step-save-out-cache - *step-maybe-notify-slack-failure @@ -1634,7 +1604,6 @@ jobs: persist: true checkout: false checkout-and-assume-cache: true - use-out-cache: false linux-x64-testing-asan: executor: @@ -1651,7 +1620,6 @@ jobs: - electron-build: persist: true checkout: true - use-out-cache: false build-nonproprietary-ffmpeg: false linux-x64-testing-no-run-as-node: @@ -1668,7 +1636,6 @@ jobs: - electron-build: persist: false checkout: true - use-out-cache: false linux-x64-testing-gn-check: executor: @@ -1719,7 +1686,6 @@ jobs: persist: true checkout: false checkout-and-assume-cache: true - use-out-cache: false linux-arm-publish: executor: @@ -1762,7 +1728,6 @@ jobs: persist: true checkout: false checkout-and-assume-cache: true - use-out-cache: false linux-arm64-testing-gn-check: executor: diff --git a/.github/workflows/electron_woa_testing.yml b/.github/workflows/electron_woa_testing.yml deleted file mode 100644 index 01c2b9a08ca71..0000000000000 --- a/.github/workflows/electron_woa_testing.yml +++ /dev/null @@ -1,178 +0,0 @@ -name: Electron WOA Testing - -on: - push: - branches: '**' - workflow_dispatch: - inputs: - appveyor_job_id: - description: 'Job Id of Appveyor WOA job to test' - type: text - required: true - -jobs: - electron-woa-init: - if: ${{ github.event_name == 'push' && github.repository == 'electron/electron' }} - runs-on: ubuntu-latest - steps: - - name: Dummy step for push event - run: | - echo "This job is a needed initialization step for Electron WOA testing. Another test result will appear once the electron-woa-testing build is done." - - electron-woa-testing: - if: ${{ github.event_name == 'workflow_dispatch' && github.repository == 'electron/electron' }} - runs-on: [self-hosted, woa] - permissions: - checks: write - pull-requests: write - steps: - - uses: LouisBrunner/checks-action@v1.1.1 - with: - token: ${{ secrets.GITHUB_TOKEN }} - name: electron-woa-testing - status: in_progress - details_url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - output: | - {"summary":"Test In Progress","text_description":"See job details here: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"} - - name: Clean Workspace - run: | - Remove-Item * -Recurse -Force - shell: powershell - - name: Checkout - uses: actions/checkout@v3 - with: - path: src\electron - fetch-depth: 0 - - name: Yarn install - run: | - cd src\electron - node script/yarn.js install --frozen-lockfile - - name: Download and extract dist.zip for test - run: | - $localArtifactPath = "$pwd\dist.zip" - $serverArtifactPath = "https://ci.appveyor.com/api/buildjobs/${{ inputs.appveyor_job_id }}/artifacts/dist.zip" - Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer ${{ secrets.APPVEYOR_TOKEN }}" } - & "${env:ProgramFiles(x86)}\7-Zip\7z.exe" x -osrc\out\Default -y $localArtifactPath - shell: powershell - - name: Download and extract native test executables for test - run: | - $localArtifactPath = "src\out\Default\shell_browser_ui_unittests.exe" - $serverArtifactPath = "https://ci.appveyor.com/api/buildjobs/${{ inputs.appveyor_job_id }}/artifacts/shell_browser_ui_unittests.exe" - Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer ${{ secrets.APPVEYOR_TOKEN }}" } - shell: powershell - - name: Download and extract ffmpeg.zip for test - run: | - $localArtifactPath = "$pwd\ffmpeg.zip" - $serverArtifactPath = "https://ci.appveyor.com/api/buildjobs/${{ inputs.appveyor_job_id }}/artifacts/ffmpeg.zip" - Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer ${{ secrets.APPVEYOR_TOKEN }}" } - & "${env:ProgramFiles(x86)}\7-Zip\7z.exe" x -osrc\out\ffmpeg $localArtifactPath - shell: powershell - - name: Download node headers for test - run: | - $localArtifactPath = "src\node_headers.zip" - $serverArtifactPath = "https://ci.appveyor.com/api/buildjobs/${{ inputs.appveyor_job_id }}/artifacts/node_headers.zip" - Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer ${{ secrets.APPVEYOR_TOKEN }}" } - cd src - & "${env:ProgramFiles(x86)}\7-Zip\7z.exe" x -y node_headers.zip - shell: powershell - - name: Download electron.lib for test - run: | - $localArtifactPath = "src\out\Default\electron.lib" - $serverArtifactPath = "https://ci.appveyor.com/api/buildjobs/${{ inputs.appveyor_job_id }}/artifacts/electron.lib" - Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer ${{ secrets.APPVEYOR_TOKEN }}" } - shell: powershell - # Uncomment the following block if pdb files are needed to debug issues - # - name: Download pdb files for detailed stacktraces - # if: ${{ github.event_name == 'workflow_dispatch' }} - # run: | - # try { - # $localArtifactPath = "src\pdb.zip" - # $serverArtifactPath = "https://ci.appveyor.com/api/buildjobs/${{ inputs.appveyor_job_id }}/artifacts/pdb.zip" - # Invoke-RestMethod -Method Get -Uri $serverArtifactPath -OutFile $localArtifactPath -Headers @{ "Authorization" = "Bearer ${{ secrets.APPVEYOR_TOKEN }}" } - # cd src - # & "${env:ProgramFiles(x86)}\7-Zip\7z.exe" x -y pdb.zip - # } catch { - # Write-Host "There was an exception encountered while downloading pdb files:" $_.Exception.Message - # } finally { - # $global:LASTEXITCODE = 0 - # } - # shell: powershell - - name: Setup node headers - run: | - New-Item src\out\Default\gen\node_headers\Release -Type directory - Copy-Item -path src\out\Default\electron.lib -destination src\out\Default\gen\node_headers\Release\node.lib - shell: powershell - - name: Run Electron Main process tests - run: | - cd src - set npm_config_nodedir=%cd%\out\Default\gen\node_headers - set npm_config_arch=arm64 - cd electron - node script/yarn test --runners=main --enable-logging --disable-features=CalculateNativeWinOcclusion - env: - ELECTRON_ENABLE_STACK_DUMPING: true - ELECTRON_OUT_DIR: Default - IGNORE_YARN_INSTALL_ERROR: 1 - ELECTRON_TEST_RESULTS_DIR: junit - MOCHA_MULTI_REPORTERS: 'mocha-junit-reporter, tap' - MOCHA_REPORTER: mocha-multi-reporters - ELECTRON_SKIP_NATIVE_MODULE_TESTS: true - - name: Run Electron Remote based tests - if: ${{ success() || failure() }} - run: | - cd src - set npm_config_nodedir=%cd%\out\Default\gen\node_headers - set npm_config_arch=arm64 - cd electron - node script/yarn test --runners=remote --enable-logging --disable-features=CalculateNativeWinOcclusion - env: - ELECTRON_OUT_DIR: Default - IGNORE_YARN_INSTALL_ERROR: 1 - ELECTRON_TEST_RESULTS_DIR: junit - MOCHA_MULTI_REPORTERS: 'mocha-junit-reporter, tap' - MOCHA_REPORTER: mocha-multi-reporters - ELECTRON_SKIP_NATIVE_MODULE_TESTS: true - - name: Verify ffmpeg - run: | - cd src - echo "Verifying non proprietary ffmpeg" - python electron\script\verify-ffmpeg.py --build-dir out\Default --source-root %cd% --ffmpeg-path out\ffmpeg - shell: cmd - - name: Kill processes left running from last test run - if: ${{ always() }} - run: | - Get-Process | Where Name -Like "electron*" | Stop-Process - Get-Process | Where Name -Like "msedge*" | Stop-Process - shell: powershell - - name: Delete user app data directories - if: ${{ always() }} - run: | - Remove-Item -path $env:APPDATA/Electron* -Recurse -Force -ErrorAction Ignore - shell: powershell - - uses: LouisBrunner/checks-action@v1.1.1 - if: ${{ success() }} - with: - token: ${{ secrets.GITHUB_TOKEN }} - name: electron-woa-testing - conclusion: "${{ job.status }}" - details_url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - output: | - {"summary":"${{ job.status }}","text_description":"See job details here: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"} - - uses: LouisBrunner/checks-action@v1.1.1 - if: ${{ success() }} - with: - token: ${{ secrets.GITHUB_TOKEN }} - name: electron-woa-testing - conclusion: "${{ job.status }}" - details_url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - output: | - {"summary":"Job Succeeded","text_description":"See job details here: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"} - - uses: LouisBrunner/checks-action@v1.1.1 - if: ${{ ! success() }} - with: - token: ${{ secrets.GITHUB_TOKEN }} - name: electron-woa-testing - conclusion: "${{ job.status }}" - details_url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - output: | - {"summary":"Job Failed","text_description":"See job details here: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"} \ No newline at end of file diff --git a/.github/workflows/update_appveyor_image.yml b/.github/workflows/update_appveyor_image.yml new file mode 100644 index 0000000000000..9d84c7d9598d8 --- /dev/null +++ b/.github/workflows/update_appveyor_image.yml @@ -0,0 +1,62 @@ +name: Update AppVeyor Image + +# Run chron daily Mon-Fri +on: + schedule: + - cron: '0 8 * * 1-5' # runs 8:00 every business day (see https://crontab.guru) + +permissions: + contents: write + pull-requests: write + +jobs: + bake-appveyor-image: + name: Bake AppVeyor Image + permissions: + contents: write + pull-requests: write # to create a new PR with updated Appveyor images + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Yarn install + run: | + node script/yarn.js install --frozen-lockfile + - name: Set Repo for Commit + run: git config --global --add safe.directory $GITHUB_WORKSPACE + - name: Check AppVeyor Image + env: + APPVEYOR_TOKEN: ${{ secrets.APPVEYOR_TOKEN }} + run: | + node ./script/prepare-appveyor + if [ -f ./image_version.txt ]; then + echo "APPVEYOR_IMAGE_VERSION="$(cat image_version.txt)"" >> $GITHUB_ENV + rm image_version.txt + fi + - name: (Optionally) Update Appveyor Image + if: ${{ env.APPVEYOR_IMAGE_VERSION }} + uses: mikefarah/yq@v4.27.2 + with: + cmd: yq '.image = "${{ env.APPVEYOR_IMAGE_VERSION }}"' "appveyor.yml" > "appveyor2.yml" + - name: (Optionally) Generate Commit Diff + if: ${{ env.APPVEYOR_IMAGE_VERSION }} + run: | + diff -w -B appveyor.yml appveyor2.yml > appveyor.diff || true + patch -f appveyor.yml < appveyor.diff + rm appveyor2.yml appveyor.diff + - name: (Optionally) Commit and Pull Request + if: ${{ env.APPVEYOR_IMAGE_VERSION }} + uses: peter-evans/create-pull-request@v4 + with: + token: ${{ secrets.ACTIONS_GITHUB_TOKEN }} + commit-message: 'build: update appveyor image to latest version' + committer: GitHub + author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com> + signoff: false + branch: bump-appveyor-image + delete-branch: true + title: 'build: update appveyor image to latest version' + body: | + This PR updates appveyor.yml to the latest baked image, ${{ env.APPVEYOR_IMAGE_VERSION }}. \ No newline at end of file diff --git a/BUILD.gn b/BUILD.gn index 0d1401ea4e5aa..97bb3f283969e 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -107,6 +107,14 @@ branding = read_file("shell/app/BRANDING.json", "json") electron_project_name = branding.project_name electron_product_name = branding.product_name electron_mac_bundle_id = branding.mac_bundle_id +electron_version = exec_script("script/print-version.py", + [], + "trim string", + [ + ".git/packed-refs", + ".git/HEAD", + "script/lib/get-version.js", + ]) if (is_mas_build) { assert(is_mac, @@ -302,12 +310,9 @@ npm_action("electron_version_args") { outputs = [ "$target_gen_dir/electron_version.args" ] - args = rebase_path(outputs) + args = rebase_path(outputs) + [ "$electron_version" ] - inputs = [ - "ELECTRON_VERSION", - "script/generate-version-json.js", - ] + inputs = [ "script/generate-version-json.js" ] } templated_file("electron_version_header") { @@ -319,6 +324,39 @@ templated_file("electron_version_header") { args_files = get_target_outputs(":electron_version_args") } +templated_file("electron_win_rc") { + deps = [ ":electron_version_args" ] + + template = "build/templates/electron_rc.tmpl" + output = "$target_gen_dir/win-resources/electron.rc" + + args_files = get_target_outputs(":electron_version_args") +} + +copy("electron_win_resource_files") { + sources = [ + "shell/browser/resources/win/electron.ico", + "shell/browser/resources/win/resource.h", + ] + outputs = [ "$target_gen_dir/win-resources/{{source_file_part}}" ] +} + +templated_file("electron_version_file") { + deps = [ ":electron_version_args" ] + + template = "build/templates/version_string.tmpl" + output = "$root_build_dir/version" + + args_files = get_target_outputs(":electron_version_args") +} + +group("electron_win32_resources") { + public_deps = [ + ":electron_win_rc", + ":electron_win_resource_files", + ] +} + action("electron_fuses") { script = "build/fuses/build.py" @@ -403,9 +441,6 @@ source_set("electron_lib") { "//media/mojo/mojom", "//net:extras", "//net:net_resources", - "//ppapi/host", - "//ppapi/proxy", - "//ppapi/shared_impl", "//printing/buildflags", "//services/device/public/cpp/geolocation", "//services/device/public/cpp/hid", @@ -616,8 +651,15 @@ source_set("electron_lib") { } if (enable_plugins) { - deps += [ "chromium_src:plugins" ] + deps += [ + "chromium_src:plugins", + "//ppapi/host", + "//ppapi/proxy", + "//ppapi/shared_impl", + ] sources += [ + "shell/renderer/electron_renderer_pepper_host_factory.cc", + "shell/renderer/electron_renderer_pepper_host_factory.h", "shell/renderer/pepper_helper.cc", "shell/renderer/pepper_helper.h", ] @@ -750,7 +792,6 @@ if (is_mac) { electron_helper_name = "$electron_product_name Helper" electron_login_helper_name = "$electron_product_name Login Helper" electron_framework_version = "A" - electron_version = read_file("ELECTRON_VERSION", "trim string") mac_xib_bundle_data("electron_xibs") { sources = [ "shell/common/resources/mac/MainMenu.xib" ] @@ -1184,6 +1225,7 @@ if (is_mac) { ":default_app_asar", ":electron_app_manifest", ":electron_lib", + ":electron_win32_resources", ":packed_resources", "//components/crash/core/app", "//content:sandbox_helper_win", @@ -1217,8 +1259,7 @@ if (is_mac) { if (is_win) { sources += [ - # TODO: we should be generating our .rc files more like how chrome does - "shell/browser/resources/win/electron.rc", + "$target_gen_dir/win-resources/electron.rc", "shell/browser/resources/win/resource.h", ] @@ -1400,15 +1441,10 @@ group("licenses") { ] } -copy("electron_version") { - sources = [ "ELECTRON_VERSION" ] - outputs = [ "$root_build_dir/version" ] -} - dist_zip("electron_dist_zip") { data_deps = [ ":electron_app", - ":electron_version", + ":electron_version_file", ":licenses", ] if (is_linux) { diff --git a/ELECTRON_VERSION b/ELECTRON_VERSION deleted file mode 100644 index 695100c785b3e..0000000000000 --- a/ELECTRON_VERSION +++ /dev/null @@ -1 +0,0 @@ -20.3.0 \ No newline at end of file diff --git a/README.md b/README.md index fcf0ab6216411..7a6df36785430 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ For more installation options and troubleshooting tips, see Each Electron release provides binaries for macOS, Windows, and Linux. -* macOS (El Capitan and up): Electron provides 64-bit Intel and ARM binaries for macOS. Apple Silicon support was added in Electron 11. +* macOS (High Sierra and up): Electron provides 64-bit Intel and ARM binaries for macOS. Apple Silicon support was added in Electron 11. * Windows (Windows 7 and up): Electron provides `ia32` (`x86`), `x64` (`amd64`), and `arm64` binaries for Windows. Windows on ARM support was added in Electron 5.0.8. * Linux: The prebuilt binaries of Electron are built on Ubuntu 20.04. They have also been verified to work on: * Ubuntu 14.04 and newer diff --git a/appveyor-bake.yml b/appveyor-bake.yml new file mode 100644 index 0000000000000..26bfc782a62ac --- /dev/null +++ b/appveyor-bake.yml @@ -0,0 +1,52 @@ +# The config is used to bake appveyor images, not for running CI jobs. +# The config expects the following environment variables to be set: +# - "APPVEYOR_BAKE_IMAGE" e.g. 'electron-99.0.4767.0'. Name of the image to be baked. +# Typically named after the Chromium version on which the image is built. +# This can be set dynamically in the prepare-appveyor script. + +version: 1.0.{build} +build_cloud: electronhq-16-core +image: Windows_Default_Appveyor +environment: + GIT_CACHE_PATH: C:\Users\appveyor\libcc_cache + ELECTRON_OUT_DIR: Default + ELECTRON_ENABLE_STACK_DUMPING: 1 + MOCHA_REPORTER: mocha-multi-reporters + MOCHA_MULTI_REPORTERS: mocha-appveyor-reporter, tap + GOMA_FALLBACK_ON_AUTH_FAILURE: true + DEPOT_TOOLS_WIN_TOOLCHAIN: 0 + PYTHONIOENCODING: UTF-8 +build_script: + - ps: Resize-Partition -DriveLetter C -Size (256GB) # ensure initial partition size + - ps: Get-Partition -DriveLetter C + - git config --global core.longpaths true + - cd .. + - mkdir src + - ps: git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git + - ps: $env:PATH="$pwd\depot_tools;$env:PATH" + - update_depot_tools.bat + - ps: Move-Item $env:APPVEYOR_BUILD_FOLDER -Destination src\electron + - src\electron\script\setup-win-for-dev.bat + - >- + gclient config + --name "src\electron" + --unmanaged + %GCLIENT_EXTRA_ARGS% + "https://github.com/electron/electron" + - ps: cd src\electron + - ps: node script\generate-deps-hash.js + - ps: $depshash = Get-Content .\.depshash -Raw + - ps: Copy-Item -path .\.depshash -destination ..\.depshash + - ps: cd ..\.. + - gclient sync --with_branch_heads --with_tags --nohooks + - ps: regsvr32 /s "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\DIA SDK\bin\amd64\msdia140.dll" +on_image_bake: + - ps: >- + echo "Baking image: $env:APPVEYOR_BAKE_IMAGE at dir $PWD" + - ps: Remove-Item -Recurse -Force $pwd\depot_tools + - ps: Remove-Item -Recurse -Force $pwd\src\electron +# Uncomment these lines to enable RDP +#on_finish: +# - ps: >- +# $env:APPVEYOR_RDP_PASSWORD = "electron" +# $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) \ No newline at end of file diff --git a/appveyor-woa.yml b/appveyor-woa.yml new file mode 100644 index 0000000000000..4b229c62a8364 --- /dev/null +++ b/appveyor-woa.yml @@ -0,0 +1,286 @@ +# NOTE IF CHANGING THIS FILE, ALSO APPLY THE CHANGE TO appveyor.yml +# IF APPLICABLE!!!! +# +# +# The config expects the following environment variables to be set: +# - "GN_CONFIG" Build type. One of {'testing', 'release'}. +# - "GN_EXTRA_ARGS" Additional gn arguments for a build config, +# e.g. 'target_cpu="x86"' to build for a 32bit platform. +# https://gn.googlesource.com/gn/+/master/docs/reference.md#target_cpu +# Don't forget to set up "NPM_CONFIG_ARCH" and "TARGET_ARCH" accordingly +# if you pass a custom value for 'target_cpu'. +# - "ELECTRON_RELEASE" Set it to '1' upload binaries on success. +# - "NPM_CONFIG_ARCH" E.g. 'x86'. Is used to build native Node.js modules. +# Must match 'target_cpu' passed to "GN_EXTRA_ARGS" and "TARGET_ARCH" value. +# - "TARGET_ARCH" Choose from {'ia32', 'x64', 'arm', 'arm64', 'mips64el'}. +# Is used in some publishing scripts, but does NOT affect the Electron binary. +# Must match 'target_cpu' passed to "GN_EXTRA_ARGS" and "NPM_CONFIG_ARCH" value. +# - "UPLOAD_TO_STORAGE" Set it to '1' upload a release to the Azure bucket. +# Otherwise the release will be uploaded to the GitHub Releases. +# (The value is only checked if "ELECTRON_RELEASE" is defined.) +# +# The publishing scripts expect access tokens to be defined as env vars, +# but those are not covered here. +# +# AppVeyor docs on variables: +# https://www.appveyor.com/docs/environment-variables/ +# https://www.appveyor.com/docs/build-configuration/#secure-variables +# https://www.appveyor.com/docs/build-configuration/#custom-environment-variables + +version: 1.0.{build} +build_cloud: electronhq-16-core +image: e-106.0.5249.199 +environment: + GIT_CACHE_PATH: C:\Users\appveyor\libcc_cache + ELECTRON_OUT_DIR: Default + ELECTRON_ENABLE_STACK_DUMPING: 1 + ELECTRON_ALSO_LOG_TO_STDERR: 1 + MOCHA_REPORTER: mocha-multi-reporters + MOCHA_MULTI_REPORTERS: mocha-appveyor-reporter, tap + GOMA_FALLBACK_ON_AUTH_FAILURE: true + DEPOT_TOOLS_WIN_TOOLCHAIN: 0 + PYTHONIOENCODING: UTF-8 + + matrix: + + - job_name: Build Arm on X64 Windows + - job_name: Test On Windows On Arm Hardware + job_depends_on: Build Arm on X64 Windows + APPVEYOR_BUILD_WORKER_IMAGE: base-woa + APPVEYOR_BUILD_WORKER_CLOUD: electronhq-woa + +clone_folder: C:\projects\src\electron + +skip_branch_with_pr: true + +# the first failed job cancels other jobs and fails entire build +matrix: + fast_finish: true + +for: + + - matrix: + only: + - job_name: Build Arm on X64 Windows + + build_script: + - ps: | + node script/yarn.js install --frozen-lockfile + node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER --prBranch=$env:APPVEYOR_REPO_BRANCH + if ($LASTEXITCODE -eq 0) { + Write-warning "Skipping build for doc only change"; Exit-AppveyorBuild + } + $global:LASTEXITCODE = 0 + - cd .. + - ps: Write-Host "Building $env:GN_CONFIG build" + - git config --global core.longpaths true + - ps: >- + if (Test-Path -Path "$pwd\depot_tools") { + Remove-Item -Recurse -Force $pwd\depot_tools + } + - ps: >- + if (Test-Path -Path "$pwd\build-tools") { + Remove-Item -Recurse -Force $pwd\build-tools + } + - ps: | + git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git + cd depot_tools + git fetch --depth 1 origin b7d8efd8bee494f4cfacacc19cf50fc4d4be3900 + git checkout b7d8efd8bee494f4cfacacc19cf50fc4d4be3900 + New-Item -Name .disable_auto_update -ItemType File + bootstrap\win_tools.bat + cd .. + - ps: $env:PATH="$pwd\depot_tools;$env:PATH" + - ps: >- + if (Test-Path -Path "$pwd\src\electron") { + Remove-Item -Recurse -Force $pwd\src\electron + } + - ps: >- + if (Test-Path 'env:RAW_GOMA_AUTH') { + $env:GOMA_OAUTH2_CONFIG_FILE = "$pwd\.goma_oauth2_config" + $env:RAW_GOMA_AUTH | Set-Content $env:GOMA_OAUTH2_CONFIG_FILE + } + - git clone https://github.com/electron/build-tools.git + - cd build-tools + - npm install + - mkdir third_party + - ps: >- + node -e "require('./src/utils/goma.js').downloadAndPrepare({ gomaOneForAll: true })" + - ps: $env:GN_GOMA_FILE = node -e "console.log(require('./src/utils/goma.js').gnFilePath)" + - ps: $env:LOCAL_GOMA_DIR = node -e "console.log(require('./src/utils/goma.js').dir)" + - cd ..\.. + - 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 + if ($goma_login -eq 'Login as Fermi Planck') { + Write-warning "Goma authentication is correct"; + } else { + Write-warning "WARNING!!!!!! Goma authentication is incorrect; please update Goma auth token."; + $host.SetShouldExit(1) + } + } + - ps: $env:CHROMIUM_BUILDTOOLS_PATH="$pwd\src\buildtools" + - ps: >- + if ($env:GN_CONFIG -ne 'release') { + $env:NINJA_STATUS="[%r processes, %f/%t @ %o/s : %es] " + } + - gclient config --name "src\electron" --unmanaged %GCLIENT_EXTRA_ARGS% "https://github.com/electron/electron" + # Patches are applied in the image bake. Check depshash to see if patches have changed. + - ps: $env:RUN_GCLIENT_SYNC="false" + - ps: $depshash_baked = Get-Content .\src\.depshash -Raw + - ps: cd src\electron + - ps: node script\generate-deps-hash.js + - ps: $depshash = Get-Content .\.depshash -Raw + - ps: cd ..\.. + - ps: >- + if ($depshash_baked -ne $depshash) { + $env:RUN_GCLIENT_SYNC="true" + } + - if "%RUN_GCLIENT_SYNC%"=="true" ( gclient sync --with_branch_heads --with_tags ) else ( gclient runhooks ) + - cd src + - ps: $env:PATH="$pwd\third_party\ninja;$env:PATH" + - set BUILD_CONFIG_PATH=//electron/build/args/%GN_CONFIG%.gn + - gn gen out/Default "--args=import(\"%BUILD_CONFIG_PATH%\") import(\"%GN_GOMA_FILE%\") %GN_EXTRA_ARGS% " + - gn check out/Default //electron:electron_lib + - gn check out/Default //electron:electron_app + - gn check out/Default //electron/shell/common/api:mojo + - if DEFINED GN_GOMA_FILE (ninja -j 300 -C out/Default electron:electron_app) else (ninja -C out/Default electron:electron_app) + - if "%GN_CONFIG%"=="testing" ( python C:\depot_tools\post_build_ninja_summary.py -C out\Default ) + - gn gen out/ffmpeg "--args=import(\"//electron/build/args/ffmpeg.gn\") %GN_EXTRA_ARGS%" + - ninja -C out/ffmpeg electron:electron_ffmpeg_zip + - ninja -C out/Default electron:electron_dist_zip + - ninja -C out/Default shell_browser_ui_unittests + - gn desc out/Default v8:run_mksnapshot_default args > out/Default/default_mksnapshot_args + # Remove unused args from mksnapshot_args + - ps: >- + Get-Content out/Default/default_mksnapshot_args | Where-Object { -not $_.Contains('--turbo-profiling-input') -And -not $_.Contains('builtins-pgo') } | Set-Content out/Default/mksnapshot_args + - ninja -C out/Default electron:electron_mksnapshot_zip + - cd out\Default + - 7z a mksnapshot.zip mksnapshot_args gen\v8\embedded.S + - cd ..\.. + - 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 + - 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 + - 7z a node_headers.zip out\Default\gen\node_headers + - ps: >- + if ($env:GN_CONFIG -eq 'release') { + # Needed for msdia140.dll on 64-bit windows + $env:Path += ";$pwd\third_party\llvm-build\Release+Asserts\bin" + ninja -C out/Default electron:electron_symbols + } + - ps: >- + if ($env:GN_CONFIG -eq 'release') { + python3 electron\script\zip-symbols.py + appveyor-retry appveyor PushArtifact out/Default/symbols.zip + } else { + # It's useful to have pdb files when debugging testing builds that are + # built on CI. + 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 + + deploy_script: + - cd electron + - ps: >- + if (Test-Path Env:\ELECTRON_RELEASE) { + if (Test-Path Env:\UPLOAD_TO_STORAGE) { + Write-Output "Uploading Electron release distribution to azure" + & python3 script\release\uploaders\upload.py --verbose --upload_to_storage + } else { + Write-Output "Uploading Electron release distribution to github releases" + & python3 script\release\uploaders\upload.py --verbose + } + } + on_finish: + # Uncomment this lines to enable RDP + # - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) + - cd C:\projects\src + - if exist out\Default\windows_toolchain_profile.json ( appveyor-retry appveyor PushArtifact out\Default\windows_toolchain_profile.json ) + - if exist out\Default\dist.zip (appveyor-retry appveyor PushArtifact out\Default\dist.zip) + - if exist out\Default\shell_browser_ui_unittests.exe (appveyor-retry appveyor PushArtifact out\Default\shell_browser_ui_unittests.exe) + - if exist out\Default\chromedriver.zip (appveyor-retry appveyor PushArtifact out\Default\chromedriver.zip) + - if exist out\ffmpeg\ffmpeg.zip (appveyor-retry appveyor PushArtifact out\ffmpeg\ffmpeg.zip) + - 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) + - ps: >- + if ((Test-Path "pdb.zip") -And ($env:GN_CONFIG -ne 'release')) { + appveyor-retry appveyor PushArtifact pdb.zip + } + - matrix: + only: + - job_name: Test On Windows On Arm Hardware + + environment: + IGNORE_YARN_INSTALL_ERROR: 1 + ELECTRON_TEST_RESULTS_DIR: junit + MOCHA_MULTI_REPORTERS: 'mocha-junit-reporter, tap' + MOCHA_REPORTER: mocha-multi-reporters + ELECTRON_SKIP_NATIVE_MODULE_TESTS: true + + build_script: + - ps: | + node script/yarn.js install --frozen-lockfile + node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER --prBranch=$env:APPVEYOR_REPO_BRANCH + if ($LASTEXITCODE -eq 0) { + Write-warning "Skipping build for doc only change"; Exit-AppveyorBuild + } + $global:LASTEXITCODE = 0 + - cd .. + - mkdir out\Default + - cd .. + - ps: | + # 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') + foreach ($job in $build_info.build.jobs) { + if ($job.name -eq "Build Arm on X64 Windows") { + $jobId = $job.jobId + foreach($artifact_name in $artifacts_to_download) { + if ($artifact_name -eq 'shell_browser_ui_unittests.exe' -Or $artifact_name -eq 'electron.lib') { + $outfile = "src\out\Default\$artifact_name" + } else { + $outfile = $artifact_name + } + Invoke-RestMethod -Method Get -Uri "$apiUrl/buildjobs/$jobId/artifacts/$artifact_name" -OutFile $outfile + } + } + } + - ps: | + $out_default_zips = @('dist.zip','pdb.zip') + foreach($zip_name in $out_default_zips) { + 7z x -y -osrc\out\Default $zip_name + } + - ps: 7z x -y -osrc\out\ffmpeg ffmpeg.zip + - ps: 7z x -y -osrc node_headers.zip + + test_script: + # Workaround for https://github.com/appveyor/ci/issues/2420 + - set "PATH=%PATH%;C:\Program Files\Git\mingw64\libexec\git-core" + - ps: | + cd src + New-Item .\out\Default\gen\node_headers\Release -Type directory + Copy-Item -path .\out\Default\electron.lib -destination .\out\Default\gen\node_headers\Release\node.lib + - set npm_config_nodedir=%cd%\out\Default\gen\node_headers + - set npm_config_arch=arm64 + - cd electron + # Explicitly set npm_config_arch because the .env doesn't persist + - ps: >- + if ($env:TARGET_ARCH -eq 'ia32') { + $env:npm_config_arch = "ia32" + } + - echo Running main test suite & node script/yarn test --runners=main --enable-logging --disable-features=CalculateNativeWinOcclusion + - cd .. + - echo Verifying non proprietary ffmpeg & python electron\script\verify-ffmpeg.py --build-dir out\Default --source-root %cd% --ffmpeg-path out\ffmpeg + + on_finish: + # Uncomment these lines to enable RDP + # - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) + - if exist electron\electron.log ( appveyor-retry appveyor PushArtifact electron\electron.log ) \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index e8e16a345343b..bb3db259f359c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,9 +1,13 @@ +# NOTE IF CHANGING THIS FILE, ALSO APPLY THE CHANGE TO appveyor-woa.yml +# IF APPLICABLE!!!! +# +# # The config expects the following environment variables to be set: # - "GN_CONFIG" Build type. One of {'testing', 'release'}. # - "GN_EXTRA_ARGS" Additional gn arguments for a build config, # e.g. 'target_cpu="x86"' to build for a 32bit platform. # https://gn.googlesource.com/gn/+/master/docs/reference.md#target_cpu -# Don't forget to set up "NPM_CONFIG_ARCH" and "TARGET_ARCH" accordningly +# Don't forget to set up "NPM_CONFIG_ARCH" and "TARGET_ARCH" accordingly # if you pass a custom value for 'target_cpu'. # - "ELECTRON_RELEASE" Set it to '1' upload binaries on success. # - "NPM_CONFIG_ARCH" E.g. 'x86'. Is used to build native Node.js modules. @@ -12,7 +16,7 @@ # Is used in some publishing scripts, but does NOT affect the Electron binary. # Must match 'target_cpu' passed to "GN_EXTRA_ARGS" and "NPM_CONFIG_ARCH" value. # - "UPLOAD_TO_STORAGE" Set it to '1' upload a release to the Azure bucket. -# Otherwise the release will be uploaded to the Github Releases. +# Otherwise the release will be uploaded to the GitHub Releases. # (The value is only checked if "ELECTRON_RELEASE" is defined.) # # The publishing scripts expect access tokens to be defined as env vars, @@ -24,224 +28,258 @@ # https://www.appveyor.com/docs/build-configuration/#custom-environment-variables version: 1.0.{build} -build_cloud: electron-16-core -image: vs2019bt-16.16.11 +build_cloud: electronhq-16-core +image: e-104.0.5112.124-fix environment: - GIT_CACHE_PATH: C:\Users\electron\libcc_cache + GIT_CACHE_PATH: C:\Users\appveyor\libcc_cache ELECTRON_OUT_DIR: Default ELECTRON_ENABLE_STACK_DUMPING: 1 ELECTRON_ALSO_LOG_TO_STDERR: 1 MOCHA_REPORTER: mocha-multi-reporters MOCHA_MULTI_REPORTERS: mocha-appveyor-reporter, tap GOMA_FALLBACK_ON_AUTH_FAILURE: true -build_script: - - ps: >- - if(($env:APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME -split "/")[0] -eq ($env:APPVEYOR_REPO_NAME -split "/")[0]) { - Write-warning "Skipping PR build for branch"; Exit-AppveyorBuild - } else { - node script/yarn.js install --frozen-lockfile + DEPOT_TOOLS_WIN_TOOLCHAIN: 0 + PYTHONIOENCODING: UTF-8 - $result = node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER --prBranch=$env:APPVEYOR_REPO_BRANCH - Write-Output $result - if ($result.ExitCode -eq 0) { - Write-warning "Skipping build for doc only change"; Exit-AppveyorBuild - } - } - - echo "Building $env:GN_CONFIG build" - - git config --global core.longpaths true - - cd .. - - mkdir src - - update_depot_tools.bat - - ps: Move-Item $env:APPVEYOR_BUILD_FOLDER -Destination src\electron - - ps: >- - if (Test-Path 'env:RAW_GOMA_AUTH') { - $env:GOMA_OAUTH2_CONFIG_FILE = "$pwd\.goma_oauth2_config" - $env:RAW_GOMA_AUTH | Set-Content $env:GOMA_OAUTH2_CONFIG_FILE - } - - git clone https://github.com/electron/build-tools.git - - cd build-tools - - npm install - - mkdir third_party - - ps: >- - node -e "require('./src/utils/goma.js').downloadAndPrepare({ gomaOneForAll: true })" - - ps: $env:GN_GOMA_FILE = node -e "console.log(require('./src/utils/goma.js').gnFilePath)" - - ps: $env:LOCAL_GOMA_DIR = node -e "console.log(require('./src/utils/goma.js').dir)" - - cd .. - - 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 - if ($goma_login -eq 'Login as Fermi Planck') { - Write-warning "Goma authentication is correct"; - } else { - Write-warning "WARNING!!!!!! Goma authentication is incorrect; please update Goma auth token."; - $host.SetShouldExit(1) - } - } - - ps: $env:CHROMIUM_BUILDTOOLS_PATH="$pwd\src\buildtools" - - ps: >- - if ($env:GN_CONFIG -ne 'release') { - $env:NINJA_STATUS="[%r processes, %f/%t @ %o/s : %es] " - } - - >- - gclient config - --name "src\electron" - --unmanaged - %GCLIENT_EXTRA_ARGS% - "https://github.com/electron/electron" - - ps: >- - if ($env:GN_CONFIG -eq 'release') { - $env:RUN_GCLIENT_SYNC="true" - } else { - cd src\electron - node script\generate-deps-hash.js - $depshash = Get-Content .\.depshash -Raw - $zipfile = "Z:\$depshash.7z" - cd ..\.. - if (Test-Path -Path $zipfile) { - # file exists, unzip and then gclient sync - 7z x -y $zipfile -mmt=30 -aoa - if (-not (Test-Path -Path "src\buildtools")) { - # the zip file must be corrupt - resync - $env:RUN_GCLIENT_SYNC="true" - if ($env:TARGET_ARCH -ne 'ia32') { - # only save on x64/woa to avoid contention saving - $env:SAVE_GCLIENT_SRC="true" + matrix: + + - job_name: Build + - job_name: Test + job_depends_on: Build + +clone_folder: C:\projects\src\electron + +skip_branch_with_pr: true + +# the first failed job cancels other jobs and fails entire build +matrix: + fast_finish: true + +for: + + - matrix: + only: + - job_name: Build + + build_script: + - ps: | + node script/yarn.js install --frozen-lockfile + node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER --prBranch=$env:APPVEYOR_REPO_BRANCH + if ($LASTEXITCODE -eq 0) { + Write-warning "Skipping build for doc only change"; Exit-AppveyorBuild + } + $global:LASTEXITCODE = 0 + - cd .. + - ps: Write-Host "Building $env:GN_CONFIG build" + - git config --global core.longpaths true + - ps: >- + if (Test-Path -Path "$pwd\depot_tools") { + Remove-Item -Recurse -Force $pwd\depot_tools + } + - ps: >- + if (Test-Path -Path "$pwd\build-tools") { + Remove-Item -Recurse -Force $pwd\build-tools + } + - ps: | + git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git + cd depot_tools + git fetch --depth 1 origin b7d8efd8bee494f4cfacacc19cf50fc4d4be3900 + git checkout b7d8efd8bee494f4cfacacc19cf50fc4d4be3900 + New-Item -Name .disable_auto_update -ItemType File + bootstrap\win_tools.bat + cd .. + - ps: $env:PATH="$pwd\depot_tools;$env:PATH" + - ps: >- + if (Test-Path -Path "$pwd\src\electron") { + Remove-Item -Recurse -Force $pwd\src\electron + } + - ps: >- + if (Test-Path 'env:RAW_GOMA_AUTH') { + $env:GOMA_OAUTH2_CONFIG_FILE = "$pwd\.goma_oauth2_config" + $env:RAW_GOMA_AUTH | Set-Content $env:GOMA_OAUTH2_CONFIG_FILE + } + - git clone https://github.com/electron/build-tools.git + - cd build-tools + - npm install + - mkdir third_party + - ps: >- + node -e "require('./src/utils/goma.js').downloadAndPrepare({ gomaOneForAll: true })" + - ps: $env:GN_GOMA_FILE = node -e "console.log(require('./src/utils/goma.js').gnFilePath)" + - ps: $env:LOCAL_GOMA_DIR = node -e "console.log(require('./src/utils/goma.js').dir)" + - cd ..\.. + - 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 + if ($goma_login -eq 'Login as Fermi Planck') { + Write-warning "Goma authentication is correct"; + } else { + Write-warning "WARNING!!!!!! Goma authentication is incorrect; please update Goma auth token."; + $host.SetShouldExit(1) } + } + - ps: $env:CHROMIUM_BUILDTOOLS_PATH="$pwd\src\buildtools" + - ps: >- + if ($env:GN_CONFIG -ne 'release') { + $env:NINJA_STATUS="[%r processes, %f/%t @ %o/s : %es] " + } + - gclient config --name "src\electron" --unmanaged %GCLIENT_EXTRA_ARGS% "https://github.com/electron/electron" + # Patches are applied in the image bake. Check depshash to see if patches have changed. + - ps: $env:RUN_GCLIENT_SYNC="false" + - ps: $depshash_baked = Get-Content .\src\.depshash -Raw + - ps: cd src\electron + - ps: node script\generate-deps-hash.js + - ps: $depshash = Get-Content .\.depshash -Raw + - ps: cd ..\.. + - ps: >- + if ($depshash_baked -ne $depshash) { + $env:RUN_GCLIENT_SYNC="true" + } + - if "%RUN_GCLIENT_SYNC%"=="true" ( gclient sync --with_branch_heads --with_tags ) else ( gclient runhooks ) + - cd src + - set BUILD_CONFIG_PATH=//electron/build/args/%GN_CONFIG%.gn + - gn gen out/Default "--args=import(\"%BUILD_CONFIG_PATH%\") import(\"%GN_GOMA_FILE%\") %GN_EXTRA_ARGS% " + - gn check out/Default //electron:electron_lib + - gn check out/Default //electron:electron_app + - gn check out/Default //electron/shell/common/api:mojo + - if DEFINED GN_GOMA_FILE (ninja -j 300 -C out/Default electron:electron_app) else (ninja -C out/Default electron:electron_app) + - if "%GN_CONFIG%"=="testing" ( python C:\depot_tools\post_build_ninja_summary.py -C out\Default ) + - gn gen out/ffmpeg "--args=import(\"//electron/build/args/ffmpeg.gn\") %GN_EXTRA_ARGS%" + - ninja -C out/ffmpeg electron:electron_ffmpeg_zip + - ninja -C out/Default electron:electron_dist_zip + - ninja -C out/Default shell_browser_ui_unittests + - gn desc out/Default v8:run_mksnapshot_default args > out/Default/default_mksnapshot_args + # Remove unused args from mksnapshot_args + - ps: >- + Get-Content out/Default/default_mksnapshot_args | Where-Object { -not $_.Contains('--turbo-profiling-input') -And -not $_.Contains('builtins-pgo') } | Set-Content out/Default/mksnapshot_args + - ninja -C out/Default electron:electron_mksnapshot_zip + - cd out\Default + - 7z a mksnapshot.zip mksnapshot_args gen\v8\embedded.S + - cd ..\.. + - 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 + - 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 + - 7z a node_headers.zip out\Default\gen\node_headers + - ps: >- + if ($env:GN_CONFIG -eq 'release') { + # Needed for msdia140.dll on 64-bit windows + $env:Path += ";$pwd\third_party\llvm-build\Release+Asserts\bin" + ninja -C out/Default electron:electron_symbols + } + - ps: >- + if ($env:GN_CONFIG -eq 'release') { + python3 electron\script\zip-symbols.py + appveyor-retry appveyor PushArtifact out/Default/symbols.zip } else { - # update angle - cd src\third_party\angle - git remote set-url origin https://chromium.googlesource.com/angle/angle.git - git fetch - cd ..\..\.. - } - } else { - # file does not exist, gclient sync, then zip - $env:RUN_GCLIENT_SYNC="true" - if ($env:TARGET_ARCH -ne 'ia32') { - # only save on x64/woa to avoid contention saving - $env:SAVE_GCLIENT_SRC="true" - } - } - } - - if "%RUN_GCLIENT_SYNC%"=="true" ( gclient sync ) - - ps: >- - if ($env:SAVE_GCLIENT_SRC -eq 'true') { - # archive current source for future use - # only run on x64/woa to avoid contention saving - $(7z a $zipfile src -xr!android_webview -xr!electron -xr'!*\.git' -xr!third_party\WebKit\LayoutTests! -xr!third_party\blink\web_tests -xr!third_party\blink\perf_tests -slp -t7z -mmt=30) - if ($LASTEXITCODE -ne 0) { - Write-warning "Could not save source to shared drive; continuing anyway" - } - # build time generation of file gen/angle/angle_commit.h depends on - # third_party/angle/.git - # https://chromium-review.googlesource.com/c/angle/angle/+/2074924 - $(7z a $zipfile src\third_party\angle\.git) - if ($LASTEXITCODE -ne 0) { - Write-warning "Failed to add third_party\angle\.git; continuing anyway" - } - # build time generation of file dawn/common/Version_autogen.h depends on third_party/dawn/.git/HEAD - # https://dawn-review.googlesource.com/c/dawn/+/83901 - $(7z a $zipfile src\third_party\dawn\.git) - if ($LASTEXITCODE -ne 0) { - Write-warning "Failed to add third_party\dawn\.git; continuing anyway" - } - } - - cd src - - set BUILD_CONFIG_PATH=//electron/build/args/%GN_CONFIG%.gn - - gn gen out/Default "--args=import(\"%BUILD_CONFIG_PATH%\") import(\"%GN_GOMA_FILE%\") %GN_EXTRA_ARGS% " - - gn check out/Default //electron:electron_lib - - gn check out/Default //electron:electron_app - - gn check out/Default //electron/shell/common/api:mojo - - if DEFINED GN_GOMA_FILE (ninja -j 300 -C out/Default electron:electron_app) else (ninja -C out/Default electron:electron_app) - - if "%GN_CONFIG%"=="testing" ( python C:\depot_tools\post_build_ninja_summary.py -C out\Default ) - - gn gen out/ffmpeg "--args=import(\"//electron/build/args/ffmpeg.gn\") %GN_EXTRA_ARGS%" - - ninja -C out/ffmpeg electron:electron_ffmpeg_zip - - ninja -C out/Default electron:electron_dist_zip - - ninja -C out/Default shell_browser_ui_unittests - - gn desc out/Default v8:run_mksnapshot_default args > out/Default/mksnapshot_args - - ninja -C out/Default electron:electron_mksnapshot_zip - - cd out\Default - - 7z a mksnapshot.zip mksnapshot_args gen\v8\embedded.S - - cd ..\.. - - 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 electron/build/profile_toolchain.py --output-json=out/Default/windows_toolchain_profile.json - - 7z a node_headers.zip out\Default\gen\node_headers - - ps: >- - if ($env:GN_CONFIG -eq 'release') { - # Needed for msdia140.dll on 64-bit windows - $env:Path += ";$pwd\third_party\llvm-build\Release+Asserts\bin" - ninja -C out/Default electron:electron_symbols - } - - ps: >- - if ($env:GN_CONFIG -eq 'release') { - python electron\script\zip-symbols.py - appveyor-retry appveyor PushArtifact out/Default/symbols.zip - } else { - # It's useful to have pdb files when debugging testing builds that are - # built on CI. - 7z a pdb.zip out\Default\*.pdb - } - - python electron/script/zip_manifests/check-zip-manifest.py out/Default/dist.zip electron/script/zip_manifests/dist_zip.win.%TARGET_ARCH%.manifest -test_script: - # Workaround for https://github.com/appveyor/ci/issues/2420 - - set "PATH=%PATH%;C:\Program Files\Git\mingw64\libexec\git-core" - - ps: >- - if ((-Not (Test-Path Env:\TEST_WOA)) -And (-Not (Test-Path Env:\ELECTRON_RELEASE)) -And ($env:GN_CONFIG -in "testing", "release")) { - $env:RUN_TESTS="true" - } - - ps: >- - if ($env:RUN_TESTS -eq 'true') { - New-Item .\out\Default\gen\node_headers\Release -Type directory - Copy-Item -path .\out\Default\electron.lib -destination .\out\Default\gen\node_headers\Release\node.lib - } else { - echo "Skipping tests for $env:GN_CONFIG build" - } - - cd electron - # CalculateNativeWinOcclusion is disabled due to https://bugs.chromium.org/p/chromium/issues/detail?id=1139022 - - if "%RUN_TESTS%"=="true" ( echo Running main test suite & node script/yarn test -- --trace-uncaught --runners=main --enable-logging=file --log-file=%cd%\electron.log --disable-features=CalculateNativeWinOcclusion ) - - if "%RUN_TESTS%"=="true" ( echo Running remote test suite & node script/yarn test -- --trace-uncaught --runners=remote --runTestFilesSeperately --enable-logging=file --log-file=%cd%\electron.log --disable-features=CalculateNativeWinOcclusion ) - - if "%RUN_TESTS%"=="true" ( echo Running native test suite & node script/yarn test -- --trace-uncaught --runners=native --enable-logging=file --log-file=%cd%\electron.log --disable-features=CalculateNativeWinOcclusion ) - - cd .. - - if "%RUN_TESTS%"=="true" ( echo Verifying non proprietary ffmpeg & python electron\script\verify-ffmpeg.py --build-dir out\Default --source-root %cd% --ffmpeg-path out\ffmpeg ) - - echo "About to verify mksnapshot" - - if "%RUN_TESTS%"=="true" ( echo Verifying mksnapshot & python electron\script\verify-mksnapshot.py --build-dir out\Default --source-root %cd% ) - - echo "Done verifying mksnapshot" - - if "%RUN_TESTS%"=="true" ( echo Verifying chromedriver & python electron\script\verify-chromedriver.py --build-dir out\Default --source-root %cd% ) - - echo "Done verifying chromedriver" -deploy_script: - - cd electron - - ps: >- - if (Test-Path Env:\ELECTRON_RELEASE) { - if (Test-Path Env:\UPLOAD_TO_STORAGE) { - Write-Output "Uploading Electron release distribution to azure" - & python script\release\uploaders\upload.py --verbose --upload_to_storage - } else { - Write-Output "Uploading Electron release distribution to github releases" - & python script\release\uploaders\upload.py --verbose - } - } elseif (Test-Path Env:\TEST_WOA) { - node script/release/ci-release-build.js --job=electron-woa-testing --ci=GHA --appveyorJobId=$env:APPVEYOR_JOB_ID $env:APPVEYOR_REPO_BRANCH - } -on_finish: - # Uncomment this lines to enable RDP - #- ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) - - cd .. - - if exist out\Default\windows_toolchain_profile.json ( appveyor-retry appveyor PushArtifact out\Default\windows_toolchain_profile.json ) - - if exist out\Default\dist.zip (appveyor-retry appveyor PushArtifact out\Default\dist.zip) - - if exist out\Default\shell_browser_ui_unittests.exe (appveyor-retry appveyor PushArtifact out\Default\shell_browser_ui_unittests.exe) - - if exist out\Default\chromedriver.zip (appveyor-retry appveyor PushArtifact out\Default\chromedriver.zip) - - if exist out\ffmpeg\ffmpeg.zip (appveyor-retry appveyor PushArtifact out\ffmpeg\ffmpeg.zip) - - 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) - - ps: >- - if ((Test-Path "pdb.zip") -And ($env:GN_CONFIG -ne 'release')) { - appveyor-retry appveyor PushArtifact pdb.zip - } + # It's useful to have pdb files when debugging testing builds that are + # built on CI. + 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 + + deploy_script: + - cd electron + - ps: >- + if (Test-Path Env:\ELECTRON_RELEASE) { + if (Test-Path Env:\UPLOAD_TO_STORAGE) { + Write-Output "Uploading Electron release distribution to azure" + & python3 script\release\uploaders\upload.py --verbose --upload_to_storage + } else { + Write-Output "Uploading Electron release distribution to github releases" + & python3 script\release\uploaders\upload.py --verbose + } + } + on_finish: + # Uncomment this lines to enable RDP + # - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) + - cd C:\projects\src + - if exist out\Default\windows_toolchain_profile.json ( appveyor-retry appveyor PushArtifact out\Default\windows_toolchain_profile.json ) + - if exist out\Default\dist.zip (appveyor-retry appveyor PushArtifact out\Default\dist.zip) + - if exist out\Default\shell_browser_ui_unittests.exe (appveyor-retry appveyor PushArtifact out\Default\shell_browser_ui_unittests.exe) + - if exist out\Default\chromedriver.zip (appveyor-retry appveyor PushArtifact out\Default\chromedriver.zip) + - if exist out\ffmpeg\ffmpeg.zip (appveyor-retry appveyor PushArtifact out\ffmpeg\ffmpeg.zip) + - 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) + - ps: >- + if ((Test-Path "pdb.zip") -And ($env:GN_CONFIG -ne 'release')) { + appveyor-retry appveyor PushArtifact pdb.zip + } + - matrix: + only: + - job_name: Test + + init: + - ps: | + if ($env:RUN_TESTS -ne 'true') { + Write-warning "Skipping tests for $env:APPVEYOR_PROJECT_NAME"; Exit-AppveyorBuild + } + build_script: + - ps: | + node script/yarn.js install --frozen-lockfile + node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER --prBranch=$env:APPVEYOR_REPO_BRANCH + if ($LASTEXITCODE -eq 0) { + Write-warning "Skipping build for doc only change"; Exit-AppveyorBuild + } + $global:LASTEXITCODE = 0 + - cd .. + - mkdir out\Default + - cd .. + - ps: | + # 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','shell_browser_ui_unittests.exe','chromedriver.zip','ffmpeg.zip','node_headers.zip','mksnapshot.zip','electron.lib') + foreach ($job in $build_info.build.jobs) { + if ($job.name -eq "Build") { + $jobId = $job.jobId + foreach($artifact_name in $artifacts_to_download) { + if ($artifact_name -eq 'shell_browser_ui_unittests.exe' -Or $artifact_name -eq 'electron.lib') { + $outfile = "src\out\Default\$artifact_name" + } else { + $outfile = $artifact_name + } + Invoke-RestMethod -Method Get -Uri "$apiUrl/buildjobs/$jobId/artifacts/$artifact_name" -OutFile $outfile + } + } + } + - ps: | + $out_default_zips = @('dist.zip','chromedriver.zip','mksnapshot.zip') + foreach($zip_name in $out_default_zips) { + 7z x -y -osrc\out\Default $zip_name + } + - ps: 7z x -y -osrc\out\ffmpeg ffmpeg.zip + - ps: 7z x -y -osrc node_headers.zip - - if exist electron\electron.log ( appveyor-retry appveyor PushArtifact electron\electron.log ) + test_script: + # Workaround for https://github.com/appveyor/ci/issues/2420 + - set "PATH=%PATH%;C:\Program Files\Git\mingw64\libexec\git-core" + - ps: | + cd src + New-Item .\out\Default\gen\node_headers\Release -Type directory + Copy-Item -path .\out\Default\electron.lib -destination .\out\Default\gen\node_headers\Release\node.lib + - cd electron + # Explicitly set npm_config_arch because the .env doesn't persist + - ps: >- + if ($env:TARGET_ARCH -eq 'ia32') { + $env:npm_config_arch = "ia32" + } + - echo Running main test suite & node script/yarn test -- --trace-uncaught --runners=main --enable-logging=file --log-file=%cd%\electron.log + - echo Running native test suite & node script/yarn test -- --trace-uncaught --runners=native --enable-logging=file --log-file=%cd%\electron.log + - cd .. + - echo Verifying non proprietary ffmpeg & python electron\script\verify-ffmpeg.py --build-dir out\Default --source-root %cd% --ffmpeg-path out\ffmpeg + - echo "About to verify mksnapshot" + - echo Verifying mksnapshot & python electron\script\verify-mksnapshot.py --build-dir out\Default --source-root %cd% + - echo "Done verifying mksnapshot" + - echo Verifying chromedriver & python electron\script\verify-chromedriver.py --build-dir out\Default --source-root %cd% + - echo "Done verifying chromedriver" + + on_finish: + # Uncomment these lines to enable RDP + # - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) + - if exist electron\electron.log ( appveyor-retry appveyor PushArtifact electron\electron.log ) \ No newline at end of file diff --git a/build/profile_toolchain.py b/build/profile_toolchain.py index 4251315e0a16a..6e51a7eaa1423 100755 --- a/build/profile_toolchain.py +++ b/build/profile_toolchain.py @@ -5,8 +5,6 @@ import os import optparse import json -import re -import subprocess sys.path.append("%s/../../build" % os.path.dirname(os.path.realpath(__file__))) @@ -36,56 +34,10 @@ def calculate_hash(root): return CalculateHash('.', None) def windows_installed_software(): - powershell_command = [ - "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", - ] - - proc = subprocess.Popen( - ["powershell.exe", "-Command", "-"], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - ) - - stdout, _ = proc.communicate(" ".join(powershell_command).encode("utf-8")) - - if proc.returncode != 0: - raise RuntimeError("Failed to get list of installed software") - - # On AppVeyor there's other output related to PSReadline, - # so grab only the JSON output and ignore everything else - json_match = re.match( - r".*(\[.*{.*}.*\]).*", stdout.decode("utf-8"), re.DOTALL - ) - - if not json_match: - raise RuntimeError( - "Couldn't find JSON output for list of installed software" - ) - - # Filter out missing keys - return list( - map( - lambda info: {k: info[k] for k in info if info[k]}, - json.loads(json_match.group(1)), - ) - ) + # file_path = os.path.join(os.getcwd(), 'installed_software.json') + # return json.loads(open('installed_software.json').read().decode('utf-8')) + f = open('installed_software.json', encoding='utf-8-sig') + return json.load(f) def windows_profile(): diff --git a/shell/browser/resources/win/electron.rc b/build/templates/electron_rc.tmpl similarity index 87% rename from shell/browser/resources/win/electron.rc rename to build/templates/electron_rc.tmpl index 334cec61d19db..2f75d9003b84b 100644 --- a/shell/browser/resources/win/electron.rc +++ b/build/templates/electron_rc.tmpl @@ -50,8 +50,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 20,3,0,0 - PRODUCTVERSION 20,3,0,0 + FILEVERSION $major,$minor,$patch,$prerelease_number + PRODUCTVERSION $major,$minor,$patch,$prerelease_number FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -68,12 +68,12 @@ BEGIN BEGIN VALUE "CompanyName", "GitHub, Inc." VALUE "FileDescription", "Electron" - VALUE "FileVersion", "20.3.0" + VALUE "FileVersion", "$major.$minor.$patch" VALUE "InternalName", "electron.exe" VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved." VALUE "OriginalFilename", "electron.exe" VALUE "ProductName", "Electron" - VALUE "ProductVersion", "20.3.0" + VALUE "ProductVersion", "$major.$minor.$patch" VALUE "SquirrelAwareVersion", "1" END END diff --git a/build/templates/version_string.tmpl b/build/templates/version_string.tmpl new file mode 100644 index 0000000000000..02e5f9c0d4f9f --- /dev/null +++ b/build/templates/version_string.tmpl @@ -0,0 +1 @@ +$full_version \ No newline at end of file diff --git a/chromium_src/BUILD.gn b/chromium_src/BUILD.gn index e3c9189b21187..438b2aa836cc3 100644 --- a/chromium_src/BUILD.gn +++ b/chromium_src/BUILD.gn @@ -6,6 +6,7 @@ import("//build/config/ozone.gni") import("//build/config/ui.gni") import("//components/spellcheck/spellcheck_build_features.gni") import("//electron/buildflags/buildflags.gni") +import("//ppapi/buildflags/buildflags.gni") import("//printing/buildflags/buildflags.gni") import("//third_party/widevine/cdm/widevine.gni") @@ -370,15 +371,20 @@ source_set("plugins") { deps += [ "//components/strings", "//media:media_buildflags", - "//ppapi/buildflags", - "//ppapi/host", - "//ppapi/proxy", - "//ppapi/proxy:ipc", - "//ppapi/shared_impl", "//services/device/public/mojom", "//skia", "//storage/browser", ] + + if (enable_plugins) { + deps += [ + "//ppapi/buildflags", + "//ppapi/host", + "//ppapi/proxy", + "//ppapi/proxy:ipc", + "//ppapi/shared_impl", + ] + } } # This source set is just so we don't have to depend on all of //chrome/browser diff --git a/default_app/main.ts b/default_app/main.ts index f2834624f7430..7defe97f3ecf3 100644 --- a/default_app/main.ts +++ b/default_app/main.ts @@ -83,7 +83,7 @@ function loadApplicationPackage (packagePath: string) { }); try { - // Override app name and version. + // Override app's package.json data. packagePath = path.resolve(packagePath); const packageJsonPath = path.join(packagePath, 'package.json'); let appPath; @@ -104,6 +104,16 @@ function loadApplicationPackage (packagePath: string) { } else if (packageJson.name) { app.name = packageJson.name; } + if (packageJson.desktopName) { + app.setDesktopName(packageJson.desktopName); + } else { + app.setDesktopName(`${app.name}.desktop`); + } + // Set v8 flags, deliberately lazy load so that apps that do not use this + // feature do not pay the price + if (packageJson.v8Flags) { + require('v8').setFlagsFromString(packageJson.v8Flags); + } appPath = packagePath; } diff --git a/docs/README.md b/docs/README.md index 40ae2be10c18c..57172020a87d6 100644 --- a/docs/README.md +++ b/docs/README.md @@ -83,7 +83,6 @@ These individual tutorials expand on topics discussed in the guide above. * Electron Releases & Developer Feedback * [Versioning Policy](tutorial/electron-versioning.md) * [Release Timelines](tutorial/electron-timelines.md) -* [Testing Widevine CDM](tutorial/testing-widevine-cdm.md) --- diff --git a/docs/api/ipc-renderer.md b/docs/api/ipc-renderer.md index dae89527aa42c..d17b761286883 100644 --- a/docs/api/ipc-renderer.md +++ b/docs/api/ipc-renderer.md @@ -96,14 +96,6 @@ Algorithm][SCA], just like [`window.postMessage`][], so prototype chains will no included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an exception. -> **NOTE:** Sending non-standard JavaScript types such as DOM objects or -> special Electron objects will throw an exception. -> -> Since the main process does not have support for DOM objects such as -> `ImageBitmap`, `File`, `DOMMatrix` and so on, such objects cannot be sent over -> Electron's IPC to the main process, as the main process would have no way to decode -> them. Attempting to send such objects over IPC will result in an error. - The main process should listen for `channel` with [`ipcMain.handle()`](./ipc-main.md#ipcmainhandlechannel-listener). @@ -126,6 +118,21 @@ If you need to transfer a [`MessagePort`][] to the main process, use [`ipcRender If you do not need a response to the message, consider using [`ipcRenderer.send`](#ipcrenderersendchannel-args). +> **Note** +> Sending non-standard JavaScript types such as DOM objects or +> special Electron objects will throw an exception. +> +> Since the main process does not have support for DOM objects such as +> `ImageBitmap`, `File`, `DOMMatrix` and so on, such objects cannot be sent over +> Electron's IPC to the main process, as the main process would have no way to decode +> them. Attempting to send such objects over IPC will result in an error. + +> **Note** +> If the handler in the main process throws an error, +> the promise returned by `invoke` will reject. +> However, the `Error` object in the renderer process +> will not be the same as the one thrown in the main process. + ### `ipcRenderer.sendSync(channel, ...args)` * `channel` string diff --git a/docs/api/session.md b/docs/api/session.md index f405d133ba523..544a83a65e05a 100644 --- a/docs/api/session.md +++ b/docs/api/session.md @@ -635,9 +635,10 @@ win.webContents.session.setCertificateVerifyProc((request, callback) => { * `notifications` - Request notification creation and the ability to display them in the user's system tray. * `midi` - Request MIDI access in the `webmidi` API. * `midiSysex` - Request the use of system exclusive messages in the `webmidi` API. - * `pointerLock` - Request to directly interpret mouse movements as an input method. Click [here](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API) to know more. + * `pointerLock` - Request to directly interpret mouse movements as an input method. Click [here](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API) to know more. These requests always appear to originate from the main frame. * `fullscreen` - Request for the app to enter fullscreen mode. * `openExternal` - Request to open links in external applications. + * `window-placement` - Request access to enumerate screens using the [`getScreenDetails`](https://developer.chrome.com/en/articles/multi-screen-window-placement/) API. * `unknown` - An unrecognized permission request * `callback` Function * `permissionGranted` boolean - Allow or deny the permission. diff --git a/docs/tutorial/mac-app-store-submission-guide.md b/docs/tutorial/mac-app-store-submission-guide.md index 18e0fbfbb8cd4..79b087dd98418 100644 --- a/docs/tutorial/mac-app-store-submission-guide.md +++ b/docs/tutorial/mac-app-store-submission-guide.md @@ -232,7 +232,7 @@ how to meet the Mac App Store requirements. ### Upload -The Application Loader should be used to upload the signed app to iTunes +[Apple Transporter][apple-transporter] should be used to upload the signed app to App Store Connect for processing, making sure you have [created a record][create-record] before uploading. @@ -345,7 +345,8 @@ Electron uses following cryptographic algorithms: [app-sandboxing]: https://developer.apple.com/app-sandboxing/ [app-notarization]: https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution [submitting-your-app]: https://developer.apple.com/library/mac/documentation/IDEs/Conceptual/AppDistributionGuide/SubmittingYourApp/SubmittingYourApp.html -[create-record]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/CreatingiTunesConnectRecord.html +[create-record]: https://help.apple.com/app-store-connect/#/dev2cd126805 +[apple-transporter]: https://help.apple.com/itc/transporteruserguide/en.lproj/static.html [submit-for-review]: https://developer.apple.com/library/ios/documentation/LanguagesUtilities/Conceptual/iTunesConnect_Guide/Chapters/SubmittingTheApp.html [export-compliance]: https://help.apple.com/app-store-connect/#/devc3f64248f [user-selected]: https://developer.apple.com/library/mac/documentation/Miscellaneous/Reference/EntitlementKeyReference/Chapters/EnablingAppSandbox.html#//apple_ref/doc/uid/TP40011195-CH4-SW6 diff --git a/docs/tutorial/testing-widevine-cdm.md b/docs/tutorial/testing-widevine-cdm.md deleted file mode 100644 index b2bcd7cde4a6f..0000000000000 --- a/docs/tutorial/testing-widevine-cdm.md +++ /dev/null @@ -1,95 +0,0 @@ -# Testing Widevine CDM - -In Electron you can use the Widevine CDM library shipped with Chrome browser. - -Widevine Content Decryption Modules (CDMs) are how streaming services protect -content using HTML5 video to web browsers without relying on an NPAPI plugin -like Flash or Silverlight. Widevine support is an alternative solution for -streaming services that currently rely on Silverlight for playback of -DRM-protected video content. It will allow websites to show DRM-protected video -content in Firefox without the use of NPAPI plugins. The Widevine CDM runs in an -open-source CDM sandbox providing better user security than NPAPI plugins. - -#### Note on VMP - -As of [`Electron v1.8.0 (Chrome v59)`](https://electronjs.org/releases#1.8.1), -the below steps are may only be some of the necessary steps to enable Widevine; -any app on or after that version intending to use the Widevine CDM may need to -be signed using a license obtained from [Widevine](https://www.widevine.com/) -itself. - -Per [Widevine](https://www.widevine.com/): - -> Chrome 59 (and later) includes support for Verified Media Path (VMP). VMP -> provides a method to verify the authenticity of a device platform. For browser -> deployments, this will provide an additional signal to determine if a -> browser-based implementation is reliable and secure. -> -> The proxy integration guide has been updated with information about VMP and -> how to issue licenses. -> -> Widevine recommends our browser-based integrations (vendors and browser-based -> applications) add support for VMP. - -To enable video playback with this new restriction, -[castLabs](https://castlabs.com/open-source/downstream/) has created a -[fork](https://github.com/castlabs/electron-releases) that has implemented the -necessary changes to enable Widevine to be played in an Electron application if -one has obtained the necessary licenses from widevine. - -## Getting the library - -Open `chrome://components/` in Chrome browser, find `Widevine Content Decryption Module` -and make sure it is up to date, then you can find the library files from the -application directory. - -### On Windows - -The library file `widevinecdm.dll` will be under -`Program Files(x86)/Google/Chrome/Application/CHROME_VERSION/WidevineCdm/_platform_specific/win_(x86|x64)/` -directory. - -### On macOS - -The library file `libwidevinecdm.dylib` will be under -`/Applications/Google Chrome.app/Contents/Versions/CHROME_VERSION/Google Chrome Framework.framework/Versions/A/Libraries/WidevineCdm/_platform_specific/mac_(x86|x64)/` -directory. - -**Note:** Make sure that chrome version used by Electron is greater than or -equal to the `min_chrome_version` value of Chrome's widevine cdm component. -The value can be found in `manifest.json` under `WidevineCdm` directory. - -## Using the library - -After getting the library files, you should pass the path to the file -with `--widevine-cdm-path` command line switch, and the library's version -with `--widevine-cdm-version` switch. The command line switches have to be -passed before the `ready` event of `app` module gets emitted. - -Example code: - -```javascript -const { app, BrowserWindow } = require('electron') - -// You have to pass the directory that contains widevine library here, it is -// * `libwidevinecdm.dylib` on macOS, -// * `widevinecdm.dll` on Windows. -app.commandLine.appendSwitch('widevine-cdm-path', '/path/to/widevine_library') -// The version of plugin can be got from `chrome://components` page in Chrome. -app.commandLine.appendSwitch('widevine-cdm-version', '1.4.8.866') - -let win = null -app.whenReady().then(() => { - win = new BrowserWindow() - win.show() -}) -``` - -## Verifying Widevine CDM support - -To verify whether widevine works, you can use following ways: - -* Open https://shaka-player-demo.appspot.com/ and load a manifest that uses -`Widevine`. -* Open http://www.dash-player.com/demo/drm-test-area/, check whether the page -says `bitdash uses Widevine in your browser`, then play the video. diff --git a/docs/tutorial/tutorial-2-first-app.md b/docs/tutorial/tutorial-2-first-app.md index 75d94d618e014..072cb5a843430 100644 --- a/docs/tutorial/tutorial-2-first-app.md +++ b/docs/tutorial/tutorial-2-first-app.md @@ -369,12 +369,12 @@ run. Create a launch.json configuration in a new `.vscode` folder in your projec "name": "Renderer", "port": 9222, "request": "attach", - "type": "pwa-chrome", + "type": "chrome", "webRoot": "${workspaceFolder}" }, { "name": "Main", - "type": "pwa-node", + "type": "node", "request": "launch", "cwd": "${workspaceFolder}", "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron", @@ -398,11 +398,11 @@ What we have done in the `launch.json` file is to create 3 configurations: - `Main` is used to start the main process and also expose port 9222 for remote debugging (`--remote-debugging-port=9222`). This is the port that we will use to attach the debugger for the `Renderer`. Because the main process is a Node.js process, the type is set to - `pwa-node` (`pwa-` is the prefix that tells VS Code to use the latest JavaScript debugger). + `node`. - `Renderer` is used to debug the renderer process. Because the main process is the one that creates the process, we have to "attach" to it (`"request": "attach"`) instead of creating a new one. - The renderer process is a web one, so the debugger we have to use is `pwa-chrome`. + The renderer process is a web one, so the debugger we have to use is `chrome`. - `Main + renderer` is a [compound task] that executes the previous ones simultaneously. :::caution diff --git a/filenames.gni b/filenames.gni index 0a0617ee5c67c..4dfdcfc6cf47f 100644 --- a/filenames.gni +++ b/filenames.gni @@ -672,8 +672,6 @@ filenames = { "shell/renderer/electron_render_frame_observer.h", "shell/renderer/electron_renderer_client.cc", "shell/renderer/electron_renderer_client.h", - "shell/renderer/electron_renderer_pepper_host_factory.cc", - "shell/renderer/electron_renderer_pepper_host_factory.h", "shell/renderer/electron_sandboxed_renderer_client.cc", "shell/renderer/electron_sandboxed_renderer_client.h", "shell/renderer/guest_view_container.cc", diff --git a/lib/browser/api/web-contents.ts b/lib/browser/api/web-contents.ts index cba02f7c849d0..cd63412e9f9f3 100644 --- a/lib/browser/api/web-contents.ts +++ b/lib/browser/api/web-contents.ts @@ -475,12 +475,14 @@ WebContents.prototype.loadURL = function (url, options) { const removeListeners = () => { this.removeListener('did-finish-load', finishListener); this.removeListener('did-fail-load', failListener); + this.removeListener('did-navigate-in-page', finishListener); this.removeListener('did-start-navigation', navigationListener); this.removeListener('did-stop-loading', stopLoadingListener); this.removeListener('destroyed', stopLoadingListener); }; this.on('did-finish-load', finishListener); this.on('did-fail-load', failListener); + this.on('did-navigate-in-page', finishListener); this.on('did-start-navigation', navigationListener); this.on('did-stop-loading', stopLoadingListener); this.on('destroyed', stopLoadingListener); diff --git a/lib/renderer/web-view/web-view-attributes.ts b/lib/renderer/web-view/web-view-attributes.ts index ce7bac90aa002..6a8e1d8728ea8 100644 --- a/lib/renderer/web-view/web-view-attributes.ts +++ b/lib/renderer/web-view/web-view-attributes.ts @@ -186,7 +186,10 @@ export class SrcAttribute extends WebViewAttribute { opts.userAgent = useragent; } - (this.webViewImpl.webviewNode as Electron.WebviewTag).loadURL(this.getValue(), opts); + (this.webViewImpl.webviewNode as Electron.WebviewTag).loadURL(this.getValue(), opts) + .catch(err => { + console.error('Unexpected error while loading URL', err); + }); } } diff --git a/npm/install.js b/npm/install.js index 864ca633fd30f..8fb438ecace25 100755 --- a/npm/install.js +++ b/npm/install.js @@ -70,29 +70,21 @@ function isInstalled () { // unzips and makes path.txt point at the correct executable function extractFile (zipPath) { - return new Promise((resolve, reject) => { - const distPath = process.env.ELECTRON_OVERRIDE_DIST_PATH || path.join(__dirname, 'dist'); - - extract(zipPath, { dir: path.join(__dirname, 'dist') }) - .then(() => { - // If the zip contains an "electron.d.ts" file, - // move that up - const srcTypeDefPath = path.join(distPath, 'electron.d.ts'); - const targetTypeDefPath = path.join(__dirname, 'electron.d.ts'); - const hasTypeDefinitions = fs.existsSync(srcTypeDefPath); - - if (hasTypeDefinitions) { - try { - fs.renameSync(srcTypeDefPath, targetTypeDefPath); - } catch (err) { - reject(err); - } - } - - // Write a "path.txt" file. - return fs.promises.writeFile(path.join(__dirname, 'path.txt'), platformPath); - }) - .catch((err) => reject(err)); + const distPath = process.env.ELECTRON_OVERRIDE_DIST_PATH || path.join(__dirname, 'dist'); + + return extract(zipPath, { dir: path.join(__dirname, 'dist') }).then(() => { + // If the zip contains an "electron.d.ts" file, + // move that up + const srcTypeDefPath = path.join(distPath, 'electron.d.ts'); + const targetTypeDefPath = path.join(__dirname, 'electron.d.ts'); + const hasTypeDefinitions = fs.existsSync(srcTypeDefPath); + + if (hasTypeDefinitions) { + fs.renameSync(srcTypeDefPath, targetTypeDefPath); + } + + // Write a "path.txt" file. + return fs.promises.writeFile(path.join(__dirname, 'path.txt'), platformPath); }); } diff --git a/package.json b/package.json index 724487fdb2a64..4e5cb9313e8b3 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,13 @@ { "name": "electron", - "version": "20.3.0", + "version": "0.0.0-development", "repository": "https://github.com/electron/electron", "description": "Build cross platform desktop apps with JavaScript, HTML, and CSS", "devDependencies": { "@azure/storage-blob": "^12.9.0", - "@electron/docs-parser": "^0.12.4", - "@electron/typescript-definitions": "^8.9.5", + "@electron/asar": "^3.2.1", + "@electron/docs-parser": "^1.0.0", + "@electron/typescript-definitions": "^8.10.0", "@octokit/auth-app": "^2.10.0", "@octokit/rest": "^18.0.3", "@primer/octicons": "^10.0.0", @@ -31,7 +32,6 @@ "@types/webpack-env": "^1.16.3", "@typescript-eslint/eslint-plugin": "^4.4.1", "@typescript-eslint/parser": "^4.4.1", - "asar": "^3.1.0", "aws-sdk": "^2.814.0", "check-for-leaks": "^1.2.1", "colors": "1.4.0", @@ -89,7 +89,7 @@ "lint:docs-relative-links": "python3 ./script/check-relative-doc-links.py", "lint:markdownlint": "markdownlint \"*.md\" \"docs/**/*.md\"", "lint:js-in-markdown": "standard-markdown docs", - "create-api-json": "electron-docs-parser --dir=./", + "create-api-json": "node script/create-api-json.js", "create-typescript-definitions": "npm run create-api-json && electron-typescript-definitions --api=electron-api.json && node spec/ts-smoke/runner.js", "gn-typescript-definitions": "npm run create-typescript-definitions && shx cp electron.d.ts", "pre-flight": "pre-flight", @@ -146,4 +146,4 @@ "resolutions": { "nan": "nodejs/nan#16fa32231e2ccd89d2804b3f765319128b20c4ac" } -} \ No newline at end of file +} diff --git a/patches/angle/.patches b/patches/angle/.patches new file mode 100644 index 0000000000000..583e0af1c8cf0 --- /dev/null +++ b/patches/angle/.patches @@ -0,0 +1 @@ +cherry-pick-b8636b57b8f2.patch diff --git a/patches/angle/cherry-pick-b8636b57b8f2.patch b/patches/angle/cherry-pick-b8636b57b8f2.patch new file mode 100644 index 0000000000000..34091fa5102ce --- /dev/null +++ b/patches/angle/cherry-pick-b8636b57b8f2.patch @@ -0,0 +1,46 @@ +From b8636b57b8f231994ecb3fb14f181c593c83a3fb Mon Sep 17 00:00:00 2001 +From: Jamie Madill +Date: Mon, 29 Aug 2022 16:25:46 -0400 +Subject: [PATCH] [M106] Vulkan: Ensure we sync the draw FB before beingQuery. + +Bug: chromium:1354271 +(cherry picked from commit 4ebdac790c76b65abf5703bcef9482c638076195) +Change-Id: I7b715a9c28badfe58a0ae1a478d2b4e8bbd23c47 +Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3956939 +Reviewed-by: Shahbaz Youssefi +--- + +diff --git a/src/libANGLE/State.h b/src/libANGLE/State.h +index 168104e..2f498d3 100644 +--- a/src/libANGLE/State.h ++++ b/src/libANGLE/State.h +@@ -603,6 +603,11 @@ + + bool isRobustResourceInitEnabled() const { return mRobustResourceInit; } + ++ bool isDrawFramebufferBindingDirty() const ++ { ++ return mDirtyBits.test(DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING); ++ } ++ + // Sets the dirty bit for the program executable. + angle::Result onProgramExecutableChange(const Context *context, Program *program); + // Sets the dirty bit for the program pipeline executable. +diff --git a/src/libANGLE/renderer/vulkan/QueryVk.cpp b/src/libANGLE/renderer/vulkan/QueryVk.cpp +index 9f475e6..6ef5f72 100644 +--- a/src/libANGLE/renderer/vulkan/QueryVk.cpp ++++ b/src/libANGLE/renderer/vulkan/QueryVk.cpp +@@ -303,6 +303,13 @@ + { + ContextVk *contextVk = vk::GetImpl(context); + ++ // Ensure that we start with the right RenderPass when we begin a new query. ++ if (contextVk->getState().isDrawFramebufferBindingDirty()) ++ { ++ ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass( ++ RenderPassClosureReason::FramebufferBindingChange)); ++ } ++ + mCachedResultValid = false; + + // Transform feedback query is handled by a CPU-calculated value when emulated. diff --git a/patches/chromium/.patches b/patches/chromium/.patches index ed250de10661a..5323c9057fa64 100644 --- a/patches/chromium/.patches +++ b/patches/chromium/.patches @@ -125,3 +125,40 @@ cherry-pick-2083e894852c.patch cherry-pick-51daffbf5cd8.patch dpwa_enable_window_controls_overlay_by_default.patch create_browser_v8_snapshot_file_name_fuse.patch +cherry-pick-fefd6198da31.patch +cherry-pick-1eb1e18ad41d.patch +cherry-pick-05a0d99c9715.patch +cherry-pick-c83640db21b5.patch +fix_on-screen-keyboard_hides_on_input_blur_in_webview.patch +cherry-pick-65f0ef609c00.patch +cherry-pick-cb9dff93f3d4.patch +build_fix_building_with_enable_plugins_false.patch +build_allow_electron_to_use_exec_script.patch +cherry-pick-d5ffb4dd4112.patch +cherry-pick-65d46507a0c9.patch +cherry-pick-933cc81c6bad.patch +cherry-pick-06c87f9f42ff.patch +cherry-pick-67c9cbc784d6.patch +cherry-pick-a1cbf05b4163.patch +cherry-pick-ac4785387fff.patch +cherry-pick-81cb17c24788.patch +cherry-pick-9b3d0e2f1aab.patch +cherry-pick-1894458e04a2.patch +cherry-pick-6b4af5d82083.patch +cherry-pick-176c526846cb.patch +cherry-pick-65ad70274d4b.patch +cherry-pick-f46db6aac3e9.patch +cherry-pick-2ef09109c0ec.patch +cherry-pick-f98adc846aad.patch +cherry-pick-eed5a4de2c40.patch +cherry-pick-d1d654d73222.patch +cherry-pick-42e15c2055c4.patch +cherry-pick-77208afba04d.patch +mojo_disable_sync_call_interrupts_in_the_browser.patch +mojo_validate_that_a_message_is_allowed_to_use_the_sync_flag.patch +cherry-pick-819d876e1bb8.patch +cherry-pick-43637378b14e.patch +win_fix_touch_mode_detection_dcheck_in_canary.patch +cherry-pick-ca2b108a0f1f.patch +cherry-pick-d652130c4bc2.patch +cherry-pick-e545559df538.patch diff --git a/patches/chromium/build_allow_electron_to_use_exec_script.patch b/patches/chromium/build_allow_electron_to_use_exec_script.patch new file mode 100644 index 0000000000000..65a1a79646155 --- /dev/null +++ b/patches/chromium/build_allow_electron_to_use_exec_script.patch @@ -0,0 +1,18 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Samuel Attard +Date: Fri, 21 Oct 2022 16:29:06 -0700 +Subject: build: allow electron to use exec_script + +This is similar to the //build usecase so we're OK adding ourselves here + +diff --git a/.gn b/.gn +index 7d538f812d72e0937e7a031e1c53651c352149c5..1cad40a9825f3c6df67dbcc12d2f9650aad809b2 100644 +--- a/.gn ++++ b/.gn +@@ -169,4 +169,6 @@ exec_script_whitelist = + + "//tools/grit/grit_rule.gni", + "//tools/gritsettings/BUILD.gn", ++ ++ "//electron/BUILD.gn" + ] diff --git a/patches/chromium/build_fix_building_with_enable_plugins_false.patch b/patches/chromium/build_fix_building_with_enable_plugins_false.patch new file mode 100644 index 0000000000000..078ebf326a78d --- /dev/null +++ b/patches/chromium/build_fix_building_with_enable_plugins_false.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Milan Burda +Date: Sun, 30 Oct 2022 22:32:39 +0100 +Subject: build: fix building with enable_plugins = false + +This issue is fixed in latest Chromium + +diff --git a/tools/ipc_fuzzer/message_lib/BUILD.gn b/tools/ipc_fuzzer/message_lib/BUILD.gn +index 00618d9f81cabd5084218431658fd91d22fb4208..26be64a51fc5767e0ee97681a0b3f2dfd74159fe 100644 +--- a/tools/ipc_fuzzer/message_lib/BUILD.gn ++++ b/tools/ipc_fuzzer/message_lib/BUILD.gn +@@ -3,6 +3,7 @@ + # found in the LICENSE file. + + import("//components/nacl/features.gni") ++import("//ppapi/buildflags/buildflags.gni") + import("//remoting/remoting_enable.gni") + + static_library("ipc_message_lib") { +@@ -22,7 +23,6 @@ static_library("ipc_message_lib") { + "//ipc", + "//media/cast:net", + "//media/gpu/ipc/common", +- "//ppapi/proxy:ipc", + "//skia", + "//third_party/blink/public:blink", + "//third_party/blink/public:blink_headers", +@@ -49,4 +49,7 @@ static_library("ipc_message_lib") { + if (enable_remoting) { + public_deps += [ "//remoting/host" ] + } ++ if (enable_plugins) { ++ public_deps += [ "//ppapi/proxy:ipc" ] ++ } + } diff --git a/patches/chromium/cherry-pick-05a0d99c9715.patch b/patches/chromium/cherry-pick-05a0d99c9715.patch new file mode 100644 index 0000000000000..6d02da731896d --- /dev/null +++ b/patches/chromium/cherry-pick-05a0d99c9715.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: David Bokan +Date: Thu, 28 Jul 2022 18:09:13 +0000 +Subject: Prevent handling input for provisional frames + +Bug: 1347644,1322812 +Change-Id: Ifd60f6aa593ce23ca6cbb65552fc9fb8f8690035 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3791883 +Commit-Queue: David Bokan +Reviewed-by: Dave Tapuska +Cr-Commit-Position: refs/heads/main@{#1029361} + +diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc +index fe775337fbc22817d7489df143821eea2d9425ec..13a241273090e54fabdba9d82510e36d2386c4a4 100644 +--- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc ++++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc +@@ -2460,10 +2460,15 @@ WebInputEventResult WebFrameWidgetImpl::HandleInputEvent( + DCHECK(!WebInputEvent::IsTouchEventType(input_event.GetType())); + CHECK(LocalRootImpl()); + ++ // Clients shouldn't be dispatching events to a provisional frame but this ++ // can happen. Ensure that event handling can assume we're in a committed ++ // frame. ++ if (IsProvisional()) ++ return WebInputEventResult::kHandledSuppressed; ++ + // Only record metrics for the root frame. +- if (ForTopMostMainFrame()) { ++ if (ForTopMostMainFrame()) + GetPage()->GetVisualViewport().StartTrackingPinchStats(); +- } + + // If a drag-and-drop operation is in progress, ignore input events except + // PointerCancel and GestureLongPress. diff --git a/patches/chromium/cherry-pick-06c87f9f42ff.patch b/patches/chromium/cherry-pick-06c87f9f42ff.patch new file mode 100644 index 0000000000000..0d1c6cf43d78b --- /dev/null +++ b/patches/chromium/cherry-pick-06c87f9f42ff.patch @@ -0,0 +1,153 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Rune Lillesveen +Date: Fri, 14 Oct 2022 09:52:34 +0000 +Subject: Avoid layout roots in subtrees skipped for style recalc + +Layout roots are laid out from inner to outer in LocalFrameView. DOM +mutations may have added layout roots inside size container subtrees +before style recalc. If we decide to postpone style recalc until layout +of the size container, it means we may try to layout a root inside a +subtree skipped for style recalc. That causes a DCHECK and possibly +other issues. + +This also fixes the use-after-poison issue 1365330. + +(cherry picked from commit 0f0f1e99201fadb3c68518350e1cd6af1b665346) + +Bug: 1371820, 1365330 +Change-Id: Ia48890c08aacfe7b9a3e660817702abce0570564 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3934847 +Reviewed-by: Ian Kilpatrick +Commit-Queue: Rune Lillesveen +Cr-Original-Commit-Position: refs/heads/main@{#1055853} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3953455 +Auto-Submit: Rune Lillesveen +Commit-Queue: Anders Hartvoll Ruud +Reviewed-by: Anders Hartvoll Ruud +Cr-Commit-Position: refs/branch-heads/5249@{#836} +Cr-Branched-From: 4f7bea5de862aaa52e6bde5920755a9ef9db120b-refs/heads/main@{#1036826} + +diff --git a/third_party/blink/renderer/core/css/style_engine.cc b/third_party/blink/renderer/core/css/style_engine.cc +index f51b8878eb0abe23889a07277efeaf7cdf961cc8..ddcef20b47357e58acae08b4183db6187b046f80 100644 +--- a/third_party/blink/renderer/core/css/style_engine.cc ++++ b/third_party/blink/renderer/core/css/style_engine.cc +@@ -2808,6 +2808,7 @@ void StyleEngine::RecalcStyle(StyleRecalcChange change, + const StyleRecalcContext& style_recalc_context) { + DCHECK(GetDocument().documentElement()); + ScriptForbiddenScope forbid_script; ++ SkipStyleRecalcScope skip_scope(*this); + CheckPseudoHasCacheScope check_pseudo_has_cache_scope(&GetDocument()); + Element& root_element = style_recalc_root_.RootElement(); + Element* parent = FlatTreeTraversal::ParentElement(root_element); +@@ -3400,4 +3401,17 @@ void StyleEngine::MarkForLayoutTreeChangesAfterDetach() { + parent_for_detached_subtree_ = nullptr; + } + ++bool StyleEngine::AllowSkipStyleRecalcForScope() const { ++ if (InContainerQueryStyleRecalc()) ++ return true; ++ if (LocalFrameView* view = GetDocument().View()) { ++ // Existing layout roots before starting style recalc may end up being ++ // inside skipped subtrees if we allowed skipping. If we start out with an ++ // empty list, any added ones will be a result of an element style recalc, ++ // which means the will not be inside a skipped subtree. ++ return !view->IsSubtreeLayout(); ++ } ++ return true; ++} ++ + } // namespace blink +diff --git a/third_party/blink/renderer/core/css/style_engine.h b/third_party/blink/renderer/core/css/style_engine.h +index a6c325b69e5bc43c657519f4c0730f6e2efd4f71..f7ccc6c2b7b306d76bba60cf46da91a5b291c29e 100644 +--- a/third_party/blink/renderer/core/css/style_engine.h ++++ b/third_party/blink/renderer/core/css/style_engine.h +@@ -178,6 +178,20 @@ class CORE_EXPORT StyleEngine final : public GarbageCollected, + base::AutoReset allow_marking_; + }; + ++ // Set up the condition for allowing to skip style recalc before starting ++ // RecalcStyle(). ++ class SkipStyleRecalcScope { ++ STACK_ALLOCATED(); ++ ++ public: ++ explicit SkipStyleRecalcScope(StyleEngine& engine) ++ : allow_skip_(&engine.allow_skip_style_recalc_, ++ engine.AllowSkipStyleRecalcForScope()) {} ++ ++ private: ++ base::AutoReset allow_skip_; ++ }; ++ + explicit StyleEngine(Document&); + ~StyleEngine() override; + +@@ -342,6 +356,10 @@ class CORE_EXPORT StyleEngine final : public GarbageCollected, + + bool MarkReattachAllowed() const; + ++ // Returns true if we can skip style recalc for a size container subtree and ++ // resume it during layout. ++ bool SkipStyleRecalcAllowed() const { return allow_skip_style_recalc_; } ++ + CSSFontSelector* GetFontSelector() { return font_selector_; } + + void RemoveFontFaceRules(const HeapVector>&); +@@ -743,6 +761,9 @@ class CORE_EXPORT StyleEngine final : public GarbageCollected, + Element& changed_element, + bool for_pseudo_change); + ++ // Initialization value for SkipStyleRecalcScope. ++ bool AllowSkipStyleRecalcForScope() const; ++ + Member document_; + + // Tracks the number of currently loading top-level stylesheets. Sheets loaded +@@ -812,6 +833,9 @@ class CORE_EXPORT StyleEngine final : public GarbageCollected, + // AllowMarkStyleDirtyFromRecalcScope. + bool allow_mark_for_reattach_from_rebuild_layout_tree_{false}; + ++ // Set to true if we are allowed to skip recalc for a size container subtree. ++ bool allow_skip_style_recalc_{false}; ++ + // See enum ViewportUnitFlag. + unsigned viewport_unit_dirty_flags_{0}; + +diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc +index 8e5c4aab2e37ed0acda0ef56273d007fbaa58780..2df360c33c54e12af341b77771fcda95e562fa92 100644 +--- a/third_party/blink/renderer/core/dom/element.cc ++++ b/third_party/blink/renderer/core/dom/element.cc +@@ -3532,6 +3532,10 @@ bool Element::SkipStyleRecalcForContainer( + const ComputedStyle& style, + const StyleRecalcChange& child_change) { + DCHECK(RuntimeEnabledFeatures::CSSContainerSkipStyleRecalcEnabled()); ++ ++ if (!GetDocument().GetStyleEngine().SkipStyleRecalcAllowed()) ++ return false; ++ + if (!child_change.TraversePseudoElements(*this)) { + // If none of the children or pseudo elements need to be traversed for style + // recalc, there is no point in marking the subtree as skipped. +diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/container-queries/crashtests/chrome-layout-root-crash.html b/third_party/blink/web_tests/external/wpt/css/css-contain/container-queries/crashtests/chrome-layout-root-crash.html +new file mode 100644 +index 0000000000000000000000000000000000000000..e3e709a240bd870250b2747c94fe96880bdf52e3 +--- /dev/null ++++ b/third_party/blink/web_tests/external/wpt/css/css-contain/container-queries/crashtests/chrome-layout-root-crash.html +@@ -0,0 +1,17 @@ ++ ++ ++ ++ ++

Pass if no crash.

++
a
++ diff --git a/patches/chromium/cherry-pick-176c526846cb.patch b/patches/chromium/cherry-pick-176c526846cb.patch new file mode 100644 index 0000000000000..de2bfe9206cbd --- /dev/null +++ b/patches/chromium/cherry-pick-176c526846cb.patch @@ -0,0 +1,192 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robert Sesek +Date: Fri, 18 Nov 2022 19:31:38 +0000 +Subject: Fix a data race leading to use-after-free in mojo::ChannelMac + ShutDown + +(cherry picked from commit bd8a1e43aa93d5bb7674cb5a431e7375f7e2f192) + +Bug: 1378564 +Change-Id: I67041b1e2ef08dd0ee1ccbf6d534249c539b74db +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4027242 +Commit-Queue: Robert Sesek +Reviewed-by: Ken Rockot +Cr-Original-Commit-Position: refs/heads/main@{#1071700} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4035114 +Commit-Queue: Rubber Stamper +Auto-Submit: Robert Sesek +Bot-Commit: Rubber Stamper +Cr-Commit-Position: refs/branch-heads/5359@{#881} +Cr-Branched-From: 27d3765d341b09369006d030f83f582a29eb57ae-refs/heads/main@{#1058933} + +diff --git a/mojo/core/channel_mac.cc b/mojo/core/channel_mac.cc +index 686dea5c783af06e41c290b03db251ca584d9a72..a24d5ab4ea9ae63f652acc2f903e577d45b1f0ee 100644 +--- a/mojo/core/channel_mac.cc ++++ b/mojo/core/channel_mac.cc +@@ -25,6 +25,7 @@ + #include "base/mac/scoped_mach_vm.h" + #include "base/message_loop/message_pump_for_io.h" + #include "base/task/current_thread.h" ++#include "base/thread_annotations.h" + #include "base/trace_event/typed_macros.h" + + extern "C" { +@@ -167,7 +168,10 @@ class ChannelMac : public Channel, + vm_allocate(mach_task_self(), &address, size, + VM_MAKE_TAG(VM_MEMORY_MACH_MSG) | VM_FLAGS_ANYWHERE); + MACH_CHECK(kr == KERN_SUCCESS, kr) << "vm_allocate"; +- send_buffer_.reset(address, size); ++ { ++ base::AutoLock lock(write_lock_); ++ send_buffer_.reset(address, size); ++ } + + kr = vm_allocate(mach_task_self(), &address, size, + VM_MAKE_TAG(VM_MEMORY_MACH_MSG) | VM_FLAGS_ANYWHERE); +@@ -207,7 +211,11 @@ class ChannelMac : public Channel, + + watch_controller_.StopWatchingMachPort(); + +- send_buffer_.reset(); ++ { ++ base::AutoLock lock(write_lock_); ++ send_buffer_.reset(); ++ reject_writes_ = true; ++ } + receive_buffer_.reset(); + incoming_handles_.clear(); + +@@ -315,7 +323,7 @@ class ChannelMac : public Channel, + SendPendingMessagesLocked(); + } + +- void SendPendingMessagesLocked() { ++ void SendPendingMessagesLocked() EXCLUSIVE_LOCKS_REQUIRED(write_lock_) { + // If a previous send failed due to the receiver's kernel message queue + // being full, attempt to send that failed message first. + if (send_buffer_contains_message_ && !reject_writes_) { +@@ -342,7 +350,8 @@ class ChannelMac : public Channel, + } + } + +- bool SendMessageLocked(MessagePtr message) { ++ bool SendMessageLocked(MessagePtr message) ++ EXCLUSIVE_LOCKS_REQUIRED(write_lock_) { + DCHECK(!send_buffer_contains_message_); + base::BufferIterator buffer( + reinterpret_cast(send_buffer_.address()), send_buffer_.size()); +@@ -437,7 +446,8 @@ class ChannelMac : public Channel, + return MachMessageSendLocked(header); + } + +- bool MachMessageSendLocked(mach_msg_header_t* header) { ++ bool MachMessageSendLocked(mach_msg_header_t* header) ++ EXCLUSIVE_LOCKS_REQUIRED(write_lock_) { + kern_return_t kr = mach_msg(header, MACH_SEND_MSG | MACH_SEND_TIMEOUT, + header->msgh_size, 0, MACH_PORT_NULL, + /*timeout=*/0, MACH_PORT_NULL); +@@ -659,7 +669,7 @@ class ChannelMac : public Channel, + } + + // Marks the channel as unaccepting of new messages and shuts it down. +- void OnWriteErrorLocked(Error error) { ++ void OnWriteErrorLocked(Error error) EXCLUSIVE_LOCKS_REQUIRED(write_lock_) { + reject_writes_ = true; + io_task_runner_->PostTask( + FROM_HERE, base::BindOnce(&ChannelMac::OnError, this, error)); +@@ -701,17 +711,17 @@ class ChannelMac : public Channel, + // Lock that protects the following members. + base::Lock write_lock_; + // Whether writes should be rejected due to an internal error. +- bool reject_writes_ = false; ++ bool reject_writes_ GUARDED_BY(write_lock_) = false; + // IO buffer for sending Mach messages. +- base::mac::ScopedMachVM send_buffer_; ++ base::mac::ScopedMachVM send_buffer_ GUARDED_BY(write_lock_); + // If a message timed out during send in MachMessageSendLocked(), this will + // be true to indicate that |send_buffer_| contains a message that must + // be sent. If this is true, then other calls to Write() queue messages onto + // |pending_messages_|. +- bool send_buffer_contains_message_ = false; ++ bool send_buffer_contains_message_ GUARDED_BY(write_lock_) = false; + // When |handshake_done_| is false or |send_buffer_contains_message_| is true, + // calls to Write() will enqueue messages here. +- base::circular_deque pending_messages_; ++ base::circular_deque pending_messages_ GUARDED_BY(write_lock_); + }; + + } // namespace +diff --git a/mojo/core/channel_unittest.cc b/mojo/core/channel_unittest.cc +index e9dee384440ee5a0500e86c522eef19c12bd8045..47422267cbaa0d3f90be6adc851a0651c1b74133 100644 +--- a/mojo/core/channel_unittest.cc ++++ b/mojo/core/channel_unittest.cc +@@ -712,6 +712,69 @@ TEST(ChannelTest, SendToDeadMachPortName) { + } + #endif // BUILDFLAG(IS_MAC) + ++TEST(ChannelTest, ShutDownStress) { ++ base::test::SingleThreadTaskEnvironment task_environment( ++ base::test::TaskEnvironment::MainThreadType::IO); ++ ++ // Create a second IO thread for Channel B. ++ base::Thread peer_thread("channel_b_io"); ++ peer_thread.StartWithOptions( ++ base::Thread::Options(base::MessagePumpType::IO, 0)); ++ ++ // Create two channels, A and B, which run on different threads. ++ PlatformChannel platform_channel; ++ ++ CallbackChannelDelegate delegate_a; ++ scoped_refptr channel_a = Channel::Create( ++ &delegate_a, ConnectionParams(platform_channel.TakeLocalEndpoint()), ++ Channel::HandlePolicy::kRejectHandles, ++ task_environment.GetMainThreadTaskRunner()); ++ channel_a->Start(); ++ ++ scoped_refptr channel_b = Channel::Create( ++ nullptr, ConnectionParams(platform_channel.TakeRemoteEndpoint()), ++ Channel::HandlePolicy::kRejectHandles, peer_thread.task_runner()); ++ channel_b->Start(); ++ ++ base::WaitableEvent go_event; ++ ++ // Warm up the channel to ensure that A and B are connected, then quit. ++ channel_b->Write(Channel::Message::CreateMessage(0, 0)); ++ { ++ base::RunLoop run_loop; ++ delegate_a.set_on_message(run_loop.QuitClosure()); ++ run_loop.Run(); ++ } ++ ++ // Block the peer thread while some tasks are queued up from the test main ++ // thread. ++ peer_thread.task_runner()->PostTask( ++ FROM_HERE, ++ base::BindOnce(&base::WaitableEvent::Wait, base::Unretained(&go_event))); ++ ++ // First, write some messages for Channel B. ++ for (int i = 0; i < 500; ++i) { ++ channel_b->Write(Channel::Message::CreateMessage(0, 0)); ++ } ++ ++ // Then shut down channel B. ++ channel_b->ShutDown(); ++ ++ // Un-block the peer thread. ++ go_event.Signal(); ++ ++ // And then flood the channel with messages. This will suss out data races ++ // during Channel B's shutdown, since Writes can happen across threads ++ // without a PostTask. ++ for (int i = 0; i < 1000; ++i) { ++ channel_b->Write(Channel::Message::CreateMessage(0, 0)); ++ } ++ ++ // Explicitly join the thread to wait for pending tasks, which may reference ++ // stack variables, to complete. ++ peer_thread.Stop(); ++} ++ + } // namespace + } // namespace core + } // namespace mojo diff --git a/patches/chromium/cherry-pick-1894458e04a2.patch b/patches/chromium/cherry-pick-1894458e04a2.patch new file mode 100644 index 0000000000000..78650403c8f18 --- /dev/null +++ b/patches/chromium/cherry-pick-1894458e04a2.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Joshua Peraza +Date: Thu, 3 Nov 2022 21:18:35 +0000 +Subject: Validate number of bytes read + +Original commit: +https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3994208 + +(cherry picked from commit 7585111a6c1dfa502f3ca1e3d27aed066e479fd9) + +Bug: chromium:1380083 +Change-Id: If9708ccdbf6957ef169b35f8f89e2b0744d066d7 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4000305 +Reviewed-by: Mark Mentovai +Commit-Queue: Joshua Peraza +Cr-Original-Commit-Position: refs/branch-heads/5359@{#529} +Cr-Original-Branched-From: 27d3765d341b09369006d030f83f582a29eb57ae-refs/heads/main@{#1058933} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4004067 +Cr-Commit-Position: refs/branch-heads/5249@{#905} +Cr-Branched-From: 4f7bea5de862aaa52e6bde5920755a9ef9db120b-refs/heads/main@{#1036826} + +diff --git a/third_party/crashpad/crashpad/util/linux/ptrace_client.cc b/third_party/crashpad/crashpad/util/linux/ptrace_client.cc +index 1863841f73f64d89391646f5c3e5fc2e2766a6cc..32cc35d9567117fe0eb6f1ec4736ac4a15ddfd83 100644 +--- a/third_party/crashpad/crashpad/util/linux/ptrace_client.cc ++++ b/third_party/crashpad/crashpad/util/linux/ptrace_client.cc +@@ -331,6 +331,11 @@ ssize_t PtraceClient::ReadUpTo(VMAddress address, size_t size, void* buffer) { + return total_read; + } + ++ if (static_cast(bytes_read) > size) { ++ LOG(ERROR) << "invalid size " << bytes_read; ++ return -1; ++ } ++ + if (!LoggingReadFileExactly(sock_, buffer_c, bytes_read)) { + return -1; + } diff --git a/patches/chromium/cherry-pick-1eb1e18ad41d.patch b/patches/chromium/cherry-pick-1eb1e18ad41d.patch new file mode 100644 index 0000000000000..62d68c159901e --- /dev/null +++ b/patches/chromium/cherry-pick-1eb1e18ad41d.patch @@ -0,0 +1,184 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Anders Hartvoll Ruud +Date: Tue, 20 Sep 2022 17:43:47 +0000 +Subject: Add CSSTokenizer-created strings to CSSVariableData's backing strings + +When computing the value of a registered custom property, we create +a CSSVariableData object equivalent to the computed CSSValue by +serializing that CSSValue to a String, then tokenizing that value. + +The problem is that CSSTokenizer can create *new* string objects +during the tokenization process (see calls to CSSTokenizer:: +RegisterString), without communicating that fact to the call-site. + +Therefore, this CL adds a way to access those strings so they can +be added to the backing strings of the CSSVariableData. + +Also added a DCHECK to verify that we don't have any tokens with +non-backed string pointers. + +Fixed: 1358907 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3892782 +Reviewed-by: Steinar H Gunderson +Commit-Queue: Anders Hartvoll Ruud +Cr-Original-Commit-Position: refs/heads/main@{#1046868} +Change-Id: Ifb6d194508e99030a5a3ed5fbad5496b7263bdc1 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3905727 +Auto-Submit: Anders Hartvoll Ruud +Cr-Commit-Position: refs/branch-heads/5249@{#518} +Cr-Branched-From: 4f7bea5de862aaa52e6bde5920755a9ef9db120b-refs/heads/main@{#1036826} + +diff --git a/third_party/blink/renderer/core/css/css_variable_data.cc b/third_party/blink/renderer/core/css/css_variable_data.cc +index a2294cc70c59ac0357dddf0f7719cc3c09d23554..b3a61b312eb5f0360e8aa4cb706c60f0085fead9 100644 +--- a/third_party/blink/renderer/core/css/css_variable_data.cc ++++ b/third_party/blink/renderer/core/css/css_variable_data.cc +@@ -4,6 +4,7 @@ + + #include "third_party/blink/renderer/core/css/css_variable_data.h" + ++#include "base/containers/span.h" + #include "third_party/blink/renderer/core/css/css_syntax_definition.h" + #include "third_party/blink/renderer/core/css/parser/css_parser_context.h" + #include "third_party/blink/renderer/platform/wtf/text/character_names.h" +@@ -109,6 +110,51 @@ void CSSVariableData::ConsumeAndUpdateTokens(const CSSParserTokenRange& range) { + UpdateTokens(range, backing_string, tokens_); + } + ++#if EXPENSIVE_DCHECKS_ARE_ON() ++ ++namespace { ++ ++template ++bool IsSubspan(base::span inner, ++ base::span outer) { ++ // Note that base::span uses CheckedContiguousIterator, which restricts ++ // which comparisons are allowed. Therefore we must avoid begin()/end() here. ++ return inner.data() >= outer.data() && ++ (inner.data() + inner.size()) <= (outer.data() + outer.size()); ++} ++ ++bool TokenValueIsBacked(const CSSParserToken& token, ++ const String& backing_string) { ++ StringView value = token.Value(); ++ if (value.Is8Bit() != backing_string.Is8Bit()) ++ return false; ++ return value.Is8Bit() ? IsSubspan(value.Span8(), backing_string.Span8()) ++ : IsSubspan(value.Span16(), backing_string.Span16()); ++} ++ ++bool TokenValueIsBacked(const CSSParserToken& token, ++ const Vector& backing_strings) { ++ DCHECK(token.HasStringBacking()); ++ for (const String& backing_string : backing_strings) { ++ if (TokenValueIsBacked(token, backing_string)) { ++ return true; ++ } ++ } ++ return false; ++} ++ ++} // namespace ++ ++void CSSVariableData::VerifyStringBacking() const { ++ for (const CSSParserToken& token : tokens_) { ++ DCHECK(!token.HasStringBacking() || ++ TokenValueIsBacked(token, backing_strings_)) ++ << "Token value is not backed: " << token.Value().ToString(); ++ } ++} ++ ++#endif // EXPENSIVE_DCHECKS_ARE_ON() ++ + CSSVariableData::CSSVariableData(const CSSTokenizedValue& tokenized_value, + bool is_animation_tainted, + bool needs_variable_resolution, +@@ -120,6 +166,9 @@ CSSVariableData::CSSVariableData(const CSSTokenizedValue& tokenized_value, + base_url_(base_url.IsValid() ? base_url.GetString() : String()), + charset_(charset) { + ConsumeAndUpdateTokens(tokenized_value.range); ++#if EXPENSIVE_DCHECKS_ARE_ON() ++ VerifyStringBacking(); ++#endif // EXPENSIVE_DCHECKS_ARE_ON() + } + + const CSSValue* CSSVariableData::ParseForSyntax( +diff --git a/third_party/blink/renderer/core/css/css_variable_data.h b/third_party/blink/renderer/core/css/css_variable_data.h +index f042f85736c2c49f8337c29cb742976c5e97a14b..7be7d201313ec3e591e2c45c9fd5bda327856645 100644 +--- a/third_party/blink/renderer/core/css/css_variable_data.h ++++ b/third_party/blink/renderer/core/css/css_variable_data.h +@@ -100,11 +100,18 @@ class CORE_EXPORT CSSVariableData : public RefCounted { + has_font_units_(has_font_units), + has_root_font_units_(has_root_font_units), + base_url_(base_url), +- charset_(charset) {} ++ charset_(charset) { ++#if EXPENSIVE_DCHECKS_ARE_ON() ++ VerifyStringBacking(); ++#endif // EXPENSIVE_DCHECKS_ARE_ON() ++ } + CSSVariableData(const CSSVariableData&) = delete; + CSSVariableData& operator=(const CSSVariableData&) = delete; + + void ConsumeAndUpdateTokens(const CSSParserTokenRange&); ++#if EXPENSIVE_DCHECKS_ARE_ON() ++ void VerifyStringBacking() const; ++#endif // EXPENSIVE_DCHECKS_ARE_ON() + + // tokens_ may have raw pointers to string data, we store the String objects + // owning that data in backing_strings_ to keep it alive alongside the +diff --git a/third_party/blink/renderer/core/css/parser/css_tokenizer.h b/third_party/blink/renderer/core/css/parser/css_tokenizer.h +index 817bcbd4b6b9a9a5519bb92d6870c5b16a19278f..682a44a478bcd0ee3aa1638601650fd420033625 100644 +--- a/third_party/blink/renderer/core/css/parser/css_tokenizer.h ++++ b/third_party/blink/renderer/core/css/parser/css_tokenizer.h +@@ -33,6 +33,7 @@ class CORE_EXPORT CSSTokenizer { + wtf_size_t Offset() const { return input_.Offset(); } + wtf_size_t PreviousOffset() const { return prev_offset_; } + StringView StringRangeAt(wtf_size_t start, wtf_size_t length) const; ++ const Vector& StringPool() const { return string_pool_; } + + private: + CSSParserToken TokenizeSingle(); +diff --git a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc +index 6739b9de4b500d6173c04966905e26f856594502..f0082d88d70d4ea76604cfac77c09727de134f2a 100644 +--- a/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc ++++ b/third_party/blink/renderer/core/css/resolver/style_builder_converter.cc +@@ -2176,6 +2176,10 @@ StyleBuilderConverter::ConvertRegisteredPropertyVariableData( + + Vector backing_strings; + backing_strings.push_back(text); ++ // CSSTokenizer may allocate new strings for some tokens (e.g. for escapes) ++ // and produce tokens that point to those strings. We need to retain those ++ // strings (if any) as well. ++ backing_strings.AppendVector(tokenizer.StringPool()); + + const bool has_font_units = false; + const bool has_root_font_units = false; +diff --git a/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/registered-property-computation.html b/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/registered-property-computation.html +index f03b257246e520bd93055203a5cb27188babc8ca..168495247a3b16a2203fb361f662b6db83044d09 100644 +--- a/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/registered-property-computation.html ++++ b/third_party/blink/web_tests/external/wpt/css/css-properties-values-api/registered-property-computation.html +@@ -167,4 +167,6 @@ test_computed_value('', '1dppx', '1dppx'); + test_computed_value('', '96dpi', '1dppx'); + test_computed_value('', 'calc(1dppx + 96dpi)', '2dppx'); + ++test_computed_value('*', 'url(why)', 'url(why)'); ++ + +diff --git a/third_party/blink/web_tests/platform/generic/external/wpt/css/css-properties-values-api/registered-property-computation-expected.txt b/third_party/blink/web_tests/platform/generic/external/wpt/css/css-properties-values-api/registered-property-computation-expected.txt +index 3823a752b99f506d11c50aee36474c6c51c849cd..eeed0dfc0def17b1ba636f7f6a076caf770e1327 100644 +--- a/third_party/blink/web_tests/platform/generic/external/wpt/css/css-properties-values-api/registered-property-computation-expected.txt ++++ b/third_party/blink/web_tests/platform/generic/external/wpt/css/css-properties-values-api/registered-property-computation-expected.txt +@@ -1,5 +1,5 @@ + This is a testharness.js-based test. +-Found 60 tests; 59 PASS, 1 FAIL, 0 TIMEOUT, 0 NOTRUN. ++Found 61 tests; 60 PASS, 1 FAIL, 0 TIMEOUT, 0 NOTRUN. + PASS values computed are correctly via var()-reference + PASS values computed are correctly via var()-reference when font-size is inherited + PASS values are computed correctly when font-size is inherited [14em] +@@ -60,5 +60,6 @@ PASS * values are computed correctly [50dpi] + PASS values are computed correctly [1dppx] + PASS values are computed correctly [96dpi] + FAIL values are computed correctly [calc(1dppx + 96dpi)] assert_equals: expected "2dppx" but got "0dppx" ++PASS * values are computed correctly [url(why)] + Harness: the test ran to completion. + diff --git a/patches/chromium/cherry-pick-2ef09109c0ec.patch b/patches/chromium/cherry-pick-2ef09109c0ec.patch new file mode 100644 index 0000000000000..cb62814f2f575 --- /dev/null +++ b/patches/chromium/cherry-pick-2ef09109c0ec.patch @@ -0,0 +1,364 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jun Kokatsu +Date: Thu, 22 Sep 2022 22:16:55 +0000 +Subject: Unify security check for Javascript URL navigation + +This change unifies CSP and Trusted Types check for Javascript URL +navigations. + +Bug: 1365082 +Change-Id: I46aea31a918c6397ea71fd5ab345bc9dc19d91c2 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3905476 +Auto-Submit: Jun Kokatsu +Commit-Queue: Jun Kokatsu +Reviewed-by: Nate Chapin +Cr-Commit-Position: refs/heads/main@{#1050416} + +diff --git a/third_party/blink/renderer/bindings/core/v8/script_controller.cc b/third_party/blink/renderer/bindings/core/v8/script_controller.cc +index 5ad3d687829db7ed64424b0f593e3aab7951e37e..da289bc7ffc4416ad817b0f344bc24cc0f084582 100644 +--- a/third_party/blink/renderer/bindings/core/v8/script_controller.cc ++++ b/third_party/blink/renderer/bindings/core/v8/script_controller.cc +@@ -164,34 +164,9 @@ void ScriptController::ExecuteJavaScriptURL( + const DOMWrapperWorld* world_for_csp) { + DCHECK(url.ProtocolIsJavaScript()); + +- const int kJavascriptSchemeLength = sizeof("javascript:") - 1; +- String script_source = DecodeURLEscapeSequences( +- url.GetString(), DecodeURLMode::kUTF8OrIsomorphic); +- + if (!window_->GetFrame()) + return; + +- auto* policy = window_->GetContentSecurityPolicyForWorld(world_for_csp); +- if (csp_disposition == network::mojom::CSPDisposition::CHECK && +- !policy->AllowInline(ContentSecurityPolicy::InlineType::kNavigation, +- nullptr, script_source, String() /* nonce */, +- window_->Url(), EventHandlerPosition().line_)) { +- return; +- } +- +- // TODO(crbug.com/896041): Investigate how trusted type checks can be +- // implemented for isolated worlds. +- const bool should_bypass_trusted_type_check = +- csp_disposition == network::mojom::CSPDisposition::DO_NOT_CHECK || +- ContentSecurityPolicy::ShouldBypassMainWorldDeprecated(world_for_csp); +- script_source = script_source.Substring(kJavascriptSchemeLength); +- if (!should_bypass_trusted_type_check) { +- script_source = TrustedTypesCheckForJavascriptURLinNavigation( +- script_source, window_.Get()); +- if (script_source.IsEmpty()) +- return; +- } +- + bool had_navigation_before = + window_->GetFrame()->Loader().HasProvisionalNavigation(); + +@@ -199,6 +174,9 @@ void ScriptController::ExecuteJavaScriptURL( + // Step 6. "Let baseURL be settings's API base URL." [spec text] + const KURL base_url = window_->BaseURL(); + ++ String script_source = window_->CheckAndGetJavascriptUrl( ++ world_for_csp, url, nullptr /* element */, csp_disposition); ++ + // Step 7. "Let script be the result of creating a classic script given + // scriptSource, settings, baseURL, and the default classic script fetch + // options." [spec text] +diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc +index 2f0615ee1454946d6f46f6626ce9b860a0e04fee..3eab00e4410e749aecdf600097cb68df22dcf072 100644 +--- a/third_party/blink/renderer/core/frame/local_dom_window.cc ++++ b/third_party/blink/renderer/core/frame/local_dom_window.cc +@@ -415,6 +415,39 @@ bool LocalDOMWindow::CanExecuteScripts( + return script_enabled; + } + ++String LocalDOMWindow::CheckAndGetJavascriptUrl( ++ const DOMWrapperWorld* world, ++ const KURL& url, ++ Element* element, ++ network::mojom::CSPDisposition csp_disposition) { ++ const int kJavascriptSchemeLength = sizeof("javascript:") - 1; ++ String decoded_url = DecodeURLEscapeSequences( ++ url.GetString(), DecodeURLMode::kUTF8OrIsomorphic); ++ String script_source = decoded_url.Substring(kJavascriptSchemeLength); ++ ++ if (csp_disposition == network::mojom::CSPDisposition::DO_NOT_CHECK) ++ return script_source; ++ ++ // Check the CSP of the caller (the "source browsing context") if required, ++ // as per https://html.spec.whatwg.org/C/#javascript-protocol. ++ if (!GetContentSecurityPolicyForWorld(world)->AllowInline( ++ ContentSecurityPolicy::InlineType::kNavigation, element, decoded_url, ++ String() /* nonce */, Url(), OrdinalNumber::First())) ++ return String(); ++ ++ // TODO(crbug.com/896041): Investigate how trusted type checks can be ++ // implemented for isolated worlds. ++ if (ContentSecurityPolicy::ShouldBypassMainWorldDeprecated(world)) ++ return script_source; ++ ++ // https://w3c.github.io/webappsec-trusted-types/dist/spec/#require-trusted-types-for-pre-navigation-check ++ // 4.9.1.1. require-trusted-types-for Pre-Navigation check ++ script_source = ++ TrustedTypesCheckForJavascriptURLinNavigation(script_source, this); ++ ++ return script_source; ++} ++ + void LocalDOMWindow::ExceptionThrown(ErrorEvent* event) { + MainThreadDebugger::Instance()->ExceptionThrown(this, event); + } +diff --git a/third_party/blink/renderer/core/frame/local_dom_window.h b/third_party/blink/renderer/core/frame/local_dom_window.h +index dcc065abe83948ca3d906f676365226dd82c732d..da06213cfbe2bd156509cd1ff67d600d528c34b0 100644 +--- a/third_party/blink/renderer/core/frame/local_dom_window.h ++++ b/third_party/blink/renderer/core/frame/local_dom_window.h +@@ -31,6 +31,7 @@ + + #include "services/metrics/public/cpp/ukm_recorder.h" + #include "services/metrics/public/cpp/ukm_source_id.h" ++#include "services/network/public/mojom/content_security_policy.mojom-blink.h" + #include "third_party/blink/public/common/frame/fullscreen_request_token.h" + #include "third_party/blink/public/common/frame/payment_request_token.h" + #include "third_party/blink/public/common/metrics/post_message_counter.h" +@@ -211,6 +212,16 @@ class CORE_EXPORT LocalDOMWindow final : public DOMWindow, + mojom::blink::PermissionsPolicyFeature feature, + UseCounterImpl::PermissionsPolicyUsageType type); + ++ // Checks if navigation to Javascript URL is allowed. This check should run ++ // before any action is taken (e.g. creating new window) for all ++ // same-origin navigations. ++ String CheckAndGetJavascriptUrl( ++ const DOMWrapperWorld* world, ++ const KURL& url, ++ Element* element, ++ network::mojom::CSPDisposition csp_disposition = ++ network::mojom::CSPDisposition::CHECK); ++ + Document* InstallNewDocument(const DocumentInit&); + + // EventTarget overrides: +diff --git a/third_party/blink/renderer/core/frame/location.cc b/third_party/blink/renderer/core/frame/location.cc +index a1aeede568cfe33267d87fa68f096d20a83d50f9..92740842827d470d63da34dd90bdb937321c1a83 100644 +--- a/third_party/blink/renderer/core/frame/location.cc ++++ b/third_party/blink/renderer/core/frame/location.cc +@@ -270,23 +270,6 @@ void Location::SetLocation(const String& url, + return; + } + +- // Check the source browsing context's CSP to fulfill the CSP check +- // requirement of https://html.spec.whatwg.org/C/#navigate for javascript +- // URLs. Although the spec states we should perform this check on task +- // execution, there are concerns about the correctness of that statement, +- // see http://github.com/whatwg/html/issues/2591. +- if (completed_url.ProtocolIsJavaScript()) { +- String script_source = DecodeURLEscapeSequences( +- completed_url.GetString(), DecodeURLMode::kUTF8OrIsomorphic); +- if (!incumbent_window->GetContentSecurityPolicyForCurrentWorld() +- ->AllowInline(ContentSecurityPolicy::InlineType::kNavigation, +- nullptr /* element */, script_source, +- String() /* nonce */, incumbent_window->Url(), +- OrdinalNumber::First())) { +- return; +- } +- } +- + V8DOMActivityLogger* activity_logger = + V8DOMActivityLogger::CurrentActivityLoggerIfIsolatedWorld(); + if (activity_logger) { +diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc +index e2398389b2064f0d804977ea9f5233cf34da5dae..49601b48571fbaebda29b6c2848a65275e4fd861 100644 +--- a/third_party/blink/renderer/core/loader/frame_loader.cc ++++ b/third_party/blink/renderer/core/loader/frame_loader.cc +@@ -547,19 +547,12 @@ bool FrameLoader::AllowRequestForThisFrame(const FrameLoadRequest& request) { + + const KURL& url = request.GetResourceRequest().Url(); + if (url.ProtocolIsJavaScript()) { +- // Check the CSP of the caller (the "source browsing context") if required, +- // as per https://html.spec.whatwg.org/C/#javascript-protocol. +- bool javascript_url_is_allowed = +- request.GetOriginWindow() +- ->GetContentSecurityPolicyForWorld(request.JavascriptWorld().get()) +- ->AllowInline(ContentSecurityPolicy::InlineType::kNavigation, +- frame_->DeprecatedLocalOwner(), url.GetString(), +- String() /* nonce */, +- request.GetOriginWindow()->Url(), +- OrdinalNumber::First()); +- +- if (!javascript_url_is_allowed) ++ if (request.GetOriginWindow() ++ ->CheckAndGetJavascriptUrl(request.JavascriptWorld().get(), url, ++ frame_->DeprecatedLocalOwner()) ++ .IsEmpty()) { + return false; ++ } + + if (frame_->Owner() && ((frame_->Owner()->GetFramePolicy().sandbox_flags & + network::mojom::blink::WebSandboxFlags::kOrigin) != +diff --git a/third_party/blink/renderer/core/page/create_window.cc b/third_party/blink/renderer/core/page/create_window.cc +index c526aab02f300a32404253537df6ff6c506664f8..36796587c96a51bc90f460def64358ec9788c72e 100644 +--- a/third_party/blink/renderer/core/page/create_window.cc ++++ b/third_party/blink/renderer/core/page/create_window.cc +@@ -294,15 +294,11 @@ Frame* CreateNewWindow(LocalFrame& opener_frame, + request.SetFrameType(mojom::RequestContextFrameType::kAuxiliary); + + const KURL& url = request.GetResourceRequest().Url(); +- auto* csp_for_world = opener_window.GetContentSecurityPolicyForCurrentWorld(); +- if (url.ProtocolIsJavaScript() && csp_for_world) { +- String script_source = DecodeURLEscapeSequences( +- url.GetString(), DecodeURLMode::kUTF8OrIsomorphic); +- +- if (!csp_for_world->AllowInline( +- ContentSecurityPolicy::InlineType::kNavigation, +- nullptr /* element */, script_source, String() /* nonce */, +- opener_window.Url(), OrdinalNumber::First())) { ++ if (url.ProtocolIsJavaScript()) { ++ if (opener_window ++ .CheckAndGetJavascriptUrl(request.JavascriptWorld().get(), url, ++ nullptr /* element */) ++ .IsEmpty()) { + return nullptr; + } + } +diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/support/frame-without-trusted-types.html b/third_party/blink/web_tests/external/wpt/trusted-types/support/frame-without-trusted-types.html +new file mode 100644 +index 0000000000000000000000000000000000000000..25cf073e79fa48f4311c3729f0b39d9be2a64e7c +--- /dev/null ++++ b/third_party/blink/web_tests/external/wpt/trusted-types/support/frame-without-trusted-types.html +@@ -0,0 +1,6 @@ ++ ++ ++ ++ ++ ++ +diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/support/navigation-report-only-support.html b/third_party/blink/web_tests/external/wpt/trusted-types/support/navigation-report-only-support.html +index d00d0538753a74411feeec42d5682082031c09d4..5f7856fabb7bb16085ffaffffbf6d7553179e8f3 100644 +--- a/third_party/blink/web_tests/external/wpt/trusted-types/support/navigation-report-only-support.html ++++ b/third_party/blink/web_tests/external/wpt/trusted-types/support/navigation-report-only-support.html +@@ -5,7 +5,8 @@ +

Support page for trusted-types-navigation-report-only.*.html tests.

+ link + + +- +diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/support/navigation-support.html b/third_party/blink/web_tests/external/wpt/trusted-types/support/navigation-support.html +index cd41f3968e7c74f84a7541506053808073ce541d..5e02e6d4bf5aff9fa4f0b4b897a35726ed24168b 100644 +--- a/third_party/blink/web_tests/external/wpt/trusted-types/support/navigation-support.html ++++ b/third_party/blink/web_tests/external/wpt/trusted-types/support/navigation-support.html +@@ -5,7 +5,8 @@ +

Support page for trusted-types-navigation.*.html tests.

+ link + + +- +diff --git a/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-navigation.tentative.html b/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-navigation.tentative.html +index 4e784611dd64ecf2f9995403b1d4e5a19f8b4548..2113711902ae787cb3ad5d0e44eaed0fc2e99b87 100644 +--- a/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-navigation.tentative.html ++++ b/third_party/blink/web_tests/external/wpt/trusted-types/trusted-types-navigation.tentative.html +@@ -38,10 +38,10 @@ + }, "Navigate a window with javascript:-urls in enforcing mode."); + + promise_test(t => { +- openWindow(t, "support/navigation-support.html?defaultpolicy"); ++ openWindow(t, "support/navigation-support.html?defaultpolicy=1"); + return Promise.all([ +- expectLoadedAsMessage("navigation-support.html?defaultpolicy"), +- expectLoadedAsMessage("navigation-support.html?defaultpolicy&defaultpolicywashere"), ++ expectLoadedAsMessage("navigation-support.html?defaultpolicy=1"), ++ expectLoadedAsMessage("navigation-support.html?defaultpolicy=1&defaultpolicywashere"), + ]); + }, "Navigate a window with javascript:-urls w/ default policy in enforcing mode."); + +@@ -55,12 +55,46 @@ + }, "Navigate a window with javascript:-urls in report-only mode."); + + promise_test(t => { +- const page = "navigation-report-only-support.html?defaultpolicy"; ++ const page = "navigation-report-only-support.html?defaultpolicy=1"; + openWindow(t, `support/${page}`); + return Promise.all([ + expectLoadedAsMessage(page), +- expectLoadedAsMessage("navigation-support.html?defaultpolicy#defaultpolicywashere"), ++ expectLoadedAsMessage("navigation-support.html?defaultpolicy=1#defaultpolicywashere"), + ]); + }, "Navigate a window with javascript:-urls w/ default policy in report-only mode."); ++ ++ promise_test(t => { ++ openWindow(t, "support/navigation-support.html?frame=1"); ++ return Promise.all([ ++ expectLoadedAsMessage("navigation-support.html?frame=1"), ++ expectViolationAsMessage("Location href"), ++ ]); ++ }, "Navigate a frame with javascript:-urls in enforcing mode."); ++ ++ promise_test(t => { ++ openWindow(t, "support/navigation-support.html?defaultpolicy=1&frame=1"); ++ return Promise.all([ ++ expectLoadedAsMessage("navigation-support.html?defaultpolicy=1&frame=1"), ++ expectLoadedAsMessage("navigation-support.html?defaultpolicy=1&frame=1&defaultpolicywashere"), ++ ]); ++ }, "Navigate a frame with javascript:-urls w/ default policy in enforcing mode."); ++ ++ promise_test(t => { ++ const page = "navigation-report-only-support.html?frame=1" ++ openWindow(t, `support/${page}`); ++ return Promise.all([ ++ expectLoadedAsMessage(page), ++ expectLoadedAsMessage("navigation-support.html?frame=1#continue"), ++ ]); ++ }, "Navigate a frame with javascript:-urls in report-only mode."); ++ ++ promise_test(t => { ++ const page = "navigation-report-only-support.html?defaultpolicy=1&frame=1"; ++ openWindow(t, `support/${page}`); ++ return Promise.all([ ++ expectLoadedAsMessage(page), ++ expectLoadedAsMessage("navigation-support.html?defaultpolicy=1&frame=1#defaultpolicywashere"), ++ ]); ++ }, "Navigate a frame with javascript:-urls w/ default policy in report-only mode."); + + diff --git a/patches/chromium/cherry-pick-42e15c2055c4.patch b/patches/chromium/cherry-pick-42e15c2055c4.patch new file mode 100644 index 0000000000000..5ce89a5cc70b4 --- /dev/null +++ b/patches/chromium/cherry-pick-42e15c2055c4.patch @@ -0,0 +1,115 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Joey Arhar +Date: Tue, 22 Nov 2022 00:12:31 +0000 +Subject: Avoid use-after-free in ValidationMessageOverlayDelegate + +When ValidationMessageOverlayDelegate calls +ForceSynchronousDocumentInstall, it can somehow cause another validation +overlay to be created and delete the ValidationMessageOverlayDelegate. +This patch avoids additional code from being run inside the deleted +ValidationMessageOverlayDelegate. + +(cherry picked from commit a37b66ded21af7ff1442bddd2ec3a0845535b3d6) + +Fixed: 1382581 +Change-Id: I044f91ecb55c77c4a5c40030b6856fc9a8ac7f6f +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4019655 +Reviewed-by: David Baron +Commit-Queue: Joey Arhar +Cr-Original-Commit-Position: refs/heads/main@{#1071652} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4043489 +Commit-Queue: David Baron +Auto-Submit: Joey Arhar +Cr-Commit-Position: refs/branch-heads/5359@{#911} +Cr-Branched-From: 27d3765d341b09369006d030f83f582a29eb57ae-refs/heads/main@{#1058933} + +diff --git a/third_party/blink/renderer/core/page/validation_message_overlay_delegate.cc b/third_party/blink/renderer/core/page/validation_message_overlay_delegate.cc +index 33575769b1fa9361c91d27815832f467f7a7f19c..a8a1df886fd8accfdf9fcf9d06ba24e11f16293a 100644 +--- a/third_party/blink/renderer/core/page/validation_message_overlay_delegate.cc ++++ b/third_party/blink/renderer/core/page/validation_message_overlay_delegate.cc +@@ -85,6 +85,8 @@ ValidationMessageOverlayDelegate::~ValidationMessageOverlayDelegate() { + EventDispatchForbiddenScope::AllowUserAgentEvents allow_events; + page_->WillBeDestroyed(); + } ++ if (destroyed_ptr_) ++ *destroyed_ptr_ = true; + } + + LocalFrameView& ValidationMessageOverlayDelegate::FrameView() const { +@@ -175,7 +177,18 @@ void ValidationMessageOverlayDelegate::CreatePage(const FrameOverlay& overlay) { + WriteDocument(data.get()); + float zoom_factor = anchor_->GetDocument().GetFrame()->PageZoomFactor(); + frame->SetPageZoomFactor(zoom_factor); ++ ++ // ForceSynchronousDocumentInstall can cause another call to ++ // ValidationMessageClientImpl::ShowValidationMessage, which will hide this ++ // validation message and may even delete this. In order to avoid continuing ++ // when this is destroyed, |destroyed| will be set to true in the destructor. ++ bool destroyed = false; ++ DCHECK(!destroyed_ptr_); ++ destroyed_ptr_ = &destroyed; + frame->ForceSynchronousDocumentInstall("text/html", data); ++ if (destroyed) ++ return; ++ destroyed_ptr_ = nullptr; + + Element& main_message = GetElementById("main-message"); + main_message.setTextContent(message_); +diff --git a/third_party/blink/renderer/core/page/validation_message_overlay_delegate.h b/third_party/blink/renderer/core/page/validation_message_overlay_delegate.h +index 9db786a4fbd12bc6aeefc520143f872965ad7df8..26e96d8ffad11938dcc3dc5b059f2c7ebf077b94 100644 +--- a/third_party/blink/renderer/core/page/validation_message_overlay_delegate.h ++++ b/third_party/blink/renderer/core/page/validation_message_overlay_delegate.h +@@ -72,6 +72,10 @@ class CORE_EXPORT ValidationMessageOverlayDelegate + String sub_message_; + TextDirection message_dir_; + TextDirection sub_message_dir_; ++ ++ // Used by CreatePage() to determine if this has been deleted in the middle of ++ // the function. ++ bool* destroyed_ptr_ = nullptr; + }; + + } // namespace blink +diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/constraints/reportValidity-crash.html b/third_party/blink/web_tests/external/wpt/html/semantics/forms/constraints/reportValidity-crash.html +new file mode 100644 +index 0000000000000000000000000000000000000000..d6bab924adc9fb481235af10d706cbf4d4ef2df9 +--- /dev/null ++++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/constraints/reportValidity-crash.html +@@ -0,0 +1,37 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++
++ ++ ++ ++ ++ ++ ++ diff --git a/patches/chromium/cherry-pick-43637378b14e.patch b/patches/chromium/cherry-pick-43637378b14e.patch new file mode 100644 index 0000000000000..988e7983bb655 --- /dev/null +++ b/patches/chromium/cherry-pick-43637378b14e.patch @@ -0,0 +1,104 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Maks Orlovich +Date: Tue, 22 Nov 2022 22:18:55 +0000 +Subject: Align NetworkContext::SetNetworkConditions better with devtools + emulateNetworkConditions + +The former used values of 0 to disable particular throttles, while the +later documents -1, and looks to be pretty much a direct client, and the +only one. So make NetworkService handle everything <= 0 as a disable, +clamping at intake of config. + +Bug: 1382033 + +(cherry picked from commit ce463c2c939818a12bbcec5e2c91c35f2a0a1f0e) + +Change-Id: I2fd3f075d5071cb0cf647838782115b5c00405bf +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4035891 +Reviewed-by: Ken Buchanan +Reviewed-by: Eric Orth +Commit-Queue: Maks Orlovich +Cr-Original-Commit-Position: refs/heads/main@{#1073566} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4048289 +Cr-Commit-Position: refs/branch-heads/5414@{#188} +Cr-Branched-From: 4417ee59d7bf6df7a9c9ea28f7722d2ee6203413-refs/heads/main@{#1070088} + +diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom +index b6a2ed2857ee9cb838542d76a5c3031a28483a8b..7f41b5a1cf98576bce93b14196cf7dfabf7aaa93 100644 +--- a/services/network/public/mojom/network_context.mojom ++++ b/services/network/public/mojom/network_context.mojom +@@ -554,11 +554,11 @@ struct NetworkConditions { + // response received. + mojo_base.mojom.TimeDelta latency; + +- // Maximal aggregated download throughput (bytes/sec). 0 disables download ++ // Maximal aggregated download throughput (bytes/sec). <=0 disables download + // throttling. + double download_throughput; + +- // Maximal aggregated upload throughput (bytes/sec). 0 disables upload ++ // Maximal aggregated upload throughput (bytes/sec). <=0 disables upload + // throttling. + double upload_throughput; + }; +diff --git a/services/network/throttling/network_conditions.cc b/services/network/throttling/network_conditions.cc +index 71cd4ac0e52cc1f262c5b58caf20448b57b6b64f..18b2b6e0efdc2e17dbbbfaa411b4ab49ec787bc4 100644 +--- a/services/network/throttling/network_conditions.cc ++++ b/services/network/throttling/network_conditions.cc +@@ -4,6 +4,8 @@ + + #include "services/network/throttling/network_conditions.h" + ++#include ++ + namespace network { + + NetworkConditions::NetworkConditions() : NetworkConditions(false) {} +@@ -16,9 +18,9 @@ NetworkConditions::NetworkConditions(bool offline, + double download_throughput, + double upload_throughput) + : offline_(offline), +- latency_(latency), +- download_throughput_(download_throughput), +- upload_throughput_(upload_throughput) {} ++ latency_(std::max(latency, 0.0)), ++ download_throughput_(std::max(download_throughput, 0.0)), ++ upload_throughput_(std::max(upload_throughput, 0.0)) {} + + NetworkConditions::~NetworkConditions() {} + +diff --git a/services/network/throttling/network_conditions.h b/services/network/throttling/network_conditions.h +index f8c8214b34bafcb1f656dd3a39a0cf17fea821ea..c5232231d308b09105234101f4bc575491505372 100644 +--- a/services/network/throttling/network_conditions.h ++++ b/services/network/throttling/network_conditions.h +@@ -28,6 +28,8 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkConditions { + bool IsThrottling() const; + + bool offline() const { return offline_; } ++ ++ // These are 0 if the corresponding throttle is disabled, >0 otherwise. + double latency() const { return latency_; } + double download_throughput() const { return download_throughput_; } + double upload_throughput() const { return upload_throughput_; } +diff --git a/services/network/throttling/throttling_controller_unittest.cc b/services/network/throttling/throttling_controller_unittest.cc +index fbe2c6d20d1d5362a77bd951e87b3fe41be13098..e834f8bdc13b5691b1e458dcafead482a0537e14 100644 +--- a/services/network/throttling/throttling_controller_unittest.cc ++++ b/services/network/throttling/throttling_controller_unittest.cc +@@ -297,7 +297,7 @@ TEST(ThrottlingControllerTest, DownloadOnly) { + ThrottlingControllerTestHelper helper; + TestCallback* callback = helper.callback(); + +- helper.SetNetworkState(false, 10000000, 0); ++ helper.SetNetworkState(false, 10000000, -1); + int rv = helper.Start(false); + EXPECT_EQ(rv, net::ERR_IO_PENDING); + helper.FastForwardUntilNoTasksRemain(); +@@ -316,7 +316,7 @@ TEST(ThrottlingControllerTest, UploadOnly) { + ThrottlingControllerTestHelper helper; + TestCallback* callback = helper.callback(); + +- helper.SetNetworkState(false, 0, 1000000); ++ helper.SetNetworkState(false, -2, 1000000); + int rv = helper.Start(true); + EXPECT_EQ(rv, net::OK); + helper.FastForwardUntilNoTasksRemain(); diff --git a/patches/chromium/cherry-pick-65ad70274d4b.patch b/patches/chromium/cherry-pick-65ad70274d4b.patch new file mode 100644 index 0000000000000..9dcb5c1b5c314 --- /dev/null +++ b/patches/chromium/cherry-pick-65ad70274d4b.patch @@ -0,0 +1,78 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ilya Nikolaevskiy +Date: Mon, 14 Nov 2022 12:33:49 +0000 +Subject: Fix UAF in VideoCaptureDeviceWin::FrameReceived + +(cherry picked from commit d08a3822658cb4ca4261659f1487069a14b51bd9) + +Bug: 1381401 +Change-Id: Ib742ec7b86d3c419f37f12694bf9cd5f3f03305c +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4013158 +Reviewed-by: Markus Handell +Commit-Queue: Ilya Nikolaevskiy +Cr-Original-Commit-Position: refs/heads/main@{#1069054} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4023295 +Cr-Commit-Position: refs/branch-heads/5359@{#809} +Cr-Branched-From: 27d3765d341b09369006d030f83f582a29eb57ae-refs/heads/main@{#1058933} + +diff --git a/media/capture/video/win/video_capture_device_win.cc b/media/capture/video/win/video_capture_device_win.cc +index df0aef940a007a594c328f10a2ea26e1d381505f..b220ded61ed5c501426ccc5c128dd4494c448b2f 100644 +--- a/media/capture/video/win/video_capture_device_win.cc ++++ b/media/capture/video/win/video_capture_device_win.cc +@@ -866,34 +866,35 @@ void VideoCaptureDeviceWin::FrameReceived(const uint8_t* buffer, + const VideoCaptureFormat& format, + base::TimeDelta timestamp, + bool flip_y) { ++ // We always calculate camera rotation for the first frame. We also cache ++ // the latest value to use when AutoRotation is turned off. ++ // To avoid potential deadlock, do this without holding a lock. ++ if (!camera_rotation_.has_value() || IsAutoRotationEnabled()) ++ camera_rotation_ = GetCameraRotation(device_descriptor_.facing); ++ + { + base::AutoLock lock(lock_); + if (state_ != kCapturing) + return; +- } + +- if (first_ref_time_.is_null()) +- first_ref_time_ = base::TimeTicks::Now(); ++ if (first_ref_time_.is_null()) ++ first_ref_time_ = base::TimeTicks::Now(); + +- // There is a chance that the platform does not provide us with the timestamp, +- // in which case, we use reference time to calculate a timestamp. +- if (timestamp == kNoTimestamp) +- timestamp = base::TimeTicks::Now() - first_ref_time_; ++ // There is a chance that the platform does not provide us with the ++ // timestamp, in which case, we use reference time to calculate a timestamp. ++ if (timestamp == kNoTimestamp) ++ timestamp = base::TimeTicks::Now() - first_ref_time_; + +- // We always calculate camera rotation for the first frame. We also cache the +- // latest value to use when AutoRotation is turned off. +- if (!camera_rotation_.has_value() || IsAutoRotationEnabled()) +- camera_rotation_ = GetCameraRotation(device_descriptor_.facing); +- +- // TODO(julien.isorce): retrieve the color space information using the +- // DirectShow api, AM_MEDIA_TYPE::VIDEOINFOHEADER2::dwControlFlags. If +- // AMCONTROL_COLORINFO_PRESENT, then reinterpret dwControlFlags as a +- // DXVA_ExtendedFormat. Then use its fields DXVA_VideoPrimaries, +- // DXVA_VideoTransferMatrix, DXVA_VideoTransferFunction and +- // DXVA_NominalRangeto build a gfx::ColorSpace. See http://crbug.com/959992. +- client_->OnIncomingCapturedData(buffer, length, format, gfx::ColorSpace(), +- camera_rotation_.value(), flip_y, +- base::TimeTicks::Now(), timestamp); ++ // TODO(julien.isorce): retrieve the color space information using the ++ // DirectShow api, AM_MEDIA_TYPE::VIDEOINFOHEADER2::dwControlFlags. If ++ // AMCONTROL_COLORINFO_PRESENT, then reinterpret dwControlFlags as a ++ // DXVA_ExtendedFormat. Then use its fields DXVA_VideoPrimaries, ++ // DXVA_VideoTransferMatrix, DXVA_VideoTransferFunction and ++ // DXVA_NominalRangeto build a gfx::ColorSpace. See http://crbug.com/959992. ++ client_->OnIncomingCapturedData(buffer, length, format, gfx::ColorSpace(), ++ camera_rotation_.value(), flip_y, ++ base::TimeTicks::Now(), timestamp); ++ } + + while (!take_photo_callbacks_.empty()) { + TakePhotoCallback cb = std::move(take_photo_callbacks_.front()); diff --git a/patches/chromium/cherry-pick-65d46507a0c9.patch b/patches/chromium/cherry-pick-65d46507a0c9.patch new file mode 100644 index 0000000000000..a4e71769135dc --- /dev/null +++ b/patches/chromium/cherry-pick-65d46507a0c9.patch @@ -0,0 +1,115 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: evliu +Date: Mon, 14 Nov 2022 20:05:12 +0000 +Subject: Replace raw pointer to LocalMuter with weak ptr + +This CL replaces a raw pointer to LocalMuter with a weak ptr. Additional +info about this bug here: http://crbug/1377783 + +(cherry picked from commit 9989b93eb12c93b9351d5bf2872c1069ef5f7d01) + +Bug: 1377783 +Change-Id: Id821ea800ba12f1cfae4677fc591c12dec112852 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3997421 +Reviewed-by: Paul Semel +Reviewed-by: Olga Sharonova +Commit-Queue: Evan Liu +Cr-Original-Commit-Position: refs/heads/main@{#1068776} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4024547 +Auto-Submit: Evan Liu +Owners-Override: Srinivas Sista +Bot-Commit: Rubber Stamper +Commit-Queue: Rubber Stamper +Reviewed-by: Evan Liu +Cr-Commit-Position: refs/branch-heads/5359@{#824} +Cr-Branched-From: 27d3765d341b09369006d030f83f582a29eb57ae-refs/heads/main@{#1058933} + +diff --git a/services/audio/local_muter.h b/services/audio/local_muter.h +index a484c7dfd60883b07c8fc61da768edf508ac53af..b108e32306a264be4d51027c4419efc70a5dbe0c 100644 +--- a/services/audio/local_muter.h ++++ b/services/audio/local_muter.h +@@ -7,6 +7,7 @@ + + #include "base/callback.h" + #include "base/memory/raw_ptr.h" ++#include "base/memory/weak_ptr.h" + #include "base/sequence_checker.h" + #include "base/unguessable_token.h" + #include "media/mojo/mojom/audio_stream_factory.mojom.h" +@@ -46,6 +47,8 @@ class LocalMuter final : public media::mojom::LocalMuter, + + bool HasReceivers() { return !receivers_.empty(); } + ++ base::WeakPtr GetWeakPtr() { return weak_factory_.GetWeakPtr(); } ++ + private: + // Runs the |all_bindings_lost_callback_| when |bindings_| becomes empty. + void OnBindingLost(); +@@ -57,6 +60,8 @@ class LocalMuter final : public media::mojom::LocalMuter, + base::RepeatingClosure all_bindings_lost_callback_; + + SEQUENCE_CHECKER(sequence_checker_); ++ ++ base::WeakPtrFactory weak_factory_{this}; + }; + + } // namespace audio +diff --git a/services/audio/stream_factory.cc b/services/audio/stream_factory.cc +index 48152cb64769ab1a76920d2581f373b57fef85c9..60ff2766809d4c43c021e47cfa5087b9dbe089b8 100644 +--- a/services/audio/stream_factory.cc ++++ b/services/audio/stream_factory.cc +@@ -181,8 +181,9 @@ void StreamFactory::BindMuter( + if (it == muters_.end()) { + auto muter_ptr = std::make_unique(&coordinator_, group_id); + muter = muter_ptr.get(); +- muter->SetAllBindingsLostCallback(base::BindRepeating( +- &StreamFactory::DestroyMuter, base::Unretained(this), muter)); ++ muter->SetAllBindingsLostCallback( ++ base::BindRepeating(&StreamFactory::DestroyMuter, ++ base::Unretained(this), muter_ptr->GetWeakPtr())); + muters_.emplace_back(std::move(muter_ptr)); + } else { + muter = it->get(); +@@ -254,9 +255,10 @@ void StreamFactory::DestroyOutputStream(OutputStream* stream) { + DCHECK_EQ(1u, erased); + } + +-void StreamFactory::DestroyMuter(LocalMuter* muter) { ++void StreamFactory::DestroyMuter(base::WeakPtr muter) { + DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_); +- DCHECK(muter); ++ if (!muter) ++ return; + + // Output streams have a task posting before destruction (see the OnError + // function in output_stream.cc). To ensure that stream destruction and +@@ -265,13 +267,11 @@ void StreamFactory::DestroyMuter(LocalMuter* muter) { + // Otherwise, a "destroy all streams, then destroy the muter" sequence may + // result in a brief blip of audio. + auto do_destroy = [](base::WeakPtr weak_this, +- LocalMuter* muter) { +- if (weak_this) { +- ++ base::WeakPtr muter) { ++ if (weak_this && muter) { + const auto it = + std::find_if(weak_this->muters_.begin(), weak_this->muters_.end(), +- base::MatchesUniquePtr(muter)); +- DCHECK(it != weak_this->muters_.end()); ++ base::MatchesUniquePtr(muter.get())); + + // The LocalMuter can still have receivers if a receiver was bound after + // DestroyMuter is called but before the do_destroy task is run. +diff --git a/services/audio/stream_factory.h b/services/audio/stream_factory.h +index 2207c72cb39e666e5c207016035a9d295d708aa0..b6119025f043e433455b35ee71e2b130299d1d21 100644 +--- a/services/audio/stream_factory.h ++++ b/services/audio/stream_factory.h +@@ -110,7 +110,7 @@ class StreamFactory final : public media::mojom::AudioStreamFactory { + + void DestroyInputStream(InputStream* stream); + void DestroyOutputStream(OutputStream* stream); +- void DestroyMuter(LocalMuter* muter); ++ void DestroyMuter(base::WeakPtr muter); + void DestroyLoopbackStream(LoopbackStream* stream); + + SEQUENCE_CHECKER(owning_sequence_); diff --git a/patches/chromium/cherry-pick-65f0ef609c00.patch b/patches/chromium/cherry-pick-65f0ef609c00.patch new file mode 100644 index 0000000000000..ccfbedad325fa --- /dev/null +++ b/patches/chromium/cherry-pick-65f0ef609c00.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andy Paicu +Date: Thu, 6 Oct 2022 21:04:23 +0000 +Subject: Fix UAF issue around permission status observer list + +(cherry picked from commit 4df595127d95d4b0bf115be1ab4604d95b75273c) + +(cherry picked from commit 1dc5dda6112bdd811c923520cc728a474583409e) + +Bug: 1363040 +Change-Id: I1f64a901b83aa834ae652c8041456e9b7d253c1f +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3907744 +Reviewed-by: Kamila Hasanbega +Commit-Queue: Andy Paicu +Cr-Original-Original-Commit-Position: refs/heads/main@{#1049058} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3929034 +Reviewed-by: Illia Klimov +Cr-Original-Commit-Position: refs/branch-heads/5304@{#483} +Cr-Original-Branched-From: 5d7b1fc9cb7103d9c82eed647cf4be38cf09738b-refs/heads/main@{#1047731} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3936291 +Bot-Commit: Rubber Stamper +Cr-Commit-Position: refs/branch-heads/5249@{#764} +Cr-Branched-From: 4f7bea5de862aaa52e6bde5920755a9ef9db120b-refs/heads/main@{#1036826} + +diff --git a/third_party/blink/renderer/modules/permissions/permission_status_listener.cc b/third_party/blink/renderer/modules/permissions/permission_status_listener.cc +index 424314c1dd49bd693643e41adb537f7a9d01e5d2..946e28ac3139a1927ac36281f04cec9f5faf76d2 100644 +--- a/third_party/blink/renderer/modules/permissions/permission_status_listener.cc ++++ b/third_party/blink/renderer/modules/permissions/permission_status_listener.cc +@@ -62,7 +62,17 @@ void PermissionStatusListener::OnPermissionStatusChange( + + status_ = status; + ++ // The `observers_` list can change in response to permission status change ++ // events as the observers map to PermissionStatus JS objects which can be ++ // created and destroyed in the JS event handler function. To avoid UAF and ++ // list modification issues, a temporary snapshot of the observers is made and ++ // used instead. ++ HeapHashSet> observers; + for (const auto& observer : observers_) { ++ observers.insert(observer); ++ } ++ ++ for (const auto& observer : observers) { + if (observer) + observer->OnPermissionStatusChange(status); + else diff --git a/patches/chromium/cherry-pick-67c9cbc784d6.patch b/patches/chromium/cherry-pick-67c9cbc784d6.patch new file mode 100644 index 0000000000000..4c2ead4e456a1 --- /dev/null +++ b/patches/chromium/cherry-pick-67c9cbc784d6.patch @@ -0,0 +1,622 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lukasz Anforowicz +Date: Tue, 30 Aug 2022 19:18:15 +0000 +Subject: Validate `source_context` in ExtensionHostMsg_OpenChannelToNativeApp. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +After this CL, the Browser process will verify `source_context` in the +IPC payload of the ExtensionHostMsg_OpenChannelToNativeApp message and +avoid processing malformed or spoofed IPCs. + +Change-Id: I9466dc076c4d07dbb4bec38973000dc0418565f6 +Bug: 1356234 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3854987 +Commit-Queue: Łukasz Anforowicz +Reviewed-by: Devlin Cronin +Cr-Commit-Position: refs/heads/main@{#1041118} + +diff --git a/chrome/browser/extensions/extension_security_exploit_browsertest.cc b/chrome/browser/extensions/extension_security_exploit_browsertest.cc +index 19c9c52fa5a796c93e80f77029727d64acfdfa07..4e5215739f8533d25831f3302515861df179525f 100644 +--- a/chrome/browser/extensions/extension_security_exploit_browsertest.cc ++++ b/chrome/browser/extensions/extension_security_exploit_browsertest.cc +@@ -10,6 +10,7 @@ + #include "base/memory/scoped_refptr.h" + #include "base/memory/weak_ptr.h" + #include "base/test/bind.h" ++#include "build/build_config.h" + #include "chrome/browser/chrome_content_browser_client.h" + #include "chrome/browser/extensions/extension_browsertest.h" + #include "chrome/browser/extensions/extension_tab_util.h" +@@ -40,6 +41,10 @@ + #include "third_party/blink/public/mojom/service_worker/service_worker_database.mojom-forward.h" + #include "url/gurl.h" + ++#if !(BUILDFLAG(IS_FUCHSIA)) ++#include "chrome/browser/extensions/api/messaging/native_messaging_test_util.h" ++#endif ++ + namespace extensions { + + // Waits for a kill of the given RenderProcessHost and returns the +@@ -233,6 +238,10 @@ class OpenChannelToExtensionExploitTest : public ExtensionBrowserTest { + return ipc_message_waiter_->WaitForMessage(); + } + ++ content::WebContents* active_web_contents() { ++ return browser()->tab_strip_model()->GetActiveWebContents(); ++ } ++ + // Asks the `extension_id` to inject `content_script` into `web_contents`. + // Returns true if the content script execution started successfully. + bool ExecuteProgrammaticContentScript(content::WebContents* web_contents, +@@ -246,63 +255,86 @@ class OpenChannelToExtensionExploitTest : public ExtensionBrowserTest { + browser()->profile(), extension_id, background_script); + } + ++ const Extension& active_extension() { return *active_extension_; } + const ExtensionId& active_extension_id() { return active_extension_->id(); } + + const ExtensionId& spoofed_extension_id() { return spoofed_extension_->id(); } + + private: ++ // Installs an `active_extension` and a separate, but otherwise identical ++ // `spoofed_extension` (the only difference will be the extension id). + void InstallTestExtensions() { +- // Install an `active_extension` and a separate, but otherwise identical +- // `spoofed_extension` (the only difference will be the extension id). +- auto install_extension = [this](TestExtensionDir& dir) -> const Extension* { ++ auto install_extension = ++ [this](TestExtensionDir& dir, ++ const char* extra_manifest_bits) -> const Extension* { + const char kManifestTemplate[] = R"( + { ++ %s + "name": "ContentScriptTrackerBrowserTest - Programmatic", + "version": "1.0", + "manifest_version": 2, +- "permissions": [ "tabs", "" ], ++ "permissions": [ ++ "tabs", ++ "", ++ "nativeMessaging" ++ ], + "background": {"scripts": ["background_script.js"]} + } )"; +- dir.WriteManifest(kManifestTemplate); ++ dir.WriteManifest( ++ base::StringPrintf(kManifestTemplate, extra_manifest_bits)); + dir.WriteFile(FILE_PATH_LITERAL("background_script.js"), ""); ++ dir.WriteFile(FILE_PATH_LITERAL("page.html"), "

page

"); + return LoadExtension(dir.UnpackedPath()); + }; +- TestExtensionDir active_dir; +- TestExtensionDir spoofed_dir; +- active_extension_ = install_extension(active_dir); +- spoofed_extension_ = install_extension(spoofed_dir); ++#if !(BUILDFLAG(IS_FUCHSIA)) ++ // The key below corresponds to the extension ID used by ++ // ScopedTestNativeMessagingHost::kExtensionId. ++ const char kActiveExtensionKey[] = R"( ++ "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcBHwzDvyBQ6bDppkIs9MP4ksKqCMyXQ/A52JivHZKh4YO/9vJsT3oaYhSpDCE9RPocOEQvwsHsFReW2nUEc6OLLyoCFFxIb7KkLGsmfakkut/fFdNJYh0xOTbSN8YvLWcqph09XAY2Y/f0AL7vfO1cuCqtkMt8hFrBGWxDdf9CQIDAQAB", ++ )"; ++#else ++ // Native messaging is not available on Fuchsia (i.e. ++ // //chrome/browser/extensions/BUILD.gn excludes ++ // api/messaging/native_messaging_test_util.h on Fuchsia). ++ const char kActiveExtensionKey[] = ""; ++#endif ++ active_extension_ = install_extension(active_dir_, kActiveExtensionKey); ++ spoofed_extension_ = install_extension(spoofed_dir_, ""); + ASSERT_TRUE(active_extension_); + ASSERT_TRUE(spoofed_extension_); ++#if !(BUILDFLAG(IS_FUCHSIA)) ++ ASSERT_EQ(active_extension_id(), ++ ScopedTestNativeMessagingHost::kExtensionId); ++#endif + ASSERT_NE(active_extension_id(), spoofed_extension_id()); + } + + using OpenChannelMessageWaiter = + ExtensionMessageWaiter; +- std::unique_ptr StartInterceptingIpcs( +- const GURL& test_page_url) { + // Start capturing IPC messages in all future/new RenderProcessHosts. +- auto ipc_message_waiter = std::make_unique(); ++ ipc_message_waiter_ = std::make_unique(); + + // Navigate to an arbitrary, mostly empty test page. Make sure that a new + // RenderProcessHost is created to make sure it is covered by the +- // `ipc_message_waiter`. (A WebUI -> http navigation should swap the ++ // `ipc_message_waiter_`. (A WebUI -> http navigation should swap the + // RenderProcessHost on all platforms.) +- content::WebContents* web_contents = +- browser()->tab_strip_model()->GetActiveWebContents(); ++ GURL test_page_url = ++ embedded_test_server()->GetURL("foo.com", "/title1.html"); + int old_process_id = +- web_contents->GetPrimaryMainFrame()->GetProcess()->GetID(); ++ active_web_contents()->GetPrimaryMainFrame()->GetProcess()->GetID(); + EXPECT_TRUE( + ui_test_utils::NavigateToURL(browser(), GURL("chrome://version"))); + EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), test_page_url)); + int new_process_id = +- web_contents->GetPrimaryMainFrame()->GetProcess()->GetID(); ++ active_web_contents()->GetPrimaryMainFrame()->GetProcess()->GetID(); + EXPECT_NE(old_process_id, new_process_id); + + // Only intercept messages from `active_extension`'s content script running + // in the main frame's process. + std::string matching_extension_id = active_extension_id(); +- int matching_process_id = new_process_id; +- ipc_message_waiter->SetIpcMatcher(base::BindLambdaForTesting( ++ int matching_process_id = ++ active_web_contents()->GetPrimaryMainFrame()->GetProcess()->GetID(); ++ ipc_message_waiter_->SetIpcMatcher(base::BindLambdaForTesting( + [matching_extension_id, matching_process_id]( + int captured_render_process_id, + const ExtensionHostMsg_OpenChannelToExtension::Param& param) { +@@ -319,12 +351,19 @@ class OpenChannelToExtensionExploitTest : public ExtensionBrowserTest { + + return true; + })); ++ } + +- return ipc_message_waiter; ++ // Waits for ExtensionHostMsg_OpenChannelToExtension IPC and returns its ++ // payload. ++ ExtensionHostMsg_OpenChannelToExtension::Param WaitForMessage() { ++ return ipc_message_waiter_->WaitForMessage(); + } + ++ private: + std::unique_ptr ipc_message_waiter_; + ++ TestExtensionDir active_dir_; ++ TestExtensionDir spoofed_dir_; + raw_ptr active_extension_ = nullptr; + raw_ptr spoofed_extension_ = nullptr; + }; +@@ -340,24 +379,22 @@ IN_PROC_BROWSER_TEST_F(OpenChannelToExtensionExploitTest, + + // Trigger sending of a valid ExtensionHostMsg_OpenChannelToExtension IPC + // from a content script of an `active_extension_id`. +- content::WebContents* web_contents = +- browser()->tab_strip_model()->GetActiveWebContents(); + ASSERT_TRUE(ExecuteProgrammaticContentScript( +- web_contents, active_extension_id(), ++ active_web_contents(), active_extension_id(), + "chrome.runtime.sendMessage({greeting: 'hello'}, (response) => {});")); + + // Capture the IPC. + auto [source_context, info, channel_name, port_id] = WaitForMessage(); +- +- // Mutate the IPC payload. + EXPECT_EQ(MessagingEndpoint::Type::kTab, info.source_endpoint.type); + EXPECT_EQ(active_extension_id(), info.source_endpoint.extension_id); ++ ++ // Mutate the IPC payload. + info.source_endpoint.extension_id = spoofed_extension_id(); + + // Inject the malformed/mutated IPC and verify that the renderer is terminated + // as expected. + content::RenderProcessHost* main_frame_process = +- web_contents->GetPrimaryMainFrame()->GetProcess(); ++ active_web_contents()->GetPrimaryMainFrame()->GetProcess(); + RenderProcessHostBadIpcMessageWaiter kill_waiter(main_frame_process); + IPC::IpcSecurityTestUtil::PwnMessageReceived( + main_frame_process->GetChannel(), +@@ -371,24 +408,22 @@ IN_PROC_BROWSER_TEST_F(OpenChannelToExtensionExploitTest, + FromContentScript_UnexpectedNativeAppType) { + // Trigger sending of a valid ExtensionHostMsg_OpenChannelToExtension IPC + // from a content script of an `active_extension_id`. +- content::WebContents* web_contents = +- browser()->tab_strip_model()->GetActiveWebContents(); + ASSERT_TRUE(ExecuteProgrammaticContentScript( +- web_contents, active_extension_id(), ++ active_web_contents(), active_extension_id(), + "chrome.runtime.sendMessage({greeting: 'hello'}, (response) => {});")); + + // Capture the IPC. + auto [source_context, info, channel_name, port_id] = WaitForMessage(); +- +- // Mutate the IPC payload. + EXPECT_EQ(MessagingEndpoint::Type::kTab, info.source_endpoint.type); + EXPECT_EQ(active_extension_id(), info.source_endpoint.extension_id); ++ ++ // Mutate the IPC payload. + info.source_endpoint.type = MessagingEndpoint::Type::kNativeApp; + + // Inject the malformed/mutated IPC and verify that the renderer is terminated + // as expected. + content::RenderProcessHost* main_frame_process = +- web_contents->GetPrimaryMainFrame()->GetProcess(); ++ active_web_contents()->GetPrimaryMainFrame()->GetProcess(); + RenderProcessHostBadIpcMessageWaiter kill_waiter(main_frame_process); + IPC::IpcSecurityTestUtil::PwnMessageReceived( + main_frame_process->GetChannel(), +@@ -401,24 +436,22 @@ IN_PROC_BROWSER_TEST_F(OpenChannelToExtensionExploitTest, + FromContentScript_UnexpectedExtensionType) { + // Trigger sending of a valid ExtensionHostMsg_OpenChannelToExtension IPC + // from a content script of an `active_extension_id`. +- content::WebContents* web_contents = +- browser()->tab_strip_model()->GetActiveWebContents(); + ASSERT_TRUE(ExecuteProgrammaticContentScript( +- web_contents, active_extension_id(), ++ active_web_contents(), active_extension_id(), + "chrome.runtime.sendMessage({greeting: 'hello'}, (response) => {});")); + + // Capture the IPC. + auto [source_context, info, channel_name, port_id] = WaitForMessage(); +- +- // Mutate the IPC payload. + EXPECT_EQ(MessagingEndpoint::Type::kTab, info.source_endpoint.type); + EXPECT_EQ(active_extension_id(), info.source_endpoint.extension_id); ++ ++ // Mutate the IPC payload. + info.source_endpoint.type = MessagingEndpoint::Type::kExtension; + + // Inject the malformed/mutated IPC and verify that the renderer is terminated + // as expected. + content::RenderProcessHost* main_frame_process = +- web_contents->GetPrimaryMainFrame()->GetProcess(); ++ active_web_contents()->GetPrimaryMainFrame()->GetProcess(); + RenderProcessHostBadIpcMessageWaiter kill_waiter(main_frame_process); + IPC::IpcSecurityTestUtil::PwnMessageReceived( + main_frame_process->GetChannel(), +@@ -432,25 +465,23 @@ IN_PROC_BROWSER_TEST_F(OpenChannelToExtensionExploitTest, + FromContentScript_NoExtensionIdForExtensionType) { + // Trigger sending of a valid ExtensionHostMsg_OpenChannelToExtension IPC + // from a content script of an `active_extension_id`. +- content::WebContents* web_contents = +- browser()->tab_strip_model()->GetActiveWebContents(); + ASSERT_TRUE(ExecuteProgrammaticContentScript( +- web_contents, active_extension_id(), ++ active_web_contents(), active_extension_id(), + "chrome.runtime.sendMessage({greeting: 'hello'}, (response) => {});")); + + // Capture the IPC. + auto [source_context, info, channel_name, port_id] = WaitForMessage(); +- +- // Mutate the IPC payload. + EXPECT_EQ(MessagingEndpoint::Type::kTab, info.source_endpoint.type); + EXPECT_EQ(active_extension_id(), info.source_endpoint.extension_id); ++ ++ // Mutate the IPC payload. + info.source_endpoint.type = MessagingEndpoint::Type::kExtension; + info.source_endpoint.extension_id = absl::nullopt; + + // Inject the malformed/mutated IPC and verify that the renderer is terminated + // as expected. + content::RenderProcessHost* main_frame_process = +- web_contents->GetPrimaryMainFrame()->GetProcess(); ++ active_web_contents()->GetPrimaryMainFrame()->GetProcess(); + RenderProcessHostBadIpcMessageWaiter kill_waiter(main_frame_process); + IPC::IpcSecurityTestUtil::PwnMessageReceived( + main_frame_process->GetChannel(), +@@ -464,18 +495,16 @@ IN_PROC_BROWSER_TEST_F(OpenChannelToExtensionExploitTest, + FromContentScript_UnexpectedWorkerContext) { + // Trigger sending of a valid ExtensionHostMsg_OpenChannelToExtension IPC + // from a content script of an `active_extension_id`. +- content::WebContents* web_contents = +- browser()->tab_strip_model()->GetActiveWebContents(); + ASSERT_TRUE(ExecuteProgrammaticContentScript( +- web_contents, active_extension_id(), ++ active_web_contents(), active_extension_id(), + "chrome.runtime.sendMessage({greeting: 'hello'}, (response) => {});")); + + // Capture the IPC. + auto [source_context, info, channel_name, port_id] = WaitForMessage(); +- +- // Mutate the IPC payload. + EXPECT_TRUE(source_context.is_for_render_frame()); + EXPECT_FALSE(source_context.is_for_service_worker()); ++ ++ // Mutate the IPC payload. + source_context.frame = absl::nullopt; + source_context.worker = PortContext::WorkerContext( + /* thread_id = */ 123, /* version_id = */ 456, +@@ -484,7 +513,7 @@ IN_PROC_BROWSER_TEST_F(OpenChannelToExtensionExploitTest, + // Inject the malformed/mutated IPC and verify that the renderer is terminated + // as expected. + content::RenderProcessHost* main_frame_process = +- web_contents->GetPrimaryMainFrame()->GetProcess(); ++ active_web_contents()->GetPrimaryMainFrame()->GetProcess(); + RenderProcessHostBadIpcMessageWaiter kill_waiter(main_frame_process); + IPC::IpcSecurityTestUtil::PwnMessageReceived( + main_frame_process->GetChannel(), +@@ -494,4 +523,98 @@ IN_PROC_BROWSER_TEST_F(OpenChannelToExtensionExploitTest, + kill_waiter.Wait()); + } + ++// Native messaging is not available on Fuchsia (i.e. ++// //chrome/browser/extensions/BUILD.gn excludes ++// api/messaging/native_messaging_test_util.h on Fuchsia). ++#if !(BUILDFLAG(IS_FUCHSIA)) ++ ++// Test suite for covering ExtensionHostMsg_OpenChannelToNativeApp IPC. ++class OpenChannelToNativeAppExploitTest ++ : public ExtensionSecurityExploitBrowserTest { ++ public: ++ OpenChannelToNativeAppExploitTest() = default; ++ ++ using OpenChannelMessageWaiter = ++ ExtensionMessageWaiter; ++ void SetUpOnMainThread() override { ++ // Set up ExtensionMessageWaiter *before* installing the extensions (i.e. ++ // *before* the corresponding RenderProcessHost objects are created). ++ ipc_message_waiter_ = std::make_unique(); ++ ++ // SetUpOnMainThread in the base class will install the test extensions. ++ ExtensionSecurityExploitBrowserTest::SetUpOnMainThread(); ++ ++ // Register a (fake, test-only) native messaging host. ++ test_native_messaging_host_.RegisterTestHost(/* user_level= */ false); ++ ++ // Navigate the test tab to an extension page. ++ GURL test_page_url = active_extension().GetResourceURL("page.html"); ++ EXPECT_TRUE(ui_test_utils::NavigateToURL(browser(), test_page_url)); ++ ++ // Only intercept messages from the test process. ++ int matching_process_id = ++ active_web_contents()->GetPrimaryMainFrame()->GetProcess()->GetID(); ++ ipc_message_waiter_->SetIpcMatcher(base::BindLambdaForTesting( ++ [matching_process_id]( ++ int captured_render_process_id, ++ const ExtensionHostMsg_OpenChannelToNativeApp::Param& param) { ++ if (captured_render_process_id != matching_process_id) ++ return false; ++ ++ return true; ++ })); ++ } ++ ++ // Waits for ExtensionHostMsg_OpenChannelToNativeApp IPC and returns its ++ // payload. ++ ExtensionHostMsg_OpenChannelToNativeApp::Param WaitForMessage() { ++ return ipc_message_waiter_->WaitForMessage(); ++ } ++ ++ private: ++ ScopedTestNativeMessagingHost test_native_messaging_host_; ++ std::unique_ptr ipc_message_waiter_; ++}; ++ ++IN_PROC_BROWSER_TEST_F(OpenChannelToNativeAppExploitTest, ++ SourceContextWithSpoofedExtensionId) { ++ // Trigger sending of a valid ExtensionHostMsg_OpenChannelToNativeApp IPC ++ // from a frame of an `active_extension`. ++ const char kScript[] = R"( ++ var message = {text: 'Hello!'}; ++ var host = $1; ++ chrome.runtime.sendNativeMessage(host, message); ++ )"; ++ ASSERT_EQ( ++ active_extension().origin(), ++ active_web_contents()->GetPrimaryMainFrame()->GetLastCommittedOrigin()); ++ ASSERT_TRUE(content::ExecuteScript( ++ active_web_contents(), ++ content::JsReplace(kScript, ScopedTestNativeMessagingHost::kHostName))); ++ ++ // Capture the IPC. ++ auto [source_context, native_app_name, port_id] = WaitForMessage(); ++ EXPECT_EQ(native_app_name, ScopedTestNativeMessagingHost::kHostName); ++ EXPECT_TRUE(source_context.is_for_render_frame()); ++ ++ // Mutate the IPC payload. ++ source_context = PortContext::ForWorker(123, // thread_id ++ 456, // version_id ++ spoofed_extension_id()); ++ ++ // Inject the malformed/mutated IPC and verify that the renderer is terminated ++ // as expected. ++ content::RenderProcessHost* main_frame_process = ++ active_web_contents()->GetPrimaryMainFrame()->GetProcess(); ++ RenderProcessHostBadIpcMessageWaiter kill_waiter(main_frame_process); ++ IPC::IpcSecurityTestUtil::PwnMessageReceived( ++ main_frame_process->GetChannel(), ++ ExtensionHostMsg_OpenChannelToNativeApp(source_context, native_app_name, ++ port_id)); ++ EXPECT_EQ(bad_message::EMF_INVALID_EXTENSION_ID_FOR_WORKER_CONTEXT, ++ kill_waiter.Wait()); ++} ++ ++#endif // !(BUILDFLAG(IS_FUCHSIA)) - native messaging is available ++ + } // namespace extensions +diff --git a/docs/security/compromised-renderers.md b/docs/security/compromised-renderers.md +index b7e56be454f2d42dc4ae4ac875586a01f2354d9a..2155a399e0e432fedc2792b6893440efd7fca572 100644 +--- a/docs/security/compromised-renderers.md ++++ b/docs/security/compromised-renderers.md +@@ -213,14 +213,21 @@ Compromised renderers shouldn’t be able to: + - Spoof the `MessageEvent.origin` seen by a recipient of a `postMessage`. + - Bypass enforcement of the `targetOrigin` argument of `postMessage`. + - Send or receive `BroadcastChannel` messages for another origin. +-- Spoof the `MessageSender.origin` seen by a recipient of a +- `chrome.runtime.sendMessage` +- (see also [MessageSender documentation](https://developers.chrome.com/extensions/runtime#type-MessageSender) and [content script security guidance](https://groups.google.com/a/chromium.org/forum/#!topic/chromium-extensions/0ei-UCHNm34)). ++- Spoof the `MessageSender.origin`, nor `MessageSender.id` (i.e. an ++ extension id which can differ from the origin when the message is sent ++ from a content script), as seen by a recipient of a ++ `chrome.runtime.sendMessage`. ++ See also [MessageSender documentation](https://developers.chrome.com/extensions/runtime#type-MessageSender) and [content script security guidance](https://groups.google.com/a/chromium.org/forum/#!topic/chromium-extensions/0ei-UCHNm34). ++- Spoof the id of a Chrome extension initiating ++ [native messaging](https://developer.chrome.com/docs/apps/nativeMessaging/) ++ communication. + + Protection techniques: + - Using `CanAccessDataForOrigin` to verify IPCs sent by a renderer process + (e.g. in `RenderFrameProxyHost::OnRouteMessageEvent` or + `BroadcastChannelProvider::ConnectToChannel`). ++- Using `ContentScriptTracker` to check if IPCs from a given renderer process ++ can legitimately claim to act on behalf content scripts of a given extension. + + **Known gaps in protection**: + - Spoofing of `MessageSender.id` object +diff --git a/extensions/browser/api/messaging/messaging_api_message_filter.cc b/extensions/browser/api/messaging/messaging_api_message_filter.cc +index 5469f5e91bfbb98aece208e9fffa8139dc9dacdf..e57cffb46d74229fff2534f7bb9f9fa3ddbc3d26 100644 +--- a/extensions/browser/api/messaging/messaging_api_message_filter.cc ++++ b/extensions/browser/api/messaging/messaging_api_message_filter.cc +@@ -156,6 +156,16 @@ bool IsValidSourceContext(RenderProcessHost& process, + } + } + ++ // This function doesn't validate frame-flavoured `source_context`s, because ++ // PortContext::FrameContext only contains frame's `routing_id` and therefore ++ // inherently cannot spoof frames in another process (a frame is identified ++ // by its `routing_id` *and* the `process_id` of the Renderer process hosting ++ // the frame; the latter is trustworthy / doesn't come from an IPC payload). ++ ++ // This function doesn't validate native app `source_context`s, because ++ // `PortContext::ForNativeHost()` is called with trustoworthy inputs (e.g. it ++ // doesn't take input from IPCs sent by a Renderer process). ++ + return true; + } + +@@ -227,6 +237,18 @@ void MessagingAPIMessageFilter::Shutdown() { + shutdown_notifier_subscription_ = {}; + } + ++content::RenderProcessHost* MessagingAPIMessageFilter::GetRenderProcessHost() { ++ DCHECK_CURRENTLY_ON(BrowserThread::UI); ++ if (!browser_context_) ++ return nullptr; ++ ++ // The IPC might race with RenderProcessHost destruction. This may only ++ // happen in scenarios that are already inherently racey, so returning nullptr ++ // (and dropping the IPC) is okay and won't lead to any additional risk of ++ // data loss. ++ return content::RenderProcessHost::FromID(render_process_id_); ++} ++ + void MessagingAPIMessageFilter::OverrideThreadForMessage( + const IPC::Message& message, + BrowserThread::ID* thread) { +@@ -272,19 +294,14 @@ void MessagingAPIMessageFilter::OnOpenChannelToExtension( + const std::string& channel_name, + const PortId& port_id) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); +- if (!browser_context_) +- return; +- +- // The IPC might race with RenderProcessHost destruction. This may only +- // happen in scenarios that are already inherently racey, so dropping the IPC +- // is okay and won't lead to any additional risk of data loss. +- auto* process = content::RenderProcessHost::FromID(render_process_id_); ++ auto* process = GetRenderProcessHost(); + if (!process) + return; + TRACE_EVENT("extensions", "MessageFilter::OnOpenChannelToExtension", + ChromeTrackEvent::kRenderProcessHost, *process); + + ScopedExternalConnectionInfoCrashKeys info_crash_keys(info); ++ debug::ScopedPortContextCrashKeys port_context_crash_keys(source_context); + if (!IsValidMessagingSource(*process, info.source_endpoint) || + !IsValidSourceContext(*process, source_context)) { + return; +@@ -303,7 +320,14 @@ void MessagingAPIMessageFilter::OnOpenChannelToNativeApp( + const std::string& native_app_name, + const PortId& port_id) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); +- if (!browser_context_) ++ auto* process = GetRenderProcessHost(); ++ if (!process) ++ return; ++ TRACE_EVENT("extensions", "MessageFilter::OnOpenChannelToNativeApp", ++ ChromeTrackEvent::kRenderProcessHost, *process); ++ ++ debug::ScopedPortContextCrashKeys port_context_crash_keys(source_context); ++ if (!IsValidSourceContext(*process, source_context)) + return; + + ChannelEndpoint source_endpoint(browser_context_, render_process_id_, +diff --git a/extensions/browser/api/messaging/messaging_api_message_filter.h b/extensions/browser/api/messaging/messaging_api_message_filter.h +index 6a0ccd698629f650d68f2b4ee168aa2b3b3a116c..3358187387cd9a5765a7bd4e522aeecfd787e06b 100644 +--- a/extensions/browser/api/messaging/messaging_api_message_filter.h ++++ b/extensions/browser/api/messaging/messaging_api_message_filter.h +@@ -14,6 +14,7 @@ struct ExtensionMsg_TabTargetConnectionInfo; + + namespace content { + class BrowserContext; ++class RenderProcessHost; + } + + namespace extensions { +@@ -40,6 +41,11 @@ class MessagingAPIMessageFilter : public content::BrowserMessageFilter { + + void Shutdown(); + ++ // Returns the process that the IPC came from, or `nullptr` if the IPC should ++ // be dropped (in case the IPC arrived racily after the process or its ++ // BrowserContext already got destructed). ++ content::RenderProcessHost* GetRenderProcessHost(); ++ + // content::BrowserMessageFilter implementation: + void OverrideThreadForMessage(const IPC::Message& message, + content::BrowserThread::ID* thread) override; +diff --git a/extensions/common/api/messaging/port_context.cc b/extensions/common/api/messaging/port_context.cc +index 6872179450d8295de7f15dc1437e9d6edefe4fde..319e2f34eca730c5eb7cf94ef8cdede0ddc3f8e1 100644 +--- a/extensions/common/api/messaging/port_context.cc ++++ b/extensions/common/api/messaging/port_context.cc +@@ -40,4 +40,27 @@ PortContext PortContext::ForNativeHost() { + return PortContext(); + } + ++namespace debug { ++ ++namespace { ++ ++base::debug::CrashKeyString* GetServiceWorkerExtensionIdCrashKey() { ++ static auto* crash_key = base::debug::AllocateCrashKeyString( ++ "PortContext-worker-extension_id", base::debug::CrashKeySize::Size64); ++ return crash_key; ++} ++ ++} // namespace ++ ++ScopedPortContextCrashKeys::ScopedPortContextCrashKeys( ++ const PortContext& port_context) { ++ if (port_context.is_for_service_worker()) { ++ extension_id_.emplace(GetServiceWorkerExtensionIdCrashKey(), ++ port_context.worker->extension_id); ++ } ++} ++ ++ScopedPortContextCrashKeys::~ScopedPortContextCrashKeys() = default; ++ ++} // namespace debug + } // namespace extensions +diff --git a/extensions/common/api/messaging/port_context.h b/extensions/common/api/messaging/port_context.h +index b2e9f057b531d90dc256773959cd586953e4915c..53d94c2ad73c58d45b186a32989e2f4864e67d79 100644 +--- a/extensions/common/api/messaging/port_context.h ++++ b/extensions/common/api/messaging/port_context.h +@@ -9,6 +9,7 @@ + + #include + ++#include "base/debug/crash_logging.h" + #include "third_party/abseil-cpp/absl/types/optional.h" + + namespace extensions { +@@ -59,6 +60,19 @@ struct PortContext { + absl::optional worker; + }; + ++namespace debug { ++ ++class ScopedPortContextCrashKeys { ++ public: ++ explicit ScopedPortContextCrashKeys(const PortContext& port_context); ++ ~ScopedPortContextCrashKeys(); ++ ++ private: ++ absl::optional extension_id_; ++}; ++ ++} // namespace debug ++ + } // namespace extensions + + #endif // EXTENSIONS_COMMON_API_MESSAGING_PORT_CONTEXT_H_ diff --git a/patches/chromium/cherry-pick-6b4af5d82083.patch b/patches/chromium/cherry-pick-6b4af5d82083.patch new file mode 100644 index 0000000000000..da63ef91aa8e7 --- /dev/null +++ b/patches/chromium/cherry-pick-6b4af5d82083.patch @@ -0,0 +1,292 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peng Huang +Date: Wed, 23 Nov 2022 00:16:49 +0000 +Subject: Fix potential OOB problem with validating command decoder + +Bug: 1392715 +Change-Id: If51b10cc08e5b3ca4b6012b97261347a5e4c134e +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4048203 +Auto-Submit: Peng Huang +Commit-Queue: Peng Huang +Reviewed-by: Geoff Lang +Cr-Commit-Position: refs/heads/main@{#1074966} + +diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc +index a36b9901b50cd99ac641d70d2f316362006e45e7..73148877e2b8b28374ffd32aa10361d21e4911e4 100644 +--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc ++++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc +@@ -8595,10 +8595,18 @@ void GLES2DecoderImpl::DoFramebufferTexture2DCommon( + service_id = texture_ref->service_id(); + } + ++ bool valid_target = false; ++ if (texture_ref) { ++ valid_target = texture_manager()->ValidForTextureTarget( ++ texture_ref->texture(), level, 0, 0, 1); ++ } else { ++ valid_target = texture_manager()->ValidForTarget(textarget, level, 0, 0, 1); ++ } ++ + if ((level > 0 && !feature_info_->IsWebGL2OrES3Context() && + !(fbo_render_mipmap_explicitly_enabled_ && + feature_info_->feature_flags().oes_fbo_render_mipmap)) || +- !texture_manager()->ValidForTarget(textarget, level, 0, 0, 1)) { ++ !valid_target) { + LOCAL_SET_GL_ERROR( + GL_INVALID_VALUE, + name, "level out of range"); +@@ -8670,8 +8678,8 @@ void GLES2DecoderImpl::DoFramebufferTextureLayer( + "texture is neither TEXTURE_3D nor TEXTURE_2D_ARRAY"); + return; + } +- if (!texture_manager()->ValidForTarget(texture_target, level, +- 0, 0, layer)) { ++ if (!texture_manager()->ValidForTextureTarget(texture_ref->texture(), level, ++ 0, 0, layer)) { + LOCAL_SET_GL_ERROR( + GL_INVALID_VALUE, function_name, "invalid level or layer"); + return; +@@ -14757,11 +14765,6 @@ error::Error GLES2DecoderImpl::DoCompressedTexImage( + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, func_name, "imageSize < 0"); + return error::kNoError; + } +- if (!texture_manager()->ValidForTarget(target, level, width, height, depth) || +- border != 0) { +- LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, func_name, "dimensions out of range"); +- return error::kNoError; +- } + TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget( + &state_, target); + if (!texture_ref) { +@@ -14770,6 +14773,12 @@ error::Error GLES2DecoderImpl::DoCompressedTexImage( + return error::kNoError; + } + Texture* texture = texture_ref->texture(); ++ if (!texture_manager()->ValidForTextureTarget(texture, level, width, height, ++ depth) || ++ border != 0) { ++ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, func_name, "dimensions out of range"); ++ return error::kNoError; ++ } + if (texture->IsImmutable()) { + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, func_name, "texture is immutable"); + return error::kNoError; +@@ -15139,10 +15148,6 @@ error::Error GLES2DecoderImpl::DoCompressedTexSubImage( + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, func_name, "imageSize < 0"); + return error::kNoError; + } +- if (!texture_manager()->ValidForTarget(target, level, width, height, depth)) { +- LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, func_name, "dimensions out of range"); +- return error::kNoError; +- } + TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget( + &state_, target); + if (!texture_ref) { +@@ -15150,7 +15155,14 @@ error::Error GLES2DecoderImpl::DoCompressedTexSubImage( + GL_INVALID_OPERATION, func_name, "no texture bound at target"); + return error::kNoError; + } ++ + Texture* texture = texture_ref->texture(); ++ if (!texture_manager()->ValidForTextureTarget(texture, level, width, height, ++ depth)) { ++ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, func_name, "dimensions out of range"); ++ return error::kNoError; ++ } ++ + GLenum type = 0; + GLenum internal_format = 0; + if (!texture->GetLevelType(target, level, &type, &internal_format)) { +@@ -15275,7 +15287,8 @@ void GLES2DecoderImpl::DoCopyTexImage2D( + GL_INVALID_OPERATION, func_name, "texture is immutable"); + return; + } +- if (!texture_manager()->ValidForTarget(target, level, width, height, 1) || ++ if (!texture_manager()->ValidForTextureTarget(texture, level, width, height, ++ 1) || + border != 0) { + LOCAL_SET_GL_ERROR( + GL_INVALID_VALUE, func_name, "dimensions out of range"); +@@ -17848,8 +17861,8 @@ void GLES2DecoderImpl::DoCopyTextureCHROMIUM( + } + + // Check that this type of texture is allowed. +- if (!texture_manager()->ValidForTarget(source_target, source_level, +- source_width, source_height, 1)) { ++ if (!texture_manager()->ValidForTextureTarget( ++ source_texture, source_level, source_width, source_height, 1)) { + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, kFunctionName, "Bad dimensions"); + return; + } +@@ -18016,8 +18029,8 @@ void GLES2DecoderImpl::CopySubTextureHelper(const char* function_name, + } + + // Check that this type of texture is allowed. +- if (!texture_manager()->ValidForTarget(source_target, source_level, +- source_width, source_height, 1)) { ++ if (!texture_manager()->ValidForTextureTarget( ++ source_texture, source_level, source_width, source_height, 1)) { + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name, + "source texture bad dimensions"); + return; +@@ -18257,11 +18270,20 @@ void GLES2DecoderImpl::TexStorageImpl(GLenum target, + return; + } + } ++ TextureRef* texture_ref = ++ texture_manager()->GetTextureInfoForTarget(&state_, target); ++ if (!texture_ref) { ++ LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name, ++ "unknown texture for target"); ++ return; ++ } ++ Texture* texture = texture_ref->texture(); + // The glTexStorage entry points require width, height, and depth to be + // at least 1, but the other texture entry points (those which use +- // ValidForTarget) do not. So we have to add an extra check here. ++ // ValidForTextureTarget) do not. So we have to add an extra check here. + bool is_invalid_texstorage_size = width < 1 || height < 1 || depth < 1; +- if (!texture_manager()->ValidForTarget(target, 0, width, height, depth) || ++ if (!texture_manager()->ValidForTextureTarget(texture, 0, width, height, ++ depth) || + is_invalid_texstorage_size) { + LOCAL_SET_GL_ERROR( + GL_INVALID_VALUE, function_name, "dimensions out of range"); +@@ -18274,14 +18296,6 @@ void GLES2DecoderImpl::TexStorageImpl(GLenum target, + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name, "too many levels"); + return; + } +- TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget( +- &state_, target); +- if (!texture_ref) { +- LOCAL_SET_GL_ERROR( +- GL_INVALID_OPERATION, function_name, "unknown texture for target"); +- return; +- } +- Texture* texture = texture_ref->texture(); + if (texture->IsAttachedToFramebuffer()) { + framebuffer_state_.clear_state_dirty = true; + } +diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc +index b20b875b6b37c36623b41e648e393ded96bae93b..f5df8270a8192d36b95e619248c128167455ef46 100644 +--- a/gpu/command_buffer/service/texture_manager.cc ++++ b/gpu/command_buffer/service/texture_manager.cc +@@ -1641,7 +1641,7 @@ void Texture::Update() { + return; + + if (face_infos_.empty() || +- static_cast(base_level_) >= face_infos_[0].level_infos.size()) { ++ static_cast(base_level_) >= MaxValidMipLevel()) { + texture_complete_ = false; + cube_complete_ = false; + return; +@@ -2028,8 +2028,7 @@ bool Texture::CanRenderTo(const FeatureInfo* feature_info, GLint level) const { + // the time. + if (face_infos_.size() == 6 && !cube_complete()) + return false; +- DCHECK(level >= 0 && +- level < static_cast(face_infos_[0].level_infos.size())); ++ DCHECK(level >= 0 && level < static_cast(MaxValidMipLevel())); + if (level > base_level_ && !texture_complete()) { + return false; + } +@@ -2064,7 +2063,7 @@ void Texture::SetCompatibilitySwizzle(const CompatibilitySwizzle* swizzle) { + + void Texture::ApplyFormatWorkarounds(const FeatureInfo* feature_info) { + if (feature_info->gl_version_info().NeedsLuminanceAlphaEmulation()) { +- if (static_cast(base_level_) >= face_infos_[0].level_infos.size()) ++ if (static_cast(base_level_) >= MaxValidMipLevel()) + return; + const Texture::LevelInfo& info = face_infos_[0].level_infos[base_level_]; + SetCompatibilitySwizzle(GetCompatibilitySwizzleInternal(info.format)); +@@ -2298,8 +2297,11 @@ scoped_refptr + return default_texture; + } + +-bool TextureManager::ValidForTarget( +- GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth) { ++bool TextureManager::ValidForTarget(GLenum target, ++ GLint level, ++ GLsizei width, ++ GLsizei height, ++ GLsizei depth) { + if (level < 0 || level >= MaxLevelsForTarget(target)) + return false; + GLsizei max_size = MaxSizeForTarget(target) >> level; +@@ -2319,6 +2321,18 @@ bool TextureManager::ValidForTarget( + (target != GL_TEXTURE_2D || (depth == 1)); + } + ++bool TextureManager::ValidForTextureTarget(const Texture* texture, ++ GLint level, ++ GLsizei width, ++ GLsizei height, ++ GLsizei depth) { ++ if (texture->target() == 0) ++ return false; ++ if (level < 0 || static_cast(level) >= texture->MaxValidMipLevel()) ++ return false; ++ return ValidForTarget(texture->target(), level, width, height, depth); ++} ++ + void TextureManager::SetTarget(TextureRef* ref, GLenum target) { + DCHECK(ref); + ref->texture()->SetTarget(target, MaxLevelsForTarget(target)); +@@ -2802,14 +2816,6 @@ bool TextureManager::ValidateTexImage(ContextState* state, + args.internal_format, args.level)) { + return false; + } +- if (!ValidForTarget(args.target, args.level, +- args.width, args.height, args.depth) || +- args.border != 0) { +- ERRORSTATE_SET_GL_ERROR( +- error_state, GL_INVALID_VALUE, function_name, +- "dimensions out of range"); +- return false; +- } + if ((GLES2Util::GetChannelsForFormat(args.format) & + (GLES2Util::kDepth | GLES2Util::kStencil)) != 0 && args.pixels + && !feature_info_->IsWebGL2OrES3Context()) { +@@ -2832,7 +2838,13 @@ bool TextureManager::ValidateTexImage(ContextState* state, + "texture is immutable"); + return false; + } +- ++ if (!ValidForTextureTarget(local_texture_ref->texture(), args.level, ++ args.width, args.height, args.depth) || ++ args.border != 0) { ++ ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_VALUE, function_name, ++ "dimensions out of range"); ++ return false; ++ } + Buffer* buffer = state->bound_pixel_unpack_buffer.get(); + if (buffer) { + if (buffer->GetMappedRange()) { +diff --git a/gpu/command_buffer/service/texture_manager.h b/gpu/command_buffer/service/texture_manager.h +index c78c914cbad58abb17439354eeb9f77a9891f21d..8f68e70e6d1c9a4b75f6bec0df7179320bc167c0 100644 +--- a/gpu/command_buffer/service/texture_manager.h ++++ b/gpu/command_buffer/service/texture_manager.h +@@ -470,6 +470,11 @@ class GPU_GLES2_EXPORT Texture final : public TextureBase { + sampler_state_.min_filter != GL_LINEAR; + } + ++ size_t MaxValidMipLevel() const { ++ DCHECK(!face_infos_.empty()); ++ return face_infos_[0].level_infos.size(); ++ } ++ + private: + friend class MailboxManagerTest; + friend class TextureManager; +@@ -932,6 +937,11 @@ class GPU_GLES2_EXPORT TextureManager + bool ValidForTarget( + GLenum target, GLint level, + GLsizei width, GLsizei height, GLsizei depth); ++ bool ValidForTextureTarget(const Texture* texture, ++ GLint level, ++ GLsizei width, ++ GLsizei height, ++ GLsizei depth); + + // True if this texture meets all the GLES2 criteria for rendering. + // See section 3.8.2 of the GLES2 spec. diff --git a/patches/chromium/cherry-pick-77208afba04d.patch b/patches/chromium/cherry-pick-77208afba04d.patch new file mode 100644 index 0000000000000..49e01c54f347e --- /dev/null +++ b/patches/chromium/cherry-pick-77208afba04d.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jaroslav Sevcik +Date: Thu, 1 Dec 2022 14:15:52 +0000 +Subject: Make WidgetBase::BeginMainFrame resilient to disposed 'this' + +This patch makes sure that WidgetBase::BeginMainFrame can finish +execution even if processing the RAF-throttled handlers +(DispatchRafAlignedInput) destroys 'this' instance. + +(cherry picked from commit af6e22c14bec7ad64115b24ece6d423f144214ca) + +Bug: chromium:1381871 +Change-Id: I81aa4ba697f80f8666bb2a3b5542cac210b1efa9 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4030809 +Reviewed-by: Dave Tapuska +Commit-Queue: Jaroslav Sevcik +Cr-Original-Commit-Position: refs/heads/main@{#1072864} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4068023 +Auto-Submit: Jaroslav Sevcik +Commit-Queue: Dave Tapuska +Cr-Commit-Position: refs/branch-heads/5359@{#1053} +Cr-Branched-From: 27d3765d341b09369006d030f83f582a29eb57ae-refs/heads/main@{#1058933} + +diff --git a/third_party/blink/renderer/platform/widget/widget_base.cc b/third_party/blink/renderer/platform/widget/widget_base.cc +index e32cbe6473e1e51f4c523b68263cffd1bfb5527c..be585e22e071b078a62552b9fc3e72d1dd8eb036 100644 +--- a/third_party/blink/renderer/platform/widget/widget_base.cc ++++ b/third_party/blink/renderer/platform/widget/widget_base.cc +@@ -861,8 +861,14 @@ void WidgetBase::BeginMainFrame(base::TimeTicks frame_time) { + if (ShouldRecordBeginMainFrameMetrics()) { + raf_aligned_input_start_time = base::TimeTicks::Now(); + } ++ ++ auto weak_this = weak_ptr_factory_.GetWeakPtr(); + widget_input_handler_manager_->input_event_queue()->DispatchRafAlignedInput( + frame_time); ++ // DispatchRafAlignedInput could have detached the frame. ++ if (!weak_this) ++ return; ++ + if (ShouldRecordBeginMainFrameMetrics()) { + client_->RecordDispatchRafAlignedInputTime(raf_aligned_input_start_time); + } diff --git a/patches/chromium/cherry-pick-819d876e1bb8.patch b/patches/chromium/cherry-pick-819d876e1bb8.patch new file mode 100644 index 0000000000000..8cf27a6bf1b0e --- /dev/null +++ b/patches/chromium/cherry-pick-819d876e1bb8.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ted Meyer +Date: Sat, 3 Dec 2022 00:09:22 +0000 +Subject: Fix UAF caused by vector operations during iteration + +MediaInspectorContextImpl::CullPlayers iterates through dead_players_ +to remove their events, but this can cause a GC event which can +end up adding more players to the |dead_players_| vector, causing +it to get re-allocated and it's iterators invalidated. + +We can fix this simply by not using an iterator, and removing elements +from the vector before we trigger any GC operations that might cause +other changes to the vector. + +Bug: 1383991 + +Change-Id: I59f5824c156ff58cf6b55ac9b942c8efdb1ed65a +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4064295 +Reviewed-by: Andrey Kosyakov +Commit-Queue: Ted (Chromium) Meyer +Reviewed-by: Thomas Guilbert +Cr-Commit-Position: refs/heads/main@{#1078842} + +diff --git a/third_party/blink/renderer/core/inspector/inspector_media_context_impl.cc b/third_party/blink/renderer/core/inspector/inspector_media_context_impl.cc +index c0965693783d5cc0eade67fc78f026cec2942792..6e89262ca229b89407c3f6fff2ab5bf74be460e0 100644 +--- a/third_party/blink/renderer/core/inspector/inspector_media_context_impl.cc ++++ b/third_party/blink/renderer/core/inspector/inspector_media_context_impl.cc +@@ -109,9 +109,13 @@ void MediaInspectorContextImpl::TrimPlayer(const WebString& playerId) { + + void MediaInspectorContextImpl::CullPlayers(const WebString& prefer_keep) { + // Erase all the dead players, but only erase the required number of others. +- for (const auto& playerId : dead_players_) ++ while (!dead_players_.IsEmpty()) { ++ auto playerId = dead_players_.back(); ++ // remove it first, since |RemovePlayer| can cause a GC event which can ++ // potentially caues more players to get added to |dead_players_|. ++ dead_players_.pop_back(); + RemovePlayer(playerId); +- dead_players_.clear(); ++ } + + while (!expendable_players_.IsEmpty()) { + if (total_event_count_ <= kMaxCachedPlayerEvents) diff --git a/patches/chromium/cherry-pick-81cb17c24788.patch b/patches/chromium/cherry-pick-81cb17c24788.patch new file mode 100644 index 0000000000000..fef119e270b62 --- /dev/null +++ b/patches/chromium/cherry-pick-81cb17c24788.patch @@ -0,0 +1,115 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Christoph Schwering +Date: Fri, 4 Nov 2022 00:56:32 +0000 +Subject: Handle misaligned FormData, FormStructure. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This CL handles the case where the fields of the cached FormStructure +and the FormData are misaligned in +BrowserAutofillManager::WillFillCreditCardNumber. + +(cherry picked from commit 1ad751f7dfa30a12a85824c291394b73c5c47eff) + +Bug: 1376637, 1376639 +Change-Id: Id7c3357a274b4d6624009ecf52b95a24cf3bfa1d +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3965141 +Commit-Queue: Christoph Schwering +Quick-Run: Christoph Schwering +Reviewed-by: Dominic Battré +Auto-Submit: Christoph Schwering +Cr-Original-Commit-Position: refs/heads/main@{#1061790} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4003032 +Commit-Queue: Dominic Battré +Cr-Commit-Position: refs/branch-heads/5249@{#907} +Cr-Branched-From: 4f7bea5de862aaa52e6bde5920755a9ef9db120b-refs/heads/main@{#1036826} + +diff --git a/chrome/test/data/autofill/captured_sites/testcases.json b/chrome/test/data/autofill/captured_sites/testcases.json +index bb7ac2a638a410b3e83b9871314eae27aa8ef229..2e69d8f8532760103b9cccd5efc4ca7a4ad016a1 100644 +--- a/chrome/test/data/autofill/captured_sites/testcases.json ++++ b/chrome/test/data/autofill/captured_sites/testcases.json +@@ -17,7 +17,7 @@ + { "site_name": "bath_and_body_works" }, + { "site_name": "beachbody" }, + { "site_name": "bed_bath_beyond" }, +- { "site_name": "belk" }, ++ { "site_name": "belk", "bug_number": 1376637 }, + { "site_name": "bestbuy" }, + { "site_name": "bhphotovideo", "bug_number":1173033 }, + { "site_name": "bloomingdales" }, +diff --git a/components/autofill/core/browser/browser_autofill_manager.cc b/components/autofill/core/browser/browser_autofill_manager.cc +index 2dad433c7deb91a2d06f7a10077c9197bd2eba98..0a6e94a1f5327600c1c13cd6fd7586c7ca09037e 100644 +--- a/components/autofill/core/browser/browser_autofill_manager.cc ++++ b/components/autofill/core/browser/browser_autofill_manager.cc +@@ -1069,26 +1069,36 @@ void BrowserAutofillManager::OnAskForValuesToFillImpl( + + bool BrowserAutofillManager::WillFillCreditCardNumber( + const FormData& form, +- const FormFieldData& field) { ++ const FormFieldData& triggered_field_data) { + FormStructure* form_structure = nullptr; +- AutofillField* autofill_field = nullptr; +- if (!GetCachedFormAndField(form, field, &form_structure, &autofill_field)) ++ AutofillField* triggered_field = nullptr; ++ if (!GetCachedFormAndField(form, triggered_field_data, &form_structure, ++ &triggered_field)) { + return false; ++ } + +- if (autofill_field->Type().GetStorableType() == CREDIT_CARD_NUMBER) ++ if (triggered_field->Type().GetStorableType() == CREDIT_CARD_NUMBER) + return true; + +- DCHECK_EQ(form_structure->field_count(), form.fields.size()); +- for (size_t i = 0; i < form_structure->field_count(); ++i) { +- if (form_structure->field(i)->section == autofill_field->section && +- form_structure->field(i)->Type().GetStorableType() == +- CREDIT_CARD_NUMBER && +- form.fields[i].value.empty() && !form.fields[i].is_autofilled) { +- return true; +- } +- } ++ // `form` is the latest version of the form received from the renderer and may ++ // be more up to date than the `form_structure` in the cache. Therefore, we ++ // need to validate for each `field` in the cache we try to fill whether ++ // it still exists in the renderer and whether it is fillable. ++ auto IsFillableField = [&form](FieldGlobalId id) { ++ auto it = base::ranges::find(form.fields, id, &FormFieldData::global_id); ++ return it != form.fields.end() && it->value.empty() && !it->is_autofilled; ++ }; + +- return false; ++ auto IsFillableCreditCardNumberField = [&triggered_field, ++ &IsFillableField](const auto& field) { ++ return field->Type().GetStorableType() == CREDIT_CARD_NUMBER && ++ field->section == triggered_field->section && ++ IsFillableField(field->global_id()); ++ }; ++ ++ // This runs O(N^2) in the worst case, but usually there aren't too many ++ // credit card number fields in a form. ++ return base::ranges::any_of(*form_structure, IsFillableCreditCardNumberField); + } + + void BrowserAutofillManager::FillOrPreviewCreditCardForm( +diff --git a/components/autofill/core/browser/browser_autofill_manager.h b/components/autofill/core/browser/browser_autofill_manager.h +index d6d33df90907dd1521108cfbae1ecbd430bb4e8e..03f92c993a05122b0df1e3b6afdad50edd9e1b41 100644 +--- a/components/autofill/core/browser/browser_autofill_manager.h ++++ b/components/autofill/core/browser/browser_autofill_manager.h +@@ -475,11 +475,11 @@ class BrowserAutofillManager : public AutofillManager, + // profile does not exist. + AutofillProfile* GetProfile(int unique_id); + +- // Determines whether a fill on |form| initiated from |field| will wind up +- // filling a credit card number. This is useful to determine if we will need +- // to unmask a card. ++ // Determines whether a fill on |form| initiated from |triggered_field| will ++ // wind up filling a credit card number. This is useful to determine if we ++ // will need to unmask a card. + bool WillFillCreditCardNumber(const FormData& form, +- const FormFieldData& field); ++ const FormFieldData& triggered_field); + + // Fills or previews the credit card form. + // Assumes the form and field are valid. diff --git a/patches/chromium/cherry-pick-933cc81c6bad.patch b/patches/chromium/cherry-pick-933cc81c6bad.patch new file mode 100644 index 0000000000000..1396cca4b7e1f --- /dev/null +++ b/patches/chromium/cherry-pick-933cc81c6bad.patch @@ -0,0 +1,323 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Xiaocheng Hu +Date: Sat, 10 Sep 2022 05:53:49 +0000 +Subject: Remove symlinks from FileChooserImpl folder upload result + +FileChooserImpl is the browser-side implementation of +. When uploading a whole folder, it +currently uses DirectoryLister to list all the files in a +directory. The result also includes resolved symbolic links +(which may even hide deep in some subfolder), which is not a +desired behavior. + +Therefore, this patch removes all symbolic links from the +result by checking each file against `base::IsLink()`. Since +the function needs blocking calls to access file data, the +job is sent to a worker pool thread. + +Fixed: 1345275 +Change-Id: I8ab58214c87944408c64b177e915247a7485925b +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3866767 +Reviewed-by: Austin Sullivan +Commit-Queue: Xiaocheng Hu +Reviewed-by: Mason Freed +Reviewed-by: Alex Moshchuk +Cr-Commit-Position: refs/heads/main@{#1045491} + +diff --git a/content/browser/web_contents/file_chooser_impl.cc b/content/browser/web_contents/file_chooser_impl.cc +index 7a3ea45d32c97980c141662f6a071cc517a15ad8..1aa19f7a735b444f2c33d5084edcdd14e3c2f5c5 100644 +--- a/content/browser/web_contents/file_chooser_impl.cc ++++ b/content/browser/web_contents/file_chooser_impl.cc +@@ -4,8 +4,11 @@ + + #include "content/browser/web_contents/file_chooser_impl.h" + ++#include "base/files/file_util.h" + #include "base/logging.h" + #include "base/memory/ptr_util.h" ++#include "base/ranges/algorithm.h" ++#include "base/task/thread_pool.h" + #include "content/browser/child_process_security_policy_impl.h" + #include "content/browser/renderer_host/back_forward_cache_disable.h" + #include "content/browser/renderer_host/render_frame_host_delegate.h" +@@ -18,6 +21,19 @@ + + namespace content { + ++namespace { ++ ++std::vector RemoveSymlinks( ++ std::vector files) { ++ auto new_end = base::ranges::remove_if( ++ files, &base::IsLink, ++ [](const auto& file) { return file->get_native_file()->file_path; }); ++ files.erase(new_end, files.end()); ++ return files; ++} ++ ++} // namespace ++ + FileChooserImpl::FileSelectListenerImpl::~FileSelectListenerImpl() { + #if DCHECK_IS_ON() + if (!was_file_select_listener_function_called_) { +@@ -51,8 +67,20 @@ void FileChooserImpl::FileSelectListenerImpl::FileSelected( + "FileSelectListener::FileSelectionCanceled()"; + was_file_select_listener_function_called_ = true; + #endif +- if (owner_) +- owner_->FileSelected(std::move(files), base_dir, mode); ++ if (!owner_) ++ return; ++ ++ if (mode != blink::mojom::FileChooserParams::Mode::kUploadFolder) { ++ owner_->FileSelected(base_dir, mode, std::move(files)); ++ return; ++ } ++ ++ base::ThreadPool::PostTaskAndReplyWithResult( ++ FROM_HERE, ++ {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, ++ base::BindOnce(&RemoveSymlinks, std::move(files)), ++ base::BindOnce(&FileChooserImpl::FileSelected, owner_->GetWeakPtr(), ++ base_dir, mode)); + } + + void FileChooserImpl::FileSelectListenerImpl::FileSelectionCanceled() { +@@ -162,9 +190,9 @@ void FileChooserImpl::EnumerateChosenDirectory( + } + + void FileChooserImpl::FileSelected( +- std::vector files, + const base::FilePath& base_dir, +- blink::mojom::FileChooserParams::Mode mode) { ++ blink::mojom::FileChooserParams::Mode mode, ++ std::vector files) { + listener_impl_ = nullptr; + if (!render_frame_host_) { + std::move(callback_).Run(nullptr); +diff --git a/content/browser/web_contents/file_chooser_impl.h b/content/browser/web_contents/file_chooser_impl.h +index b9f11f9e6a0b548cb5ab8ca721ae823e079ce6fa..b628b29a5f84264e62bb3fa9e92550787b8342de 100644 +--- a/content/browser/web_contents/file_chooser_impl.h ++++ b/content/browser/web_contents/file_chooser_impl.h +@@ -37,6 +37,8 @@ class CONTENT_EXPORT FileChooserImpl : public blink::mojom::FileChooser, + + // FileSelectListener overrides: + ++ // TODO(xiaochengh): Move |file| to the end of the argument list to match ++ // the argument ordering of FileChooserImpl::FileSelected(). + void FileSelected(std::vector files, + const base::FilePath& base_dir, + blink::mojom::FileChooserParams::Mode mode) override; +@@ -68,9 +70,9 @@ class CONTENT_EXPORT FileChooserImpl : public blink::mojom::FileChooser, + + ~FileChooserImpl() override; + +- void FileSelected(std::vector files, +- const base::FilePath& base_dir, +- blink::mojom::FileChooserParams::Mode mode); ++ void FileSelected(const base::FilePath& base_dir, ++ blink::mojom::FileChooserParams::Mode mode, ++ std::vector files); + + void FileSelectionCanceled(); + +@@ -82,6 +84,10 @@ class CONTENT_EXPORT FileChooserImpl : public blink::mojom::FileChooser, + const base::FilePath& directory_path, + EnumerateChosenDirectoryCallback callback) override; + ++ base::WeakPtr GetWeakPtr() { ++ return weak_factory_.GetWeakPtr(); ++ } ++ + private: + explicit FileChooserImpl(RenderFrameHostImpl* render_frame_host); + +@@ -95,6 +101,8 @@ class CONTENT_EXPORT FileChooserImpl : public blink::mojom::FileChooser, + raw_ptr render_frame_host_; + scoped_refptr listener_impl_; + base::OnceCallback callback_; ++ ++ base::WeakPtrFactory weak_factory_{this}; + }; + + } // namespace content +diff --git a/content/browser/web_contents/file_chooser_impl_browsertest.cc b/content/browser/web_contents/file_chooser_impl_browsertest.cc +index ced9bfd8fe905acbb6ab5c3e52a9882fc23a7303..f7519189638ece437c4285ddd490be3ea59e638d 100644 +--- a/content/browser/web_contents/file_chooser_impl_browsertest.cc ++++ b/content/browser/web_contents/file_chooser_impl_browsertest.cc +@@ -5,14 +5,18 @@ + #include "content/browser/web_contents/file_chooser_impl.h" + + #include "base/bind.h" ++#include "base/files/file_util.h" ++#include "base/path_service.h" + #include "base/run_loop.h" + #include "content/browser/renderer_host/render_frame_host_impl.h" + #include "content/public/browser/web_contents_delegate.h" ++#include "content/public/common/content_paths.h" + #include "content/public/test/browser_test.h" + #include "content/public/test/browser_test_utils.h" + #include "content/public/test/content_browser_test.h" + #include "content/public/test/content_browser_test_utils.h" + #include "content/shell/browser/shell.h" ++#include "content/test/content_browser_test_utils_internal.h" + #include "url/gurl.h" + #include "url/url_constants.h" + +@@ -143,11 +147,52 @@ IN_PROC_BROWSER_TEST_F(FileChooserImplBrowserTest, + ->SetListenerFunctionCalledTrueForTesting(); + std::vector files; + files.emplace_back(blink::mojom::FileChooserFileInfoPtr(nullptr)); +- chooser->FileSelected(std::move(files), base::FilePath(), +- blink::mojom::FileChooserParams::Mode::kOpen); ++ chooser->FileSelected(base::FilePath(), ++ blink::mojom::FileChooserParams::Mode::kOpen, ++ std::move(files)); + + // Test passes if this run_loop.Run() returns instead of timing out. + run_loop.Run(); + } + ++// https://crbug.com/1345275 ++IN_PROC_BROWSER_TEST_F(FileChooserImplBrowserTest, UploadFolderWithSymlink) { ++ EXPECT_TRUE(NavigateToURL( ++ shell(), GetTestUrl(".", "file_input_webkitdirectory.html"))); ++ ++ // The folder contains a regular file and a symbolic link. ++ // When uploading the folder, the symbolic link should be excluded. ++ base::FilePath dir_test_data; ++ ASSERT_TRUE(base::PathService::Get(DIR_TEST_DATA, &dir_test_data)); ++ base::FilePath folder_to_upload = ++ dir_test_data.AppendASCII("file_chooser").AppendASCII("dir_with_symlink"); ++ ++ base::FilePath text_file = folder_to_upload.AppendASCII("text_file.txt"); ++ base::FilePath symlink_file = folder_to_upload.AppendASCII("symlink"); ++ ++ // Skip the test if symbolic links are not supported. ++ { ++ base::ScopedAllowBlockingForTesting allow_blocking; ++ if (!base::IsLink(symlink_file)) ++ return; ++ } ++ ++ std::unique_ptr delegate( ++ new FileChooserDelegate({text_file, symlink_file}, base::OnceClosure())); ++ shell()->web_contents()->SetDelegate(delegate.get()); ++ EXPECT_TRUE(ExecJs(shell(), ++ "(async () => {" ++ " let listener = new Promise(" ++ " resolve => fileinput.onchange = resolve);" ++ " fileinput.click();" ++ " await listener;" ++ "})()")); ++ ++ EXPECT_EQ( ++ 1, EvalJs(shell(), "document.getElementById('fileinput').files.length;")); ++ EXPECT_EQ( ++ "text_file.txt", ++ EvalJs(shell(), "document.getElementById('fileinput').files[0].name;")); ++} ++ + } // namespace content +diff --git a/content/test/content_browser_test_utils_internal.cc b/content/test/content_browser_test_utils_internal.cc +index d8e63b56c8ac89a08cd7c40cabb156eb4d1923aa..c70d088bfd007e9a6cd9cfcb6f92b07b99653048 100644 +--- a/content/test/content_browser_test_utils_internal.cc ++++ b/content/test/content_browser_test_utils_internal.cc +@@ -446,9 +446,14 @@ Shell* OpenPopup(const ToRenderFrameHost& opener, + return new_shell_observer.GetShell(); + } + ++FileChooserDelegate::FileChooserDelegate(std::vector files, ++ base::OnceClosure callback) ++ : files_(std::move(files)), callback_(std::move(callback)) {} ++ + FileChooserDelegate::FileChooserDelegate(const base::FilePath& file, + base::OnceClosure callback) +- : file_(file), callback_(std::move(callback)) {} ++ : FileChooserDelegate(std::vector(1, file), ++ std::move(callback)) {} + + FileChooserDelegate::~FileChooserDelegate() = default; + +@@ -456,16 +461,18 @@ void FileChooserDelegate::RunFileChooser( + RenderFrameHost* render_frame_host, + scoped_refptr listener, + const blink::mojom::FileChooserParams& params) { +- // Send the selected file to the renderer process. +- auto file_info = blink::mojom::FileChooserFileInfo::NewNativeFile( +- blink::mojom::NativeFileInfo::New(file_, std::u16string())); ++ // Send the selected files to the renderer process. + std::vector files; +- files.push_back(std::move(file_info)); +- listener->FileSelected(std::move(files), base::FilePath(), +- blink::mojom::FileChooserParams::Mode::kOpen); ++ for (const auto& file : files_) { ++ auto file_info = blink::mojom::FileChooserFileInfo::NewNativeFile( ++ blink::mojom::NativeFileInfo::New(file, std::u16string())); ++ files.push_back(std::move(file_info)); ++ } ++ listener->FileSelected(std::move(files), base::FilePath(), params.mode); + + params_ = params.Clone(); +- std::move(callback_).Run(); ++ if (callback_) ++ std::move(callback_).Run(); + } + + FrameTestNavigationManager::FrameTestNavigationManager( +diff --git a/content/test/content_browser_test_utils_internal.h b/content/test/content_browser_test_utils_internal.h +index 73be6e8a2f458128b08aae34d951c7a80139997d..43c6aabc5414d0cc12fb5a03142e8b20e2a7fab3 100644 +--- a/content/test/content_browser_test_utils_internal.h ++++ b/content/test/content_browser_test_utils_internal.h +@@ -176,9 +176,11 @@ Shell* OpenPopup(const ToRenderFrameHost& opener, + class FileChooserDelegate : public WebContentsDelegate { + public: + // Constructs a WebContentsDelegate that mocks a file dialog. +- // The mocked file dialog will always reply that the user selected |file|. +- // |callback| is invoked when RunFileChooser() is called. ++ // The mocked file dialog will always reply that the user selected |file| or ++ // |files|. |callback| is invoked when RunFileChooser() is called. + FileChooserDelegate(const base::FilePath& file, base::OnceClosure callback); ++ FileChooserDelegate(std::vector files, ++ base::OnceClosure callback); + ~FileChooserDelegate() override; + + // Implementation of WebContentsDelegate::RunFileChooser. +@@ -190,7 +192,7 @@ class FileChooserDelegate : public WebContentsDelegate { + const blink::mojom::FileChooserParams& params() const { return *params_; } + + private: +- base::FilePath file_; ++ std::vector files_; + base::OnceClosure callback_; + blink::mojom::FileChooserParamsPtr params_; + }; +diff --git a/content/test/data/file_chooser/dir_with_symlink/symlink b/content/test/data/file_chooser/dir_with_symlink/symlink +new file mode 120000 +index 0000000000000000000000000000000000000000..7857c689f7043265b4e6d4dcdf6d40d0be2d3d60 +--- /dev/null ++++ b/content/test/data/file_chooser/dir_with_symlink/symlink +@@ -0,0 +1 @@ ++../linked_text_file.txt +\ No newline at end of file +diff --git a/content/test/data/file_chooser/dir_with_symlink/text_file.txt b/content/test/data/file_chooser/dir_with_symlink/text_file.txt +new file mode 100644 +index 0000000000000000000000000000000000000000..8e27be7d6154a1f68ea9160ef0e18691d20560dc +--- /dev/null ++++ b/content/test/data/file_chooser/dir_with_symlink/text_file.txt +@@ -0,0 +1 @@ ++text +diff --git a/content/test/data/file_chooser/linked_text_file.txt b/content/test/data/file_chooser/linked_text_file.txt +new file mode 100644 +index 0000000000000000000000000000000000000000..9a1f4bc60917c014eac1464ad664a0271c288b84 +--- /dev/null ++++ b/content/test/data/file_chooser/linked_text_file.txt +@@ -0,0 +1 @@ ++linked text file +diff --git a/content/test/data/file_input_webkitdirectory.html b/content/test/data/file_input_webkitdirectory.html +new file mode 100644 +index 0000000000000000000000000000000000000000..5b7bb501f7eb5d9f28751f36380e4ad01d2da0c7 +--- /dev/null ++++ b/content/test/data/file_input_webkitdirectory.html +@@ -0,0 +1 @@ ++ diff --git a/patches/chromium/cherry-pick-9b3d0e2f1aab.patch b/patches/chromium/cherry-pick-9b3d0e2f1aab.patch new file mode 100644 index 0000000000000..c35fb2fb56cae --- /dev/null +++ b/patches/chromium/cherry-pick-9b3d0e2f1aab.patch @@ -0,0 +1,119 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Corentin Wallez +Date: Tue, 29 Nov 2022 14:07:46 +0000 +Subject: Keep a reference to the transfer buffer in Dawn read/write handles. + +Previously the Dawn read/write handles in the GPU process only contained +a pointer to the inside of a shmem region owned by a gpu::Buffer that +had a different lifetime. This could allow a renderer process to +deallocate the memory from underneath the handle which is bad. + +Fix this by keepind a scoped_refptr to the gpu::Buffer inside the +read/write handles to extend the lifetime of the shmem to be at least as +big as the handle's. + +Fixed: chromium:1393177 +Change-Id: I9d9c18d5155a46e0e3a01d385d221a6370bd2bea +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4056276 +Reviewed-by: Austin Eng +Commit-Queue: Corentin Wallez +Cr-Commit-Position: refs/heads/main@{#1076828} + +diff --git a/gpu/command_buffer/service/dawn_service_memory_transfer_service.cc b/gpu/command_buffer/service/dawn_service_memory_transfer_service.cc +index a15b6f9b3b345079d8cf8251ca5f77b6e7ef647a..10941d9f65c66e50303cf7293180c29fced8ffe2 100644 +--- a/gpu/command_buffer/service/dawn_service_memory_transfer_service.cc ++++ b/gpu/command_buffer/service/dawn_service_memory_transfer_service.cc +@@ -6,6 +6,7 @@ + + #include "base/memory/raw_ptr.h" + #include "gpu/command_buffer/common/dawn_memory_transfer_handle.h" ++#include "gpu/command_buffer/service/command_buffer_service.h" + #include "gpu/command_buffer/service/common_decoder.h" + + namespace gpu { +@@ -16,8 +17,8 @@ namespace { + class ReadHandleImpl + : public dawn::wire::server::MemoryTransferService::ReadHandle { + public: +- ReadHandleImpl(void* ptr, uint32_t size) +- : ReadHandle(), ptr_(ptr), size_(size) {} ++ ReadHandleImpl(scoped_refptr buffer, void* ptr, uint32_t size) ++ : buffer_(std::move(buffer)), ptr_(ptr), size_(size) {} + + ~ReadHandleImpl() override = default; + +@@ -44,6 +45,8 @@ class ReadHandleImpl + } + + private: ++ scoped_refptr buffer_; ++ // Pointer to client-visible shared memory owned by buffer_. + raw_ptr ptr_; + uint32_t size_; + }; +@@ -51,8 +54,8 @@ class ReadHandleImpl + class WriteHandleImpl + : public dawn::wire::server::MemoryTransferService::WriteHandle { + public: +- WriteHandleImpl(const void* ptr, uint32_t size) +- : WriteHandle(), ptr_(ptr), size_(size) {} ++ WriteHandleImpl(scoped_refptr buffer, const void* ptr, uint32_t size) ++ : buffer_(std::move(buffer)), ptr_(ptr), size_(size) {} + + ~WriteHandleImpl() override = default; + +@@ -82,7 +85,9 @@ class WriteHandleImpl + } + + private: +- raw_ptr ptr_; // Pointer to client-visible shared memory. ++ scoped_refptr buffer_; ++ // Pointer to client-visible shared memory owned by buffer_. ++ raw_ptr ptr_; + uint32_t size_; + }; + +@@ -111,13 +116,19 @@ bool DawnServiceMemoryTransferService::DeserializeReadHandle( + int32_t shm_id = handle->shm_id; + uint32_t shm_offset = handle->shm_offset; + +- void* ptr = decoder_->GetAddressAndCheckSize(shm_id, shm_offset, size); ++ scoped_refptr buffer = ++ decoder_->command_buffer_service()->GetTransferBuffer(shm_id); ++ if (buffer == nullptr) { ++ return false; ++ } ++ ++ void* ptr = buffer->GetDataAddress(shm_offset, size); + if (ptr == nullptr) { + return false; + } + + DCHECK(read_handle); +- *read_handle = new ReadHandleImpl(ptr, size); ++ *read_handle = new ReadHandleImpl(std::move(buffer), ptr, size); + + return true; + } +@@ -139,13 +150,19 @@ bool DawnServiceMemoryTransferService::DeserializeWriteHandle( + int32_t shm_id = handle->shm_id; + uint32_t shm_offset = handle->shm_offset; + +- void* ptr = decoder_->GetAddressAndCheckSize(shm_id, shm_offset, size); ++ scoped_refptr buffer = ++ decoder_->command_buffer_service()->GetTransferBuffer(shm_id); ++ if (buffer == nullptr) { ++ return false; ++ } ++ ++ const void* ptr = buffer->GetDataAddress(shm_offset, size); + if (ptr == nullptr) { + return false; + } + + DCHECK(write_handle); +- *write_handle = new WriteHandleImpl(ptr, size); ++ *write_handle = new WriteHandleImpl(std::move(buffer), ptr, size); + + return true; + } diff --git a/patches/chromium/cherry-pick-a1cbf05b4163.patch b/patches/chromium/cherry-pick-a1cbf05b4163.patch new file mode 100644 index 0000000000000..a020ef89eca49 --- /dev/null +++ b/patches/chromium/cherry-pick-a1cbf05b4163.patch @@ -0,0 +1,102 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Matt Wolenetz +Date: Fri, 4 Nov 2022 22:06:47 +0000 +Subject: webcodecs: Fix race in VE.isConfigSupported() promise resolution + +If the context is destroyed before VideoEncoder calls `done_callback`, bad +things can happen. That's why we extract a callback runner before doing +anything asynchronous. Since we hold a ref-counted pointer to the +runner it should be safe now. + +(cherry picked from commit 2acf28478008315f302fd52b571623e784be707b) + +Bug: 1375059 +Change-Id: I984ab27e03e50bd5ae4bf0eb13431834b14f89b7 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3965544 +Commit-Queue: Eugene Zemtsov +Reviewed-by: Dale Curtis +Cr-Original-Commit-Position: refs/heads/main@{#1061737} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4005574 +Reviewed-by: Matthew Wolenetz +Cr-Commit-Position: refs/branch-heads/5249@{#911} +Cr-Branched-From: 4f7bea5de862aaa52e6bde5920755a9ef9db120b-refs/heads/main@{#1036826} + +diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc +index 5332ae4094c5a8062cb1b8c830869095b964eabc..8f2be276b702bf5a3071b1bf44a9a5419880acf1 100644 +--- a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc ++++ b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc +@@ -68,6 +68,7 @@ + #include "third_party/blink/renderer/platform/instrumentation/use_counter.h" + #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h" + #include "third_party/blink/renderer/platform/scheduler/public/thread.h" ++#include "third_party/blink/renderer/platform/wtf/cross_thread_copier_base.h" + #include "third_party/blink/renderer/platform/wtf/cross_thread_copier_std.h" + #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h" + +@@ -100,16 +101,6 @@ namespace { + constexpr const char kCategory[] = "media"; + constexpr int kMaxActiveEncodes = 5; + +-// Use this function in cases when we can't immediately delete |ptr| because +-// there might be its methods on the call stack. +-template +-void DeleteLater(ScriptState* state, std::unique_ptr ptr) { +- DCHECK(state->ContextIsValid()); +- auto* context = ExecutionContext::From(state); +- auto runner = context->GetTaskRunner(TaskType::kInternalDefault); +- runner->DeleteSoon(FROM_HERE, std::move(ptr)); +-} +- + bool IsAcceleratedConfigurationSupported( + media::VideoCodecProfile profile, + const media::VideoEncoder::Options& options, +@@ -979,6 +970,7 @@ void VideoEncoder::ResetInternal() { + } + + static void isConfigSupportedWithSoftwareOnly( ++ ScriptState* script_state, + ScriptPromiseResolver* resolver, + VideoEncoderSupport* support, + VideoEncoderTraits::ParsedConfig* config) { +@@ -1003,22 +995,25 @@ static void isConfigSupportedWithSoftwareOnly( + return; + } + +- auto done_callback = [](std::unique_ptr sw_encoder, ++ auto done_callback = [](std::unique_ptr encoder, + ScriptPromiseResolver* resolver, ++ scoped_refptr runner, + VideoEncoderSupport* support, + media::EncoderStatus status) { + support->setSupported(status.is_ok()); + resolver->Resolve(support); +- DeleteLater(resolver->GetScriptState(), std::move(sw_encoder)); ++ runner->DeleteSoon(FROM_HERE, std::move(encoder)); + }; + ++ auto* context = ExecutionContext::From(script_state); ++ auto runner = context->GetTaskRunner(TaskType::kInternalDefault); + auto* software_encoder_raw = software_encoder.get(); + software_encoder_raw->Initialize( + config->profile, config->options, base::DoNothing(), +- ConvertToBaseOnceCallback( +- CrossThreadBindOnce(done_callback, std::move(software_encoder), +- WrapCrossThreadPersistent(resolver), +- WrapCrossThreadPersistent(support)))); ++ ConvertToBaseOnceCallback(CrossThreadBindOnce( ++ done_callback, std::move(software_encoder), ++ WrapCrossThreadPersistent(resolver), std::move(runner), ++ WrapCrossThreadPersistent(support)))); + } + + static void isConfigSupportedWithHardwareOnly( +@@ -1105,7 +1100,8 @@ ScriptPromise VideoEncoder::isConfigSupported(ScriptState* script_state, + promises.push_back(resolver->Promise()); + auto* support = VideoEncoderSupport::Create(); + support->setConfig(config_copy); +- isConfigSupportedWithSoftwareOnly(resolver, support, parsed_config); ++ isConfigSupportedWithSoftwareOnly(script_state, resolver, support, ++ parsed_config); + } + + // Wait for all |promises| to resolve and check if any of them have diff --git a/patches/chromium/cherry-pick-ac4785387fff.patch b/patches/chromium/cherry-pick-ac4785387fff.patch new file mode 100644 index 0000000000000..792ce173c976b --- /dev/null +++ b/patches/chromium/cherry-pick-ac4785387fff.patch @@ -0,0 +1,285 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Dave Tapuska +Date: Thu, 3 Nov 2022 23:16:16 +0000 +Subject: Fix PauseOrFreezeOnWorkerThread with nested Worklets. + +Worklets can use the same backing thread which means we can have +nested WorkerThreads paused. If a parent WorkerThread gets deallocated +make sure we don't access anything after it is deallocated once the +nested event queue is released. + +BUG=1372695 + +(cherry picked from commit ff5696ba4bc0f8782e3de40e04685507d9f17fd2) + +Change-Id: I176b8f750da5a41d19d1b3a623944d9a2ed4a441 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3953152 +Commit-Queue: Dave Tapuska +Reviewed-by: Daniel Cheng +Cr-Original-Commit-Position: refs/heads/main@{#1059485} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4004562 +Cr-Commit-Position: refs/branch-heads/5249@{#906} +Cr-Branched-From: 4f7bea5de862aaa52e6bde5920755a9ef9db120b-refs/heads/main@{#1036826} + +diff --git a/third_party/blink/renderer/core/workers/threaded_worklet_test.cc b/third_party/blink/renderer/core/workers/threaded_worklet_test.cc +index c54d0a91447717f014f44d36e004d9092e98f8bb..dbe40e69a276983bc2df5dcddd7b9b483d2534b1 100644 +--- a/third_party/blink/renderer/core/workers/threaded_worklet_test.cc ++++ b/third_party/blink/renderer/core/workers/threaded_worklet_test.cc +@@ -234,6 +234,7 @@ class ThreadedWorkletMessagingProxyForTest + + private: + friend class ThreadedWorkletTest; ++ FRIEND_TEST_ALL_PREFIXES(ThreadedWorkletTest, NestedRunLoopTermination); + + std::unique_ptr CreateWorkerThread() final { + return std::make_unique(WorkletObjectProxy()); +@@ -280,6 +281,16 @@ class ThreadedWorkletTest : public testing::Test { + } + Document& GetDocument() { return page_->GetDocument(); } + ++ void WaitForReady(WorkerThread* worker_thread) { ++ base::WaitableEvent child_waitable; ++ PostCrossThreadTask( ++ *worker_thread->GetTaskRunner(TaskType::kInternalTest), FROM_HERE, ++ CrossThreadBindOnce(&base::WaitableEvent::Signal, ++ CrossThreadUnretained(&child_waitable))); ++ ++ child_waitable.Wait(); ++ } ++ + private: + std::unique_ptr page_; + Persistent messaging_proxy_; +@@ -403,4 +414,40 @@ TEST_F(ThreadedWorkletTest, TaskRunner) { + test::EnterRunLoop(); + } + ++TEST_F(ThreadedWorkletTest, NestedRunLoopTermination) { ++ MessagingProxy()->Start(); ++ ++ ThreadedWorkletMessagingProxyForTest* second_messaging_proxy = ++ MakeGarbageCollected( ++ GetExecutionContext()); ++ ++ // Get a nested event loop where the first one is on the stack ++ // and the second is still alive. ++ second_messaging_proxy->Start(); ++ ++ // Wait until the workers are setup and ready to accept work before we ++ // pause them. ++ WaitForReady(GetWorkerThread()); ++ WaitForReady(second_messaging_proxy->GetWorkerThread()); ++ ++ // Pause the second worker, then the first. ++ second_messaging_proxy->GetWorkerThread()->Pause(); ++ GetWorkerThread()->Pause(); ++ ++ // Resume then terminate the second worker. ++ second_messaging_proxy->GetWorkerThread()->Resume(); ++ second_messaging_proxy->GetWorkerThread()->Terminate(); ++ second_messaging_proxy = nullptr; ++ ++ // Now resume the first worker. ++ GetWorkerThread()->Resume(); ++ ++ // Make sure execution still works without crashing. ++ PostCrossThreadTask( ++ *GetWorkerThread()->GetTaskRunner(TaskType::kInternalTest), FROM_HERE, ++ CrossThreadBindOnce(&ThreadedWorkletThreadForTest::TestTaskRunner, ++ CrossThreadUnretained(GetWorkerThread()))); ++ test::EnterRunLoop(); ++} ++ + } // namespace blink +diff --git a/third_party/blink/renderer/core/workers/worker_thread.cc b/third_party/blink/renderer/core/workers/worker_thread.cc +index 892b3e58443f1a82a6a41c6d52df7d2d701b377d..3a98c2d192e1e47d1586d1dab1fc9e9dc9daf83b 100644 +--- a/third_party/blink/renderer/core/workers/worker_thread.cc ++++ b/third_party/blink/renderer/core/workers/worker_thread.cc +@@ -30,7 +30,6 @@ + #include + #include + +-#include "base/auto_reset.h" + #include "base/metrics/histogram_functions.h" + #include "base/synchronization/waitable_event.h" + #include "base/threading/thread_restrictions.h" +@@ -593,6 +592,7 @@ void WorkerThread::InitializeOnWorkerThread( + const absl::optional& thread_startup_data, + std::unique_ptr devtools_params) { + DCHECK(IsCurrentThread()); ++ backing_thread_weak_factory_.emplace(this); + worker_reporting_proxy_.WillInitializeWorkerContext(); + { + TRACE_EVENT0("blink.worker", "WorkerThread::InitializeWorkerContext"); +@@ -728,11 +728,13 @@ void WorkerThread::PrepareForShutdownOnWorkerThread() { + SetThreadState(ThreadState::kReadyToShutdown); + } + ++ backing_thread_weak_factory_ = absl::nullopt; + if (pause_or_freeze_count_ > 0) { + DCHECK(nested_runner_); + pause_or_freeze_count_ = 0; + nested_runner_->QuitNow(); + } ++ pause_handle_.reset(); + + { + v8::HandleScope handle_scope(GetIsolate()); +@@ -883,8 +885,7 @@ void WorkerThread::PauseOrFreezeOnWorkerThread( + if (pause_or_freeze_count_ > 1) + return; + +- std::unique_ptr pause_handle = +- GetScheduler()->Pause(); ++ pause_handle_ = GetScheduler()->Pause(); + { + // Since the nested message loop runner needs to be created and destroyed on + // the same thread we allocate and destroy a new message loop runner each +@@ -892,13 +893,20 @@ void WorkerThread::PauseOrFreezeOnWorkerThread( + // the worker thread such that the resume/terminate can quit this runner. + std::unique_ptr nested_runner = + Platform::Current()->CreateNestedMessageLoopRunner(); +- base::AutoReset nested_runner_autoreset( +- &nested_runner_, nested_runner.get()); ++ auto weak_this = backing_thread_weak_factory_->GetWeakPtr(); ++ nested_runner_ = nested_runner.get(); + nested_runner->Run(); ++ ++ // Careful `this` may be destroyed. ++ if (!weak_this) { ++ return; ++ } ++ nested_runner_ = nullptr; + } + GlobalScope()->SetDefersLoadingForResourceFetchers(LoaderFreezeMode::kNone); + GlobalScope()->SetIsInBackForwardCache(false); + GlobalScope()->SetLifecycleState(mojom::blink::FrameLifecycleState::kRunning); ++ pause_handle_.reset(); + } + + void WorkerThread::ResumeOnWorkerThread() { +diff --git a/third_party/blink/renderer/core/workers/worker_thread.h b/third_party/blink/renderer/core/workers/worker_thread.h +index 834aabc12fe0c43f69bb3a5fa669571c84847c6d..2431c406268a3631df157a24c3fd7accf184cccc 100644 +--- a/third_party/blink/renderer/core/workers/worker_thread.h ++++ b/third_party/blink/renderer/core/workers/worker_thread.h +@@ -31,6 +31,7 @@ + + #include "base/gtest_prod_util.h" + #include "base/memory/scoped_refptr.h" ++#include "base/memory/weak_ptr.h" + #include "base/synchronization/waitable_event.h" + #include "base/task/single_thread_task_runner.h" + #include "base/thread_annotations.h" +@@ -80,7 +81,7 @@ struct WorkerMainScriptLoadParameters; + // abstract class. Multiple WorkerThreads may share one WorkerBackingThread for + // worklets. + // +-// WorkerThread start and termination must be initiated on the main thread and ++// WorkerThread start and termination must be initiated on the parent thread and + // an actual task is executed on the worker thread. + // + // When termination starts, (debugger) tasks on WorkerThread are handled as +@@ -103,7 +104,7 @@ class CORE_EXPORT WorkerThread : public Thread::TaskObserver { + ~WorkerThread() override; + + // Starts the underlying thread and creates the global scope. Called on the +- // main thread. ++ // parent thread. + // Startup data for WorkerBackingThread is absl::nullopt if |this| doesn't own + // the underlying WorkerBackingThread. + // TODO(nhiroki): We could separate WorkerBackingThread initialization from +@@ -115,14 +116,14 @@ class CORE_EXPORT WorkerThread : public Thread::TaskObserver { + std::unique_ptr); + + // Posts a task to evaluate a top-level classic script on the worker thread. +- // Called on the main thread after Start(). ++ // Called on the parent thread after Start(). + void EvaluateClassicScript(const KURL& script_url, + const String& source_code, + std::unique_ptr> cached_meta_data, + const v8_inspector::V8StackTraceId& stack_id); + + // Posts a task to fetch and run a top-level classic script on the worker +- // thread. Called on the main thread after Start(). ++ // thread. Called on the parent thread after Start(). + void FetchAndRunClassicScript( + const KURL& script_url, + std::unique_ptr +@@ -133,7 +134,7 @@ class CORE_EXPORT WorkerThread : public Thread::TaskObserver { + const v8_inspector::V8StackTraceId& stack_id); + + // Posts a task to fetch and run a top-level module script on the worker +- // thread. Called on the main thread after Start(). ++ // thread. Called on the parent thread after Start(). + void FetchAndRunModuleScript( + const KURL& script_url, + std::unique_ptr +@@ -154,7 +155,7 @@ class CORE_EXPORT WorkerThread : public Thread::TaskObserver { + // Terminates the worker thread. Subclasses of WorkerThread can override this + // to do cleanup. The default behavior is to call Terminate() and + // synchronously call EnsureScriptExecutionTerminates() to ensure the thread +- // is quickly terminated. Called on the main thread. ++ // is quickly terminated. Called on the parent thread. + virtual void TerminateForTesting(); + + // Thread::TaskObserver. +@@ -181,7 +182,7 @@ class CORE_EXPORT WorkerThread : public Thread::TaskObserver { + void DebuggerTaskStarted(); + void DebuggerTaskFinished(); + +- // Callable on both the main thread and the worker thread. ++ // Callable on both the parent thread and the worker thread. + const base::UnguessableToken& GetDevToolsWorkerToken() const { + return devtools_worker_token_; + } +@@ -325,7 +326,7 @@ class CORE_EXPORT WorkerThread : public Thread::TaskObserver { + // already shutting down. Does not terminate if a debugger task is running, + // because the debugger task is guaranteed to finish and it heavily uses V8 + // API calls which would crash after forcible script termination. Called on +- // the main thread. ++ // the parent thread. + void EnsureScriptExecutionTerminates(ExitCode) LOCKS_EXCLUDED(mutex_); + + // These are called in this order during worker thread startup. +@@ -410,7 +411,7 @@ class CORE_EXPORT WorkerThread : public Thread::TaskObserver { + // A unique identifier among all WorkerThreads. + const int worker_thread_id_; + +- // Set on the main thread. ++ // Set on the parent thread. + bool requested_to_terminate_ GUARDED_BY(mutex_) = false; + + ThreadState thread_state_ GUARDED_BY(mutex_) = ThreadState::kNotStarted; +@@ -444,7 +445,7 @@ class CORE_EXPORT WorkerThread : public Thread::TaskObserver { + TaskTypeTraits>; + TaskRunnerHashMap worker_task_runners_; + +- // This lock protects shared states between the main thread and the worker ++ // This lock protects shared states between the parent thread and the worker + // thread. See thread-safety annotations (e.g., GUARDED_BY) in this header + // file. + Mutex mutex_; +@@ -453,6 +454,10 @@ class CORE_EXPORT WorkerThread : public Thread::TaskObserver { + // only on the worker thread. + int pause_or_freeze_count_ = 0; + ++ // The `PauseHandle` needs to be destroyed before the scheduler is destroyed ++ // otherwise we will hit a DCHECK. ++ std::unique_ptr pause_handle_; ++ + // A nested message loop for handling pausing. Pointer is not owned. Used only + // on the worker thread. + Platform::NestedMessageLoopRunner* nested_runner_ = nullptr; +@@ -479,6 +484,12 @@ class CORE_EXPORT WorkerThread : public Thread::TaskObserver { + HashSet> pending_interrupts_ + GUARDED_BY(mutex_); + ++ // Since the WorkerThread is allocated and deallocated on the parent thread, ++ // we need a WeakPtrFactory that is allocated and cleared on the backing ++ // thread. ++ absl::optional> ++ backing_thread_weak_factory_; ++ + THREAD_CHECKER(parent_thread_checker_); + }; + diff --git a/patches/chromium/cherry-pick-c83640db21b5.patch b/patches/chromium/cherry-pick-c83640db21b5.patch new file mode 100644 index 0000000000000..405f2f45731ef --- /dev/null +++ b/patches/chromium/cherry-pick-c83640db21b5.patch @@ -0,0 +1,122 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Samuel Attard +Date: Wed, 5 Oct 2022 06:03:23 +0000 +Subject: build: set DTSDKBuild correctly when generating plist files + +Currently we set DTSDKBuild to the version of the SDK used to build +Chromium. This value is supposed to be the build version (this is +what xcode sets it to for instance). We read this value out of the +SDK directly and use it instead. + +Change-Id: Ieb7990f13095683ad8c026f027b2605ae39523a4 + +diff --git a/build/config/mac/mac_sdk.gni b/build/config/mac/mac_sdk.gni +index 7b1761607c853ae79619d6b872167a00a39f8236..c8e07ad62519236ead55c9b7ce1b1a4c3d5491af 100644 +--- a/build/config/mac/mac_sdk.gni ++++ b/build/config/mac/mac_sdk.gni +@@ -40,6 +40,11 @@ declare_args() { + # will fail. + mac_sdk_official_version = "12.3" + ++ # The SDK build version used when making official builds. This is a single ++ # exact version found at "System/Library/CoreServices/SystemVersion.plist" ++ # inside the SDK. ++ mac_sdk_official_build_version = "21E226" ++ + # Production builds should use hermetic Xcode. If you want to do production + # builds with system Xcode to test new SDKs, set this. + # Don't set this on any bots. +@@ -101,11 +106,13 @@ if (use_system_xcode) { + find_sdk_args = [ + "--print_sdk_path", + "--print_bin_path", ++ "--print_sdk_build", + mac_sdk_min, + ] + find_sdk_lines = + exec_script("//build/mac/find_sdk.py", find_sdk_args, "list lines") +- mac_sdk_version = find_sdk_lines[2] ++ mac_sdk_version = find_sdk_lines[3] ++ mac_sdk_build_version = find_sdk_lines[2] + if (mac_sdk_path == "") { + mac_sdk_path = find_sdk_lines[0] + mac_bin_path = find_sdk_lines[1] +@@ -114,6 +121,7 @@ if (use_system_xcode) { + } + } else { + mac_sdk_version = mac_sdk_official_version ++ mac_sdk_build_version = mac_sdk_official_build_version + _dev = _hermetic_xcode_path + "/Contents/Developer" + _sdk = "MacOSX${mac_sdk_version}.sdk" + mac_sdk_path = _dev + "/Platforms/MacOSX.platform/Developer/SDKs/$_sdk" +diff --git a/build/config/mac/rules.gni b/build/config/mac/rules.gni +index 03073f830401c4891376a3b59e2e7a870e3d34b7..04d403054c1a83fcbbc70be7cfd239ecbec315d3 100644 +--- a/build/config/mac/rules.gni ++++ b/build/config/mac/rules.gni +@@ -41,7 +41,7 @@ template("mac_info_plist") { + apple_info_plist(target_name) { + format = "xml1" + extra_substitutions = [ +- "MAC_SDK_BUILD=$mac_sdk_version", ++ "MAC_SDK_BUILD=$mac_sdk_build_version", + "MAC_SDK_NAME=$mac_sdk_name$mac_sdk_version", + "MACOSX_DEPLOYMENT_TARGET=$mac_deployment_target", + "CHROMIUM_MIN_SYSTEM_VERSION=$mac_min_system_version", +diff --git a/build/mac/find_sdk.py b/build/mac/find_sdk.py +index d86f3109357a9246d570cb02992dc82552ba7c20..b2400c7e8c70957e364444f509880900ce3b641f 100755 +--- a/build/mac/find_sdk.py ++++ b/build/mac/find_sdk.py +@@ -24,6 +24,7 @@ Sample Output: + from __future__ import print_function + + import os ++import plistlib + import re + import subprocess + import sys +@@ -51,6 +52,9 @@ def main(): + parser.add_option("--print_bin_path", + action="store_true", dest="print_bin_path", default=False, + help="Additionally print the path the toolchain bin dir.") ++ parser.add_option("--print_sdk_build", ++ action="store_true", dest="print_sdk_build", default=False, ++ help="Additionally print the build version of the SDK.") + options, args = parser.parse_args() + if len(args) != 1: + parser.error('Please specify a minimum SDK version') +@@ -80,20 +84,30 @@ def main(): + if not sdks: + raise Exception('No %s+ SDK found' % min_sdk_version) + best_sdk = sorted(sdks, key=parse_version)[0] ++ sdk_name = 'MacOSX' + best_sdk + '.sdk' ++ sdk_path = os.path.join(sdk_dir, sdk_name) + + if options.print_sdk_path: +- sdk_name = 'MacOSX' + best_sdk + '.sdk' +- print(os.path.join(sdk_dir, sdk_name)) ++ print(sdk_path) + + if options.print_bin_path: + bin_path = 'Toolchains/XcodeDefault.xctoolchain/usr/bin/' + print(os.path.join(dev_dir, bin_path)) + +- return best_sdk ++ if options.print_sdk_build: ++ system_version_plist = os.path.join(sdk_path, ++ 'System/Library/CoreServices/SystemVersion.plist') ++ with open(system_version_plist, 'rb') as f: ++ system_version_info = plistlib.load(f) ++ if 'ProductBuildVersion' not in system_version_info: ++ raise Exception('Failed to determine ProductBuildVersion' + ++ 'for SDK at path %s' % system_version_plist) ++ print(system_version_info['ProductBuildVersion']) ++ ++ print(best_sdk) + + + if __name__ == '__main__': + if sys.platform != 'darwin': + raise Exception("This script only runs on Mac") +- print(main()) +- sys.exit(0) ++ sys.exit(main()) diff --git a/patches/chromium/cherry-pick-ca2b108a0f1f.patch b/patches/chromium/cherry-pick-ca2b108a0f1f.patch new file mode 100644 index 0000000000000..a54950ca4cbe9 --- /dev/null +++ b/patches/chromium/cherry-pick-ca2b108a0f1f.patch @@ -0,0 +1,116 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Harald Alvestrand +Date: Wed, 18 Jan 2023 08:02:48 +0000 +Subject: Delete PeerConnectionHandler in PeerConnection finalizer + +Also guard against removal of PC during PeerConnectionHandler +call that may cause garbage collection. + +(cherry picked from commit 5066dd66309d884762e5fb9be04b59582893d09a) + +Bug: chromium:1405256 +Change-Id: I9adf7b219e2026e07ccc0868c1a85f3b35cd9d26 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4154578 +Commit-Queue: Harald Alvestrand +Reviewed-by: Guido Urdaneta +Commit-Queue: Guido Urdaneta +Cr-Original-Commit-Position: refs/heads/main@{#1091801} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4176372 +Auto-Submit: Harald Alvestrand +Cr-Commit-Position: refs/branch-heads/5481@{#418} +Cr-Branched-From: 130f3e4d850f4bc7387cfb8d08aa993d288a67a9-refs/heads/main@{#1084008} + +diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc +index bcb9e9f13cfa525499023e369cefe0ed23f47abc..cf01e7144fc2901c88f320ea7b1c093dfb6ab8b1 100644 +--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc ++++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc +@@ -819,10 +819,11 @@ RTCPeerConnection::~RTCPeerConnection() { + } + + void RTCPeerConnection::Dispose() { +- // Promptly clears the handler's pointer to |this| ++ // Promptly clears the handler + // so that content/ doesn't access it in a lazy sweeping phase. ++ // Other references to the handler use a weak pointer, preventing access. + if (peer_handler_) { +- peer_handler_->CloseAndUnregister(); ++ peer_handler_.reset(); + } + } + +diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc +index 7662f2cda29b6265705a4f83dbf76ccaf50ab576..48bd8a4eee90b07a38c7f09f260da30c9e7e34bc 100644 +--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc ++++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_handler.cc +@@ -771,6 +771,8 @@ class RTCPeerConnectionHandler::WebRtcSetDescriptionObserverImpl + if (handler_) { + handler_->OnModifySctpTransport(std::move(states.sctp_transport_state)); + } ++ // Since OnSessionDescriptionsUpdated can fire events, it may cause ++ // garbage collection. Ensure that handler_ is still valid. + if (handler_) { + handler_->OnModifyTransceivers( + states.signaling_state, std::move(states.transceiver_states), +@@ -1128,6 +1130,8 @@ bool RTCPeerConnectionHandler::Initialize( + CHECK(!initialize_called_); + initialize_called_ = true; + ++ // Prevent garbage collection of client_ during processing. ++ auto* client_on_stack = client_; + peer_connection_tracker_ = PeerConnectionTracker::From(*frame); + + configuration_ = server_configuration; +@@ -1165,8 +1169,8 @@ bool RTCPeerConnectionHandler::Initialize( + peer_connection_tracker_->RegisterPeerConnection(this, configuration_, + options, frame_); + } +- +- return true; ++ // Gratuitous usage of client_on_stack to prevent compiler errors. ++ return !!client_on_stack; + } + + bool RTCPeerConnectionHandler::InitializeForTest( +@@ -2229,9 +2233,11 @@ void RTCPeerConnectionHandler::OnSessionDescriptionsUpdated( + pending_remote_description, + std::unique_ptr + current_remote_description) { ++ // Prevent garbage collection of client_ during processing. ++ auto* client_on_stack = client_; + if (!client_ || is_closed_) + return; +- client_->DidChangeSessionDescriptions( ++ client_on_stack->DidChangeSessionDescriptions( + pending_local_description + ? CreateWebKitSessionDescription(pending_local_description.get()) + : nullptr, +@@ -2552,8 +2558,12 @@ void RTCPeerConnectionHandler::OnIceCandidate(const String& sdp, + int sdp_mline_index, + int component, + int address_family) { ++ // In order to ensure that the RTCPeerConnection is not garbage collected ++ // from under the function, we keep a pointer to it on the stack. ++ auto* client_on_stack = client_; + DCHECK(task_runner_->RunsTasksInCurrentSequence()); + TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnIceCandidateImpl"); ++ // This line can cause garbage collection. + auto* platform_candidate = MakeGarbageCollected( + sdp, sdp_mid, sdp_mline_index); + if (peer_connection_tracker_) { +@@ -2573,7 +2583,7 @@ void RTCPeerConnectionHandler::OnIceCandidate(const String& sdp, + } + } + if (!is_closed_) +- client_->DidGenerateICECandidate(platform_candidate); ++ client_on_stack->DidGenerateICECandidate(platform_candidate); + } + + void RTCPeerConnectionHandler::OnIceCandidateError( +@@ -2585,7 +2595,6 @@ void RTCPeerConnectionHandler::OnIceCandidateError( + const String& error_text) { + DCHECK(task_runner_->RunsTasksInCurrentSequence()); + TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::OnIceCandidateError"); +- + if (peer_connection_tracker_) { + peer_connection_tracker_->TrackIceCandidateError( + this, address, port, host_candidate, url, error_code, error_text); diff --git a/patches/chromium/cherry-pick-cb9dff93f3d4.patch b/patches/chromium/cherry-pick-cb9dff93f3d4.patch new file mode 100644 index 0000000000000..ddc6e7bec280b --- /dev/null +++ b/patches/chromium/cherry-pick-cb9dff93f3d4.patch @@ -0,0 +1,86 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Harald Alvestrand +Date: Mon, 10 Oct 2022 08:37:15 +0000 +Subject: Use HeapMojoReceiver rather than mojo::Receiver for + PeerConnectionTracker +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +HeapMojoReceiver is recommended for garbage collected objects, avoiding +problems with conflicting lifetimes. + +(cherry picked from commit e3437317c4cd8401f0f0d599b61751bbe0e1ec70) + +Bug: chromium:1369882 +Change-Id: Ic38e761cf4275e6d7b30a6d7e2daa5d1596e67a4 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3936144 +Reviewed-by: Henrik Boström +Commit-Queue: Harald Alvestrand +Cr-Original-Commit-Position: refs/heads/main@{#1055630} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3934344 +Commit-Queue: Henrik Boström +Auto-Submit: Harald Alvestrand +Cr-Commit-Position: refs/branch-heads/5249@{#790} +Cr-Branched-From: 4f7bea5de862aaa52e6bde5920755a9ef9db120b-refs/heads/main@{#1036826} + +diff --git a/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.cc b/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.cc +index 30e5b6bfb365a738d72fdab31fee0d657cbc26c7..e77370db8ae1115a9e99e658364b14efe8d27cd3 100644 +--- a/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.cc ++++ b/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.cc +@@ -644,16 +644,20 @@ PeerConnectionTracker::PeerConnectionTracker( + scoped_refptr main_thread_task_runner, + base::PassKey) + : Supplement(window), ++ receiver_(this, &window), + main_thread_task_runner_(std::move(main_thread_task_runner)) { + window.GetBrowserInterfaceBroker().GetInterface( + peer_connection_tracker_host_.BindNewPipeAndPassReceiver()); + } + ++// Constructor used for testing. Note that receiver_ doesn't have a context ++// notifier in this case. + PeerConnectionTracker::PeerConnectionTracker( + mojo::Remote host, + scoped_refptr main_thread_task_runner) + : Supplement(nullptr), + peer_connection_tracker_host_(std::move(host)), ++ receiver_(this, nullptr), + main_thread_task_runner_(std::move(main_thread_task_runner)) {} + + PeerConnectionTracker::~PeerConnectionTracker() {} +diff --git a/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.h b/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.h +index 477dfc3a5384643f46804966888afa549769d39d..6a31cf39f3d1a03981ff438c9c1463f168f53423 100644 +--- a/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.h ++++ b/third_party/blink/renderer/modules/peerconnection/peer_connection_tracker.h +@@ -15,6 +15,7 @@ + #include "third_party/blink/renderer/core/frame/local_dom_window.h" + #include "third_party/blink/renderer/modules/mediastream/media_stream.h" + #include "third_party/blink/renderer/modules/modules_export.h" ++#include "third_party/blink/renderer/platform/mojo/heap_mojo_receiver.h" + #include "third_party/blink/renderer/platform/peerconnection/rtc_peer_connection_handler_client.h" + #include "third_party/blink/renderer/platform/peerconnection/rtc_rtp_transceiver_platform.h" + #include "third_party/blink/renderer/platform/peerconnection/rtc_session_description_platform.h" +@@ -252,6 +253,11 @@ class MODULES_EXPORT PeerConnectionTracker + virtual void TrackRtcEventLogWrite(RTCPeerConnectionHandler* pc_handler, + const WTF::Vector& output); + ++ void Trace(Visitor* visitor) const override { ++ visitor->Trace(receiver_); ++ Supplement::Trace(visitor); ++ } ++ + private: + FRIEND_TEST_ALL_PREFIXES(PeerConnectionTrackerTest, OnSuspend); + FRIEND_TEST_ALL_PREFIXES(PeerConnectionTrackerTest, OnThermalStateChange); +@@ -320,7 +326,9 @@ class MODULES_EXPORT PeerConnectionTracker + THREAD_CHECKER(main_thread_); + mojo::Remote + peer_connection_tracker_host_; +- mojo::Receiver receiver_{this}; ++ HeapMojoReceiver ++ receiver_; + + scoped_refptr main_thread_task_runner_; + }; diff --git a/patches/chromium/cherry-pick-d1d654d73222.patch b/patches/chromium/cherry-pick-d1d654d73222.patch new file mode 100644 index 0000000000000..c4467ef8cc37c --- /dev/null +++ b/patches/chromium/cherry-pick-d1d654d73222.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ken Rockot +Date: Wed, 7 Dec 2022 20:35:15 +0000 +Subject: Mojo: Fix potential UAF in IPC Channel + +(cherry picked from commit 120b4b05ac7eaa9024f677394aa663c2702174ce) + +Fixed: 1394692 +Change-Id: I1753b79eb6e9230ebb663eca47295d81dd859068 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4066994 +Commit-Queue: Ken Rockot +Reviewed-by: Daniel Cheng +Cr-Original-Commit-Position: refs/heads/main@{#1077742} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4085806 +Commit-Queue: Rubber Stamper +Auto-Submit: Ken Rockot +Bot-Commit: Rubber Stamper +Cr-Commit-Position: refs/branch-heads/5359@{#1115} +Cr-Branched-From: 27d3765d341b09369006d030f83f582a29eb57ae-refs/heads/main@{#1058933} + +diff --git a/ipc/ipc_mojo_bootstrap.cc b/ipc/ipc_mojo_bootstrap.cc +index a0bd86951a20cf2d60c7805a3a7fa687d66ca329..eb8fa358b0a72eea2e294c531549da5fc81f394c 100644 +--- a/ipc/ipc_mojo_bootstrap.cc ++++ b/ipc/ipc_mojo_bootstrap.cc +@@ -629,9 +629,12 @@ class ChannelAssociatedGroupController + void OnSyncMessageEventReady() { + DCHECK(task_runner_->RunsTasksInCurrentSequence()); + +- scoped_refptr keepalive(this); ++ // SUBTLE: The order of these scoped_refptrs matters. ++ // `controller_keepalive` MUST outlive `keepalive` because the Endpoint ++ // holds raw pointer to the AssociatedGroupController. + scoped_refptr controller_keepalive( + controller_.get()); ++ scoped_refptr keepalive(this); + base::AutoLock locker(controller_->lock_); + bool more_to_process = false; + if (!sync_messages_.empty()) { diff --git a/patches/chromium/cherry-pick-d5ffb4dd4112.patch b/patches/chromium/cherry-pick-d5ffb4dd4112.patch new file mode 100644 index 0000000000000..75efb704cc390 --- /dev/null +++ b/patches/chromium/cherry-pick-d5ffb4dd4112.patch @@ -0,0 +1,70 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shrek Shao +Date: Tue, 18 Oct 2022 01:30:12 +0000 +Subject: WebGPU: use CHECK instead of DCHECK to crash out of bounds write in + SerializeDataUpdate + +A comprised renderer could have a shared memory size not large enough +to fit the GPU buffer contents. Instead of DCHECK, do a CHECK here to +crash the release build. The crash is fine since it is not reachable +from normal behavior. WebGPU post-V1 will have a refactored API. + +(cherry picked from commit 9bcbce75d5feaa1ba48a5d0d8036b5c77500bb67) + +Fixed: 1373314 +Change-Id: I8d8e1a469c2b10ff16e7363f9b6f7b63587cb007 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3946246 +Reviewed-by: Austin Eng +Commit-Queue: Shrek Shao +Cr-Original-Commit-Position: refs/heads/main@{#1058233} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3956286 +Owners-Override: Prudhvikumar Bommana +Reviewed-by: Prudhvikumar Bommana +Commit-Queue: Prudhvikumar Bommana +Cr-Commit-Position: refs/branch-heads/5249@{#850} +Cr-Branched-From: 4f7bea5de862aaa52e6bde5920755a9ef9db120b-refs/heads/main@{#1036826} + +diff --git a/gpu/command_buffer/service/dawn_service_memory_transfer_service.cc b/gpu/command_buffer/service/dawn_service_memory_transfer_service.cc +index 579cd3cbdfcd5990db02960413bcac86e41c69b2..a15b6f9b3b345079d8cf8251ca5f77b6e7ef647a 100644 +--- a/gpu/command_buffer/service/dawn_service_memory_transfer_service.cc ++++ b/gpu/command_buffer/service/dawn_service_memory_transfer_service.cc +@@ -30,8 +30,13 @@ class ReadHandleImpl + size_t offset, + size_t size, + void* serializePointer) override { +- DCHECK_LE(offset, size_); +- DCHECK_LE(size, size_ - offset); ++ // TODO(crbug.com/1373314): A compromised renderer could have a shared ++ // memory size not large enough to fit the GPU buffer contents. Instead of ++ // DCHECK, do a CHECK here to crash the release build. The crash is fine ++ // since it is not reachable from normal behavior. WebGPU post-V1 will have ++ // a refactored API. ++ CHECK_LE(offset, size_); ++ CHECK_LE(size, size_ - offset); + // Copy the data into the shared memory allocation. + // In the case of buffer mapping, this is the mapped GPU memory which we + // copy into client-visible shared memory. +@@ -94,7 +99,10 @@ bool DawnServiceMemoryTransferService::DeserializeReadHandle( + size_t deserialize_size, + ReadHandle** read_handle) { + DCHECK(deserialize_pointer); +- DCHECK_EQ(deserialize_size, sizeof(MemoryTransferHandle)); ++ // Use CHECK instead of DCHECK because the cast of the memory to ++ // MemoryTransferHandle and subsequent reads won't be safe if deserialize_size ++ // is too small. ++ CHECK_EQ(deserialize_size, sizeof(MemoryTransferHandle)); + const volatile MemoryTransferHandle* handle = + reinterpret_cast( + deserialize_pointer); +@@ -119,7 +127,10 @@ bool DawnServiceMemoryTransferService::DeserializeWriteHandle( + size_t deserialize_size, + WriteHandle** write_handle) { + DCHECK(deserialize_pointer); +- DCHECK_EQ(deserialize_size, sizeof(MemoryTransferHandle)); ++ // Use CHECK instead of DCHECK because the cast of the memory to ++ // MemoryTransferHandle and subsequent reads won't be safe if deserialize_size ++ // is too small. ++ CHECK_EQ(deserialize_size, sizeof(MemoryTransferHandle)); + const volatile MemoryTransferHandle* handle = + reinterpret_cast( + deserialize_pointer); diff --git a/patches/chromium/cherry-pick-d652130c4bc2.patch b/patches/chromium/cherry-pick-d652130c4bc2.patch new file mode 100644 index 0000000000000..243d3ef8702c2 --- /dev/null +++ b/patches/chromium/cherry-pick-d652130c4bc2.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Vasiliy Telezhnikov +Date: Mon, 16 Jan 2023 17:43:34 +0000 +Subject: Remove NUM_COMMAND_BUFFER_NAMESPACES from SyncToken.mojom + +Mojo validates input for allowed values, NUM_COMMAND_BUFFER_NAMESPACES +is not valid value to send over ipc and is used only to know maximum +value in code. + +Bug: 1406115 +Change-Id: I8e5c3b6b2a9a9206fbeb377b27ceb1242a4f54e2 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4167409 +Reviewed-by: danakj +Commit-Queue: Vasiliy Telezhnikov +Cr-Commit-Position: refs/heads/main@{#1093100} + +diff --git a/gpu/ipc/common/sync_token.mojom b/gpu/ipc/common/sync_token.mojom +index 7c957007e3a377bd1e9969f14d9edc80c7d76645..b24017647aa6a11080580dd48e4c3d1cd79d1cf3 100644 +--- a/gpu/ipc/common/sync_token.mojom ++++ b/gpu/ipc/common/sync_token.mojom +@@ -11,9 +11,7 @@ enum CommandBufferNamespace { + GPU_IO, + IN_PROCESS, + MOJO, +- MOJO_LOCAL, +- +- NUM_COMMAND_BUFFER_NAMESPACES ++ MOJO_LOCAL + }; + + // See gpu/command_buffer/common/sync_token.h diff --git a/patches/chromium/cherry-pick-e545559df538.patch b/patches/chromium/cherry-pick-e545559df538.patch new file mode 100644 index 0000000000000..b1e274af6aa43 --- /dev/null +++ b/patches/chromium/cherry-pick-e545559df538.patch @@ -0,0 +1,103 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Victor Vasiliev +Date: Thu, 12 Jan 2023 22:03:48 +0000 +Subject: Ensure clean destruction of network::WebTransport + +Once the destruction of the object begins, we should not process any +callbacks, nor should we attempt to reset the streams on a connection +that is already being closed. + +(cherry picked from commit 57c54ae221d60e9f9394d7ee69634d66c9cd26f3) + +Bug: 1376354 +Change-Id: Ib49e0ce0b177062cccd0e52368782e291cf8166c +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4117501 +Reviewed-by: Eric Orth +Commit-Queue: Victor Vasiliev +Cr-Original-Commit-Position: refs/heads/main@{#1085965} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4139783 +Reviewed-by: Kenichi Ishibashi +Cr-Commit-Position: refs/branch-heads/5359@{#1326} +Cr-Branched-From: 27d3765d341b09369006d030f83f582a29eb57ae-refs/heads/main@{#1058933} + +diff --git a/services/network/web_transport.cc b/services/network/web_transport.cc +index fd62b83d43052d9d588a211b59e46a6c25ffeb76..534954181abcd7c4cf11eade64a2aa97c62785cc 100644 +--- a/services/network/web_transport.cc ++++ b/services/network/web_transport.cc +@@ -177,7 +177,7 @@ class WebTransport::Stream final { + + ~Stream() { + auto* stream = incoming_ ? incoming_.get() : outgoing_.get(); +- if (!stream) { ++ if (!stream || transport_->closing_ || transport_->torn_down_) { + return; + } + stream->MaybeResetDueToStreamObjectGone(); +@@ -399,7 +399,10 @@ WebTransport::WebTransport( + transport_->Connect(); + } + +-WebTransport::~WebTransport() = default; ++WebTransport::~WebTransport() { ++ // Ensure that we ignore all callbacks while mid-destruction. ++ torn_down_ = true; ++} + + void WebTransport::SendDatagram(base::span data, + base::OnceCallback callback) { +diff --git a/services/network/web_transport_unittest.cc b/services/network/web_transport_unittest.cc +index ffac5c19f9d154b91eb6aeac1e19a62277e4e7e8..46deb561091232fe64950be01e9157c8d891f111 100644 +--- a/services/network/web_transport_unittest.cc ++++ b/services/network/web_transport_unittest.cc +@@ -611,6 +611,51 @@ TEST_F(WebTransportTest, EchoOnUnidirectionalStreams) { + EXPECT_EQ(0u, resets_sent.size()); + } + ++TEST_F(WebTransportTest, DeleteClientWithStreamsOpen) { ++ base::RunLoop run_loop_for_handshake; ++ mojo::PendingRemote handshake_client; ++ TestHandshakeClient test_handshake_client( ++ handshake_client.InitWithNewPipeAndPassReceiver(), ++ run_loop_for_handshake.QuitClosure()); ++ ++ CreateWebTransport(GetURL("/echo"), ++ url::Origin::Create(GURL("https://example.org/")), ++ std::move(handshake_client)); ++ ++ run_loop_for_handshake.Run(); ++ ++ ASSERT_TRUE(test_handshake_client.has_seen_connection_establishment()); ++ ++ TestClient client(test_handshake_client.PassClientReceiver()); ++ mojo::Remote transport_remote( ++ test_handshake_client.PassTransport()); ++ ++ constexpr int kNumStreams = 10; ++ auto writable_for_outgoing = ++ std::make_unique(kNumStreams); ++ for (int i = 0; i < kNumStreams; i++) { ++ const MojoCreateDataPipeOptions options = { ++ sizeof(options), MOJO_CREATE_DATA_PIPE_FLAG_NONE, 1, 4 * 1024}; ++ mojo::ScopedDataPipeConsumerHandle readable_for_outgoing; ++ ASSERT_EQ(MOJO_RESULT_OK, ++ mojo::CreateDataPipe(&options, writable_for_outgoing[i], ++ readable_for_outgoing)); ++ base::RunLoop run_loop_for_stream_creation; ++ bool stream_created; ++ transport_remote->CreateStream( ++ std::move(readable_for_outgoing), ++ /*writable=*/{}, ++ base::BindLambdaForTesting([&](bool b, uint32_t /*id*/) { ++ stream_created = b; ++ run_loop_for_stream_creation.Quit(); ++ })); ++ run_loop_for_stream_creation.Run(); ++ ASSERT_TRUE(stream_created); ++ } ++ ++ // Keep the streams open so that they are closed via destructor. ++} ++ + // crbug.com/1129847: disabled because it is flaky. + TEST_F(WebTransportTest, DISABLED_EchoOnBidirectionalStream) { + base::RunLoop run_loop_for_handshake; diff --git a/patches/chromium/cherry-pick-eed5a4de2c40.patch b/patches/chromium/cherry-pick-eed5a4de2c40.patch new file mode 100644 index 0000000000000..72d2ff2413fe5 --- /dev/null +++ b/patches/chromium/cherry-pick-eed5a4de2c40.patch @@ -0,0 +1,132 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: David Yeung +Date: Thu, 8 Dec 2022 17:56:44 +0000 +Subject: Fix UaF in ui::DropTargetEvent::DropTargetEvent. + +There is an async operation in WebContentsViewAura that uses a ui::DropTargetEvent. DropTargetEvent has a pointer to OSExchangeData which gets destroyed before the async operation is called. This triggers the UaF because the operation attempts to reference a freed object (OSExchangeData). + +Fix is for WebContentsViewAura::DragUpdatedCallback to use a DropMetadata struct instead of a ui::DropTargetEvent. This is the same pattern used by other callbacks in WebContentsViewAura. + +(cherry picked from commit 9f4b5761c546a118b7187c0c7ddcb9ee5756f32c) + +Bug: 1392661 +Change-Id: I3c62a7473ef9b6cdd223f75fbda50671f539f9eb +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4070787 +Reviewed-by: Avi Drissman +Commit-Queue: David Yeung +Cr-Original-Commit-Position: refs/heads/main@{#1078218} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4085256 +Cr-Commit-Position: refs/branch-heads/5359@{#1125} +Cr-Branched-From: 27d3765d341b09369006d030f83f582a29eb57ae-refs/heads/main@{#1058933} + +diff --git a/content/browser/web_contents/web_contents_view_aura.cc b/content/browser/web_contents/web_contents_view_aura.cc +index 6792e64b2f0f4a5080beb57804f861d8297524d2..aae78786a7fd9290fb1e79e3417f29662d58ed0d 100644 +--- a/content/browser/web_contents/web_contents_view_aura.cc ++++ b/content/browser/web_contents/web_contents_view_aura.cc +@@ -348,6 +348,7 @@ aura::Window* GetHostWindow(aura::Window* window) { + WebContentsViewAura::DropMetadata::DropMetadata( + const ui::DropTargetEvent& event) { + localized_location = event.location_f(); ++ root_location = event.root_location_f(); + source_operations = event.source_operations(); + flags = event.flags(); + } +@@ -1444,7 +1445,7 @@ void WebContentsViewAura::OnDragEntered(const ui::DropTargetEvent& event) { + } + + void WebContentsViewAura::DragUpdatedCallback( +- ui::DropTargetEvent event, ++ DropMetadata drop_metadata, + std::unique_ptr drop_data, + base::WeakPtr target, + absl::optional transformed_pt) { +@@ -1465,24 +1466,23 @@ void WebContentsViewAura::DragUpdatedCallback( + aura::Window* root_window = GetNativeView()->GetRootWindow(); + aura::client::ScreenPositionClient* screen_position_client = + aura::client::GetScreenPositionClient(root_window); +- gfx::PointF screen_pt = event.root_location_f(); ++ gfx::PointF screen_pt = drop_metadata.root_location; + if (screen_position_client) + screen_position_client->ConvertPointToScreen(root_window, &screen_pt); + + if (target_rwh != current_rwh_for_drag_.get()) { + if (current_rwh_for_drag_) { +- gfx::PointF transformed_leave_point = event.location_f(); ++ gfx::PointF transformed_leave_point = drop_metadata.localized_location; + static_cast( + web_contents_->GetRenderWidgetHostView()) + ->TransformPointToCoordSpaceForView( +- event.location_f(), ++ drop_metadata.localized_location, + static_cast( + current_rwh_for_drag_->GetView()), + &transformed_leave_point); + current_rwh_for_drag_->DragTargetDragLeave(transformed_leave_point, + screen_pt); + } +- DropMetadata drop_metadata(event); + DragEnteredCallback(drop_metadata, std::move(drop_data), target, + transformed_pt); + } +@@ -1493,10 +1493,11 @@ void WebContentsViewAura::DragUpdatedCallback( + + DCHECK(transformed_pt.has_value()); + blink::DragOperationsMask op_mask = +- ConvertToDragOperationsMask(event.source_operations()); ++ ConvertToDragOperationsMask(drop_metadata.source_operations); + target_rwh->DragTargetDragOver( + transformed_pt.value(), screen_pt, op_mask, +- ui::EventFlagsToWebEventModifiers(event.flags()), base::DoNothing()); ++ ui::EventFlagsToWebEventModifiers(drop_metadata.flags), ++ base::DoNothing()); + + if (drag_dest_delegate_) + drag_dest_delegate_->OnDragOver(); +@@ -1506,7 +1507,6 @@ aura::client::DragUpdateInfo WebContentsViewAura::OnDragUpdated( + const ui::DropTargetEvent& event) { + if (web_contents_->ShouldIgnoreInputEvents()) + return aura::client::DragUpdateInfo(); +- + aura::client::DragUpdateInfo drag_info; + auto* focused_frame = web_contents_->GetFocusedFrame(); + if (focused_frame && !web_contents_->GetBrowserContext()->IsOffTheRecord()) { +@@ -1517,13 +1517,13 @@ aura::client::DragUpdateInfo WebContentsViewAura::OnDragUpdated( + std::unique_ptr drop_data = std::make_unique(); + // Calling this here as event.data might become invalid inside the callback. + PrepareDropData(drop_data.get(), event.data()); +- ++ DropMetadata drop_metadata(event); + web_contents_->GetInputEventRouter() + ->GetRenderWidgetHostAtPointAsynchronously( + web_contents_->GetRenderViewHost()->GetWidget()->GetView(), + event.location_f(), + base::BindOnce(&WebContentsViewAura::DragUpdatedCallback, +- weak_ptr_factory_.GetWeakPtr(), event, ++ weak_ptr_factory_.GetWeakPtr(), drop_metadata, + std::move(drop_data))); + + drag_info.drag_operation = static_cast(current_drag_op_); +diff --git a/content/browser/web_contents/web_contents_view_aura.h b/content/browser/web_contents/web_contents_view_aura.h +index 17745664eda9832da61ec0150fe5085776c9c7bc..aaa42c930ef04d8f0d20d65fbb22d5fd06ba2d48 100644 +--- a/content/browser/web_contents/web_contents_view_aura.h ++++ b/content/browser/web_contents/web_contents_view_aura.h +@@ -84,6 +84,10 @@ class CONTENT_EXPORT WebContentsViewAura + + // Location local to WebContentsViewAura. + gfx::PointF localized_location; ++ ++ // Root location of the drop target event. ++ gfx::PointF root_location; ++ + // The supported DnD operation of the source. A bitmask of + // ui::mojom::DragOperations. + int source_operations; +@@ -263,7 +267,7 @@ class CONTENT_EXPORT WebContentsViewAura + std::unique_ptr drop_data, + base::WeakPtr target, + absl::optional transformed_pt); +- void DragUpdatedCallback(ui::DropTargetEvent event, ++ void DragUpdatedCallback(DropMetadata drop_metadata, + std::unique_ptr drop_data, + base::WeakPtr target, + absl::optional transformed_pt); diff --git a/patches/chromium/cherry-pick-f46db6aac3e9.patch b/patches/chromium/cherry-pick-f46db6aac3e9.patch new file mode 100644 index 0000000000000..542dd6709371f --- /dev/null +++ b/patches/chromium/cherry-pick-f46db6aac3e9.patch @@ -0,0 +1,218 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Xiaocheng Hu +Date: Mon, 14 Nov 2022 20:01:38 +0000 +Subject: Do not traverse directory symlinks when uploading folder + +Previous patch crrev.com/c/3866767 removed symlink files when uploading +a folder. However, while the remaining files are themselves not +symlinks, they may be included as the result of traversing directory +symlink. + +This patch further excludes such files by checking if any parent +directory is a symlink, all the way until the base directory (which is +the directory chosen for upload). + +(cherry picked from commit 4fa830d8af6b2fb293219edeb39eebccfd322305) + +Fixed: 1378997 +Change-Id: I75a92df4cd50f9aba7824955a3de792583bc6154 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3997720 +Reviewed-by: Austin Sullivan +Reviewed-by: Mason Freed +Reviewed-by: Alex Moshchuk +Commit-Queue: Xiaocheng Hu +Cr-Original-Commit-Position: refs/heads/main@{#1067310} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4025427 +Bot-Commit: Rubber Stamper +Commit-Queue: Srinivas Sista +Owners-Override: Srinivas Sista +Cr-Commit-Position: refs/branch-heads/5359@{#823} +Cr-Branched-From: 27d3765d341b09369006d030f83f582a29eb57ae-refs/heads/main@{#1058933} + +diff --git a/content/browser/web_contents/file_chooser_impl.cc b/content/browser/web_contents/file_chooser_impl.cc +index 1aa19f7a735b444f2c33d5084edcdd14e3c2f5c5..f4fa1afda64bf0606d28d4accaec56e2624133db 100644 +--- a/content/browser/web_contents/file_chooser_impl.cc ++++ b/content/browser/web_contents/file_chooser_impl.cc +@@ -23,10 +23,24 @@ namespace content { + + namespace { + ++// Removes any file that is a symlink or is inside a directory symlink. ++// For |kUploadFolder| mode only. |base_dir| is the folder being uploaded. + std::vector RemoveSymlinks( +- std::vector files) { ++ std::vector files, ++ base::FilePath base_dir) { ++ DCHECK(!base_dir.empty()); + auto new_end = base::ranges::remove_if( +- files, &base::IsLink, ++ files, ++ [&base_dir](const base::FilePath& file_path) { ++ if (base::IsLink(file_path)) ++ return true; ++ for (base::FilePath path = file_path.DirName(); base_dir.IsParent(path); ++ path = path.DirName()) { ++ if (base::IsLink(path)) ++ return true; ++ } ++ return false; ++ }, + [](const auto& file) { return file->get_native_file()->file_path; }); + files.erase(new_end, files.end()); + return files; +@@ -78,7 +92,7 @@ void FileChooserImpl::FileSelectListenerImpl::FileSelected( + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, + {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, +- base::BindOnce(&RemoveSymlinks, std::move(files)), ++ base::BindOnce(&RemoveSymlinks, std::move(files), base_dir), + base::BindOnce(&FileChooserImpl::FileSelected, owner_->GetWeakPtr(), + base_dir, mode)); + } +diff --git a/content/browser/web_contents/file_chooser_impl_browsertest.cc b/content/browser/web_contents/file_chooser_impl_browsertest.cc +index f7519189638ece437c4285ddd490be3ea59e638d..7753f01681c21dc7afcb9ab124d301407874b76b 100644 +--- a/content/browser/web_contents/file_chooser_impl_browsertest.cc ++++ b/content/browser/web_contents/file_chooser_impl_browsertest.cc +@@ -177,8 +177,8 @@ IN_PROC_BROWSER_TEST_F(FileChooserImplBrowserTest, UploadFolderWithSymlink) { + return; + } + +- std::unique_ptr delegate( +- new FileChooserDelegate({text_file, symlink_file}, base::OnceClosure())); ++ std::unique_ptr delegate(new FileChooserDelegate( ++ {text_file, symlink_file}, folder_to_upload, base::OnceClosure())); + shell()->web_contents()->SetDelegate(delegate.get()); + EXPECT_TRUE(ExecJs(shell(), + "(async () => {" +@@ -195,4 +195,45 @@ IN_PROC_BROWSER_TEST_F(FileChooserImplBrowserTest, UploadFolderWithSymlink) { + EvalJs(shell(), "document.getElementById('fileinput').files[0].name;")); + } + ++// https://crbug.com/1378997 ++IN_PROC_BROWSER_TEST_F(FileChooserImplBrowserTest, UploadFolderWithDirSymlink) { ++ EXPECT_TRUE(NavigateToURL( ++ shell(), GetTestUrl(".", "file_input_webkitdirectory.html"))); ++ ++ // The folder contains a regular file and a directory symbolic link. ++ // When uploading the folder, the symbolic link should not be followed. ++ base::FilePath dir_test_data; ++ ASSERT_TRUE(base::PathService::Get(DIR_TEST_DATA, &dir_test_data)); ++ base::FilePath folder_to_upload = dir_test_data.AppendASCII("file_chooser") ++ .AppendASCII("dir_with_dir_symlink"); ++ ++ base::FilePath foo_file = folder_to_upload.AppendASCII("foo.txt"); ++ base::FilePath dir_symlink = folder_to_upload.AppendASCII("symlink"); ++ base::FilePath bar_file = dir_symlink.AppendASCII("bar.txt"); ++ ++ // Skip the test if symbolic links are not supported. ++ { ++ base::ScopedAllowBlockingForTesting allow_blocking; ++ if (!base::IsLink(dir_symlink)) ++ return; ++ } ++ ++ std::unique_ptr delegate(new FileChooserDelegate( ++ {foo_file, bar_file}, folder_to_upload, base::OnceClosure())); ++ shell()->web_contents()->SetDelegate(delegate.get()); ++ EXPECT_TRUE(ExecJs(shell(), ++ "(async () => {" ++ " let listener = new Promise(" ++ " resolve => fileinput.onchange = resolve);" ++ " fileinput.click();" ++ " await listener;" ++ "})()")); ++ ++ EXPECT_EQ( ++ 1, EvalJs(shell(), "document.getElementById('fileinput').files.length;")); ++ EXPECT_EQ( ++ "foo.txt", ++ EvalJs(shell(), "document.getElementById('fileinput').files[0].name;")); ++} ++ + } // namespace content +diff --git a/content/test/content_browser_test_utils_internal.cc b/content/test/content_browser_test_utils_internal.cc +index c70d088bfd007e9a6cd9cfcb6f92b07b99653048..3e68311abfefc1e93ccc5c05de14137d8db0dc60 100644 +--- a/content/test/content_browser_test_utils_internal.cc ++++ b/content/test/content_browser_test_utils_internal.cc +@@ -447,12 +447,16 @@ Shell* OpenPopup(const ToRenderFrameHost& opener, + } + + FileChooserDelegate::FileChooserDelegate(std::vector files, ++ const base::FilePath& base_dir, + base::OnceClosure callback) +- : files_(std::move(files)), callback_(std::move(callback)) {} ++ : files_(std::move(files)), ++ base_dir_(base_dir), ++ callback_(std::move(callback)) {} + + FileChooserDelegate::FileChooserDelegate(const base::FilePath& file, + base::OnceClosure callback) + : FileChooserDelegate(std::vector(1, file), ++ base::FilePath(), + std::move(callback)) {} + + FileChooserDelegate::~FileChooserDelegate() = default; +@@ -461,6 +465,9 @@ void FileChooserDelegate::RunFileChooser( + RenderFrameHost* render_frame_host, + scoped_refptr listener, + const blink::mojom::FileChooserParams& params) { ++ // |base_dir_| should be set for and only for |kUploadFolder| mode. ++ DCHECK(base_dir_.empty() == ++ (params.mode != blink::mojom::FileChooserParams::Mode::kUploadFolder)); + // Send the selected files to the renderer process. + std::vector files; + for (const auto& file : files_) { +@@ -468,7 +475,7 @@ void FileChooserDelegate::RunFileChooser( + blink::mojom::NativeFileInfo::New(file, std::u16string())); + files.push_back(std::move(file_info)); + } +- listener->FileSelected(std::move(files), base::FilePath(), params.mode); ++ listener->FileSelected(std::move(files), base_dir_, params.mode); + + params_ = params.Clone(); + if (callback_) +diff --git a/content/test/content_browser_test_utils_internal.h b/content/test/content_browser_test_utils_internal.h +index 43c6aabc5414d0cc12fb5a03142e8b20e2a7fab3..bff69b028af40726107928868748ad0f19dc4459 100644 +--- a/content/test/content_browser_test_utils_internal.h ++++ b/content/test/content_browser_test_utils_internal.h +@@ -179,7 +179,10 @@ class FileChooserDelegate : public WebContentsDelegate { + // The mocked file dialog will always reply that the user selected |file| or + // |files|. |callback| is invoked when RunFileChooser() is called. + FileChooserDelegate(const base::FilePath& file, base::OnceClosure callback); ++ // |base_dir| must be set to the folder being uploaded in |kUploadFolder| ++ // mode, and must be empty in all other modes. + FileChooserDelegate(std::vector files, ++ const base::FilePath& base_dir, + base::OnceClosure callback); + ~FileChooserDelegate() override; + +@@ -193,6 +196,7 @@ class FileChooserDelegate : public WebContentsDelegate { + + private: + std::vector files_; ++ const base::FilePath base_dir_; + base::OnceClosure callback_; + blink::mojom::FileChooserParamsPtr params_; + }; +diff --git a/content/test/data/file_chooser/dir_with_dir_symlink/foo.txt b/content/test/data/file_chooser/dir_with_dir_symlink/foo.txt +new file mode 100644 +index 0000000000000000000000000000000000000000..257cc5642cb1a054f08cc83f2d943e56fd3ebe99 +--- /dev/null ++++ b/content/test/data/file_chooser/dir_with_dir_symlink/foo.txt +@@ -0,0 +1 @@ ++foo +diff --git a/content/test/data/file_chooser/dir_with_dir_symlink/symlink b/content/test/data/file_chooser/dir_with_dir_symlink/symlink +new file mode 120000 +index 0000000000000000000000000000000000000000..10f6d1ab9ba9ede59b719d4ba1581588e172abb6 +--- /dev/null ++++ b/content/test/data/file_chooser/dir_with_dir_symlink/symlink +@@ -0,0 +1 @@ ++../linked_dir/ +\ No newline at end of file +diff --git a/content/test/data/file_chooser/linked_dir/bar.txt b/content/test/data/file_chooser/linked_dir/bar.txt +new file mode 100644 +index 0000000000000000000000000000000000000000..5716ca5987cbf97d6bb54920bea6adde242d87e6 +--- /dev/null ++++ b/content/test/data/file_chooser/linked_dir/bar.txt +@@ -0,0 +1 @@ ++bar diff --git a/patches/chromium/cherry-pick-f98adc846aad.patch b/patches/chromium/cherry-pick-f98adc846aad.patch new file mode 100644 index 0000000000000..3ec53dc055cbe --- /dev/null +++ b/patches/chromium/cherry-pick-f98adc846aad.patch @@ -0,0 +1,55 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Austin Sullivan +Date: Tue, 11 Oct 2022 20:53:22 +0000 +Subject: FSA: Block .url files in getFileHandle and getEntries + +Fixed: 1354518 +Change-Id: I663d4481ccc2047c49d7466bbfe9751e8c140edf +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3945587 +Reviewed-by: Marijn Kruisselbrink +Commit-Queue: Marijn Kruisselbrink +Auto-Submit: Austin Sullivan +Cr-Commit-Position: refs/heads/main@{#1057675} + +diff --git a/content/browser/file_system_access/file_system_access_directory_handle_impl.cc b/content/browser/file_system_access/file_system_access_directory_handle_impl.cc +index 7e673f903a71a309e8d92b966330875ef2772f84..13ce0b974268215f0e92ccedd2f56643c8a36679 100644 +--- a/content/browser/file_system_access/file_system_access_directory_handle_impl.cc ++++ b/content/browser/file_system_access/file_system_access_directory_handle_impl.cc +@@ -444,9 +444,12 @@ bool IsShellIntegratedExtension(const base::FilePath::StringType& extension) { + + // .lnk and .scf files may be used to execute arbitrary code (see + // https://nvd.nist.gov/vuln/detail/CVE-2010-2568 and +- // https://crbug.com/1227995, respectively). ++ // https://crbug.com/1227995, respectively). '.url' files can be used to read ++ // arbitrary files (see https://crbug.com/1307930 and ++ // https://crbug.com/1354518). + if (extension_lower == FILE_PATH_LITERAL("lnk") || +- extension_lower == FILE_PATH_LITERAL("scf")) { ++ extension_lower == FILE_PATH_LITERAL("scf") || ++ extension_lower == FILE_PATH_LITERAL("url")) { + return true; + } + +diff --git a/content/browser/file_system_access/file_system_access_directory_handle_impl_unittest.cc b/content/browser/file_system_access/file_system_access_directory_handle_impl_unittest.cc +index 606e34473296199317747fa949158f402b163ec0..9dd03ca412fdc69d7e6bb18b08a157ac9b69bf13 100644 +--- a/content/browser/file_system_access/file_system_access_directory_handle_impl_unittest.cc ++++ b/content/browser/file_system_access/file_system_access_directory_handle_impl_unittest.cc +@@ -150,6 +150,7 @@ TEST_F(FileSystemAccessDirectoryHandleImplTest, IsSafePathComponent) { + "My Computer.{20D04FE0-3AEA-1069-A2D8-08002B30309D}", + "a\\a", + "a.lnk", ++ "a.url", + "a/a", + "C:\\", + "C:/", +@@ -205,8 +206,8 @@ TEST_F(FileSystemAccessDirectoryHandleImplTest, GetEntries) { + constexpr const char* kSafeNames[] = {"a", "a.txt", "My Computer", "lnk.txt", + "a.local"}; + constexpr const char* kUnsafeNames[] = { +- "con", "con.zip", "NUL", "a.", +- "a\"a", "a . .", "a.lnk", "My Computer.{a}", ++ "con", "con.zip", "NUL", "a.", "a\"a", "a . .", ++ "a.lnk", "My Computer.{a}", "a.url", + }; + for (const char* name : kSafeNames) { + ASSERT_TRUE(base::WriteFile(dir_.GetPath().AppendASCII(name), "data")) diff --git a/patches/chromium/cherry-pick-fefd6198da31.patch b/patches/chromium/cherry-pick-fefd6198da31.patch new file mode 100644 index 0000000000000..b1bbbc4cb396a --- /dev/null +++ b/patches/chromium/cherry-pick-fefd6198da31.patch @@ -0,0 +1,305 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ben Wagner +Date: Tue, 20 Sep 2022 18:38:53 +0000 +Subject: Fix races in FrameQueueUnderlyingSource related to + CrossThreadPersistent + +The repro in bug 1323488 unfortunately does not reliably reproduce +the races when run as a web test. I was also not able to repro the +races in a unit test. + +There are actually three fixes in this CL; it was easiest to fix them +all together so that I can run the repro locally for an extended period +without it being stopped by a crash. + +The underlying cause for all three races is that CrossThreadPersistent +can refer to an object whose heap has already been destroyed. When +accessed on the thread corresponding to that heap, there is no race, +but when accessed from a different thread, there is a period of time +after the heap is destroyed before the CrossThreadPersistent is +cleared. + +1. The FrameQueueUnderlyingSource::transferred_source_ member's pointer + is accessed in FrameQueueUnderlyingSource::Close. This CL adds a + callback to clear the pointer in + TransferredFrameQueueUnderlyingSource::ContextDestroyed. + +2. The TransferredFrameQueueUnderlyingSource constructor takes a raw + pointer to the original FrameQueueUnderlyingSource, which is + associated with a different thread. GC won't be able to update this + raw pointer since it's on the wrong stack. This CL changes the raw + pointer to a CrossThreadPersistent which is visible to GC. + +3. Same as 2, but for the callstack ConnectHostCallback, + MediaStream(Audio|Video)TrackUnderlyingSource::OnSourceTransferStarted + and FrameQueueUnderlyingSource::TransferSource. + +(cherry picked from commit 63ce9c40e1a67395278dfc70ecfb545a818747bb) + +Bug: 1323488 +Change-Id: Id63484eebefd2e003959b25bd752ac8263caab4f +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3865452 +Commit-Queue: Ben Wagner +Reviewed-by: Thomas Guilbert +Auto-Submit: Ben Wagner +Cr-Original-Commit-Position: refs/heads/main@{#1041434} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3908010 +Commit-Queue: Srinivas Sista +Reviewed-by: Srinivas Sista +Cr-Commit-Position: refs/branch-heads/5249@{#521} +Cr-Branched-From: 4f7bea5de862aaa52e6bde5920755a9ef9db120b-refs/heads/main@{#1036826} + +diff --git a/third_party/blink/renderer/modules/breakout_box/frame_queue_transferring_optimizer.cc b/third_party/blink/renderer/modules/breakout_box/frame_queue_transferring_optimizer.cc +index 2cc89e8cd32421bf80b262bac2e4a7cb685db62f..ab41fa086ad9eb8c1cd66db74ea1f05a66ac56a4 100644 +--- a/third_party/blink/renderer/modules/breakout_box/frame_queue_transferring_optimizer.cc ++++ b/third_party/blink/renderer/modules/breakout_box/frame_queue_transferring_optimizer.cc +@@ -19,10 +19,13 @@ FrameQueueTransferringOptimizer:: + FrameQueueHost* host, + scoped_refptr host_runner, + wtf_size_t max_queue_size, +- ConnectHostCallback connect_host_callback) ++ ConnectHostCallback connect_host_callback, ++ CrossThreadOnceClosure transferred_source_destroyed_callback) + : host_(host), + host_runner_(std::move(host_runner)), + connect_host_callback_(std::move(connect_host_callback)), ++ transferred_source_destroyed_callback_( ++ std::move(transferred_source_destroyed_callback)), + max_queue_size_(max_queue_size) {} + + template +@@ -40,7 +43,8 @@ FrameQueueTransferringOptimizer::PerformInProcessOptimization( + + auto* source = MakeGarbageCollected< + TransferredFrameQueueUnderlyingSource>( +- script_state, host, host_runner_); ++ script_state, host, host_runner_, ++ std::move(transferred_source_destroyed_callback_)); + + PostCrossThreadTask( + *host_runner_, FROM_HERE, +diff --git a/third_party/blink/renderer/modules/breakout_box/frame_queue_transferring_optimizer.h b/third_party/blink/renderer/modules/breakout_box/frame_queue_transferring_optimizer.h +index 6d33945b7c840e55ae73a1efd1f1cf33ccfaaa71..336073235ba7f6c05cf2cf19fccbfac0be9597c9 100644 +--- a/third_party/blink/renderer/modules/breakout_box/frame_queue_transferring_optimizer.h ++++ b/third_party/blink/renderer/modules/breakout_box/frame_queue_transferring_optimizer.h +@@ -25,13 +25,15 @@ class FrameQueueTransferringOptimizer final + + using ConnectHostCallback = CrossThreadOnceFunction, +- TransferredFrameQueueUnderlyingSource*)>; ++ CrossThreadPersistent< ++ TransferredFrameQueueUnderlyingSource>)>; + + FrameQueueTransferringOptimizer( + FrameQueueHost*, + scoped_refptr host_runner, + wtf_size_t max_queue_size, +- ConnectHostCallback callback); ++ ConnectHostCallback connect_host_callback, ++ CrossThreadOnceFunction transferred_source_destroyed_callback); + ~FrameQueueTransferringOptimizer() override = default; + + UnderlyingSourceBase* PerformInProcessOptimization( +@@ -41,6 +43,7 @@ class FrameQueueTransferringOptimizer final + CrossThreadWeakPersistent host_; + scoped_refptr host_runner_; + ConnectHostCallback connect_host_callback_; ++ CrossThreadOnceFunction transferred_source_destroyed_callback_; + wtf_size_t max_queue_size_; + }; + +diff --git a/third_party/blink/renderer/modules/breakout_box/frame_queue_underlying_source.cc b/third_party/blink/renderer/modules/breakout_box/frame_queue_underlying_source.cc +index b93b67f131e1e58118e32d2c9b29e472a28d4664..fcd676b3035e19c6e0b28ee1c44109c6737a1c35 100644 +--- a/third_party/blink/renderer/modules/breakout_box/frame_queue_underlying_source.cc ++++ b/third_party/blink/renderer/modules/breakout_box/frame_queue_underlying_source.cc +@@ -266,15 +266,22 @@ double FrameQueueUnderlyingSource::DesiredSizeForTesting() + + template + void FrameQueueUnderlyingSource::TransferSource( +- FrameQueueUnderlyingSource* transferred_source) { ++ CrossThreadPersistent> ++ transferred_source) { + DCHECK(realm_task_runner_->RunsTasksInCurrentSequence()); + MutexLocker locker(mutex_); + DCHECK(!transferred_source_); +- transferred_source_ = transferred_source; ++ transferred_source_ = std::move(transferred_source); + CloseController(); + frame_queue_handle_.Invalidate(); + } + ++template ++void FrameQueueUnderlyingSource::ClearTransferredSource() { ++ MutexLocker locker(mutex_); ++ transferred_source_.Clear(); ++} ++ + template + void FrameQueueUnderlyingSource::CloseController() { + DCHECK(realm_task_runner_->RunsTasksInCurrentSequence()); +diff --git a/third_party/blink/renderer/modules/breakout_box/frame_queue_underlying_source.h b/third_party/blink/renderer/modules/breakout_box/frame_queue_underlying_source.h +index 7e097b4eb6e9085be73ceb7fd84a4588baf64471..3908909d04f5b6cf4a9be4a3a3e004c3775a3d42 100644 +--- a/third_party/blink/renderer/modules/breakout_box/frame_queue_underlying_source.h ++++ b/third_party/blink/renderer/modules/breakout_box/frame_queue_underlying_source.h +@@ -85,7 +85,13 @@ class FrameQueueUnderlyingSource + // QueueFrame(). |transferred_source| will pull frames from the same circular + // queue. Must be called on |realm_task_runner_|. + void TransferSource( +- FrameQueueUnderlyingSource* transferred_source); ++ CrossThreadPersistent> ++ transferred_source); ++ ++ // Due to a potential race condition between |transferred_source_|'s heap ++ // being destroyed and the Close() method being called, we need to explicitly ++ // clear |transferred_source_| when its context is being destroyed. ++ void ClearTransferredSource(); + + protected: + bool MustUseMonitor() const; +diff --git a/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.cc b/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.cc +index bfc966452e4134e5133d559698497ce82f89aad4..da9a4bffc3a8c9ec5a1595a7cd78110bfadbfb5e 100644 +--- a/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.cc ++++ b/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.cc +@@ -93,14 +93,17 @@ MediaStreamAudioTrackUnderlyingSource::GetTransferringOptimizer() { + this, GetRealmRunner(), MaxQueueSize(), + CrossThreadBindOnce( + &MediaStreamAudioTrackUnderlyingSource::OnSourceTransferStarted, ++ WrapCrossThreadWeakPersistent(this)), ++ CrossThreadBindOnce( ++ &MediaStreamAudioTrackUnderlyingSource::ClearTransferredSource, + WrapCrossThreadWeakPersistent(this))); + } + + void MediaStreamAudioTrackUnderlyingSource::OnSourceTransferStarted( + scoped_refptr transferred_runner, +- TransferredAudioDataQueueUnderlyingSource* source) { ++ CrossThreadPersistent source) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); +- TransferSource(source); ++ TransferSource(std::move(source)); + RecordBreakoutBoxUsage(BreakoutBoxUsage::kReadableAudioWorker); + } + +diff --git a/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.h b/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.h +index 19a290ea6b83e4b56b8d96cb7632fca55bd65fd0..73c16dc5ff3855e258e1e70397def478485f1481 100644 +--- a/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.h ++++ b/third_party/blink/renderer/modules/breakout_box/media_stream_audio_track_underlying_source.h +@@ -56,7 +56,7 @@ class MODULES_EXPORT MediaStreamAudioTrackUnderlyingSource + void DisconnectFromTrack(); + void OnSourceTransferStarted( + scoped_refptr transferred_runner, +- TransferredAudioDataQueueUnderlyingSource* source); ++ CrossThreadPersistent source); + + // Only used to prevent the gargabe collector from reclaiming the media + // stream track processor that created |this|. +diff --git a/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source.cc b/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source.cc +index bcb941aca4e4d0729dc1253e01ef477fdaae1877..e748bf6eaf8f9d1acf8519c38a5a8cb53b031d0e 100644 +--- a/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source.cc ++++ b/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source.cc +@@ -66,6 +66,9 @@ MediaStreamVideoTrackUnderlyingSource::GetStreamTransferOptimizer() { + this, GetRealmRunner(), MaxQueueSize(), + CrossThreadBindOnce( + &MediaStreamVideoTrackUnderlyingSource::OnSourceTransferStarted, ++ WrapCrossThreadWeakPersistent(this)), ++ CrossThreadBindOnce( ++ &MediaStreamVideoTrackUnderlyingSource::ClearTransferredSource, + WrapCrossThreadWeakPersistent(this))); + } + +@@ -76,9 +79,9 @@ MediaStreamVideoTrackUnderlyingSource::GetIOTaskRunner() { + + void MediaStreamVideoTrackUnderlyingSource::OnSourceTransferStarted( + scoped_refptr transferred_runner, +- TransferredVideoFrameQueueUnderlyingSource* source) { ++ CrossThreadPersistent source) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); +- TransferSource(source); ++ TransferSource(std::move(source)); + RecordBreakoutBoxUsage(BreakoutBoxUsage::kReadableVideoWorker); + } + +diff --git a/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source.h b/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source.h +index 1bbd4f6bbf20eaf168bf1319f1b35819dabe3cce..8964eb5eb83964c4bb2633092a12cb144da4e9b0 100644 +--- a/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source.h ++++ b/third_party/blink/renderer/modules/breakout_box/media_stream_video_track_underlying_source.h +@@ -59,8 +59,9 @@ class MODULES_EXPORT MediaStreamVideoTrackUnderlyingSource + bool StartFrameDelivery() override; + void StopFrameDelivery() override; + +- void OnSourceTransferStarted(scoped_refptr, +- TransferredVideoFrameQueueUnderlyingSource*); ++ void OnSourceTransferStarted( ++ scoped_refptr, ++ CrossThreadPersistent); + + void OnFrameFromTrack( + scoped_refptr media_frame, +diff --git a/third_party/blink/renderer/modules/breakout_box/transferred_frame_queue_underlying_source.cc b/third_party/blink/renderer/modules/breakout_box/transferred_frame_queue_underlying_source.cc +index 5c62b8f1b752c24f8b8d0048d646ea64dba0e49c..e38173482d455788861a1d831dd3422119d4d4d6 100644 +--- a/third_party/blink/renderer/modules/breakout_box/transferred_frame_queue_underlying_source.cc ++++ b/third_party/blink/renderer/modules/breakout_box/transferred_frame_queue_underlying_source.cc +@@ -15,11 +15,14 @@ template + TransferredFrameQueueUnderlyingSource:: + TransferredFrameQueueUnderlyingSource( + ScriptState* script_state, +- FrameQueueHost* host, +- scoped_refptr host_runner) ++ CrossThreadPersistent host, ++ scoped_refptr host_runner, ++ CrossThreadOnceClosure transferred_source_destroyed_callback) + : FrameQueueUnderlyingSource(script_state, host), + host_runner_(host_runner), +- host_(host) {} ++ host_(std::move(host)), ++ transferred_source_destroyed_callback_( ++ std::move(transferred_source_destroyed_callback)) {} + + template + bool TransferredFrameQueueUnderlyingSource< +@@ -44,6 +47,13 @@ void TransferredFrameQueueUnderlyingSource< + CrossThreadBindOnce(&FrameQueueHost::Close, host_)); + } + ++template ++void TransferredFrameQueueUnderlyingSource< ++ NativeFrameType>::ContextDestroyed() { ++ std::move(transferred_source_destroyed_callback_).Run(); ++ FrameQueueUnderlyingSource::ContextDestroyed(); ++} ++ + template + void TransferredFrameQueueUnderlyingSource::Trace( + Visitor* visitor) const { +diff --git a/third_party/blink/renderer/modules/breakout_box/transferred_frame_queue_underlying_source.h b/third_party/blink/renderer/modules/breakout_box/transferred_frame_queue_underlying_source.h +index 5f8a36719407a404756d672530c0b9fcff9d6924..7cd3270fbb3cf5b0e2c09b16000ea5c0e4247866 100644 +--- a/third_party/blink/renderer/modules/breakout_box/transferred_frame_queue_underlying_source.h ++++ b/third_party/blink/renderer/modules/breakout_box/transferred_frame_queue_underlying_source.h +@@ -19,8 +19,9 @@ class TransferredFrameQueueUnderlyingSource + + TransferredFrameQueueUnderlyingSource( + ScriptState*, +- FrameQueueHost*, +- scoped_refptr host_runner); ++ CrossThreadPersistent, ++ scoped_refptr host_runner, ++ CrossThreadOnceClosure transferred_source_destroyed_callback); + ~TransferredFrameQueueUnderlyingSource() override = default; + + TransferredFrameQueueUnderlyingSource( +@@ -32,11 +33,15 @@ class TransferredFrameQueueUnderlyingSource + bool StartFrameDelivery() override; + void StopFrameDelivery() override; + ++ // ExecutionLifecycleObserver ++ void ContextDestroyed() override; ++ + void Trace(Visitor*) const override; + + private: + scoped_refptr host_runner_; + CrossThreadPersistent host_; ++ CrossThreadOnceClosure transferred_source_destroyed_callback_; + }; + + extern template class MODULES_EXTERN_TEMPLATE_EXPORT diff --git a/patches/chromium/fix_on-screen-keyboard_hides_on_input_blur_in_webview.patch b/patches/chromium/fix_on-screen-keyboard_hides_on_input_blur_in_webview.patch new file mode 100644 index 0000000000000..82c4b734fdbde --- /dev/null +++ b/patches/chromium/fix_on-screen-keyboard_hides_on_input_blur_in_webview.patch @@ -0,0 +1,59 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Kyrylo Hrechykhin +Date: Thu, 6 Oct 2022 18:30:53 +0200 +Subject: fix: on-screen-keyboard hides on input blur in webview + +Changes introduced by this patch fix issue where OSK does not hide on +input rendered inside webview is blurred. This patch should be removed +when proper fix in chromium repo is available. + +Note: the issue still occurs if input rendered in webview blurred due +to touch outside of webview. It is caused by webview implementation +details. Specificaly due to webview has its own tree nodes and focused +node does not change in this case. + +chromium-bug: https://crbug.com/1369605 + +diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.cc b/content/browser/renderer_host/render_widget_host_view_child_frame.cc +index c56d5c06ca3eb5e2c11bd1af00a8667bfa422dc9..bccc940958180481947a5a5ee82562bd99d28b78 100644 +--- a/content/browser/renderer_host/render_widget_host_view_child_frame.cc ++++ b/content/browser/renderer_host/render_widget_host_view_child_frame.cc +@@ -985,6 +985,12 @@ RenderWidgetHostViewChildFrame::DidUpdateVisualProperties( + return viz::ScopedSurfaceIdAllocator(std::move(allocation_task)); + } + ++void RenderWidgetHostViewChildFrame::FocusedNodeChanged( ++ bool is_editable_node, ++ const gfx::Rect& node_bounds_in_screen) { ++ NOTREACHED(); ++} ++ + ui::TextInputType RenderWidgetHostViewChildFrame::GetTextInputType() const { + if (!text_input_manager_) + return ui::TEXT_INPUT_TYPE_NONE; +diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.h b/content/browser/renderer_host/render_widget_host_view_child_frame.h +index 457dabe428e84230b2e831e9281feee06e7c8e76..9436d55b390ac6fa16398efebad0a87beef6e959 100644 +--- a/content/browser/renderer_host/render_widget_host_view_child_frame.h ++++ b/content/browser/renderer_host/render_widget_host_view_child_frame.h +@@ -178,6 +178,8 @@ class CONTENT_EXPORT RenderWidgetHostViewChildFrame + void DisableAutoResize(const gfx::Size& new_size) override; + viz::ScopedSurfaceIdAllocator DidUpdateVisualProperties( + const cc::RenderFrameMetadata& metadata) override; ++ void FocusedNodeChanged(bool is_editable_node, ++ const gfx::Rect& node_bounds_in_screen) override; + + // RenderFrameMetadataProvider::Observer implementation. + void OnRenderFrameMetadataChangedBeforeActivation( +diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc +index 8982a2a4d2be23e56472b17e9d59e289e8255336..92f73106ba8c9559281add6fe7a2f2a613ca3cdc 100644 +--- a/content/browser/web_contents/web_contents_impl.cc ++++ b/content/browser/web_contents/web_contents_impl.cc +@@ -7891,7 +7891,7 @@ void WebContentsImpl::OnFocusedElementChangedInFrame( + "WebContentsImpl::OnFocusedElementChangedInFrame", + "render_frame_host", frame); + RenderWidgetHostViewBase* root_view = +- static_cast(GetRenderWidgetHostView()); ++ static_cast(GetTopLevelRenderWidgetHostView()); + if (!root_view || !frame->GetView()) + return; + // Convert to screen coordinates from window coordinates by adding the diff --git a/patches/chromium/mojo_disable_sync_call_interrupts_in_the_browser.patch b/patches/chromium/mojo_disable_sync_call_interrupts_in_the_browser.patch new file mode 100644 index 0000000000000..8f6a053a1f721 --- /dev/null +++ b/patches/chromium/mojo_disable_sync_call_interrupts_in_the_browser.patch @@ -0,0 +1,536 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ken Rockot +Date: Thu, 10 Nov 2022 03:24:17 +0000 +Subject: Mojo: Disable sync call interrupts in the browser + +This changes the default Mojo sync call behavior in the browser process +to prevent any blocking sync calls from being interrupted by other +incoming sync IPC dispatches. + +(cherry picked from commit b6f921260e0e763db7a72de9c7a3f0f78a99f21f) + +Bug: 1376099 +Change-Id: I53681ef379fdd3c2bfc37d7e16b3de17acad5d20 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3989408 +Commit-Queue: Ken Rockot +Reviewed-by: Daniel Cheng +Cr-Original-Commit-Position: refs/heads/main@{#1065369} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4018257 +Commit-Queue: Daniel Cheng +Auto-Submit: Daniel Cheng +Reviewed-by: Ken Rockot +Commit-Queue: Rubber Stamper +Bot-Commit: Rubber Stamper +Cr-Commit-Position: refs/branch-heads/5359@{#719} +Cr-Branched-From: 27d3765d341b09369006d030f83f582a29eb57ae-refs/heads/main@{#1058933} + +diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc +index 2f973efcf3e38edcc74060929339fc21bdf0aa3b..f8f72678fd8bbcf857bf09176b8b6388d35e3605 100644 +--- a/content/app/content_main_runner_impl.cc ++++ b/content/app/content_main_runner_impl.cc +@@ -92,6 +92,7 @@ + #include "media/media_buildflags.h" + #include "mojo/core/embedder/embedder.h" + #include "mojo/public/cpp/bindings/self_owned_receiver.h" ++#include "mojo/public/cpp/bindings/sync_call_restrictions.h" + #include "mojo/public/cpp/platform/platform_channel.h" + #include "mojo/public/cpp/system/dynamic_library_support.h" + #include "mojo/public/cpp/system/invitation.h" +@@ -1073,6 +1074,11 @@ int ContentMainRunnerImpl::RunBrowser(MainFunctionParams main_params, + if (is_browser_main_loop_started_) + return -1; + ++ if (!base::CommandLine::ForCurrentProcess()->HasSwitch( ++ switches::kSingleProcess)) { ++ mojo::SyncCallRestrictions::DisableSyncCallInterrupts(); ++ } ++ + if (!mojo_ipc_support_) { + const auto invoked_in = main_params.ui_task + ? InvokedIn::kBrowserProcessUnderTest +diff --git a/ipc/ipc_mojo_bootstrap.cc b/ipc/ipc_mojo_bootstrap.cc +index eb8fa358b0a72eea2e294c531549da5fc81f394c..8c13ef236ba6f7cf05584cffba522a3cb54536c9 100644 +--- a/ipc/ipc_mojo_bootstrap.cc ++++ b/ipc/ipc_mojo_bootstrap.cc +@@ -16,13 +16,15 @@ + #include "base/bind.h" + #include "base/callback.h" + #include "base/check_op.h" ++#include "base/containers/circular_deque.h" + #include "base/containers/contains.h" +-#include "base/containers/queue.h" + #include "base/memory/ptr_util.h" + #include "base/memory/raw_ptr.h" + #include "base/no_destructor.h" ++#include "base/ranges/algorithm.h" + #include "base/strings/stringprintf.h" + #include "base/synchronization/lock.h" ++#include "base/synchronization/waitable_event.h" + #include "base/task/common/task_annotator.h" + #include "base/task/sequenced_task_runner.h" + #include "base/task/single_thread_task_runner.h" +@@ -48,6 +50,7 @@ + #include "mojo/public/cpp/bindings/pipe_control_message_proxy.h" + #include "mojo/public/cpp/bindings/sequence_local_sync_event_watcher.h" + #include "mojo/public/cpp/bindings/tracing_helpers.h" ++#include "third_party/abseil-cpp/absl/types/optional.h" + + namespace IPC { + +@@ -466,6 +469,11 @@ class ChannelAssociatedGroupController + return *this; + } + ++ bool HasRequestId(uint64_t request_id) { ++ return !value_.IsNull() && value_.version() >= 1 && ++ value_.header_v1()->request_id == request_id; ++ } ++ + mojo::Message& value() { return value_; } + + private: +@@ -557,10 +565,15 @@ class ChannelAssociatedGroupController + sync_watcher_.reset(); + } + +- uint32_t EnqueueSyncMessage(MessageWrapper message) { ++ absl::optional EnqueueSyncMessage(MessageWrapper message) { + controller_->lock_.AssertAcquired(); ++ if (exclusive_wait_ && exclusive_wait_->TryFulfillingWith(message)) { ++ exclusive_wait_ = nullptr; ++ return absl::nullopt; ++ } ++ + uint32_t id = GenerateSyncMessageId(); +- sync_messages_.emplace(id, std::move(message)); ++ sync_messages_.emplace_back(id, std::move(message)); + SignalSyncMessageEvent(); + return id; + } +@@ -577,7 +590,7 @@ class ChannelAssociatedGroupController + if (sync_messages_.empty() || sync_messages_.front().first != id) + return MessageWrapper(); + MessageWrapper message = std::move(sync_messages_.front().second); +- sync_messages_.pop(); ++ sync_messages_.pop_front(); + return message; + } + +@@ -607,10 +620,38 @@ class ChannelAssociatedGroupController + return sync_watcher_->SyncWatch(&should_stop); + } + ++ MessageWrapper WaitForIncomingSyncReply(uint64_t request_id) { ++ absl::optional wait; ++ { ++ base::AutoLock lock(controller_->lock_); ++ for (auto& [id, message] : sync_messages_) { ++ if (message.HasRequestId(request_id)) { ++ return std::move(message); ++ } ++ } ++ ++ DCHECK(!exclusive_wait_); ++ wait.emplace(request_id); ++ exclusive_wait_ = &wait.value(); ++ } ++ ++ wait->event.Wait(); ++ return std::move(wait->message); ++ } ++ + bool SyncWatchExclusive(uint64_t request_id) override { +- // We don't support exclusive waits on Channel-associated interfaces. +- NOTREACHED(); +- return false; ++ MessageWrapper message = WaitForIncomingSyncReply(request_id); ++ if (message.value().IsNull() || !client_) { ++ return false; ++ } ++ ++ if (!client_->HandleIncomingMessage(&message.value())) { ++ base::AutoLock locker(controller_->lock_); ++ controller_->RaiseError(); ++ return false; ++ } ++ ++ return true; + } + + void RegisterExternalSyncWaiter(uint64_t request_id) override {} +@@ -624,6 +665,9 @@ class ChannelAssociatedGroupController + DCHECK(closed_); + DCHECK(peer_closed_); + DCHECK(!sync_watcher_); ++ if (exclusive_wait_) { ++ exclusive_wait_->event.Signal(); ++ } + } + + void OnSyncMessageEventReady() { +@@ -640,7 +684,7 @@ class ChannelAssociatedGroupController + if (!sync_messages_.empty()) { + MessageWrapper message_wrapper = + std::move(sync_messages_.front().second); +- sync_messages_.pop(); ++ sync_messages_.pop_front(); + + bool dispatch_succeeded; + mojo::InterfaceEndpointClient* client = client_; +@@ -688,6 +732,28 @@ class ChannelAssociatedGroupController + return id; + } + ++ // Tracks the state of a pending sync wait which excludes all other incoming ++ // IPC on the waiting thread. ++ struct ExclusiveSyncWait { ++ explicit ExclusiveSyncWait(uint64_t request_id) ++ : request_id(request_id) {} ++ ~ExclusiveSyncWait() = default; ++ ++ bool TryFulfillingWith(MessageWrapper& wrapper) { ++ if (!wrapper.HasRequestId(request_id)) { ++ return false; ++ } ++ ++ message = std::move(wrapper); ++ event.Signal(); ++ return true; ++ } ++ ++ uint64_t request_id; ++ base::WaitableEvent event; ++ MessageWrapper message; ++ }; ++ + const raw_ptr controller_; + const mojo::InterfaceId id_; + +@@ -699,7 +765,8 @@ class ChannelAssociatedGroupController + raw_ptr client_ = nullptr; + scoped_refptr task_runner_; + std::unique_ptr sync_watcher_; +- base::queue> sync_messages_; ++ base::circular_deque> sync_messages_; ++ ExclusiveSyncWait* exclusive_wait_ = nullptr; + uint32_t next_sync_message_id_ = 0; + }; + +@@ -932,12 +999,15 @@ class ChannelAssociatedGroupController + // sync message queue. If the endpoint was blocking, it will dequeue the + // message and dispatch it. Otherwise the posted |AcceptSyncMessage()| + // call will dequeue the message and dispatch it. +- uint32_t message_id = ++ absl::optional message_id = + endpoint->EnqueueSyncMessage(std::move(message_wrapper)); +- task_runner->PostTask( +- FROM_HERE, +- base::BindOnce(&ChannelAssociatedGroupController::AcceptSyncMessage, +- this, id, message_id)); ++ if (message_id) { ++ task_runner->PostTask( ++ FROM_HERE, ++ base::BindOnce( ++ &ChannelAssociatedGroupController::AcceptSyncMessage, this, ++ id, *message_id)); ++ } + return true; + } + +diff --git a/mojo/public/cpp/bindings/interface_endpoint_controller.h b/mojo/public/cpp/bindings/interface_endpoint_controller.h +index 89dbe39994620148e0ef33910b7cc7baacd7cc2e..8649abe1ac9c4b964c2bf833b850aa6f898b7103 100644 +--- a/mojo/public/cpp/bindings/interface_endpoint_controller.h ++++ b/mojo/public/cpp/bindings/interface_endpoint_controller.h +@@ -36,6 +36,10 @@ class InterfaceEndpointController { + // Watches the endpoint for a specific incoming sync reply. This method only + // returns true once the reply is received, or false if the endpoint is + // detached or destroyed beforehand. ++ // ++ // Unlike with SyncWatch(), no other IPCs (not even other sync IPCs) can be ++ // dispatched to the calling thread while SyncWatchExclusive() is waiting on ++ // the reply for `request_id`. + virtual bool SyncWatchExclusive(uint64_t request_id) = 0; + + // Notifies the controller that a specific in-flight sync message identified +diff --git a/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc b/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc +index 6e87db197c603d8ac44b591f2cd70023217dcbe2..1a786923f6d66c0b8d17765ea7b629add2db104c 100644 +--- a/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc ++++ b/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc +@@ -387,7 +387,9 @@ void ThreadSafeInterfaceEndpointClientProxy::SendMessageWithResponder( + } + + // If the Remote is bound on another sequence, post the call. +- const bool allow_interrupt = !message.has_flag(Message::kFlagNoInterrupt); ++ const bool allow_interrupt = ++ SyncCallRestrictions::AreSyncCallInterruptsEnabled() && ++ !message.has_flag(Message::kFlagNoInterrupt); + auto response = base::MakeRefCounted(); + auto response_signaler = std::make_unique(response); + task_runner_->PostTask( +@@ -625,7 +627,9 @@ bool InterfaceEndpointClient::SendMessageWithResponder( + + const uint32_t message_name = message->name(); + const bool is_sync = message->has_flag(Message::kFlagIsSync); +- const bool exclusive_wait = message->has_flag(Message::kFlagNoInterrupt); ++ const bool exclusive_wait = ++ message->has_flag(Message::kFlagNoInterrupt) || ++ !SyncCallRestrictions::AreSyncCallInterruptsEnabled(); + if (!controller_->SendMessage(message)) + return false; + +diff --git a/mojo/public/cpp/bindings/lib/sync_call_restrictions.cc b/mojo/public/cpp/bindings/lib/sync_call_restrictions.cc +index 329901dec12572e8d8833eba33ad1cc793919084..6242391074ee6279cfea29cf1e73ac4ef874445a 100644 +--- a/mojo/public/cpp/bindings/lib/sync_call_restrictions.cc ++++ b/mojo/public/cpp/bindings/lib/sync_call_restrictions.cc +@@ -4,8 +4,6 @@ + + #include "mojo/public/cpp/bindings/sync_call_restrictions.h" + +-#if ENABLE_SYNC_CALL_RESTRICTIONS +- + #include "base/check_op.h" + #include "base/debug/leak_annotations.h" + #include "base/logging.h" +@@ -19,6 +17,11 @@ namespace mojo { + + namespace { + ++// Sync call interrupts are enabled by default. ++bool g_enable_sync_call_interrupts = true; ++ ++#if ENABLE_SYNC_CALL_RESTRICTIONS ++ + class GlobalSyncCallSettings { + public: + GlobalSyncCallSettings() = default; +@@ -61,8 +64,12 @@ bool SyncCallRestrictionsEnforceable() { + return base::internal::SequenceLocalStorageMap::IsSetForCurrentThread(); + } + ++#endif // ENABLE_SYNC_CALL_RESTRICTIONS ++ + } // namespace + ++#if ENABLE_SYNC_CALL_RESTRICTIONS ++ + // static + void SyncCallRestrictions::AssertSyncCallAllowed() { + if (GetGlobalSettings().sync_call_allowed_by_default() || +@@ -102,6 +109,21 @@ void SyncCallRestrictions::DecreaseScopedAllowCount() { + --GetSequenceLocalScopedAllowCount(); + } + +-} // namespace mojo +- + #endif // ENABLE_SYNC_CALL_RESTRICTIONS ++ ++// static ++void SyncCallRestrictions::DisableSyncCallInterrupts() { ++ g_enable_sync_call_interrupts = false; ++} ++ ++// static ++void SyncCallRestrictions::EnableSyncCallInterruptsForTesting() { ++ g_enable_sync_call_interrupts = true; ++} ++ ++// static ++bool SyncCallRestrictions::AreSyncCallInterruptsEnabled() { ++ return g_enable_sync_call_interrupts; ++} ++ ++} // namespace mojo +diff --git a/mojo/public/cpp/bindings/sync_call_restrictions.h b/mojo/public/cpp/bindings/sync_call_restrictions.h +index e7e67ee824b2a87eb14b45a3f2d76d471ff864fb..1653fd63033383b40b643c03500b26bdc65a44a6 100644 +--- a/mojo/public/cpp/bindings/sync_call_restrictions.h ++++ b/mojo/public/cpp/bindings/sync_call_restrictions.h +@@ -86,6 +86,20 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) SyncCallRestrictions { + static void DisallowSyncCall() {} + #endif + ++ // Globally disables sync call interrupts. This means that all sync calls in ++ // the current process will be strictly blocking until a reply is received, ++ // and no incoming sync calls can dispatch on the blocking thread in interim. ++ static void DisableSyncCallInterrupts(); ++ ++ // Used only in tests to re-enable sync call interrupts after disabling them. ++ static void EnableSyncCallInterruptsForTesting(); ++ ++ // Indicates whether sync call interrupts are enabled in the calling process. ++ // They're enabled by default, so any sync message that isn't marked [Sync] ++ // may have its blocking call interrupted to dispatch other incoming sync ++ // IPCs which target the blocking thread. ++ static bool AreSyncCallInterruptsEnabled(); ++ + private: + // DO NOT ADD ANY OTHER FRIEND STATEMENTS, talk to mojo/OWNERS first. + // BEGIN ALLOWED USAGE. +diff --git a/mojo/public/cpp/bindings/tests/sync_method_unittest.cc b/mojo/public/cpp/bindings/tests/sync_method_unittest.cc +index cfac737af29e653d788eb1ce7669f73ae7b320d4..d794d29df07d289d34b3b1aae9f8574fc914c050 100644 +--- a/mojo/public/cpp/bindings/tests/sync_method_unittest.cc ++++ b/mojo/public/cpp/bindings/tests/sync_method_unittest.cc +@@ -25,6 +25,7 @@ + #include "mojo/public/cpp/bindings/self_owned_receiver.h" + #include "mojo/public/cpp/bindings/shared_associated_remote.h" + #include "mojo/public/cpp/bindings/shared_remote.h" ++#include "mojo/public/cpp/bindings/sync_call_restrictions.h" + #include "mojo/public/cpp/bindings/tests/bindings_test_base.h" + #include "mojo/public/cpp/bindings/tests/sync_method_unittest.test-mojom.h" + #include "mojo/public/interfaces/bindings/tests/test_sync_methods.mojom.h" +@@ -1563,7 +1564,144 @@ TEST_P(SyncInterruptTest, SharedAssociatedRemoteNoInterrupt) { + EXPECT_EQ(0, same_pipe_ponger().num_sync_pongs()); + } + ++class SyncService : public mojom::SyncService { ++ public: ++ explicit SyncService(PendingReceiver receiver) ++ : receiver_(this, std::move(receiver)) {} ++ ++ void SetCallHandler(base::OnceClosure call_handler) { ++ call_handler_ = std::move(call_handler); ++ } ++ ++ // mojom::SyncService: ++ void SyncCall(SyncCallCallback callback) override { ++ std::move(callback).Run(); ++ if (call_handler_) { ++ std::move(call_handler_).Run(); ++ } ++ } ++ ++ private: ++ Receiver receiver_; ++ base::OnceClosure call_handler_; ++}; ++ ++class DisableSyncInterruptTest : public BindingsTestBase { ++ public: ++ void SetUp() override { ++ mojo::SyncCallRestrictions::DisableSyncCallInterrupts(); ++ } ++ ++ void TearDown() override { ++ mojo::SyncCallRestrictions::EnableSyncCallInterruptsForTesting(); ++ } ++}; ++ ++TEST_P(DisableSyncInterruptTest, NoInterruptWhenDisabled) { ++ PendingRemote interrupter; ++ SyncService service(interrupter.InitWithNewPipeAndPassReceiver()); ++ ++ base::RunLoop wait_for_main_thread_service_call; ++ bool main_thread_service_called = false; ++ service.SetCallHandler(base::BindLambdaForTesting([&] { ++ main_thread_service_called = true; ++ wait_for_main_thread_service_call.Quit(); ++ })); ++ ++ Remote caller; ++ base::Thread background_service_thread("SyncService"); ++ background_service_thread.Start(); ++ base::SequenceBound background_service{ ++ background_service_thread.task_runner(), ++ caller.BindNewPipeAndPassReceiver()}; ++ ++ base::Thread interrupter_thread("Interrupter"); ++ interrupter_thread.Start(); ++ interrupter_thread.task_runner()->PostTask( ++ FROM_HERE, base::BindLambdaForTesting([&interrupter] { ++ // Issue a sync call to the SyncService on the main thread. This should ++ // never be dispatched until *after* the sync call *from* the main ++ // thread completes below. ++ Remote(std::move(interrupter))->SyncCall(); ++ })); ++ ++ // The key test expectation here is that `main_thread_service_called` cannot ++ // be set to true until after SyncCall() returns and we can pump the thread's ++ // message loop. If sync interrupts are not properly disabled, this ++ // expectation can fail flakily (and often.) ++ caller->SyncCall(); ++ EXPECT_FALSE(main_thread_service_called); ++ ++ // Now the incoming sync call can be dispatched. ++ wait_for_main_thread_service_call.Run(); ++ EXPECT_TRUE(main_thread_service_called); ++ ++ background_service.SynchronouslyResetForTest(); ++ interrupter_thread.Stop(); ++ background_service_thread.Stop(); ++} ++ ++TEST_P(DisableSyncInterruptTest, SharedRemoteNoInterruptWhenDisabled) { ++ PendingRemote interrupter; ++ SyncService service(interrupter.InitWithNewPipeAndPassReceiver()); ++ ++ base::RunLoop wait_for_main_thread_service_call; ++ bool main_thread_service_called = false; ++ service.SetCallHandler(base::BindLambdaForTesting([&] { ++ main_thread_service_called = true; ++ wait_for_main_thread_service_call.Quit(); ++ })); ++ ++ // Bind a SharedRemote to another background thread so that we exercise ++ // SharedRemote's own sync wait codepath when called into from the main ++ // thread. ++ base::Thread background_client_thread("Client"); ++ background_client_thread.Start(); ++ ++ base::Thread background_service_thread("Service"); ++ background_service_thread.Start(); ++ ++ SharedRemote caller; ++ base::SequenceBound background_service{ ++ background_service_thread.task_runner(), ++ caller.BindNewPipeAndPassReceiver( ++ background_client_thread.task_runner())}; ++ ++ base::Thread interrupter_thread("Interrupter"); ++ interrupter_thread.Start(); ++ interrupter_thread.task_runner()->PostTask( ++ FROM_HERE, base::BindLambdaForTesting([&interrupter] { ++ // Issue a sync call to the SyncService on the main thread. This should ++ // never be dispatched until *after* the sync call *from* the main ++ // thread completes below. ++ Remote(std::move(interrupter))->SyncCall(); ++ })); ++ ++ // The key test expectation here is that `main_thread_service_called` cannot ++ // be set to true until after SyncCall() returns and we can pump the thread's ++ // message loop. If sync interrupts are not properly disabled, this ++ // expectation can fail flakily (and often.) ++ caller->SyncCall(); ++ EXPECT_FALSE(main_thread_service_called); ++ ++ // Now the incoming sync call can be dispatched. ++ wait_for_main_thread_service_call.Run(); ++ EXPECT_TRUE(main_thread_service_called); ++ ++ background_service.SynchronouslyResetForTest(); ++ ++ // We need to reset the SharedRemote before the client thread is stopped, to ++ // ensure the necessary teardown work is executed on that thread. Otherwise ++ // the underlying pipe and related state will leak, and ASan will complain. ++ caller.reset(); ++ ++ interrupter_thread.Stop(); ++ background_service_thread.Stop(); ++ background_client_thread.Stop(); ++} ++ + INSTANTIATE_MOJO_BINDINGS_TEST_SUITE_P(SyncInterruptTest); ++INSTANTIATE_MOJO_BINDINGS_TEST_SUITE_P(DisableSyncInterruptTest); + + } // namespace + } // namespace sync_method_unittest +diff --git a/mojo/public/cpp/bindings/tests/sync_method_unittest.test-mojom b/mojo/public/cpp/bindings/tests/sync_method_unittest.test-mojom +index 383b54f3ab654d664192522c061058b29fd0509a..951442b3585ad22f936568e211ad41f8ae358705 100644 +--- a/mojo/public/cpp/bindings/tests/sync_method_unittest.test-mojom ++++ b/mojo/public/cpp/bindings/tests/sync_method_unittest.test-mojom +@@ -45,3 +45,7 @@ interface Ponger { + [Sync] Pong() => (); + PongAsync(); + }; ++ ++interface SyncService { ++ [Sync] SyncCall() => (); ++}; diff --git a/patches/chromium/mojo_validate_that_a_message_is_allowed_to_use_the_sync_flag.patch b/patches/chromium/mojo_validate_that_a_message_is_allowed_to_use_the_sync_flag.patch new file mode 100644 index 0000000000000..182c5b1739628 --- /dev/null +++ b/patches/chromium/mojo_validate_that_a_message_is_allowed_to_use_the_sync_flag.patch @@ -0,0 +1,953 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Cheng +Date: Sat, 12 Nov 2022 00:27:56 +0000 +Subject: Validate that a message is allowed to use the sync flag. + +This changes consists of several coordinated changes: +- The C++ bindings generator now emits an array of method ordinals that + are allowed to use sync calls, but only if any method has a [Sync] + annotation. This is intended to minimize the code cost to interfaces + that do not have any sync methods (i.e. most of them). +- The C++ binding endpoints (mojo::Receiver, et cetera) now plumb the + array of sync-allowed ordinals to the InterfaceEndpointClient. +- Processing an incoming message checks if the incoming message is + allowed to use the sync flag by filtering it against the array of + sync-allowed ordinals that was previously passed to the + InterfaceEndpointClient. + +This also fixes an incorrect forward declaration of ValidationContext in +the generated bindings that discovered in the process of writing the +test. + +(cherry picked from commit 4365dddb49847a422bce674383b4aa4f38ff9e89) + +Bug: 1376099 +Change-Id: Icb5864dcab96ccd18c98b4cc6ade7cdef39e209f +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3994146 +Reviewed-by: Ken Rockot +Commit-Queue: Daniel Cheng +Cr-Original-Commit-Position: refs/heads/main@{#1067894} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4018151 +Auto-Submit: Daniel Cheng +Commit-Queue: Ken Rockot +Cr-Commit-Position: refs/branch-heads/5359@{#774} +Cr-Branched-From: 27d3765d341b09369006d030f83f582a29eb57ae-refs/heads/main@{#1058933} + +diff --git a/mojo/public/cpp/bindings/BUILD.gn b/mojo/public/cpp/bindings/BUILD.gn +index 2c27474d1200f80ff7abc773eaafdc9d30494f58..de587d8759f2e850ef9de355551c4be12f3ca6e7 100644 +--- a/mojo/public/cpp/bindings/BUILD.gn ++++ b/mojo/public/cpp/bindings/BUILD.gn +@@ -183,6 +183,7 @@ component("bindings") { + "lib/sync_event_watcher.cc", + "lib/sync_handle_registry.cc", + "lib/sync_handle_watcher.cc", ++ "lib/sync_method_traits.h", + "lib/task_runner_helper.cc", + "lib/task_runner_helper.h", + "lib/thread_safe_forwarder_base.cc", +diff --git a/mojo/public/cpp/bindings/associated_receiver.h b/mojo/public/cpp/bindings/associated_receiver.h +index 78c53543ed01cafe627d0559c31be1d792750685..59b86367122074e8c59fcbd9877bf59d669cc436 100644 +--- a/mojo/public/cpp/bindings/associated_receiver.h ++++ b/mojo/public/cpp/bindings/associated_receiver.h +@@ -5,15 +5,19 @@ + #ifndef MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_RECEIVER_H_ + #define MOJO_PUBLIC_CPP_BINDINGS_ASSOCIATED_RECEIVER_H_ + ++#include ++ + #include + #include + + #include "base/check.h" ++#include "base/containers/span.h" + #include "base/memory/ptr_util.h" + #include "base/memory/scoped_refptr.h" + #include "base/memory/weak_ptr.h" + #include "base/strings/string_piece.h" + #include "base/task/sequenced_task_runner.h" ++#include "mojo/public/cpp/bindings/lib/sync_method_traits.h" + #include "mojo/public/cpp/bindings/pending_associated_receiver.h" + #include "mojo/public/cpp/bindings/pending_associated_remote.h" + #include "mojo/public/cpp/bindings/raw_ptr_impl_ref_traits.h" +@@ -60,7 +64,7 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) AssociatedReceiverBase { + void BindImpl(ScopedInterfaceEndpointHandle handle, + MessageReceiverWithResponderStatus* receiver, + std::unique_ptr payload_validator, +- bool expect_sync_requests, ++ base::span sync_method_ordinals, + scoped_refptr runner, + uint32_t interface_version, + const char* interface_name, +@@ -201,8 +205,8 @@ class AssociatedReceiver : public internal::AssociatedReceiverBase { + if (pending_receiver) { + BindImpl(pending_receiver.PassHandle(), &stub_, + base::WrapUnique(new typename Interface::RequestValidator_()), +- Interface::HasSyncMethods_, std::move(task_runner), +- Interface::Version_, Interface::Name_, ++ internal::SyncMethodTraits::GetOrdinals(), ++ std::move(task_runner), Interface::Version_, Interface::Name_, + Interface::MessageToStableIPCHash_, + Interface::MessageToMethodName_); + } else { +diff --git a/mojo/public/cpp/bindings/interface_endpoint_client.h b/mojo/public/cpp/bindings/interface_endpoint_client.h +index dcc6e2aa8d9e97ff716d6ab1de02a83eba95eec2..93aea2bd29c5171f63401bc5d88fb7d6dc302e71 100644 +--- a/mojo/public/cpp/bindings/interface_endpoint_client.h ++++ b/mojo/public/cpp/bindings/interface_endpoint_client.h +@@ -13,6 +13,7 @@ + + #include "base/callback.h" + #include "base/component_export.h" ++#include "base/containers/span.h" + #include "base/dcheck_is_on.h" + #include "base/location.h" + #include "base/memory/raw_ptr.h" +@@ -56,7 +57,7 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) InterfaceEndpointClient + InterfaceEndpointClient(ScopedInterfaceEndpointHandle handle, + MessageReceiverWithResponderStatus* receiver, + std::unique_ptr payload_validator, +- bool expect_sync_requests, ++ base::span sync_method_ordinals, + scoped_refptr task_runner, + uint32_t interface_version, + const char* interface_name, +@@ -220,6 +221,10 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) InterfaceEndpointClient + // The router lock must be held when calling this. + void ForgetAsyncRequest(uint64_t request_id); + ++ base::span sync_method_ordinals() const { ++ return sync_method_ordinals_; ++ } ++ + private: + struct PendingAsyncResponse { + public: +@@ -281,7 +286,7 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) InterfaceEndpointClient + + bool HandleValidatedMessage(Message* message); + +- const bool expect_sync_requests_ = false; ++ const base::span sync_method_ordinals_; + + // The callback to invoke when our peer endpoint sends us NotifyIdle and we + // have no outstanding unacked messages. If null, no callback has been set and +diff --git a/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.cc b/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.cc +index 957ce42c4fa8e69ce63ee876653ef8f8a2ae5b28..a8b86f529329c8358172e4d0d6c3fe61fbede31b 100644 +--- a/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.cc ++++ b/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.cc +@@ -4,6 +4,11 @@ + + #include "mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h" + ++#include ++ ++#include ++ ++#include "base/containers/span.h" + #include "mojo/public/cpp/bindings/lib/task_runner_helper.h" + + namespace mojo { +@@ -70,7 +75,8 @@ void AssociatedInterfacePtrStateBase::Bind( + // The version is only queried from the client so the value passed here + // will not be used. + endpoint_client_ = std::make_unique( +- std::move(handle), nullptr, std::move(validator), false, ++ std::move(handle), nullptr, std::move(validator), ++ /*sync_method_ordinals=*/base::span(), + GetTaskRunnerToUseFromUserProvidedTaskRunner(std::move(runner)), 0u, + interface_name, ipc_hash_callback, method_name_callback); + } +diff --git a/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h b/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h +index d9a4ef1fd6c8141a69de15895ae411a77a03462a..81806976b9c5ccc3d001344a55633d447ac2df24 100644 +--- a/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h ++++ b/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h +@@ -141,6 +141,10 @@ class AssociatedInterfacePtrState : public AssociatedInterfacePtrStateBase { + return info; + } + ++ InterfaceEndpointClient* endpoint_client_for_test() { ++ return endpoint_client(); ++ } ++ + private: + std::unique_ptr proxy_; + }; +diff --git a/mojo/public/cpp/bindings/lib/associated_receiver.cc b/mojo/public/cpp/bindings/lib/associated_receiver.cc +index be3d8689cbdeaaa685f470f39fef3650d19f0aa0..413104e622a879db15ab6d6fa631462104a409e4 100644 +--- a/mojo/public/cpp/bindings/lib/associated_receiver.cc ++++ b/mojo/public/cpp/bindings/lib/associated_receiver.cc +@@ -64,7 +64,7 @@ void AssociatedReceiverBase::BindImpl( + ScopedInterfaceEndpointHandle handle, + MessageReceiverWithResponderStatus* receiver, + std::unique_ptr payload_validator, +- bool expect_sync_requests, ++ base::span sync_method_ordinals, + scoped_refptr runner, + uint32_t interface_version, + const char* interface_name, +@@ -74,7 +74,7 @@ void AssociatedReceiverBase::BindImpl( + + endpoint_client_ = std::make_unique( + std::move(handle), receiver, std::move(payload_validator), +- expect_sync_requests, ++ sync_method_ordinals, + internal::GetTaskRunnerToUseFromUserProvidedTaskRunner(std::move(runner)), + interface_version, interface_name, ipc_hash_callback, + method_name_callback); +diff --git a/mojo/public/cpp/bindings/lib/binding_state.cc b/mojo/public/cpp/bindings/lib/binding_state.cc +index c40b244184601a6fc661a623f6ae45430925b789..a07943d50add0f840752eceb5d7c56f11ce958e6 100644 +--- a/mojo/public/cpp/bindings/lib/binding_state.cc ++++ b/mojo/public/cpp/bindings/lib/binding_state.cc +@@ -107,7 +107,7 @@ void BindingStateBase::BindInternal( + const char* interface_name, + std::unique_ptr request_validator, + bool passes_associated_kinds, +- bool has_sync_methods, ++ base::span sync_method_ordinals, + MessageReceiverWithResponderStatus* stub, + uint32_t interface_version, + MessageToStableIPCHashCallback ipc_hash_callback, +@@ -121,7 +121,7 @@ void BindingStateBase::BindInternal( + MultiplexRouter::Config config = + passes_associated_kinds + ? MultiplexRouter::MULTI_INTERFACE +- : (has_sync_methods ++ : (!sync_method_ordinals.empty() + ? MultiplexRouter::SINGLE_INTERFACE_WITH_SYNC_METHODS + : MultiplexRouter::SINGLE_INTERFACE); + router_ = MultiplexRouter::CreateAndStartReceiving( +@@ -131,7 +131,7 @@ void BindingStateBase::BindInternal( + + endpoint_client_ = std::make_unique( + router_->CreateLocalEndpointHandle(kPrimaryInterfaceId), stub, +- std::move(request_validator), has_sync_methods, ++ std::move(request_validator), sync_method_ordinals, + std::move(sequenced_runner), interface_version, interface_name, + ipc_hash_callback, method_name_callback); + endpoint_client_->SetIdleTrackingEnabledCallback( +diff --git a/mojo/public/cpp/bindings/lib/binding_state.h b/mojo/public/cpp/bindings/lib/binding_state.h +index 64e3fb139fcd8afcf66a85f68e5264dbb47ca997..949b6d8a6eb5ae7d19e26e1b0afe63f1640cff76 100644 +--- a/mojo/public/cpp/bindings/lib/binding_state.h ++++ b/mojo/public/cpp/bindings/lib/binding_state.h +@@ -5,6 +5,8 @@ + #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDING_STATE_H_ + #define MOJO_PUBLIC_CPP_BINDINGS_LIB_BINDING_STATE_H_ + ++#include ++ + #include + #include + +@@ -12,6 +14,7 @@ + #include "base/callback.h" + #include "base/check.h" + #include "base/component_export.h" ++#include "base/containers/span.h" + #include "base/memory/ptr_util.h" + #include "base/memory/ref_counted.h" + #include "base/strings/string_piece.h" +@@ -23,6 +26,7 @@ + #include "mojo/public/cpp/bindings/interface_id.h" + #include "mojo/public/cpp/bindings/lib/multiplex_router.h" + #include "mojo/public/cpp/bindings/lib/pending_receiver_state.h" ++#include "mojo/public/cpp/bindings/lib/sync_method_traits.h" + #include "mojo/public/cpp/bindings/message_header_validator.h" + #include "mojo/public/cpp/bindings/pending_flush.h" + #include "mojo/public/cpp/bindings/pending_receiver.h" +@@ -90,7 +94,7 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) BindingStateBase { + const char* interface_name, + std::unique_ptr request_validator, + bool passes_associated_kinds, +- bool has_sync_methods, ++ base::span sync_method_ordinals, + MessageReceiverWithResponderStatus* stub, + uint32_t interface_version, + MessageToStableIPCHashCallback ipc_hash_callback, +@@ -121,9 +125,9 @@ class BindingState : public BindingStateBase { + BindingStateBase::BindInternal( + std::move(receiver_state), runner, Interface::Name_, + std::make_unique(), +- Interface::PassesAssociatedKinds_, Interface::HasSyncMethods_, &stub_, +- Interface::Version_, Interface::MessageToStableIPCHash_, +- Interface::MessageToMethodName_); ++ Interface::PassesAssociatedKinds_, ++ SyncMethodTraits::GetOrdinals(), &stub_, Interface::Version_, ++ Interface::MessageToStableIPCHash_, Interface::MessageToMethodName_); + } + + PendingReceiver Unbind() { +diff --git a/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc b/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc +index 1a786923f6d66c0b8d17765ea7b629add2db104c..c1e7efe6954ae3dc9186d33067bc324b05273e65 100644 +--- a/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc ++++ b/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc +@@ -439,13 +439,13 @@ InterfaceEndpointClient::InterfaceEndpointClient( + ScopedInterfaceEndpointHandle handle, + MessageReceiverWithResponderStatus* receiver, + std::unique_ptr payload_validator, +- bool expect_sync_requests, ++ base::span sync_method_ordinals, + scoped_refptr task_runner, + uint32_t interface_version, + const char* interface_name, + MessageToStableIPCHashCallback ipc_hash_callback, + MessageToMethodNameCallback method_name_callback) +- : expect_sync_requests_(expect_sync_requests), ++ : sync_method_ordinals_(sync_method_ordinals), + handle_(std::move(handle)), + incoming_receiver_(receiver), + dispatcher_(&thunk_), +@@ -849,7 +849,8 @@ void InterfaceEndpointClient::InitControllerIfNecessary() { + + controller_ = handle_.group_controller()->AttachEndpointClient(handle_, this, + task_runner_); +- if (expect_sync_requests_ && task_runner_->RunsTasksInCurrentSequence()) ++ if (!sync_method_ordinals_.empty() && ++ task_runner_->RunsTasksInCurrentSequence()) + controller_->AllowWokenUpBySyncWatchOnSameThread(); + } + +diff --git a/mojo/public/cpp/bindings/lib/interface_ptr_state.cc b/mojo/public/cpp/bindings/lib/interface_ptr_state.cc +index 8607d5fba2fd59f4f0ca154a9085c47a26ff2c21..aa12189148f79a742be39f3cfaeba9cf54c2dc91 100644 +--- a/mojo/public/cpp/bindings/lib/interface_ptr_state.cc ++++ b/mojo/public/cpp/bindings/lib/interface_ptr_state.cc +@@ -4,6 +4,11 @@ + + #include "mojo/public/cpp/bindings/lib/interface_ptr_state.h" + ++#include ++ ++#include ++ ++#include "base/containers/span.h" + #include "mojo/public/cpp/bindings/lib/task_runner_helper.h" + + namespace mojo { +@@ -100,7 +105,9 @@ bool InterfacePtrStateBase::InitializeEndpointClient( + interface_name); + endpoint_client_ = std::make_unique( + router_->CreateLocalEndpointHandle(kPrimaryInterfaceId), nullptr, +- std::move(payload_validator), false, std::move(runner_), ++ std::move(payload_validator), ++ /* sync_method_ordinals= */ base::span(), ++ std::move(runner_), + // The version is only queried from the client so the value passed here + // will not be used. + 0u, interface_name, ipc_hash_callback, method_name_callback); +diff --git a/mojo/public/cpp/bindings/lib/interface_ptr_state.h b/mojo/public/cpp/bindings/lib/interface_ptr_state.h +index 2d379a081e6731db5cd2182365529da2200e3d7b..5b7bb34ac5c9a4764ee9a41c1d3ce324c6a93b13 100644 +--- a/mojo/public/cpp/bindings/lib/interface_ptr_state.h ++++ b/mojo/public/cpp/bindings/lib/interface_ptr_state.h +@@ -25,6 +25,7 @@ + #include "mojo/public/cpp/bindings/interface_endpoint_client.h" + #include "mojo/public/cpp/bindings/lib/multiplex_router.h" + #include "mojo/public/cpp/bindings/lib/pending_remote_state.h" ++#include "mojo/public/cpp/bindings/lib/sync_method_traits.h" + #include "mojo/public/cpp/bindings/pending_flush.h" + #include "mojo/public/cpp/bindings/thread_safe_proxy.h" + #include "mojo/public/cpp/system/message_pipe.h" +@@ -249,6 +250,10 @@ class InterfacePtrState : public InterfacePtrStateBase { + endpoint_client()->RaiseError(); + } + ++ InterfaceEndpointClient* endpoint_client_for_test() { ++ return endpoint_client(); ++ } ++ + private: + void ConfigureProxyIfNecessary() { + // The proxy has been configured. +@@ -259,7 +264,8 @@ class InterfacePtrState : public InterfacePtrStateBase { + } + + if (InitializeEndpointClient( +- Interface::PassesAssociatedKinds_, Interface::HasSyncMethods_, ++ Interface::PassesAssociatedKinds_, ++ !SyncMethodTraits::GetOrdinals().empty(), + Interface::HasUninterruptableMethods_, + std::make_unique(), + Interface::Name_, Interface::MessageToStableIPCHash_, +diff --git a/mojo/public/cpp/bindings/lib/multiplex_router.cc b/mojo/public/cpp/bindings/lib/multiplex_router.cc +index b9c92d5ec9eab57972cf870efff51fe09e381623..c04999f0ac8881cc86ed34761ddeb8e8dfc83164 100644 +--- a/mojo/public/cpp/bindings/lib/multiplex_router.cc ++++ b/mojo/public/cpp/bindings/lib/multiplex_router.cc +@@ -1067,6 +1067,12 @@ bool MultiplexRouter::ProcessIncomingMessage( + + bool can_direct_call; + if (message->has_flag(Message::kFlagIsSync)) { ++ if (!message->has_flag(Message::kFlagIsResponse) && ++ !base::Contains(endpoint->client()->sync_method_ordinals(), ++ message->name())) { ++ RaiseErrorInNonTestingMode(); ++ return true; ++ } + can_direct_call = client_call_behavior != NO_DIRECT_CLIENT_CALLS && + endpoint->task_runner()->RunsTasksInCurrentSequence(); + } else { +diff --git a/mojo/public/cpp/bindings/lib/sync_method_traits.h b/mojo/public/cpp/bindings/lib/sync_method_traits.h +new file mode 100644 +index 0000000000000000000000000000000000000000..2b334f8d01c2edb7c3e6b98fb8d35925aded11ab +--- /dev/null ++++ b/mojo/public/cpp/bindings/lib/sync_method_traits.h +@@ -0,0 +1,31 @@ ++// Copyright 2022 The Chromium Authors ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_SYNC_METHOD_TRAITS_H_ ++#define MOJO_PUBLIC_CPP_BINDINGS_LIB_SYNC_METHOD_TRAITS_H_ ++ ++#include ++ ++#include ++ ++#include "base/containers/span.h" ++ ++namespace mojo::internal { ++ ++template ++struct SyncMethodTraits { ++ static constexpr base::span GetOrdinals() { return {}; } ++}; ++ ++template ++struct SyncMethodTraits> { ++ static constexpr base::span GetOrdinals() { ++ return Interface::kSyncMethodOrdinals; ++ } ++}; ++ ++} // namespace mojo::internal ++ ++#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_SYNC_METHOD_TRAITS_H_ +diff --git a/mojo/public/cpp/bindings/tests/BUILD.gn b/mojo/public/cpp/bindings/tests/BUILD.gn +index 248176f6f350b57bb5138924c68c4393ba1c11a8..25cfe56438d099ddcb4ed04a4e83b9abb89b8d14 100644 +--- a/mojo/public/cpp/bindings/tests/BUILD.gn ++++ b/mojo/public/cpp/bindings/tests/BUILD.gn +@@ -65,6 +65,7 @@ source_set("tests") { + ":mojo_public_bindings_test_utils", + ":test_extra_cpp_template_mojom", + ":test_mojom", ++ ":test_mojom__generate_message_ids", + "//base/test:test_support", + "//mojo/core/test:test_support", + "//mojo/public/cpp/bindings", +diff --git a/mojo/public/cpp/bindings/tests/bindings_perftest.cc b/mojo/public/cpp/bindings/tests/bindings_perftest.cc +index 2c44aaedd8b1a9415d41d8215266aad5033e34e3..1bb2c2d7c03f3b2069e09c1746b17cfea0477b0b 100644 +--- a/mojo/public/cpp/bindings/tests/bindings_perftest.cc ++++ b/mojo/public/cpp/bindings/tests/bindings_perftest.cc +@@ -213,12 +213,12 @@ TEST_F(MojoBindingsPerftest, MultiplexRouterPingPong) { + + InterfaceEndpointClient client0( + router0->CreateLocalEndpointHandle(kPrimaryInterfaceId), &paddle0, +- nullptr, false, base::ThreadTaskRunnerHandle::Get(), 0u, +- kTestInterfaceName, MessageToStableIPCHash, MessageToMethodName); ++ nullptr, {}, base::ThreadTaskRunnerHandle::Get(), 0u, kTestInterfaceName, ++ MessageToStableIPCHash, MessageToMethodName); + InterfaceEndpointClient client1( + router1->CreateLocalEndpointHandle(kPrimaryInterfaceId), &paddle1, +- nullptr, false, base::ThreadTaskRunnerHandle::Get(), 0u, +- kTestInterfaceName, MessageToStableIPCHash, MessageToMethodName); ++ nullptr, {}, base::ThreadTaskRunnerHandle::Get(), 0u, kTestInterfaceName, ++ MessageToStableIPCHash, MessageToMethodName); + + paddle0.set_sender(&client0); + paddle1.set_sender(&client1); +@@ -265,8 +265,8 @@ TEST_F(MojoBindingsPerftest, MultiplexRouterDispatchCost) { + CounterReceiver receiver; + InterfaceEndpointClient client( + router->CreateLocalEndpointHandle(kPrimaryInterfaceId), &receiver, +- nullptr, false, base::ThreadTaskRunnerHandle::Get(), 0u, +- kTestInterfaceName, MessageToStableIPCHash, MessageToMethodName); ++ nullptr, {}, base::ThreadTaskRunnerHandle::Get(), 0u, kTestInterfaceName, ++ MessageToStableIPCHash, MessageToMethodName); + + static const uint32_t kIterations[] = {1000, 3000000}; + +diff --git a/mojo/public/cpp/bindings/tests/multiplex_router_unittest.cc b/mojo/public/cpp/bindings/tests/multiplex_router_unittest.cc +index 300ead4aefd2d5167c29c0afae4ea7c1a3f85426..1dcb7bcddc04cc8584300e4add052cb2059613cf 100644 +--- a/mojo/public/cpp/bindings/tests/multiplex_router_unittest.cc ++++ b/mojo/public/cpp/bindings/tests/multiplex_router_unittest.cc +@@ -74,13 +74,13 @@ class MultiplexRouterTest : public testing::Test { + + TEST_F(MultiplexRouterTest, BasicRequestResponse) { + InterfaceEndpointClient client0( +- std::move(endpoint0_), nullptr, std::make_unique(), +- false, base::ThreadTaskRunnerHandle::Get(), 0u, kTestInterfaceName, ++ std::move(endpoint0_), nullptr, std::make_unique(), {}, ++ base::ThreadTaskRunnerHandle::Get(), 0u, kTestInterfaceName, + MessageToStableIPCHash, MessageToMethodName); + ResponseGenerator generator; + InterfaceEndpointClient client1( + std::move(endpoint1_), &generator, std::make_unique(), +- false, base::ThreadTaskRunnerHandle::Get(), 0u, kTestInterfaceName, ++ {}, base::ThreadTaskRunnerHandle::Get(), 0u, kTestInterfaceName, + MessageToStableIPCHash, MessageToMethodName); + + Message request; +@@ -123,13 +123,13 @@ TEST_F(MultiplexRouterTest, BasicRequestResponse) { + + TEST_F(MultiplexRouterTest, BasicRequestResponse_Synchronous) { + InterfaceEndpointClient client0( +- std::move(endpoint0_), nullptr, std::make_unique(), +- false, base::ThreadTaskRunnerHandle::Get(), 0u, kTestInterfaceName, ++ std::move(endpoint0_), nullptr, std::make_unique(), {}, ++ base::ThreadTaskRunnerHandle::Get(), 0u, kTestInterfaceName, + MessageToStableIPCHash, MessageToMethodName); + ResponseGenerator generator; + InterfaceEndpointClient client1( + std::move(endpoint1_), &generator, std::make_unique(), +- false, base::ThreadTaskRunnerHandle::Get(), 0u, kTestInterfaceName, ++ {}, base::ThreadTaskRunnerHandle::Get(), 0u, kTestInterfaceName, + MessageToStableIPCHash, MessageToMethodName); + + Message request; +@@ -173,15 +173,15 @@ TEST_F(MultiplexRouterTest, BasicRequestResponse_Synchronous) { + TEST_F(MultiplexRouterTest, LazyResponses) { + InterfaceEndpointClient client0( + std::move(endpoint0_), nullptr, base::WrapUnique(new PassThroughFilter()), +- false, base::ThreadTaskRunnerHandle::Get(), 0u, kTestInterfaceName, ++ {}, base::ThreadTaskRunnerHandle::Get(), 0u, kTestInterfaceName, + MessageToStableIPCHash, MessageToMethodName); + base::RunLoop run_loop; + LazyResponseGenerator generator(run_loop.QuitClosure()); + InterfaceEndpointClient client1(std::move(endpoint1_), &generator, +- base::WrapUnique(new PassThroughFilter()), +- false, base::ThreadTaskRunnerHandle::Get(), +- 0u, kTestInterfaceName, +- MessageToStableIPCHash, MessageToMethodName); ++ base::WrapUnique(new PassThroughFilter()), {}, ++ base::ThreadTaskRunnerHandle::Get(), 0u, ++ kTestInterfaceName, MessageToStableIPCHash, ++ MessageToMethodName); + + Message request; + AllocRequestMessage(1, "hello", &request); +@@ -247,7 +247,7 @@ TEST_F(MultiplexRouterTest, MissingResponses) { + base::RunLoop run_loop0, run_loop1; + InterfaceEndpointClient client0( + std::move(endpoint0_), nullptr, base::WrapUnique(new PassThroughFilter()), +- false, base::ThreadTaskRunnerHandle::Get(), 0u, kTestInterfaceName, ++ {}, base::ThreadTaskRunnerHandle::Get(), 0u, kTestInterfaceName, + MessageToStableIPCHash, MessageToMethodName); + bool error_handler_called0 = false; + client0.set_connection_error_handler(base::BindOnce( +@@ -256,10 +256,10 @@ TEST_F(MultiplexRouterTest, MissingResponses) { + base::RunLoop run_loop3; + LazyResponseGenerator generator(run_loop3.QuitClosure()); + InterfaceEndpointClient client1(std::move(endpoint1_), &generator, +- base::WrapUnique(new PassThroughFilter()), +- false, base::ThreadTaskRunnerHandle::Get(), +- 0u, kTestInterfaceName, +- MessageToStableIPCHash, MessageToMethodName); ++ base::WrapUnique(new PassThroughFilter()), {}, ++ base::ThreadTaskRunnerHandle::Get(), 0u, ++ kTestInterfaceName, MessageToStableIPCHash, ++ MessageToMethodName); + bool error_handler_called1 = false; + client1.set_connection_error_handler(base::BindOnce( + &ForwardErrorHandler, &error_handler_called1, run_loop1.QuitClosure())); +@@ -306,13 +306,13 @@ TEST_F(MultiplexRouterTest, LateResponse) { + { + InterfaceEndpointClient client0( + std::move(endpoint0_), nullptr, std::make_unique(), +- false, base::ThreadTaskRunnerHandle::Get(), 0u, kTestInterfaceName, +- MessageToStableIPCHash, MessageToMethodName); +- InterfaceEndpointClient client1( +- std::move(endpoint1_), &generator, +- std::make_unique(), false, +- base::ThreadTaskRunnerHandle::Get(), 0u, kTestInterfaceName, ++ {}, base::ThreadTaskRunnerHandle::Get(), 0u, kTestInterfaceName, + MessageToStableIPCHash, MessageToMethodName); ++ InterfaceEndpointClient client1(std::move(endpoint1_), &generator, ++ std::make_unique(), {}, ++ base::ThreadTaskRunnerHandle::Get(), 0u, ++ kTestInterfaceName, MessageToStableIPCHash, ++ MessageToMethodName); + + Message request; + AllocRequestMessage(1, "hello", &request); +diff --git a/mojo/public/cpp/bindings/tests/sync_method_unittest.cc b/mojo/public/cpp/bindings/tests/sync_method_unittest.cc +index d794d29df07d289d34b3b1aae9f8574fc914c050..6de90c8ec9619358e97d50726d7c8c6820df7990 100644 +--- a/mojo/public/cpp/bindings/tests/sync_method_unittest.cc ++++ b/mojo/public/cpp/bindings/tests/sync_method_unittest.cc +@@ -2,6 +2,7 @@ + // Use of this source code is governed by a BSD-style license that can be + // found in the LICENSE file. + ++#include + #include + + #include "base/barrier_closure.h" +@@ -9,15 +10,21 @@ + #include "base/check.h" + #include "base/run_loop.h" + #include "base/sequence_token.h" ++#include "base/task/sequenced_task_runner.h" + #include "base/task/thread_pool.h" + #include "base/test/bind.h" + #include "base/test/task_environment.h" + #include "base/threading/sequence_bound.h" ++#include "base/threading/sequenced_task_runner_handle.h" + #include "base/threading/thread.h" + #include "base/time/time.h" + #include "mojo/public/cpp/bindings/associated_receiver.h" + #include "mojo/public/cpp/bindings/associated_receiver_set.h" + #include "mojo/public/cpp/bindings/associated_remote.h" ++#include "mojo/public/cpp/bindings/lib/message_fragment.h" ++#include "mojo/public/cpp/bindings/lib/send_message_helper.h" ++#include "mojo/public/cpp/bindings/lib/serialization_util.h" ++#include "mojo/public/cpp/bindings/message.h" + #include "mojo/public/cpp/bindings/receiver.h" + #include "mojo/public/cpp/bindings/receiver_set.h" + #include "mojo/public/cpp/bindings/remote.h" +@@ -27,10 +34,16 @@ + #include "mojo/public/cpp/bindings/shared_remote.h" + #include "mojo/public/cpp/bindings/sync_call_restrictions.h" + #include "mojo/public/cpp/bindings/tests/bindings_test_base.h" ++#include "mojo/public/cpp/bindings/tests/sync_method_unittest.test-mojom-shared-message-ids.h" + #include "mojo/public/cpp/bindings/tests/sync_method_unittest.test-mojom.h" + #include "mojo/public/interfaces/bindings/tests/test_sync_methods.mojom.h" + #include "testing/gtest/include/gtest/gtest.h" + ++// This needs to be included last, since it forward declares a bunch of classes ++// but depends on those definitions to be included by headers that sort ++// lexicographically after. ++#include "mojo/public/cpp/bindings/tests/sync_method_unittest.test-mojom-params-data.h" ++ + namespace mojo { + namespace test { + namespace sync_method_unittest { +@@ -1703,6 +1716,237 @@ TEST_P(DisableSyncInterruptTest, SharedRemoteNoInterruptWhenDisabled) { + INSTANTIATE_MOJO_BINDINGS_TEST_SUITE_P(SyncInterruptTest); + INSTANTIATE_MOJO_BINDINGS_TEST_SUITE_P(DisableSyncInterruptTest); + ++class OneSyncImpl; ++ ++class NoSyncImpl : public mojom::NoSync { ++ public: ++ explicit NoSyncImpl(PendingReceiver receiver) ++ : receiver_(this, std::move(receiver)) {} ++ ++ explicit NoSyncImpl( ++ PendingAssociatedReceiver associated_receiver) ++ : associated_receiver_(this, std::move(associated_receiver)) {} ++ ++ // mojom::NoSync implementation: ++ void Method(MethodCallback callback) override; ++ void BindNoSync(PendingAssociatedReceiver receiver) override; ++ void BindOneSync(PendingAssociatedReceiver receiver) override; ++ ++ private: ++ Receiver receiver_{this}; ++ AssociatedReceiver associated_receiver_{this}; ++ ++ std::unique_ptr associated_no_sync_; ++ std::unique_ptr associated_one_sync_; ++}; ++ ++class OneSyncImpl : public mojom::OneSync { ++ public: ++ explicit OneSyncImpl(PendingReceiver receiver) ++ : receiver_(this, std::move(receiver)) {} ++ ++ explicit OneSyncImpl( ++ PendingAssociatedReceiver associated_receiver) ++ : associated_receiver_(this, std::move(associated_receiver)) {} ++ ++ // mojom::OneSync implementation: ++ void Method(MethodCallback callback) override; ++ void SyncMethod(SyncMethodCallback callback) override; ++ void BindNoSync(PendingAssociatedReceiver receiver) override; ++ void BindOneSync(PendingAssociatedReceiver receiver) override; ++ ++ private: ++ Receiver receiver_{this}; ++ AssociatedReceiver associated_receiver_{this}; ++ ++ std::unique_ptr associated_no_sync_; ++ std::unique_ptr associated_one_sync_; ++}; ++ ++void NoSyncImpl::Method(MethodCallback callback) { ++ EXPECT_TRUE(false); ++ std::move(callback).Run(); ++} ++ ++void NoSyncImpl::BindNoSync(PendingAssociatedReceiver receiver) { ++ associated_no_sync_ = std::make_unique(std::move(receiver)); ++} ++ ++void NoSyncImpl::BindOneSync( ++ PendingAssociatedReceiver receiver) { ++ associated_one_sync_ = std::make_unique(std::move(receiver)); ++} ++ ++void OneSyncImpl::Method(MethodCallback callback) { ++ EXPECT_TRUE(false); ++ std::move(callback).Run(); ++} ++ ++void OneSyncImpl::SyncMethod(MethodCallback callback) { ++ std::move(callback).Run(); ++} ++ ++void OneSyncImpl::BindNoSync( ++ PendingAssociatedReceiver receiver) { ++ associated_no_sync_ = std::make_unique(std::move(receiver)); ++} ++ ++void OneSyncImpl::BindOneSync( ++ PendingAssociatedReceiver receiver) { ++ associated_one_sync_ = std::make_unique(std::move(receiver)); ++} ++ ++class NoResponseExpectedResponder : public MessageReceiver { ++ public: ++ explicit NoResponseExpectedResponder() = default; ++ ++ // MessageReceiver implementation: ++ bool Accept(Message* message) override { ++ EXPECT_TRUE(false); ++ return true; ++ } ++}; ++ ++class SyncFlagValidationTest : public ::testing::TestWithParam { ++ protected: ++ Message MakeNoSyncMethodMessage() { ++ const uint32_t flags = ++ // Always set the sync flag, as that's the primary point of the test. ++ Message::kFlagIsSync | ++ // InterfaceEndpointClient requires this flag if sending a message with ++ // a responder. ++ Message::kFlagExpectsResponse | GetParam(); ++ Message message(mojom::internal::kNoSync_Method_Name, flags, 0, 0, nullptr); ++ ::mojo::internal::MessageFragment< ++ mojom::internal::NoSync_Method_Params_Data> ++ params(message); ++ params.Allocate(); ++ return message; ++ } ++ ++ Message MakeOneSyncMethodMessage() { ++ const uint32_t flags = ++ // Always set the sync flag, as that's the primary point of the test. ++ Message::kFlagIsSync | ++ // InterfaceEndpointClient requires this flag if sending a message with ++ // a responder. ++ Message::kFlagExpectsResponse | GetParam(); ++ Message message(mojom::internal::kOneSync_Method_Name, flags, 0, 0, ++ nullptr); ++ ::mojo::internal::MessageFragment< ++ mojom::internal::NoSync_Method_Params_Data> ++ params(message); ++ params.Allocate(); ++ return message; ++ } ++ ++ void FlushPostedTasks() { ++ base::RunLoop run_loop; ++ base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE, ++ run_loop.QuitClosure()); ++ run_loop.Run(); ++ } ++ ++ private: ++ base::test::SingleThreadTaskEnvironment task_environment; ++}; ++ ++TEST_P(SyncFlagValidationTest, NonSync) { ++ Remote remote; ++ NoSyncImpl impl(remote.BindNewPipeAndPassReceiver()); ++ ++ Message message = MakeNoSyncMethodMessage(); ++ auto responder = std::make_unique(); ++ ASSERT_TRUE(remote.internal_state()->endpoint_client_for_test()); ++ ::mojo::internal::SendMojoMessage( ++ *remote.internal_state()->endpoint_client_for_test(), message, ++ std::move(responder)); ++} ++ ++TEST_P(SyncFlagValidationTest, OneSync) { ++ Remote remote; ++ OneSyncImpl impl(remote.BindNewPipeAndPassReceiver()); ++ ++ Message message = MakeOneSyncMethodMessage(); ++ auto responder = std::make_unique(); ++ ASSERT_TRUE(remote.internal_state()->endpoint_client_for_test()); ++ ::mojo::internal::SendMojoMessage( ++ *remote.internal_state()->endpoint_client_for_test(), message, ++ std::move(responder)); ++} ++ ++TEST_P(SyncFlagValidationTest, NoSyncAssociatedWithNoSync) { ++ Remote remote; ++ NoSyncImpl impl(remote.BindNewPipeAndPassReceiver()); ++ ++ AssociatedRemote associated_remote; ++ remote->BindNoSync(associated_remote.BindNewEndpointAndPassReceiver()); ++ ++ FlushPostedTasks(); ++ ++ Message message = MakeNoSyncMethodMessage(); ++ auto responder = std::make_unique(); ++ ASSERT_TRUE(remote.internal_state()->endpoint_client_for_test()); ++ ::mojo::internal::SendMojoMessage( ++ *associated_remote.internal_state()->endpoint_client_for_test(), message, ++ std::move(responder)); ++} ++ ++TEST_P(SyncFlagValidationTest, OneSyncAssociatedWithNoSync) { ++ Remote remote; ++ NoSyncImpl impl(remote.BindNewPipeAndPassReceiver()); ++ ++ AssociatedRemote associated_remote; ++ remote->BindOneSync(associated_remote.BindNewEndpointAndPassReceiver()); ++ ++ FlushPostedTasks(); ++ ++ Message message = MakeOneSyncMethodMessage(); ++ auto responder = std::make_unique(); ++ ASSERT_TRUE(remote.internal_state()->endpoint_client_for_test()); ++ ::mojo::internal::SendMojoMessage( ++ *associated_remote.internal_state()->endpoint_client_for_test(), message, ++ std::move(responder)); ++} ++ ++TEST_P(SyncFlagValidationTest, NoSyncAssociatedWithOneSync) { ++ Remote remote; ++ OneSyncImpl impl(remote.BindNewPipeAndPassReceiver()); ++ ++ AssociatedRemote associated_remote; ++ remote->BindNoSync(associated_remote.BindNewEndpointAndPassReceiver()); ++ ++ FlushPostedTasks(); ++ ++ Message message = MakeNoSyncMethodMessage(); ++ auto responder = std::make_unique(); ++ ASSERT_TRUE(remote.internal_state()->endpoint_client_for_test()); ++ ::mojo::internal::SendMojoMessage( ++ *associated_remote.internal_state()->endpoint_client_for_test(), message, ++ std::move(responder)); ++} ++ ++TEST_P(SyncFlagValidationTest, OneSyncAssociatedWithOneSync) { ++ Remote remote; ++ OneSyncImpl impl(remote.BindNewPipeAndPassReceiver()); ++ ++ AssociatedRemote associated_remote; ++ remote->BindOneSync(associated_remote.BindNewEndpointAndPassReceiver()); ++ ++ FlushPostedTasks(); ++ ++ Message message = MakeOneSyncMethodMessage(); ++ auto responder = std::make_unique(); ++ ASSERT_TRUE(remote.internal_state()->endpoint_client_for_test()); ++ ::mojo::internal::SendMojoMessage( ++ *associated_remote.internal_state()->endpoint_client_for_test(), message, ++ std::move(responder)); ++} ++ ++INSTANTIATE_TEST_SUITE_P(, ++ SyncFlagValidationTest, ++ ::testing::Values(0, Message::kFlagIsResponse)); ++ + } // namespace + } // namespace sync_method_unittest + } // namespace test +diff --git a/mojo/public/cpp/bindings/tests/sync_method_unittest.test-mojom b/mojo/public/cpp/bindings/tests/sync_method_unittest.test-mojom +index 951442b3585ad22f936568e211ad41f8ae358705..0cc5f7c6d288f988b6114ff6b5b80546558eb378 100644 +--- a/mojo/public/cpp/bindings/tests/sync_method_unittest.test-mojom ++++ b/mojo/public/cpp/bindings/tests/sync_method_unittest.test-mojom +@@ -49,3 +49,20 @@ interface Ponger { + interface SyncService { + [Sync] SyncCall() => (); + }; ++ ++interface NoSync { ++ Method() => (); ++ ++ BindNoSync(pending_associated_receiver no_sync); ++ BindOneSync(pending_associated_receiver one_sync); ++}; ++ ++interface OneSync { ++ Method() => (); ++ ++ [Sync] ++ SyncMethod() => (); ++ ++ BindNoSync(pending_associated_receiver no_sync); ++ BindOneSync(pending_associated_receiver one_sync); ++}; +diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl +index c09a1ec210acbc8d09cdf4d4e09916a8809fa586..57d9f66922475c73f65b4d2713ad50cbb3ae0f23 100644 +--- a/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl ++++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl +@@ -29,7 +29,12 @@ class {{export_attribute}} {{interface.name}} + {%- endif %} + static constexpr uint32_t Version_ = {{interface.version}}; + static constexpr bool PassesAssociatedKinds_ = {% if interface|passes_associated_kinds %}true{% else %}false{% endif %}; +- static constexpr bool HasSyncMethods_ = {% if interface|has_sync_methods %}true{% else %}false{% endif %}; ++{%- set sync_method_ordinals = interface|get_sync_method_ordinals -%} ++{%- if sync_method_ordinals %} ++ static inline constexpr uint32_t kSyncMethodOrdinals[] = { ++ {{sync_method_ordinals|sort|join(', \n')|indent(4)}} ++ }; ++{%- endif %} + static constexpr bool HasUninterruptableMethods_ = + {%- if interface|has_uninterruptable_methods %} true + {%- else %} false{% endif %}; +diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module-params-data.h.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module-params-data.h.tmpl +index af3bc5168beb5f9e5b9cfe63354dbdb6b29ff8a1..ab71e91dab403f4c552165eba5da7e32a61b1b83 100644 +--- a/mojo/public/tools/bindings/generators/cpp_templates/module-params-data.h.tmpl ++++ b/mojo/public/tools/bindings/generators/cpp_templates/module-params-data.h.tmpl +@@ -17,13 +17,15 @@ + #pragma clang diagnostic ignored "-Wunused-private-field" + #endif + ++namespace mojo::internal { ++class ValidationContext; ++} ++ + {%- for namespace in namespaces_as_array %} + namespace {{namespace}} { + {%- endfor %} + namespace internal { + +-class ValidationContext; +- + {#--- Interface parameter definitions #} + {%- for interface in interfaces %} + {%- for method in interface.methods %} +diff --git a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py +index 014f2bf04da4f2e11a13d57d910ecc8a8b489113..add5a877cb7e38da4599d3ae76ea0bd9486637da 100644 +--- a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py ++++ b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py +@@ -403,7 +403,7 @@ class Generator(generator.Generator): + "get_qualified_name_for_kind": self._GetQualifiedNameForKind, + "has_callbacks": mojom.HasCallbacks, + "has_packed_method_ordinals": HasPackedMethodOrdinals, +- "has_sync_methods": mojom.HasSyncMethods, ++ "get_sync_method_ordinals": mojom.GetSyncMethodOrdinals, + "has_uninterruptable_methods": mojom.HasUninterruptableMethods, + "method_supports_lazy_serialization": + self._MethodSupportsLazySerialization, +diff --git a/mojo/public/tools/mojom/mojom/generate/module.py b/mojo/public/tools/mojom/mojom/generate/module.py +index 160ad1ef37d7bab86fb15081e0b202845820f8b5..a34d9f0e8134281806a6dc7e7f21e649bce95674 100644 +--- a/mojo/public/tools/mojom/mojom/generate/module.py ++++ b/mojo/public/tools/mojom/mojom/generate/module.py +@@ -1739,11 +1739,8 @@ def MethodPassesInterfaces(method): + return _AnyMethodParameterRecursive(method, IsInterfaceKind) + + +-def HasSyncMethods(interface): +- for method in interface.methods: +- if method.sync: +- return True +- return False ++def GetSyncMethodOrdinals(interface): ++ return [method.ordinal for method in interface.methods if method.sync] + + + def HasUninterruptableMethods(interface): diff --git a/patches/chromium/win_fix_touch_mode_detection_dcheck_in_canary.patch b/patches/chromium/win_fix_touch_mode_detection_dcheck_in_canary.patch new file mode 100644 index 0000000000000..97b80ef2d6007 --- /dev/null +++ b/patches/chromium/win_fix_touch_mode_detection_dcheck_in_canary.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: David Bienvenu +Date: Fri, 10 Jun 2022 23:41:51 +0000 +Subject: win: Fix touch mode detection DCHECK in canary + +Remove the DCHECK that the ConvertibleSlateMode key exists. If it does +exist, and is set to 1 (physical keyboard available), then we're not +in touch mode. If the key doesn't exist, or is set to the default (0), +use IsDeviceUsedAsATablet() to determine if we're in touch mode. + +Bug: 1330848 +Change-Id: Ic2d02979c4eb2d318fcc08b37a56163bb7cce55b +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3696127 +Commit-Queue: David Bienvenu +Reviewed-by: Jesse McKenna +Cr-Commit-Position: refs/heads/main@{#1013189} + +diff --git a/base/win/win_util.cc b/base/win/win_util.cc +index a5c20144f6b512ad5d3e2d6f911ab9ad5570bece..ba489fc83d4cc3e91a3c7c8938bf95de46ebe33c 100644 +--- a/base/win/win_util.cc ++++ b/base/win/win_util.cc +@@ -253,16 +253,19 @@ bool IsWindows10OrGreaterTabletMode(HWND hwnd) { + // instead we check if we're in slate mode or not - 0 value means slate + // mode. See + // https://docs.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/microsoft-windows-gpiobuttons-convertibleslatemode ++ ++ constexpr int kKeyboardPresent = 1; + base::win::RegKey registry_key( + HKEY_LOCAL_MACHINE, + L"System\\CurrentControlSet\\Control\\PriorityControl", KEY_READ); + DWORD slate_mode = 0; + bool value_exists = registry_key.ReadValueDW(L"ConvertibleSlateMode", + &slate_mode) == ERROR_SUCCESS; +- DCHECK(value_exists) << "ConvertibleSlateMode value not in registry"; +- // Some devices don't set the reg key to 0 for non touch devices, so also +- // check if the device is used as a tablet. +- return value_exists && slate_mode == 0 && ++ // Some devices don't set the reg key to 1 for keyboard-only devices, so ++ // also check if the device is used as a tablet if it is not 1. Some devices ++ // don't set the registry key at all; fall back to checking if the device ++ // is used as a tablet for them as well. ++ return !(value_exists && slate_mode == kKeyboardPresent) && + IsDeviceUsedAsATablet(/*reason=*/nullptr); + } + diff --git a/patches/config.json b/patches/config.json index 0f4600e674162..83c1c58c75d8d 100644 --- a/patches/config.json +++ b/patches/config.json @@ -21,5 +21,9 @@ "src/electron/patches/ReactiveObjC": "src/third_party/squirrel.mac/vendor/ReactiveObjC", - "src/electron/patches/sqlite": "src/third_party/sqlite/src" + "src/electron/patches/sqlite": "src/third_party/sqlite/src", + + "src/electron/patches/skia": "src/third_party/skia", + + "src/electron/patches/libaom": "src/third_party/libaom/source/libaom" } diff --git a/patches/libaom/.patches b/patches/libaom/.patches new file mode 100644 index 0000000000000..fec630fecf6f9 --- /dev/null +++ b/patches/libaom/.patches @@ -0,0 +1 @@ +rtc_avoid_scene_detection_on_resize.patch diff --git a/patches/libaom/rtc_avoid_scene_detection_on_resize.patch b/patches/libaom/rtc_avoid_scene_detection_on_resize.patch new file mode 100644 index 0000000000000..379c6e555a186 --- /dev/null +++ b/patches/libaom/rtc_avoid_scene_detection_on_resize.patch @@ -0,0 +1,72 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Marco Paniconi +Date: Mon, 28 Nov 2022 14:25:08 -0800 +Subject: rtc: Avoid scene detection on resize + +Don't enter scene detection under external resize. +Add rc->prev_coded_width/height to track the +previous encoded frame eweight/height. +The rc is part of layer context so this will be +per spatial layer for SVC. + +This fixes the buffer overflow issue below. + +Bug: chromium:1393384 +Change-Id: I4b11818a27c439c2d2c42036dff7b8777f70a86e +(cherry picked from commit bee1caded272127a6d6b70ac79479083d183d5d0) + +diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c +index 40da4f4564e670a74353613620ce162d445f32f8..daadb3ee7d70066d2e38293c4b2029cfee2aab4d 100644 +--- a/av1/encoder/ratectrl.c ++++ b/av1/encoder/ratectrl.c +@@ -2128,6 +2128,9 @@ void av1_rc_postencode_update(AV1_COMP *cpi, uint64_t bytes_used) { + } + #endif + if (current_frame->frame_type == KEY_FRAME) rc->frames_since_key = 0; ++ ++ rc->prev_coded_width = cm->width; ++ rc->prev_coded_height = cm->height; + // if (current_frame->frame_number == 1 && cm->show_frame) + /* + rc->this_frame_target = +@@ -2144,6 +2147,8 @@ void av1_rc_postencode_update_drop_frame(AV1_COMP *cpi) { + cpi->rc.rc_2_frame = 0; + cpi->rc.rc_1_frame = 0; + cpi->rc.prev_avg_frame_bandwidth = cpi->rc.avg_frame_bandwidth; ++ cpi->rc.prev_coded_width = cpi->common.width; ++ cpi->rc.prev_coded_height = cpi->common.height; + } + + int av1_find_qindex(double desired_q, aom_bit_depth_t bit_depth, +@@ -3083,8 +3088,15 @@ void av1_get_one_pass_rt_params(AV1_COMP *cpi, + } + } + // Check for scene change: for SVC check on base spatial layer only. +- if (cpi->sf.rt_sf.check_scene_detection && svc->spatial_layer_id == 0) +- rc_scene_detection_onepass_rt(cpi); ++ if (cpi->sf.rt_sf.check_scene_detection && svc->spatial_layer_id == 0) { ++ if (rc->prev_coded_width == cm->width && ++ rc->prev_coded_height == cm->height) { ++ rc_scene_detection_onepass_rt(cpi); ++ } else if (cpi->src_sad_blk_64x64) { ++ aom_free(cpi->src_sad_blk_64x64); ++ cpi->src_sad_blk_64x64 = NULL; ++ } ++ } + // Check for dynamic resize, for single spatial layer for now. + // For temporal layers only check on base temporal layer. + if (cpi->oxcf.resize_cfg.resize_mode == RESIZE_DYNAMIC) { +diff --git a/av1/encoder/ratectrl.h b/av1/encoder/ratectrl.h +index 5ac9660ab8d31440a5608bab6794286e63203da7..5291323ff4f1401a6a02a8332e552aa8c33b0b0f 100644 +--- a/av1/encoder/ratectrl.h ++++ b/av1/encoder/ratectrl.h +@@ -252,6 +252,9 @@ typedef struct { + int frame_level_fast_extra_bits; + + double frame_level_rate_correction_factors[RATE_FACTOR_LEVELS]; ++ ++ int prev_coded_width; ++ int prev_coded_height; + /*!\endcond */ + } RATE_CONTROL; + diff --git a/patches/node/.patches b/patches/node/.patches index 22e77d301fb08..ba016afe7ea1d 100644 --- a/patches/node/.patches +++ b/patches/node/.patches @@ -45,3 +45,6 @@ json_parse_errors_made_user-friendly.patch build_ensure_v8_pointer_compression_sandbox_is_enabled_on_64bit.patch build_ensure_native_module_compilation_fails_if_not_using_a_new.patch buffer_fix_atob_input_validation.patch +fix_expose_the_built-in_electron_module_via_the_esm_loader.patch +chore_enable_c_17_for_native_modules.patch +cherry-pick-09ae62b.patch diff --git a/patches/node/cherry-pick-09ae62b.patch b/patches/node/cherry-pick-09ae62b.patch new file mode 100644 index 0000000000000..d41a1ac1b6477 --- /dev/null +++ b/patches/node/cherry-pick-09ae62b.patch @@ -0,0 +1,236 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Dawson +Date: Tue, 25 Oct 2022 17:39:41 -0400 +Subject: node-api: handle no support for external buffers + +Refs: https://github.com/electron/electron/issues/35801 +Refs: https://github.com/nodejs/abi-stable-node/issues/441 + +Electron recently dropped support for external +buffers. Provide a way for addon authors to: +- hide the methods to create external buffers so they can + avoid using them if they want the broadest compatibility. +- call the methods that create external buffers at runtime + to check if external buffers are supported and either + use them or not based on the return code. + +Signed-off-by: Michael Dawson + +PR-URL: https://github.com/nodejs/node/pull/45181 +Reviewed-By: Chengzhong Wu +Reviewed-By: Minwoo Jung + +diff --git a/doc/api/n-api.md b/doc/api/n-api.md +index 3d1741bad82359af6a258fb2a059656f1528bba0..d64f80e2635074df7f8ecd72d1fde7d1747786fa 100644 +--- a/doc/api/n-api.md ++++ b/doc/api/n-api.md +@@ -579,6 +579,7 @@ typedef enum { + napi_arraybuffer_expected, + napi_detachable_arraybuffer_expected, + napi_would_deadlock, /* unused */ ++ napi_no_external_buffers_allowed + } napi_status; + ``` + +@@ -2394,6 +2395,19 @@ napi_create_external_arraybuffer(napi_env env, + + Returns `napi_ok` if the API succeeded. + ++**Some runtimes other than Node.js have dropped support for external buffers**. ++On runtimes other than Node.js this method may return ++`napi_no_external_buffers_allowed` to indicate that external ++buffers are not supported. One such runtime is Electron as ++described in this issue ++[electron/issues/35801](https://github.com/electron/electron/issues/35801). ++ ++In order to maintain broadest compatibility with all runtimes ++you may define `NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED` in your addon before ++includes for the node-api headers. Doing so will hide the 2 functions ++that create external buffers. This will ensure a compilation error ++occurs if you accidentally use one of these methods. ++ + This API returns a Node-API value corresponding to a JavaScript `ArrayBuffer`. + The underlying byte buffer of the `ArrayBuffer` is externally allocated and + managed. The caller must ensure that the byte buffer remains valid until the +@@ -2438,6 +2452,19 @@ napi_status napi_create_external_buffer(napi_env env, + + Returns `napi_ok` if the API succeeded. + ++**Some runtimes other than Node.js have dropped support for external buffers**. ++On runtimes other than Node.js this method may return ++`napi_no_external_buffers_allowed` to indicate that external ++buffers are not supported. One such runtime is Electron as ++described in this issue ++[electron/issues/35801](https://github.com/electron/electron/issues/35801). ++ ++In order to maintain broadest compatibility with all runtimes ++you may define `NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED` in your addon before ++includes for the node-api headers. Doing so will hide the 2 functions ++that create external buffers. This will ensure a compilation error ++occurs if you accidentally use one of these methods. ++ + This API allocates a `node::Buffer` object and initializes it with data + backed by the passed in buffer. While this is still a fully-supported data + structure, in most cases using a `TypedArray` will suffice. +diff --git a/src/js_native_api.h b/src/js_native_api.h +index 50ccf11e2405802f1c48764067b4010e8b9a0815..2ddf3780e8bde8df59b202c0913cf6434a6581ce 100644 +--- a/src/js_native_api.h ++++ b/src/js_native_api.h +@@ -404,6 +404,7 @@ NAPI_EXTERN napi_status napi_create_arraybuffer(napi_env env, + size_t byte_length, + void** data, + napi_value* result); ++#ifndef NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED + NAPI_EXTERN napi_status + napi_create_external_arraybuffer(napi_env env, + void* external_data, +@@ -411,6 +412,7 @@ napi_create_external_arraybuffer(napi_env env, + napi_finalize finalize_cb, + void* finalize_hint, + napi_value* result); ++#endif // NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED + NAPI_EXTERN napi_status napi_get_arraybuffer_info(napi_env env, + napi_value arraybuffer, + void** data, +diff --git a/src/js_native_api_types.h b/src/js_native_api_types.h +index 6aba06629b31543c13698dbb02b82db309587c4a..7529b853655a25dd6f945df77c9dd024a0403b26 100644 +--- a/src/js_native_api_types.h ++++ b/src/js_native_api_types.h +@@ -92,7 +92,8 @@ typedef enum { + napi_date_expected, + napi_arraybuffer_expected, + napi_detachable_arraybuffer_expected, +- napi_would_deadlock // unused ++ napi_would_deadlock, // unused ++ napi_no_external_buffers_allowed + } napi_status; + // Note: when adding a new enum value to `napi_status`, please also update + // * `const int last_status` in the definition of `napi_get_last_error_info()' +diff --git a/src/js_native_api_v8.cc b/src/js_native_api_v8.cc +index 1c29c43836a0c35a832e494f8eaebbbe1eee8ea4..108ba4bedbd1684b9a69834ae12347faf4670a27 100644 +--- a/src/js_native_api_v8.cc ++++ b/src/js_native_api_v8.cc +@@ -721,29 +721,30 @@ void Reference::SecondPassCallback( + } // end of namespace v8impl + + // Warning: Keep in-sync with napi_status enum +-static +-const char* error_messages[] = {nullptr, +- "Invalid argument", +- "An object was expected", +- "A string was expected", +- "A string or symbol was expected", +- "A function was expected", +- "A number was expected", +- "A boolean was expected", +- "An array was expected", +- "Unknown failure", +- "An exception is pending", +- "The async work item was cancelled", +- "napi_escape_handle already called on scope", +- "Invalid handle scope usage", +- "Invalid callback scope usage", +- "Thread-safe function queue is full", +- "Thread-safe function handle is closing", +- "A bigint was expected", +- "A date was expected", +- "An arraybuffer was expected", +- "A detachable arraybuffer was expected", +- "Main thread would deadlock", ++static const char* error_messages[] = { ++ nullptr, ++ "Invalid argument", ++ "An object was expected", ++ "A string was expected", ++ "A string or symbol was expected", ++ "A function was expected", ++ "A number was expected", ++ "A boolean was expected", ++ "An array was expected", ++ "Unknown failure", ++ "An exception is pending", ++ "The async work item was cancelled", ++ "napi_escape_handle already called on scope", ++ "Invalid handle scope usage", ++ "Invalid callback scope usage", ++ "Thread-safe function queue is full", ++ "Thread-safe function handle is closing", ++ "A bigint was expected", ++ "A date was expected", ++ "An arraybuffer was expected", ++ "A detachable arraybuffer was expected", ++ "Main thread would deadlock", ++ "External buffers are not allowed", + }; + + napi_status napi_get_last_error_info(napi_env env, +@@ -755,7 +756,7 @@ napi_status napi_get_last_error_info(napi_env env, + // message in the `napi_status` enum each time a new error message is added. + // We don't have a napi_status_last as this would result in an ABI + // change each time a message was added. +- const int last_status = napi_would_deadlock; ++ const int last_status = napi_no_external_buffers_allowed; + + static_assert( + NAPI_ARRAYSIZE(error_messages) == last_status + 1, +diff --git a/src/node_api.cc b/src/node_api.cc +index 60fbe96b8ef272768736ce029bac3ff72f3c84a5..6f8575bb8f289aab041bc126b2fd5f53b1116af5 100644 +--- a/src/node_api.cc ++++ b/src/node_api.cc +@@ -929,6 +929,10 @@ napi_status napi_create_external_buffer(napi_env env, + NAPI_PREAMBLE(env); + CHECK_ARG(env, result); + ++#if defined(V8_ENABLE_SANDBOX) ++ return napi_set_last_error(env, napi_no_external_buffers_allowed); ++#endif ++ + v8::Isolate* isolate = env->isolate; + + // The finalizer object will delete itself after invoking the callback. +diff --git a/src/node_api.h b/src/node_api.h +index 1772c67c15afb2d2712b1900a584f627852e3d7e..47703198fed09a61c3e9e06fa5781d340cc39cf9 100644 +--- a/src/node_api.h ++++ b/src/node_api.h +@@ -138,12 +138,14 @@ NAPI_EXTERN napi_status napi_create_buffer(napi_env env, + size_t length, + void** data, + napi_value* result); ++#ifndef NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED + NAPI_EXTERN napi_status napi_create_external_buffer(napi_env env, + size_t length, + void* data, + napi_finalize finalize_cb, + void* finalize_hint, + napi_value* result); ++#endif // NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED + NAPI_EXTERN napi_status napi_create_buffer_copy(napi_env env, + size_t length, + const void* data, +diff --git a/test/js-native-api/test_general/test_general.c b/test/js-native-api/test_general/test_general.c +index 7b755ce9a9f202eaf91e5103d6c0204925f99cac..b474ab442cb763cb84ec77901da91a6f1471c946 100644 +--- a/test/js-native-api/test_general/test_general.c ++++ b/test/js-native-api/test_general/test_general.c +@@ -1,3 +1,8 @@ ++// we define NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED here to ++// validate that it can be used as a form of test itself. It is ++// not related to any of the other tests ++// defined in the file ++#define NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED + #include + #include + #include +diff --git a/test/node-api/test_general/test_general.c b/test/node-api/test_general/test_general.c +index d430e2df4f3520fddbc5ce8d260adba565e6c3c9..b8d837d5e45650fcb9ba04030721b0f51377f078 100644 +--- a/test/node-api/test_general/test_general.c ++++ b/test/node-api/test_general/test_general.c +@@ -1,4 +1,9 @@ + #define NAPI_EXPERIMENTAL ++// we define NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED here to validate that it can ++// be used as a form of test itself. It is ++// not related to any of the other tests ++// defined in the file ++#define NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED + #include + #include + #include "../../js-native-api/common.h" diff --git a/patches/node/chore_enable_c_17_for_native_modules.patch b/patches/node/chore_enable_c_17_for_native_modules.patch new file mode 100644 index 0000000000000..b306d229a267c --- /dev/null +++ b/patches/node/chore_enable_c_17_for_native_modules.patch @@ -0,0 +1,54 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: deepak1556 +Date: Wed, 16 Nov 2022 13:18:23 +0900 +Subject: chore: enable c++17 for native modules + +V8 headers shipped since 10.4 use C++17 featuers, update the compile flags +correspondinly for native addons. C++ version in this file should be updated +following the version bump in upstream. + +Next update: crbug.com/1284275 + +diff --git a/common.gypi b/common.gypi +index 6bf1b3395250d05cad215bd56f6efea9abc7a7aa..d6b026511acf7a69b1e86093075db30e2f518e17 100644 +--- a/common.gypi ++++ b/common.gypi +@@ -308,7 +308,10 @@ + ], + 'msvs_settings': { + 'VCCLCompilerTool': { +- 'AdditionalOptions': ['/Zc:__cplusplus'], ++ 'AdditionalOptions': [ ++ '/Zc:__cplusplus', ++ '-std:c++17', ++ ], + 'BufferSecurityCheck': 'true', + 'DebugInformationFormat': 1, # /Z7 embed info in .obj files + 'ExceptionHandling': 0, # /EHsc +@@ -440,7 +443,7 @@ + }], + [ 'OS in "linux freebsd openbsd solaris android aix cloudabi"', { + 'cflags': [ '-Wall', '-Wextra', '-Wno-unused-parameter', ], +- 'cflags_cc': [ '-fno-rtti', '-fno-exceptions', '-std=gnu++14' ], ++ 'cflags_cc': [ '-fno-rtti', '-fno-exceptions', '-std=gnu++17' ], + 'defines': [ '__STDC_FORMAT_MACROS' ], + 'ldflags': [ '-rdynamic' ], + 'target_conditions': [ +@@ -580,7 +583,7 @@ + ['clang==1', { + 'xcode_settings': { + 'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0', +- 'CLANG_CXX_LANGUAGE_STANDARD': 'gnu++14', # -std=gnu++14 ++ 'CLANG_CXX_LANGUAGE_STANDARD': 'gnu++17', # -std=gnu++17 + 'CLANG_CXX_LIBRARY': 'libc++', + }, + }], +@@ -653,7 +656,7 @@ + '-qASM', + ], + 'cflags_cc': [ +- '-qxclang=-std=c++14', ++ '-qxclang=-std=c++17', + ], + 'ldflags': [ + '-q64', diff --git a/patches/node/fix_expose_the_built-in_electron_module_via_the_esm_loader.patch b/patches/node/fix_expose_the_built-in_electron_module_via_the_esm_loader.patch new file mode 100644 index 0000000000000..ca41bd3391169 --- /dev/null +++ b/patches/node/fix_expose_the_built-in_electron_module_via_the_esm_loader.patch @@ -0,0 +1,87 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Samuel Attard +Date: Thu, 6 Oct 2022 04:09:16 -0700 +Subject: fix: expose the built-in electron module via the ESM loader + +This allows usage of `import { app } from 'electron'` and `import('electron')` natively in the browser + non-sandboxed renderer + +diff --git a/lib/internal/modules/esm/get_format.js b/lib/internal/modules/esm/get_format.js +index 5ae0e17dcfb5e24a1a117c33c4d42891686e693f..619fe6cef3b02eb575410225f41d3e7d51f37b93 100644 +--- a/lib/internal/modules/esm/get_format.js ++++ b/lib/internal/modules/esm/get_format.js +@@ -31,6 +31,7 @@ const protocolHandlers = ObjectAssign(ObjectCreate(null), { + 'http:': getHttpProtocolModuleFormat, + 'https:': getHttpProtocolModuleFormat, + 'node:'() { return 'builtin'; }, ++ 'electron:'() { return 'commonjs'; }, + }); + + function getDataProtocolModuleFormat(parsed) { +diff --git a/lib/internal/modules/esm/resolve.js b/lib/internal/modules/esm/resolve.js +index 3576f75f0a40a64dceb7e2649b344b83ebc04b39..314fbb78931eef154a1e47c655e2d4bafe11bac3 100644 +--- a/lib/internal/modules/esm/resolve.js ++++ b/lib/internal/modules/esm/resolve.js +@@ -888,6 +888,8 @@ function parsePackageName(specifier, base) { + return { packageName, packageSubpath, isScoped }; + } + ++const electronSpecifiers = new SafeSet(['electron', 'electron/main', 'electron/common', 'electron/renderer']); ++ + /** + * @param {string} specifier + * @param {string | URL | undefined} base +@@ -898,6 +900,10 @@ function packageResolve(specifier, base, conditions) { + if (NativeModule.canBeRequiredByUsers(specifier)) + return new URL('node:' + specifier); + ++ if (electronSpecifiers.has(specifier)) { ++ return new URL('electron:electron'); ++ } ++ + const { packageName, packageSubpath, isScoped } = + parsePackageName(specifier, base); + +@@ -1099,7 +1105,7 @@ function checkIfDisallowedImport(specifier, parsed, parsedParentURL) { + + function throwIfUnsupportedURLProtocol(url) { + if (url.protocol !== 'file:' && url.protocol !== 'data:' && +- url.protocol !== 'node:') { ++ url.protocol !== 'node:' && url.protocol !== 'electron:') { + throw new ERR_UNSUPPORTED_ESM_URL_SCHEME(url); + } + } +diff --git a/lib/internal/modules/esm/translators.js b/lib/internal/modules/esm/translators.js +index d7f4c7edec63d3ce500955a37c6eac00e3e524fd..b97cac53365b121f8e232f0085ff166511c3dda3 100644 +--- a/lib/internal/modules/esm/translators.js ++++ b/lib/internal/modules/esm/translators.js +@@ -155,7 +155,7 @@ translators.set('commonjs', async function commonjsStrategy(url, source, + + if (!cjsParse) await initCJSParse(); + const { module, exportNames } = cjsPreparseModuleExports(filename); +- const namesWithDefault = exportNames.has('default') ? ++ const namesWithDefault = filename === 'electron' ? ['default', ...Object.keys(module.exports)] : exportNames.has('default') ? + [...exportNames] : ['default', ...exportNames]; + + return new ModuleWrap(url, undefined, namesWithDefault, function() { +@@ -174,7 +174,7 @@ translators.set('commonjs', async function commonjsStrategy(url, source, + } + } + +- for (const exportName of exportNames) { ++ for (const exportName of namesWithDefault) { + if (!ObjectPrototypeHasOwnProperty(exports, exportName) || + exportName === 'default') + continue; +diff --git a/lib/internal/url.js b/lib/internal/url.js +index 939374a495856cf2b9c573fa98dc1895eee5e143..c37258ac29e8b7558c1f9a2af7ba6bdd0eab1355 100644 +--- a/lib/internal/url.js ++++ b/lib/internal/url.js +@@ -1418,6 +1418,8 @@ function fileURLToPath(path) { + path = new URL(path); + else if (!isURLInstance(path)) + throw new ERR_INVALID_ARG_TYPE('path', ['string', 'URL'], path); ++ if (path.protocol === 'electron:') ++ return 'electron'; + if (path.protocol !== 'file:') + throw new ERR_INVALID_URL_SCHEME('file'); + return isWindows ? getPathFromURLWin32(path) : getPathFromURLPosix(path); diff --git a/patches/skia/.patches b/patches/skia/.patches new file mode 100644 index 0000000000000..f6dc3e7b8183f --- /dev/null +++ b/patches/skia/.patches @@ -0,0 +1 @@ +cherry-pick-07a2ce61e31a.patch diff --git a/patches/skia/cherry-pick-07a2ce61e31a.patch b/patches/skia/cherry-pick-07a2ce61e31a.patch new file mode 100644 index 0000000000000..52a89a5009051 --- /dev/null +++ b/patches/skia/cherry-pick-07a2ce61e31a.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Greg Daniel +Date: Wed, 5 Oct 2022 15:28:56 -0400 +Subject: Fix GrDirectContext::fClinetMappedBuffer access in abandoned + callbacks. + +Bug: chromium:1364604 +Change-Id: I1ca44cab1c762e7f94ac94be94991ec94a7497be +Reviewed-on: https://skia-review.googlesource.com/c/skia/+/583963 +Commit-Queue: Greg Daniel +Reviewed-by: Brian Salomon +Reviewed-on: https://skia-review.googlesource.com/c/skia/+/587879 +Auto-Submit: Greg Daniel +Commit-Queue: Brian Salomon + +diff --git a/src/gpu/ganesh/GrDirectContext.cpp b/src/gpu/ganesh/GrDirectContext.cpp +index 0ff55edd47e9eaa7d9ac9912806fd29e0043a498..ad42f11b93b9e269a997f9e02e58078f03a51844 100644 +--- a/src/gpu/ganesh/GrDirectContext.cpp ++++ b/src/gpu/ganesh/GrDirectContext.cpp +@@ -144,9 +144,6 @@ void GrDirectContext::abandonContext() { + + fGpu->disconnect(GrGpu::DisconnectType::kAbandon); + +- // Must be after GrResourceCache::abandonAll(). +- fMappedBufferManager.reset(); +- + if (fSmallPathAtlasMgr) { + fSmallPathAtlasMgr->reset(); + } +diff --git a/src/gpu/ganesh/GrFinishCallbacks.cpp b/src/gpu/ganesh/GrFinishCallbacks.cpp +index 5519d2ca639d31f86e33ff0f617246b785fbc779..172f07d4de4554663140fdc2ad30ceab9bf449aa 100644 +--- a/src/gpu/ganesh/GrFinishCallbacks.cpp ++++ b/src/gpu/ganesh/GrFinishCallbacks.cpp +@@ -35,10 +35,16 @@ void GrFinishCallbacks::check() { + + void GrFinishCallbacks::callAll(bool doDelete) { + while (!fCallbacks.empty()) { +- fCallbacks.front().fCallback(fCallbacks.front().fContext); ++ // While we are processing a proc we need to make sure to remove it from ++ // the callback list before calling it. This is because the client could ++ // trigger a call (e.g. calling flushAndSubmit(/*sync=*/true)) that has ++ // us process the finished callbacks. We also must process deleting the ++ // fence before a client may abandon the context. ++ auto finishCallback = fCallbacks.front(); + if (doDelete) { +- fGpu->deleteFence(fCallbacks.front().fFence); ++ fGpu->deleteFence(finishCallback.fFence); + } + fCallbacks.pop_front(); ++ finishCallback.fCallback(finishCallback.fContext); + } + } diff --git a/patches/sqlite/.patches b/patches/sqlite/.patches index 0d7f385925d37..2c8e5ed923e60 100644 --- a/patches/sqlite/.patches +++ b/patches/sqlite/.patches @@ -1,2 +1,3 @@ utf-8_q_simplify_20the_20logic_20that_20converts_20the_20_1_20.patch utf-8_q_when_20applying_20the_20omit-order-by_20optimization.patch +utf-8_q_m102-lts_20enhance_20defensive_20mode_20so_20that_20i.patch diff --git a/patches/sqlite/utf-8_q_m102-lts_20enhance_20defensive_20mode_20so_20that_20i.patch b/patches/sqlite/utf-8_q_m102-lts_20enhance_20defensive_20mode_20so_20that_20i.patch new file mode 100644 index 0000000000000..d2e40a61ab9bd --- /dev/null +++ b/patches/sqlite/utf-8_q_m102-lts_20enhance_20defensive_20mode_20so_20that_20i.patch @@ -0,0 +1,1104 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: drh <> +Date: Tue, 18 Oct 2022 18:55:52 +0000 +Subject: Enhance defensive mode so that it disallows CREATE TRIGGER statements + if the statements within the trigger attempt to write on a shadow table. Also + make the legacy FTS3 code more robust against integer overflow during memory + allocation. + +Bug: 1368076 +FossilOrigin-Name: c41f25e6f3591e575452c4c68f8072a0163cc00d80af31f90d407c7deca79622 +(cherry picked from commit 3ec786ab9cfa213525ecc18b326aeb18ab842f7d) +Change-Id: I3b2cbf7c04f1873a6001d577feefaa8abd9f2a7d +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/deps/sqlite/+/3933554 +Reviewed-by: Ayu Ishii + +diff --git a/amalgamation/sqlite3.c b/amalgamation/sqlite3.c +index 9b9c2d727e7b0c21a03353aba6b4725e7d7c1633..dca202f0165ac40f2e023443222391fbf2885693 100644 +--- a/amalgamation/sqlite3.c ++++ b/amalgamation/sqlite3.c +@@ -454,7 +454,7 @@ extern "C" { + */ + #define SQLITE_VERSION "3.38.5" + #define SQLITE_VERSION_NUMBER 3038005 +-#define SQLITE_SOURCE_ID "2022-05-06 15:25:27 78d9c993d404cdfaa7fdd2973fa1052e3da9f66215cff9c5540ebe55c407alt1" ++#define SQLITE_SOURCE_ID "2022-05-06 15:25:27 4cf1f47cc2533b1c8053f642fa0754cddb26df96804e4fa144dee4a78632alt1" + + /* + ** CAPI3REF: Run-Time Library Version Numbers +@@ -142357,6 +142357,23 @@ SQLITE_PRIVATE void sqlite3FinishTrigger( + Vdbe *v; + char *z; + ++ /* If this is a new CREATE TABLE statement, and if shadow tables ++ ** are read-only, and the trigger makes a change to a shadow table, ++ ** then raise an error - do not allow the trigger to be created. */ ++ if( sqlite3ReadOnlyShadowTables(db) ){ ++ TriggerStep *pStep; ++ for(pStep=pTrig->step_list; pStep; pStep=pStep->pNext){ ++ if( pStep->zTarget!=0 ++ && sqlite3ShadowTableName(db, pStep->zTarget) ++ ){ ++ sqlite3ErrorMsg(pParse, ++ "trigger \"%s\" may not write to shadow table \"%s\"", ++ pTrig->zName, pStep->zTarget); ++ goto triggerfinish_cleanup; ++ } ++ } ++ } ++ + /* Make an entry in the sqlite_schema table */ + v = sqlite3GetVdbe(pParse); + if( v==0 ) goto triggerfinish_cleanup; +@@ -174292,7 +174309,7 @@ struct Fts3MultiSegReader { + int nAdvance; /* How many seg-readers to advance */ + Fts3SegFilter *pFilter; /* Pointer to filter object */ + char *aBuffer; /* Buffer to merge doclists in */ +- int nBuffer; /* Allocated size of aBuffer[] in bytes */ ++ i64 nBuffer; /* Allocated size of aBuffer[] in bytes */ + + int iColFilter; /* If >=0, filter for this column */ + int bRestart; +@@ -176988,7 +177005,7 @@ static int fts3TermSelectMerge( + ** + ** Similar padding is added in the fts3DoclistOrMerge() function. + */ +- pTS->aaOutput[0] = sqlite3_malloc(nDoclist + FTS3_VARINT_MAX + 1); ++ pTS->aaOutput[0] = sqlite3_malloc64((i64)nDoclist + FTS3_VARINT_MAX + 1); + pTS->anOutput[0] = nDoclist; + if( pTS->aaOutput[0] ){ + memcpy(pTS->aaOutput[0], aDoclist, nDoclist); +@@ -178842,7 +178859,7 @@ static int fts3EvalIncrPhraseNext( + if( bEof==0 ){ + int nList = 0; + int nByte = a[p->nToken-1].nList; +- char *aDoclist = sqlite3_malloc(nByte+FTS3_BUFFER_PADDING); ++ char *aDoclist = sqlite3_malloc64((i64)nByte+FTS3_BUFFER_PADDING); + if( !aDoclist ) return SQLITE_NOMEM; + memcpy(aDoclist, a[p->nToken-1].pList, nByte+1); + memset(&aDoclist[nByte], 0, FTS3_BUFFER_PADDING); +@@ -183079,7 +183096,7 @@ static int porterNext( + if( n>c->nAllocated ){ + char *pNew; + c->nAllocated = n+20; +- pNew = sqlite3_realloc(c->zToken, c->nAllocated); ++ pNew = sqlite3_realloc64(c->zToken, c->nAllocated); + if( !pNew ) return SQLITE_NOMEM; + c->zToken = pNew; + } +@@ -183831,7 +183848,7 @@ static int simpleNext( + if( n>c->nTokenAllocated ){ + char *pNew; + c->nTokenAllocated = n+20; +- pNew = sqlite3_realloc(c->pToken, c->nTokenAllocated); ++ pNew = sqlite3_realloc64(c->pToken, c->nTokenAllocated); + if( !pNew ) return SQLITE_NOMEM; + c->pToken = pNew; + } +@@ -184993,7 +185010,7 @@ static int fts3PendingListAppendVarint( + + /* Allocate or grow the PendingList as required. */ + if( !p ){ +- p = sqlite3_malloc(sizeof(*p) + 100); ++ p = sqlite3_malloc64(sizeof(*p) + 100); + if( !p ){ + return SQLITE_NOMEM; + } +@@ -185002,14 +185019,14 @@ static int fts3PendingListAppendVarint( + p->nData = 0; + } + else if( p->nData+FTS3_VARINT_MAX+1>p->nSpace ){ +- int nNew = p->nSpace * 2; +- p = sqlite3_realloc(p, sizeof(*p) + nNew); ++ i64 nNew = p->nSpace * 2; ++ p = sqlite3_realloc64(p, sizeof(*p) + nNew); + if( !p ){ + sqlite3_free(*pp); + *pp = 0; + return SQLITE_NOMEM; + } +- p->nSpace = nNew; ++ p->nSpace = (int)nNew; + p->aData = (char *)&p[1]; + } + +@@ -185566,7 +185583,7 @@ SQLITE_PRIVATE int sqlite3Fts3ReadBlock( + int nByte = sqlite3_blob_bytes(p->pSegments); + *pnBlob = nByte; + if( paBlob ){ +- char *aByte = sqlite3_malloc(nByte + FTS3_NODE_PADDING); ++ char *aByte = sqlite3_malloc64((i64)nByte + FTS3_NODE_PADDING); + if( !aByte ){ + rc = SQLITE_NOMEM; + }else{ +@@ -185683,7 +185700,7 @@ static int fts3SegReaderNext( + int nTerm = fts3HashKeysize(pElem); + if( (nTerm+1)>pReader->nTermAlloc ){ + sqlite3_free(pReader->zTerm); +- pReader->zTerm = (char*)sqlite3_malloc((nTerm+1)*2); ++ pReader->zTerm = (char*)sqlite3_malloc64(((i64)nTerm+1)*2); + if( !pReader->zTerm ) return SQLITE_NOMEM; + pReader->nTermAlloc = (nTerm+1)*2; + } +@@ -185691,7 +185708,7 @@ static int fts3SegReaderNext( + pReader->zTerm[nTerm] = '\0'; + pReader->nTerm = nTerm; + +- aCopy = (char*)sqlite3_malloc(nCopy); ++ aCopy = (char*)sqlite3_malloc64(nCopy); + if( !aCopy ) return SQLITE_NOMEM; + memcpy(aCopy, pList->aData, nCopy); + pReader->nNode = pReader->nDoclist = nCopy; +@@ -185978,7 +185995,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderNew( + nExtra = nRoot + FTS3_NODE_PADDING; + } + +- pReader = (Fts3SegReader *)sqlite3_malloc(sizeof(Fts3SegReader) + nExtra); ++ pReader = (Fts3SegReader *)sqlite3_malloc64(sizeof(Fts3SegReader) + nExtra); + if( !pReader ){ + return SQLITE_NOMEM; + } +@@ -186070,7 +186087,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderPending( + if( nElem==nAlloc ){ + Fts3HashElem **aElem2; + nAlloc += 16; +- aElem2 = (Fts3HashElem **)sqlite3_realloc( ++ aElem2 = (Fts3HashElem **)sqlite3_realloc64( + aElem, nAlloc*sizeof(Fts3HashElem *) + ); + if( !aElem2 ){ +@@ -186404,7 +186421,7 @@ static int fts3NodeAddTerm( + ** this is not expected to be a serious problem. + */ + assert( pTree->aData==(char *)&pTree[1] ); +- pTree->aData = (char *)sqlite3_malloc(nReq); ++ pTree->aData = (char *)sqlite3_malloc64(nReq); + if( !pTree->aData ){ + return SQLITE_NOMEM; + } +@@ -186422,7 +186439,7 @@ static int fts3NodeAddTerm( + + if( isCopyTerm ){ + if( pTree->nMalloczMalloc, nTerm*2); ++ char *zNew = sqlite3_realloc64(pTree->zMalloc, (i64)nTerm*2); + if( !zNew ){ + return SQLITE_NOMEM; + } +@@ -186448,7 +186465,7 @@ static int fts3NodeAddTerm( + ** now. Instead, the term is inserted into the parent of pTree. If pTree + ** has no parent, one is created here. + */ +- pNew = (SegmentNode *)sqlite3_malloc(sizeof(SegmentNode) + p->nNodeSize); ++ pNew = (SegmentNode *)sqlite3_malloc64(sizeof(SegmentNode) + p->nNodeSize); + if( !pNew ){ + return SQLITE_NOMEM; + } +@@ -186586,7 +186603,7 @@ static int fts3SegWriterAdd( + ){ + int nPrefix; /* Size of term prefix in bytes */ + int nSuffix; /* Size of term suffix in bytes */ +- int nReq; /* Number of bytes required on leaf page */ ++ i64 nReq; /* Number of bytes required on leaf page */ + int nData; + SegmentWriter *pWriter = *ppWriter; + +@@ -186595,13 +186612,13 @@ static int fts3SegWriterAdd( + sqlite3_stmt *pStmt; + + /* Allocate the SegmentWriter structure */ +- pWriter = (SegmentWriter *)sqlite3_malloc(sizeof(SegmentWriter)); ++ pWriter = (SegmentWriter *)sqlite3_malloc64(sizeof(SegmentWriter)); + if( !pWriter ) return SQLITE_NOMEM; + memset(pWriter, 0, sizeof(SegmentWriter)); + *ppWriter = pWriter; + + /* Allocate a buffer in which to accumulate data */ +- pWriter->aData = (char *)sqlite3_malloc(p->nNodeSize); ++ pWriter->aData = (char *)sqlite3_malloc64(p->nNodeSize); + if( !pWriter->aData ) return SQLITE_NOMEM; + pWriter->nSize = p->nNodeSize; + +@@ -186676,7 +186693,7 @@ static int fts3SegWriterAdd( + ** the buffer to make it large enough. + */ + if( nReq>pWriter->nSize ){ +- char *aNew = sqlite3_realloc(pWriter->aData, nReq); ++ char *aNew = sqlite3_realloc64(pWriter->aData, nReq); + if( !aNew ) return SQLITE_NOMEM; + pWriter->aData = aNew; + pWriter->nSize = nReq; +@@ -186701,7 +186718,7 @@ static int fts3SegWriterAdd( + */ + if( isCopyTerm ){ + if( nTerm>pWriter->nMalloc ){ +- char *zNew = sqlite3_realloc(pWriter->zMalloc, nTerm*2); ++ char *zNew = sqlite3_realloc64(pWriter->zMalloc, (i64)nTerm*2); + if( !zNew ){ + return SQLITE_NOMEM; + } +@@ -187009,12 +187026,12 @@ static void fts3ColumnFilter( + static int fts3MsrBufferData( + Fts3MultiSegReader *pMsr, /* Multi-segment-reader handle */ + char *pList, +- int nList ++ i64 nList + ){ + if( nList>pMsr->nBuffer ){ + char *pNew; + pMsr->nBuffer = nList*2; +- pNew = (char *)sqlite3_realloc(pMsr->aBuffer, pMsr->nBuffer); ++ pNew = (char *)sqlite3_realloc64(pMsr->aBuffer, pMsr->nBuffer); + if( !pNew ) return SQLITE_NOMEM; + pMsr->aBuffer = pNew; + } +@@ -187070,7 +187087,7 @@ SQLITE_PRIVATE int sqlite3Fts3MsrIncrNext( + fts3SegReaderSort(pMsr->apSegment, nMerge, j, xCmp); + + if( nList>0 && fts3SegReaderIsPending(apSegment[0]) ){ +- rc = fts3MsrBufferData(pMsr, pList, nList+1); ++ rc = fts3MsrBufferData(pMsr, pList, (i64)nList+1); + if( rc!=SQLITE_OK ) return rc; + assert( (pMsr->aBuffer[nList] & 0xFE)==0x00 ); + pList = pMsr->aBuffer; +@@ -187207,11 +187224,11 @@ SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr){ + return SQLITE_OK; + } + +-static int fts3GrowSegReaderBuffer(Fts3MultiSegReader *pCsr, int nReq){ ++static int fts3GrowSegReaderBuffer(Fts3MultiSegReader *pCsr, i64 nReq){ + if( nReq>pCsr->nBuffer ){ + char *aNew; + pCsr->nBuffer = nReq*2; +- aNew = sqlite3_realloc(pCsr->aBuffer, pCsr->nBuffer); ++ aNew = sqlite3_realloc64(pCsr->aBuffer, pCsr->nBuffer); + if( !aNew ){ + return SQLITE_NOMEM; + } +@@ -187302,7 +187319,8 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep( + ){ + pCsr->nDoclist = apSegment[0]->nDoclist; + if( fts3SegReaderIsPending(apSegment[0]) ){ +- rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist, pCsr->nDoclist); ++ rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist, ++ (i64)pCsr->nDoclist); + pCsr->aDoclist = pCsr->aBuffer; + }else{ + pCsr->aDoclist = apSegment[0]->aDoclist; +@@ -187355,7 +187373,8 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep( + + nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0); + +- rc = fts3GrowSegReaderBuffer(pCsr, nByte+nDoclist+FTS3_NODE_PADDING); ++ rc = fts3GrowSegReaderBuffer(pCsr, ++ (i64)nByte+nDoclist+FTS3_NODE_PADDING); + if( rc ) return rc; + + if( isFirst ){ +@@ -187381,7 +187400,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep( + fts3SegReaderSort(apSegment, nMerge, j, xCmp); + } + if( nDoclist>0 ){ +- rc = fts3GrowSegReaderBuffer(pCsr, nDoclist+FTS3_NODE_PADDING); ++ rc = fts3GrowSegReaderBuffer(pCsr, (i64)nDoclist+FTS3_NODE_PADDING); + if( rc ) return rc; + memset(&pCsr->aBuffer[nDoclist], 0, FTS3_NODE_PADDING); + pCsr->aDoclist = pCsr->aBuffer; +@@ -188094,7 +188113,7 @@ struct NodeReader { + static void blobGrowBuffer(Blob *pBlob, int nMin, int *pRc){ + if( *pRc==SQLITE_OK && nMin>pBlob->nAlloc ){ + int nAlloc = nMin; +- char *a = (char *)sqlite3_realloc(pBlob->a, nAlloc); ++ char *a = (char *)sqlite3_realloc64(pBlob->a, nAlloc); + if( a ){ + pBlob->nAlloc = nAlloc; + pBlob->a = a; +@@ -188888,7 +188907,7 @@ static int fts3RepackSegdirLevel( + if( nIdx>=nAlloc ){ + int *aNew; + nAlloc += 16; +- aNew = sqlite3_realloc(aIdx, nAlloc*sizeof(int)); ++ aNew = sqlite3_realloc64(aIdx, nAlloc*sizeof(int)); + if( !aNew ){ + rc = SQLITE_NOMEM; + break; +@@ -189262,7 +189281,7 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){ + + /* Allocate space for the cursor, filter and writer objects */ + const int nAlloc = sizeof(*pCsr) + sizeof(*pFilter) + sizeof(*pWriter); +- pWriter = (IncrmergeWriter *)sqlite3_malloc(nAlloc); ++ pWriter = (IncrmergeWriter *)sqlite3_malloc64(nAlloc); + if( !pWriter ) return SQLITE_NOMEM; + pFilter = (Fts3SegFilter *)&pWriter[1]; + pCsr = (Fts3MultiSegReader *)&pFilter[1]; +@@ -189898,7 +189917,7 @@ SQLITE_PRIVATE int sqlite3Fts3DeferredTokenList( + return SQLITE_OK; + } + +- pRet = (char *)sqlite3_malloc(p->pList->nData); ++ pRet = (char *)sqlite3_malloc64(p->pList->nData); + if( !pRet ) return SQLITE_NOMEM; + + nSkip = sqlite3Fts3GetVarint(p->pList->aData, &dummy); +@@ -189918,7 +189937,7 @@ SQLITE_PRIVATE int sqlite3Fts3DeferToken( + int iCol /* Column that token must appear in (or -1) */ + ){ + Fts3DeferredToken *pDeferred; +- pDeferred = sqlite3_malloc(sizeof(*pDeferred)); ++ pDeferred = sqlite3_malloc64(sizeof(*pDeferred)); + if( !pDeferred ){ + return SQLITE_NOMEM; + } +diff --git a/amalgamation/sqlite3.h b/amalgamation/sqlite3.h +index 4ef161c20403dfc7f71e9b081a3dff8b1c615506..792848f39ccfeeefe9665cd3d164adfa3601223a 100644 +--- a/amalgamation/sqlite3.h ++++ b/amalgamation/sqlite3.h +@@ -148,7 +148,7 @@ extern "C" { + */ + #define SQLITE_VERSION "3.38.5" + #define SQLITE_VERSION_NUMBER 3038005 +-#define SQLITE_SOURCE_ID "2022-05-06 15:25:27 78d9c993d404cdfaa7fdd2973fa1052e3da9f66215cff9c5540ebe55c407alt1" ++#define SQLITE_SOURCE_ID "2022-05-06 15:25:27 4cf1f47cc2533b1c8053f642fa0754cddb26df96804e4fa144dee4a78632alt1" + + /* + ** CAPI3REF: Run-Time Library Version Numbers +diff --git a/amalgamation_dev/sqlite3.c b/amalgamation_dev/sqlite3.c +index 94222875ff2d1e47370e3fa766003cfb0f8dc015..414782240a4901d9b46c4345ee599d4f4e2b8619 100644 +--- a/amalgamation_dev/sqlite3.c ++++ b/amalgamation_dev/sqlite3.c +@@ -454,7 +454,7 @@ extern "C" { + */ + #define SQLITE_VERSION "3.38.5" + #define SQLITE_VERSION_NUMBER 3038005 +-#define SQLITE_SOURCE_ID "2022-05-06 15:25:27 78d9c993d404cdfaa7fdd2973fa1052e3da9f66215cff9c5540ebe55c407alt1" ++#define SQLITE_SOURCE_ID "2022-05-06 15:25:27 4cf1f47cc2533b1c8053f642fa0754cddb26df96804e4fa144dee4a78632alt1" + + /* + ** CAPI3REF: Run-Time Library Version Numbers +@@ -142370,6 +142370,23 @@ SQLITE_PRIVATE void sqlite3FinishTrigger( + Vdbe *v; + char *z; + ++ /* If this is a new CREATE TABLE statement, and if shadow tables ++ ** are read-only, and the trigger makes a change to a shadow table, ++ ** then raise an error - do not allow the trigger to be created. */ ++ if( sqlite3ReadOnlyShadowTables(db) ){ ++ TriggerStep *pStep; ++ for(pStep=pTrig->step_list; pStep; pStep=pStep->pNext){ ++ if( pStep->zTarget!=0 ++ && sqlite3ShadowTableName(db, pStep->zTarget) ++ ){ ++ sqlite3ErrorMsg(pParse, ++ "trigger \"%s\" may not write to shadow table \"%s\"", ++ pTrig->zName, pStep->zTarget); ++ goto triggerfinish_cleanup; ++ } ++ } ++ } ++ + /* Make an entry in the sqlite_schema table */ + v = sqlite3GetVdbe(pParse); + if( v==0 ) goto triggerfinish_cleanup; +@@ -174811,7 +174828,7 @@ struct Fts3MultiSegReader { + int nAdvance; /* How many seg-readers to advance */ + Fts3SegFilter *pFilter; /* Pointer to filter object */ + char *aBuffer; /* Buffer to merge doclists in */ +- int nBuffer; /* Allocated size of aBuffer[] in bytes */ ++ i64 nBuffer; /* Allocated size of aBuffer[] in bytes */ + + int iColFilter; /* If >=0, filter for this column */ + int bRestart; +@@ -177507,7 +177524,7 @@ static int fts3TermSelectMerge( + ** + ** Similar padding is added in the fts3DoclistOrMerge() function. + */ +- pTS->aaOutput[0] = sqlite3_malloc(nDoclist + FTS3_VARINT_MAX + 1); ++ pTS->aaOutput[0] = sqlite3_malloc64((i64)nDoclist + FTS3_VARINT_MAX + 1); + pTS->anOutput[0] = nDoclist; + if( pTS->aaOutput[0] ){ + memcpy(pTS->aaOutput[0], aDoclist, nDoclist); +@@ -179361,7 +179378,7 @@ static int fts3EvalIncrPhraseNext( + if( bEof==0 ){ + int nList = 0; + int nByte = a[p->nToken-1].nList; +- char *aDoclist = sqlite3_malloc(nByte+FTS3_BUFFER_PADDING); ++ char *aDoclist = sqlite3_malloc64((i64)nByte+FTS3_BUFFER_PADDING); + if( !aDoclist ) return SQLITE_NOMEM; + memcpy(aDoclist, a[p->nToken-1].pList, nByte+1); + memset(&aDoclist[nByte], 0, FTS3_BUFFER_PADDING); +@@ -183598,7 +183615,7 @@ static int porterNext( + if( n>c->nAllocated ){ + char *pNew; + c->nAllocated = n+20; +- pNew = sqlite3_realloc(c->zToken, c->nAllocated); ++ pNew = sqlite3_realloc64(c->zToken, c->nAllocated); + if( !pNew ) return SQLITE_NOMEM; + c->zToken = pNew; + } +@@ -184350,7 +184367,7 @@ static int simpleNext( + if( n>c->nTokenAllocated ){ + char *pNew; + c->nTokenAllocated = n+20; +- pNew = sqlite3_realloc(c->pToken, c->nTokenAllocated); ++ pNew = sqlite3_realloc64(c->pToken, c->nTokenAllocated); + if( !pNew ) return SQLITE_NOMEM; + c->pToken = pNew; + } +@@ -185512,7 +185529,7 @@ static int fts3PendingListAppendVarint( + + /* Allocate or grow the PendingList as required. */ + if( !p ){ +- p = sqlite3_malloc(sizeof(*p) + 100); ++ p = sqlite3_malloc64(sizeof(*p) + 100); + if( !p ){ + return SQLITE_NOMEM; + } +@@ -185521,14 +185538,14 @@ static int fts3PendingListAppendVarint( + p->nData = 0; + } + else if( p->nData+FTS3_VARINT_MAX+1>p->nSpace ){ +- int nNew = p->nSpace * 2; +- p = sqlite3_realloc(p, sizeof(*p) + nNew); ++ i64 nNew = p->nSpace * 2; ++ p = sqlite3_realloc64(p, sizeof(*p) + nNew); + if( !p ){ + sqlite3_free(*pp); + *pp = 0; + return SQLITE_NOMEM; + } +- p->nSpace = nNew; ++ p->nSpace = (int)nNew; + p->aData = (char *)&p[1]; + } + +@@ -186085,7 +186102,7 @@ SQLITE_PRIVATE int sqlite3Fts3ReadBlock( + int nByte = sqlite3_blob_bytes(p->pSegments); + *pnBlob = nByte; + if( paBlob ){ +- char *aByte = sqlite3_malloc(nByte + FTS3_NODE_PADDING); ++ char *aByte = sqlite3_malloc64((i64)nByte + FTS3_NODE_PADDING); + if( !aByte ){ + rc = SQLITE_NOMEM; + }else{ +@@ -186202,7 +186219,7 @@ static int fts3SegReaderNext( + int nTerm = fts3HashKeysize(pElem); + if( (nTerm+1)>pReader->nTermAlloc ){ + sqlite3_free(pReader->zTerm); +- pReader->zTerm = (char*)sqlite3_malloc((nTerm+1)*2); ++ pReader->zTerm = (char*)sqlite3_malloc64(((i64)nTerm+1)*2); + if( !pReader->zTerm ) return SQLITE_NOMEM; + pReader->nTermAlloc = (nTerm+1)*2; + } +@@ -186210,7 +186227,7 @@ static int fts3SegReaderNext( + pReader->zTerm[nTerm] = '\0'; + pReader->nTerm = nTerm; + +- aCopy = (char*)sqlite3_malloc(nCopy); ++ aCopy = (char*)sqlite3_malloc64(nCopy); + if( !aCopy ) return SQLITE_NOMEM; + memcpy(aCopy, pList->aData, nCopy); + pReader->nNode = pReader->nDoclist = nCopy; +@@ -186497,7 +186514,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderNew( + nExtra = nRoot + FTS3_NODE_PADDING; + } + +- pReader = (Fts3SegReader *)sqlite3_malloc(sizeof(Fts3SegReader) + nExtra); ++ pReader = (Fts3SegReader *)sqlite3_malloc64(sizeof(Fts3SegReader) + nExtra); + if( !pReader ){ + return SQLITE_NOMEM; + } +@@ -186589,7 +186606,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderPending( + if( nElem==nAlloc ){ + Fts3HashElem **aElem2; + nAlloc += 16; +- aElem2 = (Fts3HashElem **)sqlite3_realloc( ++ aElem2 = (Fts3HashElem **)sqlite3_realloc64( + aElem, nAlloc*sizeof(Fts3HashElem *) + ); + if( !aElem2 ){ +@@ -186923,7 +186940,7 @@ static int fts3NodeAddTerm( + ** this is not expected to be a serious problem. + */ + assert( pTree->aData==(char *)&pTree[1] ); +- pTree->aData = (char *)sqlite3_malloc(nReq); ++ pTree->aData = (char *)sqlite3_malloc64(nReq); + if( !pTree->aData ){ + return SQLITE_NOMEM; + } +@@ -186941,7 +186958,7 @@ static int fts3NodeAddTerm( + + if( isCopyTerm ){ + if( pTree->nMalloczMalloc, nTerm*2); ++ char *zNew = sqlite3_realloc64(pTree->zMalloc, (i64)nTerm*2); + if( !zNew ){ + return SQLITE_NOMEM; + } +@@ -186967,7 +186984,7 @@ static int fts3NodeAddTerm( + ** now. Instead, the term is inserted into the parent of pTree. If pTree + ** has no parent, one is created here. + */ +- pNew = (SegmentNode *)sqlite3_malloc(sizeof(SegmentNode) + p->nNodeSize); ++ pNew = (SegmentNode *)sqlite3_malloc64(sizeof(SegmentNode) + p->nNodeSize); + if( !pNew ){ + return SQLITE_NOMEM; + } +@@ -187105,7 +187122,7 @@ static int fts3SegWriterAdd( + ){ + int nPrefix; /* Size of term prefix in bytes */ + int nSuffix; /* Size of term suffix in bytes */ +- int nReq; /* Number of bytes required on leaf page */ ++ i64 nReq; /* Number of bytes required on leaf page */ + int nData; + SegmentWriter *pWriter = *ppWriter; + +@@ -187114,13 +187131,13 @@ static int fts3SegWriterAdd( + sqlite3_stmt *pStmt; + + /* Allocate the SegmentWriter structure */ +- pWriter = (SegmentWriter *)sqlite3_malloc(sizeof(SegmentWriter)); ++ pWriter = (SegmentWriter *)sqlite3_malloc64(sizeof(SegmentWriter)); + if( !pWriter ) return SQLITE_NOMEM; + memset(pWriter, 0, sizeof(SegmentWriter)); + *ppWriter = pWriter; + + /* Allocate a buffer in which to accumulate data */ +- pWriter->aData = (char *)sqlite3_malloc(p->nNodeSize); ++ pWriter->aData = (char *)sqlite3_malloc64(p->nNodeSize); + if( !pWriter->aData ) return SQLITE_NOMEM; + pWriter->nSize = p->nNodeSize; + +@@ -187195,7 +187212,7 @@ static int fts3SegWriterAdd( + ** the buffer to make it large enough. + */ + if( nReq>pWriter->nSize ){ +- char *aNew = sqlite3_realloc(pWriter->aData, nReq); ++ char *aNew = sqlite3_realloc64(pWriter->aData, nReq); + if( !aNew ) return SQLITE_NOMEM; + pWriter->aData = aNew; + pWriter->nSize = nReq; +@@ -187220,7 +187237,7 @@ static int fts3SegWriterAdd( + */ + if( isCopyTerm ){ + if( nTerm>pWriter->nMalloc ){ +- char *zNew = sqlite3_realloc(pWriter->zMalloc, nTerm*2); ++ char *zNew = sqlite3_realloc64(pWriter->zMalloc, (i64)nTerm*2); + if( !zNew ){ + return SQLITE_NOMEM; + } +@@ -187528,12 +187545,12 @@ static void fts3ColumnFilter( + static int fts3MsrBufferData( + Fts3MultiSegReader *pMsr, /* Multi-segment-reader handle */ + char *pList, +- int nList ++ i64 nList + ){ + if( nList>pMsr->nBuffer ){ + char *pNew; + pMsr->nBuffer = nList*2; +- pNew = (char *)sqlite3_realloc(pMsr->aBuffer, pMsr->nBuffer); ++ pNew = (char *)sqlite3_realloc64(pMsr->aBuffer, pMsr->nBuffer); + if( !pNew ) return SQLITE_NOMEM; + pMsr->aBuffer = pNew; + } +@@ -187589,7 +187606,7 @@ SQLITE_PRIVATE int sqlite3Fts3MsrIncrNext( + fts3SegReaderSort(pMsr->apSegment, nMerge, j, xCmp); + + if( nList>0 && fts3SegReaderIsPending(apSegment[0]) ){ +- rc = fts3MsrBufferData(pMsr, pList, nList+1); ++ rc = fts3MsrBufferData(pMsr, pList, (i64)nList+1); + if( rc!=SQLITE_OK ) return rc; + assert( (pMsr->aBuffer[nList] & 0xFE)==0x00 ); + pList = pMsr->aBuffer; +@@ -187726,11 +187743,11 @@ SQLITE_PRIVATE int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr){ + return SQLITE_OK; + } + +-static int fts3GrowSegReaderBuffer(Fts3MultiSegReader *pCsr, int nReq){ ++static int fts3GrowSegReaderBuffer(Fts3MultiSegReader *pCsr, i64 nReq){ + if( nReq>pCsr->nBuffer ){ + char *aNew; + pCsr->nBuffer = nReq*2; +- aNew = sqlite3_realloc(pCsr->aBuffer, pCsr->nBuffer); ++ aNew = sqlite3_realloc64(pCsr->aBuffer, pCsr->nBuffer); + if( !aNew ){ + return SQLITE_NOMEM; + } +@@ -187821,7 +187838,8 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep( + ){ + pCsr->nDoclist = apSegment[0]->nDoclist; + if( fts3SegReaderIsPending(apSegment[0]) ){ +- rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist, pCsr->nDoclist); ++ rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist, ++ (i64)pCsr->nDoclist); + pCsr->aDoclist = pCsr->aBuffer; + }else{ + pCsr->aDoclist = apSegment[0]->aDoclist; +@@ -187874,7 +187892,8 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep( + + nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0); + +- rc = fts3GrowSegReaderBuffer(pCsr, nByte+nDoclist+FTS3_NODE_PADDING); ++ rc = fts3GrowSegReaderBuffer(pCsr, ++ (i64)nByte+nDoclist+FTS3_NODE_PADDING); + if( rc ) return rc; + + if( isFirst ){ +@@ -187900,7 +187919,7 @@ SQLITE_PRIVATE int sqlite3Fts3SegReaderStep( + fts3SegReaderSort(apSegment, nMerge, j, xCmp); + } + if( nDoclist>0 ){ +- rc = fts3GrowSegReaderBuffer(pCsr, nDoclist+FTS3_NODE_PADDING); ++ rc = fts3GrowSegReaderBuffer(pCsr, (i64)nDoclist+FTS3_NODE_PADDING); + if( rc ) return rc; + memset(&pCsr->aBuffer[nDoclist], 0, FTS3_NODE_PADDING); + pCsr->aDoclist = pCsr->aBuffer; +@@ -188613,7 +188632,7 @@ struct NodeReader { + static void blobGrowBuffer(Blob *pBlob, int nMin, int *pRc){ + if( *pRc==SQLITE_OK && nMin>pBlob->nAlloc ){ + int nAlloc = nMin; +- char *a = (char *)sqlite3_realloc(pBlob->a, nAlloc); ++ char *a = (char *)sqlite3_realloc64(pBlob->a, nAlloc); + if( a ){ + pBlob->nAlloc = nAlloc; + pBlob->a = a; +@@ -189407,7 +189426,7 @@ static int fts3RepackSegdirLevel( + if( nIdx>=nAlloc ){ + int *aNew; + nAlloc += 16; +- aNew = sqlite3_realloc(aIdx, nAlloc*sizeof(int)); ++ aNew = sqlite3_realloc64(aIdx, nAlloc*sizeof(int)); + if( !aNew ){ + rc = SQLITE_NOMEM; + break; +@@ -189781,7 +189800,7 @@ SQLITE_PRIVATE int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){ + + /* Allocate space for the cursor, filter and writer objects */ + const int nAlloc = sizeof(*pCsr) + sizeof(*pFilter) + sizeof(*pWriter); +- pWriter = (IncrmergeWriter *)sqlite3_malloc(nAlloc); ++ pWriter = (IncrmergeWriter *)sqlite3_malloc64(nAlloc); + if( !pWriter ) return SQLITE_NOMEM; + pFilter = (Fts3SegFilter *)&pWriter[1]; + pCsr = (Fts3MultiSegReader *)&pFilter[1]; +@@ -190417,7 +190436,7 @@ SQLITE_PRIVATE int sqlite3Fts3DeferredTokenList( + return SQLITE_OK; + } + +- pRet = (char *)sqlite3_malloc(p->pList->nData); ++ pRet = (char *)sqlite3_malloc64(p->pList->nData); + if( !pRet ) return SQLITE_NOMEM; + + nSkip = sqlite3Fts3GetVarint(p->pList->aData, &dummy); +@@ -190437,7 +190456,7 @@ SQLITE_PRIVATE int sqlite3Fts3DeferToken( + int iCol /* Column that token must appear in (or -1) */ + ){ + Fts3DeferredToken *pDeferred; +- pDeferred = sqlite3_malloc(sizeof(*pDeferred)); ++ pDeferred = sqlite3_malloc64(sizeof(*pDeferred)); + if( !pDeferred ){ + return SQLITE_NOMEM; + } +diff --git a/amalgamation_dev/sqlite3.h b/amalgamation_dev/sqlite3.h +index 4ef161c20403dfc7f71e9b081a3dff8b1c615506..792848f39ccfeeefe9665cd3d164adfa3601223a 100644 +--- a/amalgamation_dev/sqlite3.h ++++ b/amalgamation_dev/sqlite3.h +@@ -148,7 +148,7 @@ extern "C" { + */ + #define SQLITE_VERSION "3.38.5" + #define SQLITE_VERSION_NUMBER 3038005 +-#define SQLITE_SOURCE_ID "2022-05-06 15:25:27 78d9c993d404cdfaa7fdd2973fa1052e3da9f66215cff9c5540ebe55c407alt1" ++#define SQLITE_SOURCE_ID "2022-05-06 15:25:27 4cf1f47cc2533b1c8053f642fa0754cddb26df96804e4fa144dee4a78632alt1" + + /* + ** CAPI3REF: Run-Time Library Version Numbers +diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c +index 097338f54770d946db93a7f814c759951dbb3535..6764bb13601386d1d8912004e6c53295c700c020 100644 +--- a/ext/fts3/fts3.c ++++ b/ext/fts3/fts3.c +@@ -2888,7 +2888,7 @@ static int fts3TermSelectMerge( + ** + ** Similar padding is added in the fts3DoclistOrMerge() function. + */ +- pTS->aaOutput[0] = sqlite3_malloc(nDoclist + FTS3_VARINT_MAX + 1); ++ pTS->aaOutput[0] = sqlite3_malloc64((i64)nDoclist + FTS3_VARINT_MAX + 1); + pTS->anOutput[0] = nDoclist; + if( pTS->aaOutput[0] ){ + memcpy(pTS->aaOutput[0], aDoclist, nDoclist); +@@ -4742,7 +4742,7 @@ static int fts3EvalIncrPhraseNext( + if( bEof==0 ){ + int nList = 0; + int nByte = a[p->nToken-1].nList; +- char *aDoclist = sqlite3_malloc(nByte+FTS3_BUFFER_PADDING); ++ char *aDoclist = sqlite3_malloc64((i64)nByte+FTS3_BUFFER_PADDING); + if( !aDoclist ) return SQLITE_NOMEM; + memcpy(aDoclist, a[p->nToken-1].pList, nByte+1); + memset(&aDoclist[nByte], 0, FTS3_BUFFER_PADDING); +diff --git a/ext/fts3/fts3Int.h b/ext/fts3/fts3Int.h +index 0626486edff3a74bfc6fa88c7fe244e06324e6e2..e821d6be31352d6878c3fca79c873009fece71d5 100644 +--- a/ext/fts3/fts3Int.h ++++ b/ext/fts3/fts3Int.h +@@ -558,7 +558,7 @@ struct Fts3MultiSegReader { + int nAdvance; /* How many seg-readers to advance */ + Fts3SegFilter *pFilter; /* Pointer to filter object */ + char *aBuffer; /* Buffer to merge doclists in */ +- int nBuffer; /* Allocated size of aBuffer[] in bytes */ ++ i64 nBuffer; /* Allocated size of aBuffer[] in bytes */ + + int iColFilter; /* If >=0, filter for this column */ + int bRestart; +diff --git a/ext/fts3/fts3_porter.c b/ext/fts3/fts3_porter.c +index 8fb4c25daa0a9ff27d0f3699ff6bd7e0a6e4c3a5..fbe7913020a4e975ce997b02a619ca589dc1dc1d 100644 +--- a/ext/fts3/fts3_porter.c ++++ b/ext/fts3/fts3_porter.c +@@ -621,7 +621,7 @@ static int porterNext( + if( n>c->nAllocated ){ + char *pNew; + c->nAllocated = n+20; +- pNew = sqlite3_realloc(c->zToken, c->nAllocated); ++ pNew = sqlite3_realloc64(c->zToken, c->nAllocated); + if( !pNew ) return SQLITE_NOMEM; + c->zToken = pNew; + } +diff --git a/ext/fts3/fts3_tokenizer1.c b/ext/fts3/fts3_tokenizer1.c +index deea06d92bf895a1f513f863484cfbffd0a2faa1..78e5889da5250184db89879b059a66eb5637aa93 100644 +--- a/ext/fts3/fts3_tokenizer1.c ++++ b/ext/fts3/fts3_tokenizer1.c +@@ -185,7 +185,7 @@ static int simpleNext( + if( n>c->nTokenAllocated ){ + char *pNew; + c->nTokenAllocated = n+20; +- pNew = sqlite3_realloc(c->pToken, c->nTokenAllocated); ++ pNew = sqlite3_realloc64(c->pToken, c->nTokenAllocated); + if( !pNew ) return SQLITE_NOMEM; + c->pToken = pNew; + } +diff --git a/ext/fts3/fts3_write.c b/ext/fts3/fts3_write.c +index 201e5813c6fe870ae46f5e1f13da55d6710896d9..450deddfa70a7a3b16e34a199184b0e096f888c0 100644 +--- a/ext/fts3/fts3_write.c ++++ b/ext/fts3/fts3_write.c +@@ -649,7 +649,7 @@ static int fts3PendingListAppendVarint( + + /* Allocate or grow the PendingList as required. */ + if( !p ){ +- p = sqlite3_malloc(sizeof(*p) + 100); ++ p = sqlite3_malloc64(sizeof(*p) + 100); + if( !p ){ + return SQLITE_NOMEM; + } +@@ -658,14 +658,14 @@ static int fts3PendingListAppendVarint( + p->nData = 0; + } + else if( p->nData+FTS3_VARINT_MAX+1>p->nSpace ){ +- int nNew = p->nSpace * 2; +- p = sqlite3_realloc(p, sizeof(*p) + nNew); ++ i64 nNew = p->nSpace * 2; ++ p = sqlite3_realloc64(p, sizeof(*p) + nNew); + if( !p ){ + sqlite3_free(*pp); + *pp = 0; + return SQLITE_NOMEM; + } +- p->nSpace = nNew; ++ p->nSpace = (int)nNew; + p->aData = (char *)&p[1]; + } + +@@ -1222,7 +1222,7 @@ int sqlite3Fts3ReadBlock( + int nByte = sqlite3_blob_bytes(p->pSegments); + *pnBlob = nByte; + if( paBlob ){ +- char *aByte = sqlite3_malloc(nByte + FTS3_NODE_PADDING); ++ char *aByte = sqlite3_malloc64((i64)nByte + FTS3_NODE_PADDING); + if( !aByte ){ + rc = SQLITE_NOMEM; + }else{ +@@ -1339,7 +1339,7 @@ static int fts3SegReaderNext( + int nTerm = fts3HashKeysize(pElem); + if( (nTerm+1)>pReader->nTermAlloc ){ + sqlite3_free(pReader->zTerm); +- pReader->zTerm = (char*)sqlite3_malloc((nTerm+1)*2); ++ pReader->zTerm = (char*)sqlite3_malloc64(((i64)nTerm+1)*2); + if( !pReader->zTerm ) return SQLITE_NOMEM; + pReader->nTermAlloc = (nTerm+1)*2; + } +@@ -1347,7 +1347,7 @@ static int fts3SegReaderNext( + pReader->zTerm[nTerm] = '\0'; + pReader->nTerm = nTerm; + +- aCopy = (char*)sqlite3_malloc(nCopy); ++ aCopy = (char*)sqlite3_malloc64(nCopy); + if( !aCopy ) return SQLITE_NOMEM; + memcpy(aCopy, pList->aData, nCopy); + pReader->nNode = pReader->nDoclist = nCopy; +@@ -1634,7 +1634,7 @@ int sqlite3Fts3SegReaderNew( + nExtra = nRoot + FTS3_NODE_PADDING; + } + +- pReader = (Fts3SegReader *)sqlite3_malloc(sizeof(Fts3SegReader) + nExtra); ++ pReader = (Fts3SegReader *)sqlite3_malloc64(sizeof(Fts3SegReader) + nExtra); + if( !pReader ){ + return SQLITE_NOMEM; + } +@@ -1726,7 +1726,7 @@ int sqlite3Fts3SegReaderPending( + if( nElem==nAlloc ){ + Fts3HashElem **aElem2; + nAlloc += 16; +- aElem2 = (Fts3HashElem **)sqlite3_realloc( ++ aElem2 = (Fts3HashElem **)sqlite3_realloc64( + aElem, nAlloc*sizeof(Fts3HashElem *) + ); + if( !aElem2 ){ +@@ -2060,7 +2060,7 @@ static int fts3NodeAddTerm( + ** this is not expected to be a serious problem. + */ + assert( pTree->aData==(char *)&pTree[1] ); +- pTree->aData = (char *)sqlite3_malloc(nReq); ++ pTree->aData = (char *)sqlite3_malloc64(nReq); + if( !pTree->aData ){ + return SQLITE_NOMEM; + } +@@ -2078,7 +2078,7 @@ static int fts3NodeAddTerm( + + if( isCopyTerm ){ + if( pTree->nMalloczMalloc, nTerm*2); ++ char *zNew = sqlite3_realloc64(pTree->zMalloc, (i64)nTerm*2); + if( !zNew ){ + return SQLITE_NOMEM; + } +@@ -2104,7 +2104,7 @@ static int fts3NodeAddTerm( + ** now. Instead, the term is inserted into the parent of pTree. If pTree + ** has no parent, one is created here. + */ +- pNew = (SegmentNode *)sqlite3_malloc(sizeof(SegmentNode) + p->nNodeSize); ++ pNew = (SegmentNode *)sqlite3_malloc64(sizeof(SegmentNode) + p->nNodeSize); + if( !pNew ){ + return SQLITE_NOMEM; + } +@@ -2242,7 +2242,7 @@ static int fts3SegWriterAdd( + ){ + int nPrefix; /* Size of term prefix in bytes */ + int nSuffix; /* Size of term suffix in bytes */ +- int nReq; /* Number of bytes required on leaf page */ ++ i64 nReq; /* Number of bytes required on leaf page */ + int nData; + SegmentWriter *pWriter = *ppWriter; + +@@ -2251,13 +2251,13 @@ static int fts3SegWriterAdd( + sqlite3_stmt *pStmt; + + /* Allocate the SegmentWriter structure */ +- pWriter = (SegmentWriter *)sqlite3_malloc(sizeof(SegmentWriter)); ++ pWriter = (SegmentWriter *)sqlite3_malloc64(sizeof(SegmentWriter)); + if( !pWriter ) return SQLITE_NOMEM; + memset(pWriter, 0, sizeof(SegmentWriter)); + *ppWriter = pWriter; + + /* Allocate a buffer in which to accumulate data */ +- pWriter->aData = (char *)sqlite3_malloc(p->nNodeSize); ++ pWriter->aData = (char *)sqlite3_malloc64(p->nNodeSize); + if( !pWriter->aData ) return SQLITE_NOMEM; + pWriter->nSize = p->nNodeSize; + +@@ -2332,7 +2332,7 @@ static int fts3SegWriterAdd( + ** the buffer to make it large enough. + */ + if( nReq>pWriter->nSize ){ +- char *aNew = sqlite3_realloc(pWriter->aData, nReq); ++ char *aNew = sqlite3_realloc64(pWriter->aData, nReq); + if( !aNew ) return SQLITE_NOMEM; + pWriter->aData = aNew; + pWriter->nSize = nReq; +@@ -2357,7 +2357,7 @@ static int fts3SegWriterAdd( + */ + if( isCopyTerm ){ + if( nTerm>pWriter->nMalloc ){ +- char *zNew = sqlite3_realloc(pWriter->zMalloc, nTerm*2); ++ char *zNew = sqlite3_realloc64(pWriter->zMalloc, (i64)nTerm*2); + if( !zNew ){ + return SQLITE_NOMEM; + } +@@ -2665,12 +2665,12 @@ static void fts3ColumnFilter( + static int fts3MsrBufferData( + Fts3MultiSegReader *pMsr, /* Multi-segment-reader handle */ + char *pList, +- int nList ++ i64 nList + ){ + if( nList>pMsr->nBuffer ){ + char *pNew; + pMsr->nBuffer = nList*2; +- pNew = (char *)sqlite3_realloc(pMsr->aBuffer, pMsr->nBuffer); ++ pNew = (char *)sqlite3_realloc64(pMsr->aBuffer, pMsr->nBuffer); + if( !pNew ) return SQLITE_NOMEM; + pMsr->aBuffer = pNew; + } +@@ -2726,7 +2726,7 @@ int sqlite3Fts3MsrIncrNext( + fts3SegReaderSort(pMsr->apSegment, nMerge, j, xCmp); + + if( nList>0 && fts3SegReaderIsPending(apSegment[0]) ){ +- rc = fts3MsrBufferData(pMsr, pList, nList+1); ++ rc = fts3MsrBufferData(pMsr, pList, (i64)nList+1); + if( rc!=SQLITE_OK ) return rc; + assert( (pMsr->aBuffer[nList] & 0xFE)==0x00 ); + pList = pMsr->aBuffer; +@@ -2863,11 +2863,11 @@ int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr){ + return SQLITE_OK; + } + +-static int fts3GrowSegReaderBuffer(Fts3MultiSegReader *pCsr, int nReq){ ++static int fts3GrowSegReaderBuffer(Fts3MultiSegReader *pCsr, i64 nReq){ + if( nReq>pCsr->nBuffer ){ + char *aNew; + pCsr->nBuffer = nReq*2; +- aNew = sqlite3_realloc(pCsr->aBuffer, pCsr->nBuffer); ++ aNew = sqlite3_realloc64(pCsr->aBuffer, pCsr->nBuffer); + if( !aNew ){ + return SQLITE_NOMEM; + } +@@ -2958,7 +2958,8 @@ int sqlite3Fts3SegReaderStep( + ){ + pCsr->nDoclist = apSegment[0]->nDoclist; + if( fts3SegReaderIsPending(apSegment[0]) ){ +- rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist, pCsr->nDoclist); ++ rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist, ++ (i64)pCsr->nDoclist); + pCsr->aDoclist = pCsr->aBuffer; + }else{ + pCsr->aDoclist = apSegment[0]->aDoclist; +@@ -3011,7 +3012,8 @@ int sqlite3Fts3SegReaderStep( + + nByte = sqlite3Fts3VarintLen(iDelta) + (isRequirePos?nList+1:0); + +- rc = fts3GrowSegReaderBuffer(pCsr, nByte+nDoclist+FTS3_NODE_PADDING); ++ rc = fts3GrowSegReaderBuffer(pCsr, ++ (i64)nByte+nDoclist+FTS3_NODE_PADDING); + if( rc ) return rc; + + if( isFirst ){ +@@ -3037,7 +3039,7 @@ int sqlite3Fts3SegReaderStep( + fts3SegReaderSort(apSegment, nMerge, j, xCmp); + } + if( nDoclist>0 ){ +- rc = fts3GrowSegReaderBuffer(pCsr, nDoclist+FTS3_NODE_PADDING); ++ rc = fts3GrowSegReaderBuffer(pCsr, (i64)nDoclist+FTS3_NODE_PADDING); + if( rc ) return rc; + memset(&pCsr->aBuffer[nDoclist], 0, FTS3_NODE_PADDING); + pCsr->aDoclist = pCsr->aBuffer; +@@ -3750,7 +3752,7 @@ struct NodeReader { + static void blobGrowBuffer(Blob *pBlob, int nMin, int *pRc){ + if( *pRc==SQLITE_OK && nMin>pBlob->nAlloc ){ + int nAlloc = nMin; +- char *a = (char *)sqlite3_realloc(pBlob->a, nAlloc); ++ char *a = (char *)sqlite3_realloc64(pBlob->a, nAlloc); + if( a ){ + pBlob->nAlloc = nAlloc; + pBlob->a = a; +@@ -4544,7 +4546,7 @@ static int fts3RepackSegdirLevel( + if( nIdx>=nAlloc ){ + int *aNew; + nAlloc += 16; +- aNew = sqlite3_realloc(aIdx, nAlloc*sizeof(int)); ++ aNew = sqlite3_realloc64(aIdx, nAlloc*sizeof(int)); + if( !aNew ){ + rc = SQLITE_NOMEM; + break; +@@ -4918,7 +4920,7 @@ int sqlite3Fts3Incrmerge(Fts3Table *p, int nMerge, int nMin){ + + /* Allocate space for the cursor, filter and writer objects */ + const int nAlloc = sizeof(*pCsr) + sizeof(*pFilter) + sizeof(*pWriter); +- pWriter = (IncrmergeWriter *)sqlite3_malloc(nAlloc); ++ pWriter = (IncrmergeWriter *)sqlite3_malloc64(nAlloc); + if( !pWriter ) return SQLITE_NOMEM; + pFilter = (Fts3SegFilter *)&pWriter[1]; + pCsr = (Fts3MultiSegReader *)&pFilter[1]; +@@ -5554,7 +5556,7 @@ int sqlite3Fts3DeferredTokenList( + return SQLITE_OK; + } + +- pRet = (char *)sqlite3_malloc(p->pList->nData); ++ pRet = (char *)sqlite3_malloc64(p->pList->nData); + if( !pRet ) return SQLITE_NOMEM; + + nSkip = sqlite3Fts3GetVarint(p->pList->aData, &dummy); +@@ -5574,7 +5576,7 @@ int sqlite3Fts3DeferToken( + int iCol /* Column that token must appear in (or -1) */ + ){ + Fts3DeferredToken *pDeferred; +- pDeferred = sqlite3_malloc(sizeof(*pDeferred)); ++ pDeferred = sqlite3_malloc64(sizeof(*pDeferred)); + if( !pDeferred ){ + return SQLITE_NOMEM; + } +diff --git a/manifest b/manifest +index 0b6d0669f9997bee8ab46af1de318178c6190f17..6174c1a449288c840d082fdd8bbb60b31b699ced 100644 +--- a/manifest ++++ b/manifest +@@ -85,25 +85,25 @@ F ext/fts3/README.content b9078d0843a094d86af0d48dffbff13c906702b4c3558012e67b9c + F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a + F ext/fts3/README.tokenizers b92bdeb8b46503f0dd301d364efc5ef59ef9fa8e2758b8e742f39fa93a2e422d + F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d +-F ext/fts3/fts3.c 6634a3854e70afa8710ee5e3a7253cd0f0c89d4cce207fcbfe2ead3bad1db7d5 ++F ext/fts3/fts3.c 0724f5a10cb5d6096d0d8b453f4d2284a3fe2896423378355671b98f9a5b7441 + F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe +-F ext/fts3/fts3Int.h dafdc371f9fbab175744b06cfe019d5f040cdfdbd11fea752f5dc28d45b04c05 ++F ext/fts3/fts3Int.h ae2a44b04cddb5fb35cac4ea5f7f819b2894fd258186465777a19f7acfdf84ed + F ext/fts3/fts3_aux.c f0dc9bd98582615b7750218899bd0c729879b6bbf94d1be57ca1833ff49afc6f + F ext/fts3/fts3_expr.c 903bfb9433109fffb10e910d7066c49cbf8eeae316adc93f0499c4da7dfc932a + F ext/fts3/fts3_hash.c 8b6e31bfb0844c27dc6092c2620bdb1fca17ed613072db057d96952c6bdb48b7 + F ext/fts3/fts3_hash.h 39cf6874dc239d6b4e30479b1975fe5b22a3caaf + F ext/fts3/fts3_icu.c 305ce7fb6036484085b5556a9c8e62acdc7763f0f4cdf5fd538212a9f3720116 +-F ext/fts3/fts3_porter.c 3565faf04b626cddf85f03825e86056a4562c009 ++F ext/fts3/fts3_porter.c b5e72d1e11d55905c5997e7e1d6f5a9111f1e83f + F ext/fts3/fts3_snippet.c f9a8149173553113f3c495a503843e30028b5dc3723d0ca798c5ad6142e130e6 + F ext/fts3/fts3_term.c f45a1e7c6ef464abb1231245d123dae12266b69e05cc56e14045b76591ae92d1 + F ext/fts3/fts3_test.c d8d7b2734f894e8a489987447658e374cdd3a3bc8575c401decf1911cb7c6454 + F ext/fts3/fts3_tokenize_vtab.c a95feda3590f3c3e17672fe35b67ea6112471aeea4c07ef7744a6606b66549aa + F ext/fts3/fts3_tokenizer.c 6d8fc150c48238955d5182bf661498db0dd473c8a2a80e00c16994a646fa96e7 + F ext/fts3/fts3_tokenizer.h 64c6ef6c5272c51ebe60fc607a896e84288fcbc3 +-F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004 ++F ext/fts3/fts3_tokenizer1.c 544d90f9991cb3d434d2c1d5acf40c6bf4b9b204 + F ext/fts3/fts3_unicode.c de426ff05c1c2e7bce161cf6b706638419c3a1d9c2667de9cb9dc0458c18e226 + F ext/fts3/fts3_unicode2.c 416eb7e1e81142703520d284b768ca2751d40e31fa912cae24ba74860532bf0f +-F ext/fts3/fts3_write.c 3109c1a232da86474e196cc7db754445a354409f141e08cb11c846cdb17bdf31 ++F ext/fts3/fts3_write.c a306e0c22176515bf89c4d2007d3162f88221a3f471b30ae4cf1f1635f03fbd1 + F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9 + F ext/fts3/tool/fts3cov.sh c331d006359456cf6f8f953e37f2b9c7d568f3863f00bb5f7eb87fea4ac01b73 + F ext/fts3/tool/fts3view.c 413c346399159df81f86c4928b7c4a455caab73bfbc8cd68f950f632e5751674 +@@ -618,7 +618,7 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 + F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c + F src/tokenize.c 6661a9fa660ecbd3ac0df1acd2ec788b3a8122b4316022bcdaf476ea6754a8de + F src/treeview.c a84b57d15e46007d8b1ae249344b3f0b7f3c62def908b98baaa54935a57c8476 +-F src/trigger.c 5fc3cde35cc4de510be68bb2db4dcff0ce0e1625f43e28a0920be9a6f010cd3f ++F src/trigger.c bc61b12589273cd63aa7a1c621fa1f093ca88f3c793b478affb226dec3a3a48a + F src/update.c f875b0d59da5c3055a0b2ac20560e1650229c6787e78de5e9836267b5cbb8359 + F src/upsert.c 8789047a8f0a601ea42fa0256d1ba3190c13746b6ba940fe2d25643a7e991937 + F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 +diff --git a/src/trigger.c b/src/trigger.c +index 5df6b0c0bc8c19d85341cc62a4e8ac35a98e75d7..63e109d784368e5879affc9076c4f40ad6e7212d 100644 +--- a/src/trigger.c ++++ b/src/trigger.c +@@ -354,6 +354,23 @@ void sqlite3FinishTrigger( + Vdbe *v; + char *z; + ++ /* If this is a new CREATE TABLE statement, and if shadow tables ++ ** are read-only, and the trigger makes a change to a shadow table, ++ ** then raise an error - do not allow the trigger to be created. */ ++ if( sqlite3ReadOnlyShadowTables(db) ){ ++ TriggerStep *pStep; ++ for(pStep=pTrig->step_list; pStep; pStep=pStep->pNext){ ++ if( pStep->zTarget!=0 ++ && sqlite3ShadowTableName(db, pStep->zTarget) ++ ){ ++ sqlite3ErrorMsg(pParse, ++ "trigger \"%s\" may not write to shadow table \"%s\"", ++ pTrig->zName, pStep->zTarget); ++ goto triggerfinish_cleanup; ++ } ++ } ++ } ++ + /* Make an entry in the sqlite_schema table */ + v = sqlite3GetVdbe(pParse); + if( v==0 ) goto triggerfinish_cleanup; diff --git a/patches/v8/.patches b/patches/v8/.patches index 0a0969c9d1dba..ce2016ac502ff 100644 --- a/patches/v8/.patches +++ b/patches/v8/.patches @@ -11,3 +11,14 @@ revert_runtime_dhceck_terminating_exception_in_microtasks.patch allow_disabling_of_v8_sandboxed_pointers.patch chore_disable_is_execution_terminating_dcheck.patch ext-code-space_fix_coderange_allocation_logic.patch +cherry-pick-8b040cb69e96.patch +cherry-pick-2f6a2939514f.patch +cherry-pick-194bcc127f21.patch +cherry-pick-ec236fef54b8.patch +cherry-pick-80ed4b917477.patch +cherry-pick-2ac0620a5bbb.patch +cherry-pick-177e8bcd3584.patch +cherry-pick-27fa951ae4a3.patch +cherry-pick-c79148742421.patch +cherry-pick-0f481c9ddf2a.patch +cherry-pick-28b9c1c04e78.patch diff --git a/patches/v8/cherry-pick-0f481c9ddf2a.patch b/patches/v8/cherry-pick-0f481c9ddf2a.patch new file mode 100644 index 0000000000000..34a3cb9dee77d --- /dev/null +++ b/patches/v8/cherry-pick-0f481c9ddf2a.patch @@ -0,0 +1,69 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Clemens Backes +Date: Thu, 15 Dec 2022 11:58:50 +0100 +Subject: Merged: [wasm][turbofan] Load 32-bit values more efficiently + +When loading a 32-bit value from the stack, just load 32 bit and +zero-extend them into the target register, instead of loading the full +64 bits. + +As there are things to fix (see https://crbug.com/1356461), we only +enable this optimization for Wasm for now. + +Also include the related fix https://crrev.com/c/4096985. + +R=mslekova@chromium.org + +(cherry picked from commit 2ee52447c878721c89a55a780eb689ecba6817d3) +(cherry picked from commit a38209949fcbf045231c316e2d790b8b70ccb7ef) + +Bug: chromium:1395604 +Change-Id: I54a2182ada6fadbfcf5565f0dc8d4f477ecff393 +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4110897 +Reviewed-by: Maya Lekova +Commit-Queue: Clemens Backes +Cr-Commit-Position: refs/branch-heads/10.8@{#46} +Cr-Branched-From: f1bc03fd6b4c201abd9f0fd9d51fb989150f97b9-refs/heads/10.8.168@{#1} +Cr-Branched-From: 237de893e1c0a0628a57d0f5797483d3add7f005-refs/heads/main@{#83672} + +diff --git a/src/compiler/backend/x64/code-generator-x64.cc b/src/compiler/backend/x64/code-generator-x64.cc +index 9fd4635d8911716019bf0116123b85a408e247ca..86e017936bab415c003476844cb981e8ad5d1e56 100644 +--- a/src/compiler/backend/x64/code-generator-x64.cc ++++ b/src/compiler/backend/x64/code-generator-x64.cc +@@ -5119,7 +5119,22 @@ void CodeGenerator::AssembleMove(InstructionOperand* source, + case MoveType::kStackToRegister: { + Operand src = g.ToOperand(source); + if (source->IsStackSlot()) { +- __ movq(g.ToRegister(destination), src); ++ MachineRepresentation mr = ++ LocationOperand::cast(source)->representation(); ++ const bool is_32_bit = mr == MachineRepresentation::kWord32 || ++ mr == MachineRepresentation::kCompressed || ++ mr == MachineRepresentation::kCompressedPointer; ++ // TODO(13581): Fix this for other code kinds (see ++ // https://crbug.com/1356461). ++ if (code_kind() == CodeKind::WASM_FUNCTION && is_32_bit) { ++ // When we need only 32 bits, move only 32 bits. Benefits: ++ // - Save a byte here and there (depending on the destination ++ // register; "movl eax, ..." is smaller than "movq rax, ..."). ++ // - Safeguard against accidental decompression of compressed slots. ++ __ movl(g.ToRegister(destination), src); ++ } else { ++ __ movq(g.ToRegister(destination), src); ++ } + } else { + DCHECK(source->IsFPStackSlot()); + XMMRegister dst = g.ToDoubleRegister(destination); +diff --git a/src/wasm/graph-builder-interface.cc b/src/wasm/graph-builder-interface.cc +index 3d899eded2d744731f2acfadce6f4d55b1417c4d..a9587d7548495dfdb0a6cf43ab22a3d06d1a76e7 100644 +--- a/src/wasm/graph-builder-interface.cc ++++ b/src/wasm/graph-builder-interface.cc +@@ -2061,7 +2061,7 @@ class WasmGraphBuildingInterface { + if (exception_value != nullptr) { + // TODO(manoskouk): Can we assign a wasm type to the exception value? + *exception_value = builder_->LoopExitValue( +- *exception_value, MachineRepresentation::kWord32); ++ *exception_value, MachineRepresentation::kTaggedPointer); + } + if (wrap_exit_values) { + WrapLocalsAtLoopExit(decoder, control); diff --git a/patches/v8/cherry-pick-177e8bcd3584.patch b/patches/v8/cherry-pick-177e8bcd3584.patch new file mode 100644 index 0000000000000..c3f27d07290de --- /dev/null +++ b/patches/v8/cherry-pick-177e8bcd3584.patch @@ -0,0 +1,144 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darius M +Date: Mon, 7 Nov 2022 08:40:11 +0100 +Subject: Merged: [compiler] fix bug in inlining of Array.At + +The inlined version of Array.At was only checking the kind of the +maps, rather than the maps themselves. When the feedback was +containing an array map that "supports_fast_array_iteration", then its +kind was added to the list of supported kinds. If this Array.at was +later called with a non-array map with the same kind, then the object +would be wrongly treated as an array. + +This is now fixed: inlining Array.at checks the maps directly rather +than only their kinds. + +Bug: chromium:1377775 +(cherry picked from commit 0ce27310674150b46605c1e226b8f1a2503bac8c) + +Change-Id: I2398f2f7a1ea37808962ba5eb3d1fe00a54fd614 +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3990747 +Commit-Queue: Darius Mercadier +Reviewed-by: Tobias Tebbi +Cr-Commit-Position: refs/branch-heads/10.6@{#49} +Cr-Branched-From: 41bc7435693fbce8ef86753cd9239e30550a3e2d-refs/heads/10.6.194@{#1} +Cr-Branched-From: d5f29b929ce7746409201d77f44048f3e9529b40-refs/heads/main@{#82548} + +diff --git a/src/compiler/js-call-reducer.cc b/src/compiler/js-call-reducer.cc +index 65d3dfe1db8e690a949f6ea3140dda4813a0b0d5..10f3301e3a10d215d731e8bd7d2ec67537d66989 100644 +--- a/src/compiler/js-call-reducer.cc ++++ b/src/compiler/js-call-reducer.cc +@@ -719,9 +719,8 @@ class IteratingArrayBuiltinReducerAssembler : public JSCallReducerAssembler { + MapInference* inference, const bool has_stability_dependency, + ElementsKind kind, const SharedFunctionInfoRef& shared, + const NativeContextRef& native_context, ArrayEverySomeVariant variant); +- TNode ReduceArrayPrototypeAt(ZoneVector kinds, +- bool needs_fallback_builtin_call, +- Node* receiver_kind); ++ TNode ReduceArrayPrototypeAt(ZoneVector kinds, ++ bool needs_fallback_builtin_call); + TNode ReduceArrayPrototypeIndexOfIncludes( + ElementsKind kind, ArrayIndexOfIncludesVariant variant); + +@@ -1331,24 +1330,26 @@ TNode JSCallReducerAssembler::ReduceStringPrototypeSlice() { + } + + TNode IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeAt( +- ZoneVector kinds, bool needs_fallback_builtin_call, +- Node* receiver_kind) { ++ ZoneVector maps, bool needs_fallback_builtin_call) { + TNode receiver = ReceiverInputAs(); + TNode index = ArgumentOrZero(0); + + TNode index_num = CheckSmi(index); + TNode elements = LoadElements(receiver); + ++ TNode receiver_map = ++ TNode::UncheckedCast(LoadField(AccessBuilder::ForMap(), receiver)); ++ + auto out = MakeLabel(MachineRepresentation::kTagged); + +- for (ElementsKind kind : kinds) { ++ for (const MapRef* map : maps) { ++ DCHECK(map->supports_fast_array_iteration()); + auto correct_map_label = MakeLabel(), wrong_map_label = MakeLabel(); +- Branch(NumberEqual(TNode::UncheckedCast(receiver_kind), +- NumberConstant(kind)), +- &correct_map_label, &wrong_map_label); ++ TNode is_map_equal = ReferenceEqual(receiver_map, Constant(*map)); ++ Branch(is_map_equal, &correct_map_label, &wrong_map_label); + Bind(&correct_map_label); + +- TNode length = LoadJSArrayLength(receiver, kind); ++ TNode length = LoadJSArrayLength(receiver, map->elements_kind()); + + // If index is less than 0, then subtract from length. + TNode cond = NumberLessThan(index_num, ZeroConstant()); +@@ -1367,15 +1368,16 @@ TNode IteratingArrayBuiltinReducerAssembler::ReduceArrayPrototypeAt( + + // Retrieving element at index. + TNode element = LoadElement( +- AccessBuilder::ForFixedArrayElement(kind), elements, real_index_num); +- if (IsHoleyElementsKind(kind)) { ++ AccessBuilder::ForFixedArrayElement(map->elements_kind()), elements, ++ real_index_num); ++ if (IsHoleyElementsKind(map->elements_kind())) { + // This case is needed in particular for HOLEY_DOUBLE_ELEMENTS: raw + // doubles are stored in the FixedDoubleArray, and need to be converted to + // HeapNumber or to Smi so that this function can return an Object. The + // automatic converstion performed by + // RepresentationChanger::GetTaggedRepresentationFor does not handle + // holes, so we convert manually a potential hole here. +- element = TryConvertHoleToUndefined(element, kind); ++ element = TryConvertHoleToUndefined(element, map->elements_kind()); + } + Goto(&out, element); + +@@ -5639,25 +5641,22 @@ Reduction JSCallReducer::ReduceArrayPrototypeAt(Node* node) { + MapInference inference(broker(), receiver, effect); + if (!inference.HaveMaps()) return NoChange(); + +- // Collecting kinds +- ZoneVector kinds(broker()->zone()); ++ // Collecting maps, and checking if a fallback builtin call will be required ++ // (it is required if at least one map doesn't support fast array iteration). ++ ZoneVector maps(broker()->zone()); + bool needs_fallback_builtin_call = false; + for (const MapRef& map : inference.GetMaps()) { + if (map.supports_fast_array_iteration()) { +- ElementsKind kind = map.elements_kind(); +- // Checking that |kind| isn't already in |kinds|. Using std::find should +- // be fast enough since |kinds| can contain at most 4 items. +- if (std::find(kinds.begin(), kinds.end(), kind) == kinds.end()) { +- kinds.push_back(kind); +- } ++ maps.push_back(&map); + } else { + needs_fallback_builtin_call = true; + } + } ++ + inference.RelyOnMapsPreferStability(dependencies(), jsgraph(), &effect, + control, p.feedback()); + +- if (kinds.empty()) { ++ if (maps.empty()) { + // No map in the feedback supports fast iteration. Keeping the builtin call. + return NoChange(); + } +@@ -5666,13 +5665,11 @@ Reduction JSCallReducer::ReduceArrayPrototypeAt(Node* node) { + return NoChange(); + } + +- Node* receiver_kind = LoadReceiverElementsKind(receiver, &effect, control); +- + IteratingArrayBuiltinReducerAssembler a(this, node); + a.InitializeEffectControl(effect, control); + +- TNode subgraph = a.ReduceArrayPrototypeAt( +- kinds, needs_fallback_builtin_call, receiver_kind); ++ TNode subgraph = ++ a.ReduceArrayPrototypeAt(maps, needs_fallback_builtin_call); + return ReplaceWithSubgraph(&a, subgraph); + } + diff --git a/patches/v8/cherry-pick-194bcc127f21.patch b/patches/v8/cherry-pick-194bcc127f21.patch new file mode 100644 index 0000000000000..79692e97d5433 --- /dev/null +++ b/patches/v8/cherry-pick-194bcc127f21.patch @@ -0,0 +1,135 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Tobias Tebbi +Date: Thu, 6 Oct 2022 13:43:19 +0200 +Subject: Merged: [turbofan] validate more concurrent reads + +Bug: chromium:1369871 +(cherry picked from commit ebe5675360e4735589a92a8836303822da79a8f4) + +Change-Id: I49243d2c604cb4635d0d49a572245f7469eabffa +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3952937 +Reviewed-by: Nico Hartmann +Commit-Queue: Tobias Tebbi +Cr-Commit-Position: refs/branch-heads/10.6@{#41} +Cr-Branched-From: 41bc7435693fbce8ef86753cd9239e30550a3e2d-refs/heads/10.6.194@{#1} +Cr-Branched-From: d5f29b929ce7746409201d77f44048f3e9529b40-refs/heads/main@{#82548} + +diff --git a/src/compiler/compilation-dependencies.cc b/src/compiler/compilation-dependencies.cc +index 4fb04ae2bd8960deb7e978641d3cf75297f72bda..45aea59373067d1f0fe63d2fcc7059b788c8277b 100644 +--- a/src/compiler/compilation-dependencies.cc ++++ b/src/compiler/compilation-dependencies.cc +@@ -35,7 +35,8 @@ namespace compiler { + V(Protector) \ + V(PrototypeProperty) \ + V(StableMap) \ +- V(Transition) ++ V(Transition) \ ++ V(ObjectSlotValue) + + CompilationDependencies::CompilationDependencies(JSHeapBroker* broker, + Zone* zone) +@@ -863,6 +864,42 @@ class ProtectorDependency final : public CompilationDependency { + const PropertyCellRef cell_; + }; + ++// Check that an object slot will not change during compilation. ++class ObjectSlotValueDependency final : public CompilationDependency { ++ public: ++ explicit ObjectSlotValueDependency(const HeapObjectRef& object, int offset, ++ const ObjectRef& value) ++ : CompilationDependency(kObjectSlotValue), ++ object_(object.object()), ++ offset_(offset), ++ value_(value.object()) {} ++ ++ bool IsValid() const override { ++ PtrComprCageBase cage_base = GetPtrComprCageBase(*object_); ++ Object current_value = ++ offset_ == HeapObject::kMapOffset ++ ? object_->map() ++ : TaggedField::Relaxed_Load(cage_base, *object_, offset_); ++ return *value_ == current_value; ++ } ++ void Install(PendingDependencies* deps) const override {} ++ ++ private: ++ size_t Hash() const override { ++ return base::hash_combine(object_.address(), offset_, value_.address()); ++ } ++ ++ bool Equals(const CompilationDependency* that) const override { ++ const ObjectSlotValueDependency* const zat = that->AsObjectSlotValue(); ++ return object_->address() == zat->object_->address() && ++ offset_ == zat->offset_ && value_.address() == zat->value_.address(); ++ } ++ ++ Handle object_; ++ int offset_; ++ Handle value_; ++}; ++ + class ElementsKindDependency final : public CompilationDependency { + public: + ElementsKindDependency(const AllocationSiteRef& site, ElementsKind kind) +@@ -1115,6 +1152,12 @@ void CompilationDependencies::DependOnElementsKind( + } + } + ++void CompilationDependencies::DependOnObjectSlotValue( ++ const HeapObjectRef& object, int offset, const ObjectRef& value) { ++ RecordDependency( ++ zone_->New(object, offset, value)); ++} ++ + void CompilationDependencies::DependOnOwnConstantElement( + const JSObjectRef& holder, uint32_t index, const ObjectRef& element) { + RecordDependency( +diff --git a/src/compiler/compilation-dependencies.h b/src/compiler/compilation-dependencies.h +index 72ee5773abfcf344e3964d58ea855461ca1ca79d..e0f4eca359b2f7cdca326702d0181b83d3dc322c 100644 +--- a/src/compiler/compilation-dependencies.h ++++ b/src/compiler/compilation-dependencies.h +@@ -94,6 +94,10 @@ class V8_EXPORT_PRIVATE CompilationDependencies : public ZoneObject { + // Record the assumption that {site}'s {ElementsKind} doesn't change. + void DependOnElementsKind(const AllocationSiteRef& site); + ++ // Check that an object slot will not change during compilation. ++ void DependOnObjectSlotValue(const HeapObjectRef& object, int offset, ++ const ObjectRef& value); ++ + void DependOnOwnConstantElement(const JSObjectRef& holder, uint32_t index, + const ObjectRef& element); + +diff --git a/src/compiler/js-create-lowering.cc b/src/compiler/js-create-lowering.cc +index 1b4755e2db290701740cbcbaf6fcab2154c68132..241186706d9388fe6127c5cf1d1e6befecf229f7 100644 +--- a/src/compiler/js-create-lowering.cc ++++ b/src/compiler/js-create-lowering.cc +@@ -1677,6 +1677,10 @@ base::Optional JSCreateLowering::TryAllocateFastLiteral( + + // Now that we hold the migration lock, get the current map. + MapRef boilerplate_map = boilerplate.map(); ++ // Protect against concurrent changes to the boilerplate object by checking ++ // for an identical value at the end of the compilation. ++ dependencies()->DependOnObjectSlotValue(boilerplate, HeapObject::kMapOffset, ++ boilerplate_map); + { + base::Optional current_boilerplate_map = + boilerplate.map_direct_read(); +@@ -1841,10 +1845,18 @@ base::Optional JSCreateLowering::TryAllocateFastLiteralElements( + boilerplate.elements(kRelaxedLoad); + if (!maybe_boilerplate_elements.has_value()) return {}; + FixedArrayBaseRef boilerplate_elements = maybe_boilerplate_elements.value(); ++ // Protect against concurrent changes to the boilerplate object by checking ++ // for an identical value at the end of the compilation. ++ dependencies()->DependOnObjectSlotValue( ++ boilerplate, JSObject::kElementsOffset, boilerplate_elements); + + // Empty or copy-on-write elements just store a constant. + int const elements_length = boilerplate_elements.length(); + MapRef elements_map = boilerplate_elements.map(); ++ // Protect against concurrent changes to the boilerplate object by checking ++ // for an identical value at the end of the compilation. ++ dependencies()->DependOnObjectSlotValue(boilerplate_elements, ++ HeapObject::kMapOffset, elements_map); + if (boilerplate_elements.length() == 0 || elements_map.IsFixedCowArrayMap()) { + if (allocation == AllocationType::kOld && + !boilerplate.IsElementsTenured(boilerplate_elements)) { diff --git a/patches/v8/cherry-pick-27fa951ae4a3.patch b/patches/v8/cherry-pick-27fa951ae4a3.patch new file mode 100644 index 0000000000000..f409bf77d7c7c --- /dev/null +++ b/patches/v8/cherry-pick-27fa951ae4a3.patch @@ -0,0 +1,209 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Toon Verwaest +Date: Wed, 30 Nov 2022 15:07:26 +0100 +Subject: Fix eval tracking + +Due to mismatch in strictness we otherwise invalidly mark scopes as +calling sloppy eval. + +Bug: chromium:1394403 +Change-Id: Iece45df87f171616a2917c2aba5540636880a7c6 +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4066044 +Reviewed-by: Igor Sheludko +Commit-Queue: Toon Verwaest +Cr-Commit-Position: refs/heads/main@{#84575} + +diff --git a/src/ast/scopes.cc b/src/ast/scopes.cc +index 679472c7c62916727735cbbcd7c6caf1fa7ae8bb..54709de5b747f0c6f450943e110c4f82b97c29ca 100644 +--- a/src/ast/scopes.cc ++++ b/src/ast/scopes.cc +@@ -888,9 +888,8 @@ void DeclarationScope::AddLocal(Variable* var) { + } + + void Scope::Snapshot::Reparent(DeclarationScope* new_parent) { +- DCHECK(!IsCleared()); +- DCHECK_EQ(new_parent, outer_scope_and_calls_eval_.GetPointer()->inner_scope_); +- DCHECK_EQ(new_parent->outer_scope_, outer_scope_and_calls_eval_.GetPointer()); ++ DCHECK_EQ(new_parent, outer_scope_->inner_scope_); ++ DCHECK_EQ(new_parent->outer_scope_, outer_scope_); + DCHECK_EQ(new_parent, new_parent->GetClosureScope()); + DCHECK_NULL(new_parent->inner_scope_); + DCHECK(new_parent->unresolved_list_.is_empty()); +@@ -915,12 +914,11 @@ void Scope::Snapshot::Reparent(DeclarationScope* new_parent) { + new_parent->sibling_ = top_inner_scope_; + } + +- Scope* outer_scope = outer_scope_and_calls_eval_.GetPointer(); +- new_parent->unresolved_list_.MoveTail(&outer_scope->unresolved_list_, ++ new_parent->unresolved_list_.MoveTail(&outer_scope_->unresolved_list_, + top_unresolved_); + + // Move temporaries allocated for complex parameter initializers. +- DeclarationScope* outer_closure = outer_scope->GetClosureScope(); ++ DeclarationScope* outer_closure = outer_scope_->GetClosureScope(); + for (auto it = top_local_; it != outer_closure->locals()->end(); ++it) { + Variable* local = *it; + DCHECK_EQ(VariableMode::kTemporary, local->mode()); +@@ -932,16 +930,10 @@ void Scope::Snapshot::Reparent(DeclarationScope* new_parent) { + outer_closure->locals_.Rewind(top_local_); + + // Move eval calls since Snapshot's creation into new_parent. +- if (outer_scope_and_calls_eval_->calls_eval_) { +- new_parent->RecordDeclarationScopeEvalCall(); +- new_parent->inner_scope_calls_eval_ = true; ++ if (outer_scope_->calls_eval_) { ++ new_parent->RecordEvalCall(); ++ declaration_scope_->sloppy_eval_can_extend_vars_ = false; + } +- +- // We are in the arrow function case. The calls eval we may have recorded +- // is intended for the inner scope and we should simply restore the +- // original "calls eval" flag of the outer scope. +- RestoreEvalFlag(); +- Clear(); + } + + void Scope::ReplaceOuterScope(Scope* outer) { +@@ -2579,6 +2571,9 @@ void Scope::AllocateVariablesRecursively() { + this->ForEach([](Scope* scope) -> Iteration { + DCHECK(!scope->already_resolved_); + if (WasLazilyParsed(scope)) return Iteration::kContinue; ++ if (scope->sloppy_eval_can_extend_vars_) { ++ scope->num_heap_slots_ = Context::MIN_CONTEXT_EXTENDED_SLOTS; ++ } + DCHECK_EQ(scope->ContextHeaderLength(), scope->num_heap_slots_); + + // Allocate variables for this scope. +diff --git a/src/ast/scopes.h b/src/ast/scopes.h +index 9f4970931454e78468eba7bc2cf01289fa598289..29e329833f247d901e20fb227ceedbdd2ee4127a 100644 +--- a/src/ast/scopes.h ++++ b/src/ast/scopes.h +@@ -112,12 +112,6 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { + + class Snapshot final { + public: +- Snapshot() +- : outer_scope_and_calls_eval_(nullptr, false), +- top_unresolved_(), +- top_local_() { +- DCHECK(IsCleared()); +- } + inline explicit Snapshot(Scope* scope); + + // Disallow copy and move. +@@ -125,45 +119,31 @@ class V8_EXPORT_PRIVATE Scope : public NON_EXPORTED_BASE(ZoneObject) { + Snapshot(Snapshot&&) = delete; + + ~Snapshot() { +- // If we're still active, there was no arrow function. In that case outer +- // calls eval if it already called eval before this snapshot started, or +- // if the code during the snapshot called eval. +- if (!IsCleared() && outer_scope_and_calls_eval_.GetPayload()) { +- RestoreEvalFlag(); ++ // Restore eval flags from before the scope was active. ++ if (sloppy_eval_can_extend_vars_) { ++ declaration_scope_->sloppy_eval_can_extend_vars_ = true; + } +- } +- +- void RestoreEvalFlag() { +- if (outer_scope_and_calls_eval_.GetPayload()) { +- // This recreates both calls_eval and sloppy_eval_can_extend_vars. +- outer_scope_and_calls_eval_.GetPointer()->RecordEvalCall(); ++ if (calls_eval_) { ++ outer_scope_->calls_eval_ = true; + } + } + + void Reparent(DeclarationScope* new_parent); +- bool IsCleared() const { +- return outer_scope_and_calls_eval_.GetPointer() == nullptr; +- } +- +- void Clear() { +- outer_scope_and_calls_eval_.SetPointer(nullptr); +-#ifdef DEBUG +- outer_scope_and_calls_eval_.SetPayload(false); +- top_inner_scope_ = nullptr; +- top_local_ = base::ThreadedList::Iterator(); +- top_unresolved_ = UnresolvedList::Iterator(); +-#endif +- } + + private: +- // During tracking calls_eval caches whether the outer scope called eval. +- // Upon move assignment we store whether the new inner scope calls eval into +- // the move target calls_eval bit, and restore calls eval on the outer +- // scope. +- base::PointerWithPayload outer_scope_and_calls_eval_; ++ Scope* outer_scope_; ++ Scope* declaration_scope_; + Scope* top_inner_scope_; + UnresolvedList::Iterator top_unresolved_; + base::ThreadedList::Iterator top_local_; ++ // While the scope is active, the scope caches the flag values for ++ // outer_scope_ / declaration_scope_ they can be used to know what happened ++ // while parsing the arrow head. If this turns out to be an arrow head, new ++ // values on the respective scopes will be cleared and moved to the inner ++ // scope. Otherwise the cached flags will be merged with the flags from the ++ // arrow head. ++ bool calls_eval_; ++ bool sloppy_eval_can_extend_vars_; + }; + + enum class DeserializationMode { kIncludingVariables, kScopesOnly }; +@@ -909,8 +889,8 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { + void RecordDeclarationScopeEvalCall() { + calls_eval_ = true; + +- // If this isn't a sloppy eval, we don't care about it. +- if (language_mode() != LanguageMode::kSloppy) return; ++ // The caller already checked whether we're in sloppy mode. ++ CHECK(is_sloppy(language_mode())); + + // Sloppy eval in script scopes can only introduce global variables anyway, + // so we don't care that it calls sloppy eval. +@@ -944,7 +924,6 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { + } + + sloppy_eval_can_extend_vars_ = true; +- num_heap_slots_ = Context::MIN_CONTEXT_EXTENDED_SLOTS; + } + + bool sloppy_eval_can_extend_vars() const { +@@ -1369,7 +1348,9 @@ class V8_EXPORT_PRIVATE DeclarationScope : public Scope { + + void Scope::RecordEvalCall() { + calls_eval_ = true; +- GetDeclarationScope()->RecordDeclarationScopeEvalCall(); ++ if (is_sloppy(language_mode())) { ++ GetDeclarationScope()->RecordDeclarationScopeEvalCall(); ++ } + RecordInnerScopeEvalCall(); + // The eval contents might access "super" (if it's inside a function that + // binds super). +@@ -1382,14 +1363,18 @@ void Scope::RecordEvalCall() { + } + + Scope::Snapshot::Snapshot(Scope* scope) +- : outer_scope_and_calls_eval_(scope, scope->calls_eval_), ++ : outer_scope_(scope), ++ declaration_scope_(scope->GetDeclarationScope()), + top_inner_scope_(scope->inner_scope_), + top_unresolved_(scope->unresolved_list_.end()), +- top_local_(scope->GetClosureScope()->locals_.end()) { +- // Reset in order to record eval calls during this Snapshot's lifetime. +- outer_scope_and_calls_eval_.GetPointer()->calls_eval_ = false; +- outer_scope_and_calls_eval_.GetPointer()->sloppy_eval_can_extend_vars_ = +- false; ++ top_local_(scope->GetClosureScope()->locals_.end()), ++ calls_eval_(outer_scope_->calls_eval_), ++ sloppy_eval_can_extend_vars_( ++ declaration_scope_->sloppy_eval_can_extend_vars_) { ++ // Reset in order to record (sloppy) eval calls during this Snapshot's ++ // lifetime. ++ outer_scope_->calls_eval_ = false; ++ declaration_scope_->sloppy_eval_can_extend_vars_ = false; + } + + class ModuleScope final : public DeclarationScope { diff --git a/patches/v8/cherry-pick-28b9c1c04e78.patch b/patches/v8/cherry-pick-28b9c1c04e78.patch new file mode 100644 index 0000000000000..4bdc55ec12909 --- /dev/null +++ b/patches/v8/cherry-pick-28b9c1c04e78.patch @@ -0,0 +1,77 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Clemens Backes +Date: Tue, 13 Dec 2022 22:37:27 +0100 +Subject: Merged: [arm] Do not emit the constant pool before a branch + +After computing the branch offset but before emitting the actual branch, +we should not emit a constant pool. Otherwise the previously computed +offset would be off. + +Instead of handling this indirectly via the Assembler::branch_offset +method, do this directly in the Assembler::b method (and friends), so it +is not missed on other call sites. + +R=nicohartmann@chromium.org + +(cherry picked from commit 9be597d194e108ba718610b9a611fe19a0fbfde5) +Bug: chromium:1399424 + +Change-Id: Ie30ba70508b4fb8913f79e049a33108608915704 +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4118864 +Reviewed-by: Nico Hartmann +Commit-Queue: Clemens Backes +Cr-Commit-Position: refs/branch-heads/10.8@{#48} +Cr-Branched-From: f1bc03fd6b4c201abd9f0fd9d51fb989150f97b9-refs/heads/10.8.168@{#1} +Cr-Branched-From: 237de893e1c0a0628a57d0f5797483d3add7f005-refs/heads/main@{#83672} + +diff --git a/src/codegen/arm/assembler-arm.cc b/src/codegen/arm/assembler-arm.cc +index 645edb17a4892aec70f0221cec889996a6868242..a95d4df308fd4651093a4911ad1c50226e059ebb 100644 +--- a/src/codegen/arm/assembler-arm.cc ++++ b/src/codegen/arm/assembler-arm.cc +@@ -1462,10 +1462,6 @@ int Assembler::branch_offset(Label* L) { + L->link_to(pc_offset()); + } + +- // Block the emission of the constant pool, since the branch instruction must +- // be emitted at the pc offset recorded by the label. +- if (!is_const_pool_blocked()) BlockConstPoolFor(1); +- + return target_pos - (pc_offset() + Instruction::kPcLoadDelta); + } + +@@ -1476,6 +1472,11 @@ void Assembler::b(int branch_offset, Condition cond, RelocInfo::Mode rmode) { + int imm24 = branch_offset >> 2; + const bool b_imm_check = is_int24(imm24); + CHECK(b_imm_check); ++ ++ // Block the emission of the constant pool before the next instruction. ++ // Otherwise the passed-in branch offset would be off. ++ BlockConstPoolFor(1); ++ + emit(cond | B27 | B25 | (imm24 & kImm24Mask)); + + if (cond == al) { +@@ -1490,6 +1491,11 @@ void Assembler::bl(int branch_offset, Condition cond, RelocInfo::Mode rmode) { + int imm24 = branch_offset >> 2; + const bool bl_imm_check = is_int24(imm24); + CHECK(bl_imm_check); ++ ++ // Block the emission of the constant pool before the next instruction. ++ // Otherwise the passed-in branch offset would be off. ++ BlockConstPoolFor(1); ++ + emit(cond | B27 | B25 | B24 | (imm24 & kImm24Mask)); + } + +@@ -1499,6 +1505,11 @@ void Assembler::blx(int branch_offset) { + int imm24 = branch_offset >> 2; + const bool blx_imm_check = is_int24(imm24); + CHECK(blx_imm_check); ++ ++ // Block the emission of the constant pool before the next instruction. ++ // Otherwise the passed-in branch offset would be off. ++ BlockConstPoolFor(1); ++ + emit(kSpecialCondition | B27 | B25 | h | (imm24 & kImm24Mask)); + } + diff --git a/patches/v8/cherry-pick-2ac0620a5bbb.patch b/patches/v8/cherry-pick-2ac0620a5bbb.patch new file mode 100644 index 0000000000000..b6e8edf150da2 --- /dev/null +++ b/patches/v8/cherry-pick-2ac0620a5bbb.patch @@ -0,0 +1,49 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Thibaud Michaud +Date: Wed, 26 Oct 2022 17:03:36 +0200 +Subject: Merged: [wasm] Reload cached instance fields in catch handler + +Bug: chromium:1377816 +(cherry picked from commit f517e518af26b7eac23c9e328b463eb1e8ee3499) + +Change-Id: I993bcff0389a1ba134e89e8ac5299d742ddd150c +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3999134 +Commit-Queue: Thibaud Michaud +Reviewed-by: Jakob Kummerow +Cr-Commit-Position: refs/branch-heads/10.6@{#47} +Cr-Branched-From: 41bc7435693fbce8ef86753cd9239e30550a3e2d-refs/heads/10.6.194@{#1} +Cr-Branched-From: d5f29b929ce7746409201d77f44048f3e9529b40-refs/heads/main@{#82548} + +diff --git a/src/wasm/graph-builder-interface.cc b/src/wasm/graph-builder-interface.cc +index 5b3256fe6d1c431adf4c10c84dfa9340d4e99754..3d899eded2d744731f2acfadce6f4d55b1417c4d 100644 +--- a/src/wasm/graph-builder-interface.cc ++++ b/src/wasm/graph-builder-interface.cc +@@ -91,6 +91,7 @@ class WasmGraphBuildingInterface { + struct TryInfo : public ZoneObject { + SsaEnv* catch_env; + TFNode* exception = nullptr; ++ bool first_catch = true; + + bool might_throw() const { return exception != nullptr; } + +@@ -937,6 +938,10 @@ class WasmGraphBuildingInterface { + + TFNode* exception = block->try_info->exception; + SetEnv(block->try_info->catch_env); ++ if (block->try_info->first_catch) { ++ LoadContextIntoSsa(ssa_env_, decoder); ++ block->try_info->first_catch = false; ++ } + + TFNode* if_catch = nullptr; + TFNode* if_no_catch = nullptr; +@@ -1014,6 +1019,9 @@ class WasmGraphBuildingInterface { + } + + SetEnv(block->try_info->catch_env); ++ if (block->try_info->first_catch) { ++ LoadContextIntoSsa(ssa_env_, decoder); ++ } + } + + void AtomicOp(FullDecoder* decoder, WasmOpcode opcode, diff --git a/patches/v8/cherry-pick-2f6a2939514f.patch b/patches/v8/cherry-pick-2f6a2939514f.patch new file mode 100644 index 0000000000000..0111fce53dee9 --- /dev/null +++ b/patches/v8/cherry-pick-2f6a2939514f.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Tobias Tebbi +Date: Thu, 1 Sep 2022 15:35:33 +0200 +Subject: Merged: [compiler] fix typing of [[DateValue]] + +Bug: chromium:1356308 +(cherry picked from commit ae329407989f1e4689baba7a7827863057d688a9) + +Change-Id: I1e132e96325296d180488774ef183daa36dc22c7 +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3915224 +Reviewed-by: Darius Mercadier +Cr-Commit-Position: refs/branch-heads/10.6@{#25} +Cr-Branched-From: 41bc7435693fbce8ef86753cd9239e30550a3e2d-refs/heads/10.6.194@{#1} +Cr-Branched-From: d5f29b929ce7746409201d77f44048f3e9529b40-refs/heads/main@{#82548} + +diff --git a/src/compiler/type-cache.h b/src/compiler/type-cache.h +index 6442b6f6b0ee39bf1a820168e9dd924e81bc0cb3..a34d094edaa4cb7dd7ac692e4a11d7c890744d7c 100644 +--- a/src/compiler/type-cache.h ++++ b/src/compiler/type-cache.h +@@ -131,9 +131,10 @@ class V8_EXPORT_PRIVATE TypeCache final { + Type const kStringLengthType = CreateRange(0.0, String::kMaxLength); + + // A time value always contains a tagged number in the range +- // [-kMaxTimeInMs, kMaxTimeInMs]. +- Type const kTimeValueType = +- CreateRange(-DateCache::kMaxTimeInMs, DateCache::kMaxTimeInMs); ++ // [-kMaxTimeInMs, kMaxTimeInMs] or -0. ++ Type const kTimeValueType = Type::Union( ++ CreateRange(-DateCache::kMaxTimeInMs, DateCache::kMaxTimeInMs), ++ Type::MinusZero(), zone()); + + // The JSDate::day property always contains a tagged number in the range + // [1, 31] or NaN. diff --git a/patches/v8/cherry-pick-80ed4b917477.patch b/patches/v8/cherry-pick-80ed4b917477.patch new file mode 100644 index 0000000000000..78b317120ed1e --- /dev/null +++ b/patches/v8/cherry-pick-80ed4b917477.patch @@ -0,0 +1,111 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Maya Lekova +Date: Wed, 2 Nov 2022 11:02:24 +0100 +Subject: Merged: [compiler] Fix mutable heap number object reference leak + +(cherry picked from commit 64112122374c00a86771b4612d20ca5d88ad5bfb) + +Bug: chromium:1380063 +No-Try: true +No-Presubmit: true +No-Tree-Checks: true +Change-Id: Ifa1737af7fbc7e14d69a5080cbe0aabf7ef466fa +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4009978 +Reviewed-by: Igor Sheludko +Commit-Queue: Maya Lekova +Cr-Commit-Position: refs/branch-heads/10.6@{#51} +Cr-Branched-From: 41bc7435693fbce8ef86753cd9239e30550a3e2d-refs/heads/10.6.194@{#1} +Cr-Branched-From: d5f29b929ce7746409201d77f44048f3e9529b40-refs/heads/main@{#82548} + +diff --git a/src/compiler/effect-control-linearizer.cc b/src/compiler/effect-control-linearizer.cc +index 5825045052be450516b30e09a2cdf3e55c42c70e..909a6781d60729d7e21d9f8dfe265ff853855ed3 100644 +--- a/src/compiler/effect-control-linearizer.cc ++++ b/src/compiler/effect-control-linearizer.cc +@@ -5380,6 +5380,8 @@ Node* EffectControlLinearizer::LowerLoadFieldByIndex(Node* node) { + + auto if_double = __ MakeDeferredLabel(); + auto done = __ MakeLabel(MachineRepresentation::kTagged); ++ auto loaded_field = __ MakeLabel(MachineRepresentation::kTagged); ++ auto done_double = __ MakeLabel(MachineRepresentation::kFloat64); + + // Check if field is a mutable double field. + __ GotoIfNot(__ IntPtrEqual(__ WordAnd(index, one), zero), &if_double); +@@ -5396,8 +5398,8 @@ Node* EffectControlLinearizer::LowerLoadFieldByIndex(Node* node) { + Node* offset = + __ IntAdd(__ WordShl(index, __ IntPtrConstant(kTaggedSizeLog2 - 1)), + __ IntPtrConstant(JSObject::kHeaderSize - kHeapObjectTag)); +- Node* result = __ Load(MachineType::AnyTagged(), object, offset); +- __ Goto(&done, result); ++ Node* field = __ Load(MachineType::AnyTagged(), object, offset); ++ __ Goto(&loaded_field, field); + } + + // The field is located in the properties backing store of {object}. +@@ -5411,8 +5413,8 @@ Node* EffectControlLinearizer::LowerLoadFieldByIndex(Node* node) { + __ IntPtrConstant(kTaggedSizeLog2 - 1)), + __ IntPtrConstant((FixedArray::kHeaderSize - kTaggedSize) - + kHeapObjectTag)); +- Node* result = __ Load(MachineType::AnyTagged(), properties, offset); +- __ Goto(&done, result); ++ Node* field = __ Load(MachineType::AnyTagged(), properties, offset); ++ __ Goto(&loaded_field, field); + } + } + +@@ -5420,9 +5422,6 @@ Node* EffectControlLinearizer::LowerLoadFieldByIndex(Node* node) { + // architectures, or a mutable HeapNumber. + __ Bind(&if_double); + { +- auto loaded_field = __ MakeLabel(MachineRepresentation::kTagged); +- auto done_double = __ MakeLabel(MachineRepresentation::kFloat64); +- + index = __ WordSar(index, one); + + // Check if field is in-object or out-of-object. +@@ -5450,27 +5449,27 @@ Node* EffectControlLinearizer::LowerLoadFieldByIndex(Node* node) { + Node* field = __ Load(MachineType::AnyTagged(), properties, offset); + __ Goto(&loaded_field, field); + } ++ } + +- __ Bind(&loaded_field); +- { +- Node* field = loaded_field.PhiAt(0); +- // We may have transitioned in-place away from double, so check that +- // this is a HeapNumber -- otherwise the load is fine and we don't need +- // to copy anything anyway. +- __ GotoIf(ObjectIsSmi(field), &done, field); +- Node* field_map = __ LoadField(AccessBuilder::ForMap(), field); +- __ GotoIfNot(__ TaggedEqual(field_map, __ HeapNumberMapConstant()), &done, +- field); +- +- Node* value = __ LoadField(AccessBuilder::ForHeapNumberValue(), field); +- __ Goto(&done_double, value); +- } ++ __ Bind(&loaded_field); ++ { ++ Node* field = loaded_field.PhiAt(0); ++ // We may have transitioned in-place away from double, so check that ++ // this is a HeapNumber -- otherwise the load is fine and we don't need ++ // to copy anything anyway. ++ __ GotoIf(ObjectIsSmi(field), &done, field); ++ Node* field_map = __ LoadField(AccessBuilder::ForMap(), field); ++ __ GotoIfNot(__ TaggedEqual(field_map, __ HeapNumberMapConstant()), &done, ++ field); + +- __ Bind(&done_double); +- { +- Node* result = AllocateHeapNumberWithValue(done_double.PhiAt(0)); +- __ Goto(&done, result); +- } ++ Node* value = __ LoadField(AccessBuilder::ForHeapNumberValue(), field); ++ __ Goto(&done_double, value); ++ } ++ ++ __ Bind(&done_double); ++ { ++ Node* result = AllocateHeapNumberWithValue(done_double.PhiAt(0)); ++ __ Goto(&done, result); + } + + __ Bind(&done); diff --git a/patches/v8/cherry-pick-8b040cb69e96.patch b/patches/v8/cherry-pick-8b040cb69e96.patch new file mode 100644 index 0000000000000..fc0ab4af1e368 --- /dev/null +++ b/patches/v8/cherry-pick-8b040cb69e96.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jakob Kummerow +Date: Fri, 23 Sep 2022 13:13:37 +0200 +Subject: Fix a register reuse corner case + +Fixed: chromium:1366399 +(cherry picked from commit 6c214db445827707d65be08d177c9a4257a03a7b) + +Change-Id: I72cf30cbd31a21acb44b524a194acfb89d8fecbc +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3925795 +Reviewed-by: Matthias Liedtke +Cr-Commit-Position: refs/branch-heads/10.6@{#29} +Cr-Branched-From: 41bc7435693fbce8ef86753cd9239e30550a3e2d-refs/heads/10.6.194@{#1} +Cr-Branched-From: d5f29b929ce7746409201d77f44048f3e9529b40-refs/heads/main@{#82548} + +diff --git a/src/wasm/baseline/liftoff-compiler.cc b/src/wasm/baseline/liftoff-compiler.cc +index 2b269516dd302c06a3eebc1c9d70f4d36612b942..3f768f8f5adcc1bfd1d64e68c638a5bf2e737051 100644 +--- a/src/wasm/baseline/liftoff-compiler.cc ++++ b/src/wasm/baseline/liftoff-compiler.cc +@@ -1421,9 +1421,11 @@ class LiftoffCompiler { + __ MergeFullStackWith(c->label_state, *__ cache_state()); + __ emit_jump(c->label.get()); + } +- // Merge the else state into the end state. ++ // Merge the else state into the end state. Set this state as the current ++ // state first so helper functions know which registers are in use. + __ bind(c->else_state->label.get()); +- __ MergeFullStackWith(c->label_state, c->else_state->state); ++ __ cache_state()->Steal(c->else_state->state); ++ __ MergeFullStackWith(c->label_state, *__ cache_state()); + __ cache_state()->Steal(c->label_state); + } else if (c->reachable()) { + // No merge yet at the end of the if, but we need to create a merge for +@@ -1435,9 +1437,11 @@ class LiftoffCompiler { + c->stack_depth + c->num_exceptions); + __ MergeFullStackWith(c->label_state, *__ cache_state()); + __ emit_jump(c->label.get()); +- // Merge the else state into the end state. ++ // Merge the else state into the end state. Set this state as the current ++ // state first so helper functions know which registers are in use. + __ bind(c->else_state->label.get()); +- __ MergeFullStackWith(c->label_state, c->else_state->state); ++ __ cache_state()->Steal(c->else_state->state); ++ __ MergeFullStackWith(c->label_state, *__ cache_state()); + __ cache_state()->Steal(c->label_state); + } else { + // No merge needed, just continue with the else state. diff --git a/patches/v8/cherry-pick-c79148742421.patch b/patches/v8/cherry-pick-c79148742421.patch new file mode 100644 index 0000000000000..80c85e76a2d7e --- /dev/null +++ b/patches/v8/cherry-pick-c79148742421.patch @@ -0,0 +1,122 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shu-yu Guo +Date: Fri, 28 Oct 2022 10:21:27 -0700 +Subject: Merged: Reland "[Promise.any] Fix errors allocation" + +Bug: chromium:1379054 + +(cherry picked from commit 8b35091b2d244c975975e1c78e4cd09cb479b5dc) + +Change-Id: Iec8f8bb51f4434d6ae86887cf742f2883a9b7bef +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4004804 +Reviewed-by: Adam Klein +Commit-Queue: Shu-yu Guo +Cr-Commit-Position: refs/branch-heads/10.8@{#34} +Cr-Branched-From: f1bc03fd6b4c201abd9f0fd9d51fb989150f97b9-refs/heads/10.8.168@{#1} +Cr-Branched-From: 237de893e1c0a0628a57d0f5797483d3add7f005-refs/heads/main@{#83672} + +diff --git a/include/v8-version.h b/include/v8-version.h +index 7baa3bf9b725652ddaac1a3d39dd96a3520b9f26..fb1097518be399c6665d53c2be79ec81a210de71 100644 +--- a/include/v8-version.h ++++ b/include/v8-version.h +@@ -11,7 +11,7 @@ + #define V8_MAJOR_VERSION 10 + #define V8_MINOR_VERSION 4 + #define V8_BUILD_NUMBER 132 +-#define V8_PATCH_LEVEL 24 ++#define V8_PATCH_LEVEL 25 + + // Use 1 for candidates and 0 otherwise. + // (Boolean macro values are not supported by all preprocessors.) +diff --git a/src/builtins/promise-any.tq b/src/builtins/promise-any.tq +index ffb285a06a83557d8657aef6c04acc5c65513a62..7e707e649f11bc946a6d1173180d7293fe94d8ce 100644 +--- a/src/builtins/promise-any.tq ++++ b/src/builtins/promise-any.tq +@@ -119,7 +119,19 @@ PromiseAnyRejectElementClosure( + kPromiseAnyRejectElementRemainingSlot); + + // 9. Set errors[index] to x. +- const newCapacity = IntPtrMax(SmiUntag(remainingElementsCount), index + 1); ++ ++ // The max computation below is an optimization to avoid excessive allocations ++ // in the case of input promises being asynchronously rejected in ascending ++ // index order. ++ // ++ // Note that subtracting 1 from remainingElementsCount is intentional. The ++ // value of remainingElementsCount is 1 larger than the actual value during ++ // iteration. So in the case of synchronous rejection, newCapacity is the ++ // correct size by subtracting 1. In the case of asynchronous rejection this ++ // is 1 smaller than the correct size, but is not incorrect as it is maxed ++ // with index + 1. ++ const newCapacity = ++ IntPtrMax(SmiUntag(remainingElementsCount) - 1, index + 1); + if (newCapacity > errors.length_intptr) deferred { + errors = ExtractFixedArray(errors, 0, errors.length_intptr, newCapacity); + *ContextSlot( +@@ -306,6 +318,7 @@ Reject(JSAny) { + PromiseAnyRejectElementContextSlots:: + kPromiseAnyRejectElementErrorsSlot); + ++ check(errors.length == index - 1); + const error = ConstructAggregateError(errors); + // 3. Return ThrowCompletion(error). + goto Reject(error); +diff --git a/tools/v8heapconst.py b/tools/v8heapconst.py +index 993785ec032917ba4004bc96366e55230dd60dbb..578388b5bb44672b000b95cdc89f573cbda72a00 100644 +--- a/tools/v8heapconst.py ++++ b/tools/v8heapconst.py +@@ -537,30 +537,30 @@ KNOWN_OBJECTS = { + ("old_space", 0x04b35): "StringSplitCache", + ("old_space", 0x04f3d): "RegExpMultipleCache", + ("old_space", 0x05345): "BuiltinsConstantsTable", +- ("old_space", 0x05781): "AsyncFunctionAwaitRejectSharedFun", +- ("old_space", 0x057a5): "AsyncFunctionAwaitResolveSharedFun", +- ("old_space", 0x057c9): "AsyncGeneratorAwaitRejectSharedFun", +- ("old_space", 0x057ed): "AsyncGeneratorAwaitResolveSharedFun", +- ("old_space", 0x05811): "AsyncGeneratorYieldResolveSharedFun", +- ("old_space", 0x05835): "AsyncGeneratorReturnResolveSharedFun", +- ("old_space", 0x05859): "AsyncGeneratorReturnClosedRejectSharedFun", +- ("old_space", 0x0587d): "AsyncGeneratorReturnClosedResolveSharedFun", +- ("old_space", 0x058a1): "AsyncIteratorValueUnwrapSharedFun", +- ("old_space", 0x058c5): "PromiseAllResolveElementSharedFun", +- ("old_space", 0x058e9): "PromiseAllSettledResolveElementSharedFun", +- ("old_space", 0x0590d): "PromiseAllSettledRejectElementSharedFun", +- ("old_space", 0x05931): "PromiseAnyRejectElementSharedFun", +- ("old_space", 0x05955): "PromiseCapabilityDefaultRejectSharedFun", +- ("old_space", 0x05979): "PromiseCapabilityDefaultResolveSharedFun", +- ("old_space", 0x0599d): "PromiseCatchFinallySharedFun", +- ("old_space", 0x059c1): "PromiseGetCapabilitiesExecutorSharedFun", +- ("old_space", 0x059e5): "PromiseThenFinallySharedFun", +- ("old_space", 0x05a09): "PromiseThrowerFinallySharedFun", +- ("old_space", 0x05a2d): "PromiseValueThunkFinallySharedFun", +- ("old_space", 0x05a51): "ProxyRevokeSharedFun", +- ("old_space", 0x05a75): "ShadowRealmImportValueFulfilledSFI", +- ("old_space", 0x05a99): "SourceTextModuleExecuteAsyncModuleFulfilledSFI", +- ("old_space", 0x05abd): "SourceTextModuleExecuteAsyncModuleRejectedSFI", ++ ("old_space", 0x05785): "AsyncFunctionAwaitRejectSharedFun", ++ ("old_space", 0x057a9): "AsyncFunctionAwaitResolveSharedFun", ++ ("old_space", 0x057cd): "AsyncGeneratorAwaitRejectSharedFun", ++ ("old_space", 0x057f1): "AsyncGeneratorAwaitResolveSharedFun", ++ ("old_space", 0x05815): "AsyncGeneratorYieldResolveSharedFun", ++ ("old_space", 0x05839): "AsyncGeneratorReturnResolveSharedFun", ++ ("old_space", 0x0585d): "AsyncGeneratorReturnClosedRejectSharedFun", ++ ("old_space", 0x05881): "AsyncGeneratorReturnClosedResolveSharedFun", ++ ("old_space", 0x058a5): "AsyncIteratorValueUnwrapSharedFun", ++ ("old_space", 0x058c9): "PromiseAllResolveElementSharedFun", ++ ("old_space", 0x058ed): "PromiseAllSettledResolveElementSharedFun", ++ ("old_space", 0x05911): "PromiseAllSettledRejectElementSharedFun", ++ ("old_space", 0x05935): "PromiseAnyRejectElementSharedFun", ++ ("old_space", 0x05959): "PromiseCapabilityDefaultRejectSharedFun", ++ ("old_space", 0x0597d): "PromiseCapabilityDefaultResolveSharedFun", ++ ("old_space", 0x059a1): "PromiseCatchFinallySharedFun", ++ ("old_space", 0x059c5): "PromiseGetCapabilitiesExecutorSharedFun", ++ ("old_space", 0x059e9): "PromiseThenFinallySharedFun", ++ ("old_space", 0x05a0d): "PromiseThrowerFinallySharedFun", ++ ("old_space", 0x05a31): "PromiseValueThunkFinallySharedFun", ++ ("old_space", 0x05a55): "ProxyRevokeSharedFun", ++ ("old_space", 0x05a79): "ShadowRealmImportValueFulfilledSFI", ++ ("old_space", 0x05a9d): "SourceTextModuleExecuteAsyncModuleFulfilledSFI", ++ ("old_space", 0x05ac1): "SourceTextModuleExecuteAsyncModuleRejectedSFI", + } + + # Lower 32 bits of first page addresses for various heap spaces. diff --git a/patches/v8/cherry-pick-ec236fef54b8.patch b/patches/v8/cherry-pick-ec236fef54b8.patch new file mode 100644 index 0000000000000..4ebdc326b7490 --- /dev/null +++ b/patches/v8/cherry-pick-ec236fef54b8.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Tobias Tebbi +Date: Wed, 26 Oct 2022 11:19:59 +0200 +Subject: Merged: [turbofan] do not optimize any stores for field type None + +Fixed: chromium:1378239 +(cherry picked from commit db83e72034c0d431ff2f73e3c4ae3130c0f3e4e1) + +Change-Id: I061d5dfe6e4ee24e6d0e7df56e15fbe37752d51e +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3982254 +Reviewed-by: Tobias Tebbi +Commit-Queue: Igor Sheludko +Cr-Commit-Position: refs/branch-heads/10.6@{#45} +Cr-Branched-From: 41bc7435693fbce8ef86753cd9239e30550a3e2d-refs/heads/10.6.194@{#1} +Cr-Branched-From: d5f29b929ce7746409201d77f44048f3e9529b40-refs/heads/main@{#82548} + +diff --git a/src/compiler/access-info.cc b/src/compiler/access-info.cc +index 307bf44cf42381ec820221806fbbc5705d71de3c..237734929f3e71e05312981506bb0735631b9451 100644 +--- a/src/compiler/access-info.cc ++++ b/src/compiler/access-info.cc +@@ -454,9 +454,15 @@ PropertyAccessInfo AccessInfoFactory::ComputeDataFieldAccessInfo( + map, descriptor, details_representation)); + } else if (details_representation.IsHeapObject()) { + if (descriptors_field_type->IsNone()) { +- // Store is not safe if the field type was cleared. +- if (access_mode == AccessMode::kStore) { +- return Invalid(); ++ switch (access_mode) { ++ case AccessMode::kStore: ++ case AccessMode::kStoreInLiteral: ++ case AccessMode::kDefine: ++ // Store is not safe if the field type was cleared. ++ return Invalid(); ++ case AccessMode::kLoad: ++ case AccessMode::kHas: ++ break; + } + + // The field type was cleared by the GC, so we don't know anything diff --git a/patches/webrtc/.patches b/patches/webrtc/.patches index 9cde1db8895b3..30f7ca0ed5c38 100644 --- a/patches/webrtc/.patches +++ b/patches/webrtc/.patches @@ -1 +1,2 @@ add_thread_local_to_x_error_trap_cc.patch +cherry-pick-136ef25acbf7.patch diff --git a/patches/webrtc/cherry-pick-136ef25acbf7.patch b/patches/webrtc/cherry-pick-136ef25acbf7.patch new file mode 100644 index 0000000000000..286a745376e0b --- /dev/null +++ b/patches/webrtc/cherry-pick-136ef25acbf7.patch @@ -0,0 +1,59 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jakob Ivarsson +Date: Fri, 23 Sep 2022 22:03:09 +0200 +Subject: Fix crash when appending empty array to AudioMultiVector. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Bug: webrtc:14442,chromium:1367993 +Change-Id: I9453e300a6d3d78571d08cc65770787e13d43885 +Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/276620 +Commit-Queue: Jakob Ivarsson‎ +Reviewed-by: Henrik Lundin +Cr-Commit-Position: refs/heads/main@{#38208} + +diff --git a/modules/audio_coding/neteq/audio_multi_vector.cc b/modules/audio_coding/neteq/audio_multi_vector.cc +index 220d5a17d7d1d4e1ed7577d4a044af29f358f88b..14ae94649b52278656eb73d91b1e73cb5307a92d 100644 +--- a/modules/audio_coding/neteq/audio_multi_vector.cc ++++ b/modules/audio_coding/neteq/audio_multi_vector.cc +@@ -69,6 +69,9 @@ void AudioMultiVector::CopyTo(AudioMultiVector* copy_to) const { + void AudioMultiVector::PushBackInterleaved( + rtc::ArrayView append_this) { + RTC_DCHECK_EQ(append_this.size() % num_channels_, 0); ++ if (append_this.empty()) { ++ return; ++ } + if (num_channels_ == 1) { + // Special case to avoid extra allocation and data shuffling. + channels_[0]->PushBack(append_this.data(), append_this.size()); +@@ -78,11 +81,8 @@ void AudioMultiVector::PushBackInterleaved( + int16_t* temp_array = new int16_t[length_per_channel]; // Temporary storage. + for (size_t channel = 0; channel < num_channels_; ++channel) { + // Copy elements to `temp_array`. +- // Set `source_ptr` to first element of this channel. +- const int16_t* source_ptr = &append_this[channel]; + for (size_t i = 0; i < length_per_channel; ++i) { +- temp_array[i] = *source_ptr; +- source_ptr += num_channels_; // Jump to next element of this channel. ++ temp_array[i] = append_this[channel + i * num_channels_]; + } + channels_[channel]->PushBack(temp_array, length_per_channel); + } +diff --git a/modules/audio_coding/neteq/audio_multi_vector_unittest.cc b/modules/audio_coding/neteq/audio_multi_vector_unittest.cc +index 329377a18edc2259dfc24dbaf82218ff69180916..386c3d48a398521730afad6642df355e29550d79 100644 +--- a/modules/audio_coding/neteq/audio_multi_vector_unittest.cc ++++ b/modules/audio_coding/neteq/audio_multi_vector_unittest.cc +@@ -309,6 +309,12 @@ TEST_P(AudioMultiVectorTest, CopyChannel) { + } + } + ++TEST_P(AudioMultiVectorTest, PushBackEmptyArray) { ++ AudioMultiVector vec(num_channels_); ++ vec.PushBackInterleaved({}); ++ EXPECT_TRUE(vec.Empty()); ++} ++ + INSTANTIATE_TEST_SUITE_P(TestNumChannels, + AudioMultiVectorTest, + ::testing::Values(static_cast(1), diff --git a/script/create-api-json.js b/script/create-api-json.js new file mode 100644 index 0000000000000..00a70355c3f8d --- /dev/null +++ b/script/create-api-json.js @@ -0,0 +1,17 @@ +const { parseDocs } = require('@electron/docs-parser'); +const fs = require('fs'); +const path = require('path'); + +const { getElectronVersion } = require('./lib/get-version'); + +parseDocs({ + baseDirectory: path.resolve(__dirname, '..'), + packageMode: 'single', + useReadme: false, + moduleVersion: getElectronVersion() +}).then((api) => { + return fs.promises.writeFile(path.resolve(__dirname, '..', 'electron-api.json'), JSON.stringify(api, null, 2)); +}).catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/script/generate-version-json.js b/script/generate-version-json.js index 5c41d0543394d..8a981f81738fb 100644 --- a/script/generate-version-json.js +++ b/script/generate-version-json.js @@ -3,8 +3,7 @@ const path = require('path'); const semver = require('semver'); const outputPath = process.argv[2]; - -const currentVersion = fs.readFileSync(path.resolve(__dirname, '../ELECTRON_VERSION'), 'utf8').trim(); +const currentVersion = process.argv[3]; const parsed = semver.parse(currentVersion); @@ -20,9 +19,11 @@ const { } = parsed; fs.writeFileSync(outputPath, JSON.stringify({ + full_version: currentVersion, major, minor, patch, prerelease, + prerelease_number: prerelease ? parsed.prerelease[parsed.prerelease.length - 1] : '0', has_prerelease: prerelease === '' ? 0 : 1 }, null, 2)); diff --git a/script/gn-asar-hash.js b/script/gn-asar-hash.js index e9801838e530c..8aa78c9a3d760 100644 --- a/script/gn-asar-hash.js +++ b/script/gn-asar-hash.js @@ -1,4 +1,4 @@ -const asar = require('asar'); +const asar = require('@electron/asar'); const crypto = require('crypto'); const fs = require('fs'); diff --git a/script/gn-asar.js b/script/gn-asar.js index 80e2cdb34f4c8..57ef6a8110c31 100644 --- a/script/gn-asar.js +++ b/script/gn-asar.js @@ -1,4 +1,4 @@ -const asar = require('asar'); +const asar = require('@electron/asar'); const assert = require('assert'); const fs = require('fs-extra'); const os = require('os'); diff --git a/script/lib/get-version.js b/script/lib/get-version.js new file mode 100644 index 0000000000000..45a120482b05d --- /dev/null +++ b/script/lib/get-version.js @@ -0,0 +1,22 @@ +const { spawnSync } = require('child_process'); +const path = require('path'); + +module.exports.getElectronVersion = () => { + // Find the nearest tag to the current HEAD + // This is equivilant to our old logic of "use a value in package.json" for the following reasons + // + // 1. Whenever we updated the package.json we ALSO pushed a tag with the same version + // 2. Whenever we _reverted_ a bump all we actually did was push a commit that deleted the tag and changed the version number back + // + // The only difference in the "git describe" technique is that technically a commit can "change" it's version + // number if a tag is created / removed retroactively. i.e. the first time a commit is pushed it will be 1.2.3 + // and after the tag is made rebuilding the same commit will result in it being 1.2.4 + const output = spawnSync('git', ['describe', '--tags', '--abbrev=0'], { + cwd: path.resolve(__dirname, '..', '..') + }); + if (output.status !== 0) { + console.error(output.stderr); + throw new Error('Failed to get current electron version'); + } + return output.stdout.toString().trim().replace(/^v/g, ''); +}; diff --git a/script/lib/util.py b/script/lib/util.py index 05d476e93ab26..7911d2da79fcf 100644 --- a/script/lib/util.py +++ b/script/lib/util.py @@ -15,7 +15,9 @@ from urllib2 import urlopen import zipfile -from lib.config import is_verbose_mode +# from lib.config import is_verbose_mode +def is_verbose_mode(): + return False ELECTRON_DIR = os.path.abspath( os.path.dirname(os.path.dirname(os.path.dirname(__file__))) @@ -149,11 +151,17 @@ def get_electron_branding(): with open(branding_file_path) as f: return json.load(f) + +cached_electron_version = None def get_electron_version(): - SOURCE_ROOT = os.path.abspath(os.path.join(__file__, '..', '..', '..')) - version_file = os.path.join(SOURCE_ROOT, 'ELECTRON_VERSION') - with open(version_file) as f: - return 'v' + f.read().strip() + global cached_electron_version + if cached_electron_version is None: + cached_electron_version = str.strip(execute([ + 'node', + '-p', + 'require("./script/lib/get-version").getElectronVersion()' + ], cwd=ELECTRON_DIR).decode()) + return cached_electron_version def store_artifact(prefix, key_prefix, files): # Azure Storage diff --git a/script/lib/utils.js b/script/lib/utils.js index 55f678b43ed1c..2e5e6f0d53b42 100644 --- a/script/lib/utils.js +++ b/script/lib/utils.js @@ -100,6 +100,7 @@ module.exports = { getElectronExec, getOutDir, getAbsoluteElectronExec, + handleGitCall, ELECTRON_DIR, SRC_DIR }; diff --git a/script/prepare-appveyor.js b/script/prepare-appveyor.js new file mode 100644 index 0000000000000..9960b877f5df6 --- /dev/null +++ b/script/prepare-appveyor.js @@ -0,0 +1,219 @@ +if (!process.env.CI) require('dotenv-safe').load(); + +const assert = require('assert'); +const fs = require('fs'); +const got = require('got'); +const path = require('path'); +const { handleGitCall, ELECTRON_DIR } = require('./lib/utils.js'); +const { Octokit } = require('@octokit/rest'); +const octokit = new Octokit(); + +const APPVEYOR_IMAGES_URL = 'https://ci.appveyor.com/api/build-clouds'; +const APPVEYOR_JOB_URL = 'https://ci.appveyor.com/api/builds'; +const ROLLER_BRANCH_PATTERN = /^roller\/chromium$/; + +const DEFAULT_BUILD_CLOUD_ID = '1598'; +const DEFAULT_BUILD_CLOUD = 'electronhq-16-core'; +const DEFAULT_BAKE_BASE_IMAGE = 'Windows_Default_Appveyor'; +const DEFAULT_BUILD_IMAGE = 'Windows_Default_Appveyor'; + +const appveyorBakeJob = 'electron-bake-image'; +const appVeyorJobs = { + 'electron-x64': 'electron-x64-testing', + 'electron-woa': 'electron-woa-testing', + 'electron-ia32': 'electron-ia32-testing' +}; + +async function makeRequest ({ auth, username, password, url, headers, body, method }) { + const clonedHeaders = { + ...(headers || {}) + }; + if (auth?.bearer) { + clonedHeaders.Authorization = `Bearer ${auth.bearer}`; + } + + const options = { + headers: clonedHeaders, + body, + method + }; + + if (username || password) { + options.username = username; + options.password = password; + } + + const response = await got(url, options); + + if (response.statusCode < 200 || response.statusCode >= 300) { + console.error('Error: ', `(status ${response.statusCode})`, response.body); + throw new Error(`Unexpected status code ${response.statusCode} from ${url}`); + } + return JSON.parse(response.body); +} + +async function checkAppVeyorImage (options) { + const IMAGE_URL = `${APPVEYOR_IMAGES_URL}/${options.cloudId}`; + const requestOpts = { + url: IMAGE_URL, + auth: { + bearer: process.env.APPVEYOR_TOKEN + }, + headers: { + 'Content-Type': 'application/json' + }, + method: 'GET' + }; + + try { + const { settings } = await makeRequest(requestOpts); + const { cloudSettings } = settings; + return cloudSettings.images.find(image => image.name === `${options.imageVersion}`) || null; + } catch (err) { + console.log('Could not call AppVeyor: ', err); + } +} + +async function getPullRequestId (targetBranch) { + const prsForBranch = await octokit.pulls.list({ + owner: 'electron', + repo: 'electron', + state: 'open', + head: `electron:${targetBranch}` + }); + if (prsForBranch.data.length === 1) { + return prsForBranch.data[0].number; + } else { + return null; + } +} + +function useAppVeyorImage (targetBranch, options) { + const validJobs = Object.keys(appVeyorJobs); + if (options.job) { + assert(validJobs.includes(options.job), `Unknown AppVeyor CI job name: ${options.job}. Valid values are: ${validJobs}.`); + callAppVeyorBuildJobs(targetBranch, options.job, options); + } else { + validJobs.forEach((job) => callAppVeyorBuildJobs(targetBranch, job, options)); + } +} + +async function callAppVeyorBuildJobs (targetBranch, job, options) { + console.log(`Using AppVeyor image ${options.version} for ${job}`); + + const pullRequestId = await getPullRequestId(targetBranch); + const environmentVariables = { + APPVEYOR_BUILD_WORKER_CLOUD: DEFAULT_BUILD_CLOUD, + APPVEYOR_BUILD_WORKER_IMAGE: options.version, + ELECTRON_OUT_DIR: 'Default', + ELECTRON_ENABLE_STACK_DUMPING: 1, + ELECTRON_ALSO_LOG_TO_STDERR: 1, + GOMA_FALLBACK_ON_AUTH_FAILURE: true, + DEPOT_TOOLS_WIN_TOOLCHAIN: 0, + PYTHONIOENCODING: 'UTF-8' + }; + + const requestOpts = { + url: APPVEYOR_JOB_URL, + auth: { + bearer: process.env.APPVEYOR_TOKEN + }, + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + accountName: 'electron-bot', + projectSlug: appVeyorJobs[job], + branch: targetBranch, + pullRequestId: pullRequestId || undefined, + commitId: options.commit || undefined, + environmentVariables + }), + method: 'POST' + }; + + try { + const { version } = await makeRequest(requestOpts); + const buildUrl = `https://ci.appveyor.com/project/electron-bot/${appVeyorJobs[job]}/build/${version}`; + console.log(`AppVeyor CI request for ${job} successful. Check status at ${buildUrl}`); + } catch (err) { + console.log('Could not call AppVeyor: ', err); + } +} + +async function bakeAppVeyorImage (targetBranch, options) { + console.log(`Baking a new AppVeyor image for ${options.version}, on build cloud ${options.cloudId}`); + + const environmentVariables = { + APPVEYOR_BUILD_WORKER_CLOUD: DEFAULT_BUILD_CLOUD, + APPVEYOR_BUILD_WORKER_IMAGE: DEFAULT_BAKE_BASE_IMAGE, + APPVEYOR_BAKE_IMAGE: options.version + }; + + const requestOpts = { + url: APPVEYOR_JOB_URL, + auth: { + bearer: process.env.APPVEYOR_TOKEN + }, + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + accountName: 'electron-bot', + projectSlug: appveyorBakeJob, + branch: targetBranch, + commitId: options.commit || undefined, + environmentVariables + }), + method: 'POST' + }; + + try { + const { version } = await makeRequest(requestOpts); + const bakeUrl = `https://ci.appveyor.com/project/electron-bot/${appveyorBakeJob}/build/${version}`; + console.log(`AppVeyor image bake request for ${options.version} successful. Check bake status at ${bakeUrl}`); + } catch (err) { + console.log('Could not call AppVeyor: ', err); + } +} + +async function prepareAppVeyorImage (opts) { + const branch = await handleGitCall(['rev-parse', '--abbrev-ref', 'HEAD'], ELECTRON_DIR); + if (ROLLER_BRANCH_PATTERN.test(branch)) { + useAppVeyorImage(branch, { ...opts, version: DEFAULT_BUILD_IMAGE, cloudId: DEFAULT_BUILD_CLOUD_ID }); + } else { + // eslint-disable-next-line no-control-regex + const versionRegex = new RegExp('chromium_version\':\n +\'(.+?)\',', 'm'); + const deps = fs.readFileSync(path.resolve(__dirname, '..', 'DEPS'), 'utf8'); + const [, CHROMIUM_VERSION] = versionRegex.exec(deps); + + const cloudId = opts.cloudId || DEFAULT_BUILD_CLOUD_ID; + const imageVersion = opts.imageVersion || `e-${CHROMIUM_VERSION}`; + const image = await checkAppVeyorImage({ cloudId, imageVersion }); + + if (image && image.name) { + console.log(`Image exists for ${image.name}. Continuing AppVeyor jobs using ${cloudId}.\n`); + } else { + console.log(`No AppVeyor image found for ${imageVersion} in ${cloudId}. + Creating new image for ${imageVersion}, using Chromium ${CHROMIUM_VERSION} - job will run after image is baked.`); + await bakeAppVeyorImage(branch, { ...opts, version: imageVersion, cloudId }); + + // write image to temp file if running on CI + if (process.env.CI) fs.writeFileSync('./image_version.txt', imageVersion); + } + } +} + +module.exports = prepareAppVeyorImage; + +// Load or bake AppVeyor images for Windows CI. +// Usage: prepare-appveyor.js [--cloudId=CLOUD_ID] [--appveyorJobId=xxx] [--imageVersion=xxx] +// [--commit=sha] [--branch=branch_name] +if (require.main === module) { + const args = require('minimist')(process.argv.slice(2)); + prepareAppVeyorImage(args) + .catch((err) => { + console.error(err); + process.exit(1); + }); +} diff --git a/script/print-version.py b/script/print-version.py new file mode 100644 index 0000000000000..20ec2231a2635 --- /dev/null +++ b/script/print-version.py @@ -0,0 +1,3 @@ +from lib.util import get_electron_version + +print(get_electron_version()) diff --git a/script/release/ci-release-build.js b/script/release/ci-release-build.js index c92dcf1b61307..6094d666603ef 100644 --- a/script/release/ci-release-build.js +++ b/script/release/ci-release-build.js @@ -24,8 +24,6 @@ const circleCIPublishIndividualArches = { 'linux-publish': ['arm', 'arm64', 'x64'] }; -const GHAJobs = ['electron-woa-testing']; - let jobRequestedCount = 0; async function makeRequest ({ auth, url, headers, body, method }) { @@ -194,7 +192,7 @@ async function callAppVeyor (targetBranch, job, options) { console.log(`Triggering AppVeyor to run build job: ${job} on branch: ${targetBranch} with release flag.`); const environmentVariables = { ELECTRON_RELEASE: 1, - APPVEYOR_BUILD_WORKER_CLOUD: 'libcc-20' + APPVEYOR_BUILD_WORKER_CLOUD: 'electronhq-16-core' }; if (!options.ghRelease) { @@ -240,31 +238,6 @@ function buildCircleCI (targetBranch, options) { } } -async function buildGHA (targetBranch, options) { - const { GHA_TOKEN } = process.env; - assert(GHA_TOKEN, `${options.ci} requires the $GHA_TOKEN environment variable to be provided`); - - const octokit = new Octokit({ auth: GHA_TOKEN }); - - assert(GHAJobs.includes(options.job), `Unknown GitHub Actions arm test job name: ${options.job}. Valid values are: ${GHAJobs}.`); - assert(options.commit !== null, 'commit is a required option for GitHub Actions'); - - console.log(`Triggering GitHub Actions to run build on branch: ${targetBranch}.`); - - jobRequestedCount++; - - try { - const response = await octokit.request('POST /repos/electron/electron/actions/workflows/electron_woa_testing.yml/dispatches', { - ref: targetBranch, - inputs: { - appveyor_job_id: `${options.appveyorJobId}` - } - }); - } catch (err) { - console.log('Problem calling GitHub Actions to get build definitions: ', err); - } -} - function runRelease (targetBranch, options) { if (options.ci) { switch (options.ci) { @@ -276,10 +249,6 @@ function runRelease (targetBranch, options) { buildAppVeyor(targetBranch, options); break; } - case 'GHA': { - buildGHA(targetBranch, options); - break; - } default: { console.log(`Error! Unknown CI: ${options.ci}.`); process.exit(1); @@ -301,7 +270,7 @@ if (require.main === module) { const targetBranch = args._[0]; if (args._.length < 1) { console.log(`Trigger CI to build release builds of electron. - Usage: ci-release-build.js [--job=CI_JOB_NAME] [--arch=INDIVIDUAL_ARCH] [--ci=CircleCI|AppVeyor|GHA] + Usage: ci-release-build.js [--job=CI_JOB_NAME] [--arch=INDIVIDUAL_ARCH] [--ci=CircleCI|AppVeyor] [--ghRelease] [--circleBuildNum=xxx] [--appveyorJobId=xxx] [--commit=sha] TARGET_BRANCH `); process.exit(0); diff --git a/script/release/publish-to-npm.js b/script/release/publish-to-npm.js index 55799665a57ad..18d4454d2f13e 100644 --- a/script/release/publish-to-npm.js +++ b/script/release/publish-to-npm.js @@ -6,6 +6,7 @@ const got = require('got'); const semver = require('semver'); const { getCurrentBranch, ELECTRON_DIR } = require('../lib/utils'); +const { getElectronVersion } = require('../lib/get-version'); const rootPackageJson = require('../../package.json'); const { Octokit } = require('@octokit/rest'); @@ -34,7 +35,6 @@ const files = [ const jsonFields = [ 'name', - 'version', 'repository', 'description', 'license', @@ -44,6 +44,9 @@ const jsonFields = [ let npmTag = ''; +const currentElectronVersion = getElectronVersion(); +const isNightlyElectronVersion = currentElectronVersion.includes('nightly'); + new Promise((resolve, reject) => { temp.mkdir('electron-npm', (err, dirPath) => { if (err) { @@ -68,6 +71,7 @@ new Promise((resolve, reject) => { jsonFields.forEach((fieldName) => { packageJson[fieldName] = rootPackageJson[fieldName]; }); + packageJson.version = currentElectronVersion; fs.writeFileSync( path.join(tempDir, 'package.json'), JSON.stringify(packageJson, null, 2) @@ -75,27 +79,27 @@ new Promise((resolve, reject) => { return octokit.repos.listReleases({ owner: 'electron', - repo: rootPackageJson.version.indexOf('nightly') > 0 ? 'nightlies' : 'electron' + repo: isNightlyElectronVersion ? 'nightlies' : 'electron' }); }) .then((releases) => { // download electron.d.ts from release const release = releases.data.find( - (release) => release.tag_name === `v${rootPackageJson.version}` + (release) => release.tag_name === `v${currentElectronVersion}` ); if (!release) { - throw new Error(`cannot find release with tag v${rootPackageJson.version}`); + throw new Error(`cannot find release with tag v${currentElectronVersion}`); } return release; }) .then(async (release) => { const tsdAsset = release.assets.find((asset) => asset.name === 'electron.d.ts'); if (!tsdAsset) { - throw new Error(`cannot find electron.d.ts from v${rootPackageJson.version} release assets`); + throw new Error(`cannot find electron.d.ts from v${currentElectronVersion} release assets`); } const typingsContent = await getAssetContents( - rootPackageJson.version.indexOf('nightly') > 0 ? 'nightlies' : 'electron', + isNightlyElectronVersion ? 'nightlies' : 'electron', tsdAsset.id ); @@ -106,11 +110,11 @@ new Promise((resolve, reject) => { .then(async (release) => { const checksumsAsset = release.assets.find((asset) => asset.name === 'SHASUMS256.txt'); if (!checksumsAsset) { - throw new Error(`cannot find SHASUMS256.txt from v${rootPackageJson.version} release assets`); + throw new Error(`cannot find SHASUMS256.txt from v${currentElectronVersion} release assets`); } const checksumsContent = await getAssetContents( - rootPackageJson.version.indexOf('nightly') > 0 ? 'nightlies' : 'electron', + isNightlyElectronVersion ? 'nightlies' : 'electron', checksumsAsset.id ); @@ -127,7 +131,7 @@ new Promise((resolve, reject) => { .then(async (release) => { const currentBranch = await getCurrentBranch(); - if (release.tag_name.indexOf('nightly') > 0) { + if (isNightlyElectronVersion) { // TODO(main-migration): Simplify once main branch is renamed. if (currentBranch === 'master' || currentBranch === 'main') { // Nightlies get published to their own module, so they should be tagged as latest @@ -164,7 +168,7 @@ new Promise((resolve, reject) => { .then(() => childProcess.execSync('npm pack', { cwd: tempDir })) .then(() => { // test that the package can install electron prebuilt from github release - const tarballPath = path.join(tempDir, `${rootPackageJson.name}-${rootPackageJson.version}.tgz`); + const tarballPath = path.join(tempDir, `${rootPackageJson.name}-${currentElectronVersion}.tgz`); return new Promise((resolve, reject) => { const result = childProcess.spawnSync('npm', ['install', tarballPath, '--force', '--silent'], { env: Object.assign({}, process.env, { electron_config_cache: tempDir }), @@ -190,7 +194,7 @@ new Promise((resolve, reject) => { }); }) .then((tarballPath) => { - const existingVersionJSON = childProcess.execSync(`npm view electron@${rootPackageJson.version} --json`).toString('utf-8'); + const existingVersionJSON = childProcess.execSync(`npx npm@7 view ${rootPackageJson.name}@${currentElectronVersion} --json`).toString('utf-8'); // It's possible this is a re-run and we already have published the package, if not we just publish like normal if (!existingVersionJSON) { childProcess.execSync(`npm publish ${tarballPath} --tag ${npmTag} --otp=${process.env.ELECTRON_NPM_OTP}`); @@ -198,22 +202,21 @@ new Promise((resolve, reject) => { }) .then(() => { const currentTags = JSON.parse(childProcess.execSync('npm show electron dist-tags --json').toString()); - const localVersion = rootPackageJson.version; - const parsedLocalVersion = semver.parse(localVersion); + const parsedLocalVersion = semver.parse(currentElectronVersion); if (rootPackageJson.name === 'electron') { // We should only customly add dist tags for non-nightly releases where the package name is still // "electron" if (parsedLocalVersion.prerelease.length === 0 && - semver.gt(localVersion, currentTags.latest)) { - childProcess.execSync(`npm dist-tag add electron@${localVersion} latest --otp=${process.env.ELECTRON_NPM_OTP}`); + semver.gt(currentElectronVersion, currentTags.latest)) { + childProcess.execSync(`npm dist-tag add electron@${currentElectronVersion} latest --otp=${process.env.ELECTRON_NPM_OTP}`); } if (parsedLocalVersion.prerelease[0] === 'beta' && - semver.gt(localVersion, currentTags.beta)) { - childProcess.execSync(`npm dist-tag add electron@${localVersion} beta --otp=${process.env.ELECTRON_NPM_OTP}`); + semver.gt(currentElectronVersion, currentTags.beta)) { + childProcess.execSync(`npm dist-tag add electron@${currentElectronVersion} beta --otp=${process.env.ELECTRON_NPM_OTP}`); } if (parsedLocalVersion.prerelease[0] === 'alpha' && - semver.gt(localVersion, currentTags.alpha)) { - childProcess.execSync(`npm dist-tag add electron@${localVersion} alpha --otp=${process.env.ELECTRON_NPM_OTP}`); + semver.gt(currentElectronVersion, currentTags.alpha)) { + childProcess.execSync(`npm dist-tag add electron@${currentElectronVersion} alpha --otp=${process.env.ELECTRON_NPM_OTP}`); } } }) diff --git a/script/release/release-artifact-cleanup.js b/script/release/release-artifact-cleanup.js index 080b078f49284..0079696c3afd8 100755 --- a/script/release/release-artifact-cleanup.js +++ b/script/release/release-artifact-cleanup.js @@ -18,26 +18,6 @@ require('colors'); const pass = '✓'.green; const fail = '✗'.red; -function getLastBumpCommit (tag) { - const data = execSync(`git log -n1 --grep "Bump ${tag}" --format='format:{"hash": "%H", "message": "%s"}'`).toString(); - return JSON.parse(data); -} - -async function revertBumpCommit (tag) { - const branch = await getCurrentBranch(); - const commitToRevert = getLastBumpCommit(tag).hash; - await GitProcess.exec(['pull', '--rebase']); - await GitProcess.exec(['revert', commitToRevert], ELECTRON_DIR); - const pushDetails = await GitProcess.exec(['push', 'origin', `HEAD:${branch}`, '--follow-tags'], ELECTRON_DIR); - if (pushDetails.exitCode === 0) { - console.log(`${pass} successfully reverted release commit.`); - } else { - const error = GitProcess.parseError(pushDetails.stderr); - console.error(`${fail} could not push release commit: `, error); - process.exit(1); - } -} - async function deleteDraft (releaseId, targetRepo) { try { const result = await octokit.repos.getRelease({ @@ -80,9 +60,6 @@ async function cleanReleaseArtifacts () { const releaseId = args.releaseID.length > 0 ? args.releaseID : null; const isNightly = args.tag.includes('nightly'); - // try to revert commit regardless of tag and draft deletion status - await revertBumpCommit(args.tag); - if (releaseId) { if (isNightly) { await deleteDraft(releaseId, 'nightlies'); diff --git a/script/release/release.js b/script/release/release.js index c3c8d6363b120..f600d7a27c42c 100755 --- a/script/release/release.js +++ b/script/release/release.js @@ -12,8 +12,6 @@ const args = require('minimist')(process.argv.slice(2), { const fs = require('fs'); const { execSync } = require('child_process'); const got = require('got'); -const pkg = require('../../package.json'); -const pkgVersion = `v${pkg.version}`; const path = require('path'); const temp = require('temp').track(); const { URL } = require('url'); @@ -25,8 +23,11 @@ const pass = '✓'.green; const fail = '✗'.red; const { ELECTRON_DIR } = require('../lib/utils'); +const { getElectronVersion } = require('../lib/get-version'); const getUrlHash = require('./get-url-hash'); +const pkgVersion = `v${getElectronVersion()}`; + const octokit = new Octokit({ auth: process.env.ELECTRON_GITHUB_TOKEN }); diff --git a/script/release/uploaders/upload.py b/script/release/uploaders/upload.py index a73955786e47c..4f285b0ed2382 100755 --- a/script/release/uploaders/upload.py +++ b/script/release/uploaders/upload.py @@ -23,7 +23,7 @@ SRC_DIR, ELECTRON_DIR, TS_NODE -ELECTRON_VERSION = get_electron_version() +ELECTRON_VERSION = 'v' + get_electron_version() PROJECT_NAME = get_electron_branding()['project_name'] PRODUCT_NAME = get_electron_branding()['product_name'] diff --git a/script/release/version-bumper.js b/script/release/version-bumper.js index 279f1f3e46096..51865bc46439c 100644 --- a/script/release/version-bumper.js +++ b/script/release/version-bumper.js @@ -1,17 +1,10 @@ #!/usr/bin/env node -const { GitProcess } = require('dugite'); -const { promises: fs } = require('fs'); const semver = require('semver'); -const path = require('path'); const minimist = require('minimist'); -const { ELECTRON_DIR } = require('../lib/utils'); +const { getElectronVersion } = require('../lib/get-version'); const versionUtils = require('./version-utils'); -const supported = path.resolve(ELECTRON_DIR, 'docs', 'tutorial', 'support.md'); - -const writeFile = fs.writeFile; -const readFile = fs.readFile; function parseCommandLine () { let help; @@ -37,7 +30,7 @@ function parseCommandLine () { // run the script async function main () { const opts = parseCommandLine(); - const currentVersion = await versionUtils.getElectronVersion(); + const currentVersion = getElectronVersion(); const version = await nextVersion(opts.bump, currentVersion); const parsed = semver.parse(version); @@ -54,20 +47,6 @@ async function main () { return 0; } - if (shouldUpdateSupported(opts.bump, currentVersion, version)) { - await updateSupported(version, supported); - } - - // update all version-related files - await Promise.all([ - updateVersion(version), - updatePackageJSON(version), - updateWinRC(components) - ]); - - // commit all updated version-related files - await commitVersionBump(version); - console.log(`Bumped to version: ${version}`); } @@ -118,10 +97,6 @@ async function nextVersion (bumpType, version) { return version; } -function shouldUpdateSupported (bump, current, version) { - return isMajorStable(bump, current) || isMajorNightly(version, current); -} - function isMajorStable (bump, currentVersion) { if (versionUtils.isBeta(currentVersion) && (bump === 'stable')) return true; return false; @@ -134,59 +109,6 @@ function isMajorNightly (version, currentVersion) { return false; } -// update VERSION file with latest release info -async function updateVersion (version) { - const versionPath = path.resolve(ELECTRON_DIR, 'ELECTRON_VERSION'); - await writeFile(versionPath, version, 'utf8'); -} - -// update package metadata files with new version -async function updatePackageJSON (version) { - const filePath = path.resolve(ELECTRON_DIR, 'package.json'); - const file = require(filePath); - file.version = version; - await writeFile(filePath, JSON.stringify(file, null, 2)); -} - -// push bump commit to release branch -async function commitVersionBump (version) { - const gitArgs = ['commit', '-a', '-m', `Bump v${version}`, '-n']; - await GitProcess.exec(gitArgs, ELECTRON_DIR); -} - -// updates electron.rc file with new semver values -async function updateWinRC (components) { - const filePath = path.resolve(ELECTRON_DIR, 'shell', 'browser', 'resources', 'win', 'electron.rc'); - const data = await readFile(filePath, 'utf8'); - const arr = data.split('\n'); - arr.forEach((line, idx) => { - if (line.includes('FILEVERSION')) { - arr[idx] = ` FILEVERSION ${versionUtils.makeVersion(components, ',', versionUtils.preType.PARTIAL)}`; - arr[idx + 1] = ` PRODUCTVERSION ${versionUtils.makeVersion(components, ',', versionUtils.preType.PARTIAL)}`; - } else if (line.includes('FileVersion')) { - arr[idx] = ` VALUE "FileVersion", "${versionUtils.makeVersion(components, '.')}"`; - arr[idx + 5] = ` VALUE "ProductVersion", "${versionUtils.makeVersion(components, '.')}"`; - } - }); - await writeFile(filePath, arr.join('\n')); -} - -// updates support.md file with new semver values (stable only) -async function updateSupported (version, filePath) { - const v = parseInt(version); - const newVersions = [`* ${v}.x.y`, `* ${v - 1}.x.y`, `* ${v - 2}.x.y`, `* ${v - 3}.x.y`]; - const contents = await readFile(filePath, 'utf8'); - const previousVersions = contents.split('\n').filter((elem) => { - return (/[^\n]*\.x\.y[^\n]*/).test(elem); - }, []); - - const newContents = previousVersions.reduce((contents, current, i) => { - return contents.replace(current, newVersions[i]); - }, contents); - - await writeFile(filePath, newContents, 'utf8'); -} - if (process.mainModule === module) { main().catch((error) => { console.error(error); @@ -194,4 +116,4 @@ if (process.mainModule === module) { }); } -module.exports = { nextVersion, shouldUpdateSupported, updateSupported }; +module.exports = { nextVersion }; diff --git a/script/release/version-utils.js b/script/release/version-utils.js index 2e9c9a88ddf2b..1bd6668339cfd 100644 --- a/script/release/version-utils.js +++ b/script/release/version-utils.js @@ -68,12 +68,6 @@ async function nextBeta (v) { return tags.length === 0 ? `${next}-beta.1` : semver.inc(tags.pop(), 'prerelease'); } -async function getElectronVersion () { - const versionPath = path.resolve(ELECTRON_DIR, 'ELECTRON_VERSION'); - const version = await readFile(versionPath, 'utf8'); - return version.trim(); -} - async function nextNightly (v) { let next = semver.valid(semver.coerce(v)); const pre = `nightly.${getCurrentDate()}`; @@ -114,7 +108,6 @@ module.exports = { nextAlpha, nextBeta, makeVersion, - getElectronVersion, nextNightly, preType }; diff --git a/script/setup-win-for-dev.bat b/script/setup-win-for-dev.bat index e2ee59f5abbb7..b02bb650e4e25 100644 --- a/script/setup-win-for-dev.bat +++ b/script/setup-win-for-dev.bat @@ -1,9 +1,7 @@ REM Parameters vs_buildtools.exe download link and wsdk version @ECHO OFF -SET buildtools_link=https://download.visualstudio.microsoft.com/download/pr/d7691cc1-82e6-434f-8e9f-a612f85b4b76/c62179f8cbbb58d4af22c21e8d4e122165f21615f529c94fad5cc7e012f1ef08/vs_BuildTools.exe -SET wsdk10_link=https://go.microsoft.com/fwlink/p/?LinkId=845298 -SET wsdk=10SDK.18362 +SET wsdk=10SDK.20348 REM Check for disk space Rem 543210987654321 @@ -44,24 +42,6 @@ IF NOT "%1"=="" ( if not exist "C:\TEMP\" mkdir C:\TEMP -REM Download vs_buildtools.exe to C:\TEMP\vs_buildtools.exe -powershell -command "& { iwr %buildtools_link% -OutFile C:\TEMP\vs_buildtools.exe }" - -REM Install Visual Studio Toolchain -C:\TEMP\vs_buildtools.exe --quiet --wait --norestart --nocache ^ - --installPath "%ProgramFiles(x86)%/Microsoft Visual Studio/2019/Community" ^ - --add Microsoft.VisualStudio.Workload.VCTools ^ - --add Microsoft.VisualStudio.Component.VC.140 ^ - --add Microsoft.VisualStudio.Component.VC.ATLMFC ^ - --add Microsoft.VisualStudio.Component.VC.Tools.ARM64 ^ - --add Microsoft.VisualStudio.Component.VC.MFC.ARM64 ^ - --add Microsoft.VisualStudio.Component.Windows%wsdk% ^ - --includeRecommended - -REM Install Windows SDK -powershell -command "& { iwr %wsdk10_link% -OutFile C:\TEMP\wsdk10.exe }" -C:\TEMP\wsdk10.exe /features /quiet - REM Install chocolatey to further install dependencies set chocolateyUseWindowsCompression='true' @"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" ^ @@ -69,15 +49,22 @@ set chocolateyUseWindowsCompression='true' -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin" -REM Install nodejs python git and yarn needed dependencies -choco install -y nodejs python2 git yarn windows-sdk-10-version-1903-windbg -call C:\ProgramData\chocolatey\bin\RefreshEnv.cmd -SET PATH=C:\Python27\;C:\Python27\Scripts;%PATH% +REM Install Visual Studio Toolchain +choco install visualstudio2019buildtools --package-parameters "--quiet --wait --norestart --nocache --installPath ""%ProgramFiles(x86)%/Microsoft Visual Studio/2019/Community"" --add Microsoft.VisualStudio.Workload.VCTools --add Microsoft.VisualStudio.Component.VC.140 --add Microsoft.VisualStudio.Component.VC.ATLMFC --add Microsoft.VisualStudio.Component.VC.Tools.ARM64 --add Microsoft.VisualStudio.Component.VC.MFC.ARM64 --add Microsoft.VisualStudio.Component.Windows%wsdk% --add Microsoft.VisualStudio.Workload.NativeDesktop --includeRecommended" + +REM Install Windows SDK +choco install windows-sdk-10-version-2104-all -pip install pywin32 +REM Install nodejs python git and yarn needed dependencies +choco install -y nodejs-lts --version=16.15.0 +choco install -y python2 git yarn +choco install python --version 3.7.9 call C:\ProgramData\chocolatey\bin\RefreshEnv.cmd -pip2 install pywin32 +SET PATH=C:\Python27\;C:\Python27\Scripts;C:\Python39\;C:\Python39\Scripts;%PATH% REM Setup Depot Tools git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git C:\depot_tools -SET PATH=%PATH%;C:\depot_tools\ \ No newline at end of file +SET PATH=%PATH%;C:\depot_tools\ + +REM Add symstore to PATH permanently +setx path "%%path%%;C:\Program Files (x86)\Windows Kits\10\Debuggers\x64" \ No newline at end of file diff --git a/shell/browser/api/electron_api_desktop_capturer.cc b/shell/browser/api/electron_api_desktop_capturer.cc index bea6a03547e58..968913d066a95 100644 --- a/shell/browser/api/electron_api_desktop_capturer.cc +++ b/shell/browser/api/electron_api_desktop_capturer.cc @@ -4,6 +4,7 @@ #include "shell/browser/api/electron_api_desktop_capturer.h" +#include #include #include #include @@ -24,12 +25,125 @@ #include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h" #include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h" +#if defined(USE_OZONE) +#include "ui/ozone/buildflags.h" +#if BUILDFLAG(OZONE_PLATFORM_X11) +#define USE_OZONE_PLATFORM_X11 +#endif +#endif + #if BUILDFLAG(IS_WIN) #include "third_party/webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.h" #include "third_party/webrtc/modules/desktop_capture/win/screen_capturer_win_directx.h" #include "ui/display/win/display_info.h" +#elif BUILDFLAG(IS_LINUX) +#if defined(USE_OZONE_PLATFORM_X11) +#include "base/logging.h" +#include "ui/base/x/x11_display_util.h" +#include "ui/base/x/x11_util.h" +#include "ui/display/util/edid_parser.h" // nogncheck +#include "ui/gfx/x/randr.h" +#include "ui/gfx/x/x11_atom_cache.h" +#include "ui/gfx/x/xproto_util.h" +#endif // defined(USE_OZONE_PLATFORM_X11) #endif // BUILDFLAG(IS_WIN) +#if BUILDFLAG(IS_LINUX) +// Private function in ui/base/x/x11_display_util.cc +std::map GetMonitors(int version, + x11::RandR* randr, + x11::Window window) { + std::map output_to_monitor; + if (version >= 105) { + if (auto reply = randr->GetMonitors({window}).Sync()) { + for (size_t monitor = 0; monitor < reply->monitors.size(); monitor++) { + for (x11::RandR::Output output : reply->monitors[monitor].outputs) + output_to_monitor[output] = monitor; + } + } + } + return output_to_monitor; +} +// Get the EDID data from the |output| and stores to |edid|. +// Private function in ui/base/x/x11_display_util.cc +std::vector GetEDIDProperty(x11::RandR* randr, + x11::RandR::Output output) { + constexpr const char kRandrEdidProperty[] = "EDID"; + auto future = randr->GetOutputProperty(x11::RandR::GetOutputPropertyRequest{ + .output = output, + .property = x11::GetAtom(kRandrEdidProperty), + .long_length = 128}); + auto response = future.Sync(); + std::vector edid; + if (response && response->format == 8 && response->type != x11::Atom::None) + edid = std::move(response->data); + return edid; +} + +// Find the mapping from monitor name atom to the display identifier +// that the screen API uses. Based on the logic in BuildDisplaysFromXRandRInfo +// in ui/base/x/x11_display_util.cc +std::map MonitorAtomIdToDisplayId() { + auto* connection = x11::Connection::Get(); + auto& randr = connection->randr(); + auto x_root_window = ui::GetX11RootWindow(); + int version = ui::GetXrandrVersion(); + + std::map monitor_atom_to_display; + + auto resources = randr.GetScreenResourcesCurrent({x_root_window}).Sync(); + if (!resources) { + LOG(ERROR) << "XRandR returned no displays; don't know how to map ids"; + return monitor_atom_to_display; + } + + std::map output_to_monitor = + GetMonitors(version, &randr, x_root_window); + auto monitors_reply = randr.GetMonitors({x_root_window}).Sync(); + + for (size_t i = 0; i < resources->outputs.size(); i++) { + x11::RandR::Output output_id = resources->outputs[i]; + auto output_info = + randr.GetOutputInfo({output_id, resources->config_timestamp}).Sync(); + if (!output_info) + continue; + + if (output_info->connection != x11::RandR::RandRConnection::Connected) + continue; + + if (output_info->crtc == static_cast(0)) + continue; + + auto crtc = + randr.GetCrtcInfo({output_info->crtc, resources->config_timestamp}) + .Sync(); + if (!crtc) + continue; + display::EdidParser edid_parser( + GetEDIDProperty(&randr, static_cast(output_id))); + auto output_32 = static_cast(output_id); + int64_t display_id = + output_32 > 0xff ? 0 : edid_parser.GetIndexBasedDisplayId(output_32); + // It isn't ideal, but if we can't parse the EDID data, fall back on the + // display number. + if (!display_id) + display_id = i; + + // Find the mapping between output identifier and the monitor name atom + // Note this isn't the atom string, but the numeric atom identifier, + // since this is what the WebRTC system uses as the display identifier + auto output_monitor_iter = output_to_monitor.find(output_id); + if (output_monitor_iter != output_to_monitor.end()) { + x11::Atom atom = + monitors_reply->monitors[output_monitor_iter->second].name; + monitor_atom_to_display[static_cast(atom)] = display_id; + } + } + + return monitor_atom_to_display; +} +#endif + namespace gin { template <> @@ -180,10 +294,22 @@ void DesktopCapturer::UpdateSourcesList(DesktopMediaList* list) { for (auto& source : screen_sources) { source.display_id = base::NumberToString(source.media_list_source.id.id); } +#elif BUILDFLAG(IS_LINUX) +#if defined(USE_OZONE_PLATFORM_X11) + // On Linux, with X11, the source id is the numeric value of the + // display name atom and the display id is either the EDID or the + // loop index when that display was found (see + // BuildDisplaysFromXRandRInfo in ui/base/x/x11_display_util.cc) + std::map monitor_atom_to_display_id = + MonitorAtomIdToDisplayId(); + for (auto& source : screen_sources) { + auto display_id_iter = + monitor_atom_to_display_id.find(source.media_list_source.id.id); + if (display_id_iter != monitor_atom_to_display_id.end()) + source.display_id = base::NumberToString(display_id_iter->second); + } +#endif // defined(USE_OZONE_PLATFORM_X11) #endif // BUILDFLAG(IS_WIN) - // TODO(ajmacd): Add Linux support. The IDs across APIs differ but Chrome - // only supports capturing the entire desktop on Linux. Revisit this if - // individual screen support is added. std::move(screen_sources.begin(), screen_sources.end(), std::back_inserter(captured_sources_)); } diff --git a/shell/browser/api/electron_api_web_contents.cc b/shell/browser/api/electron_api_web_contents.cc index 08da8b45bc314..f3da715f1c34b 100644 --- a/shell/browser/api/electron_api_web_contents.cc +++ b/shell/browser/api/electron_api_web_contents.cc @@ -1318,7 +1318,7 @@ void WebContents::EnterFullscreenModeForTab( auto callback = base::BindRepeating(&WebContents::OnEnterFullscreenModeForTab, base::Unretained(this), requesting_frame, options); - permission_helper->RequestFullscreenPermission(callback); + permission_helper->RequestFullscreenPermission(requesting_frame, callback); } void WebContents::OnEnterFullscreenModeForTab( diff --git a/shell/browser/browser_mac.mm b/shell/browser/browser_mac.mm index 1853c77714244..9c42648b998e9 100644 --- a/shell/browser/browser_mac.mm +++ b/shell/browser/browser_mac.mm @@ -444,6 +444,13 @@ image = native_image->image(); } + // This is needed when this fn is called before the browser + // process is ready, since supported scales are normally set + // by ui::ResourceBundle::InitSharedInstance + // during browser process startup. + if (!is_ready()) + gfx::ImageSkia::SetSupportedScales({1.0f}); + [[AtomApplication sharedApplication] setApplicationIconImage:image.AsNSImage()]; } diff --git a/shell/browser/electron_browser_client.cc b/shell/browser/electron_browser_client.cc index e6294a79c41fe..a93f90e9efeb5 100644 --- a/shell/browser/electron_browser_client.cc +++ b/shell/browser/electron_browser_client.cc @@ -49,6 +49,7 @@ #include "content/public/browser/tts_controller.h" #include "content/public/browser/tts_platform.h" #include "content/public/browser/url_loader_request_interceptor.h" +#include "content/public/browser/weak_document_ptr.h" #include "content/public/common/content_descriptors.h" #include "content/public/common/content_paths.h" #include "content/public/common/content_switches.h" @@ -987,7 +988,7 @@ void ElectronBrowserClient::WebNotificationAllowed( return; } permission_helper->RequestWebNotificationPermission( - base::BindOnce(std::move(callback), web_contents->IsAudioMuted())); + rfh, base::BindOnce(std::move(callback), web_contents->IsAudioMuted())); } void ElectronBrowserClient::RenderProcessHostDestroyed( @@ -1022,6 +1023,7 @@ void OnOpenExternal(const GURL& escaped_url, bool allowed) { void HandleExternalProtocolInUI( const GURL& url, + content::WeakDocumentPtr document_ptr, content::WebContents::OnceGetter web_contents_getter, bool has_user_gesture) { content::WebContents* web_contents = std::move(web_contents_getter).Run(); @@ -1033,9 +1035,18 @@ void HandleExternalProtocolInUI( if (!permission_helper) return; + content::RenderFrameHost* rfh = document_ptr.AsRenderFrameHostIfValid(); + if (!rfh) { + // If the render frame host is not valid it means it was a top level + // navigation and the frame has already been disposed of. In this case we + // take the current main frame and declare it responsible for the + // transition. + rfh = web_contents->GetPrimaryMainFrame(); + } + GURL escaped_url(base::EscapeExternalHandlerValue(url.spec())); auto callback = base::BindOnce(&OnOpenExternal, escaped_url); - permission_helper->RequestOpenExternalPermission(std::move(callback), + permission_helper->RequestOpenExternalPermission(rfh, std::move(callback), has_user_gesture, url); } @@ -1055,6 +1066,9 @@ bool ElectronBrowserClient::HandleExternalProtocol( content::GetUIThreadTaskRunner({})->PostTask( FROM_HERE, base::BindOnce(&HandleExternalProtocolInUI, url, + initiator_document + ? initiator_document->GetWeakDocumentPtr() + : content::WeakDocumentPtr(), std::move(web_contents_getter), has_user_gesture)); return true; } diff --git a/shell/browser/ui/drag_util_mac.mm b/shell/browser/ui/drag_util_mac.mm index 4c4649c6cb434..36656ea362941 100644 --- a/shell/browser/ui/drag_util_mac.mm +++ b/shell/browser/ui/drag_util_mac.mm @@ -20,7 +20,8 @@ @implementation DragDownloadItemSource - (NSDragOperation)draggingSession:(NSDraggingSession*)session sourceOperationMaskForDraggingContext:(NSDraggingContext)context { - return NSDragOperationEvery; + return context == NSDraggingContextOutsideApplication ? NSDragOperationCopy + : NSDragOperationEvery; } @end @@ -70,7 +71,7 @@ void DragFileItems(const std::vector& files, NSEvent* dragEvent = [NSEvent mouseEventWithType:NSEventTypeLeftMouseDragged location:position - modifierFlags:NSEventMaskLeftMouseDragged + modifierFlags:0 timestamp:eventTime windowNumber:[[native_view window] windowNumber] context:nil diff --git a/shell/browser/ui/views/win_caption_button.cc b/shell/browser/ui/views/win_caption_button.cc index 9903fecd3146d..9d90fc6a6fd27 100644 --- a/shell/browser/ui/views/win_caption_button.cc +++ b/shell/browser/ui/views/win_caption_button.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Modified from chrome/browser/ui/views/frame/windows_10_caption_button.cc +// Modified from chrome/browser/ui/views/frame/windows_caption_button.cc #include "shell/browser/ui/views/win_caption_button.h" diff --git a/shell/browser/ui/views/win_icon_painter.cc b/shell/browser/ui/views/win_icon_painter.cc index d61a7970c6705..d89d63d439051 100644 --- a/shell/browser/ui/views/win_icon_painter.cc +++ b/shell/browser/ui/views/win_icon_painter.cc @@ -25,7 +25,7 @@ void DrawRect(gfx::Canvas* canvas, void DrawRoundRect(gfx::Canvas* canvas, const gfx::Rect& rect, - int radius, + float radius, const cc::PaintFlags& flags) { gfx::RectF rect_f(rect); float stroke_half_width = flags.getStrokeWidth() / 2; @@ -74,7 +74,7 @@ void WinIconPainter::PaintMaximizeIcon(gfx::Canvas* canvas, void WinIconPainter::PaintRestoreIcon(gfx::Canvas* canvas, const gfx::Rect& symbol_rect, const cc::PaintFlags& flags) { - const int separation = std::floor(2 * canvas->image_scale()); + const int separation = base::ClampFloor(2 * canvas->image_scale()); gfx::Rect icon_rect = symbol_rect; icon_rect.Inset(gfx::Insets::TLBR(separation, 0, 0, separation)); @@ -113,14 +113,14 @@ void Win11IconPainter::PaintMaximizeIcon(gfx::Canvas* canvas, cc::PaintFlags paint_flags = flags; paint_flags.setAntiAlias(true); - const float corner_radius = 2 * canvas->image_scale(); + const float corner_radius = canvas->image_scale(); DrawRoundRect(canvas, symbol_rect, corner_radius, flags); } void Win11IconPainter::PaintRestoreIcon(gfx::Canvas* canvas, const gfx::Rect& symbol_rect, const cc::PaintFlags& flags) { - const int separation = std::floor(2 * canvas->image_scale()); + const int separation = base::ClampFloor(2 * canvas->image_scale()); gfx::Rect icon_rect = symbol_rect; icon_rect.Inset(gfx::Insets::TLBR(separation, 0, 0, separation)); @@ -128,14 +128,11 @@ void Win11IconPainter::PaintRestoreIcon(gfx::Canvas* canvas, paint_flags.setAntiAlias(true); // Bottom left ("in front") rounded square. - const float bottom_rect_radius = 1 * canvas->image_scale(); + const float bottom_rect_radius = canvas->image_scale(); DrawRoundRect(canvas, icon_rect, bottom_rect_radius, flags); // Top right ("behind") top+right edges of rounded square (2.5x). icon_rect.Offset(separation, -separation); - // Apply inset to left+bottom edges since we don't draw arcs for those edges - constexpr int top_rect_inset = 1; - icon_rect.Inset(gfx::Insets::TLBR(0, top_rect_inset, top_rect_inset, 0)); const float top_rect_radius = 2.5f * canvas->image_scale(); DrawRoundRectEdges(canvas, icon_rect, top_rect_radius, flags); diff --git a/shell/browser/web_contents_permission_helper.cc b/shell/browser/web_contents_permission_helper.cc index d12ee24602dc0..4e304e2e326e0 100644 --- a/shell/browser/web_contents_permission_helper.cc +++ b/shell/browser/web_contents_permission_helper.cc @@ -61,16 +61,16 @@ WebContentsPermissionHelper::WebContentsPermissionHelper( WebContentsPermissionHelper::~WebContentsPermissionHelper() = default; void WebContentsPermissionHelper::RequestPermission( + content::RenderFrameHost* requesting_frame, blink::PermissionType permission, base::OnceCallback callback, bool user_gesture, const base::DictionaryValue* details) { - auto* rfh = web_contents_->GetMainFrame(); auto* permission_manager = static_cast( web_contents_->GetBrowserContext()->GetPermissionControllerDelegate()); auto origin = web_contents_->GetLastCommittedURL(); permission_manager->RequestPermissionWithDetails( - permission, rfh, origin, false, details, + permission, requesting_frame, origin, false, details, base::BindOnce(&OnPermissionResponse, std::move(callback))); } @@ -86,8 +86,10 @@ bool WebContentsPermissionHelper::CheckPermission( } void WebContentsPermissionHelper::RequestFullscreenPermission( + content::RenderFrameHost* requesting_frame, base::OnceCallback callback) { RequestPermission( + requesting_frame, static_cast(PermissionType::FULLSCREEN), std::move(callback)); } @@ -113,13 +115,17 @@ void WebContentsPermissionHelper::RequestMediaAccessPermission( // The permission type doesn't matter here, AUDIO_CAPTURE/VIDEO_CAPTURE // are presented as same type in content_converter.h. - RequestPermission(blink::PermissionType::AUDIO_CAPTURE, std::move(callback), + RequestPermission(content::RenderFrameHost::FromID(request.render_process_id, + request.render_frame_id), + blink::PermissionType::AUDIO_CAPTURE, std::move(callback), false, &details); } void WebContentsPermissionHelper::RequestWebNotificationPermission( + content::RenderFrameHost* requesting_frame, base::OnceCallback callback) { - RequestPermission(blink::PermissionType::NOTIFICATIONS, std::move(callback)); + RequestPermission(requesting_frame, blink::PermissionType::NOTIFICATIONS, + std::move(callback)); } void WebContentsPermissionHelper::RequestPointerLockPermission( @@ -128,6 +134,7 @@ void WebContentsPermissionHelper::RequestPointerLockPermission( base::OnceCallback callback) { RequestPermission( + web_contents_->GetPrimaryMainFrame(), static_cast(PermissionType::POINTER_LOCK), base::BindOnce(std::move(callback), web_contents_, user_gesture, last_unlocked_by_target), @@ -135,12 +142,14 @@ void WebContentsPermissionHelper::RequestPointerLockPermission( } void WebContentsPermissionHelper::RequestOpenExternalPermission( + content::RenderFrameHost* requesting_frame, base::OnceCallback callback, bool user_gesture, const GURL& url) { base::DictionaryValue details; details.SetString("externalURL", url.spec()); RequestPermission( + requesting_frame, static_cast(PermissionType::OPEN_EXTERNAL), std::move(callback), user_gesture, &details); } diff --git a/shell/browser/web_contents_permission_helper.h b/shell/browser/web_contents_permission_helper.h index cfd4fc4600dcc..948c1914a5154 100644 --- a/shell/browser/web_contents_permission_helper.h +++ b/shell/browser/web_contents_permission_helper.h @@ -33,7 +33,8 @@ class WebContentsPermissionHelper }; // Asynchronous Requests - void RequestFullscreenPermission(base::OnceCallback callback); + void RequestFullscreenPermission(content::RenderFrameHost* requesting_frame, + base::OnceCallback callback); void RequestMediaAccessPermission(const content::MediaStreamRequest& request, content::MediaResponseCallback callback); void RequestPointerLockPermission( @@ -42,8 +43,10 @@ class WebContentsPermissionHelper base::OnceCallback callback); void RequestWebNotificationPermission( + content::RenderFrameHost* requesting_frame, base::OnceCallback callback); - void RequestOpenExternalPermission(base::OnceCallback callback, + void RequestOpenExternalPermission(content::RenderFrameHost* requesting_frame, + base::OnceCallback callback, bool user_gesture, const GURL& url); @@ -56,7 +59,8 @@ class WebContentsPermissionHelper explicit WebContentsPermissionHelper(content::WebContents* web_contents); friend class content::WebContentsUserData; - void RequestPermission(blink::PermissionType permission, + void RequestPermission(content::RenderFrameHost* requesting_frame, + blink::PermissionType permission, base::OnceCallback callback, bool user_gesture = false, const base::DictionaryValue* details = nullptr); diff --git a/shell/common/node_bindings.cc b/shell/common/node_bindings.cc index 6ed9786eafe68..dd95b149d468b 100644 --- a/shell/common/node_bindings.cc +++ b/shell/common/node_bindings.cc @@ -491,19 +491,22 @@ node::Environment* NodeBindings::CreateEnvironment( flags |= node::EnvironmentFlags::kNoStartDebugSignalHandler; } - v8::TryCatch try_catch(isolate); - env = node::CreateEnvironment( - isolate_data_, context, args, exec_args, - static_cast(flags)); - - if (try_catch.HasCaught()) { - std::string err_msg = - "Failed to initialize node environment in process: " + process_type; - v8::Local message = try_catch.Message(); - std::string msg; - if (!message.IsEmpty() && gin::ConvertFromV8(isolate, message->Get(), &msg)) - err_msg += " , with error: " + msg; - LOG(ERROR) << err_msg; + { + v8::TryCatch try_catch(isolate); + env = node::CreateEnvironment( + isolate_data_, context, args, exec_args, + static_cast(flags)); + + if (try_catch.HasCaught()) { + std::string err_msg = + "Failed to initialize node environment in process: " + process_type; + v8::Local message = try_catch.Message(); + std::string msg; + if (!message.IsEmpty() && + gin::ConvertFromV8(isolate, message->Get(), &msg)) + err_msg += " , with error: " + msg; + LOG(ERROR) << err_msg; + } } DCHECK(env); diff --git a/spec-main/api-browser-view-spec.ts b/spec-main/api-browser-view-spec.ts index ef32bef9feaa2..d7ff94223f7c8 100644 --- a/spec-main/api-browser-view-spec.ts +++ b/spec-main/api-browser-view-spec.ts @@ -63,7 +63,7 @@ describe('BrowserView module', () => { }); // Linux and arm64 platforms (WOA and macOS) do not return any capture sources - ifit(process.platform !== 'linux' && process.arch !== 'arm64')('sets the background color to transparent if none is set', async () => { + ifit(process.platform === 'darwin' && process.arch === 'x64')('sets the background color to transparent if none is set', async () => { const display = screen.getPrimaryDisplay(); const WINDOW_BACKGROUND_COLOR = '#55ccbb'; @@ -87,7 +87,7 @@ describe('BrowserView module', () => { }); // Linux and arm64 platforms (WOA and macOS) do not return any capture sources - ifit(process.platform !== 'linux' && process.arch !== 'arm64')('successfully applies the background color', async () => { + ifit(process.platform === 'darwin' && process.arch === 'x64')('successfully applies the background color', async () => { const WINDOW_BACKGROUND_COLOR = '#55ccbb'; const VIEW_BACKGROUND_COLOR = '#ff00ff'; const display = screen.getPrimaryDisplay(); diff --git a/spec-main/api-browser-window-spec.ts b/spec-main/api-browser-window-spec.ts index 4d4b083be5624..1d9bac034a593 100644 --- a/spec-main/api-browser-window-spec.ts +++ b/spec-main/api-browser-window-spec.ts @@ -567,6 +567,10 @@ describe('BrowserWindow module', () => { targetId: iframeTarget.targetId, flatten: true }); + let willNavigateEmitted = false; + w.webContents.on('will-navigate', () => { + willNavigateEmitted = true; + }); await w.webContents.debugger.sendCommand('Input.dispatchMouseEvent', { type: 'mousePressed', x: 10, @@ -581,10 +585,6 @@ describe('BrowserWindow module', () => { clickCount: 1, button: 'left' }, sessionId); - let willNavigateEmitted = false; - w.webContents.on('will-navigate', () => { - willNavigateEmitted = true; - }); await emittedOnce(w.webContents, 'did-navigate'); expect(willNavigateEmitted).to.be.true(); }); @@ -5585,7 +5585,7 @@ describe('BrowserWindow module', () => { }); // Linux and arm64 platforms (WOA and macOS) do not return any capture sources - ifit(process.platform !== 'linux' && process.arch !== 'arm64')('should not display a visible background', async () => { + ifit(process.platform === 'darwin' && process.arch !== 'arm64')('should not display a visible background', async () => { const display = screen.getPrimaryDisplay(); const backgroundWindow = new BrowserWindow({ @@ -5627,7 +5627,7 @@ describe('BrowserWindow module', () => { afterEach(closeAllWindows); // Linux/WOA doesn't return any capture sources. - ifit(process.platform !== 'linux' && (process.platform !== 'win32' || process.arch !== 'arm64'))('should display the set color', async () => { + ifit(process.platform === 'darwin')('should display the set color', async () => { const display = screen.getPrimaryDisplay(); const w = new BrowserWindow({ diff --git a/spec-main/api-power-monitor-spec.ts b/spec-main/api-power-monitor-spec.ts index c1f55fc5606ae..1867e8f97b0e3 100644 --- a/spec-main/api-power-monitor-spec.ts +++ b/spec-main/api-power-monitor-spec.ts @@ -14,8 +14,7 @@ import { promisify } from 'util'; describe('powerMonitor', () => { let logindMock: any, dbusMockPowerMonitor: any, getCalls: any, emitSignal: any, reset: any; - // TODO(deepak1556): Enable on arm64 after upgrade, it crashes at the moment. - ifdescribe(process.platform === 'linux' && process.arch !== 'arm64' && process.env.DBUS_SYSTEM_BUS_ADDRESS != null)('when powerMonitor module is loaded with dbus mock', () => { + ifdescribe(process.platform === 'linux' && process.env.DBUS_SYSTEM_BUS_ADDRESS != null)('when powerMonitor module is loaded with dbus mock', () => { before(async () => { const systemBus = dbus.systemBus(); const loginService = systemBus.getService('org.freedesktop.login1'); diff --git a/spec-main/api-web-contents-spec.ts b/spec-main/api-web-contents-spec.ts index 71ca36b9f94e9..cca45842e10f3 100644 --- a/spec-main/api-web-contents-spec.ts +++ b/spec-main/api-web-contents-spec.ts @@ -340,6 +340,12 @@ describe('webContents module', () => { await expect(w.loadFile(path.join(fixturesPath, 'pages', 'base-page.html'))).to.eventually.be.fulfilled(); }); + it('resolves when navigating within the page', async () => { + await w.loadFile(path.join(fixturesPath, 'pages', 'base-page.html')); + await new Promise(resolve => setTimeout(resolve)); + await expect(w.loadURL(w.getURL() + '#foo')).to.eventually.be.fulfilled(); + }); + it('rejects when failing to load a file URL', async () => { await expect(w.loadURL('file:non-existent')).to.eventually.be.rejected() .and.have.property('code', 'ERR_FILE_NOT_FOUND'); diff --git a/spec-main/chromium-spec.ts b/spec-main/chromium-spec.ts index fea30d87732eb..ecb716ef020c3 100644 --- a/spec-main/chromium-spec.ts +++ b/spec-main/chromium-spec.ts @@ -1864,6 +1864,54 @@ describe('navigator.serial', () => { }); }); +describe('window.getScreenDetails', () => { + let w: BrowserWindow; + before(async () => { + w = new BrowserWindow({ + show: false + }); + await w.loadFile(path.join(fixturesPath, 'pages', 'blank.html')); + }); + + after(closeAllWindows); + afterEach(() => { + session.defaultSession.setPermissionRequestHandler(null); + }); + + const getScreenDetails: any = () => { + return w.webContents.executeJavaScript('window.getScreenDetails().then(data => data.screens).catch(err => err.message)', true); + }; + + it('returns screens when a PermissionRequestHandler is not defined', async () => { + const screens = await getScreenDetails(); + expect(screens).to.not.equal('Read permission denied.'); + }); + + it('returns an error when permission denied', async () => { + session.defaultSession.setPermissionRequestHandler((wc, permission, callback) => { + if (permission === 'window-placement') { + callback(false); + } else { + callback(true); + } + }); + const screens = await getScreenDetails(); + expect(screens).to.equal('Permission denied.'); + }); + + it('returns screens when permission is granted', async () => { + session.defaultSession.setPermissionRequestHandler((wc, permission, callback) => { + if (permission === 'window-placement') { + callback(true); + } else { + callback(false); + } + }); + const screens = await getScreenDetails(); + expect(screens).to.not.equal('Permission denied.'); + }); +}); + describe('navigator.clipboard', () => { let w: BrowserWindow; before(async () => { @@ -2122,9 +2170,7 @@ describe('navigator.hid', () => { } else { expect(device).to.equal(''); } - if (process.arch === 'arm64' || process.arch === 'arm') { - // arm CI returns HID devices - this block may need to change if CI hardware changes. - expect(haveDevices).to.be.true(); + if (haveDevices) { // Verify that navigation will clear device permissions const grantedDevices = await w.webContents.executeJavaScript('navigator.hid.getDevices()'); expect(grantedDevices).to.not.be.empty(); diff --git a/spec-main/crash-spec.ts b/spec-main/crash-spec.ts index 803d9117d1a13..dae3c75cec4a2 100644 --- a/spec-main/crash-spec.ts +++ b/spec-main/crash-spec.ts @@ -31,6 +31,22 @@ const runFixtureAndEnsureCleanExit = (args: string[]) => { }); }; +const shouldRunCase = (crashCase: string) => { + switch (crashCase) { + // TODO(jkleinsc) fix this flaky test on Windows 32-bit + case 'quit-on-crashed-event': { + return (process.platform !== 'win32' || process.arch !== 'ia32'); + } + // TODO(jkleinsc) fix this test on Linux on arm/arm64 + case 'js-execute-iframe': { + return (process.platform !== 'linux' || (process.arch !== 'arm64' && process.arch !== 'arm')); + } + default: { + return true; + } + } +}; + describe('crash cases', () => { afterEach(() => { for (const child of children) { @@ -42,8 +58,7 @@ describe('crash cases', () => { const cases = fs.readdirSync(fixturePath); for (const crashCase of cases) { - // TODO(jkleinsc) fix this flaky test on Windows 32-bit - ifit(process.platform !== 'win32' || process.arch !== 'ia32' || crashCase !== 'quit-on-crashed-event')(`the "${crashCase}" case should not crash`, () => { + ifit(shouldRunCase(crashCase))(`the "${crashCase}" case should not crash`, () => { const fixture = path.resolve(fixturePath, crashCase); const argsFile = path.resolve(fixture, 'electron.args'); const args = [fixture]; diff --git a/spec-main/modules-spec.ts b/spec-main/modules-spec.ts index a83797961fcf7..0cebbbeb642d9 100644 --- a/spec-main/modules-spec.ts +++ b/spec-main/modules-spec.ts @@ -183,4 +183,16 @@ describe('modules support', () => { }); }); }); + + describe('esm', () => { + it('can load the built-in "electron" module via ESM import', async () => { + await expect(import('electron')).to.eventually.be.ok(); + }); + + it('the built-in "electron" module loaded via ESM import has the same exports as the CJS module', async () => { + const esmElectron = await import('electron'); + const cjsElectron = require('electron'); + expect(Object.keys(esmElectron)).to.deep.equal(Object.keys(cjsElectron)); + }); + }); }); diff --git a/spec-main/version-bump-spec.ts b/spec-main/version-bump-spec.ts index ef37d871b77d4..e78f5da40d59d 100644 --- a/spec-main/version-bump-spec.ts +++ b/spec-main/version-bump-spec.ts @@ -1,15 +1,9 @@ import { expect } from 'chai'; import { GitProcess, IGitExecutionOptions, IGitResult } from 'dugite'; -import { nextVersion, shouldUpdateSupported, updateSupported } from '../script/release/version-bumper'; +import { nextVersion } from '../script/release/version-bumper'; import * as utils from '../script/release/version-utils'; import * as sinon from 'sinon'; import { ifdescribe } from './spec-helpers'; -const { promises: fs } = require('fs'); -const path = require('path'); - -const fixtureDir = path.resolve(__dirname, 'fixtures', 'version-bumper', 'fixture_support.md'); -const readFile = fs.readFile; -const writeFile = fs.writeFile; class GitFake { branches: { @@ -96,94 +90,6 @@ describe('version-bumper', () => { }); }); - describe('updateSupported', () => { - let restore: any; - before(async () => { - restore = await readFile(fixtureDir, 'utf8'); - }); - - afterEach(async () => { - await writeFile(fixtureDir, restore, 'utf8'); - }); - - it('updates correctly when a new stable version is promoted from beta', async () => { - const version = '4.0.0'; - const currentVersion = '4.0.0-beta.29'; - if (shouldUpdateSupported('stable', currentVersion, version)) { - await updateSupported(version, fixtureDir); - } - const contents = await readFile(fixtureDir, 'utf8'); - - expect(contents).to.contain('4.x.y\n* 3.x.y\n* 2.x.y'); - }); - - it('should not update when a new stable patch version is promoted', async () => { - const version = '3.0.1'; - const currentVersion = '3.0.0'; - if (shouldUpdateSupported('stable', currentVersion, version)) { - await updateSupported(version, fixtureDir); - } - const contents = await readFile(fixtureDir, 'utf8'); - - expect(contents).to.contain('3.x.y\n* 2.x.y\n* 1.x.y'); - }); - - it('should not update when a new stable minor version is promoted', async () => { - const version = '3.1.0'; - const currentVersion = '3.0.0'; - if (shouldUpdateSupported('minor', currentVersion, version)) { - await updateSupported(version, fixtureDir); - } - const contents = await readFile(fixtureDir, 'utf8'); - - expect(contents).to.contain('3.x.y\n* 2.x.y\n* 1.x.y'); - }); - - it('should not update when a new beta.1 version is promoted', async () => { - const version = '5.0.0-beta.1'; - const currentVersion = '4.0.0-beta.29'; - if (shouldUpdateSupported('beta', currentVersion, version)) { - await updateSupported(version, fixtureDir); - } - const contents = await readFile(fixtureDir, 'utf8'); - - expect(contents).to.contain('3.x.y\n* 2.x.y\n* 1.x.y'); - }); - - it('should not update when a new beta.12 version is promoted', async () => { - const version = '4.0.0-beta.12'; - const currentVersion = '4.0.0-beta.11'; - if (shouldUpdateSupported('beta', currentVersion, version)) { - await updateSupported(version, fixtureDir); - } - const contents = await readFile(fixtureDir, 'utf8'); - - expect(contents).to.contain('3.x.y\n* 2.x.y\n* 1.x.y'); - }); - - it('should update when a new major nightly version is promoted', async () => { - const version = '4.0.0-nightly.19950901'; - const currentVersion = '3.0.0-nightly.19950828'; - if (shouldUpdateSupported('nightly', currentVersion, version)) { - await updateSupported(version, fixtureDir); - } - const contents = await readFile(fixtureDir, 'utf8'); - - expect(contents).to.contain('4.x.y\n* 3.x.y\n* 2.x.y'); - }); - - it('should not update when a new nightly version is promoted', async () => { - const version = '3.0.0-nightly.19950901'; - const currentVersion = '3.0.0-nightly.19950828'; - if (shouldUpdateSupported('nightly', currentVersion, version)) { - await updateSupported(version, fixtureDir); - } - const contents = await readFile(fixtureDir, 'utf8'); - - expect(contents).to.contain('3.x.y\n* 2.x.y\n* 1.x.y'); - }); - }); - // On macOS Circle CI we don't have a real git environment due to running // gclient sync on a linux machine. These tests therefore don't run as expected. ifdescribe(!(process.platform === 'linux' && process.arch.indexOf('arm') === 0) && process.platform !== 'darwin')('nextVersion', () => { diff --git a/spec/fixtures/test.asar/repack.js b/spec/fixtures/test.asar/repack.js index 1220b595a8ecf..4a02b6f4cca6e 100644 --- a/spec/fixtures/test.asar/repack.js +++ b/spec/fixtures/test.asar/repack.js @@ -1,7 +1,7 @@ // Use this script to regenerate these fixture files // using a new version of the asar package -const asar = require('asar'); +const asar = require('@electron/asar'); const fs = require('fs'); const os = require('os'); const path = require('path'); diff --git a/yarn.lock b/yarn.lock index 226aae6f5b92c..b6b35abeb30af 100644 --- a/yarn.lock +++ b/yarn.lock @@ -106,10 +106,22 @@ esutils "^2.0.2" js-tokens "^4.0.0" -"@electron/docs-parser@^0.12.4": - version "0.12.4" - resolved "https://registry.yarnpkg.com/@electron/docs-parser/-/docs-parser-0.12.4.tgz#cca403c8c2200181339c3115cdd25f3fbfc7dea3" - integrity sha512-vdkjcvkI7zTd2v1A8qsl5+HY+9AQCrW5Eh60I9rhPtUPoxo2V1pQwogTW6kzc3XZ54crTa7R3KxwkZpSbcGCug== +"@electron/asar@^3.2.1": + version "3.2.1" + resolved "https://registry.yarnpkg.com/@electron/asar/-/asar-3.2.1.tgz#c4143896f3dd43b59a80a9c9068d76f77efb62ea" + integrity sha512-hE2cQMZ5+4o7+6T2lUaVbxIzrOjZZfX7dB02xuapyYFJZEAiWTelq6J3mMoxzd0iONDvYLPVKecB5tyjIoVDVA== + dependencies: + chromium-pickle-js "^0.2.0" + commander "^5.0.0" + glob "^7.1.6" + minimatch "^3.0.4" + optionalDependencies: + "@types/glob" "^7.1.1" + +"@electron/docs-parser@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@electron/docs-parser/-/docs-parser-1.0.0.tgz#1844ed2e18528ea56aaef0ace1cfa0633a6fa1b1" + integrity sha512-nIqEO8Ga6LavdaY2aJMPfq2vSOPVlgOvNv7jpiyaoqsAz5vYnWNUnxeCyaalCaDyFiKhVeHbKwP8Kt2TENwneg== dependencies: "@types/markdown-it" "^10.0.0" chai "^4.2.0" @@ -121,10 +133,10 @@ ora "^4.0.3" pretty-ms "^5.1.0" -"@electron/typescript-definitions@^8.9.5": - version "8.9.5" - resolved "https://registry.yarnpkg.com/@electron/typescript-definitions/-/typescript-definitions-8.9.5.tgz#e6cb08e0e7c9656e178b892eab50866a8a80bf7a" - integrity sha512-xDLFl6joGpA8c9cGSPWC3DFHyIGf9+OWZmDrPbGJW1URt6C1ukdQWKSmjb1Rttb94QQxBrGuUlSyz27IQgLFsw== +"@electron/typescript-definitions@^8.10.0": + version "8.10.0" + resolved "https://registry.yarnpkg.com/@electron/typescript-definitions/-/typescript-definitions-8.10.0.tgz#e9cf2b329ec4b0b76947ef751725383a6cf8994d" + integrity sha512-FVc2y0GUfxFZDoma0scYiMxkoalle19Fq332fNFGWoCJ9rCj5OUvriewSjPtGBsRuHv2xaMS5MhBuy2/pRuFuQ== dependencies: "@types/node" "^11.13.7" chalk "^2.4.2" @@ -1162,18 +1174,6 @@ arrify@^1.0.0: resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= -asar@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/asar/-/asar-3.1.0.tgz#70b0509449fe3daccc63beb4d3c7d2e24d3c6473" - integrity sha512-vyxPxP5arcAqN4F/ebHd/HhwnAiZtwhglvdmc7BR2f0ywbVNTOpSeyhLDbGXtE/y58hv1oC75TaNIXutnsOZsQ== - dependencies: - chromium-pickle-js "^0.2.0" - commander "^5.0.0" - glob "^7.1.6" - minimatch "^3.0.4" - optionalDependencies: - "@types/glob" "^7.1.1" - asn1.js@^4.0.0: version "4.10.1" resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" @@ -1838,7 +1838,7 @@ component-emitter@^1.2.1: concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== concat-stream@^1.5.0: version "1.6.2" @@ -4961,9 +4961,9 @@ minimalistic-crypto-utils@^1.0.1: integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= minimatch@^3.0.2, minimatch@^3.0.4, minimatch@~3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + version "3.0.8" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.8.tgz#5e6a59bd11e2ab0de1cfb843eb2d82e546c321c1" + integrity sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q== dependencies: brace-expansion "^1.1.7"