diff --git a/.circleci/config.yml b/.circleci/config.yml index ab81b1c403525..33a52f19f8e60 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -57,6 +57,16 @@ parameters: type: boolean default: false +# Executors +executors: + linux-arm: + resource_class: electronjs/linux-arm + machine: true + + linux-arm64: + resource_class: electronjs/linux-arm64 + machine: true + # The config expects the following environment variables to be set: # - "SLACK_WEBHOOK" Slack hook URL to send notifications. # @@ -69,7 +79,7 @@ parameters: # Build machines configs. docker-image: &docker-image docker: - - image: electron.azurecr.io/build:4cec2c5ab66765caa724e37bae2bffb9b29722a5 + - image: electron.azurecr.io/build:d818f06a9b1540c7fd38f75ad5a2c493dd6843b6 machine-linux-medium: &machine-linux-medium <<: *docker-image @@ -225,6 +235,25 @@ step-maybe-notify-slack-success: &step-maybe-notify-slack-success fi when: on_success +step-maybe-cleanup-arm: &step-maybe-cleanup-arm + run: + name: Cleanup after testing + command: | + if [ "$TARGET_ARCH" == "arm64" ] &&[ "`uname`" == "Darwin" ]; then + killall Electron || echo "No Electron processes left running" + killall Safari || echo "No Safari processes left running" + rm -rf ~/Library/Application\ Support/Electron* + rm -rf ~/Library/Application\ Support/electron* + elif [ "$TARGET_ARCH" == "arm" ] || [ "$TARGET_ARCH" == "arm64" ]; then + XVFB=/usr/bin/Xvfb + /sbin/start-stop-daemon --stop --exec $XVFB || echo "Xvfb not running" + pkill electron || echo "electron not running" + rm -rf ~/.config/Electron* + rm -rf ~/.config/electron* + fi + + when: always + step-checkout-electron: &step-checkout-electron checkout: path: src/electron @@ -261,7 +290,7 @@ step-gclient-sync: &step-gclient-sync if ! git diff-index --quiet HEAD --; then # There are changes to the patches. Make a git commit with the updated patches git add patches - GIT_COMMITTER_NAME="Electron Bot" GIT_COMMITTER_EMAIL="electron@github.com" git commit -m "update patches" --author="Electron Bot " + GIT_COMMITTER_NAME="PatchUp" GIT_COMMITTER_EMAIL="73610968+patchup[bot]@users.noreply.github.com" git commit -m "chore: update patches" --author="PatchUp <73610968+patchup[bot]@users.noreply.github.com>" # Export it mkdir -p ../../patches git format-patch -1 --stdout --keep-subject --no-stat --full-index > ../../patches/update-patches.patch @@ -308,6 +337,7 @@ step-setup-goma-for-build: &step-setup-goma-for-build npm install mkdir third_party node -e "require('./src/utils/goma.js').downloadAndPrepare({ gomaOneForAll: true })" + export GOMA_FALLBACK_ON_AUTH_FAILURE=true third_party/goma/goma_ctl.py ensure_start echo 'export GN_GOMA_FILE='`node -e "console.log(require('./src/utils/goma.js').gnFilePath)"` >> $BASH_ENV echo 'export LOCAL_GOMA_DIR='`node -e "console.log(require('./src/utils/goma.js').dir)"` >> $BASH_ENV @@ -517,6 +547,7 @@ step-electron-build: &step-electron-build ninja -C out/Default electron:electron_mksnapshot_zip -j $NUMBER_OF_NINJA_PROCESSES ninja -C out/Default tools/v8_context_snapshot -j $NUMBER_OF_NINJA_PROCESSES gn desc out/Default v8:run_mksnapshot_default args > out/Default/mksnapshot_args + (cd out/Default; zip mksnapshot.zip mksnapshot_args clang_x64_v8_arm64/gen/v8/embedded.S) rm -rf out/Default/clang_x64_v8_arm64/obj # Regenerate because we just deleted some ninja files @@ -671,6 +702,7 @@ step-persist-data-for-tests: &step-persist-data-for-tests - src/electron - src/third_party/electron_node - src/third_party/nan + - src/cross-arch-snapshots step-electron-dist-unzip: &step-electron-dist-unzip run: @@ -733,7 +765,11 @@ step-verify-mksnapshot: &step-verify-mksnapshot name: Verify mksnapshot command: | cd src - python electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default + if [ "$TARGET_ARCH" == "arm" ] || [ "$TARGET_ARCH" == "arm64" ]; then + python electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default --snapshot-files-dir $PWD/cross-arch-snapshots + else + python electron/script/verify-mksnapshot.py --source-root "$PWD" --build-dir out/Default + fi step-verify-chromedriver: &step-verify-chromedriver run: @@ -860,23 +896,6 @@ step-maybe-cross-arch-snapshot-store: &step-maybe-cross-arch-snapshot-store path: src/cross-arch-snapshots destination: cross-arch-snapshots -step-maybe-trigger-arm-test: &step-maybe-trigger-arm-test - run: - name: Trigger an arm test on VSTS if applicable - command: | - cd src - # Only run for non-fork prs - if [ "$TRIGGER_ARM_TEST" == "true" ] && [ -z "$CIRCLE_PR_NUMBER" ]; then - #Trigger VSTS job, passing along CircleCI job number and branch to build - if [ "`uname`" == "Darwin" ]; then - echo "Triggering electron-arm2-testing build on Azure DevOps" - node electron/script/release/ci-release-build.js --job=electron-arm2-testing --ci=DevOps --armTest --circleBuildNum=$CIRCLE_BUILD_NUM $CIRCLE_BRANCH - else - echo "Triggering electron-$TARGET_ARCH-testing build on VSTS" - node electron/script/release/ci-release-build.js --job=electron-$TARGET_ARCH-testing --ci=VSTS --armTest --circleBuildNum=$CIRCLE_BUILD_NUM $CIRCLE_BRANCH - fi - fi - step-maybe-generate-typescript-defs: &step-maybe-generate-typescript-defs run: name: Generate type declarations @@ -1291,8 +1310,14 @@ steps-tests: &steps-tests ELECTRON_DISABLE_SECURITY_WARNINGS: 1 command: | cd src - (cd electron && node script/yarn test --runners=main --trace-uncaught --enable-logging --files $(circleci tests glob spec-main/*-spec.ts | circleci tests split)) - (cd electron && node script/yarn test --runners=remote --trace-uncaught --enable-logging --files $(circleci tests glob spec/*-spec.js | circleci tests split)) + if [ "$TARGET_ARCH" == "arm" ] || [ "$TARGET_ARCH" == "arm64" ]; then + export ELECTRON_SKIP_NATIVE_MODULE_TESTS=true + (cd electron && node script/yarn test --runners=main --trace-uncaught --enable-logging) + (cd electron && node script/yarn test --runners=remote --trace-uncaught --enable-logging) + else + (cd electron && node script/yarn test --runners=main --trace-uncaught --enable-logging --files $(circleci tests glob spec-main/*-spec.ts | circleci tests split)) + (cd electron && node script/yarn test --runners=remote --trace-uncaught --enable-logging --files $(circleci tests glob spec/*-spec.js | circleci tests split)) + fi - run: name: Check test results existence command: | @@ -1313,6 +1338,8 @@ steps-tests: &steps-tests - *step-maybe-notify-slack-failure + - *step-maybe-cleanup-arm + steps-test-nan: &steps-test-nan steps: - attach_workspace: @@ -1588,9 +1615,6 @@ commands: steps: - *step-save-out-cache - # Trigger tests on arm hardware if needed - - *step-maybe-trigger-arm-test - - *step-maybe-notify-slack-failure electron-publish: @@ -1918,7 +1942,7 @@ jobs: GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' steps: - electron-build: - persist: false + persist: true checkout: true use-out-cache: false @@ -1976,7 +2000,7 @@ jobs: GCLIENT_EXTRA_ARGS: '--custom-var=checkout_arm=True --custom-var=checkout_arm64=True' steps: - electron-build: - persist: false + persist: true checkout: true use-out-cache: false @@ -2364,6 +2388,24 @@ jobs: <<: *env-send-slack-notifications <<: *steps-verify-ffmpeg + linux-arm-testing-tests: + executor: linux-arm + environment: + <<: *env-arm + <<: *env-global + <<: *env-headless-testing + <<: *env-stack-dumping + <<: *steps-tests + + linux-arm64-testing-tests: + executor: linux-arm64 + environment: + <<: *env-arm64 + <<: *env-global + <<: *env-headless-testing + <<: *env-stack-dumping + <<: *steps-tests + osx-testing-x64-tests: <<: *machine-mac-large environment: @@ -2596,8 +2638,23 @@ workflows: - linux-ia32-testing - linux-arm-testing + - linux-arm-testing-tests: + filters: + branches: + # Do not run this on forked pull requests + ignore: /pull\/[0-9]+/ + requires: + - linux-arm-testing - linux-arm64-testing + - linux-arm64-testing-tests: + filters: + branches: + # Do not run this on forked pull requests + ignore: /pull\/[0-9]+/ + requires: + - linux-arm64-testing + - linux-arm64-testing-gn-check: requires: - linux-checkout-fast diff --git a/ELECTRON_VERSION b/ELECTRON_VERSION index 6453fa4737d57..2ff206b07c9a6 100644 --- a/ELECTRON_VERSION +++ b/ELECTRON_VERSION @@ -1 +1 @@ -11.4.6 \ No newline at end of file +11.5.0 \ No newline at end of file diff --git a/README.md b/README.md index 50e3bc1cbe4ef..a5cbcae7f99cd 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/4lggi9dpjc1qob7k/branch/master?svg=true)](https://ci.appveyor.com/project/electron-bot/electron-ljo26/branch/master) [![devDependency Status](https://david-dm.org/electron/electron/dev-status.svg)](https://david-dm.org/electron/electron?type=dev) -:memo: Available Translations: 🇨🇳 🇹🇼 🇧🇷 🇪🇸 🇰🇷 🇯🇵 🇷🇺 🇫🇷 🇹🇭 🇳🇱 🇹🇷 🇮🇩 🇺🇦 🇨🇿 🇮🇹 🇵🇱. +:memo: Available Translations: 🇨🇳 🇧🇷 🇪🇸 🇯🇵 🇷🇺 🇫🇷 🇺🇸 🇩🇪. View these docs in other languages at [electron/i18n](https://github.com/electron/i18n/tree/master/content/). The Electron framework lets you write cross-platform desktop applications diff --git a/docs/api/command-line-switches.md b/docs/api/command-line-switches.md index ba3529835cd71..2bcaa37a409cf 100644 --- a/docs/api/command-line-switches.md +++ b/docs/api/command-line-switches.md @@ -79,7 +79,7 @@ This switch can not be used in `app.commandLine.appendSwitch` since it is parsed earlier than user's app is loaded, but you can set the `ELECTRON_ENABLE_LOGGING` environment variable to achieve the same effect. -## --force-fieldtrials=`trials` +### --force-fieldtrials=`trials` Field trials to be forcefully enabled or disabled. diff --git a/docs/api/dialog.md b/docs/api/dialog.md index a0ed591d8c415..e4f9fb98b15f9 100644 --- a/docs/api/dialog.md +++ b/docs/api/dialog.md @@ -154,7 +154,7 @@ dialog.showOpenDialog(mainWindow, { * `browserWindow` [BrowserWindow](browser-window.md) (optional) * `options` Object - * `title` String (optional) + * `title` String (optional) - The dialog title. Cannot be displayed on some _Linux_ desktop environments. * `defaultPath` String (optional) - Absolute directory path, absolute file path, or file name to use by default. * `buttonLabel` String (optional) - Custom label for the confirmation button, when @@ -185,7 +185,7 @@ The `filters` specifies an array of file types that can be displayed, see * `browserWindow` [BrowserWindow](browser-window.md) (optional) * `options` Object - * `title` String (optional) + * `title` String (optional) - The dialog title. Cannot be displayed on some _Linux_ desktop environments. * `defaultPath` String (optional) - Absolute directory path, absolute file path, or file name to use by default. * `buttonLabel` String (optional) - Custom label for the confirmation button, when diff --git a/docs/api/web-contents.md b/docs/api/web-contents.md index 68f72ff2d3f4f..37420bce217f2 100644 --- a/docs/api/web-contents.md +++ b/docs/api/web-contents.md @@ -1233,8 +1233,7 @@ Inserts `text` to the focused element. * `text` String - Content to be searched, must not be empty. * `options` Object (optional) * `forward` Boolean (optional) - Whether to search forward or backward, defaults to `true`. - * `findNext` Boolean (optional) - Whether the operation is first request or a follow up, - defaults to `false`. + * `findNext` Boolean (optional) - Whether to begin a new text finding session with this request. Should be `true` for initial requests, and `false` for follow-up requests. Defaults to `false`. * `matchCase` Boolean (optional) - Whether search should be case-sensitive, defaults to `false`. * `wordStart` Boolean (optional) - Whether to look only at the start of words. diff --git a/docs/api/webview-tag.md b/docs/api/webview-tag.md index e2f4ec4834e5f..08a6ed1b711be 100644 --- a/docs/api/webview-tag.md +++ b/docs/api/webview-tag.md @@ -515,8 +515,7 @@ Inserts `text` to the focused element. * `text` String - Content to be searched, must not be empty. * `options` Object (optional) * `forward` Boolean (optional) - Whether to search forward or backward, defaults to `true`. - * `findNext` Boolean (optional) - Whether the operation is first request or a follow up, - defaults to `false`. + * `findNext` Boolean (optional) - Whether to begin a new text finding session with this request. Should be `true` for initial requests, and `false` for follow-up requests. Defaults to `false`. * `matchCase` Boolean (optional) - Whether search should be case-sensitive, defaults to `false`. * `wordStart` Boolean (optional) - Whether to look only at the start of words. diff --git a/lib/browser/rpc-server.ts b/lib/browser/rpc-server.ts index 00bbca673dc6c..785ad360b6694 100644 --- a/lib/browser/rpc-server.ts +++ b/lib/browser/rpc-server.ts @@ -1,6 +1,6 @@ import { app } from 'electron/main'; import type { IpcMainInvokeEvent, WebContents } from 'electron/main'; -import { clipboard, crashReporter, nativeImage } from 'electron/common'; +import { clipboard, crashReporter } from 'electron/common'; import * as fs from 'fs'; import { ipcMainInternal } from '@electron/internal/browser/ipc-main-internal'; import * as ipcMainUtils from '@electron/internal/browser/ipc-main-internal-utils'; @@ -132,7 +132,3 @@ ipcMainUtils.handleSync('ELECTRON_CRASH_REPORTER_SET_UPLOAD_TO_SERVER', (event: ipcMainUtils.handleSync('ELECTRON_CRASH_REPORTER_GET_CRASHES_DIRECTORY', () => { return crashReporter.getCrashesDirectory(); }); - -ipcMainInternal.handle('ELECTRON_NATIVE_IMAGE_CREATE_THUMBNAIL_FROM_PATH', async (_, path: string, size: Electron.Size) => { - return typeUtils.serialize(await nativeImage.createThumbnailFromPath(path, size)); -}); diff --git a/lib/renderer/api/native-image.ts b/lib/renderer/api/native-image.ts index 1264a900edbef..e68d81a132c42 100644 --- a/lib/renderer/api/native-image.ts +++ b/lib/renderer/api/native-image.ts @@ -1,10 +1,3 @@ -import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal'; -import { deserialize } from '@electron/internal/common/type-utils'; - const { nativeImage } = process._linkedBinding('electron_common_native_image'); -nativeImage.createThumbnailFromPath = async (path: string, size: Electron.Size) => { - return deserialize(await ipcRendererInternal.invoke('ELECTRON_NATIVE_IMAGE_CREATE_THUMBNAIL_FROM_PATH', path, size)); -}; - export default nativeImage; diff --git a/lib/renderer/security-warnings.ts b/lib/renderer/security-warnings.ts index 4f17200b5ffbb..e8cb7a5b9041d 100644 --- a/lib/renderer/security-warnings.ts +++ b/lib/renderer/security-warnings.ts @@ -270,7 +270,7 @@ const warnAboutAllowedPopups = function () { const warnAboutRemoteModuleWithRemoteContent = function (webPreferences?: Electron.WebPreferences) { if (!webPreferences || isLocalhost()) return; - const remoteModuleEnabled = webPreferences.enableRemoteModule != null ? !!webPreferences.enableRemoteModule : true; + const remoteModuleEnabled = webPreferences.enableRemoteModule != null ? !!webPreferences.enableRemoteModule : false; if (!remoteModuleEnabled) return; if (getIsRemoteProtocol()) { diff --git a/lib/renderer/web-view/guest-view-internal.ts b/lib/renderer/web-view/guest-view-internal.ts index f84f46e4e6d40..ccdc53f9c1060 100644 --- a/lib/renderer/web-view/guest-view-internal.ts +++ b/lib/renderer/web-view/guest-view-internal.ts @@ -1,4 +1,4 @@ -import { webFrame, IpcMessageEvent } from 'electron'; +import { webFrame } from 'electron'; import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal'; import * as ipcRendererUtils from '@electron/internal/renderer/ipc-renderer-internal-utils'; @@ -52,15 +52,15 @@ const dispatchEvent = function ( dispatchEvent(webView, DEPRECATED_EVENTS[eventName], eventKey, ...args); } - const domEvent = new Event(eventName) as ElectronInternal.WebViewEvent; + const props: Record = {}; WEB_VIEW_EVENTS[eventKey].forEach((prop, index) => { - (domEvent as any)[prop] = args[index]; + props[prop] = args[index]; }); - webView.dispatchEvent(domEvent); + webView.dispatchEvent(eventName, props); if (eventName === 'load-commit') { - webView.onLoadCommit(domEvent); + webView.onLoadCommit(props); } else if (eventName === 'focus-change') { webView.onFocusChange(); } @@ -70,8 +70,7 @@ export function registerEvents (webView: WebViewImpl, viewInstanceId: number) { ipcRendererInternal.onMessageFromMain(`ELECTRON_GUEST_VIEW_INTERNAL_DESTROY_GUEST-${viewInstanceId}`, function () { webView.guestInstanceId = undefined; webView.reset(); - const domEvent = new Event('destroyed'); - webView.dispatchEvent(domEvent); + webView.dispatchEvent('destroyed'); }); ipcRendererInternal.onMessageFromMain(`ELECTRON_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-${viewInstanceId}`, function (event, eventName, ...args) { @@ -79,11 +78,7 @@ export function registerEvents (webView: WebViewImpl, viewInstanceId: number) { }); ipcRendererInternal.onMessageFromMain(`ELECTRON_GUEST_VIEW_INTERNAL_IPC_MESSAGE-${viewInstanceId}`, function (event, channel, ...args) { - const domEvent = new Event('ipc-message') as IpcMessageEvent; - domEvent.channel = channel; - domEvent.args = args; - - webView.dispatchEvent(domEvent); + webView.dispatchEvent('ipc-message', { channel, args }); }); } diff --git a/lib/renderer/web-view/web-view-element.ts b/lib/renderer/web-view/web-view-element.ts index e723ebbbe1076..c63748456abad 100644 --- a/lib/renderer/web-view/web-view-element.ts +++ b/lib/renderer/web-view/web-view-element.ts @@ -39,7 +39,13 @@ const defineWebViewElement = (v8Util: NodeJS.V8UtilBinding, webViewImpl: typeof constructor () { super(); - v8Util.setHiddenValue(this, 'internal', new WebViewImpl(this)); + const internal = new WebViewImpl(this); + internal.dispatchEventInMainWorld = (eventName, props) => { + const event = new Event(eventName); + Object.assign(event, props); + return internal.webviewNode.dispatchEvent(event); + }; + v8Util.setHiddenValue(this, 'internal', internal); } connectedCallback () { diff --git a/lib/renderer/web-view/web-view-impl.ts b/lib/renderer/web-view/web-view-impl.ts index 1fc597186cc73..3d296cabf3a29 100644 --- a/lib/renderer/web-view/web-view-impl.ts +++ b/lib/renderer/web-view/web-view-impl.ts @@ -37,6 +37,8 @@ export class WebViewImpl { public attributes = new Map(); public setupWebViewAttributes (): void {} + public dispatchEventInMainWorld?: (eventName: string, props: any) => boolean; + constructor (public webviewNode: HTMLElement) { // Create internal iframe element. this.internalElement = this.createInternalElement(); @@ -107,10 +109,11 @@ export class WebViewImpl { } onElementResize () { - const resizeEvent = new Event('resize') as ElectronInternal.WebFrameResizeEvent; - resizeEvent.newWidth = this.webviewNode.clientWidth; - resizeEvent.newHeight = this.webviewNode.clientHeight; - this.dispatchEvent(resizeEvent); + const props = { + newWidth: this.webviewNode.clientWidth, + newHeight: this.webviewNode.clientHeight + }; + this.dispatchEvent('resize', props); } createGuest () { @@ -119,8 +122,8 @@ export class WebViewImpl { }); } - dispatchEvent (webViewEvent: Electron.Event) { - this.webviewNode.dispatchEvent(webViewEvent); + dispatchEvent (eventName: string, props: Record = {}) { + this.dispatchEventInMainWorld!(eventName, props); } // Adds an 'on' property on the webview, which can be used to set/unset @@ -145,10 +148,10 @@ export class WebViewImpl { } // Updates state upon loadcommit. - onLoadCommit (webViewEvent: ElectronInternal.WebViewEvent) { + onLoadCommit (props: Record) { const oldValue = this.webviewNode.getAttribute(WEB_VIEW_CONSTANTS.ATTRIBUTE_SRC); - const newValue = webViewEvent.url; - if (webViewEvent.isMainFrame && (oldValue !== newValue)) { + const newValue = props.url; + if (props.isMainFrame && (oldValue !== newValue)) { // Touching the src attribute triggers a navigation. To avoid // triggering a page reload on every guest-initiated navigation, // we do not handle this mutation. @@ -161,7 +164,7 @@ export class WebViewImpl { const hasFocus = this.webviewNode.ownerDocument.activeElement === this.webviewNode; if (hasFocus !== this.hasFocus) { this.hasFocus = hasFocus; - this.dispatchEvent(new Event(hasFocus ? 'focus' : 'blur')); + this.dispatchEvent(hasFocus ? 'focus' : 'blur'); } } diff --git a/package.json b/package.json index cd1f4b6cd7043..ab430c9046b0d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "electron", - "version": "11.4.6", + "version": "11.5.0", "repository": "https://github.com/electron/electron", "description": "Build cross platform desktop apps with JavaScript, HTML, and CSS", "devDependencies": { diff --git a/patches/angle/.patches b/patches/angle/.patches index 82ed05bacaf4f..b291c2cc2b545 100644 --- a/patches/angle/.patches +++ b/patches/angle/.patches @@ -1 +1,2 @@ d3d11_skip_blits_if_there_is_no_intersection_of_dest_areas.patch +cherry-pick-3d4f87ab5b9b.patch diff --git a/patches/angle/cherry-pick-3d4f87ab5b9b.patch b/patches/angle/cherry-pick-3d4f87ab5b9b.patch new file mode 100644 index 0000000000000..811d0a8867ebc --- /dev/null +++ b/patches/angle/cherry-pick-3d4f87ab5b9b.patch @@ -0,0 +1,59 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jamie Madill +Date: Thu, 20 May 2021 12:22:46 -0400 +Subject: D3D11: Fix respecifying 3D textures. + +The missing check for the "Depth" dimension could lead to a bug +where we would not recreate a texture when the dimension changed. + +Bug: chromium:1210414 +Change-Id: Id59097ad14ae77ff80d27081f61786dad17a77ea +Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2911032 +Reviewed-by: Geoff Lang +Commit-Queue: Jamie Madill +(cherry picked from commit 2697358464cf20576701987f60300b6c4086c11e) +Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2937026 +Reviewed-by: Jamie Madill + +diff --git a/src/libANGLE/renderer/d3d/d3d11/Image11.cpp b/src/libANGLE/renderer/d3d/d3d11/Image11.cpp +index c502d00fac032ea708015bbbf4f51db2dc2b3c59..daa5c3abc3ab4f4460ec48d0aba9649cf66897ac 100644 +--- a/src/libANGLE/renderer/d3d/d3d11/Image11.cpp ++++ b/src/libANGLE/renderer/d3d/d3d11/Image11.cpp +@@ -223,8 +223,8 @@ bool Image11::redefine(gl::TextureType type, + const gl::Extents &size, + bool forceRelease) + { +- if (mWidth != size.width || mHeight != size.height || mInternalFormat != internalformat || +- forceRelease) ++ if (mWidth != size.width || mHeight != size.height || mDepth != size.depth || ++ mInternalFormat != internalformat || forceRelease) + { + // End the association with the TextureStorage, since that data will be out of date. + // Also reset mRecoveredFromStorageCount since this Image is getting completely redefined. +diff --git a/src/tests/gl_tests/MipmapTest.cpp b/src/tests/gl_tests/MipmapTest.cpp +index 888088b5e38191e38e07bf50a0d1b6fa0a09db95..372c6645a587563c616a961ed3ac46dc667e9660 100644 +--- a/src/tests/gl_tests/MipmapTest.cpp ++++ b/src/tests/gl_tests/MipmapTest.cpp +@@ -1991,6 +1991,22 @@ void main() + EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 8, getWindowHeight() / 8, GLColor::green); + } + ++// Tests respecifying 3D mipmaps. ++TEST_P(MipmapTestES3, Generate3DMipmapRespecification) ++{ ++ std::vector pixels(256 * 256 * 100, GLColor::black); ++ ++ GLTexture texture; ++ glBindTexture(GL_TEXTURE_3D, texture); ++ glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, 256, 256, 100, 0, GL_RGBA, GL_UNSIGNED_BYTE, ++ pixels.data()); ++ glTexImage3D(GL_TEXTURE_3D, 1, GL_RGBA, 128, 128, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, ++ pixels.data()); ++ glGenerateMipmap(GL_TEXTURE_3D); ++ ++ ASSERT_GL_NO_ERROR(); ++} ++ + // Use this to select which configurations (e.g. which renderer, which GLES major version) these + // tests should be run against. + ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(MipmapTest); diff --git a/patches/chromium/.patches b/patches/chromium/.patches index c090ab407ac1c..e1f759deef89b 100644 --- a/patches/chromium/.patches +++ b/patches/chromium/.patches @@ -159,3 +159,29 @@ cherry-pick-406ae3e8a9a8.patch cherry-pick-668cf831e912.patch cherry-pick-02f5ef8c88d7.patch cherry-pick-f37149c4434f.patch +replace_std_vector_with_base_observerlist_to_support_container.patch +guard_webcontents_downloadimage_against_malformed_renderer.patch +fileapi_terminate_filereaderloader_before_dispatching_onabort_event.patch +notifications_crash_if_improper_action_icons_sent_from_renderer.patch +reland_views_handle_deletion_when_toggling_fullscreen.patch +media_feeds_disable_media_feeds_and_related_features.patch +remove_tabs_and_line_breaks_from_the_middle_of_app_names_when.patch +autofill_fixed_refill_of_changed_form.patch +x11_fix_window_enumeration_order_when_wm_doesn_t_set.patch +cherry-pick-0e36d324d6ef.patch +m86-lts_longtaskdetector_remove_container_mutation_during.patch +m86-lts_reduce_memory_consumption_on.patch +cherry-pick-b77b38a3380c.patch +cherry-pick-d9556a80a790.patch +cherry-pick-910e9e40d376.patch +cherry-pick-ff0d013f60fa.patch +cherry-pick-e60cc80ff744.patch +fix_use-after-free_with_xslt_strip-space.patch +cherry-pick-3feda0244490.patch +cherry-pick-cd98d7c0dae9.patch +replace_first_of_two_waitableevents_in_creditcardaccessmanager.patch +cherry-pick-ac9dc1235e28.patch +cherry-pick-1227933.patch +cherry-pick-1231134.patch +cherry-pick-1233564.patch +cherry-pick-1234009.patch diff --git a/patches/chromium/autofill_fixed_refill_of_changed_form.patch b/patches/chromium/autofill_fixed_refill_of_changed_form.patch new file mode 100644 index 0000000000000..7d732afd22575 --- /dev/null +++ b/patches/chromium/autofill_fixed_refill_of_changed_form.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrey Belenko +Date: Wed, 19 May 2021 17:22:52 +0200 +Subject: Fixed refill of changed form. + +(cherry picked from commit 533bb3adcfe3499f90e2646fc60312f303b963ac) + +Bug: 1203667 +Change-Id: I2693a024531775e0e60cc330107d77d10558f466 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2867655 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2874611 + +diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc +index 0b72ac3b8a0d3bb3294be995d2b9a4bc52b81a8f..5f92b20734d06249fc119432f45def087214709c 100644 +--- a/components/autofill/core/browser/autofill_manager.cc ++++ b/components/autofill/core/browser/autofill_manager.cc +@@ -1743,7 +1743,10 @@ void AutofillManager::FillOrPreviewDataModelForm( + form_structure->RationalizePhoneNumbersInSection(autofill_field->section); + + FormData result = form; +- DCHECK_EQ(form_structure->field_count(), form.fields.size()); ++ // TODO(crbug/1203667#c9): Skip if the form has changed in the meantime, which ++ // may happen with refills. ++ if (form_structure->field_count() != form.fields.size()) ++ return; + + if (action == AutofillDriver::FORM_DATA_ACTION_FILL && !is_refill) { + filling_contexts_map_[form_structure->GetIdentifierForRefill()] = +@@ -1787,8 +1790,10 @@ void AutofillManager::FillOrPreviewDataModelForm( + continue; + } + +- // The field order should be the same in |form_structure| and |result|. +- DCHECK(form_structure->field(i)->SameFieldAs(result.fields[i])); ++ // TODO(crbug/1203667#c9): Skip if the form has changed in the meantime, ++ // which may happen with refills. ++ if (!form_structure->field(i)->SameFieldAs(result.fields[i])) ++ continue; + + AutofillField* cached_field = form_structure->field(i); + FieldTypeGroup field_group_type = cached_field->Type().group(); diff --git a/patches/chromium/cherry-pick-0e36d324d6ef.patch b/patches/chromium/cherry-pick-0e36d324d6ef.patch new file mode 100644 index 0000000000000..800e88803009a --- /dev/null +++ b/patches/chromium/cherry-pick-0e36d324d6ef.patch @@ -0,0 +1,101 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Asami Doi +Date: Thu, 10 Jun 2021 07:07:44 +0000 +Subject: BFCache: remove a controllee stored in `bfcached_controllee_map_` + +This CL fixes the UAF that happens with the following case: +Let's assume we have 2 service workers (sw1.js and sw2.js) are +registered in the same page. When the second service worker (sw2.js) is +registered, ServiceWorkerContainerHost::UpdateController() is called +and the previous SWVersion (sw1.js) removes a controllee from +`controllee_map_`. If BackForwardCache is enabled, a controllee is +stored in `bfcached_controllee_map_` instead and the controllee will +not be removed in ServiceWorkerContainerHost::UpdateController(). +When ServiceWorkerContainerHost::UpdateController() is called and +keep a controllee in `bfcached_controllee_map_`, and a page navigates to +a different page (evicts BFCache), use-after-free (UAF) happens. + +This CL updates ServiceWorkerContainerHost::UpdateController() +to remove a controllee from `bfcached_controllee_map_` if it exists. + +(cherry picked from commit a2414a05a486ca0ad18ba4caf78e883a668a0555) + +(cherry picked from commit 7cd7f6741fc4491c2f7ef21052a370ee23887e37) + +Bug: 1212618 +Change-Id: I13e023e6d273268a08ea9276a056f7f5acba39cd +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2919020 +Commit-Queue: Asami Doi +Reviewed-by: Matt Falkenhagen +Cr-Original-Original-Commit-Position: refs/heads/master@{#887109} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2929401 +Reviewed-by: Krishna Govind +Reviewed-by: Ben Mason +Reviewed-by: Prudhvi Kumar Bommana +Commit-Queue: Krishna Govind +Owners-Override: Krishna Govind +Cr-Original-Commit-Position: refs/branch-heads/4472@{#1375} +Cr-Original-Branched-From: 3d60439cfb36485e76a1c5bb7f513d3721b20da1-refs/heads/master@{#870763} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2948660 +Owners-Override: Victor-Gabriel Savu +Reviewed-by: Artem Sumaneev +Commit-Queue: Victor-Gabriel Savu +Cr-Commit-Position: refs/branch-heads/4240@{#1663} +Cr-Branched-From: f297677702651916bbf65e59c0d4bbd4ce57d1ee-refs/heads/master@{#800218} + +diff --git a/content/browser/service_worker/service_worker_container_host.cc b/content/browser/service_worker/service_worker_container_host.cc +index 5cb7b2da2c9a4c857c756589ba2c9eaf0dc2b67f..b91a0ec16483a38574ed7d63fdeb9133877d17ae 100644 +--- a/content/browser/service_worker/service_worker_container_host.cc ++++ b/content/browser/service_worker/service_worker_container_host.cc +@@ -149,7 +149,7 @@ ServiceWorkerContainerHost::~ServiceWorkerContainerHost() { + FrameTreeNodeIdRegistry::GetInstance()->Remove(fetch_request_window_id_); + + if (IsContainerForClient() && controller_) +- controller_->OnControlleeDestroyed(client_uuid()); ++ controller_->Uncontrol(client_uuid()); + + // Remove |this| as an observer of ServiceWorkerRegistrations. + // TODO(falken): Use ScopedObserver instead of this explicit call. +@@ -1236,7 +1236,7 @@ void ServiceWorkerContainerHost::UpdateController( + } + } + if (previous_version) +- previous_version->RemoveControllee(client_uuid()); ++ previous_version->Uncontrol(client_uuid()); + + // SetController message should be sent only for clients. + DCHECK(IsContainerForClient()); +diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc +index d360afea47c40f8c533ff52f46417371bd3a1ad3..7d057af1b760b67f061cbcb7436c1bfb651ded68 100644 +--- a/content/browser/service_worker/service_worker_version.cc ++++ b/content/browser/service_worker/service_worker_version.cc +@@ -880,8 +880,7 @@ void ServiceWorkerVersion::RemoveControlleeFromBackForwardCacheMap( + bfcached_controllee_map_.erase(client_uuid); + } + +-void ServiceWorkerVersion::OnControlleeDestroyed( +- const std::string& client_uuid) { ++void ServiceWorkerVersion::Uncontrol(const std::string& client_uuid) { + if (!IsBackForwardCacheEnabled()) { + RemoveControllee(client_uuid); + } else { +diff --git a/content/browser/service_worker/service_worker_version.h b/content/browser/service_worker/service_worker_version.h +index b7c3b5cc809c42111b0bf5bddff574197c9a77a8..90431fe256dc67d51ed1c01ec8202a335af78032 100644 +--- a/content/browser/service_worker/service_worker_version.h ++++ b/content/browser/service_worker/service_worker_version.h +@@ -390,9 +390,12 @@ class CONTENT_EXPORT ServiceWorkerVersion + void RestoreControlleeFromBackForwardCacheMap(const std::string& client_uuid); + // Called when a back-forward cached controllee is evicted or destroyed. + void RemoveControlleeFromBackForwardCacheMap(const std::string& client_uuid); +- // Called when a controllee is destroyed. Remove controllee from whichever +- // map it belongs to, or do nothing when it is already removed. +- void OnControlleeDestroyed(const std::string& client_uuid); ++ // Called when this version should no longer be the controller of this client. ++ // Called when the controllee is destroyed or it changes controller. Removes ++ // controllee from whichever map it belongs to, or do nothing when it is ++ // already removed. This function is different from RemoveController(), which ++ // can only be called if the controllee is not in the back-forward cache map. ++ void Uncontrol(const std::string& client_uuid); + + // Returns true if this version has a controllee. + // Note regarding BackForwardCache: diff --git a/patches/chromium/cherry-pick-1227933.patch b/patches/chromium/cherry-pick-1227933.patch new file mode 100644 index 0000000000000..abbdf26d4e598 --- /dev/null +++ b/patches/chromium/cherry-pick-1227933.patch @@ -0,0 +1,215 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Koji Ishii +Date: Mon, 26 Jul 2021 07:09:18 +0000 +Subject: Fix nested inline box fragmentation + +This patch fixes when nested inline boxes are fragmented in a +line due to bidi reordering. + +Before this change, the fragmented boxes are appended to the +end of |box_data_list_|. Then when |NGInlineLayoutStateStack:: +CreateBoxFragments| creates inline boxes in the ascending +order of |box_data_list_|, it failed to add the fragmented +boxes into their parent inline boxes. + +This is critical for out-of-flow positioned objects whose +containing block is an inline box, because they expect to be +propagated through all ancestor inline boxes. + +|UpdateBoxDataFragmentRange| is a little tricky by appending +to a vector it is iterating. Changing it to insert to the +correct position makes the function even trickier. This patch +changes it to add fragmented boxes to a separate vector, and +let later process |UpdateFragmentedBoxDataEdges| to merge the +vector to |box_data_list_|. + +(cherry picked from commit 9c8a39c14a9c80556468593cddf436f5047a16ce) + +Bug: 1227933, 1229999 +Change-Id: I7edcd209e1fdac06bab01b16d660383e7e9c37bd +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3038308 +Commit-Queue: Koji Ishii +Reviewed-by: Yoshifumi Inoue +Cr-Original-Commit-Position: refs/heads/master@{#903356} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3053212 +Commit-Queue: Rubber Stamper +Bot-Commit: Rubber Stamper +Auto-Submit: Koji Ishii +Cr-Commit-Position: refs/branch-heads/4577@{#145} +Cr-Branched-From: 761ddde228655e313424edec06497d0c56b0f3c4-refs/heads/master@{#902210} + +diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc +index c61298842eaa308b7ae863d6e1cf5457a8091dd2..f6fb0f03c3ec63c0c2de2b9501534108dea85422 100644 +--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc ++++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc +@@ -4,6 +4,7 @@ + + #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h" + ++#include "base/containers/adapters.h" + #include "third_party/blink/renderer/core/layout/geometry/logical_offset.h" + #include "third_party/blink/renderer/core/layout/geometry/logical_size.h" + #include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h" +@@ -389,13 +390,14 @@ void NGInlineLayoutStateStack::UpdateAfterReorder( + box_data.fragment_start = box_data.fragment_end = 0; + + // Scan children and update start/end from their box_data_index. +- unsigned box_count = box_data_list_.size(); ++ Vector fragmented_boxes; + for (unsigned index = 0; index < line_box->size();) +- index = UpdateBoxDataFragmentRange(line_box, index); ++ index = UpdateBoxDataFragmentRange(line_box, index, &fragmented_boxes); + +- // If any inline fragmentation due to BiDi reorder, adjust box edges. +- if (box_count != box_data_list_.size()) +- UpdateFragmentedBoxDataEdges(); ++ // If any inline fragmentation occurred due to BiDi reorder, append them and ++ // adjust box edges. ++ if (UNLIKELY(!fragmented_boxes.IsEmpty())) ++ UpdateFragmentedBoxDataEdges(&fragmented_boxes); + + #if DCHECK_IS_ON() + // Check all BoxData have ranges. +@@ -412,7 +414,8 @@ void NGInlineLayoutStateStack::UpdateAfterReorder( + + unsigned NGInlineLayoutStateStack::UpdateBoxDataFragmentRange( + NGLogicalLineItems* line_box, +- unsigned index) { ++ unsigned index, ++ Vector* fragmented_boxes) { + // Find the first line box item that should create a box fragment. + for (; index < line_box->size(); index++) { + NGLogicalLineItem* start = &(*line_box)[index]; +@@ -440,7 +443,7 @@ unsigned NGInlineLayoutStateStack::UpdateBoxDataFragmentRange( + // It also changes other BoxData, but not the one we're dealing with here + // because the update is limited only when its |box_data_index| is lower. + while (end->box_data_index && end->box_data_index < box_data_index) { +- UpdateBoxDataFragmentRange(line_box, index); ++ UpdateBoxDataFragmentRange(line_box, index, fragmented_boxes); + } + + if (box_data_index != end->box_data_index) +@@ -455,14 +458,9 @@ unsigned NGInlineLayoutStateStack::UpdateBoxDataFragmentRange( + } else { + // This box is fragmented by BiDi reordering. Add a new BoxData for the + // fragmented range. +- box_data_list_[box_data_index - 1].fragmented_box_data_index = +- box_data_list_.size(); +- // Do not use `emplace_back()` here because adding to |box_data_list_| may +- // reallocate the buffer, but the `BoxData` ctor must run before the +- // reallocation. Create a new instance and |push_back()| instead. +- BoxData fragmented_box_data(box_data_list_[box_data_index - 1], +- start_index, index); +- box_data_list_.push_back(fragmented_box_data); ++ BoxData& fragmented_box = fragmented_boxes->emplace_back( ++ box_data_list_[box_data_index - 1], start_index, index); ++ fragmented_box.fragmented_box_data_index = box_data_index; + } + // If this box has parent boxes, we need to process it again. + if (box_data_list_[box_data_index - 1].parent_box_data_index) +@@ -472,7 +470,43 @@ unsigned NGInlineLayoutStateStack::UpdateBoxDataFragmentRange( + return index; + } + +-void NGInlineLayoutStateStack::UpdateFragmentedBoxDataEdges() { ++void NGInlineLayoutStateStack::UpdateFragmentedBoxDataEdges( ++ Vector* fragmented_boxes) { ++ DCHECK(!fragmented_boxes->IsEmpty()); ++ // Append in the descending order of |fragmented_box_data_index| because the ++ // indices will change as boxes are inserted into |box_data_list_|. ++ std::sort(fragmented_boxes->begin(), fragmented_boxes->end(), ++ [](const BoxData& a, const BoxData& b) { ++ if (a.fragmented_box_data_index != b.fragmented_box_data_index) { ++ return a.fragmented_box_data_index < ++ b.fragmented_box_data_index; ++ } ++ DCHECK_NE(a.fragment_start, b.fragment_start); ++ return a.fragment_start < b.fragment_start; ++ }); ++ for (BoxData& fragmented_box : base::Reversed(*fragmented_boxes)) { ++ // Insert the fragmented box to right after the box it was fragmented from. ++ // The order in the |box_data_list_| is critical when propagating child ++ // fragment data such as OOF to ancestors. ++ const unsigned insert_at = fragmented_box.fragmented_box_data_index; ++ DCHECK_GT(insert_at, 0u); ++ fragmented_box.fragmented_box_data_index = 0; ++ box_data_list_.insert(insert_at, fragmented_box); ++ ++ // Adjust box data indices by the insertion. ++ for (BoxData& box_data : box_data_list_) { ++ if (box_data.fragmented_box_data_index >= insert_at) ++ ++box_data.fragmented_box_data_index; ++ } ++ ++ // Set the index of the last fragment to the original box. This is needed to ++ // update fragment edges. ++ const unsigned fragmented_from = insert_at - 1; ++ if (!box_data_list_[fragmented_from].fragmented_box_data_index) ++ box_data_list_[fragmented_from].fragmented_box_data_index = insert_at; ++ } ++ ++ // Move the line-right edge to the last fragment. + for (BoxData& box_data : box_data_list_) { + if (box_data.fragmented_box_data_index) + box_data.UpdateFragmentEdges(box_data_list_); +diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h +index 36aa27914a6598671c3f9266f323ab03847db5a6..7fb13383a21116ce1dd17a327ad2cc911c3f7c01 100644 +--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h ++++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h +@@ -157,17 +157,6 @@ class CORE_EXPORT NGInlineLayoutStateStack { + // reordering. + void UpdateAfterReorder(NGLogicalLineItems*); + +- // Update start/end of the first BoxData found at |index|. +- // +- // If inline fragmentation is found, a new BoxData is added. +- // +- // Returns the index to process next. It should be given to the next call to +- // this function. +- unsigned UpdateBoxDataFragmentRange(NGLogicalLineItems*, unsigned index); +- +- // Update edges of inline fragmented boxes. +- void UpdateFragmentedBoxDataEdges(); +- + // Compute inline positions of fragments and boxes. + LayoutUnit ComputeInlinePositions(NGLogicalLineItems*, LayoutUnit position); + +@@ -260,6 +249,19 @@ class CORE_EXPORT NGInlineLayoutStateStack { + scoped_refptr CreateBoxFragment(NGLogicalLineItems*); + }; + ++ // Update start/end of the first BoxData found at |index|. ++ // ++ // If inline fragmentation is found, a new BoxData is added. ++ // ++ // Returns the index to process next. It should be given to the next call to ++ // this function. ++ unsigned UpdateBoxDataFragmentRange(NGLogicalLineItems*, ++ unsigned index, ++ Vector* fragmented_boxes); ++ ++ // Update edges of inline fragmented boxes. ++ void UpdateFragmentedBoxDataEdges(Vector* fragmented_boxes); ++ + Vector stack_; + Vector box_data_list_; + +diff --git a/third_party/blink/web_tests/external/wpt/css/CSS2/text/crashtests/bidi-inline-fragment-oof-crash.html b/third_party/blink/web_tests/external/wpt/css/CSS2/text/crashtests/bidi-inline-fragment-oof-crash.html +new file mode 100644 +index 0000000000000000000000000000000000000000..b701d2b5688ace54aa99530c12fa8143f1e6a508 +--- /dev/null ++++ b/third_party/blink/web_tests/external/wpt/css/CSS2/text/crashtests/bidi-inline-fragment-oof-crash.html +@@ -0,0 +1,13 @@ ++ ++ ++ ++
++ ++ ++
++ ++
++
++
++
++
diff --git a/patches/chromium/cherry-pick-1231134.patch b/patches/chromium/cherry-pick-1231134.patch new file mode 100644 index 0000000000000..2c95e166f67c4 --- /dev/null +++ b/patches/chromium/cherry-pick-1231134.patch @@ -0,0 +1,163 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lei Zhang +Date: Tue, 10 Aug 2021 21:38:36 +0000 +Subject: Do more class validity checks in PrintViewManagerBase. + +PrintViewManagerBase runs a nested loop. In some situations, +PrintViewManagerBase and related classes like PrintViewManager and +PrintPreviewHandler can get deleted while the nested loop is running. +When this happens, the nested loop exists to a PrintViewManagerBase +that is no longer valid. + +Use base::WeakPtrs liberally to check for this condition and exit +safely. + +(cherry picked from commit a2cb1fb333d2faacb2fe1380f8d2621b5ee6af7e) + +Bug: 1231134 +Change-Id: I21ec131574331ce973d22594c11e70088147e149 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3057880 +Reviewed-by: Alan Screen +Commit-Queue: Lei Zhang +Cr-Original-Commit-Position: refs/heads/master@{#906269} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3086110 +Bot-Commit: Rubber Stamper +Cr-Commit-Position: refs/branch-heads/4515@{#2024} +Cr-Branched-From: 488fc70865ddaa05324ac00a54a6eb783b4bc41c-refs/heads/master@{#885287} + +diff --git a/chrome/browser/printing/print_view_manager.cc b/chrome/browser/printing/print_view_manager.cc +index b7a2fa5a10b2461e83d78fca63e3165d5eb1350f..9f11d5053ff19e4ccfdbe54e7f59e311da3c6e0a 100644 +--- a/chrome/browser/printing/print_view_manager.cc ++++ b/chrome/browser/printing/print_view_manager.cc +@@ -91,7 +91,11 @@ bool PrintViewManager::PrintForSystemDialogNow( + DCHECK(!on_print_dialog_shown_callback_); + on_print_dialog_shown_callback_ = std::move(dialog_shown_callback); + is_switching_to_system_dialog_ = true; ++ ++ auto weak_this = weak_factory_.GetWeakPtr(); + DisconnectFromCurrentPrintJob(); ++ if (!weak_this) ++ return false; + + // Don't print / print preview crashed tabs. + if (IsCrashed()) +diff --git a/chrome/browser/printing/print_view_manager.h b/chrome/browser/printing/print_view_manager.h +index 8770b7bc60cb28d70cde3af8303939bf7ac27892..16c13724c397fade0eb64f9b5ec26c7bf51570ac 100644 +--- a/chrome/browser/printing/print_view_manager.h ++++ b/chrome/browser/printing/print_view_manager.h +@@ -130,6 +130,11 @@ class PrintViewManager : public PrintViewManagerBase, + + WEB_CONTENTS_USER_DATA_KEY_DECL(); + ++ // Keep this last so that all weak pointers will be invalidated at the ++ // beginning of destruction. Note that PrintViewManagerBase has its own ++ // base::WeakPtrFactory as well, but PrintViewManager should use this one. ++ base::WeakPtrFactory weak_factory_{this}; ++ + DISALLOW_COPY_AND_ASSIGN(PrintViewManager); + }; + +diff --git a/chrome/browser/printing/print_view_manager_base.cc b/chrome/browser/printing/print_view_manager_base.cc +index 75908fc9978db020d752e7fc7211d1a075c11ffb..b896f69f3ec272001c5c6c0071bc23a3c9134d70 100644 +--- a/chrome/browser/printing/print_view_manager_base.cc ++++ b/chrome/browser/printing/print_view_manager_base.cc +@@ -192,7 +192,10 @@ bool PrintViewManagerBase::PrintNow(content::RenderFrameHost* rfh, + bool silent, + base::Value settings, + CompletionCallback callback) { ++ auto weak_this = weak_ptr_factory_.GetWeakPtr(); + DisconnectFromCurrentPrintJob(); ++ if (!weak_this) ++ return false; + + // Don't print / print preview crashed tabs. + if (IsCrashed()) +@@ -625,6 +628,8 @@ bool PrintViewManagerBase::RenderAllMissingPagesNow() { + // or in DidPrintDocument(). The check is done in + // ShouldQuitFromInnerMessageLoop(). + // BLOCKS until all the pages are received. (Need to enable recursive task) ++ // WARNING: Do not do any work after RunInnerMessageLoop() returns, as `this` ++ // may have gone away. + if (!RunInnerMessageLoop()) { + // This function is always called from DisconnectFromCurrentPrintJob() so we + // know that the job will be stopped/canceled in any case. +@@ -651,8 +656,11 @@ bool PrintViewManagerBase::CreateNewPrintJob( + DCHECK(query); + + if (callback_.is_null()) { ++ auto weak_this = weak_ptr_factory_.GetWeakPtr(); + // Disconnect the current |print_job_| only when calling window.print() + DisconnectFromCurrentPrintJob(); ++ if (!weak_this) ++ return false; + } + + // We can't print if there is no renderer. +@@ -681,7 +689,10 @@ bool PrintViewManagerBase::CreateNewPrintJob( + void PrintViewManagerBase::DisconnectFromCurrentPrintJob() { + // Make sure all the necessary rendered page are done. Don't bother with the + // return value. ++ auto weak_this = weak_ptr_factory_.GetWeakPtr(); + bool result = RenderAllMissingPagesNow(); ++ if (!weak_this) ++ return; + + // Verify that assertion. + if (print_job_ && print_job_->document() && +@@ -763,7 +774,10 @@ bool PrintViewManagerBase::RunInnerMessageLoop() { + + quit_inner_loop_ = run_loop.QuitClosure(); + ++ auto weak_this = weak_ptr_factory_.GetWeakPtr(); + run_loop.Run(); ++ if (!weak_this) ++ return false; + + // If the inner-loop quit closure is still set then we timed out. + bool success = !quit_inner_loop_; +diff --git a/chrome/browser/printing/print_view_manager_base.h b/chrome/browser/printing/print_view_manager_base.h +index 095d9dfcc3ee14b646b63c29e406434c1623704a..ed4c0ec98bb84753828d0649799077edc9796317 100644 +--- a/chrome/browser/printing/print_view_manager_base.h ++++ b/chrome/browser/printing/print_view_manager_base.h +@@ -115,6 +115,8 @@ class PrintViewManagerBase : public content::NotificationObserver, + + // Makes sure the current print_job_ has all its data before continuing, and + // disconnect from it. ++ // WARNING: `this` may not be alive after DisconnectFromCurrentPrintJob() ++ // returns. + void DisconnectFromCurrentPrintJob(); + + // Manages the low-level talk to the printer. +@@ -168,6 +170,7 @@ class PrintViewManagerBase : public content::NotificationObserver, + // Requests the RenderView to render all the missing pages for the print job. + // No-op if no print job is pending. Returns true if at least one page has + // been requested to the renderer. ++ // WARNING: `this` may not be alive after RenderAllMissingPagesNow() returns. + bool RenderAllMissingPagesNow(); + + // Checks that synchronization is correct with |print_job_| based on |cookie|. +@@ -201,6 +204,7 @@ class PrintViewManagerBase : public content::NotificationObserver, + // while the blocking inner message loop is running. This is useful in cases + // where the RenderView is about to be destroyed while a printing job isn't + // finished. ++ // WARNING: `this` may not be alive after RunInnerMessageLoop() returns. + bool RunInnerMessageLoop(); + + // In the case of Scripted Printing, where the renderer is controlling the +diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc +index 2cea700c82790f696775ece3080662232326aabc..ab89b180e6f9586d6280d884f126fb46b278be04 100644 +--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc ++++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc +@@ -864,9 +864,12 @@ void PrintPreviewHandler::HandleShowSystemDialog( + if (!initiator) + return; + ++ auto weak_this = weak_factory_.GetWeakPtr(); + auto* print_view_manager = PrintViewManager::FromWebContents(initiator); + print_view_manager->PrintForSystemDialogNow(base::BindOnce( + &PrintPreviewHandler::ClosePreviewDialog, weak_factory_.GetWeakPtr())); ++ if (!weak_this) ++ return; + + // Cancel the pending preview request if exists. + print_preview_ui()->OnCancelPendingPreviewRequest(); diff --git a/patches/chromium/cherry-pick-1233564.patch b/patches/chromium/cherry-pick-1233564.patch new file mode 100644 index 0000000000000..9803f407050ea --- /dev/null +++ b/patches/chromium/cherry-pick-1233564.patch @@ -0,0 +1,77 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Hongchan Choi +Date: Mon, 9 Aug 2021 18:43:22 +0000 +Subject: Protect HRTF database loader thread from access by different threads + +This patch add a new mutex locker around the HRTF database loader +thread to ensure the safe exclusive access of the loader thread +and the HRTF database. + +(cherry picked from commit 6811e850ee10847da16c4d5fdc0f845494586b65) + +Bug: 1233564 +Change-Id: Ie12b99ffe520d3747e34af387a37637a10aab38a +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3068260 +Auto-Submit: Hongchan Choi +Commit-Queue: Kentaro Hara +Reviewed-by: Kentaro Hara +Cr-Original-Commit-Position: refs/heads/master@{#908269} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3082114 +Reviewed-by: Chris Mumford +Commit-Queue: Hongchan Choi +Cr-Commit-Position: refs/branch-heads/4577@{#601} +Cr-Branched-From: 761ddde228655e313424edec06497d0c56b0f3c4-refs/heads/master@{#902210} + +diff --git a/third_party/blink/renderer/platform/audio/hrtf_database_loader.cc b/third_party/blink/renderer/platform/audio/hrtf_database_loader.cc +index 034ded03d11fa42f0d0f62c6a91f6e20ee5f93e1..01cb98a1116fe1eb6a13ff6345b6bdf4e136badc 100644 +--- a/third_party/blink/renderer/platform/audio/hrtf_database_loader.cc ++++ b/third_party/blink/renderer/platform/audio/hrtf_database_loader.cc +@@ -86,6 +86,8 @@ void HRTFDatabaseLoader::LoadTask() { + void HRTFDatabaseLoader::LoadAsynchronously() { + DCHECK(IsMainThread()); + ++ MutexLocker locker(lock_); ++ + // m_hrtfDatabase and m_thread should both be unset because this should be a + // new HRTFDatabaseLoader object that was just created by + // createAndLoadAsynchronouslyIfNecessary and because we haven't started +@@ -122,6 +124,10 @@ void HRTFDatabaseLoader::CleanupTask(base::WaitableEvent* sync) { + } + + void HRTFDatabaseLoader::WaitForLoaderThreadCompletion() { ++ // We can lock this because this is called from either the main thread or ++ // the offline audio rendering thread. ++ MutexLocker locker(lock_); ++ + if (!thread_) + return; + +diff --git a/third_party/blink/renderer/platform/audio/hrtf_database_loader.h b/third_party/blink/renderer/platform/audio/hrtf_database_loader.h +index 3ce476fa68e066d6faf40011e94203f0fb778e71..a94997b4f7e06f96018187967faa524d4acfd5f6 100644 +--- a/third_party/blink/renderer/platform/audio/hrtf_database_loader.h ++++ b/third_party/blink/renderer/platform/audio/hrtf_database_loader.h +@@ -64,8 +64,8 @@ class PLATFORM_EXPORT HRTFDatabaseLoader final + // must be called from the audio thread. + bool IsLoaded() { return Database(); } + +- // waitForLoaderThreadCompletion() may be called more than once and is +- // thread-safe. ++ // May be called from both main and audio thread, and also can be called more ++ // than once. + void WaitForLoaderThreadCompletion(); + + // Returns the database or nullptr if the database doesn't yet exist. Must +@@ -87,11 +87,10 @@ class PLATFORM_EXPORT HRTFDatabaseLoader final + void LoadTask(); + void CleanupTask(base::WaitableEvent*); + +- // Holding a m_lock is required when accessing m_hrtfDatabase since we access +- // it from multiple threads. ++ // |lock_| MUST be held when accessing |hrtf_database_| or |thread_| because ++ // it can be accessed by multiple threads (e.g multiple AudioContexts). + Mutex lock_; + std::unique_ptr hrtf_database_; +- + std::unique_ptr thread_; + + float database_sample_rate_; diff --git a/patches/chromium/cherry-pick-1234009.patch b/patches/chromium/cherry-pick-1234009.patch new file mode 100644 index 0000000000000..e475f309c142a --- /dev/null +++ b/patches/chromium/cherry-pick-1234009.patch @@ -0,0 +1,138 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sam McNally +Date: Tue, 10 Aug 2021 02:14:43 +0000 +Subject: Defer looking up the WebContents for the directory confirmation + dialog. + +Look up the WebContents to use for the sensitive directory confirmation +dialog immediately before it's used instead of before performing some +blocking file access to determine whether it's necessary. + +(cherry picked from commit 18236a0db8341302120c60781ae3129e94fbaf1c) + +Bug: 1234009 +Change-Id: I5e00c7fa199b3da522e1fdb73242891d7f5f7423 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3063743 +Reviewed-by: Alex Danilo +Reviewed-by: Ben Wells +Commit-Queue: Sam McNally +Cr-Original-Commit-Position: refs/heads/master@{#907467} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3083204 +Bot-Commit: Rubber Stamper +Cr-Commit-Position: refs/branch-heads/4577@{#648} +Cr-Branched-From: 761ddde228655e313424edec06497d0c56b0f3c4-refs/heads/master@{#902210} + +diff --git a/extensions/browser/api/file_system/file_system_api.cc b/extensions/browser/api/file_system/file_system_api.cc +index a128893387beac06fb1256416ae234af251378db..870298116be17a2bb0874f8b32c8926ec19ed0d4 100644 +--- a/extensions/browser/api/file_system/file_system_api.cc ++++ b/extensions/browser/api/file_system/file_system_api.cc +@@ -196,6 +196,9 @@ void PassFileInfoToUIThread(FileInfoOptCallback callback, + content::WebContents* GetWebContentsForRenderFrameHost( + content::BrowserContext* browser_context, + content::RenderFrameHost* render_frame_host) { ++ if (!render_frame_host) ++ return nullptr; ++ + content::WebContents* web_contents = + content::WebContents::FromRenderFrameHost(render_frame_host); + // Check if there is an app window associated with the web contents; if not, +@@ -508,15 +511,6 @@ void FileSystemChooseEntryFunction::FilesSelected( + } + + if (is_directory_) { +- // Get the WebContents for the app window to be the parent window of the +- // confirmation dialog if necessary. +- content::WebContents* const web_contents = GetWebContentsForRenderFrameHost( +- browser_context(), render_frame_host()); +- if (!web_contents) { +- Respond(Error(kInvalidCallingPage)); +- return; +- } +- + DCHECK_EQ(paths.size(), 1u); + bool non_native_path = false; + #if defined(OS_CHROMEOS) +@@ -530,7 +524,7 @@ void FileSystemChooseEntryFunction::FilesSelected( + FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, + base::BindOnce( + &FileSystemChooseEntryFunction::ConfirmDirectoryAccessAsync, this, +- non_native_path, paths, web_contents)); ++ non_native_path, paths)); + return; + } + +@@ -543,8 +537,7 @@ void FileSystemChooseEntryFunction::FileSelectionCanceled() { + + void FileSystemChooseEntryFunction::ConfirmDirectoryAccessAsync( + bool non_native_path, +- const std::vector& paths, +- content::WebContents* web_contents) { ++ const std::vector& paths) { + const base::FilePath check_path = + non_native_path ? paths[0] : base::MakeAbsoluteFilePath(paths[0]); + if (check_path.empty()) { +@@ -576,7 +569,7 @@ void FileSystemChooseEntryFunction::ConfirmDirectoryAccessAsync( + FROM_HERE, + base::BindOnce( + &FileSystemChooseEntryFunction::ConfirmSensitiveDirectoryAccess, +- this, paths, web_contents)); ++ this, paths)); + return; + } + +@@ -587,8 +580,7 @@ void FileSystemChooseEntryFunction::ConfirmDirectoryAccessAsync( + } + + void FileSystemChooseEntryFunction::ConfirmSensitiveDirectoryAccess( +- const std::vector& paths, +- content::WebContents* web_contents) { ++ const std::vector& paths) { + if (ExtensionsBrowserClient::Get()->IsShuttingDown()) { + FileSelectionCanceled(); + return; +@@ -601,6 +593,13 @@ void FileSystemChooseEntryFunction::ConfirmSensitiveDirectoryAccess( + return; + } + ++ content::WebContents* const web_contents = ++ GetWebContentsForRenderFrameHost(browser_context(), render_frame_host()); ++ if (!web_contents) { ++ Respond(Error(kInvalidCallingPage)); ++ return; ++ } ++ + delegate->ConfirmSensitiveDirectoryAccess( + app_file_handler_util::HasFileSystemWritePermission(extension_.get()), + base::UTF8ToUTF16(extension_->name()), web_contents, +diff --git a/extensions/browser/api/file_system/file_system_api.h b/extensions/browser/api/file_system/file_system_api.h +index 2a95c4d89fd2746aec0792f231bd20eac1b82d63..95ae48b3338ca90c25c098cd23655a84236aa6e6 100644 +--- a/extensions/browser/api/file_system/file_system_api.h ++++ b/extensions/browser/api/file_system/file_system_api.h +@@ -18,10 +18,6 @@ + #include "extensions/common/api/file_system.h" + #include "ui/shell_dialogs/select_file_dialog.h" + +-namespace content { +-class WebContents; +-} // namespace content +- + namespace extensions { + class ExtensionPrefs; + +@@ -167,13 +163,12 @@ class FileSystemChooseEntryFunction : public FileSystemEntryFunction { + // directory. If so, calls ConfirmSensitiveDirectoryAccess. Otherwise, calls + // OnDirectoryAccessConfirmed. + void ConfirmDirectoryAccessAsync(bool non_native_path, +- const std::vector& paths, +- content::WebContents* web_contents); ++ const std::vector& paths); + + // Shows a dialog to confirm whether the user wants to open the directory. + // Calls OnDirectoryAccessConfirmed or FileSelectionCanceled. +- void ConfirmSensitiveDirectoryAccess(const std::vector& paths, +- content::WebContents* web_contents); ++ void ConfirmSensitiveDirectoryAccess( ++ const std::vector& paths); + + void OnDirectoryAccessConfirmed(const std::vector& paths); + diff --git a/patches/chromium/cherry-pick-3feda0244490.patch b/patches/chromium/cherry-pick-3feda0244490.patch new file mode 100644 index 0000000000000..619fe129e0fb4 --- /dev/null +++ b/patches/chromium/cherry-pick-3feda0244490.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Reilly Grant +Date: Mon, 28 Jun 2021 21:55:24 +0000 +Subject: serial: Fix parent class tracing for SerialPort + +When SerialPort was updated to be ActiveScriptWrappable and an +EventTarget the Trace method was not updated to call the parent class +trace methods. + +(cherry picked from commit 4059ecc3a5352601a4d79196f90c8ca19262afe1) + +Bug: 1220078 +Change-Id: If6967a913268bce86d4488359a9418a814530f84 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2965255 +Auto-Submit: Reilly Grant +Commit-Queue: Tom Sepez +Reviewed-by: Tom Sepez +Cr-Original-Commit-Position: refs/heads/master@{#893039} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2992740 +Bot-Commit: Rubber Stamper +Commit-Queue: Reilly Grant +Cr-Commit-Position: refs/branch-heads/4472@{#1531} +Cr-Branched-From: 3d60439cfb36485e76a1c5bb7f513d3721b20da1-refs/heads/master@{#870763} + +diff --git a/third_party/blink/renderer/modules/serial/serial_port.cc b/third_party/blink/renderer/modules/serial/serial_port.cc +index 989104ef12774896c254812fff804eaafc5b2e6c..ee3c26a0a711751de93e3bc2ed457b54a84d430d 100644 +--- a/third_party/blink/renderer/modules/serial/serial_port.cc ++++ b/third_party/blink/renderer/modules/serial/serial_port.cc +@@ -492,6 +492,7 @@ void SerialPort::Trace(Visitor* visitor) const { + visitor->Trace(signal_resolvers_); + visitor->Trace(close_resolver_); + ScriptWrappable::Trace(visitor); ++ ActiveScriptWrappable::Trace(visitor); + } + + ExecutionContext* SerialPort::GetExecutionContext() const { diff --git a/patches/chromium/cherry-pick-910e9e40d376.patch b/patches/chromium/cherry-pick-910e9e40d376.patch new file mode 100644 index 0000000000000..ce9249722ccf4 --- /dev/null +++ b/patches/chromium/cherry-pick-910e9e40d376.patch @@ -0,0 +1,204 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Matt Menke +Date: Thu, 10 Jun 2021 07:05:07 +0000 +Subject: Fix URLLoader cleanup on CorsURLLoaderFactory destruction. + +Destroying one URLLoader can result in other URLLoaders getting errors, +due to to cache interconnectedness. CorsURLLoaderFactory's destructor +was not taking that into account. + +Also fix a bonus bug: HttpCache::Transaction::response_ wasn't being +cleared in HttpCache::Transaction::DoHeadersPhaseCannotProceed(), which +could result in DCHECKs when calling GetResponseInfo() when a +transaction that was waiting on a cached response from another +transaction ended up failing. + +[M90]: Fixed trivial conflict + +(cherry picked from commit 2f49a3c69a2184c95f43a395e4f33a3959cb8dbc) + +(cherry picked from commit baf23e3c5b1394982cff718a0e055d4f239245ad) + +Bug: 1209769 +Change-Id: I2c18caa488767a29011aca1e1b0bace24c1ba8fc +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2922826 +Reviewed-by: Maksim Orlovich +Commit-Queue: Matt Menke +Cr-Original-Original-Commit-Position: refs/heads/master@{#887522} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2935241 +Auto-Submit: Matt Menke +Cr-Original-Commit-Position: refs/branch-heads/4472@{#1433} +Cr-Original-Branched-From: 3d60439cfb36485e76a1c5bb7f513d3721b20da1-refs/heads/master@{#870763} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2948654 +Owners-Override: Victor-Gabriel Savu +Reviewed-by: Artem Sumaneev +Reviewed-by: Matt Menke +Commit-Queue: Victor-Gabriel Savu +Cr-Commit-Position: refs/branch-heads/4430@{#1513} +Cr-Branched-From: e5ce7dc4f7518237b3d9bb93cccca35d25216cbe-refs/heads/master@{#857950} + +diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc +index 663677c5865f6fee039fcd49a0adcd86a94b03ba..610d65e11b6b268d323247927bf2db3869906c90 100644 +--- a/net/http/http_cache_transaction.cc ++++ b/net/http/http_cache_transaction.cc +@@ -2101,6 +2101,8 @@ int HttpCache::Transaction::DoHeadersPhaseCannotProceed(int result) { + entry_ = nullptr; + new_entry_ = nullptr; + ++ SetResponse(HttpResponseInfo()); ++ + // Bypass the cache for timeout scenario. + if (result == ERR_CACHE_LOCK_TIMEOUT) + effective_load_flags_ |= LOAD_DISABLE_CACHE; +diff --git a/services/network/cors/cors_url_loader_factory.cc b/services/network/cors/cors_url_loader_factory.cc +index 93328dbcc3f219a92b3ebcc5c0a3b6af37ebd4a1..60f73825b80ef4c27cf5926e33c351d505389631 100644 +--- a/services/network/cors/cors_url_loader_factory.cc ++++ b/services/network/cors/cors_url_loader_factory.cc +@@ -229,7 +229,17 @@ CorsURLLoaderFactory::CorsURLLoaderFactory( + &CorsURLLoaderFactory::DeleteIfNeeded, base::Unretained(this))); + } + +-CorsURLLoaderFactory::~CorsURLLoaderFactory() = default; ++CorsURLLoaderFactory::~CorsURLLoaderFactory() { ++ // Delete loaders one at a time, since deleting one loader can cause another ++ // loader waiting on it to fail synchronously, which could result in the other ++ // loader calling DestroyURLLoader(). ++ while (!loaders_.empty()) { ++ // No need to call context_->LoaderDestroyed(), since this method is only ++ // called from the NetworkContext's destructor, or when there are no ++ // remaining URLLoaders. ++ loaders_.erase(loaders_.begin()); ++ } ++} + + void CorsURLLoaderFactory::OnLoaderCreated( + std::unique_ptr loader) { +diff --git a/services/network/cors/cors_url_loader_factory_unittest.cc b/services/network/cors/cors_url_loader_factory_unittest.cc +index 994d6f091e663a2b12d9002fa12526790fdc14e9..292d77116ceef94633e693009ce1b165c8b0af38 100644 +--- a/services/network/cors/cors_url_loader_factory_unittest.cc ++++ b/services/network/cors/cors_url_loader_factory_unittest.cc +@@ -8,7 +8,9 @@ + #include "base/test/scoped_feature_list.h" + #include "base/test/task_environment.h" + #include "mojo/public/cpp/bindings/remote.h" ++#include "net/base/load_flags.h" + #include "net/proxy_resolution/configured_proxy_resolution_service.h" ++#include "net/test/embedded_test_server/embedded_test_server.h" + #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" + #include "net/url_request/url_request_context.h" + #include "net/url_request/url_request_context_builder.h" +@@ -50,6 +52,9 @@ class CorsURLLoaderFactoryTest : public testing::Test { + protected: + // testing::Test implementation. + void SetUp() override { ++ test_server_.AddDefaultHandlers(); ++ ASSERT_TRUE(test_server_.Start()); ++ + network_service_ = NetworkService::CreateForTesting(); + + auto context_params = mojom::NetworkContextParams::New(); +@@ -69,7 +74,7 @@ class CorsURLLoaderFactoryTest : public testing::Test { + auto factory_params = network::mojom::URLLoaderFactoryParams::New(); + factory_params->process_id = kProcessId; + factory_params->request_initiator_origin_lock = +- url::Origin::Create(GURL("http://localhost")); ++ url::Origin::Create(test_server_.base_url()); + auto resource_scheduler_client = + base::MakeRefCounted( + kProcessId, kRouteId, &resource_scheduler_, +@@ -82,15 +87,25 @@ class CorsURLLoaderFactoryTest : public testing::Test { + } + + void CreateLoaderAndStart(const ResourceRequest& request) { ++ url_loaders_.emplace_back(mojo::Remote()); ++ test_cors_loader_clients_.emplace_back( ++ std::make_unique()); + cors_url_loader_factory_->CreateLoaderAndStart( +- url_loader_.BindNewPipeAndPassReceiver(), kRouteId, kRequestId, ++ url_loaders_.back().BindNewPipeAndPassReceiver(), kRouteId, kRequestId, + mojom::kURLLoadOptionNone, request, +- test_cors_loader_client_.CreateRemote(), ++ test_cors_loader_clients_.back()->CreateRemote(), + net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS)); + } + + void ResetFactory() { cors_url_loader_factory_.reset(); } + ++ net::test_server::EmbeddedTestServer* test_server() { return &test_server_; } ++ ++ std::vector>& ++ test_cors_loader_clients() { ++ return test_cors_loader_clients_; ++ } ++ + private: + // Test environment. + base::test::TaskEnvironment task_environment_; +@@ -100,15 +115,17 @@ class CorsURLLoaderFactoryTest : public testing::Test { + std::unique_ptr network_context_; + mojo::Remote network_context_remote_; + ++ net::test_server::EmbeddedTestServer test_server_; ++ + // CorsURLLoaderFactory instance under tests. + std::unique_ptr cors_url_loader_factory_; + mojo::Remote cors_url_loader_factory_remote_; + +- // Holds URLLoader that CreateLoaderAndStart() creates. +- mojo::Remote url_loader_; ++ // Holds the URLLoaders that CreateLoaderAndStart() creates. ++ std::vector> url_loaders_; + +- // TestURLLoaderClient that records callback activities. +- TestURLLoaderClient test_cors_loader_client_; ++ // TestURLLoaderClients that record callback activities. ++ std::vector> test_cors_loader_clients_; + + // Holds for allowed origin access lists. + OriginAccessList origin_access_list_; +@@ -119,7 +136,7 @@ class CorsURLLoaderFactoryTest : public testing::Test { + // Regression test for https://crbug.com/906305. + TEST_F(CorsURLLoaderFactoryTest, DestructionOrder) { + ResourceRequest request; +- GURL url("http://localhost"); ++ GURL url = test_server()->GetURL("/hung"); + request.mode = mojom::RequestMode::kNoCors; + request.credentials_mode = mojom::CredentialsMode::kOmit; + request.method = net::HttpRequestHeaders::kGetMethod; +@@ -142,5 +159,36 @@ TEST_F(CorsURLLoaderFactoryTest, DestructionOrder) { + ResetFactory(); + } + ++TEST_F(CorsURLLoaderFactoryTest, CleanupWithSharedCacheObjectInUse) { ++ // Create a loader for a response that hangs after receiving headers, and run ++ // it until headers are received. ++ ResourceRequest request; ++ GURL url = test_server()->GetURL("/hung-after-headers"); ++ request.mode = mojom::RequestMode::kNoCors; ++ request.credentials_mode = mojom::CredentialsMode::kOmit; ++ request.method = net::HttpRequestHeaders::kGetMethod; ++ request.url = url; ++ request.request_initiator = url::Origin::Create(url); ++ CreateLoaderAndStart(request); ++ test_cors_loader_clients().back()->RunUntilResponseReceived(); ++ ++ // Read only requests will fail synchonously on destruction of the request ++ // they're waiting on if they're in the |done_headers_queue| when the other ++ // request fails. Make a large number of such requests, spin the message loop ++ // so they end up blocked on the hung request, and then destroy all loads. A ++ // large number of loaders is needed because they're stored in a set, indexed ++ // by address, so teardown order is random. ++ request.load_flags = ++ net::LOAD_ONLY_FROM_CACHE | net::LOAD_SKIP_CACHE_VALIDATION; ++ for (int i = 0; i < 10; ++i) ++ CreateLoaderAndStart(request); ++ base::RunLoop().RunUntilIdle(); ++ ++ // This should result in a crash if tearing down one URLLoaderFactory ++ // resulting in a another one failing causes a crash during teardown. See ++ // https://crbug.com/1209769. ++ ResetFactory(); ++} ++ + } // namespace cors + } // namespace network diff --git a/patches/chromium/cherry-pick-ac9dc1235e28.patch b/patches/chromium/cherry-pick-ac9dc1235e28.patch new file mode 100644 index 0000000000000..d0838b9889996 --- /dev/null +++ b/patches/chromium/cherry-pick-ac9dc1235e28.patch @@ -0,0 +1,103 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ilya Nikolaevskiy +Date: Mon, 17 May 2021 08:34:41 +0000 +Subject: Add locks and empty string checks to FakeV4L2Impl + +FakeV4L2Impl is crashed by fuzzer with some weird ASAN errors, which +turned out to be a threading issue. + +Bug: 1205059,1196302 +Change-Id: Ieb3a917c9a4549b655862e69214774e183a70bc3 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2883613 +Reviewed-by: Ricky Liang +Commit-Queue: Ilya Nikolaevskiy +Cr-Commit-Position: refs/heads/master@{#883390} + +diff --git a/media/capture/video/linux/fake_v4l2_impl.cc b/media/capture/video/linux/fake_v4l2_impl.cc +index 4a976815d009e68b3740aa71e8c8fd641bf91493..09647474bed3c7c7b34cd9fb161edd2a7d2e170f 100644 +--- a/media/capture/video/linux/fake_v4l2_impl.cc ++++ b/media/capture/video/linux/fake_v4l2_impl.cc +@@ -380,10 +380,16 @@ FakeV4L2Impl::~FakeV4L2Impl() = default; + + void FakeV4L2Impl::AddDevice(const std::string& device_name, + const FakeV4L2DeviceConfig& config) { ++ base::AutoLock lock(lock_); + device_configs_.emplace(device_name, config); + } + + int FakeV4L2Impl::open(const char* device_name, int flags) { ++ if (!device_name) ++ return kInvalidId; ++ ++ base::AutoLock lock(lock_); ++ + std::string device_name_as_string(device_name); + auto device_configs_iter = device_configs_.find(device_name_as_string); + if (device_configs_iter == device_configs_.end()) +@@ -403,6 +409,7 @@ int FakeV4L2Impl::open(const char* device_name, int flags) { + } + + int FakeV4L2Impl::close(int fd) { ++ base::AutoLock lock(lock_); + auto device_iter = opened_devices_.find(fd); + if (device_iter == opened_devices_.end()) + return kErrorReturnValue; +@@ -412,6 +419,7 @@ int FakeV4L2Impl::close(int fd) { + } + + int FakeV4L2Impl::ioctl(int fd, int request, void* argp) { ++ base::AutoLock lock(lock_); + auto device_iter = opened_devices_.find(fd); + if (device_iter == opened_devices_.end()) + return EBADF; +@@ -518,6 +526,7 @@ void* FakeV4L2Impl::mmap(void* /*start*/, + int flags, + int fd, + off_t offset) { ++ base::AutoLock lock(lock_); + if (flags & MAP_FIXED) { + errno = EINVAL; + return MAP_FAILED; +@@ -543,10 +552,12 @@ void* FakeV4L2Impl::mmap(void* /*start*/, + } + + int FakeV4L2Impl::munmap(void* start, size_t length) { ++ base::AutoLock lock(lock_); + return kSuccessReturnValue; + } + + int FakeV4L2Impl::poll(struct pollfd* ufds, unsigned int nfds, int timeout) { ++ base::AutoLock lock(lock_); + if (nfds != 1) { + // We only support polling of a single device. + errno = EINVAL; +diff --git a/media/capture/video/linux/fake_v4l2_impl.h b/media/capture/video/linux/fake_v4l2_impl.h +index 0a035a97dd8761b08eb4cfdbe2865efc346f0e23..ae7167f95163581c756ab4951717fd4352c67757 100644 +--- a/media/capture/video/linux/fake_v4l2_impl.h ++++ b/media/capture/video/linux/fake_v4l2_impl.h +@@ -10,6 +10,7 @@ + + #include + ++#include "base/synchronization/lock.h" + #include "media/capture/capture_export.h" + #include "media/capture/video/linux/v4l2_capture_device.h" + #include "media/capture/video/video_capture_device_descriptor.h" +@@ -52,11 +53,13 @@ class CAPTURE_EXPORT FakeV4L2Impl : public V4L2CaptureDevice { + private: + class OpenedDevice; + +- int next_id_to_return_from_open_; +- std::map device_configs_; +- std::map device_name_to_open_id_map_; ++ base::Lock lock_; ++ ++ int next_id_to_return_from_open_ GUARDED_BY(lock_); ++ std::map device_configs_ GUARDED_BY(lock_); ++ std::map device_name_to_open_id_map_ GUARDED_BY(lock_); + std::map> +- opened_devices_; ++ opened_devices_ GUARDED_BY(lock_); + }; + + } // namespace media diff --git a/patches/chromium/cherry-pick-b77b38a3380c.patch b/patches/chromium/cherry-pick-b77b38a3380c.patch new file mode 100644 index 0000000000000..ba445dab6a2b8 --- /dev/null +++ b/patches/chromium/cherry-pick-b77b38a3380c.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Brandon Jones +Date: Wed, 16 Jun 2021 21:47:09 +0000 +Subject: Ensure that XRLayer includes base EventTarget in Trace + +Trace was skipping a level in the class hierarchy and calling +ScriptWrappable::Trace() instead. This was likely the result of the +class inheritance changing in the spec a while back and getting updated +elsewhere but not here, since it didn't raise any warnings. + +(cherry picked from commit 01b6f7e0a70648d7c7302454993f0bf86d5a0241) + +Bug: 1219857 +Change-Id: I4ac9f7b037ac5e5dd0e6d670f1d5a30e6344862f +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2964533 +Commit-Queue: Brandon Jones +Reviewed-by: Alexander Cooper +Cr-Original-Commit-Position: refs/heads/master@{#892650} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2967199 +Auto-Submit: Brandon Jones +Commit-Queue: Rubber Stamper +Bot-Commit: Rubber Stamper +Cr-Commit-Position: refs/branch-heads/4472@{#1492} +Cr-Branched-From: 3d60439cfb36485e76a1c5bb7f513d3721b20da1-refs/heads/master@{#870763} + +diff --git a/third_party/blink/renderer/modules/xr/xr_layer.cc b/third_party/blink/renderer/modules/xr/xr_layer.cc +index eaa8603c7354a5c8e71e9a2e6161824063804fb6..aa30a4cec88fa11b342695dc675ab572320e9166 100644 +--- a/third_party/blink/renderer/modules/xr/xr_layer.cc ++++ b/third_party/blink/renderer/modules/xr/xr_layer.cc +@@ -21,7 +21,7 @@ const AtomicString& XRLayer::InterfaceName() const { + + void XRLayer::Trace(Visitor* visitor) const { + visitor->Trace(session_); +- ScriptWrappable::Trace(visitor); ++ EventTargetWithInlineData::Trace(visitor); + } + + } // namespace blink diff --git a/patches/chromium/cherry-pick-cd98d7c0dae9.patch b/patches/chromium/cherry-pick-cd98d7c0dae9.patch new file mode 100644 index 0000000000000..e8efedb8601f5 --- /dev/null +++ b/patches/chromium/cherry-pick-cd98d7c0dae9.patch @@ -0,0 +1,50 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peng Huang +Date: Wed, 7 Jul 2021 20:50:53 +0000 +Subject: Fix UAF problem in SharedImageInterfaceInProcess + +(cherry picked from commit 38b4905f8d877b27bc2d4ccd4cfc0f82b636deea) + +Bug: 1216822 +Change-Id: I8ae1f7c406e1899e500ee7ddeaaf18230b1cbcb2 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2971144 +Commit-Queue: Peng Huang +Commit-Queue: Vasiliy Telezhnikov +Auto-Submit: Peng Huang +Reviewed-by: Vasiliy Telezhnikov +Cr-Original-Commit-Position: refs/heads/master@{#893931} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3011895 +Auto-Submit: Mason Freed +Reviewed-by: Peng Huang +Cr-Commit-Position: refs/branch-heads/4515@{#1369} +Cr-Branched-From: 488fc70865ddaa05324ac00a54a6eb783b4bc41c-refs/heads/master@{#885287} + +diff --git a/gpu/ipc/shared_image_interface_in_process.cc b/gpu/ipc/shared_image_interface_in_process.cc +index d6169e6b04b4ad4fd17b48507331dee059338610..e28ec015c8efce5d7af3c660d29f325869137b65 100644 +--- a/gpu/ipc/shared_image_interface_in_process.cc ++++ b/gpu/ipc/shared_image_interface_in_process.cc +@@ -93,6 +93,8 @@ void SharedImageInterfaceInProcess::DestroyOnGpu( + sync_point_client_state_->Destroy(); + sync_point_client_state_ = nullptr; + } ++ ++ context_state_ = nullptr; + completion->Signal(); + } + +diff --git a/gpu/ipc/shared_image_interface_in_process.h b/gpu/ipc/shared_image_interface_in_process.h +index 7ce2bc3eb52083b2505fb6d648f192cb5c7247e2..23bc32c0b35145c1cf7a14e519f205c66d5e7f47 100644 +--- a/gpu/ipc/shared_image_interface_in_process.h ++++ b/gpu/ipc/shared_image_interface_in_process.h +@@ -237,10 +237,7 @@ class GL_IN_PROCESS_CONTEXT_EXPORT SharedImageInterfaceInProcess + // Accessed on GPU thread. + // TODO(weiliangc): Check whether can be removed when !UsesSync(). + MailboxManager* mailbox_manager_; +- // Used to check if context is lost at destruction time. +- // TODO(weiliangc): SharedImageInterface should become active observer of +- // whether context is lost. +- SharedContextState* context_state_; ++ scoped_refptr context_state_; + // Created and only used by this SharedImageInterface. + SyncPointManager* sync_point_manager_; + scoped_refptr sync_point_client_state_; diff --git a/patches/chromium/cherry-pick-d9556a80a790.patch b/patches/chromium/cherry-pick-d9556a80a790.patch new file mode 100644 index 0000000000000..17d8125b87221 --- /dev/null +++ b/patches/chromium/cherry-pick-d9556a80a790.patch @@ -0,0 +1,197 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ted Meyer +Date: Mon, 7 Jun 2021 20:41:16 +0000 +Subject: A few fixes to the D3D11H264Accelerator + + - Adds a AsD3D11H264Picture method to H264Pictures because sometimes + there can be just normal H264Pictures in the DPB and this could cause + some invalid variable access as we were statically casting the + pointer before. + + - Adds a bounds check just in case there are more than 16 items in the + DPB. + +(cherry picked from commit 5a3cf91d0f2352e697017e13f4754989f46f2f3e) + +Bug: 1194689 +Change-Id: Ief2e1d00b451fbc0585dd0b22b5aff7a6918fa11 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2923118 +Commit-Queue: Ted Meyer +Reviewed-by: Frank Liberato +Cr-Original-Commit-Position: refs/heads/master@{#888267} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2944579 +Auto-Submit: Ted Meyer +Commit-Queue: Rubber Stamper +Bot-Commit: Rubber Stamper +Cr-Commit-Position: refs/branch-heads/4472@{#1455} +Cr-Branched-From: 3d60439cfb36485e76a1c5bb7f513d3721b20da1-refs/heads/master@{#870763} + +diff --git a/media/gpu/h264_dpb.cc b/media/gpu/h264_dpb.cc +index 8ef3bafb255349c6ac602c02a30615f0dd0b7d06..859e184b129f21f6af41b276051ca3a3adc03a7f 100644 +--- a/media/gpu/h264_dpb.cc ++++ b/media/gpu/h264_dpb.cc +@@ -55,6 +55,10 @@ VaapiH264Picture* H264Picture::AsVaapiH264Picture() { + return nullptr; + } + ++D3D11H264Picture* H264Picture::AsD3D11H264Picture() { ++ return nullptr; ++} ++ + H264DPB::H264DPB() : max_num_pics_(0) {} + H264DPB::~H264DPB() = default; + +diff --git a/media/gpu/h264_dpb.h b/media/gpu/h264_dpb.h +index 1395f9ecb35302632c49392d11fecb91436cbdf6..36abd4a8984dcb01ce85fc5fffa5ec916ecbf46a 100644 +--- a/media/gpu/h264_dpb.h ++++ b/media/gpu/h264_dpb.h +@@ -23,6 +23,7 @@ namespace media { + + class V4L2H264Picture; + class VaapiH264Picture; ++class D3D11H264Picture; + + // A picture (a frame or a field) in the H.264 spec sense. + // See spec at http://www.itu.int/rec/T-REC-H.264 +@@ -40,6 +41,7 @@ class MEDIA_GPU_EXPORT H264Picture : public CodecPicture { + + virtual V4L2H264Picture* AsV4L2H264Picture(); + virtual VaapiH264Picture* AsVaapiH264Picture(); ++ virtual D3D11H264Picture* AsD3D11H264Picture(); + + // Values calculated per H.264 specification or taken from slice header. + // See spec for more details on each (some names have been converted from +diff --git a/media/gpu/windows/d3d11_h264_accelerator.cc b/media/gpu/windows/d3d11_h264_accelerator.cc +index e87c1ece44f4c2af44e1c626ae69bfede43a0289..82abc9af5ed4255d5e262d539b4462e6e089fc61 100644 +--- a/media/gpu/windows/d3d11_h264_accelerator.cc ++++ b/media/gpu/windows/d3d11_h264_accelerator.cc +@@ -52,6 +52,8 @@ class D3D11H264Picture : public H264Picture { + D3D11PictureBuffer* picture; + size_t picture_index_; + ++ D3D11H264Picture* AsD3D11H264Picture() override { return this; } ++ + protected: + ~D3D11H264Picture() override; + }; +@@ -101,10 +103,12 @@ DecoderStatus D3D11H264Accelerator::SubmitFrameMetadata( + + HRESULT hr; + for (;;) { ++ D3D11H264Picture* d3d11_pic = pic->AsD3D11H264Picture(); ++ if (!d3d11_pic) ++ return DecoderStatus::kFail; + hr = video_context_->DecoderBeginFrame( +- video_decoder_.Get(), +- static_cast(pic.get())->picture->output_view().Get(), +- 0, nullptr); ++ video_decoder_.Get(), d3d11_pic->picture->output_view().Get(), 0, ++ nullptr); + + if (hr == E_PENDING || hr == D3DERR_WASSTILLDRAWING) { + // Hardware is busy. We should make the call again. +@@ -119,7 +123,7 @@ DecoderStatus D3D11H264Accelerator::SubmitFrameMetadata( + } + + sps_ = *sps; +- for (size_t i = 0; i < 16; i++) { ++ for (size_t i = 0; i < media::kRefFrameMaxCount; i++) { + ref_frame_list_[i].bPicEntry = 0xFF; + field_order_cnt_list_[i][0] = 0; + field_order_cnt_list_[i][1] = 0; +@@ -132,8 +136,19 @@ DecoderStatus D3D11H264Accelerator::SubmitFrameMetadata( + + int i = 0; + for (auto it = dpb.begin(); it != dpb.end(); i++, it++) { +- D3D11H264Picture* our_ref_pic = static_cast(it->get()); +- if (!our_ref_pic->ref) ++ // The DPB is supposed to have a maximum of 16 pictures in it, but there's ++ // nothing actually stopping it from having more. If we run into this case, ++ // something is clearly wrong, and we should just fail decoding rather than ++ // try to sort out which pictures really shouldn't be included. ++ if (i >= media::kRefFrameMaxCount) ++ return DecoderStatus::kFail; ++ ++ D3D11H264Picture* our_ref_pic = it->get()->AsD3D11H264Picture(); ++ // How does a non-d3d11 picture get here you might ask? The decoder ++ // inserts blank H264Picture objects that we can't use as part of filling ++ // gaps in frame numbers. If we see one, it's not a reference picture ++ // anyway, so skip it. ++ if (!our_ref_pic || !our_ref_pic->ref) + continue; + ref_frame_list_[i].Index7Bits = our_ref_pic->picture_index_; + ref_frame_list_[i].AssociatedFlag = our_ref_pic->long_term; +@@ -279,9 +294,8 @@ void D3D11H264Accelerator::PicParamsFromSliceHeader( + } + + void D3D11H264Accelerator::PicParamsFromPic(DXVA_PicParams_H264* pic_param, +- scoped_refptr pic) { +- pic_param->CurrPic.Index7Bits = +- static_cast(pic.get())->picture_index_; ++ D3D11H264Picture* pic) { ++ pic_param->CurrPic.Index7Bits = pic->picture_index_; + pic_param->RefPicFlag = pic->ref; + pic_param->frame_num = pic->frame_num; + +@@ -314,7 +328,11 @@ DecoderStatus D3D11H264Accelerator::SubmitSlice( + if (!PicParamsFromPPS(&pic_param, pps)) + return DecoderStatus::kFail; + PicParamsFromSliceHeader(&pic_param, slice_hdr); +- PicParamsFromPic(&pic_param, std::move(pic)); ++ ++ D3D11H264Picture* d3d11_pic = pic->AsD3D11H264Picture(); ++ if (!d3d11_pic) ++ return DecoderStatus::kFail; ++ PicParamsFromPic(&pic_param, d3d11_pic); + + memcpy(pic_param.RefFrameList, ref_frame_list_, + sizeof pic_param.RefFrameList); +@@ -573,9 +591,8 @@ void D3D11H264Accelerator::Reset() { + } + + bool D3D11H264Accelerator::OutputPicture(scoped_refptr pic) { +- D3D11H264Picture* our_pic = static_cast(pic.get()); +- +- return client_->OutputResult(our_pic, our_pic->picture); ++ D3D11H264Picture* our_pic = pic->AsD3D11H264Picture(); ++ return our_pic && client_->OutputResult(our_pic, our_pic->picture); + } + + void D3D11H264Accelerator::RecordFailure(const std::string& reason, +diff --git a/media/gpu/windows/d3d11_h264_accelerator.h b/media/gpu/windows/d3d11_h264_accelerator.h +index 00e2bd5cecd34f947c15aed1a7f5873b2ba4736c..c927706fb58b0637b6cf27516495028ead95325c 100644 +--- a/media/gpu/windows/d3d11_h264_accelerator.h ++++ b/media/gpu/windows/d3d11_h264_accelerator.h +@@ -27,6 +27,8 @@ + + namespace media { + ++constexpr int kRefFrameMaxCount = 16; ++ + class D3D11H264Accelerator; + class MediaLog; + +@@ -74,8 +76,7 @@ class D3D11H264Accelerator : public H264Decoder::H264Accelerator { + void PicParamsFromSliceHeader(DXVA_PicParams_H264* pic_param, + const H264SliceHeader* pps); + +- void PicParamsFromPic(DXVA_PicParams_H264* pic_param, +- scoped_refptr pic); ++ void PicParamsFromPic(DXVA_PicParams_H264* pic_param, D3D11H264Picture* pic); + + void SetVideoDecoder(ComD3D11VideoDecoder video_decoder); + +@@ -95,10 +96,10 @@ class D3D11H264Accelerator : public H264Decoder::H264Accelerator { + + // This information set at the beginning of a frame and saved for processing + // all the slices. +- DXVA_PicEntry_H264 ref_frame_list_[16]; ++ DXVA_PicEntry_H264 ref_frame_list_[kRefFrameMaxCount]; + H264SPS sps_; +- INT field_order_cnt_list_[16][2]; +- USHORT frame_num_list_[16]; ++ INT field_order_cnt_list_[kRefFrameMaxCount][2]; ++ USHORT frame_num_list_[kRefFrameMaxCount]; + UINT used_for_reference_flags_; + USHORT non_existing_frame_flags_; + diff --git a/patches/chromium/cherry-pick-e60cc80ff744.patch b/patches/chromium/cherry-pick-e60cc80ff744.patch new file mode 100644 index 0000000000000..7dee0278eac65 --- /dev/null +++ b/patches/chromium/cherry-pick-e60cc80ff744.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shrek Shao +Date: Tue, 29 Jun 2021 01:17:03 +0000 +Subject: Fix multidraw validation drawcount + offset out of bounds + +(cherry picked from commit 7d0a12ce19fed024d56b95a692d888fe3ef14e2f) + +Bug: 1219886 +Change-Id: I8a84664150758370d9a77ee22ac5549bead0e37e +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2977850 +Reviewed-by: Kenneth Russell +Commit-Queue: Kenneth Russell +Cr-Original-Commit-Position: refs/heads/master@{#895423} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2988885 +Reviewed-by: Shrek Shao +Reviewed-by: Austin Eng +Cr-Commit-Position: refs/branch-heads/4515@{#1101} +Cr-Branched-From: 488fc70865ddaa05324ac00a54a6eb783b4bc41c-refs/heads/master@{#885287} + +diff --git a/third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.cc b/third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.cc +index 6720d46394ae0346331e133f0fa8d24e5dd1e95b..bae874bbf23cdb497b92bda7bb87429dafe7d5d4 100644 +--- a/third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.cc ++++ b/third_party/blink/renderer/modules/webgl/webgl_multi_draw_common.cc +@@ -34,6 +34,11 @@ bool WebGLMultiDrawCommon::ValidateArray(WebGLExtensionScopedContext* scoped, + outOfBoundsDescription); + return false; + } ++ if (static_cast(drawcount) + offset > size) { ++ scoped->Context()->SynthesizeGLError(GL_INVALID_OPERATION, function_name, ++ "drawcount plus offset out of bounds"); ++ return false; ++ } + return true; + } + diff --git a/patches/chromium/cherry-pick-ff0d013f60fa.patch b/patches/chromium/cherry-pick-ff0d013f60fa.patch new file mode 100644 index 0000000000000..65d804a108189 --- /dev/null +++ b/patches/chromium/cherry-pick-ff0d013f60fa.patch @@ -0,0 +1,53 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Raymond Toy +Date: Wed, 26 May 2021 16:06:10 +0000 +Subject: Add AudioHandler to orphan handlers when context is suspended. + +If the context is suspended, pulling of the audio graph is stopped. +But we still need to add the handler in this case so that when the +context is resumed, the handler is still alive until it can be safely +removed. Hence, we must still add the handler if the context is +suspended. + +Test cases from issue 1176218 manually tested with no failures. Also +this doesn't cause any regressions in issue 1003807 and issue 1017961. +(Manually tested the test cases from those issues.) + +(cherry picked from commit 4a38ea3f1f78e0a0ffc1464e227cee6c1f2fd90b) + +Bug: 1176218 +Change-Id: Icd927c488505dfee9ff716866f98286e286d546a +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2874771 +Commit-Queue: Raymond Toy +Cr-Original-Commit-Position: refs/heads/master@{#881533} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2917093 +Reviewed-by: Raymond Toy +Reviewed-by: Victor-Gabriel Savu +Commit-Queue: Jana Grill +Cr-Commit-Position: refs/branch-heads/4240@{#1648} +Cr-Branched-From: f297677702651916bbf65e59c0d4bbd4ce57d1ee-refs/heads/master@{#800218} + +diff --git a/third_party/blink/renderer/modules/webaudio/audio_node.cc b/third_party/blink/renderer/modules/webaudio/audio_node.cc +index e1f1a068d233f633e2e2c911f5954632ebf60654..22974448d059f3523e0cbf2d7d1bfd9877d98bbf 100644 +--- a/third_party/blink/renderer/modules/webaudio/audio_node.cc ++++ b/third_party/blink/renderer/modules/webaudio/audio_node.cc +@@ -609,13 +609,13 @@ void AudioNode::Dispose() { + BaseAudioContext::GraphAutoLocker locker(context()); + Handler().Dispose(); + +- // Add the handler to the orphan list if the context is pulling on the audio +- // graph. This keeps the handler alive until it can be deleted at a safe +- // point (in pre/post handler task). If graph isn't being pulled, we can +- // delete the handler now since nothing on the audio thread will be touching +- // it. ++ // Add the handler to the orphan list. This keeps the handler alive until it ++ // can be deleted at a safe point (in pre/post handler task). If the graph is ++ // being processed, the handler must be added. If the context is suspended, ++ // the handler still needs to be added in case the context is resumed. + DCHECK(context()); +- if (context()->IsPullingAudioGraph()) { ++ if (context()->IsPullingAudioGraph() || ++ context()->ContextState() == BaseAudioContext::kSuspended) { + context()->GetDeferredTaskHandler().AddRenderingOrphanHandler( + std::move(handler_)); + } diff --git a/patches/chromium/fileapi_terminate_filereaderloader_before_dispatching_onabort_event.patch b/patches/chromium/fileapi_terminate_filereaderloader_before_dispatching_onabort_event.patch new file mode 100644 index 0000000000000..7bee0b1ce8198 --- /dev/null +++ b/patches/chromium/fileapi_terminate_filereaderloader_before_dispatching_onabort_event.patch @@ -0,0 +1,58 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrey Belenko +Date: Wed, 19 May 2021 12:27:18 +0200 +Subject: FileAPI: Terminate FileReaderLoader before dispatching onabort event. + +Otherwise FileReader could end up in an inconsistent state where a load +is still in progress while the state was set to done. + +(cherry picked from commit a74c980df61dd7367ad1b11e6a735be82d2696f0) + +Bug: 1201073 +Change-Id: Ib2c833537e1badc57d125568d5d35f53f12582a8 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2860442 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2871355 + +diff --git a/third_party/blink/renderer/core/fileapi/file_reader.cc b/third_party/blink/renderer/core/fileapi/file_reader.cc +index 2bbc4db7923c659eda6d63230998ca3414f397d3..93221ba5cf92b9efd702378e1b94cca4fb6ab470 100644 +--- a/third_party/blink/renderer/core/fileapi/file_reader.cc ++++ b/third_party/blink/renderer/core/fileapi/file_reader.cc +@@ -335,7 +335,10 @@ void FileReader::abort() { + loading_state_ = kLoadingStateAborted; + + DCHECK_NE(kDone, state_); +- state_ = kDone; ++ // Synchronously cancel the loader before dispatching events. This way we make ++ // sure the FileReader internal state stays consistent even if another load ++ // is started from one of the event handlers, or right after abort returns. ++ Terminate(); + + base::AutoReset firing_events(&still_firing_events_, true); + +@@ -347,15 +350,12 @@ void FileReader::abort() { + ThrottlingController::RemoveReader(GetExecutionContext(), this); + + FireEvent(event_type_names::kAbort); ++ // TODO(https://crbug.com/1204139): Only fire loadend event if no new load was ++ // started from the abort event handler. + FireEvent(event_type_names::kLoadend); + + // All possible events have fired and we're done, no more pending activity. + ThrottlingController::FinishReader(GetExecutionContext(), this, final_step); +- +- // Also synchronously cancel the loader, as script might initiate a new load +- // right after this method returns, in which case an async termination would +- // terminate the wrong loader. +- Terminate(); + } + + void FileReader::result(StringOrArrayBuffer& result_attribute) const { +@@ -428,6 +428,8 @@ void FileReader::DidFinishLoading() { + ThrottlingController::RemoveReader(GetExecutionContext(), this); + + FireEvent(event_type_names::kLoad); ++ // TODO(https://crbug.com/1204139): Only fire loadend event if no new load was ++ // started from the abort event handler. + FireEvent(event_type_names::kLoadend); + + // All possible events have fired and we're done, no more pending activity. diff --git a/patches/chromium/fix_use-after-free_with_xslt_strip-space.patch b/patches/chromium/fix_use-after-free_with_xslt_strip-space.patch new file mode 100644 index 0000000000000..9c4f22214c388 --- /dev/null +++ b/patches/chromium/fix_use-after-free_with_xslt_strip-space.patch @@ -0,0 +1,431 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Joey Arhar +Date: Wed, 16 Jun 2021 02:41:13 +0000 +Subject: Fix use-after-free with XSLT strip-space + +Fixed: 1219209 +Change-Id: I3baab9d1b419407d964a80f10c6ca05e0294554f +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2965632 +Commit-Queue: Joey Arhar +Reviewed-by: Stephen Chenney +Cr-Commit-Position: refs/heads/master@{#892861} + +diff --git a/third_party/blink/web_tests/external/wpt/xslt/strip-space-crash.xml b/third_party/blink/web_tests/external/wpt/xslt/strip-space-crash.xml +new file mode 100644 +index 0000000000000000000000000000000000000000..61a906a5e74b9c88061c565615187f9970baff72 +--- /dev/null ++++ b/third_party/blink/web_tests/external/wpt/xslt/strip-space-crash.xml +@@ -0,0 +1,33 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/third_party/libxslt/chromium/Fix-use-after-free-in-xsltApplyTemplates.patch b/third_party/libxslt/chromium/Fix-use-after-free-in-xsltApplyTemplates.patch +new file mode 100644 +index 0000000000000000000000000000000000000000..9b4c28d8756d6cf95027fc105ec875be5f71d952 +--- /dev/null ++++ b/third_party/libxslt/chromium/Fix-use-after-free-in-xsltApplyTemplates.patch +@@ -0,0 +1,195 @@ ++From: Nick Wellnhofer ++Date: Sat, 12 Jun 2021 20:02:53 +0200 ++Subject: [PATCH] Fix use-after-free in xsltApplyTemplates ++ ++xsltApplyTemplates without a select expression could delete nodes in ++the source document. ++ ++1. Text nodes with strippable whitespace ++ ++Whitespace from input documents is already stripped, so there's no ++need to strip it again. Under certain circumstances, xsltApplyTemplates ++could be fooled into deleting text nodes that are still referenced, ++resulting in a use-after-free. ++ ++2. The DTD ++ ++The DTD was only unlinked, but there's no good reason to do this just ++now. Maybe it was meant as a micro-optimization. ++ ++3. Unknown nodes ++ ++Useless and dangerous as well, especially with XInclude nodes. ++See https://gitlab.gnome.org/GNOME/libxml2/-/issues/268 ++ ++Simply stop trying to uselessly delete nodes when applying a template. ++This part of the code is probably a leftover from a time where ++xsltApplyStripSpaces wasn't implemented yet. Also note that ++xsltApplyTemplates with a select expression never tried to delete ++nodes. ++ ++Also stop xsltDefaultProcessOneNode from deleting nodes for the same ++reasons. ++--- ++ libxslt/transform.c | 119 +++----------------------------------------- ++ 1 file changed, 7 insertions(+), 112 deletions(-) ++ ++diff --git a/libxslt/transform.c b/libxslt/transform.c ++index 04522154..3aba354f 100644 ++--- a/libxslt/transform.c +++++ b/libxslt/transform.c ++@@ -1895,7 +1895,7 @@ static void ++ xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node, ++ xsltStackElemPtr params) { ++ xmlNodePtr copy; ++- xmlNodePtr delete = NULL, cur; +++ xmlNodePtr cur; ++ int nbchild = 0, oldSize; ++ int childno = 0, oldPos; ++ xsltTemplatePtr template; ++@@ -1968,54 +1968,13 @@ xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node, ++ return; ++ } ++ /* ++- * Handling of Elements: first pass, cleanup and counting +++ * Handling of Elements: first pass, counting ++ */ ++ cur = node->children; ++ while (cur != NULL) { ++- switch (cur->type) { ++- case XML_TEXT_NODE: ++- case XML_CDATA_SECTION_NODE: ++- case XML_DOCUMENT_NODE: ++- case XML_HTML_DOCUMENT_NODE: ++- case XML_ELEMENT_NODE: ++- case XML_PI_NODE: ++- case XML_COMMENT_NODE: ++- nbchild++; ++- break; ++- case XML_DTD_NODE: ++- /* Unlink the DTD, it's still reachable using doc->intSubset */ ++- if (cur->next != NULL) ++- cur->next->prev = cur->prev; ++- if (cur->prev != NULL) ++- cur->prev->next = cur->next; ++- break; ++- default: ++-#ifdef WITH_XSLT_DEBUG_PROCESS ++- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, ++- "xsltDefaultProcessOneNode: skipping node type %d\n", ++- cur->type)); ++-#endif ++- delete = cur; ++- } +++ if (IS_XSLT_REAL_NODE(cur)) +++ nbchild++; ++ cur = cur->next; ++- if (delete != NULL) { ++-#ifdef WITH_XSLT_DEBUG_PROCESS ++- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, ++- "xsltDefaultProcessOneNode: removing ignorable blank node\n")); ++-#endif ++- xmlUnlinkNode(delete); ++- xmlFreeNode(delete); ++- delete = NULL; ++- } ++- } ++- if (delete != NULL) { ++-#ifdef WITH_XSLT_DEBUG_PROCESS ++- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, ++- "xsltDefaultProcessOneNode: removing ignorable blank node\n")); ++-#endif ++- xmlUnlinkNode(delete); ++- xmlFreeNode(delete); ++- delete = NULL; ++ } ++ ++ /* ++@@ -4864,7 +4823,7 @@ xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node, ++ xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp; ++ #endif ++ int i; ++- xmlNodePtr cur, delNode = NULL, oldContextNode; +++ xmlNodePtr cur, oldContextNode; ++ xmlNodeSetPtr list = NULL, oldList; ++ xsltStackElemPtr withParams = NULL; ++ int oldXPProximityPosition, oldXPContextSize; ++@@ -4998,73 +4957,9 @@ xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node, ++ else ++ cur = NULL; ++ while (cur != NULL) { ++- switch (cur->type) { ++- case XML_TEXT_NODE: ++- if ((IS_BLANK_NODE(cur)) && ++- (cur->parent != NULL) && ++- (cur->parent->type == XML_ELEMENT_NODE) && ++- (ctxt->style->stripSpaces != NULL)) { ++- const xmlChar *val; ++- ++- if (cur->parent->ns != NULL) { ++- val = (const xmlChar *) ++- xmlHashLookup2(ctxt->style->stripSpaces, ++- cur->parent->name, ++- cur->parent->ns->href); ++- if (val == NULL) { ++- val = (const xmlChar *) ++- xmlHashLookup2(ctxt->style->stripSpaces, ++- BAD_CAST "*", ++- cur->parent->ns->href); ++- } ++- } else { ++- val = (const xmlChar *) ++- xmlHashLookup2(ctxt->style->stripSpaces, ++- cur->parent->name, NULL); ++- } ++- if ((val != NULL) && ++- (xmlStrEqual(val, (xmlChar *) "strip"))) { ++- delNode = cur; ++- break; ++- } ++- } ++- /* Intentional fall-through */ ++- case XML_ELEMENT_NODE: ++- case XML_DOCUMENT_NODE: ++- case XML_HTML_DOCUMENT_NODE: ++- case XML_CDATA_SECTION_NODE: ++- case XML_PI_NODE: ++- case XML_COMMENT_NODE: ++- xmlXPathNodeSetAddUnique(list, cur); ++- break; ++- case XML_DTD_NODE: ++- /* Unlink the DTD, it's still reachable ++- * using doc->intSubset */ ++- if (cur->next != NULL) ++- cur->next->prev = cur->prev; ++- if (cur->prev != NULL) ++- cur->prev->next = cur->next; ++- break; ++- case XML_NAMESPACE_DECL: ++- break; ++- default: ++-#ifdef WITH_XSLT_DEBUG_PROCESS ++- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, ++- "xsltApplyTemplates: skipping cur type %d\n", ++- cur->type)); ++-#endif ++- delNode = cur; ++- } +++ if (IS_XSLT_REAL_NODE(cur)) +++ xmlXPathNodeSetAddUnique(list, cur); ++ cur = cur->next; ++- if (delNode != NULL) { ++-#ifdef WITH_XSLT_DEBUG_PROCESS ++- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, ++- "xsltApplyTemplates: removing ignorable blank cur\n")); ++-#endif ++- xmlUnlinkNode(delNode); ++- xmlFreeNode(delNode); ++- delNode = NULL; ++- } ++ } ++ } ++ ++-- ++2.20.1 (Apple Git-117) ++ +diff --git a/third_party/libxslt/chromium/roll.py b/third_party/libxslt/chromium/roll.py +index 352bbd6d937f19c5cbb409f184f5b4e0abf4b7b3..c438a9eb96dcc62ca827fb4a647fb2cf1cc8cc0b 100755 +--- a/third_party/libxslt/chromium/roll.py ++++ b/third_party/libxslt/chromium/roll.py +@@ -67,6 +67,7 @@ import tempfile + PATCHES = [ + 'get-file-attributes-a.patch', + 'xslt-locale.patch', ++ 'Fix-use-after-free-in-xsltApplyTemplates.patch', + ] + + +diff --git a/third_party/libxslt/src/libxslt.spec b/third_party/libxslt/src/libxslt.spec +index 80b320fb86980367cddc579c386c24a2a1708f7c..7fb51e275fa4cc4a2bfc613ffb3868f464deeb5a 100644 +--- a/third_party/libxslt/src/libxslt.spec ++++ b/third_party/libxslt/src/libxslt.spec +@@ -128,5 +128,5 @@ rm -fr %{buildroot} + %doc python/tests/*.xsl + + %changelog +-* Fri Nov 8 2019 Daniel Veillard ++* Tue Jun 15 2021 Daniel Veillard + - upstream release 1.1.34 see http://xmlsoft.org/XSLT/news.html +diff --git a/third_party/libxslt/src/libxslt/transform.c b/third_party/libxslt/src/libxslt/transform.c +index d1c479320eca266c7b0996e3c16d47e7d6c5aaa9..265f5b3856f785f565691e2f5939c99275183e7f 100644 +--- a/third_party/libxslt/src/libxslt/transform.c ++++ b/third_party/libxslt/src/libxslt/transform.c +@@ -1895,7 +1895,7 @@ static void + xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node, + xsltStackElemPtr params) { + xmlNodePtr copy; +- xmlNodePtr delete = NULL, cur; ++ xmlNodePtr cur; + int nbchild = 0, oldSize; + int childno = 0, oldPos; + xsltTemplatePtr template; +@@ -1968,54 +1968,13 @@ xsltDefaultProcessOneNode(xsltTransformContextPtr ctxt, xmlNodePtr node, + return; + } + /* +- * Handling of Elements: first pass, cleanup and counting ++ * Handling of Elements: first pass, counting + */ + cur = node->children; + while (cur != NULL) { +- switch (cur->type) { +- case XML_TEXT_NODE: +- case XML_CDATA_SECTION_NODE: +- case XML_DOCUMENT_NODE: +- case XML_HTML_DOCUMENT_NODE: +- case XML_ELEMENT_NODE: +- case XML_PI_NODE: +- case XML_COMMENT_NODE: +- nbchild++; +- break; +- case XML_DTD_NODE: +- /* Unlink the DTD, it's still reachable using doc->intSubset */ +- if (cur->next != NULL) +- cur->next->prev = cur->prev; +- if (cur->prev != NULL) +- cur->prev->next = cur->next; +- break; +- default: +-#ifdef WITH_XSLT_DEBUG_PROCESS +- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, +- "xsltDefaultProcessOneNode: skipping node type %d\n", +- cur->type)); +-#endif +- delete = cur; +- } ++ if (IS_XSLT_REAL_NODE(cur)) ++ nbchild++; + cur = cur->next; +- if (delete != NULL) { +-#ifdef WITH_XSLT_DEBUG_PROCESS +- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, +- "xsltDefaultProcessOneNode: removing ignorable blank node\n")); +-#endif +- xmlUnlinkNode(delete); +- xmlFreeNode(delete); +- delete = NULL; +- } +- } +- if (delete != NULL) { +-#ifdef WITH_XSLT_DEBUG_PROCESS +- XSLT_TRACE(ctxt,XSLT_TRACE_PROCESS_NODE,xsltGenericDebug(xsltGenericDebugContext, +- "xsltDefaultProcessOneNode: removing ignorable blank node\n")); +-#endif +- xmlUnlinkNode(delete); +- xmlFreeNode(delete); +- delete = NULL; + } + + /* +@@ -4864,7 +4823,7 @@ xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node, + xsltStylePreCompPtr comp = (xsltStylePreCompPtr) castedComp; + #endif + int i; +- xmlNodePtr cur, delNode = NULL, oldContextNode; ++ xmlNodePtr cur, oldContextNode; + xmlNodeSetPtr list = NULL, oldList; + xsltStackElemPtr withParams = NULL; + int oldXPProximityPosition, oldXPContextSize; +@@ -4998,73 +4957,9 @@ xsltApplyTemplates(xsltTransformContextPtr ctxt, xmlNodePtr node, + else + cur = NULL; + while (cur != NULL) { +- switch (cur->type) { +- case XML_TEXT_NODE: +- if ((IS_BLANK_NODE(cur)) && +- (cur->parent != NULL) && +- (cur->parent->type == XML_ELEMENT_NODE) && +- (ctxt->style->stripSpaces != NULL)) { +- const xmlChar *val; +- +- if (cur->parent->ns != NULL) { +- val = (const xmlChar *) +- xmlHashLookup2(ctxt->style->stripSpaces, +- cur->parent->name, +- cur->parent->ns->href); +- if (val == NULL) { +- val = (const xmlChar *) +- xmlHashLookup2(ctxt->style->stripSpaces, +- BAD_CAST "*", +- cur->parent->ns->href); +- } +- } else { +- val = (const xmlChar *) +- xmlHashLookup2(ctxt->style->stripSpaces, +- cur->parent->name, NULL); +- } +- if ((val != NULL) && +- (xmlStrEqual(val, (xmlChar *) "strip"))) { +- delNode = cur; +- break; +- } +- } +- /* Intentional fall-through */ +- case XML_ELEMENT_NODE: +- case XML_DOCUMENT_NODE: +- case XML_HTML_DOCUMENT_NODE: +- case XML_CDATA_SECTION_NODE: +- case XML_PI_NODE: +- case XML_COMMENT_NODE: +- xmlXPathNodeSetAddUnique(list, cur); +- break; +- case XML_DTD_NODE: +- /* Unlink the DTD, it's still reachable +- * using doc->intSubset */ +- if (cur->next != NULL) +- cur->next->prev = cur->prev; +- if (cur->prev != NULL) +- cur->prev->next = cur->next; +- break; +- case XML_NAMESPACE_DECL: +- break; +- default: +-#ifdef WITH_XSLT_DEBUG_PROCESS +- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, +- "xsltApplyTemplates: skipping cur type %d\n", +- cur->type)); +-#endif +- delNode = cur; +- } ++ if (IS_XSLT_REAL_NODE(cur)) ++ xmlXPathNodeSetAddUnique(list, cur); + cur = cur->next; +- if (delNode != NULL) { +-#ifdef WITH_XSLT_DEBUG_PROCESS +- XSLT_TRACE(ctxt,XSLT_TRACE_APPLY_TEMPLATES,xsltGenericDebug(xsltGenericDebugContext, +- "xsltApplyTemplates: removing ignorable blank cur\n")); +-#endif +- xmlUnlinkNode(delNode); +- xmlFreeNode(delNode); +- delNode = NULL; +- } + } + } + diff --git a/patches/chromium/guard_webcontents_downloadimage_against_malformed_renderer.patch b/patches/chromium/guard_webcontents_downloadimage_against_malformed_renderer.patch new file mode 100644 index 0000000000000..fcee223cb0d37 --- /dev/null +++ b/patches/chromium/guard_webcontents_downloadimage_against_malformed_renderer.patch @@ -0,0 +1,232 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrey Belenko +Date: Wed, 19 May 2021 10:54:46 +0200 +Subject: Guard WebContents::DownloadImage() against malformed renderer + response + +Callers expect that ImageDownloadCallback gets invoked with two vectors +having the same number of elements (one containing the bitmaps and the +other one the corresponding sizes). + +However, these vectors are populated directly from the Mojo response, +so there needs to be some browser-process sanitization to protect +against buggy or compromised renderers. + +In this patch, WebContentsImpl::OnDidDownloadImage() mimics a 400 error +if the response is malformed, similarly to how it's done in other edge +cases (renderer process dead upon download). Because this scenario is +a violation of the Mojo API contract, the browser process also issues +a bad message log (newly-introduced WCI_INVALID_DOWNLOAD_IMAGE_RESULT) +and shuts down the renderer process. + +(cherry picked from commit 034ba14e44f08e8ca84b42350f3238f847e08e5f) + +Change-Id: Ic0843e10efc26809fabd8f1bbe506ba1703d1486 +Fixed: 1201446 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2871796 + +diff --git a/components/favicon/core/favicon_handler.cc b/components/favicon/core/favicon_handler.cc +index 3d278c8e7cb1212c266e3b1838be8f658165a795..197901e64c7cd8d8e2750c28d502ee5428b35df4 100644 +--- a/components/favicon/core/favicon_handler.cc ++++ b/components/favicon/core/favicon_handler.cc +@@ -507,6 +507,8 @@ void FaviconHandler::OnDidDownloadFavicon( + const GURL& image_url, + const std::vector& bitmaps, + const std::vector& original_bitmap_sizes) { ++ DCHECK_EQ(bitmaps.size(), original_bitmap_sizes.size()); ++ + // Mark download as finished. + image_download_request_.Cancel(); + +diff --git a/components/favicon/core/favicon_handler.h b/components/favicon/core/favicon_handler.h +index 98706de7a7bcdeee857acd5a9113c45ecf82dca7..574d88ac91a6322644cbe5fda9e964807830c20e 100644 +--- a/components/favicon/core/favicon_handler.h ++++ b/components/favicon/core/favicon_handler.h +@@ -238,7 +238,9 @@ class FaviconHandler { + void ScheduleImageDownload(const GURL& image_url, + favicon_base::IconType icon_type); + +- // Triggered when a download of an image has finished. ++ // Triggered when a download of an image has finished. |bitmaps| and ++ // |original_bitmap_sizes| must contain the same number of elements (i.e. same ++ // vector size). + void OnDidDownloadFavicon( + favicon_base::IconType icon_type, + int id, +diff --git a/components/favicon/ios/web_favicon_driver.mm b/components/favicon/ios/web_favicon_driver.mm +index 963a4dbcc5c971ea53c5d603cc73d1d2dab4f3ae..1dd5f4f2b38b55b8831aa527dd52ae11d45632fb 100644 +--- a/components/favicon/ios/web_favicon_driver.mm ++++ b/components/favicon/ios/web_favicon_driver.mm +@@ -75,6 +75,7 @@ + for (const auto& frame : frames) { + sizes.push_back(gfx::Size(frame.width(), frame.height())); + } ++ DCHECK_EQ(frames.size(), sizes.size()); + } + std::move(local_callback) + .Run(local_download_id, metadata.http_response_code, local_url, +diff --git a/components/favicon_base/select_favicon_frames.cc b/components/favicon_base/select_favicon_frames.cc +index 90b58e621492d0e503f7965de91581c0a451d163..73cd7dd5331a818f413d831b4ae596bc88805a8a 100644 +--- a/components/favicon_base/select_favicon_frames.cc ++++ b/components/favicon_base/select_favicon_frames.cc +@@ -216,6 +216,7 @@ gfx::ImageSkia CreateFaviconImageSkia( + const std::vector& original_sizes, + int desired_size_in_dip, + float* score) { ++ DCHECK_EQ(bitmaps.size(), original_sizes.size()); + + const std::vector& favicon_scales = favicon_base::GetFaviconScales(); + std::vector desired_sizes; +diff --git a/components/favicon_base/select_favicon_frames.h b/components/favicon_base/select_favicon_frames.h +index 573a38c79cddf839622488589b71b4d19fbdfba6..eab1e54466763e5a6a6069a29e877da054972fa8 100644 +--- a/components/favicon_base/select_favicon_frames.h ++++ b/components/favicon_base/select_favicon_frames.h +@@ -38,6 +38,8 @@ extern const float kSelectFaviconFramesInvalidScore; + // it inspired by this method. + // If an unsupported scale (not in the favicon_base::GetFaviconScales()) + // is requested, the ImageSkia will automatically scales using lancoz3. ++// |original_sizes| represents the pixel sizes of the favicon bitmaps in ++// |bitmaps|, which also means both vectors must have the same size. + gfx::ImageSkia CreateFaviconImageSkia( + const std::vector& bitmaps, + const std::vector& original_sizes, +diff --git a/content/browser/bad_message.h b/content/browser/bad_message.h +index c6675ef501de6cbaa175793ac0b13ba9b93a12e6..e198d661c711dc648a4e4c2249e0a60f69c406da 100644 +--- a/content/browser/bad_message.h ++++ b/content/browser/bad_message.h +@@ -260,6 +260,15 @@ enum BadMessageReason { + RFH_RECEIVED_ASSOCIATED_MESSAGE_WHILE_BFCACHED = 232, + RWH_CLOSE_PORTAL = 233, + MSDH_INVALID_STREAM_TYPE = 234, ++ RFH_CREATE_CHILD_FRAME_TOKENS_NOT_FOUND = 235, ++ ASGH_ASSOCIATED_INTERFACE_REQUEST = 236, ++ ASGH_RECEIVED_CONTROL_MESSAGE = 237, ++ CSDH_BAD_OWNER = 238, ++ SYNC_COMPOSITOR_NO_LOCAL_SURFACE_ID = 239, ++ WCI_INVALID_FULLSCREEN_OPTIONS = 240, ++ PAYMENTS_WITHOUT_PERMISSION = 241, ++ WEB_BUNDLE_INVALID_NAVIGATION_URL = 242, ++ WCI_INVALID_DOWNLOAD_IMAGE_RESULT = 243, + + // Please add new elements here. The naming convention is abbreviated class + // name (e.g. RenderFrameHost becomes RFH) plus a unique description of the +diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc +index 750944d45d66f70a5e32219148a4f0cb9edd351c..d0e25934cda73577524b80051b7e4cd6150077e8 100644 +--- a/content/browser/web_contents/web_contents_impl.cc ++++ b/content/browser/web_contents/web_contents_impl.cc +@@ -169,6 +169,7 @@ + #include "third_party/blink/public/common/web_preferences/web_preferences.h" + #include "third_party/blink/public/mojom/frame/frame.mojom.h" + #include "third_party/blink/public/mojom/frame/fullscreen.mojom.h" ++#include "third_party/blink/public/mojom/image_downloader/image_downloader.mojom.h" + #include "third_party/blink/public/mojom/loader/pause_subresource_loading_handle.mojom.h" + #include "third_party/blink/public/mojom/mediastream/media_stream.mojom-shared.h" + #include "third_party/skia/include/core/SkBitmap.h" +@@ -5066,18 +5067,18 @@ int WebContentsImpl::DownloadImageInFrame( + // respond with a 400 HTTP error code to indicate that something went wrong. + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, +- base::BindOnce(&WebContentsImpl::OnDidDownloadImage, +- weak_factory_.GetWeakPtr(), std::move(callback), +- download_id, url, 400, std::vector(), +- std::vector())); ++ base::BindOnce( ++ &WebContentsImpl::OnDidDownloadImage, weak_factory_.GetWeakPtr(), ++ initiator_frame->GetWeakPtr(), std::move(callback), download_id, ++ url, 400, std::vector(), std::vector())); + return download_id; + } + + mojo_image_downloader->DownloadImage( + url, is_favicon, preferred_size, max_bitmap_size, bypass_cache, + base::BindOnce(&WebContentsImpl::OnDidDownloadImage, +- weak_factory_.GetWeakPtr(), std::move(callback), +- download_id, url)); ++ weak_factory_.GetWeakPtr(), initiator_frame->GetWeakPtr(), ++ std::move(callback), download_id, url)); + return download_id; + } + +@@ -8044,6 +8045,7 @@ bool WebContentsImpl::CompletedFirstVisuallyNonEmptyPaint() { + } + + void WebContentsImpl::OnDidDownloadImage( ++ base::WeakPtr rfh, + ImageDownloadCallback callback, + int id, + const GURL& image_url, +@@ -8053,6 +8055,21 @@ void WebContentsImpl::OnDidDownloadImage( + OPTIONAL_TRACE_EVENT1("content", "WebContentsImpl::OnDidDownloadImage", + "image_url", + base::trace_event::ValueToString(image_url)); ++ ++ // Guard against buggy or compromised renderers that could violate the API ++ // contract that |images| and |original_image_sizes| must have the same ++ // length. ++ if (images.size() != original_image_sizes.size()) { ++ if (rfh) { ++ ReceivedBadMessage(rfh->GetProcess(), ++ bad_message::WCI_INVALID_DOWNLOAD_IMAGE_RESULT); ++ } ++ // Respond with a 400 to indicate that something went wrong. ++ std::move(callback).Run(id, 400, image_url, std::vector(), ++ std::vector()); ++ return; ++ } ++ + std::move(callback).Run(id, http_status_code, image_url, images, + original_image_sizes); + } +diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h +index b78cb8f558052e01d61456ca282359eb4b342c35..54a780a2cbbe1259b13d5d46c9a90aaffbb516a9 100644 +--- a/content/browser/web_contents/web_contents_impl.h ++++ b/content/browser/web_contents/web_contents_impl.h +@@ -1470,7 +1470,8 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents, + std::set& result); + + // Called with the result of a DownloadImage() request. +- void OnDidDownloadImage(ImageDownloadCallback callback, ++ void OnDidDownloadImage(base::WeakPtr rfh, ++ ImageDownloadCallback callback, + int id, + const GURL& image_url, + int32_t http_status_code, +diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h +index a43c9972377f6365c3fe0e33f0d29700f597bd2d..8260da280d387847e18ca22782e71c0d6614385f 100644 +--- a/content/public/browser/web_contents.h ++++ b/content/public/browser/web_contents.h +@@ -918,8 +918,9 @@ class WebContents : public PageNavigator, + // |bitmaps| will be empty on download failure. + // |sizes| are the sizes in pixels of the bitmaps before they were resized due + // to the max bitmap size passed to DownloadImage(). Each entry in the bitmaps +- // vector corresponds to an entry in the sizes vector. If a bitmap was +- // resized, there should be a single returned bitmap. ++ // vector corresponds to an entry in the sizes vector (both vector sizes are ++ // guaranteed to be equal). If a bitmap was resized, there should be a single ++ // returned bitmap. + using ImageDownloadCallback = + base::OnceCallback& unfiltered, + uint32_t max_image_size, +@@ -202,6 +203,8 @@ void ImageDownloaderImpl::DidDownloadImage( + FilterAndResizeImagesForMaximalSize(images, max_image_size, &result_images, + &result_original_image_sizes); + ++ DCHECK_EQ(result_images.size(), result_original_image_sizes.size()); ++ + std::move(callback).Run(http_status_code, result_images, + result_original_image_sizes); + } diff --git a/patches/chromium/m86-lts_longtaskdetector_remove_container_mutation_during.patch b/patches/chromium/m86-lts_longtaskdetector_remove_container_mutation_during.patch new file mode 100644 index 0000000000000..726cd2be674f5 --- /dev/null +++ b/patches/chromium/m86-lts_longtaskdetector_remove_container_mutation_during.patch @@ -0,0 +1,99 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Yutaka Hirano +Date: Fri, 11 Jun 2021 08:07:55 +0000 +Subject: Remove container mutation during iteration +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +On LongTaskDetector, we call OnLongTaskDetected for all registered +observers. Some observers call LongTaskDetector::UnregisterObserver +in the callback, which is problematic because container mutation is +not allowed during iteration. + +Copy the observer set to avoid the violation. + +(cherry picked from commit 702f4d4ddb963cafb0d133972282dfc803510b75) + +(cherry picked from commit e88c656a9fb4a7bb1c66ddcedae8049a448ebef4) + +Bug: 1210487 +Change-Id: Iccea748ac144def6884be8cf542cdc3572bed81a +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2909934 +Reviewed-by: Deep Roy +Reviewed-by: Nicolás Peña Moreno +Commit-Queue: Yutaka Hirano +Cr-Original-Original-Commit-Position: refs/heads/master@{#885033} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2939704 +Auto-Submit: Yutaka Hirano +Owners-Override: Prudhvi Kumar Bommana +Reviewed-by: Prudhvi Kumar Bommana +Cr-Original-Commit-Position: refs/branch-heads/4472@{#1443} +Cr-Original-Branched-From: 3d60439cfb36485e76a1c5bb7f513d3721b20da1-refs/heads/master@{#870763} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2945787 +Owners-Override: Victor-Gabriel Savu +Reviewed-by: Artem Sumaneev +Commit-Queue: Victor-Gabriel Savu +Cr-Commit-Position: refs/branch-heads/4240@{#1669} +Cr-Branched-From: f297677702651916bbf65e59c0d4bbd4ce57d1ee-refs/heads/master@{#800218} + +diff --git a/third_party/blink/renderer/core/loader/long_task_detector.cc b/third_party/blink/renderer/core/loader/long_task_detector.cc +index 7e1499b1ddde30db2344db6fd9a9d3e7be574033..f040ae5053265fb136c629f106aeefa0b01130f1 100644 +--- a/third_party/blink/renderer/core/loader/long_task_detector.cc ++++ b/third_party/blink/renderer/core/loader/long_task_detector.cc +@@ -43,7 +43,10 @@ void LongTaskDetector::DidProcessTask(base::TimeTicks start_time, + if ((end_time - start_time) < LongTaskDetector::kLongTaskThreshold) + return; + +- for (auto& observer : observers_) { ++ // We copy `observers_` because it might be mutated in OnLongTaskDetected, ++ // and container mutation is not allowed during iteration. ++ const HeapHashSet> observers = observers_; ++ for (auto& observer : observers) { + observer->OnLongTaskDetected(start_time, end_time); + } + } +diff --git a/third_party/blink/renderer/core/loader/long_task_detector_test.cc b/third_party/blink/renderer/core/loader/long_task_detector_test.cc +index 3384fa8ebfb0bd3ad1c408390db3fcb26edc4118..04959d3b682ddbf40577adc5799fe57a9ae9d500 100644 +--- a/third_party/blink/renderer/core/loader/long_task_detector_test.cc ++++ b/third_party/blink/renderer/core/loader/long_task_detector_test.cc +@@ -27,9 +27,24 @@ class TestLongTaskObserver : + last_long_task_start = start_time; + last_long_task_end = end_time; + } +-}; // Anonymous namespace ++}; ++ ++class SelfUnregisteringObserver ++ : public GarbageCollected, ++ public LongTaskObserver { ++ public: ++ void OnLongTaskDetected(base::TimeTicks, base::TimeTicks) override { ++ called_ = true; ++ LongTaskDetector::Instance().UnregisterObserver(this); ++ } ++ bool IsCalled() const { return called_; } ++ ++ private: ++ bool called_ = false; ++}; + + } // namespace ++ + class LongTaskDetectorTest : public testing::Test { + public: + // Public because it's executed on a task queue. +@@ -126,4 +141,13 @@ TEST_F(LongTaskDetectorTest, RegisterSameObserverTwice) { + long_task_end_when_registered); + } + ++TEST_F(LongTaskDetectorTest, SelfUnregisteringObserver) { ++ auto* observer = MakeGarbageCollected(); ++ ++ LongTaskDetector::Instance().RegisterObserver(observer); ++ SimulateTask(LongTaskDetector::kLongTaskThreshold + ++ base::TimeDelta::FromMilliseconds(10)); ++ EXPECT_TRUE(observer->IsCalled()); ++} ++ + } // namespace blink diff --git a/patches/chromium/m86-lts_reduce_memory_consumption_on.patch b/patches/chromium/m86-lts_reduce_memory_consumption_on.patch new file mode 100644 index 0000000000000..7ebb245a3d298 --- /dev/null +++ b/patches/chromium/m86-lts_reduce_memory_consumption_on.patch @@ -0,0 +1,118 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Yutaka Hirano +Date: Fri, 11 Jun 2021 08:42:36 +0000 +Subject: Reduce memory consumption on LongTaskObserver::DidProcessTask + +https://crrev.com/c/2909934 fixed a security issue, but it introduced a +copy operation for each DidProcessTask for a long task. We see a memory +regression on the change, and this is an attempt to mitigate the +regression. + +(cherry picked from commit 8097e73295a88e64d8318d982847a5e4f2bcc4d2) + +(cherry picked from commit 7be6a34fe2f01af881bb074bc616bf5b6b5f7c31) + +Bug: 1210487, 1211539 +Change-Id: Ib9101e29d70fadb11b7967754e847bb5cc754feb +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2915153 +Reviewed-by: Benoit L +Commit-Queue: Yutaka Hirano +Cr-Original-Original-Commit-Position: refs/heads/master@{#886221} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2944320 +Bot-Commit: Rubber Stamper +Cr-Original-Commit-Position: refs/branch-heads/4472@{#1460} +Cr-Original-Branched-From: 3d60439cfb36485e76a1c5bb7f513d3721b20da1-refs/heads/master@{#870763} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2952502 +Owners-Override: Victor-Gabriel Savu +Reviewed-by: Artem Sumaneev +Commit-Queue: Victor-Gabriel Savu +Cr-Commit-Position: refs/branch-heads/4240@{#1670} +Cr-Branched-From: f297677702651916bbf65e59c0d4bbd4ce57d1ee-refs/heads/master@{#800218} + +diff --git a/third_party/blink/renderer/core/loader/long_task_detector.cc b/third_party/blink/renderer/core/loader/long_task_detector.cc +index f040ae5053265fb136c629f106aeefa0b01130f1..3816779cfafaef06295734b4a8a2f033bf752691 100644 +--- a/third_party/blink/renderer/core/loader/long_task_detector.cc ++++ b/third_party/blink/renderer/core/loader/long_task_detector.cc +@@ -24,6 +24,7 @@ LongTaskDetector::LongTaskDetector() = default; + void LongTaskDetector::RegisterObserver(LongTaskObserver* observer) { + DCHECK(IsMainThread()); + DCHECK(observer); ++ DCHECK(!iterating_); + if (observers_.insert(observer).is_new_entry && observers_.size() == 1) { + // Number of observers just became non-zero. + Thread::Current()->AddTaskTimeObserver(this); +@@ -32,6 +33,10 @@ void LongTaskDetector::RegisterObserver(LongTaskObserver* observer) { + + void LongTaskDetector::UnregisterObserver(LongTaskObserver* observer) { + DCHECK(IsMainThread()); ++ if (iterating_) { ++ observers_to_be_removed_.push_back(observer); ++ return; ++ } + observers_.erase(observer); + if (observers_.size() == 0) { + Thread::Current()->RemoveTaskTimeObserver(this); +@@ -43,16 +48,21 @@ void LongTaskDetector::DidProcessTask(base::TimeTicks start_time, + if ((end_time - start_time) < LongTaskDetector::kLongTaskThreshold) + return; + +- // We copy `observers_` because it might be mutated in OnLongTaskDetected, +- // and container mutation is not allowed during iteration. +- const HeapHashSet> observers = observers_; +- for (auto& observer : observers) { ++ iterating_ = true; ++ for (auto& observer : observers_) { + observer->OnLongTaskDetected(start_time, end_time); + } ++ iterating_ = false; ++ ++ for (const auto& observer : observers_to_be_removed_) { ++ UnregisterObserver(observer); ++ } ++ observers_to_be_removed_.clear(); + } + + void LongTaskDetector::Trace(Visitor* visitor) const { + visitor->Trace(observers_); ++ visitor->Trace(observers_to_be_removed_); + } + + } // namespace blink +diff --git a/third_party/blink/renderer/core/loader/long_task_detector.h b/third_party/blink/renderer/core/loader/long_task_detector.h +index dc6f0dbab5c059b83bfe4212f0126e9690ab1a7f..5fd4bb8d2abcc67dd4e47927daa260fa37bc4aca 100644 +--- a/third_party/blink/renderer/core/loader/long_task_detector.h ++++ b/third_party/blink/renderer/core/loader/long_task_detector.h +@@ -49,6 +49,8 @@ class CORE_EXPORT LongTaskDetector final + base::TimeTicks end_time) override; + + HeapHashSet> observers_; ++ HeapVector> observers_to_be_removed_; ++ bool iterating_ = false; + + DISALLOW_COPY_AND_ASSIGN(LongTaskDetector); + }; +diff --git a/third_party/blink/renderer/core/loader/long_task_detector_test.cc b/third_party/blink/renderer/core/loader/long_task_detector_test.cc +index 04959d3b682ddbf40577adc5799fe57a9ae9d500..403ba452362a3fa2a6b24f238bad35d9eb1bac0c 100644 +--- a/third_party/blink/renderer/core/loader/long_task_detector_test.cc ++++ b/third_party/blink/renderer/core/loader/long_task_detector_test.cc +@@ -39,6 +39,8 @@ class SelfUnregisteringObserver + } + bool IsCalled() const { return called_; } + ++ void Reset() { called_ = false; } ++ + private: + bool called_ = false; + }; +@@ -148,6 +150,11 @@ TEST_F(LongTaskDetectorTest, SelfUnregisteringObserver) { + SimulateTask(LongTaskDetector::kLongTaskThreshold + + base::TimeDelta::FromMilliseconds(10)); + EXPECT_TRUE(observer->IsCalled()); ++ observer->Reset(); ++ ++ SimulateTask(LongTaskDetector::kLongTaskThreshold + ++ base::TimeDelta::FromMilliseconds(10)); ++ EXPECT_FALSE(observer->IsCalled()); + } + + } // namespace blink diff --git a/patches/chromium/media_feeds_disable_media_feeds_and_related_features.patch b/patches/chromium/media_feeds_disable_media_feeds_and_related_features.patch new file mode 100644 index 0000000000000..b72815626f340 --- /dev/null +++ b/patches/chromium/media_feeds_disable_media_feeds_and_related_features.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrey Belenko +Date: Wed, 19 May 2021 14:12:59 +0200 +Subject: Media Feeds: Disable Media Feeds and related features + +Media Feeds is deleted in M91 and later and is unused in previous +versions as well. There is a security issue with Media Feeds though, so +we'd like to force it to be disabled in previous versions, so this CL +turns it off for M90. + +(cherry picked from commit b064a73431541e520d273c227e762983c2f177b7) + +Bug: 1195340 +Change-Id: I29e18be2abe4c1b4560d6324af3b6da93a97d947 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2847504 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2883741 + +diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc +index 0c20d23e273405a78f59d91196f12160dba2e824..37fc954bffa26cad04a8d31e2838416f84670281 100644 +--- a/media/base/media_switches.cc ++++ b/media/base/media_switches.cc +@@ -730,15 +730,16 @@ const base::Feature kMediaEngagementHTTPSOnly{ + + // Enables Media Feeds to allow sites to provide specific recommendations for + // users. +-const base::Feature kMediaFeeds{"MediaFeeds", base::FEATURE_ENABLED_BY_DEFAULT}; ++const base::Feature kMediaFeeds{"MediaFeeds", ++ base::FEATURE_DISABLED_BY_DEFAULT}; + + // Enables fetching Media Feeds periodically in the background. + const base::Feature kMediaFeedsBackgroundFetching{ +- "MediaFeedsBackgroundFetching", base::FEATURE_ENABLED_BY_DEFAULT}; ++ "MediaFeedsBackgroundFetching", base::FEATURE_DISABLED_BY_DEFAULT}; + + // Enables checking Media Feeds against safe search to prevent adult content. + const base::Feature kMediaFeedsSafeSearch{"MediaFeedsSafeSearch", +- base::FEATURE_ENABLED_BY_DEFAULT}; ++ base::FEATURE_DISABLED_BY_DEFAULT}; + + // Send events to devtools rather than to chrome://media-internals + const base::Feature kMediaInspectorLogging{"MediaInspectorLogging", diff --git a/patches/chromium/notifications_crash_if_improper_action_icons_sent_from_renderer.patch b/patches/chromium/notifications_crash_if_improper_action_icons_sent_from_renderer.patch new file mode 100644 index 0000000000000..5661927b006dc --- /dev/null +++ b/patches/chromium/notifications_crash_if_improper_action_icons_sent_from_renderer.patch @@ -0,0 +1,149 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrey Belenko +Date: Wed, 19 May 2021 12:54:32 +0200 +Subject: Notifications: crash if improper action icons sent from renderer. + +Previously, the code only called DCHECK but as this data is from a +renderer we should probably crash the browser. + +(cherry picked from commit 3b28dc50187b22e080ad9c1e4e6c4f3b08f3136d) + +Bug: 1200019 +Change-Id: If4d9d48c8e18a3ed9c8bb3a50b952591259e0db5 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2838205 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2872493 + +diff --git a/chrome/browser/notifications/platform_notification_service_impl.cc b/chrome/browser/notifications/platform_notification_service_impl.cc +index 403cf8f11bec68504e32ebace2f80e04ad136491..5d5f7fafd484ff5cb9fe31b459b5b23b740cf513 100644 +--- a/chrome/browser/notifications/platform_notification_service_impl.cc ++++ b/chrome/browser/notifications/platform_notification_service_impl.cc +@@ -403,8 +403,10 @@ PlatformNotificationServiceImpl::CreateNotificationFromData( + const std::string& notification_id, + const blink::PlatformNotificationData& notification_data, + const blink::NotificationResources& notification_resources) const { +- DCHECK_EQ(notification_data.actions.size(), +- notification_resources.action_icons.size()); ++ // Blink always populates action icons to match the actions, even if no icon ++ // was fetched, so this indicates a compromised renderer. ++ CHECK_EQ(notification_data.actions.size(), ++ notification_resources.action_icons.size()); + + message_center::RichNotificationData optional_fields; + +diff --git a/content/browser/notifications/blink_notification_service_impl.cc b/content/browser/notifications/blink_notification_service_impl.cc +index 7105781e0019b456f287fd0ebb6e309efe2cecad..8fcbb96ed39da9ec468cbe310bf8f499e338a235 100644 +--- a/content/browser/notifications/blink_notification_service_impl.cc ++++ b/content/browser/notifications/blink_notification_service_impl.cc +@@ -39,6 +39,9 @@ const char kBadMessageImproperNotificationImage[] = + "disabled."; + const char kBadMessageInvalidNotificationTriggerTimestamp[] = + "Received an invalid notification trigger timestamp."; ++const char kBadMessageInvalidNotificationActionButtons[] = ++ "Received a notification with a number of action images that does not " ++ "match the number of actions."; + + // Returns the implementation of the PlatformNotificationService. May be NULL. + PlatformNotificationService* GetNotificationService( +@@ -134,7 +137,8 @@ void BlinkNotificationServiceImpl::DisplayNonPersistentNotification( + mojo::PendingRemote + event_listener_remote) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); +- if (!ValidateNotificationResources(notification_resources)) ++ if (!ValidateNotificationDataAndResources(platform_notification_data, ++ notification_resources)) + return; + + if (!GetNotificationService(browser_context_)) +@@ -190,28 +194,32 @@ BlinkNotificationServiceImpl::CheckPermissionStatus() { + origin_.GetURL()); + } + +-bool BlinkNotificationServiceImpl::ValidateNotificationResources( ++bool BlinkNotificationServiceImpl::ValidateNotificationDataAndResources( ++ const blink::PlatformNotificationData& platform_notification_data, + const blink::NotificationResources& notification_resources) { +- if (notification_resources.image.drawsNothing() || +- base::FeatureList::IsEnabled(features::kNotificationContentImage)) +- return true; +- receiver_.ReportBadMessage(kBadMessageImproperNotificationImage); +- // The above ReportBadMessage() closes |binding_| but does not trigger its +- // connection error handler, so we need to call the error handler explicitly +- // here to do some necessary work. +- OnConnectionError(); +- return false; +-} ++ if (platform_notification_data.actions.size() != ++ notification_resources.action_icons.size()) { ++ receiver_.ReportBadMessage(kBadMessageInvalidNotificationActionButtons); ++ OnConnectionError(); ++ return false; ++ } + +-// Checks if this notification has a valid trigger. +-bool BlinkNotificationServiceImpl::ValidateNotificationData( +- const blink::PlatformNotificationData& notification_data) { +- if (!CheckNotificationTriggerRange(notification_data)) { ++ if (!CheckNotificationTriggerRange(platform_notification_data)) { + receiver_.ReportBadMessage(kBadMessageInvalidNotificationTriggerTimestamp); + OnConnectionError(); + return false; + } + ++ if (!notification_resources.image.drawsNothing() && ++ !base::FeatureList::IsEnabled(features::kNotificationContentImage)) { ++ receiver_.ReportBadMessage(kBadMessageImproperNotificationImage); ++ // The above ReportBadMessage() closes |binding_| but does not trigger its ++ // connection error handler, so we need to call the error handler explicitly ++ // here to do some necessary work. ++ OnConnectionError(); ++ return false; ++ } ++ + return true; + } + +@@ -221,10 +229,8 @@ void BlinkNotificationServiceImpl::DisplayPersistentNotification( + const blink::NotificationResources& notification_resources, + DisplayPersistentNotificationCallback callback) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); +- if (!ValidateNotificationResources(notification_resources)) +- return; +- +- if (!ValidateNotificationData(platform_notification_data)) ++ if (!ValidateNotificationDataAndResources(platform_notification_data, ++ notification_resources)) + return; + + if (!GetNotificationService(browser_context_)) { +diff --git a/content/browser/notifications/blink_notification_service_impl.h b/content/browser/notifications/blink_notification_service_impl.h +index dc5307e6500b0bfb5da83e8d8ff8886b91133522..fe1abadd2bc196914cb7b6d9fe29a75435f08988 100644 +--- a/content/browser/notifications/blink_notification_service_impl.h ++++ b/content/browser/notifications/blink_notification_service_impl.h +@@ -72,20 +72,15 @@ class CONTENT_EXPORT BlinkNotificationServiceImpl + // Check the permission status for the current |origin_|. + blink::mojom::PermissionStatus CheckPermissionStatus(); + +- // Validate |notification_resources| received in a Mojo IPC message. +- // If the validation failed, we'd close the Mojo connection |binding_| and +- // destroy |this| by calling OnConnectionError() directly, then return false. +- // So, please do not touch |this| again after you got a false return value. +- bool ValidateNotificationResources( ++ // Validate |notification_data| and |notification_resources| received in a ++ // Mojo IPC message. If the validation failed, we'd close the Mojo connection ++ // |binding_| and destroy |this| by calling OnConnectionError() directly, then ++ // return false. So, please do not touch |this| again after you got a false ++ // return value. ++ bool ValidateNotificationDataAndResources( ++ const blink::PlatformNotificationData& notification_data, + const blink::NotificationResources& notification_resources); + +- // Validate |notification_data| received in a Mojo IPC message. +- // If the validation failed, we'd close the Mojo connection |binding_| and +- // destroy |this| by calling OnConnectionError() directly, then return false. +- // So, please do not touch |this| again after you got a false return value. +- bool ValidateNotificationData( +- const blink::PlatformNotificationData& notification_data); +- + void DidWriteNotificationData(DisplayPersistentNotificationCallback callback, + bool success, + const std::string& notification_id); diff --git a/patches/chromium/reland_views_handle_deletion_when_toggling_fullscreen.patch b/patches/chromium/reland_views_handle_deletion_when_toggling_fullscreen.patch new file mode 100644 index 0000000000000..7f3f0ec27a738 --- /dev/null +++ b/patches/chromium/reland_views_handle_deletion_when_toggling_fullscreen.patch @@ -0,0 +1,149 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrey Belenko +Date: Wed, 19 May 2021 13:18:02 +0200 +Subject: views: handle deletion when toggling fullscreen + +This differs from the first in so far as needing to add more early +outs in the windows side if destroyed. This was caught by the asan +bot. + +Toggling fullscreen means the bounds change. There are some +code paths that may delete the Widget when the bounds changes. +This patch ensures the right thing happens if the Widget is +deleted when this happens. + +BUG=1197436 + +(cherry picked from commit 60fe7a686c0620855c28a60721f668a99e409ee4) + +Change-Id: I8ce8f2045878b6f6de530f58e386149189900498 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2857227 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2868317 + +diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc +index 6a1fcf7fe75d8fadbcb024c7434651bfaf05dc73..e539f14cb2bd56000dccfc557ca6573a3b53dcf1 100644 +--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc ++++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc +@@ -583,7 +583,10 @@ void DesktopWindowTreeHostPlatform::SetFullscreen(bool fullscreen) { + if (IsFullscreen() == fullscreen) + return; + ++ auto weak_ptr = GetWeakPtr(); + platform_window()->ToggleFullscreen(); ++ if (!weak_ptr) ++ return; + + // The state must change synchronously to let media react on fullscreen + // changes. +diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc +index af2c2f2bbc1f52f4455fb973ab2fc0d0dd013ca5..cf0c64cebe0c9c1acb789527a0406d74daeb250a 100644 +--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc ++++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc +@@ -463,7 +463,10 @@ void DesktopWindowTreeHostWin::FrameTypeChanged() { + } + + void DesktopWindowTreeHostWin::SetFullscreen(bool fullscreen) { ++ auto weak_ptr = GetWeakPtr(); + message_handler_->SetFullscreen(fullscreen); ++ if (!weak_ptr) ++ return; + // TODO(sky): workaround for ScopedFullscreenVisibility showing window + // directly. Instead of this should listen for visibility changes and then + // update window. +diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc +index d784b8eae003ba79b109845f0d7f40c99c007791..b54f42885c976ebcd13f08ccf666447791124063 100644 +--- a/ui/views/widget/widget.cc ++++ b/ui/views/widget/widget.cc +@@ -724,7 +724,10 @@ void Widget::SetFullscreen(bool fullscreen) { + if (IsFullscreen() == fullscreen) + return; + ++ auto weak_ptr = GetWeakPtr(); + native_widget_->SetFullscreen(fullscreen); ++ if (!weak_ptr) ++ return; + + if (non_client_view_) + non_client_view_->InvalidateLayout(); +diff --git a/ui/views/win/fullscreen_handler.cc b/ui/views/win/fullscreen_handler.cc +index 8791362556fcd7544b79982dd6535d55ecd25a50..708d28f45028ee10459c7973d51caecfe0d09097 100644 +--- a/ui/views/win/fullscreen_handler.cc ++++ b/ui/views/win/fullscreen_handler.cc +@@ -70,6 +70,7 @@ void FullscreenHandler::SetFullscreenImpl(bool fullscreen) { + + fullscreen_ = fullscreen; + ++ auto ref = weak_ptr_factory_.GetWeakPtr(); + if (fullscreen_) { + // Set new window style and size. + SetWindowLong(hwnd_, GWL_STYLE, +@@ -102,6 +103,8 @@ void FullscreenHandler::SetFullscreenImpl(bool fullscreen) { + new_rect.height(), + SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED); + } ++ if (!ref) ++ return; + + MarkFullscreen(fullscreen); + } +diff --git a/ui/views/win/fullscreen_handler.h b/ui/views/win/fullscreen_handler.h +index fe17c7f0368b1dd35a37006033ddf34d35ea3982..c76ef18a6f59e9239d5a281d26c6e34646b68ee3 100644 +--- a/ui/views/win/fullscreen_handler.h ++++ b/ui/views/win/fullscreen_handler.h +@@ -11,6 +11,7 @@ + #include + + #include "base/macros.h" ++#include "base/memory/weak_ptr.h" + + namespace gfx { + class Rect; +@@ -54,6 +55,8 @@ class FullscreenHandler { + // Used to mark a window as fullscreen. + Microsoft::WRL::ComPtr task_bar_list_; + ++ base::WeakPtrFactory weak_ptr_factory_{this}; ++ + DISALLOW_COPY_AND_ASSIGN(FullscreenHandler); + }; + +diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc +index bb8b1c4fd7f1e93b6d50978ccb701393df956425..d7f91e4d70dcd7224aa8569e8773f69efac7a4e5 100644 +--- a/ui/views/win/hwnd_message_handler.cc ++++ b/ui/views/win/hwnd_message_handler.cc +@@ -900,7 +900,10 @@ void HWNDMessageHandler::SetWindowIcons(const gfx::ImageSkia& window_icon, + + void HWNDMessageHandler::SetFullscreen(bool fullscreen) { + background_fullscreen_hack_ = false; ++ auto ref = msg_handler_weak_factory_.GetWeakPtr(); + fullscreen_handler()->SetFullscreen(fullscreen); ++ if (!ref) ++ return; + + // Add the fullscreen window to the fullscreen window map which is used to + // handle window activations. +@@ -1404,8 +1407,10 @@ void HWNDMessageHandler::ClientAreaSizeChanged() { + // Ignore size changes due to fullscreen windows losing activation. + if (background_fullscreen_hack_ && !sent_window_size_changing_) + return; +- gfx::Size s = GetClientAreaBounds().size(); +- delegate_->HandleClientSizeChanged(s); ++ auto ref = msg_handler_weak_factory_.GetWeakPtr(); ++ delegate_->HandleClientSizeChanged(GetClientAreaBounds().size()); ++ if (!ref) ++ return; + + current_window_size_message_++; + sent_window_size_changing_ = false; +@@ -2930,8 +2935,11 @@ void HWNDMessageHandler::OnWindowPosChanging(WINDOWPOS* window_pos) { + void HWNDMessageHandler::OnWindowPosChanged(WINDOWPOS* window_pos) { + TRACE_EVENT0("ui", "HWNDMessageHandler::OnWindowPosChanged"); + ++ base::WeakPtr ref(msg_handler_weak_factory_.GetWeakPtr()); + if (DidClientAreaSizeChange(window_pos)) + ClientAreaSizeChanged(); ++ if (!ref) ++ return; + if (window_pos->flags & SWP_FRAMECHANGED) + SetDwmFrameExtension(DwmFrameState::kOn); + if (window_pos->flags & SWP_SHOWWINDOW) { diff --git a/patches/chromium/remove_tabs_and_line_breaks_from_the_middle_of_app_names_when.patch b/patches/chromium/remove_tabs_and_line_breaks_from_the_middle_of_app_names_when.patch new file mode 100644 index 0000000000000..b17b843ce6350 --- /dev/null +++ b/patches/chromium/remove_tabs_and_line_breaks_from_the_middle_of_app_names_when.patch @@ -0,0 +1,50 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrey Belenko +Date: Wed, 19 May 2021 17:11:00 +0200 +Subject: Remove tabs and line breaks from the middle of app names when + parsing. + +(cherry picked from commit f9b0a09d60acabadfcb9ddeacc9d943cc9811199) + +Bug: 1180126 +Change-Id: Ie6f08d45f97214c4f1ab766aa8af001b8fb8599c +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2821876 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2877715 + +diff --git a/third_party/blink/renderer/modules/manifest/manifest_parser.cc b/third_party/blink/renderer/modules/manifest/manifest_parser.cc +index d50f50ca92f0f622bb26f2b0a29b3fb8d70eed85..ed45e9fff703dd07c8f14f60eaa3c97a213c1b4f 100644 +--- a/third_party/blink/renderer/modules/manifest/manifest_parser.cc ++++ b/third_party/blink/renderer/modules/manifest/manifest_parser.cc +@@ -46,6 +46,10 @@ bool URLIsWithinScope(const KURL& url, const KURL& scope) { + url.GetPath().StartsWith(scope.GetPath()); + } + ++static bool IsCrLfOrTabChar(UChar c) { ++ return c == '\n' || c == '\r' || c == '\t'; ++} ++ + } // anonymous namespace + + ManifestParser::ManifestParser(const String& data, +@@ -256,11 +260,21 @@ KURL ManifestParser::ParseURL(const JSONObject* object, + + String ManifestParser::ParseName(const JSONObject* object) { + base::Optional name = ParseString(object, "name", Trim); ++ if (name.has_value()) { ++ name = name->RemoveCharacters(IsCrLfOrTabChar); ++ if (name->length() == 0) ++ name = base::nullopt; ++ } + return name.has_value() ? *name : String(); + } + + String ManifestParser::ParseShortName(const JSONObject* object) { + base::Optional short_name = ParseString(object, "short_name", Trim); ++ if (short_name.has_value()) { ++ short_name = short_name->RemoveCharacters(IsCrLfOrTabChar); ++ if (short_name->length() == 0) ++ short_name = base::nullopt; ++ } + return short_name.has_value() ? *short_name : String(); + } + diff --git a/patches/chromium/replace_first_of_two_waitableevents_in_creditcardaccessmanager.patch b/patches/chromium/replace_first_of_two_waitableevents_in_creditcardaccessmanager.patch new file mode 100644 index 0000000000000..79ad0c3edf9a8 --- /dev/null +++ b/patches/chromium/replace_first_of_two_waitableevents_in_creditcardaccessmanager.patch @@ -0,0 +1,574 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Dominic Battre +Date: Wed, 7 Jul 2021 20:02:45 +0000 +Subject: Replace first of two WaitableEvents in CreditCardAccessManager +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +(cherry picked from commit 48cf01e4039fecbe119d8223d1f6072aaf44f258) + +Bug: 1214234 +Change-Id: I38171be7b38982f25abfbb3dff7a41f19a167764 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3001123 +Reviewed-by: Jared Saul +Commit-Queue: Dominic Battré +Cr-Original-Commit-Position: refs/heads/master@{#898237} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3011066 +Reviewed-by: Dominic Battré +Reviewed-by: Prudhvi Kumar Bommana +Owners-Override: Prudhvi Kumar Bommana +Cr-Commit-Position: refs/branch-heads/4515@{#1366} +Cr-Branched-From: 488fc70865ddaa05324ac00a54a6eb783b4bc41c-refs/heads/master@{#885287} + +diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn +index 3447ad7a30331d3fc31653083f1411784c244198..ed26a8dd8e0e444ec8e37b292c5fbde4ed0bbc91 100644 +--- a/components/autofill/core/browser/BUILD.gn ++++ b/components/autofill/core/browser/BUILD.gn +@@ -213,6 +213,8 @@ static_library("browser") { + "payments/payments_util.cc", + "payments/payments_util.h", + "payments/risk_data_loader.h", ++ "payments/wait_for_signal_or_timeout.cc", ++ "payments/wait_for_signal_or_timeout.h", + "payments/strike_database.cc", + "payments/strike_database.h", + "payments/strike_database_integrator_base.cc", +@@ -638,6 +640,7 @@ source_set("unit_tests") { + "payments/payments_client_unittest.cc", + "payments/payments_service_url_unittest.cc", + "payments/payments_util_unittest.cc", ++ "payments/wait_for_signal_or_timeout_unittest.cc", + "payments/strike_database_integrator_test_strike_database_unittest.cc", + "payments/strike_database_unittest.cc", + "personal_data_manager_unittest.cc", +diff --git a/components/autofill/core/browser/payments/credit_card_access_manager.cc b/components/autofill/core/browser/payments/credit_card_access_manager.cc +index cbd1018b3dd6c30cec3a92f6e0108fadf7a48dc8..46b143fcc5e1736736e913c8a32f21d15a85be33 100644 +--- a/components/autofill/core/browser/payments/credit_card_access_manager.cc ++++ b/components/autofill/core/browser/payments/credit_card_access_manager.cc +@@ -18,7 +18,6 @@ + #include "base/task/post_task.h" + #include "base/task/task_traits.h" + #include "base/task/thread_pool.h" +-#include "base/threading/sequenced_task_runner_handle.h" + #include "base/time/time.h" + #include "build/build_config.h" + #include "components/autofill/core/browser/autofill_client.h" +@@ -47,12 +46,6 @@ constexpr int64_t kUnmaskDetailsResponseTimeoutMs = 3 * 1000; // 3 sec + // Time to wait between multiple calls to GetUnmaskDetails(). + constexpr int64_t kDelayForGetUnmaskDetails = 3 * 60 * 1000; // 3 min + +-// Used for asynchronously waiting for |event| to be signaled. +-bool WaitForEvent(base::WaitableEvent* event) { +- event->declare_only_used_while_idle(); +- return event->TimedWait( +- base::TimeDelta::FromMilliseconds(kUnmaskDetailsResponseTimeoutMs)); +-} + } // namespace + + CreditCardAccessManager::CreditCardAccessManager( +@@ -65,9 +58,6 @@ CreditCardAccessManager::CreditCardAccessManager( + payments_client_(client_->GetPaymentsClient()), + personal_data_manager_(personal_data_manager), + form_event_logger_(form_event_logger), +- ready_to_start_authentication_( +- base::WaitableEvent::ResetPolicy::AUTOMATIC, +- base::WaitableEvent::InitialState::NOT_SIGNALED), + can_fetch_unmask_details_(base::WaitableEvent::ResetPolicy::AUTOMATIC, + base::WaitableEvent::InitialState::SIGNALED) { + } +@@ -341,12 +331,10 @@ void CreditCardAccessManager::FetchCreditCard( + + // Wait for |ready_to_start_authentication_| to be signaled by + // OnDidGetUnmaskDetails() or until timeout before calling Authenticate(). +- auto task_runner = base::ThreadPool::CreateTaskRunner({base::MayBlock()}); +- cancelable_authenticate_task_tracker_.PostTaskAndReplyWithResult( +- task_runner.get(), FROM_HERE, +- base::BindOnce(&WaitForEvent, &ready_to_start_authentication_), ++ ready_to_start_authentication_.OnEventOrTimeOut( + base::BindOnce(&CreditCardAccessManager::Authenticate, +- weak_ptr_factory_.GetWeakPtr())); ++ weak_ptr_factory_.GetWeakPtr()), ++ base::TimeDelta::FromMilliseconds(kUnmaskDetailsResponseTimeoutMs)); + } else { + Authenticate(get_unmask_details_returned); + } +@@ -711,7 +699,6 @@ void CreditCardAccessManager::HandleDialogUserResponse( + case WebauthnDialogCallbackType::kVerificationCancelled: + // TODO(crbug.com/949269): Add tests and logging for canceling verify + // pending dialog. +- cancelable_authenticate_task_tracker_.TryCancelAll(); + payments_client_->CancelRequest(); + SignalCanFetchUnmaskDetails(); + ready_to_start_authentication_.Reset(); +diff --git a/components/autofill/core/browser/payments/credit_card_access_manager.h b/components/autofill/core/browser/payments/credit_card_access_manager.h +index 6bdf8b8c647f885aad5784f737e117b3a55bd2be..99f6581b7320312776f52383b8e8e3b7845268a8 100644 +--- a/components/autofill/core/browser/payments/credit_card_access_manager.h ++++ b/components/autofill/core/browser/payments/credit_card_access_manager.h +@@ -22,6 +22,7 @@ + #include "components/autofill/core/browser/metrics/credit_card_form_event_logger.h" + #include "components/autofill/core/browser/payments/credit_card_cvc_authenticator.h" + #include "components/autofill/core/browser/payments/payments_client.h" ++#include "components/autofill/core/browser/payments/wait_for_signal_or_timeout.h" + #include "components/autofill/core/browser/personal_data_manager.h" + + #if !defined(OS_IOS) +@@ -295,11 +296,7 @@ class CreditCardAccessManager : public CreditCardCVCAuthenticator::Requester, + // Resets when PrepareToFetchCreditCard() is called, if not already reset. + // Signaled when OnDidGetUnmaskDetails() is called or after timeout. + // Authenticate() is called when signaled. +- base::WaitableEvent ready_to_start_authentication_; +- +- // Tracks the Authenticate() task that is signaled by +- // |ready_to_start_authentication_|, allowing it to be canceled if necessary. +- base::CancelableTaskTracker cancelable_authenticate_task_tracker_; ++ WaitForSignalOrTimeout ready_to_start_authentication_; + + // Required to avoid any unnecessary preflight calls to Payments servers. + // Initial state is signaled. Resets when PrepareToFetchCreditCard() is +diff --git a/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc b/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc +index 68b1b1ccf5ac5c7000c09de4b57932834735aaf6..ecfebce277b3b757b83d7c663b2b753f952cf02e 100644 +--- a/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc ++++ b/components/autofill/core/browser/payments/credit_card_access_manager_unittest.cc +@@ -139,8 +139,23 @@ class CreditCardAccessManagerTest : public testing::Test { + public: + CreditCardAccessManagerTest() + : task_environment_( ++ base::test::TaskEnvironment::TimeSource::MOCK_TIME, + base::test::TaskEnvironment::MainThreadType::DEFAULT, +- base::test::TaskEnvironment::ThreadPoolExecutionMode::QUEUED) {} ++ base::test::TaskEnvironment::ThreadPoolExecutionMode::QUEUED) { ++ // Advance the mock clock to 2021-01-01, 00:00:00.000. ++ base::Time year_2021; ++ CHECK(base::Time::FromUTCExploded({.year = 2021, ++ .month = 1, ++ .day_of_week = 4, ++ .day_of_month = 1, ++ .hour = 0, ++ .minute = 0, ++ .second = 0, ++ .millisecond = 0}, ++ &year_2021)); ++ task_environment_.AdvanceClock(year_2021 - ++ task_environment_.GetMockClock()->Now()); ++ } + + void SetUp() override { + autofill_client_.SetPrefs(test::PrefServiceForTesting()); +@@ -929,6 +944,7 @@ TEST_F(CreditCardAccessManagerTest, + + ResetFetchCreditCard(); + credit_card_access_manager_->PrepareToFetchCreditCard(); ++ task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(4)); + WaitForCallbacks(); + + credit_card_access_manager_->FetchCreditCard(local_card, +@@ -949,6 +965,7 @@ TEST_F(CreditCardAccessManagerTest, + credit_card_access_manager_->PrepareToFetchCreditCard(); + credit_card_access_manager_->FetchCreditCard(server_card, + accessor_->GetWeakPtr()); ++ task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(4)); + WaitForCallbacks(); + + histogram_tester.ExpectUniqueSample( +@@ -1022,6 +1039,8 @@ TEST_F(CreditCardAccessManagerTest, Metrics_LoggingTimedOutCvcFallback) { + + // Mock a delayed response. + InvokeDelayedGetUnmaskDetailsResponse(); ++ ++ task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(4)); + WaitForCallbacks(); + + histogram_tester.ExpectUniqueSample( +@@ -1043,6 +1062,7 @@ TEST_F(CreditCardAccessManagerTest, Metrics_LoggingTimedOutCvcFallback) { + credit_card_access_manager_->PrepareToFetchCreditCard(); + credit_card_access_manager_->FetchCreditCard(server_card, + accessor_->GetWeakPtr()); ++ task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(4)); + WaitForCallbacks(); + + histogram_tester.ExpectUniqueSample( +diff --git a/components/autofill/core/browser/payments/wait_for_signal_or_timeout.cc b/components/autofill/core/browser/payments/wait_for_signal_or_timeout.cc +new file mode 100644 +index 0000000000000000000000000000000000000000..713a53e0f006e51f5d9bd64466712bf75b3ba095 +--- /dev/null ++++ b/components/autofill/core/browser/payments/wait_for_signal_or_timeout.cc +@@ -0,0 +1,78 @@ ++// Copyright 2021 The Chromium Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#include "components/autofill/core/browser/payments/wait_for_signal_or_timeout.h" ++ ++#include "base/threading/sequenced_task_runner_handle.h" ++ ++WaitForSignalOrTimeout::WaitForSignalOrTimeout() = default; ++WaitForSignalOrTimeout::~WaitForSignalOrTimeout() = default; ++ ++void WaitForSignalOrTimeout::Signal() { ++ DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_); ++ SignalHandler(/*triggered_by_signal=*/true); ++} ++ ++bool WaitForSignalOrTimeout::IsSignaled() const { ++ DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_); ++ return state_ == State::kSignalReceived || state_ == State::kDone; ++} ++ ++void WaitForSignalOrTimeout::OnEventOrTimeOut(Callback callback, ++ base::TimeDelta timeout) { ++ DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_); ++ switch (state_) { ++ case State::kInitialState: ++ callback_ = std::move(callback); ++ ++generation_id_; // Invalidate previous OnTimeOut tasks. ++ base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( ++ FROM_HERE, ++ base::BindOnce(&WaitForSignalOrTimeout::OnTimeOut, ++ weak_factory_.GetWeakPtr(), generation_id_), ++ timeout); ++ break; ++ ++ case State::kSignalReceived: ++ state_ = State::kDone; ++ std::move(callback).Run( ++ /*triggered_by_signal=*/in_state_signal_received_due_to_signal_call_); ++ break; ++ ++ case State::kDone: ++ Reset(); ++ OnEventOrTimeOut(std::move(callback), timeout); ++ break; ++ } ++} ++ ++void WaitForSignalOrTimeout::Reset() { ++ DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_); ++ state_ = State::kInitialState; ++ ++generation_id_; ++ callback_ = Callback(); ++} ++ ++void WaitForSignalOrTimeout::OnTimeOut(int generation_id) { ++ DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_); ++ if (generation_id == generation_id_) ++ SignalHandler(/*triggered_by_signal=*/false); ++} ++ ++void WaitForSignalOrTimeout::SignalHandler(bool triggered_by_signal) { ++ switch (state_) { ++ case State::kInitialState: ++ if (callback_.is_null()) { ++ state_ = State::kSignalReceived; ++ in_state_signal_received_due_to_signal_call_ = triggered_by_signal; ++ } else { ++ state_ = State::kDone; ++ std::move(callback_).Run(triggered_by_signal); ++ } ++ break; ++ ++ case State::kSignalReceived: ++ case State::kDone: ++ break; ++ } ++} +diff --git a/components/autofill/core/browser/payments/wait_for_signal_or_timeout.h b/components/autofill/core/browser/payments/wait_for_signal_or_timeout.h +new file mode 100644 +index 0000000000000000000000000000000000000000..6b2c451245441f784938e4132e2ab03e7d85f9b6 +--- /dev/null ++++ b/components/autofill/core/browser/payments/wait_for_signal_or_timeout.h +@@ -0,0 +1,100 @@ ++// Copyright 2021 The Chromium Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_WAIT_FOR_SIGNAL_OR_TIMEOUT_H_ ++#define COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_WAIT_FOR_SIGNAL_OR_TIMEOUT_H_ ++ ++#include "base/callback.h" ++#include "base/memory/weak_ptr.h" ++#include "base/sequence_checker.h" ++#include "base/time/time.h" ++ ++// A WaitForSignalOrTimeout waits for Signal() or a time out and calls a ++// callback when either of these happens for the first time. ++// ++// The WaitForSignalOrTimeout is Reset()-able and ensures that the callback will ++// be called at most once (unless Reset() resets the state). The ++// WaitForSignalOrTimeout can be destroyed at any time without negative ++// side-effects. The callback won't be called in this case. If the Signal() ++// arrives before a call for OnEventOrTimeOut(), the callback will be called ++// immediately. If a second Signal() arrives, nothing happens. The ++// WaitForSignalOrTimeout must be used on single task sequence. ++// ++// This class provides the bare minimum needed for a Payment task. If there are ++// more use cases, feel free to spice it up and move it to base/. ++class WaitForSignalOrTimeout { ++ public: ++ // The passed boolean is true if the callback happened by a call of Signal() ++ // (as opposed to a timeout). ++ using Callback = base::OnceCallback; ++ ++ WaitForSignalOrTimeout(); ++ ~WaitForSignalOrTimeout(); ++ WaitForSignalOrTimeout(const WaitForSignalOrTimeout&) = delete; ++ WaitForSignalOrTimeout& operator=(const WaitForSignalOrTimeout&) = delete; ++ ++ // Triggers |callback_| if it has not been called before, or registers that ++ // the signal occurred, so that |callback| of OnEventOrTimeOut() can be ++ // called immediately. ++ void Signal(); ++ ++ // Returns whether Signal() was called at least once or a timeout happened, ++ // and Reset() has not been called afterwards. Note that this function does ++ // not discriminate whether Signal() was called or a timeout happened. ++ // The |callback_|'s parameter has this distinction, though. ++ bool IsSignaled() const; ++ ++ // Registers the |callback| and calls it immediately if Signal() was called ++ // already. Starts a timeout task, so that |callback| is called if no call of ++ // Signal() is observed within |timeout|. A previous timeout is replaced by a ++ // new one. ++ void OnEventOrTimeOut(Callback callback, base::TimeDelta timeout); ++ ++ // Resets the state machine so that no Signal() was observed, no callback is ++ // registered and no timeout task is running. ++ void Reset(); ++ ++ private: ++ enum class State { ++ // Signal() has not been called, yet. ++ kInitialState, ++ // Signal() has been called, but callback is not specified. ++ kSignalReceived, ++ // callback has been called. ++ kDone, ++ }; ++ ++ // Internal callback for the timeout. |generation_id| is a generation counter ++ // to ensure that old, delayed timeout tasks are ignored. ++ void OnTimeOut(int generation_id); ++ ++ // Handler for Signal() and OnTimeOut(). Calls |callback_| if appropriate. ++ // The parameter is true if this function is called via Signal() and false if ++ // the function is called via OnTimeOut(). This parameter is passed to ++ // callback. ++ void SignalHandler(bool triggered_by_signal); ++ ++ State state_ = State::kInitialState; ++ ++ // This variable is only valid if state_ == State::kSignalReceived. It is ++ // true if we moved into this state due to a Signal() call, and false if ++ // we moved into this state due to an OnTimeOut() call. ++ bool in_state_signal_received_due_to_signal_call_; ++ ++ // As the base::ThreadPool does not support cancelable tasks, we just rely on ++ // a generation counter. Every time Reset() or OnEventOrTimeOut() are called, ++ // the generation id is incremented. If outdated delayed OnTimeOut() tasks ++ // trickle in, we recognize them as tasks for which the |generation_id| ++ // parameter is less than the current generation_id_ and ignore them. ++ int generation_id_ = 0; ++ ++ // Callback to be called in case of a Signal() or a time out. ++ Callback callback_; ++ ++ SEQUENCE_CHECKER(my_sequence_checker_); ++ ++ base::WeakPtrFactory weak_factory_{this}; ++}; ++ ++#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_PAYMENTS_WAIT_FOR_SIGNAL_OR_TIMEOUT_H_ +diff --git a/components/autofill/core/browser/payments/wait_for_signal_or_timeout_unittest.cc b/components/autofill/core/browser/payments/wait_for_signal_or_timeout_unittest.cc +new file mode 100644 +index 0000000000000000000000000000000000000000..eda3fd362221cb9c08c893af02ce33a2826c5d6f +--- /dev/null ++++ b/components/autofill/core/browser/payments/wait_for_signal_or_timeout_unittest.cc +@@ -0,0 +1,188 @@ ++// Copyright 2021 The Chromium Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++#include "components/autofill/core/browser/payments/wait_for_signal_or_timeout.h" ++ ++#include "base/test/task_environment.h" ++#include "testing/gtest/include/gtest/gtest.h" ++ ++class WaitForSignalOrTimeoutTest : public testing::Test { ++ public: ++ WaitForSignalOrTimeoutTest() = default; ++ ~WaitForSignalOrTimeoutTest() override = default; ++ ++ WaitForSignalOrTimeout::Callback GetCallback() { ++ return base::BindOnce(&WaitForSignalOrTimeoutTest::Callback, ++ base::Unretained(this)); ++ } ++ ++ protected: ++ void Callback(bool triggered_by_signal) { ++ callbacks_++; ++ last_callback_triggered_by_signal_ = triggered_by_signal; ++ } ++ ++ // Number of observed callbacks. ++ int callbacks_ = 0; ++ ++ bool last_callback_triggered_by_signal_ = false; ++ ++ base::test::TaskEnvironment task_env_{ ++ base::test::TaskEnvironment::TimeSource::MOCK_TIME}; ++}; ++ ++// WaitForSignalOrTimeout is initialized with a callback and then the Signal() ++// happens. ++TEST_F(WaitForSignalOrTimeoutTest, InitThenSignal) { ++ WaitForSignalOrTimeout wait; ++ wait.OnEventOrTimeOut(GetCallback(), base::TimeDelta::FromSeconds(30)); ++ EXPECT_EQ(0, callbacks_); ++ EXPECT_FALSE(wait.IsSignaled()); ++ wait.Signal(); ++ EXPECT_EQ(1, callbacks_); ++ EXPECT_TRUE(wait.IsSignaled()); ++ EXPECT_TRUE(last_callback_triggered_by_signal_); ++ ++ // Another signal call should be ignored. ++ wait.Signal(); ++ EXPECT_EQ(1, callbacks_); ++ EXPECT_TRUE(wait.IsSignaled()); ++ ++ // Also the pending timeout should not trigger further callbacks. ++ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(35)); ++ EXPECT_TRUE(wait.IsSignaled()); ++ EXPECT_EQ(1, callbacks_); ++} ++ ++// A Signal() is registered before the callback. ++TEST_F(WaitForSignalOrTimeoutTest, SignalThenInit) { ++ WaitForSignalOrTimeout wait; ++ EXPECT_FALSE(wait.IsSignaled()); ++ ++ // Trigger the signal before a callback handler is registered. ++ wait.Signal(); ++ EXPECT_TRUE(wait.IsSignaled()); ++ EXPECT_EQ(0, callbacks_); ++ ++ // Once the callback handler is registered, it should be called immediately. ++ wait.OnEventOrTimeOut(GetCallback(), base::TimeDelta::FromSeconds(30)); ++ EXPECT_TRUE(wait.IsSignaled()); ++ EXPECT_EQ(1, callbacks_); ++ EXPECT_TRUE(last_callback_triggered_by_signal_); ++ ++ // Another signal call should be ignored. ++ wait.Signal(); ++ EXPECT_TRUE(wait.IsSignaled()); ++ EXPECT_EQ(1, callbacks_); ++ ++ // Also the pending timeout should not trigger further callbacks. ++ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(35)); ++ EXPECT_TRUE(wait.IsSignaled()); ++ EXPECT_EQ(1, callbacks_); ++} ++ ++// A timeout occurs before Signal() is called. ++TEST_F(WaitForSignalOrTimeoutTest, InitThenTimeout) { ++ WaitForSignalOrTimeout wait; ++ wait.OnEventOrTimeOut(GetCallback(), base::TimeDelta::FromSeconds(30)); ++ EXPECT_FALSE(wait.IsSignaled()); ++ EXPECT_EQ(0, callbacks_); ++ ++ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(35)); ++ EXPECT_TRUE(wait.IsSignaled()); ++ EXPECT_EQ(1, callbacks_); ++ EXPECT_FALSE(last_callback_triggered_by_signal_); ++ ++ // A late signal will be ignored. ++ wait.Signal(); ++ EXPECT_TRUE(wait.IsSignaled()); ++ EXPECT_EQ(1, callbacks_); ++} ++ ++// The WaitForSignalOrTimeout gets destroyed before a Signal() or timeout ++// happens. ++TEST_F(WaitForSignalOrTimeoutTest, DestroyedBeforeSignal) { ++ { ++ WaitForSignalOrTimeout wait; ++ wait.OnEventOrTimeOut(GetCallback(), base::TimeDelta::FromSeconds(30)); ++ } ++ EXPECT_EQ(0, callbacks_); ++ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(35)); ++ EXPECT_EQ(0, callbacks_); ++} ++ ++// The WaitForSignalOrTimeout gets signaled, reset, and signaled again. ++TEST_F(WaitForSignalOrTimeoutTest, Reset) { ++ WaitForSignalOrTimeout wait; ++ wait.OnEventOrTimeOut(GetCallback(), base::TimeDelta::FromSeconds(30)); ++ EXPECT_EQ(0, callbacks_); ++ wait.Signal(); ++ EXPECT_EQ(1, callbacks_); ++ EXPECT_TRUE(wait.IsSignaled()); ++ EXPECT_TRUE(last_callback_triggered_by_signal_); ++ ++ wait.Reset(); ++ ++ EXPECT_FALSE(wait.IsSignaled()); ++ ++ // This signal does not trigger a callback because none is registered. ++ wait.Signal(); ++ EXPECT_EQ(1, callbacks_); ++ // Now the callback happens immediately. ++ wait.OnEventOrTimeOut(GetCallback(), base::TimeDelta::FromSeconds(30)); ++ EXPECT_EQ(2, callbacks_); ++ EXPECT_TRUE(last_callback_triggered_by_signal_); ++ ++ wait.Reset(); ++ ++ // Finally, we simulate a timeout after the reset. ++ EXPECT_FALSE(wait.IsSignaled()); ++ wait.OnEventOrTimeOut(GetCallback(), base::TimeDelta::FromSeconds(30)); ++ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(35)); ++ EXPECT_EQ(3, callbacks_); ++ EXPECT_FALSE(last_callback_triggered_by_signal_); ++} ++ ++TEST_F(WaitForSignalOrTimeoutTest, OnEventOrTimeOutCalledTwice) { ++ WaitForSignalOrTimeout wait; ++ wait.OnEventOrTimeOut(GetCallback(), base::TimeDelta::FromSeconds(30)); ++ EXPECT_EQ(0, callbacks_); ++ ++ // Wait some time but not long enough for the timeout to trigger. ++ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(25)); ++ EXPECT_EQ(0, callbacks_); ++ EXPECT_FALSE(wait.IsSignaled()); ++ ++ // This resets the state machine (currently waiting for a signal or timeout) ++ // and starts a new wait. ++ wait.OnEventOrTimeOut(GetCallback(), base::TimeDelta::FromSeconds(30)); ++ ++ // Wait some time but not long enough for the timeout to trigger. ++ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(25)); ++ // The first timeout should not have triggered anything. ++ EXPECT_EQ(0, callbacks_); ++ EXPECT_FALSE(wait.IsSignaled()); ++ ++ // Wait some more time for the second timeout to kick in. ++ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(10)); ++ EXPECT_EQ(1, callbacks_); ++ EXPECT_TRUE(wait.IsSignaled()); ++ EXPECT_FALSE(last_callback_triggered_by_signal_); ++ ++ // This resets the state machine (currently in done state) once more and ++ // starts a new wait. ++ wait.OnEventOrTimeOut(GetCallback(), base::TimeDelta::FromSeconds(30)); ++ ++ // Wait some time but not long enough for the timeout to trigger. ++ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(25)); ++ // The first timeout should not have triggered anything. ++ EXPECT_EQ(1, callbacks_); ++ EXPECT_FALSE(wait.IsSignaled()); ++ ++ // Wait some more time for the second timeout to kick in. ++ task_env_.FastForwardBy(base::TimeDelta::FromSeconds(10)); ++ EXPECT_EQ(2, callbacks_); ++ EXPECT_TRUE(wait.IsSignaled()); ++ EXPECT_FALSE(last_callback_triggered_by_signal_); ++} diff --git a/patches/chromium/replace_std_vector_with_base_observerlist_to_support_container.patch b/patches/chromium/replace_std_vector_with_base_observerlist_to_support_container.patch new file mode 100644 index 0000000000000..efa73957988cf --- /dev/null +++ b/patches/chromium/replace_std_vector_with_base_observerlist_to_support_container.patch @@ -0,0 +1,144 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrey Belenko +Date: Tue, 18 May 2021 23:22:27 +0200 +Subject: Replace std::vector with base::ObserverList to support container + modification while iterating + +TaskTracker saves list of viewers in vector, that needs to be notified +when distillation is completed. At the time of notifying the viewers, +we are indirectly erasing viewers from vector while iterating. + +This is causing container-overflow in asan build when vector has more +than one viewer while notifying. + +This change is to replace vector with ObserverList that can be modified +during iteration without invalidating the iterator. + +(cherry picked from commit be19f42dab0706d5fdd74acd6eaa424e9277e9c4) + +Bug: 1203590 +Change-Id: I7c7b8237584c48c9ebc2639b9268a6a78c2db4b2 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2856118 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2883743 + +diff --git a/base/observer_list.h b/base/observer_list.h +index 28369a25941dd62ba63a14dccfb46b8092eb6a24..a2f830191f36f74c12aa8e67db978356309e2691 100644 +--- a/base/observer_list.h ++++ b/base/observer_list.h +@@ -272,6 +272,7 @@ class ObserverList { + NOTREACHED() << "Observers can only be added once!"; + return; + } ++ observers_count_++; + observers_.emplace_back(ObserverStorageType(obs)); + } + +@@ -284,7 +285,8 @@ class ObserverList { + [obs](const auto& o) { return o.IsEqual(obs); }); + if (it == observers_.end()) + return; +- ++ if (!it->IsMarkedForRemoval()) ++ observers_count_--; + if (live_iterators_.empty()) { + observers_.erase(it); + } else { +@@ -314,8 +316,12 @@ class ObserverList { + for (auto& observer : observers_) + observer.MarkForRemoval(); + } ++ ++ observers_count_ = 0; + } + ++ bool empty() const { return !observers_count_; } ++ + bool might_have_observers() const { return !observers_.empty(); } + + private: +@@ -334,6 +340,8 @@ class ObserverList { + + base::LinkedList> live_iterators_; + ++ size_t observers_count_{0}; ++ + const ObserverListPolicy policy_; + + SEQUENCE_CHECKER(iteration_sequence_checker_); +diff --git a/components/dom_distiller/core/task_tracker.cc b/components/dom_distiller/core/task_tracker.cc +index e66a62c4091e44183253ba7221db6dedcca4a1a2..f22c88967bc7d7b1a32339657b5fc2bf8248bbde 100644 +--- a/components/dom_distiller/core/task_tracker.cc ++++ b/components/dom_distiller/core/task_tracker.cc +@@ -85,7 +85,7 @@ void TaskTracker::AddSaveCallback(SaveCallback callback) { + + std::unique_ptr TaskTracker::AddViewer( + ViewRequestDelegate* delegate) { +- viewers_.push_back(delegate); ++ viewers_.AddObserver(delegate); + if (content_ready_) { + // Distillation for this task has already completed, and so the delegate can + // be immediately told of the result. +@@ -115,7 +115,7 @@ bool TaskTracker::HasUrl(const GURL& url) const { + } + + void TaskTracker::RemoveViewer(ViewRequestDelegate* delegate) { +- base::Erase(viewers_, delegate); ++ viewers_.RemoveObserver(delegate); + if (viewers_.empty()) { + MaybeCancel(); + } +@@ -219,8 +219,8 @@ void TaskTracker::DistilledArticleReady( + } + + void TaskTracker::NotifyViewersAndCallbacks() { +- for (auto* viewer : viewers_) { +- NotifyViewer(viewer); ++ for (auto& viewer : viewers_) { ++ NotifyViewer(&viewer); + } + + // Already inside a callback run SaveCallbacks directly. +@@ -242,8 +242,8 @@ void TaskTracker::DoSaveCallbacks(bool success) { + + void TaskTracker::OnArticleDistillationUpdated( + const ArticleDistillationUpdate& article_update) { +- for (auto* viewer : viewers_) { +- viewer->OnArticleUpdated(article_update); ++ for (auto& viewer : viewers_) { ++ viewer.OnArticleUpdated(article_update); + } + } + +diff --git a/components/dom_distiller/core/task_tracker.h b/components/dom_distiller/core/task_tracker.h +index 484145cf7d176fd0c3f2fa73da4cf94c23cc0bda..cc13e7272923ec3de52bcea186fdc30391c8cd2b 100644 +--- a/components/dom_distiller/core/task_tracker.h ++++ b/components/dom_distiller/core/task_tracker.h +@@ -11,6 +11,7 @@ + #include "base/bind.h" + #include "base/callback.h" + #include "base/memory/weak_ptr.h" ++#include "base/observer_list.h" + #include "components/dom_distiller/core/article_distillation_update.h" + #include "components/dom_distiller/core/article_entry.h" + #include "components/dom_distiller/core/distiller.h" +@@ -40,9 +41,9 @@ class ViewerHandle { + + // Interface for a DOM distiller entry viewer. Implement this to make a view + // request and receive the data for an entry when it becomes available. +-class ViewRequestDelegate { ++class ViewRequestDelegate : public base::CheckedObserver { + public: +- virtual ~ViewRequestDelegate() = default; ++ ~ViewRequestDelegate() override = default; + + // Called when the distilled article contents are available. The + // DistilledArticleProto is owned by a TaskTracker instance and is invalidated +@@ -140,7 +141,7 @@ class TaskTracker { + std::vector save_callbacks_; + // A ViewRequestDelegate will be added to this list when a view request is + // made and removed when the corresponding ViewerHandle is destroyed. +- std::vector viewers_; ++ base::ObserverList viewers_; + + std::unique_ptr distiller_; + bool blob_fetcher_running_; diff --git a/patches/chromium/x11_fix_window_enumeration_order_when_wm_doesn_t_set.patch b/patches/chromium/x11_fix_window_enumeration_order_when_wm_doesn_t_set.patch new file mode 100644 index 0000000000000..ce7d7d5445229 --- /dev/null +++ b/patches/chromium/x11_fix_window_enumeration_order_when_wm_doesn_t_set.patch @@ -0,0 +1,95 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Tudor Brindus +Date: Tue, 4 May 2021 07:17:23 +0000 +Subject: x11: Fix window enumeration order when WM doesn't set + |_NET_CLIENT_LIST_STACKING| + +Chrome needs to know what window to send Xdnd events to during a +drag-and-drop operation. + +It does so through |X11TopmostWindowFinder::FindWindowAt|, which calls +into |EnumerateWindows| when the WM has not set +|_NET_CLIENT_LIST_STACKING|. GNOME/mutter set this property, so this is +a little-tested code path. + +However, setting this property is not mandated by the spec, and in +practice wlroots/Sway do not currently set it. + +Chrome's current |EnumerateWindows| fallback path is incorrect, +resulting in downstream bugs like +https://github.com/swaywm/sway/issues/5692 and +https://github.com/swaywm/wlroots/issues/2889. + +|EnumerateWindows| ends up calling |EnumerateChildren|, which uses +|XQueryTree| to determine the stacking order. |XQueryTree| returns +windows in bottom-to-top order, so the list has to be reverse-iterated +to get a top-down order that |FindWindowAt| expects (and to match the +order reported by |_NET_CLIENT_LIST_STACKING|). + +The original code introduced in da11eed did so; however, it regressed in +3c64537 -- currently, the code comments are inconsistent with the actual +logic. + +This commit switches |EnumerateChildren| to use a reverse iterator. It +is not used anywhere but as a fallback when |_NET_CLIENT_LIST_STACKING| +is not present, so this should be a safe change. + +I have not touched the iteration order of Chrome's X11 menus. I suspect +that these are in the right order already. + +TEST=manually tested on Sway 1.6, with Chromium overlapping an X11 gedit + window + +Change-Id: I8f777aa566db1e8d0614187fa4b3d156caa1e0f9 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2844104 +Reviewed-by: Maksim Sisov +Commit-Queue: Maksim Sisov +Cr-Commit-Position: refs/heads/master@{#878767} + +diff --git a/AUTHORS b/AUTHORS +index ae48471f7360a946447c915621236155e1399f86..4b48c543aa3c70fa5f785fb294f5dfe1a48217be 100644 +--- a/AUTHORS ++++ b/AUTHORS +@@ -1036,6 +1036,7 @@ Toshihito Kikuchi + Trent Willis + Trevor Perrin + Tripta Gupta ++Tudor Brindus + Tuukka Toivonen + U. Artie Eoff + Umar Hansa +diff --git a/ui/base/x/x11_util.cc b/ui/base/x/x11_util.cc +index c210014f2b07e731fb2e7c3ccbce44dec43dda25..482fa1d3528fe1ca7280af2f3a32f55128e0ce96 100644 +--- a/ui/base/x/x11_util.cc ++++ b/ui/base/x/x11_util.cc +@@ -811,10 +811,10 @@ bool EnumerateChildren(EnumerateWindowsDelegate* delegate, + return false; + + std::vector windows; +- std::vector::iterator iter; + if (depth == 0) { + XMenuList::GetInstance()->InsertMenuWindows(&windows); + // Enumerate the menus first. ++ std::vector::iterator iter; + for (iter = windows.begin(); iter != windows.end(); iter++) { + if (delegate->ShouldStopIterating(*iter)) + return true; +@@ -829,7 +829,8 @@ bool EnumerateChildren(EnumerateWindowsDelegate* delegate, + + // XQueryTree returns the children of |window| in bottom-to-top order, so + // reverse-iterate the list to check the windows from top-to-bottom. +- for (iter = windows.begin(); iter != windows.end(); iter++) { ++ std::vector::reverse_iterator iter; ++ for (iter = windows.rbegin(); iter != windows.rend(); iter++) { + if (IsWindowNamed(*iter) && delegate->ShouldStopIterating(*iter)) + return true; + } +@@ -839,7 +840,7 @@ bool EnumerateChildren(EnumerateWindowsDelegate* delegate, + // loop because the recursion and call to XQueryTree are expensive and is only + // needed for a small number of cases. + if (++depth <= max_depth) { +- for (iter = windows.begin(); iter != windows.end(); iter++) { ++ for (iter = windows.rbegin(); iter != windows.rend(); iter++) { + if (EnumerateChildren(delegate, *iter, max_depth, depth)) + return true; + } diff --git a/patches/node/.patches b/patches/node/.patches index 2618e731bd747..546aa1217d5af 100644 --- a/patches/node/.patches +++ b/patches/node/.patches @@ -49,3 +49,4 @@ fix_add_safeforterminationscopes_for_sigint_interruptions.patch allow_preventing_preparestacktracecallback.patch src_inline_asynccleanuphookhandle_in_headers.patch src_make_freeenvironment_perform_all_necessary_cleanup.patch +process_correctly_parse_unicode_in_node_options.patch diff --git a/patches/node/process_correctly_parse_unicode_in_node_options.patch b/patches/node/process_correctly_parse_unicode_in_node_options.patch new file mode 100644 index 0000000000000..2f55d7e5cc368 --- /dev/null +++ b/patches/node/process_correctly_parse_unicode_in_node_options.patch @@ -0,0 +1,75 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Bartosz Sosnowski +Date: Wed, 22 Jul 2020 12:55:11 +0200 +Subject: process: correctly parse Unicode in NODE_OPTIONS + +Fixes an issue on Windows, where Unicode in NODE_OPTIONS was not parsed +correctly. + +Fixes: https://github.com/nodejs/node/issues/34399 + +PR-URL: https://github.com/nodejs/node/pull/34476 +Reviewed-By: Anna Henningsen +Reviewed-By: James M Snell +Reviewed-By: Gus Caplan +Reviewed-By: Denys Otrishko + +diff --git a/src/node_credentials.cc b/src/node_credentials.cc +index d552a501726396b0d38c55f6f7cb5c2287189fc8..7c7a4f84c860844641d6931a6352ea4473ab4eac 100644 +--- a/src/node_credentials.cc ++++ b/src/node_credentials.cc +@@ -58,8 +58,20 @@ bool SafeGetenv(const char* key, std::string* text, Environment* env) { + + { + Mutex::ScopedLock lock(per_process::env_var_mutex); +- if (const char* value = getenv(key)) { +- *text = value; ++ ++ size_t init_sz = 256; ++ MaybeStackBuffer val; ++ int ret = uv_os_getenv(key, *val, &init_sz); ++ ++ if (ret == UV_ENOBUFS) { ++ // Buffer is not large enough, reallocate to the updated init_sz ++ // and fetch env value again. ++ val.AllocateSufficientStorage(init_sz); ++ ret = uv_os_getenv(key, *val, &init_sz); ++ } ++ ++ if (ret >= 0) { // Env key value fetch success. ++ *text = *val; + return true; + } + } +diff --git a/test/parallel/test-unicode-node-options.js b/test/parallel/test-unicode-node-options.js +new file mode 100644 +index 0000000000000000000000000000000000000000..e5a40d118791d3748fa2a82e9c8bddefd78ad17e +--- /dev/null ++++ b/test/parallel/test-unicode-node-options.js +@@ -0,0 +1,26 @@ ++'use strict'; ++// Flags: --expose-internals ++require('../common'); ++const { getOptionValue } = require('internal/options'); ++const assert = require('assert'); ++const cp = require('child_process'); ++ ++const expected_redirect_value = 'foó'; ++ ++if (process.argv.length === 2) { ++ const NODE_OPTIONS = `--redirect-warnings=${expected_redirect_value}`; ++ const result = cp.spawnSync(process.argv0, ++ ['--expose-internals', __filename, 'test'], ++ { ++ env: { ++ ...process.env, ++ NODE_OPTIONS ++ }, ++ stdio: 'inherit' ++ }); ++ assert.strictEqual(result.status, 0); ++} else { ++ const redirect_value = getOptionValue('--redirect-warnings'); ++ console.log(`--redirect-warings=${redirect_value}`); ++ assert.strictEqual(redirect_value, expected_redirect_value); ++} diff --git a/patches/sqlite/.patches b/patches/sqlite/.patches index c842e852f3c98..7109ed15cc4c5 100644 --- a/patches/sqlite/.patches +++ b/patches/sqlite/.patches @@ -1 +1,3 @@ fix_a_problem_handling_sub-queries_with_both_a_correlated_where.patch +utf-8_q_when_20constructing_20the_20synthensized_20select_20sta.patch +sqlite_fix_an_undefined-integer-overflow_problem_in_fts3_c.patch diff --git a/patches/sqlite/sqlite_fix_an_undefined-integer-overflow_problem_in_fts3_c.patch b/patches/sqlite/sqlite_fix_an_undefined-integer-overflow_problem_in_fts3_c.patch new file mode 100644 index 0000000000000..5acc09a5eb729 --- /dev/null +++ b/patches/sqlite/sqlite_fix_an_undefined-integer-overflow_problem_in_fts3_c.patch @@ -0,0 +1,157 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darwin Huang +Date: Wed, 19 May 2021 14:13:15 -0700 +Subject: sqlite: Fix an undefined-integer-overflow problem in fts3.c. + +Original change: https://sqlite.org/src/info/a0bf931bd712037e + +Bug: 1204066 +Change-Id: I34704f1cfe36672d10065f4103c91fb4f35d3895 + +diff --git a/amalgamation/sqlite3.c b/amalgamation/sqlite3.c +index 9e3a46624d09f7abe645d1d9e4b2c430c8acc99e..8dff8dcb9be5fd5d1010a44d30d27461659f89c0 100644 +--- a/amalgamation/sqlite3.c ++++ b/amalgamation/sqlite3.c +@@ -168279,7 +168279,7 @@ static int fts3ScanInteriorNode( + char *zBuffer = 0; /* Buffer to load terms into */ + i64 nAlloc = 0; /* Size of allocated buffer */ + int isFirstTerm = 1; /* True when processing first term on page */ +- sqlite3_int64 iChild; /* Block id of child node to descend to */ ++ u64 iChild; /* Block id of child node to descend to */ + int nBuffer = 0; /* Total term size */ + + /* Skip over the 'height' varint that occurs at the start of every +@@ -168295,8 +168295,8 @@ static int fts3ScanInteriorNode( + ** table, then there are always 20 bytes of zeroed padding following the + ** nNode bytes of content (see sqlite3Fts3ReadBlock() for details). + */ +- zCsr += sqlite3Fts3GetVarint(zCsr, &iChild); +- zCsr += sqlite3Fts3GetVarint(zCsr, &iChild); ++ zCsr += sqlite3Fts3GetVarintU(zCsr, &iChild); ++ zCsr += sqlite3Fts3GetVarintU(zCsr, &iChild); + if( zCsr>zEnd ){ + return FTS_CORRUPT_VTAB; + } +@@ -168349,20 +168349,20 @@ static int fts3ScanInteriorNode( + */ + cmp = memcmp(zTerm, zBuffer, (nBuffer>nTerm ? nTerm : nBuffer)); + if( piFirst && (cmp<0 || (cmp==0 && nBuffer>nTerm)) ){ +- *piFirst = iChild; ++ *piFirst = (i64)iChild; + piFirst = 0; + } + + if( piLast && cmp<0 ){ +- *piLast = iChild; ++ *piLast = (i64)iChild; + piLast = 0; + } + + iChild++; + }; + +- if( piFirst ) *piFirst = iChild; +- if( piLast ) *piLast = iChild; ++ if( piFirst ) *piFirst = (i64)iChild; ++ if( piLast ) *piLast = (i64)iChild; + + finish_scan: + sqlite3_free(zBuffer); +diff --git a/amalgamation_dev/sqlite3.c b/amalgamation_dev/sqlite3.c +index 689d52d5f51e8f552d4191b6811f556a2b997303..5e56254000b0225d24b332cb4fa6b2b0507c68ea 100644 +--- a/amalgamation_dev/sqlite3.c ++++ b/amalgamation_dev/sqlite3.c +@@ -168779,7 +168779,7 @@ static int fts3ScanInteriorNode( + char *zBuffer = 0; /* Buffer to load terms into */ + i64 nAlloc = 0; /* Size of allocated buffer */ + int isFirstTerm = 1; /* True when processing first term on page */ +- sqlite3_int64 iChild; /* Block id of child node to descend to */ ++ u64 iChild; /* Block id of child node to descend to */ + int nBuffer = 0; /* Total term size */ + + /* Skip over the 'height' varint that occurs at the start of every +@@ -168795,8 +168795,8 @@ static int fts3ScanInteriorNode( + ** table, then there are always 20 bytes of zeroed padding following the + ** nNode bytes of content (see sqlite3Fts3ReadBlock() for details). + */ +- zCsr += sqlite3Fts3GetVarint(zCsr, &iChild); +- zCsr += sqlite3Fts3GetVarint(zCsr, &iChild); ++ zCsr += sqlite3Fts3GetVarintU(zCsr, &iChild); ++ zCsr += sqlite3Fts3GetVarintU(zCsr, &iChild); + if( zCsr>zEnd ){ + return FTS_CORRUPT_VTAB; + } +@@ -168849,20 +168849,20 @@ static int fts3ScanInteriorNode( + */ + cmp = memcmp(zTerm, zBuffer, (nBuffer>nTerm ? nTerm : nBuffer)); + if( piFirst && (cmp<0 || (cmp==0 && nBuffer>nTerm)) ){ +- *piFirst = iChild; ++ *piFirst = (i64)iChild; + piFirst = 0; + } + + if( piLast && cmp<0 ){ +- *piLast = iChild; ++ *piLast = (i64)iChild; + piLast = 0; + } + + iChild++; + }; + +- if( piFirst ) *piFirst = iChild; +- if( piLast ) *piLast = iChild; ++ if( piFirst ) *piFirst = (i64)iChild; ++ if( piLast ) *piLast = (i64)iChild; + + finish_scan: + sqlite3_free(zBuffer); +diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c +index 79dc5c88ceacb823d16889bd36250597361d6186..62b31373c3c3e9b61b3e1daae8d87d9393779b61 100644 +--- a/ext/fts3/fts3.c ++++ b/ext/fts3/fts3.c +@@ -1897,7 +1897,7 @@ static int fts3ScanInteriorNode( + char *zBuffer = 0; /* Buffer to load terms into */ + i64 nAlloc = 0; /* Size of allocated buffer */ + int isFirstTerm = 1; /* True when processing first term on page */ +- sqlite3_int64 iChild; /* Block id of child node to descend to */ ++ u64 iChild; /* Block id of child node to descend to */ + int nBuffer = 0; /* Total term size */ + + /* Skip over the 'height' varint that occurs at the start of every +@@ -1913,8 +1913,8 @@ static int fts3ScanInteriorNode( + ** table, then there are always 20 bytes of zeroed padding following the + ** nNode bytes of content (see sqlite3Fts3ReadBlock() for details). + */ +- zCsr += sqlite3Fts3GetVarint(zCsr, &iChild); +- zCsr += sqlite3Fts3GetVarint(zCsr, &iChild); ++ zCsr += sqlite3Fts3GetVarintU(zCsr, &iChild); ++ zCsr += sqlite3Fts3GetVarintU(zCsr, &iChild); + if( zCsr>zEnd ){ + return FTS_CORRUPT_VTAB; + } +@@ -1967,20 +1967,20 @@ static int fts3ScanInteriorNode( + */ + cmp = memcmp(zTerm, zBuffer, (nBuffer>nTerm ? nTerm : nBuffer)); + if( piFirst && (cmp<0 || (cmp==0 && nBuffer>nTerm)) ){ +- *piFirst = iChild; ++ *piFirst = (i64)iChild; + piFirst = 0; + } + + if( piLast && cmp<0 ){ +- *piLast = iChild; ++ *piLast = (i64)iChild; + piLast = 0; + } + + iChild++; + }; + +- if( piFirst ) *piFirst = iChild; +- if( piLast ) *piLast = iChild; ++ if( piFirst ) *piFirst = (i64)iChild; ++ if( piLast ) *piLast = (i64)iChild; + + finish_scan: + sqlite3_free(zBuffer); diff --git a/patches/sqlite/utf-8_q_when_20constructing_20the_20synthensized_20select_20sta.patch b/patches/sqlite/utf-8_q_when_20constructing_20the_20synthensized_20select_20sta.patch new file mode 100644 index 0000000000000..3d74441b7e633 --- /dev/null +++ b/patches/sqlite/utf-8_q_when_20constructing_20the_20synthensized_20select_20sta.patch @@ -0,0 +1,178 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: drh <> +Date: Wed, 19 May 2021 21:55:56 +0000 +Subject: When constructing the synthensized SELECT statement that is used to + choose the rows in an UPDATE FROM, make sure the first table is really the + table being updated, and not some common-table expression that happens to + have the same name. [forum:/forumpost/a274248080|forum post a274248080]. More + changes associated with CTE name resolution are pending. + +FossilOrigin-Name: 0f0959c6f95046e8e7887716e0a7de95da18d1e926ab1f919527083a56541db5 +(cherry picked from commit 1168f810929ede4d8d323a6acf721ff9cd89de90) + +diff --git a/amalgamation/sqlite3.c b/amalgamation/sqlite3.c +index 439a4c8f7a3162be775bea2d37e7b821cf2acd33..9e3a46624d09f7abe645d1d9e4b2c430c8acc99e 100644 +--- a/amalgamation/sqlite3.c ++++ b/amalgamation/sqlite3.c +@@ -1173,7 +1173,7 @@ extern "C" { + */ + #define SQLITE_VERSION "3.33.0" + #define SQLITE_VERSION_NUMBER 3033000 +-#define SQLITE_SOURCE_ID "2020-08-14 13:23:32 ba9c5a7088bb97ded8e889d7e21e6afe229baf8e670ea4f20d9625b61c8a3984" ++#define SQLITE_SOURCE_ID "2020-08-14 13:23:32 71b8cad5197c8a6074b4b716e311aab34b4a9952f37f56e7d755c4e96a8324d0" + + /* + ** CAPI3REF: Run-Time Library Version Numbers +@@ -110833,7 +110833,7 @@ SQLITE_PRIVATE Table *sqlite3LocateTableItem( + struct SrcList_item *p + ){ + const char *zDb; +- assert( p->pSchema==0 || p->zDatabase==0 ); ++ /* assert( p->pSchema==0 || p->zDatabase==0 ); FIX-ME */ + if( p->pSchema ){ + int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema); + zDb = pParse->db->aDb[iDb].zDbSName; +@@ -137810,6 +137810,10 @@ static void updateFromSelect( + + assert( pTabList->nSrc>1 ); + if( pSrc ){ ++ if( pSrc->a[0].zDatabase==0 ){ ++ int iSchema = sqlite3SchemaToIndex(db, pTab->pSchema); ++ pSrc->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iSchema].zDbSName); ++ } + pSrc->a[0].iCursor = -1; + pSrc->a[0].pTab->nTabRef--; + pSrc->a[0].pTab = 0; +@@ -230010,9 +230014,9 @@ SQLITE_API int sqlite3_stmt_init( + #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */ + + /************** End of stmt.c ************************************************/ +-#if __LINE__!=230013 ++#if __LINE__!=230017 + #undef SQLITE_SOURCE_ID +-#define SQLITE_SOURCE_ID "2020-08-14 13:23:32 ba9c5a7088bb97ded8e889d7e21e6afe229baf8e670ea4f20d9625b61c8aalt2" ++#define SQLITE_SOURCE_ID "2020-08-14 13:23:32 71b8cad5197c8a6074b4b716e311aab34b4a9952f37f56e7d755c4e96a83alt2" + #endif + /* Return the source-id for this library */ + SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } +diff --git a/amalgamation/sqlite3.h b/amalgamation/sqlite3.h +index fa3733fc1e68b49317e9531f690d634a3a508d74..231a1846bcf1f6ac789b589a7d7bef57c3567b88 100644 +--- a/amalgamation/sqlite3.h ++++ b/amalgamation/sqlite3.h +@@ -125,7 +125,7 @@ extern "C" { + */ + #define SQLITE_VERSION "3.33.0" + #define SQLITE_VERSION_NUMBER 3033000 +-#define SQLITE_SOURCE_ID "2020-08-14 13:23:32 ba9c5a7088bb97ded8e889d7e21e6afe229baf8e670ea4f20d9625b61c8a3984" ++#define SQLITE_SOURCE_ID "2020-08-14 13:23:32 71b8cad5197c8a6074b4b716e311aab34b4a9952f37f56e7d755c4e96a8324d0" + + /* + ** CAPI3REF: Run-Time Library Version Numbers +diff --git a/amalgamation_dev/sqlite3.c b/amalgamation_dev/sqlite3.c +index b98eb8b971f979d50a74bfb6b738625c515064ca..689d52d5f51e8f552d4191b6811f556a2b997303 100644 +--- a/amalgamation_dev/sqlite3.c ++++ b/amalgamation_dev/sqlite3.c +@@ -1173,7 +1173,7 @@ extern "C" { + */ + #define SQLITE_VERSION "3.33.0" + #define SQLITE_VERSION_NUMBER 3033000 +-#define SQLITE_SOURCE_ID "2020-08-14 13:23:32 ba9c5a7088bb97ded8e889d7e21e6afe229baf8e670ea4f20d9625b61c8a3984" ++#define SQLITE_SOURCE_ID "2020-08-14 13:23:32 71b8cad5197c8a6074b4b716e311aab34b4a9952f37f56e7d755c4e96a8324d0" + + /* + ** CAPI3REF: Run-Time Library Version Numbers +@@ -110846,7 +110846,7 @@ SQLITE_PRIVATE Table *sqlite3LocateTableItem( + struct SrcList_item *p + ){ + const char *zDb; +- assert( p->pSchema==0 || p->zDatabase==0 ); ++ /* assert( p->pSchema==0 || p->zDatabase==0 ); FIX-ME */ + if( p->pSchema ){ + int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema); + zDb = pParse->db->aDb[iDb].zDbSName; +@@ -137823,6 +137823,10 @@ static void updateFromSelect( + + assert( pTabList->nSrc>1 ); + if( pSrc ){ ++ if( pSrc->a[0].zDatabase==0 ){ ++ int iSchema = sqlite3SchemaToIndex(db, pTab->pSchema); ++ pSrc->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iSchema].zDbSName); ++ } + pSrc->a[0].iCursor = -1; + pSrc->a[0].pTab->nTabRef--; + pSrc->a[0].pTab = 0; +@@ -230510,9 +230514,9 @@ SQLITE_API int sqlite3_stmt_init( + #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */ + + /************** End of stmt.c ************************************************/ +-#if __LINE__!=230513 ++#if __LINE__!=230517 + #undef SQLITE_SOURCE_ID +-#define SQLITE_SOURCE_ID "2020-08-14 13:23:32 ba9c5a7088bb97ded8e889d7e21e6afe229baf8e670ea4f20d9625b61c8aalt2" ++#define SQLITE_SOURCE_ID "2020-08-14 13:23:32 71b8cad5197c8a6074b4b716e311aab34b4a9952f37f56e7d755c4e96a83alt2" + #endif + /* Return the source-id for this library */ + SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } +diff --git a/amalgamation_dev/sqlite3.h b/amalgamation_dev/sqlite3.h +index fa3733fc1e68b49317e9531f690d634a3a508d74..231a1846bcf1f6ac789b589a7d7bef57c3567b88 100644 +--- a/amalgamation_dev/sqlite3.h ++++ b/amalgamation_dev/sqlite3.h +@@ -125,7 +125,7 @@ extern "C" { + */ + #define SQLITE_VERSION "3.33.0" + #define SQLITE_VERSION_NUMBER 3033000 +-#define SQLITE_SOURCE_ID "2020-08-14 13:23:32 ba9c5a7088bb97ded8e889d7e21e6afe229baf8e670ea4f20d9625b61c8a3984" ++#define SQLITE_SOURCE_ID "2020-08-14 13:23:32 71b8cad5197c8a6074b4b716e311aab34b4a9952f37f56e7d755c4e96a8324d0" + + /* + ** CAPI3REF: Run-Time Library Version Numbers +diff --git a/manifest b/manifest +index dedff0947551e496fd7bd174d7ce47d362552987..989b65317019a735ef8ef7055fa7248d07fd4bd9 100644 +--- a/manifest ++++ b/manifest +@@ -479,7 +479,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 + F src/btree.c 1439fd9b45d4d1883c53752daef42af489adaa1a1508fa39dedbc9c80ea21a2f + F src/btree.h 7af72bbb4863c331c8f6753277ab40ee67d2a2125a63256d5c25489722ec162b + F src/btreeInt.h 83166f6daeb91062b6ae9ee6247b3ad07e40eba58f3c05ba9e8dedad4ab1ea38 +-F src/build.c dbdaee54ffef924a070eb6202017e10d6be56baab953ef0a8e714a6def683198 ++F src/build.c 961d09149c1273b4137f5a31c9c4c4ed51e3080049d945de19602d7456f30242 + F src/callback.c d0b853dd413255d2e337b34545e54d888ea02f20da5ad0e63585b389624c4a6c + F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e + F src/ctime.c e98518d2d3d4029a13c805e07313fb60c877be56db76e90dd5f3af73085d0ce6 +@@ -602,7 +602,7 @@ F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c + F src/tokenize.c 4dc01b267593537e2a0d0efe9f80dabe24c5b6f7627bc6971c487fa6a1dacbbf + F src/treeview.c 4b92992176fb2caefbe06ba5bd06e0e0ebcde3d5564758da672631f17aa51cda + F src/trigger.c ef67bde309a831515dc3c2173d792574309f2f42d45f8c078743fae9f7f98c75 +-F src/update.c fb15bec5b54fd098f4b84f6abc83c7103b45ba8484011fff8edf5ae31656eab6 ++F src/update.c 7c5cbbf9c15ff5c281246cfd7d7450501de02c49ec963557f9f1e4355845daeb + F src/upsert.c 2920de71b20f04fe25eb00b655d086f0ba60ea133c59d7fa3325c49838818e78 + F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 + F src/util.c c8bf30c4356b091bcc3b624d0e24b2b4d11b8be4d6c90d8e0705971e15cc819b +diff --git a/src/build.c b/src/build.c +index aa0f919bc6f2a2b59614233f86086868050aa9af..789ed80bb075f5394b7d241c468af76ba54d7f55 100644 +--- a/src/build.c ++++ b/src/build.c +@@ -452,7 +452,7 @@ Table *sqlite3LocateTableItem( + struct SrcList_item *p + ){ + const char *zDb; +- assert( p->pSchema==0 || p->zDatabase==0 ); ++ /* assert( p->pSchema==0 || p->zDatabase==0 ); FIX-ME */ + if( p->pSchema ){ + int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema); + zDb = pParse->db->aDb[iDb].zDbSName; +diff --git a/src/update.c b/src/update.c +index a9c43d62eb3e407426462e0536e0b94c0f19c006..807584e6c79daeec857cbeb98adc5045fbe54816 100644 +--- a/src/update.c ++++ b/src/update.c +@@ -220,6 +220,10 @@ static void updateFromSelect( + + assert( pTabList->nSrc>1 ); + if( pSrc ){ ++ if( pSrc->a[0].zDatabase==0 ){ ++ int iSchema = sqlite3SchemaToIndex(db, pTab->pSchema); ++ pSrc->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iSchema].zDbSName); ++ } + pSrc->a[0].iCursor = -1; + pSrc->a[0].pTab->nTabRef--; + pSrc->a[0].pTab = 0; diff --git a/patches/usrsctp/.patches b/patches/usrsctp/.patches index a679b67919e29..04537a78dfef6 100644 --- a/patches/usrsctp/.patches +++ b/patches/usrsctp/.patches @@ -1,3 +1,4 @@ cherry_picking_improve_the_input_validation_and_processing_of.patch cherry_picking_clean_up_more_resources_of_an_existing_sctp.patch cherry_picking_harden_the_handling_of_outgoing_streams.patch +improve_restart_handling.patch diff --git a/patches/usrsctp/improve_restart_handling.patch b/patches/usrsctp/improve_restart_handling.patch new file mode 100644 index 0000000000000..b68646d2f2c29 --- /dev/null +++ b/patches/usrsctp/improve_restart_handling.patch @@ -0,0 +1,63 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Michael Tuexen +Date: Mon, 3 May 2021 02:29:58 +0200 +Subject: Improve restart handling. + +This fixes in particular a possible use after free bug reported +Anatoly Korniltsev and Taylor Brandstetter for the userland stack. + +diff --git a/usrsctplib/netinet/sctp_input.c b/usrsctplib/netinet/sctp_input.c +index 6a5bdba4264b47e10766467255dd9ebd5d135556..c36743b1fd2c3ab82cacbbf78e2e07547da2e457 100755 +--- a/usrsctplib/netinet/sctp_input.c ++++ b/usrsctplib/netinet/sctp_input.c +@@ -2015,11 +2015,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, + /* temp code */ + if (how_indx < sizeof(asoc->cookie_how)) + asoc->cookie_how[how_indx] = 12; +- sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, net, +- SCTP_FROM_SCTP_INPUT + SCTP_LOC_16); +- sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, +- SCTP_FROM_SCTP_INPUT + SCTP_LOC_17); +- ++ sctp_stop_association_timers(stcb, false); + /* notify upper layer */ + *notification = SCTP_NOTIFY_ASSOC_RESTART; + atomic_add_int(&stcb->asoc.refcnt, 1); +@@ -2054,6 +2050,10 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, + asoc->str_reset_seq_in = asoc->init_seq_number; + + asoc->advanced_peer_ack_point = asoc->last_acked_seq; ++ asoc->data_pkts_seen = 0; ++ asoc->last_data_chunk_from = NULL; ++ asoc->last_control_chunk_from = NULL; ++ asoc->last_net_cmt_send_started = NULL; + if (asoc->mapping_array) { + memset(asoc->mapping_array, 0, + asoc->mapping_array_size); +@@ -2118,6 +2118,9 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, + SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk); + SCTP_DECR_CHK_COUNT(); + } ++ asoc->ctrl_queue_cnt = 0; ++ asoc->str_reset = NULL; ++ asoc->stream_reset_outstanding = 0; + TAILQ_FOREACH_SAFE(chk, &asoc->asconf_send_queue, sctp_next, nchk) { + TAILQ_REMOVE(&asoc->asconf_send_queue, chk, sctp_next); + if (chk->data) { +@@ -2188,12 +2191,13 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset, + return (NULL); + } + /* respond with a COOKIE-ACK */ +- sctp_stop_all_cookie_timers(stcb); +- sctp_toss_old_cookies(stcb, asoc); + sctp_send_cookie_ack(stcb); + if (how_indx < sizeof(asoc->cookie_how)) + asoc->cookie_how[how_indx] = 15; +- ++ if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE) && ++ (asoc->sctp_autoclose_ticks > 0)) { ++ sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb, NULL); ++ } + return (stcb); + } + if (how_indx < sizeof(asoc->cookie_how)) diff --git a/patches/v8/.patches b/patches/v8/.patches index e512b259474a6..59833e6b216c7 100644 --- a/patches/v8/.patches +++ b/patches/v8/.patches @@ -26,3 +26,13 @@ lts-m86_builtins_harden_array_prototype_concat.patch merged_compiler_fix_a_bug_in_visitspeculativeintegeradditiveop.patch merged_turbofan_harden_arrayprototypepop_and_arrayprototypeshift.patch m86-lts_compiler_fix_off-by-one_error_in_kadditivesafeinteger.patch +merged_wasm-simd_ia32_fix_f64x2_min_max_to_use_registers.patch +merged_liftoff_fix_2gb_memory_accesses_on_32-bit.patch +reland_compiler_fix_more_truncation_bugs_in_simplifiedlowering.patch +cherry-pick-9da8fb7c4b80.patch +m86-lts_squashed_multiple_commits.patch +cherry-pick-fd8cbdf7b888.patch +cherry-pick-fd9ce58ecd13.patch +merged_json_fix_gc_issue_in_buildjsonobject.patch +merged_compiler_fix_a_bug_in.patch +cherry-pick-1234764.patch diff --git a/patches/v8/cherry-pick-1234764.patch b/patches/v8/cherry-pick-1234764.patch new file mode 100644 index 0000000000000..de7d4de08aefe --- /dev/null +++ b/patches/v8/cherry-pick-1234764.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Georg Neis +Date: Tue, 10 Aug 2021 09:29:33 +0200 +Subject: Merged: [compiler] Harden + JSCallReducer::ReduceArrayIteratorPrototypeNext + +Revision: 65b20a0e65e1078f5dd230a5203e231bec790ab4 + +BUG=chromium:1234764 +NOTRY=true +NOPRESUBMIT=true +NOTREECHECKS=true +R=vahl@chromium.org + +Change-Id: I45faf253695011092de144c8e29bafac5337adec +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3084363 +Reviewed-by: Lutz Vahl +Commit-Queue: Georg Neis +Cr-Commit-Position: refs/branch-heads/9.2@{#53} +Cr-Branched-From: 51238348f95a1f5e0acc321efac7942d18a687a2-refs/heads/9.2.230@{#1} +Cr-Branched-From: 587a04f02ab0487d194b55a7137dc2045e071597-refs/heads/master@{#74656} + +diff --git a/src/compiler/js-call-reducer.cc b/src/compiler/js-call-reducer.cc +index b77094b7e1f0c57552fc7c8d3cea1f9d9ed7a269..a34b33e3a88b72f3ef6ca665f67cf3e9c7fff173 100644 +--- a/src/compiler/js-call-reducer.cc ++++ b/src/compiler/js-call-reducer.cc +@@ -5826,11 +5826,12 @@ Reduction JSCallReducer::ReduceArrayIteratorPrototypeNext(Node* node) { + Node* etrue = effect; + Node* if_true = graph()->NewNode(common()->IfTrue(), branch); + { +- // We know that the {index} is range of the {length} now. ++ // This extra check exists to refine the type of {index} but also to break ++ // an exploitation technique that abuses typer mismatches. + index = etrue = graph()->NewNode( +- common()->TypeGuard( +- Type::Range(0.0, length_access.type.Max() - 1.0, graph()->zone())), +- index, etrue, if_true); ++ simplified()->CheckBounds(p.feedback(), ++ CheckBoundsFlag::kAbortOnOutOfBounds), ++ index, length, etrue, if_true); + + done_true = jsgraph()->FalseConstant(); + if (iteration_kind == IterationKind::kKeys) { diff --git a/patches/v8/cherry-pick-9da8fb7c4b80.patch b/patches/v8/cherry-pick-9da8fb7c4b80.patch new file mode 100644 index 0000000000000..ce5dcefcb43fc --- /dev/null +++ b/patches/v8/cherry-pick-9da8fb7c4b80.patch @@ -0,0 +1,137 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Georg Neis +Date: Mon, 7 Jun 2021 10:41:38 +0200 +Subject: Squashed multiple commits. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Merged: Disable left-trimming when optimizing compile jobs exist +Revision: ac0605a1a486b8d074f116cc365de9d2b6d7c9e5 + +Merged: [heap] Don't assume that optimizing-compile-dispatcher exists +Revision: 022b312d55e75935cfa99cca7729ae2d3f795bd0 + +BUG=chromium:1211215,chromium:1215514 +NOTRY=true +NOPRESUBMIT=true +NOTREECHECKS=true + +(cherry picked from commit 8704c7c0b2f79cbe745f293b30d68f4505da7416) + +Change-Id: I3b3a37d64402ea464c8e653517928522a1c5e0da +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2940899 +Reviewed-by: Dominik Inführ +Commit-Queue: Georg Neis +Cr-Original-Commit-Position: refs/branch-heads/9.1@{#67} +Cr-Original-Branched-From: 0e4ac64a8cf298b14034a22f9fe7b085d2cb238d-refs/heads/9.1.269@{#1} +Cr-Original-Branched-From: f565e72d5ba88daae35a59d0f978643e2343e912-refs/heads/master@{#73847} +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2948657 +Reviewed-by: Artem Sumaneev +Commit-Queue: Victor-Gabriel Savu +Cr-Commit-Position: refs/branch-heads/8.6@{#107} +Cr-Branched-From: a64aed2333abf49e494d2a5ce24bbd14fff19f60-refs/heads/8.6.395@{#1} +Cr-Branched-From: a626bc036236c9bf92ac7b87dc40c9e538b087e3-refs/heads/master@{#69472} + +diff --git a/src/compiler-dispatcher/optimizing-compile-dispatcher.cc b/src/compiler-dispatcher/optimizing-compile-dispatcher.cc +index 528a9babe33041ff85c82e0ba8afbdb975783af8..b47aa5431ca634f677cd4b2441f75d42b3f0a930 100644 +--- a/src/compiler-dispatcher/optimizing-compile-dispatcher.cc ++++ b/src/compiler-dispatcher/optimizing-compile-dispatcher.cc +@@ -47,7 +47,6 @@ class OptimizingCompileDispatcher::CompileTask : public CancelableTask { + worker_thread_runtime_call_stats_( + isolate->counters()->worker_thread_runtime_call_stats()), + dispatcher_(dispatcher) { +- base::MutexGuard lock_guard(&dispatcher_->ref_count_mutex_); + ++dispatcher_->ref_count_; + } + +@@ -95,12 +94,7 @@ class OptimizingCompileDispatcher::CompileTask : public CancelableTask { + }; + + OptimizingCompileDispatcher::~OptimizingCompileDispatcher() { +-#ifdef DEBUG +- { +- base::MutexGuard lock_guard(&ref_count_mutex_); +- DCHECK_EQ(0, ref_count_); +- } +-#endif ++ DCHECK_EQ(0, ref_count_); + DCHECK_EQ(0, input_queue_length_); + DeleteArray(input_queue_); + } +@@ -227,6 +221,14 @@ void OptimizingCompileDispatcher::InstallOptimizedFunctions() { + } + } + ++bool OptimizingCompileDispatcher::HasJobs() { ++ DCHECK_EQ(ThreadId::Current(), isolate_->thread_id()); ++ // Note: This relies on {output_queue_} being mutated by a background thread ++ // only when {ref_count_} is not zero. Also, {ref_count_} is never incremented ++ // by a background thread. ++ return !(ref_count_ == 0 && output_queue_.empty()); ++} ++ + void OptimizingCompileDispatcher::QueueForOptimization( + OptimizedCompilationJob* job) { + DCHECK(IsQueueAvailable()); +diff --git a/src/compiler-dispatcher/optimizing-compile-dispatcher.h b/src/compiler-dispatcher/optimizing-compile-dispatcher.h +index 51803822d15353af31c446b960c3ee43cc7533fe..390e90b4ab8b7d1680545905ac8ef90c3a9099c9 100644 +--- a/src/compiler-dispatcher/optimizing-compile-dispatcher.h ++++ b/src/compiler-dispatcher/optimizing-compile-dispatcher.h +@@ -52,6 +52,9 @@ class V8_EXPORT_PRIVATE OptimizingCompileDispatcher { + + static bool Enabled() { return FLAG_concurrent_recompilation; } + ++ // This method must be called on the main thread. ++ bool HasJobs(); ++ + private: + class CompileTask; + +@@ -87,7 +90,7 @@ class V8_EXPORT_PRIVATE OptimizingCompileDispatcher { + + int blocked_jobs_; + +- int ref_count_; ++ std::atomic ref_count_; + base::Mutex ref_count_mutex_; + base::ConditionVariable ref_count_zero_; + +diff --git a/src/heap/heap.cc b/src/heap/heap.cc +index 6755a991df16a9c9d0e9efb2f378e4d68463532c..a017905bfcb0059aa12dbd1bd5a477bcca2dd616 100644 +--- a/src/heap/heap.cc ++++ b/src/heap/heap.cc +@@ -22,6 +22,7 @@ + #include "src/codegen/compilation-cache.h" + #include "src/common/assert-scope.h" + #include "src/common/globals.h" ++#include "src/compiler-dispatcher/optimizing-compile-dispatcher.h" + #include "src/debug/debug.h" + #include "src/deoptimizer/deoptimizer.h" + #include "src/execution/isolate-utils-inl.h" +@@ -3036,6 +3037,12 @@ bool Heap::CanMoveObjectStart(HeapObject object) { + + if (IsLargeObject(object)) return false; + ++ // Compilation jobs may have references to the object. ++ if (isolate()->concurrent_recompilation_enabled() && ++ isolate()->optimizing_compile_dispatcher()->HasJobs()) { ++ return false; ++ } ++ + // We can move the object start if the page was already swept. + return Page::FromHeapObject(object)->SweepingDone(); + } +diff --git a/test/mjsunit/compiler/regress-1215514.js b/test/mjsunit/compiler/regress-1215514.js +new file mode 100644 +index 0000000000000000000000000000000000000000..a597b310498458fd7219c33ff188ca2a6e543f45 +--- /dev/null ++++ b/test/mjsunit/compiler/regress-1215514.js +@@ -0,0 +1,7 @@ ++// Copyright 2021 the V8 project authors. All rights reserved. ++// Use of this source code is governed by a BSD-style license that can be ++// found in the LICENSE file. ++ ++// Flags: --no-concurrent-recompilation ++ ++new Array(4242).shift(); diff --git a/patches/v8/cherry-pick-fd8cbdf7b888.patch b/patches/v8/cherry-pick-fd8cbdf7b888.patch new file mode 100644 index 0000000000000..6a30c4667ec65 --- /dev/null +++ b/patches/v8/cherry-pick-fd8cbdf7b888.patch @@ -0,0 +1,62 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Georg Neis +Date: Thu, 27 May 2021 13:04:30 +0200 +Subject: Reland "Merged: [compiler] Always record constness dependency for + FastDataConstant" + +This is a reland of 638d1b238d510a349bdd38648add8d5c85bc5f7d after a +one-character change. A local variable still has a non-optional type +in this version of V8. + +Original change's description: +> Merged: [compiler] Always record constness dependency for FastDataConstant +> +> Revision: 1bfa5139966fe0c9e8036fe6362b61c483675775 +> +> BUG=chromium:1209558 +> NOTRY=true +> NOPRESUBMIT=true +> NOTREECHECKS=true +> +> Change-Id: If4f7243647bcc12ed482796c1353f0717630f6b9 +> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2919823 +> Commit-Queue: Georg Neis +> Reviewed-by: Igor Sheludko +> Cr-Commit-Position: refs/branch-heads/9.1@{#59} +> Cr-Branched-From: 0e4ac64a8cf298b14034a22f9fe7b085d2cb238d-refs/heads/9.1.269@{#1} +> Cr-Branched-From: f565e72d5ba88daae35a59d0f978643e2343e912-refs/heads/master@{#73847} + +NOTRY=true +NOPRESUBMIT=true +NOTREECHECKS=true + +(cherry picked from commit 73666e3f6d6bdbc93ab81cf8b3803dd04930e293) + +Bug: chromium:1209558 +Change-Id: I0c81353882b0f17942fd92ad4181732f941bcb1d +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2939991 +Commit-Queue: Georg Neis +Reviewed-by: Igor Sheludko +Cr-Original-Commit-Position: refs/branch-heads/9.1@{#63} +Cr-Original-Branched-From: 0e4ac64a8cf298b14034a22f9fe7b085d2cb238d-refs/heads/9.1.269@{#1} +Cr-Original-Branched-From: f565e72d5ba88daae35a59d0f978643e2343e912-refs/heads/master@{#73847} +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2948652 +Reviewed-by: Artem Sumaneev +Commit-Queue: Victor-Gabriel Savu +Cr-Commit-Position: refs/branch-heads/8.6@{#108} +Cr-Branched-From: a64aed2333abf49e494d2a5ce24bbd14fff19f60-refs/heads/8.6.395@{#1} +Cr-Branched-From: a626bc036236c9bf92ac7b87dc40c9e538b087e3-refs/heads/master@{#69472} + +diff --git a/src/compiler/access-info.cc b/src/compiler/access-info.cc +index 046927e9430e89596bd4077af37fb9374d279282..7f7a8fee63ed8bdd322bbbca8444c9345b3d32f7 100644 +--- a/src/compiler/access-info.cc ++++ b/src/compiler/access-info.cc +@@ -892,7 +892,7 @@ PropertyAccessInfo AccessInfoFactory::LookupTransition( + // Transitioning stores *may* store to const fields. The resulting + // DataConstant access infos can be distinguished from later, i.e. redundant, + // stores to the same constant field by the presence of a transition map. +- switch (details.constness()) { ++ switch (dependencies()->DependOnFieldConstness(transition_map_ref, number)) { + case PropertyConstness::kMutable: + return PropertyAccessInfo::DataField( + zone(), map, std::move(unrecorded_dependencies), field_index, diff --git a/patches/v8/cherry-pick-fd9ce58ecd13.patch b/patches/v8/cherry-pick-fd9ce58ecd13.patch new file mode 100644 index 0000000000000..22eae1f236880 --- /dev/null +++ b/patches/v8/cherry-pick-fd9ce58ecd13.patch @@ -0,0 +1,107 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Kim-Anh Tran +Date: Thu, 6 May 2021 10:02:01 +0200 +Subject: M86-LTS: [debugger] Return ServerError if debugger agent is disabled + +This returns a server error on setting breakpoints if the +agent is disabled. + +(cherry picked from commit 5aa2de8128f885c44df79d38fb4aa5c6a5d94306) + +Also-by: bmeurer@chromium.org +Fixed: chromium:1202534 +No-Try: true +No-Presubmit: true +No-Tree-Checks: true +Change-Id: I87c80a4bd785fa5c59a8dd0d5ac5f4b31b015ed8 +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2874662 +Commit-Queue: Kim-Anh Tran +Commit-Queue: Benedikt Meurer +Auto-Submit: Kim-Anh Tran +Reviewed-by: Benedikt Meurer +Cr-Original-Commit-Position: refs/heads/master@{#74399} +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2940882 +Reviewed-by: Achuith Bhandarkar +Commit-Queue: Artem Sumaneev +Cr-Commit-Position: refs/branch-heads/8.6@{#105} +Cr-Branched-From: a64aed2333abf49e494d2a5ce24bbd14fff19f60-refs/heads/8.6.395@{#1} +Cr-Branched-From: a626bc036236c9bf92ac7b87dc40c9e538b087e3-refs/heads/master@{#69472} + +diff --git a/src/inspector/v8-debugger-agent-impl.cc b/src/inspector/v8-debugger-agent-impl.cc +index 399fa4c4093450db89309d5aff680a2613614192..bd948cd8ac1c1492df191b63b83298fb9b3c5c5c 100644 +--- a/src/inspector/v8-debugger-agent-impl.cc ++++ b/src/inspector/v8-debugger-agent-impl.cc +@@ -499,6 +499,8 @@ Response V8DebuggerAgentImpl::setBreakpointByUrl( + Maybe optionalColumnNumber, Maybe optionalCondition, + String16* outBreakpointId, + std::unique_ptr>* locations) { ++ if (!enabled()) return Response::ServerError(kDebuggerNotEnabled); ++ + *locations = std::make_unique>(); + + int specified = (optionalURL.isJust() ? 1 : 0) + +@@ -587,6 +589,8 @@ Response V8DebuggerAgentImpl::setBreakpoint( + String16 breakpointId = generateBreakpointId( + BreakpointType::kByScriptId, location->getScriptId(), + location->getLineNumber(), location->getColumnNumber(0)); ++ if (!enabled()) return Response::ServerError(kDebuggerNotEnabled); ++ + if (m_breakpointIdToDebuggerBreakpointIds.find(breakpointId) != + m_breakpointIdToDebuggerBreakpointIds.end()) { + return Response::ServerError( +@@ -605,6 +609,8 @@ Response V8DebuggerAgentImpl::setBreakpoint( + Response V8DebuggerAgentImpl::setBreakpointOnFunctionCall( + const String16& functionObjectId, Maybe optionalCondition, + String16* outBreakpointId) { ++ if (!enabled()) return Response::ServerError(kDebuggerNotEnabled); ++ + InjectedScript::ObjectScope scope(m_session, functionObjectId); + Response response = scope.initialize(); + if (!response.IsSuccess()) return response; +diff --git a/test/inspector/debugger/set-breakpoint-before-enabling-expected.txt b/test/inspector/debugger/set-breakpoint-before-enabling-expected.txt +index 02bfe0d80cdecd96d37988d9d6850b49c5d7e39d..a85aab6fe0c71f3346fe79694d1a334e2cb12fb2 100644 +--- a/test/inspector/debugger/set-breakpoint-before-enabling-expected.txt ++++ b/test/inspector/debugger/set-breakpoint-before-enabling-expected.txt +@@ -1,7 +1,13 @@ + Tests that setting breakpoint before enabling debugger produces an error +-setBreakpointByUrl error: undefined ++setBreakpointByUrl error: { ++ "code": -32000, ++ "message": "Debugger agent is not enabled" ++} + setBreakpoint error: { +- "code": -32602, +- "message": "Invalid parameters", +- "data": "Failed to deserialize params.location - BINDINGS: mandatory field missing at " ++ "code": -32000, ++ "message": "Debugger agent is not enabled" ++} ++setBreakpointOnFunctionCall error: { ++ "code": -32000, ++ "message": "Debugger agent is not enabled" + } +diff --git a/test/inspector/debugger/set-breakpoint-before-enabling.js b/test/inspector/debugger/set-breakpoint-before-enabling.js +index 5af1085c8747089dea15550949130b8ea243b524..4401466a921692bbe94b52e60083d92769407ee3 100644 +--- a/test/inspector/debugger/set-breakpoint-before-enabling.js ++++ b/test/inspector/debugger/set-breakpoint-before-enabling.js +@@ -10,12 +10,19 @@ function didSetBreakpointByUrlBeforeEnable(message) + { + InspectorTest.log("setBreakpointByUrl error: " + JSON.stringify( + InspectorTest.trimErrorMessage(message).error, null, 2)); +- Protocol.Debugger.setBreakpoint().then(didSetBreakpointBeforeEnable); ++ Protocol.Debugger.setBreakpoint({location: { scriptId: "4", lineNumber: 0, columnNumber: 0 }}).then(didSetBreakpointBeforeEnable); + } + + function didSetBreakpointBeforeEnable(message) + { + InspectorTest.log("setBreakpoint error: " + JSON.stringify( + InspectorTest.trimErrorMessage(message).error, null, 2)); ++ Protocol.Debugger.setBreakpointOnFunctionCall({objectId: "4"}).then(didSetBreakpointOnFunctionCallBeforeEnable); ++} ++ ++function didSetBreakpointOnFunctionCallBeforeEnable(message) ++{ ++ InspectorTest.log("setBreakpointOnFunctionCall error: " + JSON.stringify( ++ InspectorTest.trimErrorMessage(message).error, null, 2)); + InspectorTest.completeTest(); + } diff --git a/patches/v8/m86-lts_squashed_multiple_commits.patch b/patches/v8/m86-lts_squashed_multiple_commits.patch new file mode 100644 index 0000000000000..8f9a3f1c3856d --- /dev/null +++ b/patches/v8/m86-lts_squashed_multiple_commits.patch @@ -0,0 +1,299 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "ishell@chromium.org" +Date: Tue, 8 Jun 2021 17:33:32 +0200 +Subject: Squashed multiple commits. + +Merged: [runtime] Fix handling of interceptors +Revision: f9857fdf74 + +Merged: [runtime] Fix handling of interceptors, pt.2 +Revision: 1f5113816c + +BUG=chromium:1216437 +NOTRY=true +NOPRESUBMIT=true +NOTREECHECKS=true + +(cherry picked from commit 1936d568193b37d50d99218724ebbb76785a30d2) + +Change-Id: Ief3da51866c8d0b5e85c76fad00b25ac2379f615 +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2947407 +Reviewed-by: Leszek Swirski +Cr-Original-Commit-Position: refs/branch-heads/9.1@{#71} +Cr-Original-Branched-From: 0e4ac64a8cf298b14034a22f9fe7b085d2cb238d-refs/heads/9.1.269@{#1} +Cr-Original-Branched-From: f565e72d5ba88daae35a59d0f978643e2343e912-refs/heads/master@{#73847} +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2948662 +Reviewed-by: Igor Sheludko +Reviewed-by: Artem Sumaneev +Commit-Queue: Victor-Gabriel Savu +Cr-Commit-Position: refs/branch-heads/8.6@{#110} +Cr-Branched-From: a64aed2333abf49e494d2a5ce24bbd14fff19f60-refs/heads/8.6.395@{#1} +Cr-Branched-From: a626bc036236c9bf92ac7b87dc40c9e538b087e3-refs/heads/master@{#69472} + +diff --git a/src/objects/objects.cc b/src/objects/objects.cc +index 51b9caef8b3531804f8aa615a4c612c1c2bdf34d..37ac3dd1063a0a750bed4340c360ff7e6fbb3a84 100644 +--- a/src/objects/objects.cc ++++ b/src/objects/objects.cc +@@ -2488,9 +2488,21 @@ Maybe Object::SetPropertyInternal(LookupIterator* it, + if ((maybe_attributes.FromJust() & READ_ONLY) != 0) { + return WriteToReadOnlyProperty(it, value, should_throw); + } +- if (maybe_attributes.FromJust() == ABSENT) break; +- *found = false; +- return Nothing(); ++ // At this point we might have called interceptor's query or getter ++ // callback. Assuming that the callbacks have side effects, we use ++ // Object::SetSuperProperty() which works properly regardless on ++ // whether the property was present on the receiver or not when ++ // storing to the receiver. ++ if (maybe_attributes.FromJust() == ABSENT) { ++ // Proceed lookup from the next state. ++ it->Next(); ++ } else { ++ // Finish lookup in order to make Object::SetSuperProperty() store ++ // property to the receiver. ++ it->NotFound(); ++ } ++ return Object::SetSuperProperty(it, value, store_origin, ++ should_throw); + } + break; + } +@@ -2565,6 +2577,8 @@ Maybe Object::SetProperty(LookupIterator* it, Handle value, + if (found) return result; + } + ++ // TODO(ishell): refactor this: both SetProperty and and SetSuperProperty have ++ // this piece of code. + // If the receiver is the JSGlobalObject, the store was contextual. In case + // the property did not exist yet on the global object itself, we have to + // throw a reference error in strict mode. In sloppy mode, we continue. +@@ -2601,6 +2615,8 @@ Maybe Object::SetSuperProperty(LookupIterator* it, Handle value, + } + Handle receiver = Handle::cast(it->GetReceiver()); + ++ // Note, the callers rely on the fact that this code is redoing the full own ++ // lookup from scratch. + LookupIterator::Configuration c = LookupIterator::OWN; + LookupIterator own_lookup = + it->IsElement() ? LookupIterator(isolate, receiver, it->index(), c) +@@ -2663,6 +2679,25 @@ Maybe Object::SetSuperProperty(LookupIterator* it, Handle value, + } + } + ++ // TODO(ishell): refactor this: both SetProperty and and SetSuperProperty have ++ // this piece of code. ++ // If the receiver is the JSGlobalObject, the store was contextual. In case ++ // the property did not exist yet on the global object itself, we have to ++ // throw a reference error in strict mode. In sloppy mode, we continue. ++ if (receiver->IsJSGlobalObject() && ++ (GetShouldThrow(isolate, should_throw) == ShouldThrow::kThrowOnError)) { ++ if (own_lookup.state() == LookupIterator::TRANSITION) { ++ // The property cell that we have created is garbage because we are going ++ // to throw now instead of putting it into the global dictionary. However, ++ // the cell might already have been stored into the feedback vector, so ++ // we must invalidate it nevertheless. ++ own_lookup.transition_cell()->ClearAndInvalidate(ReadOnlyRoots(isolate)); ++ } ++ isolate->Throw(*isolate->factory()->NewReferenceError( ++ MessageTemplate::kNotDefined, own_lookup.GetName())); ++ return Nothing(); ++ } ++ + return AddDataProperty(&own_lookup, value, NONE, should_throw, store_origin); + } + +diff --git a/test/cctest/test-api-interceptors.cc b/test/cctest/test-api-interceptors.cc +index 812768b461a471075becd83c7c9481d12191ff51..05edb1fdd4c4a3aa21e618269a1a8ad0822788e6 100644 +--- a/test/cctest/test-api-interceptors.cc ++++ b/test/cctest/test-api-interceptors.cc +@@ -877,9 +877,11 @@ THREADED_TEST(InterceptorHasOwnPropertyCausingGC) { + CHECK(!value->BooleanValue(isolate)); + } + +-static void CheckInterceptorIC(v8::GenericNamedPropertyGetterCallback getter, +- v8::GenericNamedPropertyQueryCallback query, +- const char* source, int expected) { ++namespace { ++ ++void CheckInterceptorIC(v8::GenericNamedPropertyGetterCallback getter, ++ v8::GenericNamedPropertyQueryCallback query, ++ const char* source, int expected) { + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope scope(isolate); + v8::Local templ = ObjectTemplate::New(isolate); +@@ -894,14 +896,13 @@ static void CheckInterceptorIC(v8::GenericNamedPropertyGetterCallback getter, + CHECK_EQ(expected, value->Int32Value(context.local()).FromJust()); + } + +-static void CheckInterceptorLoadIC( +- v8::GenericNamedPropertyGetterCallback getter, const char* source, +- int expected) { ++void CheckInterceptorLoadIC(v8::GenericNamedPropertyGetterCallback getter, ++ const char* source, int expected) { + CheckInterceptorIC(getter, nullptr, source, expected); + } + +-static void InterceptorLoadICGetter( +- Local name, const v8::PropertyCallbackInfo& info) { ++void InterceptorLoadICGetter(Local name, ++ const v8::PropertyCallbackInfo& info) { + ApiTestFuzzer::Fuzz(); + v8::Isolate* isolate = CcTest::isolate(); + CHECK_EQ(isolate, info.GetIsolate()); +@@ -911,6 +912,7 @@ static void InterceptorLoadICGetter( + info.GetReturnValue().Set(v8::Integer::New(isolate, 42)); + } + ++} // namespace + + // This test should hit the load IC for the interceptor case. + THREADED_TEST(InterceptorLoadIC) { +@@ -927,9 +929,23 @@ THREADED_TEST(InterceptorLoadIC) { + // configurations of interceptor and explicit fields works fine + // (those cases are special cased to get better performance). + +-static void InterceptorLoadXICGetter( ++namespace { ++ ++void InterceptorLoadXICGetter(Local name, ++ const v8::PropertyCallbackInfo& info) { ++ ApiTestFuzzer::Fuzz(); ++ info.GetReturnValue().Set( ++ v8_str("x") ++ ->Equals(info.GetIsolate()->GetCurrentContext(), name) ++ .FromJust() ++ ? v8::Local(v8::Integer::New(info.GetIsolate(), 42)) ++ : v8::Local()); ++} ++ ++void InterceptorLoadXICGetterWithSideEffects( + Local name, const v8::PropertyCallbackInfo& info) { + ApiTestFuzzer::Fuzz(); ++ CompileRun("interceptor_getter_side_effect()"); + info.GetReturnValue().Set( + v8_str("x") + ->Equals(info.GetIsolate()->GetCurrentContext(), name) +@@ -938,6 +954,7 @@ static void InterceptorLoadXICGetter( + : v8::Local()); + } + ++} // namespace + + THREADED_TEST(InterceptorLoadICWithFieldOnHolder) { + CheckInterceptorLoadIC(InterceptorLoadXICGetter, +@@ -1461,6 +1478,18 @@ void HasICQueryToggle(TKey name, + isolate, toggle ? v8::internal::ABSENT : v8::internal::NONE)); + } + ++template ++void HasICQuerySideEffect(TKey name, ++ const v8::PropertyCallbackInfo& info) { ++ ApiTestFuzzer::Fuzz(); ++ v8::Isolate* isolate = CcTest::isolate(); ++ CHECK_EQ(isolate, info.GetIsolate()); ++ CompileRun("interceptor_query_side_effect()"); ++ if (attribute != v8::internal::ABSENT) { ++ info.GetReturnValue().Set(v8::Integer::New(isolate, attribute)); ++ } ++} ++ + int named_query_counter = 0; + void NamedQueryCallback(Local name, + const v8::PropertyCallbackInfo& info) { +@@ -1526,6 +1555,42 @@ THREADED_TEST(InterceptorHasICQueryToggle) { + 500); + } + ++THREADED_TEST(InterceptorStoreICWithSideEffectfulCallbacks) { ++ CheckInterceptorIC(EmptyInterceptorGetter, ++ HasICQuerySideEffect, v8::internal::ABSENT>, ++ "let r;" ++ "let inside_side_effect = false;" ++ "let interceptor_query_side_effect = function() {" ++ " if (!inside_side_effect) {" ++ " inside_side_effect = true;" ++ " r.x = 153;" ++ " inside_side_effect = false;" ++ " }" ++ "};" ++ "for (var i = 0; i < 20; i++) {" ++ " r = { __proto__: o };" ++ " r.x = i;" ++ "}", ++ 19); ++ ++ CheckInterceptorIC(InterceptorLoadXICGetterWithSideEffects, ++ nullptr, // query callback is not provided ++ "let r;" ++ "let inside_side_effect = false;" ++ "let interceptor_getter_side_effect = function() {" ++ " if (!inside_side_effect) {" ++ " inside_side_effect = true;" ++ " r.y = 153;" ++ " inside_side_effect = false;" ++ " }" ++ "};" ++ "for (var i = 0; i < 20; i++) {" ++ " r = { __proto__: o };" ++ " r.y = i;" ++ "}", ++ 19); ++} ++ + static void InterceptorStoreICSetter( + Local key, Local value, + const v8::PropertyCallbackInfo& info) { +@@ -1575,6 +1640,52 @@ THREADED_TEST(InterceptorStoreICWithNoSetter) { + CHECK_EQ(239 + 42, value->Int32Value(context.local()).FromJust()); + } + ++THREADED_TEST(EmptyInterceptorDoesNotShadowReadOnlyProperty) { ++ // Interceptor should not shadow readonly property 'x' on the prototype, and ++ // attempt to store to 'x' must throw. ++ CheckInterceptorIC(EmptyInterceptorGetter, ++ HasICQuery, v8::internal::ABSENT>, ++ "'use strict';" ++ "let p = {};" ++ "Object.defineProperty(p, 'x', " ++ " {value: 153, writable: false});" ++ "o.__proto__ = p;" ++ "let result = 0;" ++ "let r;" ++ "for (var i = 0; i < 20; i++) {" ++ " r = { __proto__: o };" ++ " try {" ++ " r.x = i;" ++ " } catch (e) {" ++ " result++;" ++ " }" ++ "}" ++ "result", ++ 20); ++} ++ ++THREADED_TEST(InterceptorShadowsReadOnlyProperty) { ++ // Interceptor claims that it has a writable property 'x', so the existence ++ // of the readonly property 'x' on the prototype should not cause exceptions. ++ CheckInterceptorIC(InterceptorLoadXICGetter, ++ nullptr, // query callback ++ "'use strict';" ++ "let p = {};" ++ "Object.defineProperty(p, 'x', " ++ " {value: 153, writable: false});" ++ "o.__proto__ = p;" ++ "let result = 0;" ++ "let r;" ++ "for (var i = 0; i < 20; i++) {" ++ " r = { __proto__: o };" ++ " try {" ++ " r.x = i;" ++ " result++;" ++ " } catch (e) {}" ++ "}" ++ "result", ++ 20); ++} + + THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) { + v8::HandleScope scope(CcTest::isolate()); diff --git a/patches/v8/merged_compiler_fix_a_bug_in.patch b/patches/v8/merged_compiler_fix_a_bug_in.patch new file mode 100644 index 0000000000000..e17421b9f3b3d --- /dev/null +++ b/patches/v8/merged_compiler_fix_a_bug_in.patch @@ -0,0 +1,35 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Georg Neis +Date: Tue, 13 Jul 2021 17:26:47 +0200 +Subject: Merged: [compiler] Fix a bug in + CodeGenerator::AddTranslationForOperand + +(cherry picked from commit 374354bfe4a30740b96936b33e522d6fcd1cda67) + +Bug: chromium:1228407 +No-Try: true +No-Presubmit: true +No-Tree-Checks: true +Change-Id: I358d8736b7b5f87300496cbb39a7689d8207d85f +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3027260 +Bot-Commit: Rubber Stamper +Reviewed-by: Adam Klein +Commit-Queue: Adam Klein +Cr-Commit-Position: refs/branch-heads/9.1@{#77} +Cr-Branched-From: 0e4ac64a8cf298b14034a22f9fe7b085d2cb238d-refs/heads/9.1.269@{#1} +Cr-Branched-From: f565e72d5ba88daae35a59d0f978643e2343e912-refs/heads/master@{#73847} + +diff --git a/src/compiler/backend/code-generator.cc b/src/compiler/backend/code-generator.cc +index 33a80f52d0d6b502eefa62a97b1f24400abec3a9..6f25ce706fd178682b764bd3fade01bb6bffcdd6 100644 +--- a/src/compiler/backend/code-generator.cc ++++ b/src/compiler/backend/code-generator.cc +@@ -1306,7 +1306,8 @@ void CodeGenerator::AddTranslationForOperand(Translation* translation, + default: + UNREACHABLE(); + } +- if (literal.object().equals(info()->closure())) { ++ if (literal.object().equals(info()->closure()) && ++ info()->function_context_specializing()) { + translation->StoreJSFrameFunction(); + } else { + int literal_id = DefineDeoptimizationLiteral(literal); diff --git a/patches/v8/merged_json_fix_gc_issue_in_buildjsonobject.patch b/patches/v8/merged_json_fix_gc_issue_in_buildjsonobject.patch new file mode 100644 index 0000000000000..145baf27643b9 --- /dev/null +++ b/patches/v8/merged_json_fix_gc_issue_in_buildjsonobject.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Victor Gomes +Date: Mon, 31 May 2021 13:16:54 +0200 +Subject: Merged: [JSON] Fix GC issue in BuildJsonObject + +We must ensure that the sweeper is not running or has already swept +mutable_double_buffer. Otherwise the GC can add it to the free list. + +Change-Id: If0fc7617acdb6690f0567215b78f8728e1643ec0 +No-Try: true +No-Presubmit: true +No-Tree-Checks: true +Bug: v8:11837, chromium:1214842 +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2993033 +Reviewed-by: Michael Lippautz +Reviewed-by: Toon Verwaest +Commit-Queue: Victor Gomes +Cr-Commit-Position: refs/branch-heads/9.1@{#75} +Cr-Branched-From: 0e4ac64a8cf298b14034a22f9fe7b085d2cb238d-refs/heads/9.1.269@{#1} +Cr-Branched-From: f565e72d5ba88daae35a59d0f978643e2343e912-refs/heads/master@{#73847} + +diff --git a/src/heap/heap.cc b/src/heap/heap.cc +index a017905bfcb0059aa12dbd1bd5a477bcca2dd616..f079fd333fb1e4571d8bbe8f6041fa6bc458bcb7 100644 +--- a/src/heap/heap.cc ++++ b/src/heap/heap.cc +@@ -2148,6 +2148,10 @@ size_t Heap::PerformGarbageCollection( + return freed_global_handles; + } + ++void Heap::EnsureSweepingCompleted() { ++ mark_compact_collector()->EnsureSweepingCompleted(); ++} ++ + void Heap::RecomputeLimits(GarbageCollector collector) { + if (!((collector == MARK_COMPACTOR) || + (HasLowYoungGenerationAllocationRate() && +diff --git a/src/heap/heap.h b/src/heap/heap.h +index b8220dad5eb08cd8bffa9ff0c11d9f149e6fad10..cff57d94e822856f607e4a16cece3ca08c6e0e3c 100644 +--- a/src/heap/heap.h ++++ b/src/heap/heap.h +@@ -1065,6 +1065,8 @@ class Heap { + Reservation* reservations, const std::vector& large_objects, + const std::vector
& maps); + ++ void EnsureSweepingCompleted(); ++ + IncrementalMarking* incremental_marking() { + return incremental_marking_.get(); + } +diff --git a/src/json/json-parser.cc b/src/json/json-parser.cc +index d099fa36cba13daa0ffe915f8a4a067f3f392685..75e78923a4bc30fcfb16fccb40759408cfa42b83 100644 +--- a/src/json/json-parser.cc ++++ b/src/json/json-parser.cc +@@ -633,6 +633,11 @@ Handle JsonParser::BuildJsonObject( + DCHECK_EQ(mutable_double_address, end); + } + #endif ++ // Before setting the length of mutable_double_buffer back to zero, we ++ // must ensure that the sweeper is not running or has already swept the ++ // object's page. Otherwise the GC can add the contents of ++ // mutable_double_buffer to the free list. ++ isolate()->heap()->EnsureSweepingCompleted(); + mutable_double_buffer->set_length(0); + } + } diff --git a/patches/v8/merged_liftoff_fix_2gb_memory_accesses_on_32-bit.patch b/patches/v8/merged_liftoff_fix_2gb_memory_accesses_on_32-bit.patch new file mode 100644 index 0000000000000..05463706258c3 --- /dev/null +++ b/patches/v8/merged_liftoff_fix_2gb_memory_accesses_on_32-bit.patch @@ -0,0 +1,120 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrey Belenko +Date: Tue, 18 May 2021 21:05:35 +0200 +Subject: Merged: [liftoff] Fix >=2GB memory accesses on 32-bit + +We were inconsistent in handling offsets >= 2GB on 32-bit systems. The +code was still relying on this being detected as statically out of +bounds, but with the increase of {kV8MaxWasmMemoryPages} to support 4GB +memories, this is not the case any more. + +This CL fixes this by again detecting such situations as statically OOB. +We do not expect to be able to allocate memories of size >2GB on such +systems. If this assumptions turns out to be wrong, we will erroneously +trap. If that happens, we will have to explicitly disallow memories of +such size on 32-bit systems. + +(cherry picked from commit 7ad5b961553d7d9bc30da1bb839726be2b92bb51) + +Bug: v8:7881, chromium:1201340 +Change-Id: Ib3d32b8d303eb047eb7811a045a8fa2b4ecb8cda +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2853596 + +diff --git a/src/wasm/baseline/arm/liftoff-assembler-arm.h b/src/wasm/baseline/arm/liftoff-assembler-arm.h +index 9379a3b78a2fc93f3558f58790f63b6bac7b6d1b..c6b4cc1276ccdc60314a0e6eb839d325eeea7ebf 100644 +--- a/src/wasm/baseline/arm/liftoff-assembler-arm.h ++++ b/src/wasm/baseline/arm/liftoff-assembler-arm.h +@@ -689,13 +689,8 @@ void LiftoffAssembler::Load(LiftoffRegister dst, Register src_addr, + Register offset_reg, uint32_t offset_imm, + LoadType type, LiftoffRegList pinned, + uint32_t* protected_load_pc, bool is_load_mem) { +- // If offset_imm cannot be converted to int32 safely, we abort as a separate +- // check should cause this code to never be executed. +- // TODO(7881): Support when >2GB is required. +- if (!is_uint31(offset_imm)) { +- TurboAssembler::Abort(AbortReason::kOffsetOutOfRange); +- return; +- } ++ // Offsets >=2GB are statically OOB on 32-bit systems. ++ DCHECK_LE(offset_imm, std::numeric_limits::max()); + liftoff::LoadInternal(this, dst, src_addr, offset_reg, + static_cast(offset_imm), type, pinned, + protected_load_pc, is_load_mem); +@@ -705,13 +700,8 @@ void LiftoffAssembler::Store(Register dst_addr, Register offset_reg, + uint32_t offset_imm, LiftoffRegister src, + StoreType type, LiftoffRegList pinned, + uint32_t* protected_store_pc, bool is_store_mem) { +- // If offset_imm cannot be converted to int32 safely, we abort as a separate +- // check should cause this code to never be executed. +- // TODO(7881): Support when >2GB is required. +- if (!is_uint31(offset_imm)) { +- TurboAssembler::Abort(AbortReason::kOffsetOutOfRange); +- return; +- } ++ // Offsets >=2GB are statically OOB on 32-bit systems. ++ DCHECK_LE(offset_imm, std::numeric_limits::max()); + UseScratchRegisterScope temps(this); + if (type.value() == StoreType::kF64Store) { + Register actual_dst_addr = liftoff::CalculateActualAddress( +diff --git a/src/wasm/baseline/ia32/liftoff-assembler-ia32.h b/src/wasm/baseline/ia32/liftoff-assembler-ia32.h +index 9bfad9313b9aa06ccee4dc50868b27007bb94fec..9005fe4303adb0cf20a23eb2f70f084bc3b08413 100644 +--- a/src/wasm/baseline/ia32/liftoff-assembler-ia32.h ++++ b/src/wasm/baseline/ia32/liftoff-assembler-ia32.h +@@ -324,13 +324,8 @@ void LiftoffAssembler::Load(LiftoffRegister dst, Register src_addr, + Register offset_reg, uint32_t offset_imm, + LoadType type, LiftoffRegList pinned, + uint32_t* protected_load_pc, bool is_load_mem) { +- if (offset_imm > static_cast(std::numeric_limits::max())) { +- // We do not generate code here, because such an offset should never pass +- // the bounds check. However, the spec requires us to compile code with such +- // an offset. +- Trap(); +- return; +- } ++ // Offsets >=2GB are statically OOB on 32-bit systems. ++ DCHECK_LE(offset_imm, std::numeric_limits::max()); + DCHECK_EQ(type.value_type() == kWasmI64, dst.is_gp_pair()); + Operand src_op = offset_reg == no_reg + ? Operand(src_addr, offset_imm) +@@ -406,6 +401,7 @@ void LiftoffAssembler::Store(Register dst_addr, Register offset_reg, + StoreType type, LiftoffRegList pinned, + uint32_t* protected_store_pc, bool is_store_mem) { + DCHECK_EQ(type.value_type() == kWasmI64, src.is_gp_pair()); ++ // Offsets >=2GB are statically OOB on 32-bit systems. + DCHECK_LE(offset_imm, std::numeric_limits::max()); + Operand dst_op = offset_reg == no_reg + ? Operand(dst_addr, offset_imm) +diff --git a/src/wasm/baseline/liftoff-compiler.cc b/src/wasm/baseline/liftoff-compiler.cc +index c9625b06d8a46ee9aa632142cf9491f0e4c96bd4..8103f5b7c14f8e87ae0e175ef7bfffd25d490539 100644 +--- a/src/wasm/baseline/liftoff-compiler.cc ++++ b/src/wasm/baseline/liftoff-compiler.cc +@@ -2100,10 +2100,7 @@ class LiftoffCompiler { + bool BoundsCheckMem(FullDecoder* decoder, uint32_t access_size, + uint64_t offset, Register index, LiftoffRegList pinned, + ForceCheck force_check) { +- // If the offset does not fit in a uintptr_t, this can never succeed on this +- // machine. + const bool statically_oob = +- offset > std::numeric_limits::max() || + !base::IsInBounds(offset, access_size, + env_->max_memory_size); + +diff --git a/src/wasm/compilation-environment.h b/src/wasm/compilation-environment.h +index d730161ad1f9d0590bc1302093e3fea48b8d230f..fc9b2fcbc2e07434b14f0ccb1e37b12550f6c9e6 100644 +--- a/src/wasm/compilation-environment.h ++++ b/src/wasm/compilation-environment.h +@@ -63,9 +63,11 @@ struct CompilationEnv { + + const LowerSimd lower_simd; + +- static constexpr uint32_t kMaxMemoryPagesAtRuntime = +- std::min(kV8MaxWasmMemoryPages, +- std::numeric_limits::max() / kWasmPageSize); ++ // We assume that memories of size >= half of the virtual address space ++ // cannot be allocated (see https://crbug.com/1201340). ++ static constexpr uint32_t kMaxMemoryPagesAtRuntime = std::min( ++ kV8MaxWasmMemoryPages, ++ (uintptr_t{1} << (kSystemPointerSize == 4 ? 31 : 63)) / kWasmPageSize); + + constexpr CompilationEnv(const WasmModule* module, + UseTrapHandler use_trap_handler, diff --git a/patches/v8/merged_wasm-simd_ia32_fix_f64x2_min_max_to_use_registers.patch b/patches/v8/merged_wasm-simd_ia32_fix_f64x2_min_max_to_use_registers.patch new file mode 100644 index 0000000000000..c51c138c7383b --- /dev/null +++ b/patches/v8/merged_wasm-simd_ia32_fix_f64x2_min_max_to_use_registers.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrey Belenko +Date: Tue, 18 May 2021 17:59:17 +0200 +Subject: Merged: [wasm-simd][ia32] Fix f64x2 min max to use registers + +We don't have memory alignment yet, so using memory operands will cause +segv if we try to access the unaligned operands (on non-AVX systems). + +The fix here is kept simple (the logic can be cleaned up a bit and +optimized to not use unique registers), in order to keep the cherry-pick +and back-merge as small and safe as possible. + +(cherry picked from commit 7f2d41fa3748ecc8fc888d93f82d77718b1dd6b0) + +Bug: chromium:1204071 +Change-Id: I7d7d177ff096ebd3de399fcf1ec7d9ac57bbb80b +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2872565 + +diff --git a/src/compiler/backend/ia32/instruction-selector-ia32.cc b/src/compiler/backend/ia32/instruction-selector-ia32.cc +index fec4053871bd14ac0f732e41e1b03eaa64a8c5cb..8a1d32e7f8096679fb265a6b7b4d84696288b8b4 100644 +--- a/src/compiler/backend/ia32/instruction-selector-ia32.cc ++++ b/src/compiler/backend/ia32/instruction-selector-ia32.cc +@@ -2199,7 +2199,7 @@ void InstructionSelector::VisitF64x2Min(Node* node) { + IA32OperandGenerator g(this); + InstructionOperand temps[] = {g.TempSimd128Register()}; + InstructionOperand operand0 = g.UseUniqueRegister(node->InputAt(0)); +- InstructionOperand operand1 = g.UseUnique(node->InputAt(1)); ++ InstructionOperand operand1 = g.UseUniqueRegister(node->InputAt(1)); + + if (IsSupported(AVX)) { + Emit(kIA32F64x2Min, g.DefineAsRegister(node), operand0, operand1, +@@ -2214,7 +2214,7 @@ void InstructionSelector::VisitF64x2Max(Node* node) { + IA32OperandGenerator g(this); + InstructionOperand temps[] = {g.TempSimd128Register()}; + InstructionOperand operand0 = g.UseUniqueRegister(node->InputAt(0)); +- InstructionOperand operand1 = g.UseUnique(node->InputAt(1)); ++ InstructionOperand operand1 = g.UseUniqueRegister(node->InputAt(1)); + if (IsSupported(AVX)) { + Emit(kIA32F64x2Max, g.DefineAsRegister(node), operand0, operand1, + arraysize(temps), temps); diff --git a/patches/v8/reland_compiler_fix_more_truncation_bugs_in_simplifiedlowering.patch b/patches/v8/reland_compiler_fix_more_truncation_bugs_in_simplifiedlowering.patch new file mode 100644 index 0000000000000..d5e9aee7e48a5 --- /dev/null +++ b/patches/v8/reland_compiler_fix_more_truncation_bugs_in_simplifiedlowering.patch @@ -0,0 +1,138 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrey Belenko +Date: Tue, 18 May 2021 21:52:40 +0200 +Subject: Reland "[compiler] Fix more truncation bugs in SimplifiedLowering" + +This is a reland of 47077d94492cb604e3a7f02c0d7c3c495ff6b713 without +changes. The revert was false alarm. + +Original change's description: +> [compiler] Fix more truncation bugs in SimplifiedLowering +> +> Bug: chromium:1200490 +> Change-Id: I3555b6d99bdb4b4e7c302a43a82c17e8bff84ebe +> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2840452 + +Bug: chromium:1200490 +Change-Id: I75cac59050bc393d157a1ee5bed776c8986a7bbe +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2843817 + +diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc +index c2f0d744c2fb698427dd876fb9a37eb280e6f583..6ed92e855c66a266e1909925caed0140a5c59a67 100644 +--- a/src/compiler/simplified-lowering.cc ++++ b/src/compiler/simplified-lowering.cc +@@ -1398,17 +1398,32 @@ class RepresentationSelector { + return jsgraph_->simplified(); + } + +- void LowerToCheckedInt32Mul(Node* node, Truncation truncation, +- Type input0_type, Type input1_type) { +- // If one of the inputs is positive and/or truncation is being applied, +- // there is no need to return -0. +- CheckForMinusZeroMode mz_mode = +- truncation.IdentifiesZeroAndMinusZero() || +- IsSomePositiveOrderedNumber(input0_type) || +- IsSomePositiveOrderedNumber(input1_type) +- ? CheckForMinusZeroMode::kDontCheckForMinusZero +- : CheckForMinusZeroMode::kCheckForMinusZero; +- NodeProperties::ChangeOp(node, simplified()->CheckedInt32Mul(mz_mode)); ++ template ++ void VisitForCheckedInt32Mul(Node* node, Truncation truncation, ++ Type input0_type, Type input1_type, ++ UseInfo input_use) { ++ DCHECK_EQ(node->opcode(), IrOpcode::kSpeculativeNumberMultiply); ++ // A -0 input is impossible or will cause a deopt. ++ DCHECK(BothInputsAre(node, Type::Signed32()) || ++ !input_use.truncation().IdentifiesZeroAndMinusZero()); ++ ++ CheckForMinusZeroMode mz_mode; ++ Type restriction; ++ if (IsSomePositiveOrderedNumber(input0_type) || ++ IsSomePositiveOrderedNumber(input1_type)) { ++ mz_mode = CheckForMinusZeroMode::kDontCheckForMinusZero; ++ restriction = Type::Signed32(); ++ } else if (truncation.IdentifiesZeroAndMinusZero()) { ++ mz_mode = CheckForMinusZeroMode::kDontCheckForMinusZero; ++ restriction = Type::Signed32OrMinusZero(); ++ } else { ++ mz_mode = CheckForMinusZeroMode::kCheckForMinusZero; ++ restriction = Type::Signed32(); ++ } ++ ++ VisitBinop(node, input_use, MachineRepresentation::kWord32, restriction); ++ if (lower()) ++ NodeProperties::ChangeOp(node, simplified()->CheckedInt32Mul(mz_mode)); + } + + void ChangeToInt32OverflowOp(Node* node) { +@@ -1600,12 +1615,22 @@ class RepresentationSelector { + VisitBinop(node, lhs_use, rhs_use, MachineRepresentation::kWord32); + if (lower()) DeferReplacement(node, lowering->Int32Mod(node)); + } else if (BothInputsAre(node, Type::Unsigned32OrMinusZeroOrNaN())) { ++ Type const restriction = ++ truncation.IdentifiesZeroAndMinusZero() && ++ TypeOf(node->InputAt(0)).Maybe(Type::MinusZero()) ++ ? Type::Unsigned32OrMinusZero() ++ : Type::Unsigned32(); + VisitBinop(node, lhs_use, rhs_use, MachineRepresentation::kWord32, +- Type::Unsigned32()); ++ restriction); + if (lower()) ChangeToUint32OverflowOp(node); + } else { ++ Type const restriction = ++ truncation.IdentifiesZeroAndMinusZero() && ++ TypeOf(node->InputAt(0)).Maybe(Type::MinusZero()) ++ ? Type::Signed32OrMinusZero() ++ : Type::Signed32(); + VisitBinop(node, lhs_use, rhs_use, MachineRepresentation::kWord32, +- Type::Signed32()); ++ restriction); + if (lower()) ChangeToInt32OverflowOp(node); + } + return; +@@ -2165,23 +2190,18 @@ class RepresentationSelector { + // If both inputs and feedback are int32, use the overflow op. + if (hint == NumberOperationHint::kSignedSmall || + hint == NumberOperationHint::kSigned32) { +- VisitBinop(node, UseInfo::TruncatingWord32(), +- MachineRepresentation::kWord32, Type::Signed32()); +- if (lower()) { +- LowerToCheckedInt32Mul(node, truncation, input0_type, +- input1_type); +- } ++ VisitForCheckedInt32Mul(node, truncation, input0_type, ++ input1_type, ++ UseInfo::TruncatingWord32()); + return; + } + } + + if (hint == NumberOperationHint::kSignedSmall || + hint == NumberOperationHint::kSigned32) { +- VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint), +- MachineRepresentation::kWord32, Type::Signed32()); +- if (lower()) { +- LowerToCheckedInt32Mul(node, truncation, input0_type, input1_type); +- } ++ VisitForCheckedInt32Mul(node, truncation, input0_type, ++ input1_type, ++ CheckedUseInfoAsWord32FromHint(hint)); + return; + } + +@@ -3901,7 +3921,6 @@ template <> + void RepresentationSelector::SetOutput( + Node* node, MachineRepresentation representation, Type restriction_type) { + NodeInfo* const info = GetInfo(node); +- DCHECK(info->restriction_type().Is(restriction_type)); + DCHECK(restriction_type.Is(info->restriction_type())); + info->set_output(representation); + } +@@ -3911,7 +3930,6 @@ void RepresentationSelector::SetOutput( + Node* node, MachineRepresentation representation, Type restriction_type) { + NodeInfo* const info = GetInfo(node); + DCHECK_EQ(info->representation(), representation); +- DCHECK(info->restriction_type().Is(restriction_type)); + DCHECK(restriction_type.Is(info->restriction_type())); + USE(info); + } diff --git a/script/lib/utils.js b/script/lib/utils.js index a0c869530d083..55f678b43ed1c 100644 --- a/script/lib/utils.js +++ b/script/lib/utils.js @@ -6,6 +6,9 @@ const ELECTRON_DIR = path.resolve(__dirname, '..', '..'); const SRC_DIR = path.resolve(ELECTRON_DIR, '..'); const RELEASE_BRANCH_PATTERN = /(\d)+-(?:(?:[0-9]+-x$)|(?:x+-y$))/; +// TODO(main-migration): Simplify once main branch is renamed +const MAIN_BRANCH_PATTERN = /^(main|master)$/; +const ORIGIN_MAIN_BRANCH_PATTERN = /^origin\/(main|master)$/; require('colors'); const pass = '✓'.green; @@ -73,7 +76,7 @@ async function handleGitCall (args, gitDir) { async function getCurrentBranch (gitDir) { let branch = await handleGitCall(['rev-parse', '--abbrev-ref', 'HEAD'], gitDir); - if (branch !== 'master' && !RELEASE_BRANCH_PATTERN.test(branch)) { + if (!MAIN_BRANCH_PATTERN.test(branch) && !RELEASE_BRANCH_PATTERN.test(branch)) { const lastCommit = await handleGitCall(['rev-parse', 'HEAD'], gitDir); const branches = (await handleGitCall([ 'branch', @@ -82,7 +85,7 @@ async function getCurrentBranch (gitDir) { '--remote' ], gitDir)).split('\n'); - branch = branches.filter(b => b.trim() === 'master' || b.trim() === 'origin/master' || RELEASE_BRANCH_PATTERN.test(b.trim()))[0]; + branch = branches.find(b => MAIN_BRANCH_PATTERN.test(b.trim()) || ORIGIN_MAIN_BRANCH_PATTERN.test(b.trim()) || RELEASE_BRANCH_PATTERN.test(b.trim())); if (!branch) { console.log(`${fail} no release branch exists for this ref`); process.exit(1); diff --git a/script/release/ci-release-build.js b/script/release/ci-release-build.js index 6b57ce215ac36..2c7a57996e7f5 100644 --- a/script/release/ci-release-build.js +++ b/script/release/ci-release-build.js @@ -230,6 +230,7 @@ async function callAppVeyor (targetBranch, job, options) { accountName: 'electron-bot', projectSlug: appVeyorJobs[job], branch: targetBranch, + commitId: options.commit || undefined, environmentVariables }), method: 'POST' @@ -365,7 +366,7 @@ if (require.main === module) { if (args._.length < 1) { console.log(`Trigger CI to build release builds of electron. Usage: ci-release-build.js [--job=CI_JOB_NAME] [--ci=CircleCI|AppVeyor|VSTS|DevOps] - [--ghRelease] [--armTest] [--circleBuildNum=xxx] [--appveyorJobId=xxx] TARGET_BRANCH + [--ghRelease] [--armTest] [--circleBuildNum=xxx] [--appveyorJobId=xxx] [--commit=sha] TARGET_BRANCH `); process.exit(0); } diff --git a/script/release/notes/index.js b/script/release/notes/index.js index 8cb7650fae1a6..644b76490fe79 100755 --- a/script/release/notes/index.js +++ b/script/release/notes/index.js @@ -8,6 +8,11 @@ const semver = require('semver'); const { ELECTRON_DIR } = require('../../lib/utils'); const notesGenerator = require('./notes.js'); +const { Octokit } = require('@octokit/rest'); +const octokit = new Octokit({ + auth: process.env.ELECTRON_GITHUB_TOKEN +}); + const semverify = version => version.replace(/^origin\//, '').replace(/[xy]/g, '0').replace(/-/g, '.'); const runGit = async (args) => { @@ -37,13 +42,17 @@ const getTagsOf = async (point) => { }; const getTagsOnBranch = async (point) => { - const masterTags = await getTagsOf('master'); - if (point === 'master') { - return masterTags; + const { data: { default_branch: defaultBranch } } = await octokit.repos.get({ + owner: 'electron', + repo: 'electron' + }); + const mainTags = await getTagsOf(defaultBranch); + if (point === defaultBranch) { + return mainTags; } - const masterTagsSet = new Set(masterTags); - return (await getTagsOf(point)).filter(tag => !masterTagsSet.has(tag)); + const mainTagsSet = new Set(mainTags); + return (await getTagsOf(point)).filter(tag => !mainTagsSet.has(tag)); }; const getBranchOf = async (point) => { @@ -66,7 +75,8 @@ const getAllBranches = async () => { return branches.split('\n') .map(branch => branch.trim()) .filter(branch => !!branch) - .filter(branch => branch !== 'origin/HEAD -> origin/master') + // TODO(main-migration): Simplify once branch rename is complete. + .filter(branch => branch !== 'origin/HEAD -> origin/master' && branch !== 'origin/HEAD -> origin/main') .sort(); } catch (err) { console.error('Failed to fetch all branches'); diff --git a/script/release/prepare-release.js b/script/release/prepare-release.js index bda57bdebc945..0a6309e85f000 100755 --- a/script/release/prepare-release.js +++ b/script/release/prepare-release.js @@ -112,7 +112,7 @@ async function createRelease (branchToTarget, isBeta) { name: `electron ${newVersion}`, body: releaseBody, prerelease: releaseIsPrelease, - target_commitish: newVersion.indexOf('nightly') !== -1 ? 'master' : branchToTarget + target_commitish: newVersion.indexOf('nightly') !== -1 ? 'main' : branchToTarget }).catch(err => { console.log(`${fail} Error creating new release: `, err); process.exit(1); @@ -181,7 +181,7 @@ async function promptForVersion (version) { }); } -// function to determine if there have been commits to master since the last release +// function to determine if there have been commits to main since the last release async function changesToRelease () { const lastCommitWasRelease = new RegExp('^Bump v[0-9.]*(-beta[0-9.]*)?(-nightly[0-9.]*)?$', 'g'); const lastCommit = await GitProcess.exec(['log', '-n', '1', '--pretty=format:\'%s\''], ELECTRON_DIR); diff --git a/script/release/publish-to-npm.js b/script/release/publish-to-npm.js index 54554fe144697..61cdffe380daf 100644 --- a/script/release/publish-to-npm.js +++ b/script/release/publish-to-npm.js @@ -111,8 +111,9 @@ new Promise((resolve, reject) => { const currentBranch = await getCurrentBranch(); if (release.tag_name.indexOf('nightly') > 0) { - if (currentBranch === 'master') { - // Nightlies get published to their own module, so master nightlies should be tagged as latest + // 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 npmTag = 'latest'; } else { npmTag = `nightly-${currentBranch}`; @@ -127,10 +128,10 @@ new Promise((resolve, reject) => { JSON.stringify(currentJson, null, 2) ); } else { - if (currentBranch === 'master') { - // This should never happen, master releases should be nightly releases + if (currentBranch === 'master' || currentBranch === 'main') { + // This should never happen, main releases should be nightly releases // this is here just-in-case - npmTag = 'master'; + throw new Error('Unreachable release phase, can\'t tag a non-nightly release on the main branch'); } else if (!release.prerelease) { // Tag the release with a `2-0-x` style tag npmTag = currentBranch; diff --git a/script/release/release-artifact-cleanup.js b/script/release/release-artifact-cleanup.js index d129207f3fef0..e849ca149f186 100755 --- a/script/release/release-artifact-cleanup.js +++ b/script/release/release-artifact-cleanup.js @@ -27,6 +27,7 @@ function getLastBumpCommit (tag) { 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) { diff --git a/script/release/version-utils.js b/script/release/version-utils.js index 58a70c0097150..68974f49ee4eb 100644 --- a/script/release/version-utils.js +++ b/script/release/version-utils.js @@ -65,8 +65,9 @@ async function nextNightly (v) { const pre = `nightly.${getCurrentDate()}`; const branch = (await GitProcess.exec(['rev-parse', '--abbrev-ref', 'HEAD'], ELECTRON_DIR)).stdout.trim(); - if (branch === 'master') { - next = semver.inc(await getLastMajorForMaster(), 'major'); + // TODO(main-migration): Simplify once main branch is renamed + if (branch === 'master' || branch === 'main') { + next = semver.inc(await getLastMajorForMain(), 'major'); } else if (isStable(v)) { next = semver.inc(next, 'patch'); } @@ -74,7 +75,7 @@ async function nextNightly (v) { return `${next}-${pre}`; } -async function getLastMajorForMaster () { +async function getLastMajorForMain () { let branchNames; const result = await GitProcess.exec(['branch', '-a', '--remote', '--list', 'origin/[0-9]*-x-y'], ELECTRON_DIR); if (result.exitCode === 0) { diff --git a/shell/browser/native_window_mac.mm b/shell/browser/native_window_mac.mm index 4924beedb2c88..945a016ee4e9c 100644 --- a/shell/browser/native_window_mac.mm +++ b/shell/browser/native_window_mac.mm @@ -1580,7 +1580,12 @@ void ViewDidMoveToSuperview(NSView* self, SEL _cmd) { // Make frameless Vibrant windows have rounded corners. if (!has_frame() && !is_modal()) { - CGFloat radius = 5.0f; // default corner radius + CGFloat radius; + if (@available(macOS 11.0, *)) { + radius = 9.0f; + } else { + radius = 5.0f; // smaller corner radius on older versions + } CGFloat dimension = 2 * radius + 1; NSSize size = NSMakeSize(dimension, dimension); NSImage* maskImage = [NSImage imageWithSize:size diff --git a/shell/browser/native_window_views.cc b/shell/browser/native_window_views.cc index 5c23bc65575ad..ad963cc8fd9fb 100644 --- a/shell/browser/native_window_views.cc +++ b/shell/browser/native_window_views.cc @@ -72,19 +72,7 @@ namespace electron { -namespace { - #if defined(OS_WIN) -const LPCWSTR kUniqueTaskBarClassName = L"Shell_TrayWnd"; - -void FlipWindowStyle(HWND handle, bool on, DWORD flag) { - DWORD style = ::GetWindowLong(handle, GWL_STYLE); - if (on) - style |= flag; - else - style &= ~flag; - ::SetWindowLong(handle, GWL_STYLE, style); -} // Similar to the ones in display::win::ScreenWin, but with rounded values // These help to avoid problems that arise from unresizable windows where the @@ -98,6 +86,22 @@ gfx::Rect ScreenToDIPRect(HWND hwnd, const gfx::Rect& pixel_bounds) { return dip_rect; } +#endif + +namespace { + +#if defined(OS_WIN) +const LPCWSTR kUniqueTaskBarClassName = L"Shell_TrayWnd"; + +void FlipWindowStyle(HWND handle, bool on, DWORD flag) { + DWORD style = ::GetWindowLong(handle, GWL_STYLE); + if (on) + style |= flag; + else + style &= ~flag; + ::SetWindowLong(handle, GWL_STYLE, style); +} + gfx::Rect DIPToScreenRect(HWND hwnd, const gfx::Rect& pixel_bounds) { float scale_factor = display::win::ScreenWin::GetScaleFactorForHWND(hwnd); gfx::Rect screen_rect = ScaleToRoundedRect(pixel_bounds, scale_factor); diff --git a/shell/browser/native_window_views.h b/shell/browser/native_window_views.h index c2491d07e18e4..085a8b7768815 100644 --- a/shell/browser/native_window_views.h +++ b/shell/browser/native_window_views.h @@ -35,6 +35,10 @@ class WindowStateWatcher; class EventDisabler; #endif +#if defined(OS_WIN) +gfx::Rect ScreenToDIPRect(HWND hwnd, const gfx::Rect& pixel_bounds); +#endif + class NativeWindowViews : public NativeWindow, public views::WidgetObserver, public ui::EventHandler { diff --git a/shell/browser/native_window_views_win.cc b/shell/browser/native_window_views_win.cc index 0ff2b7ad14af4..13e369c716c25 100644 --- a/shell/browser/native_window_views_win.cc +++ b/shell/browser/native_window_views_win.cc @@ -260,11 +260,12 @@ bool NativeWindowViews::PreHandleMSG(UINT message, case WM_SIZING: { is_resizing_ = true; bool prevent_default = false; - NotifyWindowWillResize(gfx::Rect(*reinterpret_cast(l_param)), - &prevent_default); + gfx::Rect bounds = gfx::Rect(*reinterpret_cast(l_param)); + HWND hwnd = GetAcceleratedWidget(); + gfx::Rect dpi_bounds = ScreenToDIPRect(hwnd, bounds); + NotifyWindowWillResize(dpi_bounds, &prevent_default); if (prevent_default) { - ::GetWindowRect(GetAcceleratedWidget(), - reinterpret_cast(l_param)); + ::GetWindowRect(hwnd, reinterpret_cast(l_param)); return true; // Tells Windows that the Sizing is handled. } return false; @@ -288,11 +289,12 @@ bool NativeWindowViews::PreHandleMSG(UINT message, case WM_MOVING: { is_moving_ = true; bool prevent_default = false; - NotifyWindowWillMove(gfx::Rect(*reinterpret_cast(l_param)), - &prevent_default); + gfx::Rect bounds = gfx::Rect(*reinterpret_cast(l_param)); + HWND hwnd = GetAcceleratedWidget(); + gfx::Rect dpi_bounds = ScreenToDIPRect(hwnd, bounds); + NotifyWindowWillMove(dpi_bounds, &prevent_default); if (!movable_ || prevent_default) { - ::GetWindowRect(GetAcceleratedWidget(), - reinterpret_cast(l_param)); + ::GetWindowRect(hwnd, reinterpret_cast(l_param)); return true; // Tells Windows that the Move is handled. If not true, // frameless windows can be moved using // -webkit-app-region: drag elements. diff --git a/shell/browser/net/url_pipe_loader.cc b/shell/browser/net/url_pipe_loader.cc index f928eaa77325e..2bf28c4886941 100644 --- a/shell/browser/net/url_pipe_loader.cc +++ b/shell/browser/net/url_pipe_loader.cc @@ -87,7 +87,7 @@ void URLPipeLoader::OnDataReceived(base::StringPiece string_piece, producer_->Write( std::make_unique( string_piece, mojo::StringDataSource::AsyncWritingMode:: - STRING_STAYS_VALID_UNTIL_COMPLETION), + STRING_MAY_BE_INVALIDATED_BEFORE_COMPLETION), base::BindOnce(&URLPipeLoader::OnWrite, weak_factory_.GetWeakPtr(), std::move(resume))); } diff --git a/shell/browser/resources/win/electron.rc b/shell/browser/resources/win/electron.rc index 0790928a9d3e4..546c900b10972 100644 --- a/shell/browser/resources/win/electron.rc +++ b/shell/browser/resources/win/electron.rc @@ -50,8 +50,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 11,4,6,0 - PRODUCTVERSION 11,4,6,0 + FILEVERSION 11,5,0,0 + PRODUCTVERSION 11,5,0,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -68,12 +68,12 @@ BEGIN BEGIN VALUE "CompanyName", "GitHub, Inc." VALUE "FileDescription", "Electron" - VALUE "FileVersion", "11.4.6" + VALUE "FileVersion", "11.5.0" VALUE "InternalName", "electron.exe" VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved." VALUE "OriginalFilename", "electron.exe" VALUE "ProductName", "Electron" - VALUE "ProductVersion", "11.4.6" + VALUE "ProductVersion", "11.5.0" VALUE "SquirrelAwareVersion", "1" END END diff --git a/shell/common/api/electron_api_native_image_win.cc b/shell/common/api/electron_api_native_image_win.cc index 4ae0c15103f6b..55c0ae75ef302 100644 --- a/shell/common/api/electron_api_native_image_win.cc +++ b/shell/common/api/electron_api_native_image_win.cc @@ -12,6 +12,7 @@ #include #include +#include "base/win/scoped_com_initializer.h" #include "shell/common/gin_converters/image_converter.h" #include "shell/common/gin_helper/promise.h" #include "shell/common/skia_util.h" @@ -26,6 +27,8 @@ v8::Local NativeImage::CreateThumbnailFromPath( v8::Isolate* isolate, const base::FilePath& path, const gfx::Size& size) { + base::win::ScopedCOMInitializer scoped_com_initializer; + gin_helper::Promise promise(isolate); v8::Local handle = promise.GetHandle(); HRESULT hr; diff --git a/shell/common/node_bindings.cc b/shell/common/node_bindings.cc index 856124463c7db..565b6945752ae 100644 --- a/shell/common/node_bindings.cc +++ b/shell/common/node_bindings.cc @@ -128,6 +128,10 @@ void stop_and_close_uv_loop(uv_loop_t* loop) { bool g_is_initialized = false; bool IsPackagedApp() { + auto env = base::Environment::Create(); + if (env->HasVar("ELECTRON_FORCE_IS_PACKAGED")) + return true; + base::FilePath exe_path; base::PathService::Get(base::FILE_EXE, &exe_path); base::FilePath::StringType base_name = diff --git a/spec-main/node-spec.ts b/spec-main/node-spec.ts index 84113ece8ca8a..8f11ec86503c2 100644 --- a/spec-main/node-spec.ts +++ b/spec-main/node-spec.ts @@ -132,6 +132,29 @@ describe('node feature', () => { child.stderr.on('data', listener); child.stdout.on('data', listener); }); + + it('does allow --require in non-packaged apps', async () => { + const appPath = path.join(fixtures, 'module', 'noop.js'); + const env = Object.assign({}, process.env, { + NODE_OPTIONS: `--require=${path.join(fixtures, 'module', 'fail.js')}` + }); + // App should exit with code 1. + const child = childProcess.spawn(process.execPath, [appPath], { env }); + const [code] = await emittedOnce(child, 'exit'); + expect(code).to.equal(1); + }); + + it('does not allow --require in packaged apps', async () => { + const appPath = path.join(fixtures, 'module', 'noop.js'); + const env = Object.assign({}, process.env, { + ELECTRON_FORCE_IS_PACKAGED: 'true', + NODE_OPTIONS: `--require=${path.join(fixtures, 'module', 'fail.js')}` + }); + // App should exit with code 0. + const child = childProcess.spawn(process.execPath, [appPath], { env }); + const [code] = await emittedOnce(child, 'exit'); + expect(code).to.equal(0); + }); }); describe('Node.js cli flags', () => { diff --git a/spec-main/security-warnings-spec.ts b/spec-main/security-warnings-spec.ts index 217cb916262c0..88bb8f9510e3a 100644 --- a/spec-main/security-warnings-spec.ts +++ b/spec-main/security-warnings-spec.ts @@ -228,7 +228,7 @@ describe('security warnings', () => { it('should warn about enabled remote module with remote content', async () => { w = new BrowserWindow({ show: false, - webPreferences + webPreferences: { ...webPreferences, enableRemoteModule: true } }); w.loadURL(`${serverUrl}/base-page-security.html`); @@ -239,7 +239,7 @@ describe('security warnings', () => { it('should not warn about enabled remote module with remote content from localhost', async () => { w = new BrowserWindow({ show: false, - webPreferences + webPreferences: { ...webPreferences, enableRemoteModule: true } }); w.loadURL(`${serverUrl}/base-page-security-onload-message.html`); const [,, message] = await emittedUntil(w.webContents, 'console-message', isLoaded); diff --git a/spec-main/version-bump-spec.ts b/spec-main/version-bump-spec.ts index aff7cd28b53f6..247f960b06f36 100644 --- a/spec-main/version-bump-spec.ts +++ b/spec-main/version-bump-spec.ts @@ -43,7 +43,7 @@ describe('version-bumper', () => { // 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 === 'arm') && process.platform !== 'darwin')('nextVersion', () => { + ifdescribe(!(process.platform === 'linux' && process.arch.indexOf('arm') === 0) && process.platform !== 'darwin')('nextVersion', () => { const nightlyPattern = /[0-9.]*(-nightly.(\d{4})(\d{2})(\d{2}))$/g; const betaPattern = /[0-9.]*(-beta[0-9.]*)/g; diff --git a/spec-main/webview-spec.ts b/spec-main/webview-spec.ts index f9199793c65e7..97142ddf19023 100644 --- a/spec-main/webview-spec.ts +++ b/spec-main/webview-spec.ts @@ -687,6 +687,26 @@ describe(' tag', function () { describe('DOM events', () => { afterEach(closeAllWindows); + it('receives extra properties on DOM events when contextIsolation is enabled', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { + webviewTag: true, + contextIsolation: true + } + }); + await w.loadURL('about:blank'); + const message = await w.webContents.executeJavaScript(`new Promise((resolve, reject) => { + const webview = new WebView() + webview.setAttribute('src', 'data:text/html,') + webview.addEventListener('console-message', (e) => { + resolve(e.message) + }) + document.body.appendChild(webview) + })`); + expect(message).to.equal('hi'); + }); + it('emits focus event when contextIsolation is enabled', async () => { const w = new BrowserWindow({ show: false, diff --git a/spec/fixtures/module/fail.js b/spec/fixtures/module/fail.js new file mode 100644 index 0000000000000..6cee2e1e79a14 --- /dev/null +++ b/spec/fixtures/module/fail.js @@ -0,0 +1 @@ +process.exit(1); diff --git a/typings/internal-electron.d.ts b/typings/internal-electron.d.ts index 4dbaaf2118e7a..9732b8cad7957 100644 --- a/typings/internal-electron.d.ts +++ b/typings/internal-electron.d.ts @@ -277,16 +277,6 @@ declare namespace ElectronInternal { allowGuestViewElementDefinition(window: Window, context: any): void; } - interface WebFrameResizeEvent extends Electron.Event { - newWidth: number; - newHeight: number; - } - - interface WebViewEvent extends Event { - url: string; - isMainFrame: boolean; - } - class WebViewElement extends HTMLElement { static observedAttributes: Array; diff --git a/yarn.lock b/yarn.lock index 4d59a175c8f07..d38d6755e23c1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4963,7 +4963,7 @@ minimist@^1.2.0, minimist@^1.2.5: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== -minipass@^2.2.1, minipass@^2.3.5: +minipass@^2.2.1: version "2.3.5" resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA== @@ -4971,6 +4971,14 @@ minipass@^2.2.1, minipass@^2.3.5: safe-buffer "^5.1.2" yallist "^3.0.0" +minipass@^2.8.6: + version "2.9.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" + integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + minizlib@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" @@ -7739,13 +7747,13 @@ tar-stream@^1.1.2: xtend "^4.0.0" tar@^4, tar@^4.4.7: - version "4.4.10" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.10.tgz#946b2810b9a5e0b26140cf78bea6b0b0d689eba1" - integrity sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA== + version "4.4.15" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.15.tgz#3caced4f39ebd46ddda4d6203d48493a919697f8" + integrity sha512-ItbufpujXkry7bHH9NpQyTXPbJ72iTlXgkBAYsAjDXk3Ds8t/3NfO5P4xZGy7u+sYuQUbimgzswX4uQIEeNVOA== dependencies: chownr "^1.1.1" fs-minipass "^1.2.5" - minipass "^2.3.5" + minipass "^2.8.6" minizlib "^1.2.1" mkdirp "^0.5.0" safe-buffer "^5.1.2"