diff --git a/.circleci/config.yml b/.circleci/config.yml index de77de712d170..2c66a8be9e4d8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -268,6 +268,12 @@ step-depot-tools-get: &step-depot-tools-get name: Get depot tools command: | git clone --depth=1 https://chromium.googlesource.com/chromium/tools/depot_tools.git + # remove ninjalog_uploader_wrapper.py from autoninja since we don't use it and it causes problems + if [ "`uname`" == "Darwin" ]; then + sed -i '' '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja + else + sed -i '/ninjalog_uploader_wrapper.py/d' ./depot_tools/autoninja + fi step-depot-tools-add-to-path: &step-depot-tools-add-to-path run: diff --git a/BUILD.gn b/BUILD.gn index 28ad68664eb5a..b6d6260feb635 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -183,6 +183,12 @@ action("electron_js2c") { rebase_path(sources, root_build_dir) } +action("generate_config_gypi") { + outputs = [ "$root_gen_dir/config.gypi" ] + script = "script/generate-config-gypi.py" + args = rebase_path(outputs) + [ target_cpu ] +} + target_gen_default_app_js = "$target_gen_dir/js/default_app" typescript_build("default_app_js") { diff --git a/ELECTRON_VERSION b/ELECTRON_VERSION index a3598784423a6..8e31bc6653acf 100644 --- a/ELECTRON_VERSION +++ b/ELECTRON_VERSION @@ -1 +1 @@ -13.4.0 \ No newline at end of file +13.6.9 \ No newline at end of file diff --git a/chromium_src/BUILD.gn b/chromium_src/BUILD.gn index 42b71245719a7..efab0de19963a 100644 --- a/chromium_src/BUILD.gn +++ b/chromium_src/BUILD.gn @@ -66,8 +66,11 @@ static_library("chrome") { "//chrome/browser/extensions/global_shortcut_listener_win.cc", "//chrome/browser/extensions/global_shortcut_listener_win.h", "//chrome/browser/icon_loader_win.cc", + "//chrome/browser/ui/frame/window_frame_util.h", + "//chrome/browser/ui/view_ids.h", "//chrome/browser/win/chrome_process_finder.cc", "//chrome/browser/win/chrome_process_finder.h", + "//chrome/browser/win/titlebar_config.h", "//chrome/child/v8_crashpad_support_win.cc", "//chrome/child/v8_crashpad_support_win.h", ] @@ -347,17 +350,13 @@ source_set("plugins") { sources += [ "//chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc", "//chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h", + "//chrome/renderer/pepper/pepper_flash_font_file_host.cc", + "//chrome/renderer/pepper/pepper_flash_font_file_host.h", "//chrome/renderer/pepper/pepper_shared_memory_message_filter.cc", "//chrome/renderer/pepper/pepper_shared_memory_message_filter.h", ] if (enable_pdf_viewer) { - sources += [ - "//chrome/renderer/pepper/pepper_flash_font_file_host.cc", - "//chrome/renderer/pepper/pepper_flash_font_file_host.h", - ] - if (enable_pdf_viewer) { - deps += [ "//components/pdf/renderer" ] - } + deps += [ "//components/pdf/renderer" ] } deps += [ "//components/strings", diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index efb08e3539d60..72b550b9e814d 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -213,16 +213,13 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. * `followWindow` - The backdrop should automatically appear active when the window is active, and inactive when it is not. This is the default. * `active` - The backdrop should always appear active. * `inactive` - The backdrop should always appear inactive. - * `titleBarStyle` String (optional) - The style of window title bar. + * `titleBarStyle` String (optional) _macOS_ _Windows_ - The style of window title bar. Default is `default`. Possible values are: - * `default` - Results in the standard gray opaque Mac title - bar. - * `hidden` - Results in a hidden title bar and a full size content window, yet - the title bar still has the standard window controls ("traffic lights") in - the top left. - * `hiddenInset` - Results in a hidden title bar with an alternative look + * `default` - Results in the standard title bar for macOS or Windows respectively. + * `hidden` - Results in a hidden title bar and a full size content window. On macOS, the window still has the standard window controls (“traffic lights”) in the top left. On Windows, when combined with `titleBarOverlay: true` it will activate the Window Controls Overlay (see `titleBarOverlay` for more information), otherwise no window controls will be shown. + * `hiddenInset` - Only on macOS, results in a hidden title bar with an alternative look where the traffic light buttons are slightly more inset from the window edge. - * `customButtonsOnHover` - Results in a hidden title bar and a full size + * `customButtonsOnHover` - Only on macOS, results in a hidden title bar and a full size content window, the traffic light buttons will display when being hovered over in the top left of the window. **Note:** This option is currently experimental. @@ -403,6 +400,7 @@ It creates a new `BrowserWindow` with native properties as set by the `options`. contain the layout of the document—without requiring scrolling. Enabling this will cause the `preferred-size-changed` event to be emitted on the `WebContents` when the preferred size changes. Default is `false`. + * `titleBarOverlay` [OverlayOptions](structures/overlay-options.md) | Boolean (optional) - When using a frameless window in conjuction with `win.setWindowButtonVisibility(true)` on macOS or using a `titleBarStyle` so that the standard window controls ("traffic lights" on macOS) are visible, this property enables the Window Controls Overlay [JavaScript APIs][overlay-javascript-apis] and [CSS Environment Variables][overlay-css-env-vars]. Specifying `true` will result in an overlay with default system colors. Default is `false`. On Windows, the [OverlayOptions](structures/overlay-options.md) can be used instead of a boolean to specify colors for the overlay. When setting minimum or maximum window size with `minWidth`/`maxWidth`/ `minHeight`/`maxHeight`, it only constrains the users. It won't prevent you from @@ -985,7 +983,7 @@ the player itself we would call this function with arguments of 16/9 and are within the content view--only that they exist. Sum any extra width and height areas you have within the overall content view. -The aspect ratio is not respected when window is resized programmingly with +The aspect ratio is not respected when window is resized programmatically with APIs like `win.setSize`. #### `win.setBackgroundColor(backgroundColor)` @@ -1689,7 +1687,7 @@ current window into a top-level window. #### `win.getParentWindow()` -Returns `BrowserWindow` - The parent window. +Returns `BrowserWindow | null` - The parent window or `null` if there is no parent. #### `win.getChildWindows()` @@ -1809,3 +1807,5 @@ removed in future Electron releases. [window-levels]: https://developer.apple.com/documentation/appkit/nswindow/level [chrome-content-scripts]: https://developer.chrome.com/extensions/content_scripts#execution-environment [event-emitter]: https://nodejs.org/api/events.html#events_class_eventemitter +[overlay-javascript-apis]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#javascript-apis +[overlay-css-env-vars]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#css-environment-variables diff --git a/docs/api/frameless-window.md b/docs/api/frameless-window.md index 8bb253e1948c2..7f327904b36e7 100644 --- a/docs/api/frameless-window.md +++ b/docs/api/frameless-window.md @@ -18,17 +18,17 @@ const win = new BrowserWindow({ width: 800, height: 600, frame: false }) win.show() ``` -### Alternatives on macOS +### Alternatives -There's an alternative way to specify a chromeless window. +There's an alternative way to specify a chromeless window on macOS and Windows. Instead of setting `frame` to `false` which disables both the titlebar and window controls, you may want to have the title bar hidden and your content extend to the full window size, -yet still preserve the window controls ("traffic lights") for standard window actions. +yet still preserve the window controls ("traffic lights" on macOS) for standard window actions. You can do so by specifying the `titleBarStyle` option: #### `hidden` -Results in a hidden title bar and a full size content window, yet the title bar still has the standard window controls (“traffic lights”) in the top left. +Results in a hidden title bar and a full size content window. On macOS, the title bar still has the standard window controls (“traffic lights”) in the top left. ```javascript const { BrowserWindow } = require('electron') @@ -36,6 +36,8 @@ const win = new BrowserWindow({ titleBarStyle: 'hidden' }) win.show() ``` +### Alternatives on macOS + #### `hiddenInset` Results in a hidden title bar with an alternative look where the traffic light buttons are slightly more inset from the window edge. @@ -61,6 +63,35 @@ const win = new BrowserWindow({ titleBarStyle: 'customButtonsOnHover', frame: fa win.show() ``` +## Windows Control Overlay + +When using a frameless window in conjuction with `win.setWindowButtonVisibility(true)` on macOS, using one of the `titleBarStyle`s as described above so +that the traffic lights are visible, or using `titleBarStyle: hidden` on Windows, you can access the Window Controls Overlay [JavaScript APIs][overlay-javascript-apis] and +[CSS Environment Variables][overlay-css-env-vars] by setting the `titleBarOverlay` option to true. Specifying `true` will result in an overlay with default system colors. + +On Windows, you can also specify the color of the overlay and its symbols by setting `titleBarOverlay` to an object with the options `color` and `symbolColor`. If an option is not specified, the color will default to its system color for the window control buttons: + +```javascript +const { BrowserWindow } = require('electron') +const win = new BrowserWindow({ + titleBarStyle: 'hidden', + titleBarOverlay: true +}) +win.show() +``` + +```javascript +const { BrowserWindow } = require('electron') +const win = new BrowserWindow({ + titleBarStyle: 'hidden', + titleBarOverlay: { + color: '#2f3241', + symbolColor: '#74b1be' + } +}) +win.show() +``` + ## Transparent window By setting the `transparent` option to `true`, you can also make the frameless @@ -186,3 +217,5 @@ behave correctly on all platforms you should never use a custom context menu on draggable areas. [ignore-mouse-events]: browser-window.md#winsetignoremouseeventsignore-options +[overlay-javascript-apis]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#javascript-apis +[overlay-css-env-vars]: https://github.com/WICG/window-controls-overlay/blob/main/explainer.md#css-environment-variables diff --git a/docs/api/session.md b/docs/api/session.md index 6d7cc55ce69c3..002c37b9c7323 100644 --- a/docs/api/session.md +++ b/docs/api/session.md @@ -506,6 +506,7 @@ win.webContents.session.setCertificateVerifyProc((request, callback) => { * `permissionGranted` Boolean - Allow or deny the permission. * `details` Object - Some properties are only available on certain permission types. * `externalURL` String (optional) - The url of the `openExternal` request. + * `securityOrigin` String (optional) - The security origin of the `media` request. * `mediaTypes` String[] (optional) - The types of media access being requested, elements can be `video` or `audio` * `requestingUrl` String - The last URL the requesting frame loaded diff --git a/docs/api/structures/overlay-options.md b/docs/api/structures/overlay-options.md new file mode 100644 index 0000000000000..9e0e4815ea59c --- /dev/null +++ b/docs/api/structures/overlay-options.md @@ -0,0 +1,4 @@ +# OverlayOptions Object + +* `color` String (optional) _Windows_ - The CSS color of the Window Controls Overlay when enabled. Default is the system color. +* `symbolColor` String (optional) _Windows_ - The CSS color of the symbols on the Window Controls Overlay when enabled. Default is the system color. diff --git a/docs/api/web-contents.md b/docs/api/web-contents.md index 59ec589e82a8a..bbf41cadb379c 100644 --- a/docs/api/web-contents.md +++ b/docs/api/web-contents.md @@ -730,6 +730,8 @@ first available device will be selected. `callback` should be called with `deviceId` to be selected, passing empty string to `callback` will cancel the request. +If no event listener is added for this event, all bluetooth requests will be cancelled. + ```javascript const { app, BrowserWindow } = require('electron') diff --git a/docs/api/webview-tag.md b/docs/api/webview-tag.md index 75d6b3bc5d9cf..fa539ecaf5cc9 100644 --- a/docs/api/webview-tag.md +++ b/docs/api/webview-tag.md @@ -1004,3 +1004,78 @@ Emitted when DevTools is focused / opened. [runtime-enabled-features]: https://cs.chromium.org/chromium/src/third_party/blink/renderer/platform/runtime_enabled_features.json5?l=70 [chrome-webview]: https://developer.chrome.com/docs/extensions/reference/webviewTag/ + +### Event: 'context-menu' + +Returns: + +* `params` Object + * `x` Integer - x coordinate. + * `y` Integer - y coordinate. + * `linkURL` String - URL of the link that encloses the node the context menu + was invoked on. + * `linkText` String - Text associated with the link. May be an empty + string if the contents of the link are an image. + * `pageURL` String - URL of the top level page that the context menu was + invoked on. + * `frameURL` String - URL of the subframe that the context menu was invoked + on. + * `srcURL` String - Source URL for the element that the context menu + was invoked on. Elements with source URLs are images, audio and video. + * `mediaType` String - Type of the node the context menu was invoked on. Can + be `none`, `image`, `audio`, `video`, `canvas`, `file` or `plugin`. + * `hasImageContents` Boolean - Whether the context menu was invoked on an image + which has non-empty contents. + * `isEditable` Boolean - Whether the context is editable. + * `selectionText` String - Text of the selection that the context menu was + invoked on. + * `titleText` String - Title text of the selection that the context menu was + invoked on. + * `altText` String - Alt text of the selection that the context menu was + invoked on. + * `suggestedFilename` String - Suggested filename to be used when saving file through 'Save + Link As' option of context menu. + * `selectionRect` [Rectangle](structures/rectangle.md) - Rect representing the coordinates in the document space of the selection. + * `selectionStartOffset` Number - Start position of the selection text. + * `referrerPolicy` [Referrer](structures/referrer.md) - The referrer policy of the frame on which the menu is invoked. + * `misspelledWord` String - The misspelled word under the cursor, if any. + * `dictionarySuggestions` String[] - An array of suggested words to show the + user to replace the `misspelledWord`. Only available if there is a misspelled + word and spellchecker is enabled. + * `frameCharset` String - The character encoding of the frame on which the + menu was invoked. + * `inputFieldType` String - If the context menu was invoked on an input + field, the type of that field. Possible values are `none`, `plainText`, + `password`, `other`. + * `spellcheckEnabled` Boolean - If the context is editable, whether or not spellchecking is enabled. + * `menuSourceType` String - Input source that invoked the context menu. + Can be `none`, `mouse`, `keyboard`, `touch`, `touchMenu`, `longPress`, `longTap`, `touchHandle`, `stylus`, `adjustSelection`, or `adjustSelectionReset`. + * `mediaFlags` Object - The flags for the media element the context menu was + invoked on. + * `inError` Boolean - Whether the media element has crashed. + * `isPaused` Boolean - Whether the media element is paused. + * `isMuted` Boolean - Whether the media element is muted. + * `hasAudio` Boolean - Whether the media element has audio. + * `isLooping` Boolean - Whether the media element is looping. + * `isControlsVisible` Boolean - Whether the media element's controls are + visible. + * `canToggleControls` Boolean - Whether the media element's controls are + toggleable. + * `canPrint` Boolean - Whether the media element can be printed. + * `canSave` Boolean - Whether or not the media element can be downloaded. + * `canShowPictureInPicture` Boolean - Whether the media element can show picture-in-picture. + * `isShowingPictureInPicture` Boolean - Whether the media element is currently showing picture-in-picture. + * `canRotate` Boolean - Whether the media element can be rotated. + * `canLoop` Boolean - Whether the media element can be looped. + * `editFlags` Object - These flags indicate whether the renderer believes it + is able to perform the corresponding action. + * `canUndo` Boolean - Whether the renderer believes it can undo. + * `canRedo` Boolean - Whether the renderer believes it can redo. + * `canCut` Boolean - Whether the renderer believes it can cut. + * `canCopy` Boolean - Whether the renderer believes it can copy. + * `canPaste` Boolean - Whether the renderer believes it can paste. + * `canDelete` Boolean - Whether the renderer believes it can delete. + * `canSelectAll` Boolean - Whether the renderer believes it can select all. + * `canEditRichly` Boolean - Whether the renderer believes it can edit text richly. + +Emitted when there is a new context menu that needs to be handled. diff --git a/docs/development/debugging-instructions-macos.md b/docs/development/debugging-instructions-macos.md index d3af2d2a1a28f..e059ac5f972cd 100644 --- a/docs/development/debugging-instructions-macos.md +++ b/docs/development/debugging-instructions-macos.md @@ -26,7 +26,9 @@ you prefer a graphical interface. * **.lldbinit**: Create or edit `~/.lldbinit` to allow Chromium code to be properly source-mapped. ```text - command script import ~/electron/src/tools/lldb/lldbinit.py + # e.g: ['~/electron/src/tools/lldb'] + script sys.path[:0] = ['<...path/to/electron/src/tools/lldb>'] + script import lldbinit ``` ## Attaching to and Debugging Electron diff --git a/electron_strings.grdp b/electron_strings.grdp index b86aaf9d849cc..6fc83d90e5ea9 100644 --- a/electron_strings.grdp +++ b/electron_strings.grdp @@ -1,5 +1,19 @@ + + + Close + + + Minimize + + + Maximize + + + Restore + + Printing Service diff --git a/filenames.auto.gni b/filenames.auto.gni index 829a794466aa9..0bf902fd04f0a 100644 --- a/filenames.auto.gni +++ b/filenames.auto.gni @@ -101,6 +101,7 @@ auto_filenames = { "docs/api/structures/new-window-web-contents-event.md", "docs/api/structures/notification-action.md", "docs/api/structures/notification-response.md", + "docs/api/structures/overlay-options.md", "docs/api/structures/point.md", "docs/api/structures/post-body.md", "docs/api/structures/printer-info.md", diff --git a/filenames.gni b/filenames.gni index 3894978859e9b..271513816fda4 100644 --- a/filenames.gni +++ b/filenames.gni @@ -90,6 +90,10 @@ filenames = { "shell/browser/ui/views/electron_views_delegate_win.cc", "shell/browser/ui/views/win_frame_view.cc", "shell/browser/ui/views/win_frame_view.h", + "shell/browser/ui/views/win_caption_button.cc", + "shell/browser/ui/views/win_caption_button.h", + "shell/browser/ui/views/win_caption_button_container.cc", + "shell/browser/ui/views/win_caption_button_container.h", "shell/browser/ui/win/dialog_thread.cc", "shell/browser/ui/win/dialog_thread.h", "shell/browser/ui/win/electron_desktop_native_widget_aura.cc", diff --git a/lib/browser/api/web-contents.ts b/lib/browser/api/web-contents.ts index 71d5134e62aa1..a0f9bd04e8027 100644 --- a/lib/browser/api/web-contents.ts +++ b/lib/browser/api/web-contents.ts @@ -541,6 +541,9 @@ WebContents.prototype._init = function () { ipcMainInternal.emit(channel, event, ...args); } else { addReplyToEvent(event); + if (this.listenerCount('ipc-message-sync') === 0 && ipcMain.listenerCount(channel) === 0) { + console.warn(`WebContents #${this.id} called ipcRenderer.sendSync() with '${channel}' channel without listeners.`); + } this.emit('ipc-message-sync', event, channel, ...args); ipcMain.emit(channel, event, ...args); } @@ -678,6 +681,14 @@ WebContents.prototype._init = function () { } }); + this.on('select-bluetooth-device', (event, devices, callback) => { + if (this.listenerCount('select-bluetooth-device') === 1) { + // Cancel it if there are no handlers + event.preventDefault(); + callback(''); + } + }); + const event = process._linkedBinding('electron_browser_event').createEmpty(); app.emit('web-contents-created', event, this); diff --git a/lib/browser/api/web-frame-main.ts b/lib/browser/api/web-frame-main.ts index 1ef76aa6f847a..2f75ee615a697 100644 --- a/lib/browser/api/web-frame-main.ts +++ b/lib/browser/api/web-frame-main.ts @@ -7,7 +7,11 @@ WebFrameMain.prototype.send = function (channel, ...args) { throw new Error('Missing required channel argument'); } - return this._send(false /* internal */, channel, args); + try { + return this._send(false /* internal */, channel, args); + } catch (e) { + console.error('Error sending from webFrameMain: ', e); + } }; WebFrameMain.prototype._sendInternal = function (channel, ...args) { @@ -15,7 +19,11 @@ WebFrameMain.prototype._sendInternal = function (channel, ...args) { throw new Error('Missing required channel argument'); } - return this._send(true /* internal */, channel, args); + try { + return this._send(true /* internal */, channel, args); + } catch (e) { + console.error('Error sending from webFrameMain: ', e); + } }; WebFrameMain.prototype.postMessage = function (...args) { diff --git a/lib/browser/rpc-server.ts b/lib/browser/rpc-server.ts index 92adc3b83fc9f..e0022be98b65b 100644 --- a/lib/browser/rpc-server.ts +++ b/lib/browser/rpc-server.ts @@ -37,6 +37,10 @@ ipcMainInternal.handle(IPC_MESSAGES.BROWSER_GET_LAST_WEB_PREFERENCES, function ( return event.sender.getLastWebPreferences(); }); +ipcMainInternal.handle(IPC_MESSAGES.BROWSER_GET_PROCESS_MEMORY_INFO, function (event) { + return event.sender._getProcessMemoryInfo(); +}); + // Methods not listed in this set are called directly in the renderer process. const allowedClipboardMethods = (() => { switch (process.platform) { diff --git a/lib/common/ipc-messages.ts b/lib/common/ipc-messages.ts index a6c7a94a8f70a..2ec7a463a2c4b 100644 --- a/lib/common/ipc-messages.ts +++ b/lib/common/ipc-messages.ts @@ -4,6 +4,7 @@ export const enum IPC_MESSAGES { BROWSER_PRELOAD_ERROR = 'BROWSER_PRELOAD_ERROR', BROWSER_SANDBOX_LOAD = 'BROWSER_SANDBOX_LOAD', BROWSER_WINDOW_CLOSE = 'BROWSER_WINDOW_CLOSE', + BROWSER_GET_PROCESS_MEMORY_INFO = 'BROWSER_GET_PROCESS_MEMORY_INFO', GUEST_INSTANCE_VISIBILITY_CHANGE = 'GUEST_INSTANCE_VISIBILITY_CHANGE', diff --git a/lib/renderer/init.ts b/lib/renderer/init.ts index 3bb3c2d6eff7e..fa49fe94bfb86 100644 --- a/lib/renderer/init.ts +++ b/lib/renderer/init.ts @@ -1,5 +1,6 @@ import * as path from 'path'; import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages'; +import type * as ipcRendererInternalModule from '@electron/internal/renderer/ipc-renderer-internal'; const Module = require('module'); @@ -43,7 +44,7 @@ const v8Util = process._linkedBinding('electron_common_v8_util'); const contextId = v8Util.getHiddenValue(global, 'contextId'); Object.defineProperty(process, 'contextId', { enumerable: true, value: contextId }); -const { ipcRendererInternal } = require('@electron/internal/renderer/ipc-renderer-internal'); +const { ipcRendererInternal } = require('@electron/internal/renderer/ipc-renderer-internal') as typeof ipcRendererInternalModule; const ipcRenderer = require('@electron/internal/renderer/api/ipc-renderer').default; v8Util.setHiddenValue(global, 'ipcNative', { @@ -57,6 +58,10 @@ v8Util.setHiddenValue(global, 'ipcNative', { } }); +process.getProcessMemoryInfo = () => { + return ipcRendererInternal.invoke(IPC_MESSAGES.BROWSER_GET_PROCESS_MEMORY_INFO); +}; + // Use electron module after everything is ready. const { webFrameInit } = require('@electron/internal/renderer/web-frame-init'); webFrameInit(); diff --git a/lib/renderer/security-warnings.ts b/lib/renderer/security-warnings.ts index 4d3cf8ad5a0c4..50f0d85eecb14 100644 --- a/lib/renderer/security-warnings.ts +++ b/lib/renderer/security-warnings.ts @@ -104,10 +104,14 @@ const warnAboutInsecureResources = function () { return; } + const isLocal = (url: URL): boolean => + ['localhost', '127.0.0.1', '[::1]', ''].includes(url.hostname); + const isInsecure = (url: URL): boolean => + ['http:', 'ftp:'].includes(url.protocol) && !isLocal(url); + const resources = window.performance .getEntriesByType('resource') - .filter(({ name }) => /^(http|ftp):/gi.test(name || '')) - .filter(({ name }) => new URL(name).hostname !== 'localhost') + .filter(({ name }) => isInsecure(new URL(name))) .map(({ name }) => `- ${name}`) .join('\n'); diff --git a/lib/sandboxed_renderer/init.ts b/lib/sandboxed_renderer/init.ts index f82f0cbe00587..89224f939a2a8 100644 --- a/lib/sandboxed_renderer/init.ts +++ b/lib/sandboxed_renderer/init.ts @@ -2,6 +2,7 @@ /* global binding */ import * as events from 'events'; import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages'; +import type * as ipcRendererInternalModule from '@electron/internal/renderer/ipc-renderer-internal'; const { EventEmitter } = events; @@ -20,7 +21,7 @@ for (const prop of Object.keys(EventEmitter.prototype) as (keyof typeof process) } Object.setPrototypeOf(process, EventEmitter.prototype); -const { ipcRendererInternal } = require('@electron/internal/renderer/ipc-renderer-internal'); +const { ipcRendererInternal } = require('@electron/internal/renderer/ipc-renderer-internal') as typeof ipcRendererInternalModule; const ipcRendererUtils = require('@electron/internal/renderer/ipc-renderer-internal-utils'); const { preloadScripts, process: processProps } = ipcRendererUtils.invokeSync(IPC_MESSAGES.BROWSER_SANDBOX_LOAD); @@ -80,6 +81,10 @@ Object.assign(preloadProcess, processProps); Object.assign(process, binding.process); Object.assign(process, processProps); +process.getProcessMemoryInfo = preloadProcess.getProcessMemoryInfo = () => { + return ipcRendererInternal.invoke(IPC_MESSAGES.BROWSER_GET_PROCESS_MEMORY_INFO); +}; + Object.defineProperty(preloadProcess, 'noDeprecation', { get () { return process.noDeprecation; diff --git a/package.json b/package.json index f5fe42cf30195..62bea35eccd2a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "electron", - "version": "13.4.0", + "version": "13.6.9", "repository": "https://github.com/electron/electron", "description": "Build cross platform desktop apps with JavaScript, HTML, and CSS", "devDependencies": { @@ -33,7 +33,7 @@ "asar": "^3.0.3", "aws-sdk": "^2.727.1", "check-for-leaks": "^1.2.1", - "colors": "^1.4.0", + "colors": "1.4.0", "dotenv-safe": "^4.0.4", "dugite": "^1.45.0", "eslint": "^7.4.0", diff --git a/patches/angle/.patches b/patches/angle/.patches index 89ec7cba41053..3deb0bb29b553 100644 --- a/patches/angle/.patches +++ b/patches/angle/.patches @@ -1,2 +1,7 @@ cherry-pick-d8cb996.patch cherry-pick-1fb846c.patch +cherry-pick-72473550f6ff.patch +webgl_make_unsuccessful_links_fail_subsequent_draw_calls.patch +fix_integer_overflow_in_blocklayoutencoder.patch +m96_fix_changing_attached_renderbuffer_from_msrtt_to_non-msrtt.patch +cherry-pick-891020ed64d4.patch diff --git a/patches/angle/cherry-pick-72473550f6ff.patch b/patches/angle/cherry-pick-72473550f6ff.patch new file mode 100644 index 0000000000000..3d8e0898786cf --- /dev/null +++ b/patches/angle/cherry-pick-72473550f6ff.patch @@ -0,0 +1,69 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jamie Madill +Date: Wed, 1 Sep 2021 12:17:26 -0400 +Subject: D3D11: Fix overflow in GenerateInitialTextureData. + +Our use of unchecked math was causing OOB accesses with very large +textures. Unfortunately it's not easy to make a passing test that +reproduces this OOB access. + +Bug: chromium:1241036 +Change-Id: Icd2749f5b3116bb51390ce769fef22c49a11f307 +Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3136733 +Reviewed-by: Geoff Lang +Commit-Queue: Jamie Madill +(cherry picked from commit 794b13ce9f874d472729ebd69897bc7ab9340a4b) +Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3149277 +Reviewed-by: Jamie Madill + +diff --git a/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp b/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp +index 3915a89de6fd161fa72519d4b9b6e82db68c6c66..6d721bd6e72d21454a868965993d930fe138b58c 100644 +--- a/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp ++++ b/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp +@@ -2181,28 +2181,35 @@ angle::Result GenerateInitialTextureData( + const d3d11::DXGIFormatSize &dxgiFormatInfo = + d3d11::GetDXGIFormatSizeInfo(d3dFormatInfo.texFormat); + +- unsigned int rowPitch = dxgiFormatInfo.pixelBytes * width; +- unsigned int depthPitch = rowPitch * height; +- unsigned int maxImageSize = depthPitch * depth; ++ using CheckedSize = angle::CheckedNumeric; ++ CheckedSize rowPitch = CheckedSize(dxgiFormatInfo.pixelBytes) * CheckedSize(width); ++ CheckedSize depthPitch = rowPitch * CheckedSize(height); ++ CheckedSize maxImageSize = depthPitch * CheckedSize(depth); ++ ++ Context11 *context11 = GetImplAs(context); ++ ANGLE_CHECK_GL_ALLOC(context11, maxImageSize.IsValid()); + + angle::MemoryBuffer *scratchBuffer = nullptr; +- ANGLE_CHECK_GL_ALLOC(GetImplAs(context), +- context->getScratchBuffer(maxImageSize, &scratchBuffer)); ++ ANGLE_CHECK_GL_ALLOC(context11, ++ context->getScratchBuffer(maxImageSize.ValueOrDie(), &scratchBuffer)); + +- d3dFormatInfo.dataInitializerFunction(width, height, depth, scratchBuffer->data(), rowPitch, +- depthPitch); ++ d3dFormatInfo.dataInitializerFunction(width, height, depth, scratchBuffer->data(), ++ rowPitch.ValueOrDie(), depthPitch.ValueOrDie()); + + for (unsigned int i = 0; i < mipLevels; i++) + { + unsigned int mipWidth = std::max(width >> i, 1U); + unsigned int mipHeight = std::max(height >> i, 1U); + +- unsigned int mipRowPitch = dxgiFormatInfo.pixelBytes * mipWidth; +- unsigned int mipDepthPitch = mipRowPitch * mipHeight; ++ using CheckedUINT = angle::CheckedNumeric; ++ CheckedUINT mipRowPitch = CheckedUINT(dxgiFormatInfo.pixelBytes) * CheckedUINT(mipWidth); ++ CheckedUINT mipDepthPitch = mipRowPitch * CheckedUINT(mipHeight); ++ ++ ANGLE_CHECK_GL_ALLOC(context11, mipRowPitch.IsValid() && mipDepthPitch.IsValid()); + + outSubresourceData->at(i).pSysMem = scratchBuffer->data(); +- outSubresourceData->at(i).SysMemPitch = mipRowPitch; +- outSubresourceData->at(i).SysMemSlicePitch = mipDepthPitch; ++ outSubresourceData->at(i).SysMemPitch = mipRowPitch.ValueOrDie(); ++ outSubresourceData->at(i).SysMemSlicePitch = mipDepthPitch.ValueOrDie(); + } + + return angle::Result::Continue; diff --git a/patches/angle/cherry-pick-891020ed64d4.patch b/patches/angle/cherry-pick-891020ed64d4.patch new file mode 100644 index 0000000000000..130eba98f8ac0 --- /dev/null +++ b/patches/angle/cherry-pick-891020ed64d4.patch @@ -0,0 +1,163 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jonah Ryan-Davis +Date: Mon, 22 Nov 2021 14:30:52 -0500 +Subject: Ignore the pixel unpack state for compressed textures. + +From OpenGL ES 3 spec: All pixel storage modes are ignored when decoding +a compressed texture image +This was causing a bad access when calling compressedTexImage3D +with GL_UNPACK_IMAGE_HEIGHT greater than the image height. + +Bug: chromium:1267496 +Change-Id: I9b1f4c645548af64f2695fd23262225a1ad07cd7 +Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3296622 +Commit-Queue: Jonah Ryan-Davis +Reviewed-by: Geoff Lang +Reviewed-by: Shahbaz Youssefi +(cherry picked from commit 870f458f507ff7ba0f67b28a30a27955ce79dd3e) +Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3309097 +Reviewed-by: Jonah Ryan-Davis +Reviewed-by: Jamie Madill + +diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp +index 4c0fbae275812e14d1732be9bc0ae0fd630cbe81..7deca1499ef55aa051ee1839dc7fcbf2e50687e8 100644 +--- a/src/libANGLE/Context.cpp ++++ b/src/libANGLE/Context.cpp +@@ -4873,7 +4873,9 @@ void Context::compressedTexImage2D(TextureTarget target, + + Extents size(width, height, 1); + Texture *texture = getTextureByTarget(target); +- ANGLE_CONTEXT_TRY(texture->setCompressedImage(this, mState.getUnpackState(), target, level, ++ // From OpenGL ES 3 spec: All pixel storage modes are ignored when decoding a compressed texture ++ // image. So we use an empty PixelUnpackState. ++ ANGLE_CONTEXT_TRY(texture->setCompressedImage(this, PixelUnpackState(), target, level, + internalformat, size, imageSize, + static_cast(data))); + } +@@ -4905,7 +4907,9 @@ void Context::compressedTexImage3D(TextureTarget target, + + Extents size(width, height, depth); + Texture *texture = getTextureByTarget(target); +- ANGLE_CONTEXT_TRY(texture->setCompressedImage(this, mState.getUnpackState(), target, level, ++ // From OpenGL ES 3 spec: All pixel storage modes are ignored when decoding a compressed texture ++ // image. So we use an empty PixelUnpackState. ++ ANGLE_CONTEXT_TRY(texture->setCompressedImage(this, PixelUnpackState(), target, level, + internalformat, size, imageSize, + static_cast(data))); + } +@@ -4939,8 +4943,10 @@ void Context::compressedTexSubImage2D(TextureTarget target, + + Box area(xoffset, yoffset, 0, width, height, 1); + Texture *texture = getTextureByTarget(target); +- ANGLE_CONTEXT_TRY(texture->setCompressedSubImage(this, mState.getUnpackState(), target, level, +- area, format, imageSize, ++ // From OpenGL ES 3 spec: All pixel storage modes are ignored when decoding a compressed texture ++ // image. So we use an empty PixelUnpackState. ++ ANGLE_CONTEXT_TRY(texture->setCompressedSubImage(this, PixelUnpackState(), target, level, area, ++ format, imageSize, + static_cast(data))); + } + +@@ -4981,8 +4987,10 @@ void Context::compressedTexSubImage3D(TextureTarget target, + + Box area(xoffset, yoffset, zoffset, width, height, depth); + Texture *texture = getTextureByTarget(target); +- ANGLE_CONTEXT_TRY(texture->setCompressedSubImage(this, mState.getUnpackState(), target, level, +- area, format, imageSize, ++ // From OpenGL ES 3 spec: All pixel storage modes are ignored when decoding a compressed texture ++ // image. So we use an empty PixelUnpackState. ++ ANGLE_CONTEXT_TRY(texture->setCompressedSubImage(this, PixelUnpackState(), target, level, area, ++ format, imageSize, + static_cast(data))); + } + +diff --git a/src/tests/gl_tests/TextureTest.cpp b/src/tests/gl_tests/TextureTest.cpp +index d238f823c4dd3cd3180a87b97857231b0c8b788e..f6dad3a3df52994284f570ed38f24b8efe37e513 100644 +--- a/src/tests/gl_tests/TextureTest.cpp ++++ b/src/tests/gl_tests/TextureTest.cpp +@@ -4580,6 +4580,43 @@ TEST_P(Texture2DTestES3, TextureCompletenessChangesWithMaxLevel) + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black); + } + ++// Test that compressed textures ignore the pixel unpack state. ++// (https://crbug.org/1267496) ++TEST_P(Texture3DTestES3, PixelUnpackStateTexImage) ++{ ++ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_s3tc") && ++ !IsGLExtensionEnabled("GL_ANGLE_texture_compression_dxt3")); ++ ++ glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 5); ++ glBindTexture(GL_TEXTURE_2D_ARRAY, mTexture3D); ++ ++ uint8_t data[64] = {0}; ++ glCompressedTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 4, 4, 4, 0, 64, ++ data); ++ EXPECT_GL_NO_ERROR(); ++} ++ ++// Test that compressed textures ignore the pixel unpack state. ++// (https://crbug.org/1267496) ++TEST_P(Texture3DTestES3, PixelUnpackStateTexSubImage) ++{ ++ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_s3tc") && ++ !IsGLExtensionEnabled("GL_ANGLE_texture_compression_dxt3")); ++ ++ glBindTexture(GL_TEXTURE_2D_ARRAY, mTexture3D); ++ ++ uint8_t data[64] = {0}; ++ glCompressedTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 4, 4, 4, 0, 64, ++ data); ++ EXPECT_GL_NO_ERROR(); ++ ++ glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 5); ++ ++ glCompressedTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, 4, 4, 4, ++ GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 64, data); ++ EXPECT_GL_NO_ERROR(); ++} ++ + // Test that 3D texture completeness is updated if texture max level changes. + // GLES 3.0.4 section 3.8.13 Texture completeness + TEST_P(Texture3DTestES3, Texture3DCompletenessChangesWithMaxLevel) +@@ -5259,6 +5296,41 @@ TEST_P(Texture2DTestES3, TextureCOMPRESSEDSRGB8ETC2ImplicitAlpha1) + EXPECT_PIXEL_ALPHA_EQ(0, 0, 255); + } + ++// Test that compressed textures ignore the pixel unpack state. ++// (https://crbug.org/1267496) ++TEST_P(Texture2DTestES3, PixelUnpackStateTexImage) ++{ ++ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_s3tc") && ++ !IsGLExtensionEnabled("GL_ANGLE_texture_compression_dxt3")); ++ ++ glPixelStorei(GL_UNPACK_ROW_LENGTH, 5); ++ glBindTexture(GL_TEXTURE_2D, mTexture2D); ++ ++ uint8_t data[16] = {0}; ++ glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 4, 4, 0, 16, data); ++ EXPECT_GL_NO_ERROR(); ++} ++ ++// Test that compressed textures ignore the pixel unpack state. ++// (https://crbug.org/1267496) ++TEST_P(Texture2DTestES3, PixelUnpackStateTexSubImage) ++{ ++ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_s3tc") && ++ !IsGLExtensionEnabled("GL_ANGLE_texture_compression_dxt3")); ++ ++ glBindTexture(GL_TEXTURE_2D, mTexture2D); ++ ++ uint8_t data[16] = {0}; ++ glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 4, 4, 0, 16, data); ++ EXPECT_GL_NO_ERROR(); ++ ++ glPixelStorei(GL_UNPACK_ROW_LENGTH, 5); ++ ++ glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 16, ++ data); ++ EXPECT_GL_NO_ERROR(); ++} ++ + // Copied from Texture2DTest::TexStorage + // Test that glTexSubImage2D works properly when glTexStorage2DEXT has initialized the image with a + // default color. diff --git a/patches/angle/fix_integer_overflow_in_blocklayoutencoder.patch b/patches/angle/fix_integer_overflow_in_blocklayoutencoder.patch new file mode 100644 index 0000000000000..1c4b0323433cb --- /dev/null +++ b/patches/angle/fix_integer_overflow_in_blocklayoutencoder.patch @@ -0,0 +1,112 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Alexis Hetu +Date: Wed, 15 Sep 2021 13:40:28 -0400 +Subject: Fix integer overflow in BlockLayoutEncoder +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +BlockLayoutEncoder::mCurrentOffset's computation had the +possibility of causing integer overflows in multiple places, +so this CL adds CheckedNumeric variables in a number of +these occurrences in order to prevent integer overflows and +causing issues. + +The issue in this case was an integer overflow causing the +code in ValidateTypeSizeLimitations.cpp to use an invalid +result from "layoutEncoder.getCurrentOffset()", which ended +up compiling a shader which would later cause an OOM error. + +Bug: chromium:1248665 +Change-Id: I688d669f21c6dc2957e43bdf91f8f8f08180a6f7 +Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3163356 +Reviewed-by: Jamie Madill +Reviewed-by: Kenneth Russell +Reviewed-by: Geoff Lang +Commit-Queue: Alexis Hétu +(cherry picked from commit 158ef351fc8b827c201e056a8ddba50fd4235671) +Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3194392 + +diff --git a/src/compiler/translator/blocklayout.cpp b/src/compiler/translator/blocklayout.cpp +index 0539923bc75f5b88228dcb387c8aba4c701edc1b..1e6b143a1e1ee9a127b71685febd36416a8840f6 100644 +--- a/src/compiler/translator/blocklayout.cpp ++++ b/src/compiler/translator/blocklayout.cpp +@@ -199,6 +199,13 @@ BlockMemberInfo BlockLayoutEncoder::encodeType(GLenum type, + return memberInfo; + } + ++size_t BlockLayoutEncoder::getCurrentOffset() const ++{ ++ angle::base::CheckedNumeric checkedOffset(mCurrentOffset); ++ checkedOffset *= kBytesPerComponent; ++ return checkedOffset.ValueOrDefault(std::numeric_limits::max()); ++} ++ + size_t BlockLayoutEncoder::getShaderVariableSize(const ShaderVariable &structVar, bool isRowMajor) + { + size_t currentOffset = mCurrentOffset; +@@ -226,7 +233,13 @@ size_t BlockLayoutEncoder::GetBlockRegisterElement(const BlockMemberInfo &info) + + void BlockLayoutEncoder::align(size_t baseAlignment) + { +- mCurrentOffset = rx::roundUp(mCurrentOffset, baseAlignment); ++ angle::base::CheckedNumeric checkedOffset(mCurrentOffset); ++ checkedOffset += baseAlignment; ++ checkedOffset -= 1; ++ angle::base::CheckedNumeric checkedAlignmentOffset = checkedOffset; ++ checkedAlignmentOffset %= baseAlignment; ++ checkedOffset -= checkedAlignmentOffset.ValueOrDefault(std::numeric_limits::max()); ++ mCurrentOffset = checkedOffset.ValueOrDefault(std::numeric_limits::max()); + } + + // StubBlockEncoder implementation. +@@ -289,7 +302,7 @@ void Std140BlockEncoder::getBlockLayoutInfo(GLenum type, + baseAlignment = ComponentAlignment(numComponents); + } + +- mCurrentOffset = rx::roundUp(mCurrentOffset, baseAlignment); ++ align(baseAlignment); + + *matrixStrideOut = matrixStride; + *arrayStrideOut = arrayStride; +@@ -303,16 +316,23 @@ void Std140BlockEncoder::advanceOffset(GLenum type, + { + if (!arraySizes.empty()) + { +- mCurrentOffset += arrayStride * gl::ArraySizeProduct(arraySizes); ++ angle::base::CheckedNumeric checkedOffset(arrayStride); ++ checkedOffset *= gl::ArraySizeProduct(arraySizes); ++ checkedOffset += mCurrentOffset; ++ mCurrentOffset = checkedOffset.ValueOrDefault(std::numeric_limits::max()); + } + else if (gl::IsMatrixType(type)) + { +- const int numRegisters = gl::MatrixRegisterCount(type, isRowMajorMatrix); +- mCurrentOffset += matrixStride * numRegisters; ++ angle::base::CheckedNumeric checkedOffset(matrixStride); ++ checkedOffset *= gl::MatrixRegisterCount(type, isRowMajorMatrix); ++ checkedOffset += mCurrentOffset; ++ mCurrentOffset = checkedOffset.ValueOrDefault(std::numeric_limits::max()); + } + else + { +- mCurrentOffset += gl::VariableComponentCount(type); ++ angle::base::CheckedNumeric checkedOffset(mCurrentOffset); ++ checkedOffset += gl::VariableComponentCount(type); ++ mCurrentOffset = checkedOffset.ValueOrDefault(std::numeric_limits::max()); + } + } + +diff --git a/src/compiler/translator/blocklayout.h b/src/compiler/translator/blocklayout.h +index 726d76fa178f77a978ff2c82ec20fb8f1ad03f0b..ff90a2487830b365697ce41d660a689857b75319 100644 +--- a/src/compiler/translator/blocklayout.h ++++ b/src/compiler/translator/blocklayout.h +@@ -80,7 +80,7 @@ class BlockLayoutEncoder + const std::vector &arraySizes, + bool isRowMajorMatrix); + +- size_t getCurrentOffset() const { return mCurrentOffset * kBytesPerComponent; } ++ size_t getCurrentOffset() const; + size_t getShaderVariableSize(const ShaderVariable &structVar, bool isRowMajor); + + // Called when entering/exiting a structure variable. diff --git a/patches/angle/m96_fix_changing_attached_renderbuffer_from_msrtt_to_non-msrtt.patch b/patches/angle/m96_fix_changing_attached_renderbuffer_from_msrtt_to_non-msrtt.patch new file mode 100644 index 0000000000000..d8dd7f98058c5 --- /dev/null +++ b/patches/angle/m96_fix_changing_attached_renderbuffer_from_msrtt_to_non-msrtt.patch @@ -0,0 +1,168 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shahbaz Youssefi +Date: Thu, 2 Dec 2021 14:30:42 -0500 +Subject: M96: Fix changing attached renderbuffer from MSRTT to non-MSRTT + +FramebufferAttachment::mRenderToTextureSamples was never updated if the +renderbuffer storage was changed after attaching to framebuffer. + +Bug: chromium:1272068 +Change-Id: Icddbb5650354ea16d06c49532d6a8d0ae962ab5f +Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3320923 +Reviewed-by: Jamie Madill + +diff --git a/src/libANGLE/FramebufferAttachment.cpp b/src/libANGLE/FramebufferAttachment.cpp +index 00714d0a0303050893abcd9564e760b22d9b2de5..720d3000d42e6c8c23214e66eee4aa6982216a60 100644 +--- a/src/libANGLE/FramebufferAttachment.cpp ++++ b/src/libANGLE/FramebufferAttachment.cpp +@@ -129,7 +129,7 @@ void FramebufferAttachment::attach(const Context *context, + mNumViews = numViews; + mBaseViewIndex = baseViewIndex; + mIsMultiview = isMultiview; +- mRenderToTextureSamples = samples; ++ mRenderToTextureSamples = type == GL_RENDERBUFFER ? kDefaultRenderToTextureSamples : samples; + resource->onAttach(context, framebufferSerial); + + if (mResource != nullptr) +@@ -222,6 +222,29 @@ GLint FramebufferAttachment::getBaseViewIndex() const + return mBaseViewIndex; + } + ++bool FramebufferAttachment::isRenderToTexture() const ++{ ++ ASSERT(mRenderToTextureSamples == kDefaultRenderToTextureSamples || mType == GL_TEXTURE); ++ ++ if (mType == GL_RENDERBUFFER) ++ { ++ return getRenderbuffer()->getMultisamplingMode() == ++ MultisamplingMode::MultisampledRenderToTexture; ++ } ++ return mRenderToTextureSamples != kDefaultRenderToTextureSamples; ++} ++ ++GLsizei FramebufferAttachment::getRenderToTextureSamples() const ++{ ++ ASSERT(mRenderToTextureSamples == kDefaultRenderToTextureSamples || mType == GL_TEXTURE); ++ ++ if (mType == GL_RENDERBUFFER) ++ { ++ return getRenderbuffer()->getState().getSamples(); ++ } ++ return mRenderToTextureSamples; ++} ++ + Texture *FramebufferAttachment::getTexture() const + { + return rx::GetAs(mResource); +diff --git a/src/libANGLE/FramebufferAttachment.h b/src/libANGLE/FramebufferAttachment.h +index 013a1e02874e4df3680e9b4a56f74aaf94d188a9..6235b42cf2fdfcb0e9fa33242b458934f1afa5b0 100644 +--- a/src/libANGLE/FramebufferAttachment.h ++++ b/src/libANGLE/FramebufferAttachment.h +@@ -117,11 +117,8 @@ class FramebufferAttachment final + bool isMultiview() const; + GLint getBaseViewIndex() const; + +- bool isRenderToTexture() const +- { +- return mRenderToTextureSamples != kDefaultRenderToTextureSamples; +- } +- GLsizei getRenderToTextureSamples() const { return mRenderToTextureSamples; } ++ bool isRenderToTexture() const; ++ GLsizei getRenderToTextureSamples() const; + + // The size of the underlying resource the attachment points to. The 'depth' value will + // correspond to a 3D texture depth or the layer count of a 2D array texture. For Surfaces and +@@ -195,6 +192,14 @@ class FramebufferAttachment final + GLsizei mNumViews; + bool mIsMultiview; + GLint mBaseViewIndex; ++ // A single-sampled texture can be attached to a framebuffer either as single-sampled or as ++ // multisampled-render-to-texture. In the latter case, |mRenderToTextureSamples| will contain ++ // the number of samples. For renderbuffers, the number of samples is inherited from the ++ // renderbuffer itself. ++ // ++ // Note that textures cannot change storage between single and multisample once attached to a ++ // framebuffer. Renderbuffers instead can, and caching the number of renderbuffer samples here ++ // can lead to stale data. + GLsizei mRenderToTextureSamples; + }; + +@@ -253,8 +258,7 @@ inline Format FramebufferAttachment::getFormat() const + + inline GLsizei FramebufferAttachment::getSamples() const + { +- return (mRenderToTextureSamples != kDefaultRenderToTextureSamples) ? getRenderToTextureSamples() +- : getResourceSamples(); ++ return isRenderToTexture() ? getRenderToTextureSamples() : getResourceSamples(); + } + + inline GLsizei FramebufferAttachment::getResourceSamples() const +diff --git a/src/tests/gl_tests/FramebufferTest.cpp b/src/tests/gl_tests/FramebufferTest.cpp +index 29b3544bf31ad462e3f5f201c8836a6b18899111..a90448af279e4172eabf53d6391b9f0c53b5d220 100644 +--- a/src/tests/gl_tests/FramebufferTest.cpp ++++ b/src/tests/gl_tests/FramebufferTest.cpp +@@ -3098,6 +3098,64 @@ TEST_P(FramebufferTest, BindAndDrawDifferentSizedFBOs) + EXPECT_PIXEL_RECT_EQ(0, 0, kLargeWidth, kLargeHeight, GLColor::blue); + } + ++// Modify renderbuffer attachment samples after bind ++TEST_P(FramebufferTest_ES3, BindRenderbufferThenModifySamples) ++{ ++ ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); ++ glUseProgram(program); ++ GLint colorUniformLocation = ++ glGetUniformLocation(program, angle::essl1_shaders::ColorUniform()); ++ ASSERT_NE(colorUniformLocation, -1); ++ ++ GLFramebuffer fbo; ++ glBindFramebuffer(GL_FRAMEBUFFER, fbo); ++ ++ GLsizei size = 16; ++ glViewport(0, 0, size, size); ++ ++ GLRenderbuffer color; ++ glBindRenderbuffer(GL_RENDERBUFFER, color); ++ ++ glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_RGBA8, size, size); ++ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color); ++ glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, size, size); ++ ++ glUniform4f(colorUniformLocation, 1, 0, 0, 1); ++ drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); ++ ++ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); ++ ASSERT_GL_NO_ERROR(); ++} ++ ++// Modify renderbuffer attachment size after bind ++TEST_P(FramebufferTest_ES3, BindRenderbufferThenModifySize) ++{ ++ ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); ++ glUseProgram(program); ++ GLint colorUniformLocation = ++ glGetUniformLocation(program, angle::essl1_shaders::ColorUniform()); ++ ASSERT_NE(colorUniformLocation, -1); ++ ++ GLFramebuffer fbo; ++ glBindFramebuffer(GL_FRAMEBUFFER, fbo); ++ ++ GLsizei size = 16; ++ glViewport(0, 0, size, size); ++ ++ GLRenderbuffer color; ++ glBindRenderbuffer(GL_RENDERBUFFER, color); ++ ++ glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, size, size); ++ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color); ++ glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, size / 2, size * 2); ++ ++ glUniform4f(colorUniformLocation, 1, 0, 0, 1); ++ drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f); ++ ++ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); ++ ASSERT_GL_NO_ERROR(); ++} ++ + ANGLE_INSTANTIATE_TEST_ES2(AddMockTextureNoRenderTargetTest); + ANGLE_INSTANTIATE_TEST_ES2(FramebufferTest); + ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(FramebufferFormatsTest); diff --git a/patches/angle/webgl_make_unsuccessful_links_fail_subsequent_draw_calls.patch b/patches/angle/webgl_make_unsuccessful_links_fail_subsequent_draw_calls.patch new file mode 100644 index 0000000000000..7d3a68b2d6f40 --- /dev/null +++ b/patches/angle/webgl_make_unsuccessful_links_fail_subsequent_draw_calls.patch @@ -0,0 +1,34 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jamie Madill +Date: Fri, 3 Sep 2021 09:34:10 -0400 +Subject: WebGL: Make unsuccessful links fail subsequent draw calls. + +This protects against incomplete state updates during a failed +link call that can interfere with draw calls. + +Bug: angleproject:6358 +Bug: chromium:1241123 +Change-Id: Ie892654c3a58c69d6e35ba3c41758ab6269d8193 +Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3140496 +Reviewed-by: Geoff Lang +Commit-Queue: Yuly Novikov +Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3152556 +Reviewed-by: Jamie Madill + +diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp +index 412b9aa0f1d75c40ce02522589c53e943d049228..7826233f206b2ae7b926cd2564c887c726b79930 100644 +--- a/src/libANGLE/validationES.cpp ++++ b/src/libANGLE/validationES.cpp +@@ -3958,6 +3958,12 @@ const char *ValidateDrawStates(const Context *context) + { + return kVertexBufferBoundForTransformFeedback; + } ++ ++ // Validate that we are rendering with a linked program. ++ if (!program->isLinked()) ++ { ++ return kProgramNotLinked; ++ } + } + } + diff --git a/patches/chromium/.patches b/patches/chromium/.patches index 26b6b9ecc0863..534a9bad9e6a1 100644 --- a/patches/chromium/.patches +++ b/patches/chromium/.patches @@ -129,7 +129,53 @@ cherry-pick-1230767.patch cherry-pick-1231134.patch cherry-pick-1233564.patch cherry-pick-1234009.patch +fix_media_key_usage_with_globalshortcuts.patch attach_to_correct_frame_in.patch merge_m92_speculative_fix_for_crash_in.patch cherry-pick-d727013bb543.patch pa_make_getusablesize_handle_nullptr_gracefully.patch +dpwas_window_control_overlay_api_values_account_for_page_zoom_factor.patch +reland_make_clientview_a_child_of_the_nonclientframeview.patch +content-visibility_force_range_base_extent_when_computing_visual.patch +cherry-pick-6215793f008f.patch +cherry-pick-6048fcd52f42.patch +contentindex_add_origin_checks_to_mojo_methods.patch +m93_indexeddb_add_browser-side_checks_for_committing_transactions.patch +m93_indexeddb_don_t_reportbadmessage_for_commit_calls.patch +cherry-pick-8623d711677d.patch +cherry-pick-ddc4cf156505.patch +skip_webgl_conformance_programs_program-test_html_on_all_platforms.patch +linux_sandbox_update_syscall_numbers_for_all_platforms.patch +linux_sandbox_return_enosys_for_clone3.patch +content-visibility_add_a_clipper_fix_for_content-visibility.patch +kill_a_renderer_if_it_provides_an_unexpected_frameownerelementtype.patch +m90-lts_backgroundfetch_check_whether_the_sw_id_is_valid_for.patch +cherry-pick-096afc1c5428.patch +cherry-pick-4e528a5a8d83.patch +cherry-pick-3a5bafa35def.patch +cherry-pick-b2c4e4dc21e5.patch +check_direction_of_rtcencodedframes.patch +cherry-pick-6a8a2098f9fa.patch +speculative_fix_for_eye_dropper_getcolor_crash.patch +mas_gate_private_enterprise_APIs.patch +cherry-pick-c69dddfe1cde.patch +cherry-pick-8af66de55aad.patch +move_networkstateobserver_from_document_to_window.patch +cherry-pick-0894af410c4e.patch +disable_quictransport_explicitly_in_the_network_service.patch +cherry-pick-91dd4f79ab5b.patch +introduce_crossthreadcopier_skbitmap.patch +allow_null_skbitmap_to_be_transferred_across_threads.patch +use_weakptrs_for_the_threadediconloader_s_background_tasks.patch +cherry-pick-27eb11a28555.patch +show_the_origin_of_the_last_redirecting_server_in_external_protocol.patch +cachestorage_store_partial_opaque_responses.patch +cherry-pick-a5f54612590d.patch +cherry-pick-1a8af2da50e4.patch +cherry-pick-f0a63e1f361f.patch +mojo_ipc_drop_messages_targeting_invalid_task_runner.patch +sandbox_fix_sandbox_inheritance_m96_merge.patch +cherry-pick-dbde8795233a.patch +cherry-pick-6bb320d134b1.patch +m96_fileapi_move_origin_checks_in_bloburlstore_sooner.patch +fix_wayland_bugs_related_to_bad_versioning.patch diff --git a/patches/chromium/allow_null_skbitmap_to_be_transferred_across_threads.patch b/patches/chromium/allow_null_skbitmap_to_be_transferred_across_threads.patch new file mode 100644 index 0000000000000..2e00aac087e42 --- /dev/null +++ b/patches/chromium/allow_null_skbitmap_to_be_transferred_across_threads.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Yutaka Hirano +Date: Tue, 9 Nov 2021 09:03:17 +0000 +Subject: Allow null SkBitmap to be transferred across threads + +(cherry picked from commit dad0c0e5162bcc49b8f60354d3bca92224d8381b) + +Bug: 1241091 +Change-Id: Ie96932c14c8884d6d3eafa76dab5043e7aa31888 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3251815 +Reviewed-by: Florin Malita +Commit-Queue: Yutaka Hirano +Cr-Original-Commit-Position: refs/heads/main@{#936861} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3268018 +Auto-Submit: Yutaka Hirano +Reviewed-by: Kentaro Hara +Commit-Queue: Kentaro Hara +Cr-Commit-Position: refs/branch-heads/4664@{#893} +Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512} + +diff --git a/third_party/blink/renderer/platform/graphics/skia/skia_utils.h b/third_party/blink/renderer/platform/graphics/skia/skia_utils.h +index 3bd49cac3f5dfcad0fcc1140fcf876fe37558930..c037b85210bf2dedeb8478cf918633ad94885048 100644 +--- a/third_party/blink/renderer/platform/graphics/skia/skia_utils.h ++++ b/third_party/blink/renderer/platform/graphics/skia/skia_utils.h +@@ -209,11 +209,13 @@ struct CrossThreadCopier { + + using Type = SkBitmap; + static SkBitmap Copy(const SkBitmap& bitmap) { +- CHECK(bitmap.isImmutable()) << "Only immutable bitmaps can be transferred."; ++ CHECK(bitmap.isImmutable() || bitmap.isNull()) ++ << "Only immutable bitmaps can be transferred."; + return bitmap; + } + static SkBitmap Copy(SkBitmap&& bitmap) { +- CHECK(bitmap.isImmutable()) << "Only immutable bitmaps can be transferred."; ++ CHECK(bitmap.isImmutable() || bitmap.isNull()) ++ << "Only immutable bitmaps can be transferred."; + return std::move(bitmap); + } + }; diff --git a/patches/chromium/cachestorage_store_partial_opaque_responses.patch b/patches/chromium/cachestorage_store_partial_opaque_responses.patch new file mode 100644 index 0000000000000..e28796d2061c2 --- /dev/null +++ b/patches/chromium/cachestorage_store_partial_opaque_responses.patch @@ -0,0 +1,94 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ben Kelly +Date: Fri, 5 Nov 2021 19:47:08 +0000 +Subject: CacheStorage: Store partial opaque responses. + +(cherry picked from commit 802faa035409ac7cbb58ad1a385bb8507fe99077) + +Fixed: 1260649 +Change-Id: If83156096e6aecec55490330d03c56c0c26120bc +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3251749 +Reviewed-by: Marijn Kruisselbrink +Commit-Queue: Ben Kelly +Cr-Original-Commit-Position: refs/heads/main@{#937400} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3264366 +Bot-Commit: Rubber Stamper +Cr-Commit-Position: refs/branch-heads/4664@{#774} +Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512} + +diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc b/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc +index 634d72af383e4b9a52ce04202388e13077754783..c5be9cd6e579ad11701c251d48966934e71e8069 100644 +--- a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc ++++ b/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc +@@ -446,10 +446,10 @@ blink::mojom::FetchAPIResponsePtr CreateResponse( + padding = storage::ComputeRandomResponsePadding(); + } + +- // Note that |has_range_requested| can be safely set to false since it only +- // affects HTTP 206 (Partial) responses, which are blocked from cache storage. +- // See https://fetch.spec.whatwg.org/#main-fetch for usage of +- // |has_range_requested|. ++ // While we block most partial responses from being stored, we can have ++ // partial responses for bgfetch or opaque responses. ++ bool has_range_requested = headers.contains(net::HttpRequestHeaders::kRange); ++ + return blink::mojom::FetchAPIResponse::New( + url_list, metadata.response().status_code(), + metadata.response().status_text(), +@@ -467,7 +467,7 @@ blink::mojom::FetchAPIResponsePtr CreateResponse( + static_cast( + metadata.response().connection_info()), + alpn_negotiated_protocol, metadata.response().was_fetched_via_spdy(), +- /*has_range_requested=*/false, /*auth_challenge_info=*/base::nullopt); ++ has_range_requested, /*auth_challenge_info=*/base::nullopt); + } + + int64_t CalculateSideDataPadding( +@@ -1907,7 +1907,13 @@ void LegacyCacheStorageCache::PutDidCreateEntry( + } + + proto::CacheResponse* response_metadata = metadata.mutable_response(); +- DCHECK_NE(put_context->response->status_code, net::HTTP_PARTIAL_CONTENT); ++ if (owner_ != storage::mojom::CacheStorageOwner::kBackgroundFetch && ++ put_context->response->response_type != ++ network::mojom::FetchResponseType::kOpaque && ++ put_context->response->response_type != ++ network::mojom::FetchResponseType::kOpaqueRedirect) { ++ DCHECK_NE(put_context->response->status_code, net::HTTP_PARTIAL_CONTENT); ++ } + response_metadata->set_status_code(put_context->response->status_code); + response_metadata->set_status_text(put_context->response->status_text); + response_metadata->set_response_type(FetchResponseTypeToProtoResponseType( +diff --git a/third_party/blink/renderer/modules/cache_storage/cache.cc b/third_party/blink/renderer/modules/cache_storage/cache.cc +index 5482ce90e5a9f591016c784a0378b73b0520be03..0ec3a20cff2fdfc1ebd0f512cfdad4c991341d89 100644 +--- a/third_party/blink/renderer/modules/cache_storage/cache.cc ++++ b/third_party/blink/renderer/modules/cache_storage/cache.cc +@@ -101,7 +101,7 @@ void ValidateResponseForPut(const Response* response, + exception_state.ThrowTypeError("Vary header contains *"); + return; + } +- if (response->GetResponse()->InternalStatus() == 206) { ++ if (response->GetResponse()->Status() == 206) { + exception_state.ThrowTypeError( + "Partial response (status code 206) is unsupported"); + return; +diff --git a/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/script-tests/cache-put.js b/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/script-tests/cache-put.js +index b45910a3b8ba089e1724efa8b9e8a8d679c59320..f60c4b905ebcb61854b83177d59861ef92095624 100644 +--- a/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/script-tests/cache-put.js ++++ b/third_party/blink/web_tests/external/wpt/service-workers/cache-storage/script-tests/cache-put.js +@@ -144,7 +144,14 @@ cache_test(function(cache, test) { + 'Test framework error: The status code should be 0 for an ' + + ' opaque-filtered response. This is actually HTTP 206.'); + response = fetch_result.clone(); +- return promise_rejects_js(test, TypeError, cache.put(request, fetch_result)); ++ return cache.put(request, fetch_result); ++ }) ++ .then(function() { ++ return cache.match(test_url); ++ }) ++ .then(function(result) { ++ assert_not_equals(result, undefined, ++ 'Cache.put should store an entry for the opaque response'); + }); + }, 'Cache.put with opaque-filtered HTTP 206 response'); + diff --git a/patches/chromium/check_direction_of_rtcencodedframes.patch b/patches/chromium/check_direction_of_rtcencodedframes.patch new file mode 100644 index 0000000000000..86c5f5cfe2e1c --- /dev/null +++ b/patches/chromium/check_direction_of_rtcencodedframes.patch @@ -0,0 +1,174 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Tony Herre +Date: Fri, 1 Oct 2021 19:18:45 +0000 +Subject: Check direction of RTCEncodedFrames + +Add a check to RTCEncodedVideoUnderlyingSink of the direction of the +underlying webrtc frame, to make sure a web app doesn't take a received +encoded frame and pass it into a sender insertable stream, which is as +yet unsupported in WebRTC. + +Bug: 1247260 +Change-Id: I9ed5bd8b2bd5e5ee461f3b553f8a91f6cc2e9ed7 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3190473 +Commit-Queue: Tony Herre +Reviewed-by: Harald Alvestrand +Cr-Commit-Position: refs/heads/main@{#927323} + +diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_sink.cc b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_sink.cc +index c390ab72418194cb10c3b0bc5a83b95de8dd19f6..775b837fee46836fd292b17ac8d80e4c83bd08a8 100644 +--- a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_sink.cc ++++ b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_sink.cc +@@ -14,8 +14,10 @@ namespace blink { + + RTCEncodedVideoUnderlyingSink::RTCEncodedVideoUnderlyingSink( + ScriptState* script_state, +- TransformerCallback transformer_callback) +- : transformer_callback_(std::move(transformer_callback)) { ++ TransformerCallback transformer_callback, ++ webrtc::TransformableFrameInterface::Direction expected_direction) ++ : transformer_callback_(std::move(transformer_callback)), ++ expected_direction_(expected_direction) { + DCHECK(transformer_callback_); + } + +@@ -53,6 +55,12 @@ ScriptPromise RTCEncodedVideoUnderlyingSink::write( + return ScriptPromise(); + } + ++ if (webrtc_frame->GetDirection() != expected_direction_) { ++ exception_state.ThrowDOMException(DOMExceptionCode::kOperationError, ++ "Invalid frame"); ++ return ScriptPromise(); ++ } ++ + RTCEncodedVideoStreamTransformer* transformer = transformer_callback_.Run(); + if (!transformer) { + exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError, +diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_sink.h b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_sink.h +index dd1cad227eb7947dd0bf2ec7ba217956cb7a8787..8591fcc6eb1c78d0e107e4f097d3133d111ab959 100644 +--- a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_sink.h ++++ b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_sink.h +@@ -7,6 +7,7 @@ + + #include "third_party/blink/renderer/core/streams/underlying_sink_base.h" + #include "third_party/blink/renderer/modules/modules_export.h" ++#include "third_party/webrtc/api/frame_transformer_interface.h" + + namespace blink { + +@@ -18,7 +19,9 @@ class MODULES_EXPORT RTCEncodedVideoUnderlyingSink final + public: + using TransformerCallback = + base::RepeatingCallback; +- RTCEncodedVideoUnderlyingSink(ScriptState*, TransformerCallback); ++ RTCEncodedVideoUnderlyingSink(ScriptState*, ++ TransformerCallback, ++ webrtc::TransformableFrameInterface::Direction); + + // UnderlyingSinkBase + ScriptPromise start(ScriptState*, +@@ -37,6 +40,7 @@ class MODULES_EXPORT RTCEncodedVideoUnderlyingSink final + + private: + TransformerCallback transformer_callback_; ++ webrtc::TransformableFrameInterface::Direction expected_direction_; + }; + + } // namespace blink +diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_sink_test.cc b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_sink_test.cc +index 3f6d24941ad7a9e5c16f11bcdcffa91b2027c0db..9837fb0be84633c88fcf451cec8c276ca6e7c17c 100644 +--- a/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_sink_test.cc ++++ b/third_party/blink/renderer/modules/peerconnection/rtc_encoded_video_underlying_sink_test.cc +@@ -75,11 +75,15 @@ class RTCEncodedVideoUnderlyingSinkTest : public testing::Test { + EXPECT_FALSE(transformer_.HasTransformedFrameSinkCallback(kSSRC)); + } + +- RTCEncodedVideoUnderlyingSink* CreateSink(ScriptState* script_state) { ++ RTCEncodedVideoUnderlyingSink* CreateSink( ++ ScriptState* script_state, ++ webrtc::TransformableFrameInterface::Direction expected_direction = ++ webrtc::TransformableFrameInterface::Direction::kSender) { + return MakeGarbageCollected( + script_state, + WTF::BindRepeating(&RTCEncodedVideoUnderlyingSinkTest::GetTransformer, +- WTF::Unretained(this))); ++ WTF::Unretained(this)), ++ expected_direction); + } + + RTCEncodedVideoUnderlyingSink* CreateNullCallbackSink( +@@ -87,15 +91,21 @@ class RTCEncodedVideoUnderlyingSinkTest : public testing::Test { + return MakeGarbageCollected( + script_state, + WTF::BindRepeating( +- []() -> RTCEncodedVideoStreamTransformer* { return nullptr; })); ++ []() -> RTCEncodedVideoStreamTransformer* { return nullptr; }), ++ webrtc::TransformableFrameInterface::Direction::kSender); + } + + RTCEncodedVideoStreamTransformer* GetTransformer() { return &transformer_; } + +- ScriptValue CreateEncodedVideoFrameChunk(ScriptState* script_state) { ++ ScriptValue CreateEncodedVideoFrameChunk( ++ ScriptState* script_state, ++ webrtc::TransformableFrameInterface::Direction direction = ++ webrtc::TransformableFrameInterface::Direction::kSender) { + auto mock_frame = + std::make_unique>(); ++ + ON_CALL(*mock_frame.get(), GetSsrc).WillByDefault(Return(kSSRC)); ++ ON_CALL(*mock_frame.get(), GetDirection).WillByDefault(Return(direction)); + RTCEncodedVideoFrame* frame = + MakeGarbageCollected(std::move(mock_frame)); + return ScriptValue(script_state->GetIsolate(), +@@ -176,4 +186,21 @@ TEST_F(RTCEncodedVideoUnderlyingSinkTest, WriteToNullCallbackSinkFails) { + DOMExceptionCode::kInvalidStateError)); + } + ++TEST_F(RTCEncodedVideoUnderlyingSinkTest, WriteInvalidDirectionFails) { ++ V8TestingScope v8_scope; ++ ScriptState* script_state = v8_scope.GetScriptState(); ++ auto* sink = CreateSink( ++ script_state, webrtc::TransformableFrameInterface::Direction::kSender); ++ ++ // Write an encoded chunk with direction set to Receiver should fail as it ++ // doesn't match the expected direction of our sink. ++ DummyExceptionStateForTesting dummy_exception_state; ++ sink->write(script_state, ++ CreateEncodedVideoFrameChunk( ++ script_state, ++ webrtc::TransformableFrameInterface::Direction::kReceiver), ++ nullptr, dummy_exception_state); ++ EXPECT_TRUE(dummy_exception_state.HadException()); ++} ++ + } // namespace blink +diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.cc b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.cc +index e654738739e18adc1937922dbb59f7f9214e651e..58cf45c9023510b4615cbebcaa3b3812481a54c3 100644 +--- a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.cc ++++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_receiver.cc +@@ -506,7 +506,8 @@ void RTCRtpReceiver::InitializeEncodedVideoStreams(ScriptState* script_state) { + ->GetEncodedVideoStreamTransformer() + : nullptr; + }, +- WrapWeakPersistent(this))); ++ WrapWeakPersistent(this)), ++ webrtc::TransformableFrameInterface::Direction::kReceiver); + // The high water mark for the stream is set to 1 so that the stream seems + // ready to write, but without queuing frames. + WritableStream* writable_stream = +diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.cc b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.cc +index 20c6325e5e7eb4e47a6324033704430ed53ea3c3..44ed2f520c88b5aa694383c749da57d6681cef9a 100644 +--- a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.cc ++++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_sender.cc +@@ -902,7 +902,8 @@ void RTCRtpSender::InitializeEncodedVideoStreams(ScriptState* script_state) { + ->GetEncodedVideoStreamTransformer() + : nullptr; + }, +- WrapWeakPersistent(this))); ++ WrapWeakPersistent(this)), ++ webrtc::TransformableFrameInterface::Direction::kSender); + // The high water mark for the stream is set to 1 so that the stream is + // ready to write, but without queuing frames. + WritableStream* writable_stream = diff --git a/patches/chromium/cherry-pick-0894af410c4e.patch b/patches/chromium/cherry-pick-0894af410c4e.patch new file mode 100644 index 0000000000000..0422279c5970d --- /dev/null +++ b/patches/chromium/cherry-pick-0894af410c4e.patch @@ -0,0 +1,385 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Min Qin +Date: Tue, 31 Aug 2021 23:03:03 +0000 +Subject: Quarantine save package items that's downloaded from network + +Currently quarantine is not performed for save page downloads. This CL +fixes the issue. + +BUG=1243020, 811161 + +Change-Id: I85d03cc324b0b90a45bd8b3429e4e9eec1aaf857 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3126709 +Reviewed-by: Xing Liu +Commit-Queue: Min Qin +Cr-Commit-Position: refs/heads/main@{#917013} + +diff --git a/chrome/browser/download/save_page_browsertest.cc b/chrome/browser/download/save_page_browsertest.cc +index b5e3997002f14208e84c0bab2f3fdee17a4962ef..ef21c3d4fc4c425666af4f6fbb6213fa8f79b002 100644 +--- a/chrome/browser/download/save_page_browsertest.cc ++++ b/chrome/browser/download/save_page_browsertest.cc +@@ -49,6 +49,7 @@ + #include "components/prefs/pref_member.h" + #include "components/prefs/pref_service.h" + #include "components/security_state/core/security_state.h" ++#include "components/services/quarantine/test_support.h" + #include "content/public/browser/download_manager.h" + #include "content/public/browser/notification_service.h" + #include "content/public/browser/notification_types.h" +@@ -433,6 +434,10 @@ IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveFileURL) { + EXPECT_TRUE(base::PathExists(full_file_name)); + EXPECT_FALSE(base::PathExists(dir)); + EXPECT_TRUE(base::ContentsEqual(GetTestDirFile("text.txt"), full_file_name)); ++#if defined(OS_WIN) ++ // Local file URL will not be quarantined. ++ EXPECT_FALSE(quarantine::IsFileQuarantined(full_file_name, GURL(), GURL())); ++#endif + } + + IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, +@@ -936,6 +941,25 @@ IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveUnauthorizedResource) { + EXPECT_FALSE(base::PathExists(dir.AppendASCII("should-not-save.jpg"))); + } + ++#if defined(OS_WIN) ++// Save a file and confirm that the file is correctly quarantined. ++IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SaveURLQuarantine) { ++ GURL url = embedded_test_server()->GetURL("/save_page/text.txt"); ++ ui_test_utils::NavigateToURL(browser(), url); ++ ++ base::FilePath full_file_name, dir; ++ SaveCurrentTab(url, content::SAVE_PAGE_TYPE_AS_ONLY_HTML, "test", 1, &dir, ++ &full_file_name); ++ ASSERT_FALSE(HasFailure()); ++ ++ base::ScopedAllowBlockingForTesting allow_blocking; ++ EXPECT_TRUE(base::PathExists(full_file_name)); ++ EXPECT_FALSE(base::PathExists(dir)); ++ EXPECT_TRUE(base::ContentsEqual(GetTestDirFile("text.txt"), full_file_name)); ++ EXPECT_TRUE(quarantine::IsFileQuarantined(full_file_name, url, GURL())); ++} ++#endif ++ + // Test suite that allows testing --site-per-process against cross-site frames. + // See http://dev.chromium.org/developers/design-documents/site-isolation. + class SavePageSitePerProcessBrowserTest : public SavePageBrowserTest { +diff --git a/content/browser/download/download_manager_impl.h b/content/browser/download/download_manager_impl.h +index 69fcf9abbe975ea35a2869f3601958e88aeb5951..0deb3b7c7781a37b47a5a04169ecd2e0ceaed4c8 100644 +--- a/content/browser/download/download_manager_impl.h ++++ b/content/browser/download/download_manager_impl.h +@@ -170,6 +170,11 @@ class CONTENT_EXPORT DownloadManagerImpl + int frame_tree_node_id, + bool from_download_cross_origin_redirect); + ++ // DownloadItemImplDelegate overrides. ++ download::QuarantineConnectionCallback GetQuarantineConnectionCallback() ++ override; ++ std::string GetApplicationClientIdForFileScanning() const override; ++ + private: + using DownloadSet = std::set; + using DownloadGuidMap = +@@ -237,7 +242,6 @@ class CONTENT_EXPORT DownloadManagerImpl + bool ShouldOpenDownload(download::DownloadItemImpl* item, + ShouldOpenDownloadCallback callback) override; + void CheckForFileRemoval(download::DownloadItemImpl* download_item) override; +- std::string GetApplicationClientIdForFileScanning() const override; + void ResumeInterruptedDownload( + std::unique_ptr params, + const GURL& site_url) override; +@@ -249,8 +253,6 @@ class CONTENT_EXPORT DownloadManagerImpl + void ReportBytesWasted(download::DownloadItemImpl* download) override; + void BindWakeLockProvider( + mojo::PendingReceiver receiver) override; +- download::QuarantineConnectionCallback GetQuarantineConnectionCallback() +- override; + std::unique_ptr + GetRenameHandlerForDownload( + download::DownloadItemImpl* download_item) override; +diff --git a/content/browser/download/save_file.cc b/content/browser/download/save_file.cc +index 72331e60fca942820b39580cee5a1890340401ae..110f66250e9608426b26333203e93045f17e9f99 100644 +--- a/content/browser/download/save_file.cc ++++ b/content/browser/download/save_file.cc +@@ -63,10 +63,15 @@ void SaveFile::Finish() { + file_.Finish(); + } + +-void SaveFile::AnnotateWithSourceInformation() { +- // TODO(gbillock): If this method is called, it should set the +- // file_.SetClientGuid() method first. +- NOTREACHED(); ++void SaveFile::AnnotateWithSourceInformation( ++ const std::string& client_guid, ++ const GURL& source_url, ++ const GURL& referrer_url, ++ mojo::PendingRemote remote_quarantine, ++ download::BaseFile::OnAnnotationDoneCallback on_annotation_done_callback) { ++ file_.AnnotateWithSourceInformation(client_guid, source_url, referrer_url, ++ std::move(remote_quarantine), ++ std::move(on_annotation_done_callback)); + } + + base::FilePath SaveFile::FullPath() const { +diff --git a/content/browser/download/save_file.h b/content/browser/download/save_file.h +index 688574b07f9374e75a25caaaa13bdb405aea7b0d..1893a0031f4c6642c6c806577da2246e55e49091 100644 +--- a/content/browser/download/save_file.h ++++ b/content/browser/download/save_file.h +@@ -34,7 +34,12 @@ class SaveFile { + void Detach(); + void Cancel(); + void Finish(); +- void AnnotateWithSourceInformation(); ++ void AnnotateWithSourceInformation( ++ const std::string& client_guid, ++ const GURL& source_url, ++ const GURL& referrer_url, ++ mojo::PendingRemote remote_quarantine, ++ download::BaseFile::OnAnnotationDoneCallback on_annotation_done_callback); + base::FilePath FullPath() const; + bool InProgress() const; + int64_t BytesSoFar() const; +diff --git a/content/browser/download/save_file_manager.cc b/content/browser/download/save_file_manager.cc +index 91786d976f7f637d659468d0700a6c858284dd66..2489b47cf864af0ff184f9250208832c31496698 100644 +--- a/content/browser/download/save_file_manager.cc ++++ b/content/browser/download/save_file_manager.cc +@@ -50,6 +50,7 @@ static SaveFileManager* g_save_file_manager = nullptr; + class SaveFileManager::SimpleURLLoaderHelper + : public network::SimpleURLLoaderStreamConsumer { + public: ++ using URLLoaderCompleteCallback = base::OnceCallback; + static std::unique_ptr CreateAndStartDownload( + std::unique_ptr resource_request, + SaveItemId save_item_id, +@@ -58,11 +59,12 @@ class SaveFileManager::SimpleURLLoaderHelper + int render_frame_routing_id, + const net::NetworkTrafficAnnotationTag& annotation_tag, + network::mojom::URLLoaderFactory* url_loader_factory, +- SaveFileManager* save_file_manager) { ++ SaveFileManager* save_file_manager, ++ URLLoaderCompleteCallback on_complete_cb) { + return std::unique_ptr(new SimpleURLLoaderHelper( + std::move(resource_request), save_item_id, save_package_id, + render_process_id, render_frame_routing_id, annotation_tag, +- url_loader_factory, save_file_manager)); ++ url_loader_factory, save_file_manager, std::move(on_complete_cb))); + } + + ~SimpleURLLoaderHelper() override = default; +@@ -76,10 +78,12 @@ class SaveFileManager::SimpleURLLoaderHelper + int render_frame_routing_id, + const net::NetworkTrafficAnnotationTag& annotation_tag, + network::mojom::URLLoaderFactory* url_loader_factory, +- SaveFileManager* save_file_manager) ++ SaveFileManager* save_file_manager, ++ URLLoaderCompleteCallback on_complete_cb) + : save_file_manager_(save_file_manager), + save_item_id_(save_item_id), +- save_package_id_(save_package_id) { ++ save_package_id_(save_package_id), ++ on_complete_cb_(std::move(on_complete_cb)) { + GURL url = resource_request->url; + url_loader_ = network::SimpleURLLoader::Create(std::move(resource_request), + annotation_tag); +@@ -124,9 +128,7 @@ class SaveFileManager::SimpleURLLoaderHelper + + void OnComplete(bool success) override { + download::GetDownloadTaskRunner()->PostTask( +- FROM_HERE, +- base::BindOnce(&SaveFileManager::SaveFinished, save_file_manager_, +- save_item_id_, save_package_id_, success)); ++ FROM_HERE, base::BindOnce(std::move(on_complete_cb_), success)); + } + + void OnRetry(base::OnceClosure start_retry) override { +@@ -138,6 +140,7 @@ class SaveFileManager::SimpleURLLoaderHelper + SaveItemId save_item_id_; + SavePackageId save_package_id_; + std::unique_ptr url_loader_; ++ URLLoaderCompleteCallback on_complete_cb_; + + DISALLOW_COPY_AND_ASSIGN(SimpleURLLoaderHelper); + }; +@@ -188,17 +191,20 @@ SavePackage* SaveFileManager::LookupPackage(SaveItemId save_item_id) { + } + + // Call from SavePackage for starting a saving job +-void SaveFileManager::SaveURL(SaveItemId save_item_id, +- const GURL& url, +- const Referrer& referrer, +- int render_process_host_id, +- int render_view_routing_id, +- int render_frame_routing_id, +- SaveFileCreateInfo::SaveFileSource save_source, +- const base::FilePath& file_full_path, +- BrowserContext* context, +- StoragePartition* storage_partition, +- SavePackage* save_package) { ++void SaveFileManager::SaveURL( ++ SaveItemId save_item_id, ++ const GURL& url, ++ const Referrer& referrer, ++ int render_process_host_id, ++ int render_view_routing_id, ++ int render_frame_routing_id, ++ SaveFileCreateInfo::SaveFileSource save_source, ++ const base::FilePath& file_full_path, ++ BrowserContext* context, ++ StoragePartition* storage_partition, ++ SavePackage* save_package, ++ const std::string& client_guid, ++ mojo::PendingRemote remote_quarantine) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + + // Insert started saving job to tracking list. +@@ -285,11 +291,18 @@ void SaveFileManager::SaveURL(SaveItemId save_item_id, + factory = storage_partition->GetURLLoaderFactoryForBrowserProcess().get(); + } + ++ base::OnceCallback save_finished_cb = ++ base::BindOnce(&SaveFileManager::OnURLLoaderComplete, this, ++ save_item_id, save_package->id(), ++ context->IsOffTheRecord() ? GURL() : url, ++ context->IsOffTheRecord() ? GURL() : referrer.url, ++ client_guid, std::move(remote_quarantine)); ++ + url_loader_helpers_[save_item_id] = + SimpleURLLoaderHelper::CreateAndStartDownload( + std::move(request), save_item_id, save_package->id(), + render_process_host_id, render_frame_routing_id, traffic_annotation, +- factory, this); ++ factory, this, std::move(save_finished_cb)); + } else { + // We manually start the save job. + auto info = std::make_unique( +@@ -344,6 +357,36 @@ void SaveFileManager::SendCancelRequest(SaveItemId save_item_id) { + base::BindOnce(&SaveFileManager::CancelSave, this, save_item_id)); + } + ++void SaveFileManager::OnURLLoaderComplete( ++ SaveItemId save_item_id, ++ SavePackageId save_package_id, ++ const GURL& url, ++ const GURL& referrer_url, ++ const std::string& client_guid, ++ mojo::PendingRemote remote_quarantine, ++ bool is_success) { ++ DCHECK(download::GetDownloadTaskRunner()->RunsTasksInCurrentSequence()); ++ SaveFile* save_file = LookupSaveFile(save_item_id); ++ if (!is_success || !save_file) { ++ SaveFinished(save_item_id, save_package_id, is_success); ++ return; ++ } ++ ++ save_file->AnnotateWithSourceInformation( ++ client_guid, url, referrer_url, std::move(remote_quarantine), ++ base::BindOnce(&SaveFileManager::OnQuarantineComplete, this, save_item_id, ++ save_package_id)); ++} ++ ++void SaveFileManager::OnQuarantineComplete( ++ SaveItemId save_item_id, ++ SavePackageId save_package_id, ++ download::DownloadInterruptReason result) { ++ DCHECK(download::GetDownloadTaskRunner()->RunsTasksInCurrentSequence()); ++ SaveFinished(save_item_id, save_package_id, ++ result == download::DOWNLOAD_INTERRUPT_REASON_NONE); ++} ++ + // Notifications sent from the IO thread and run on the file thread: + + // The IO thread created |info|, but the file thread (this method) uses it +diff --git a/content/browser/download/save_file_manager.h b/content/browser/download/save_file_manager.h +index 51eb63a9b189be388e4dff48e04644956e968345..0d4290b273ba4f150bc9a49418e54b709a601581 100644 +--- a/content/browser/download/save_file_manager.h ++++ b/content/browser/download/save_file_manager.h +@@ -61,6 +61,8 @@ + + #include "base/macros.h" + #include "base/memory/ref_counted.h" ++#include "components/download/public/common/download_interrupt_reasons.h" ++#include "components/services/quarantine/quarantine.h" + #include "content/browser/download/save_types.h" + #include "content/common/content_export.h" + +@@ -90,17 +92,20 @@ class CONTENT_EXPORT SaveFileManager + + // Saves the specified URL |url|. |save_package| must not be deleted before + // the call to RemoveSaveFile. Should be called on the UI thread, +- void SaveURL(SaveItemId save_item_id, +- const GURL& url, +- const Referrer& referrer, +- int render_process_host_id, +- int render_view_routing_id, +- int render_frame_routing_id, +- SaveFileCreateInfo::SaveFileSource save_source, +- const base::FilePath& file_full_path, +- BrowserContext* context, +- StoragePartition* storage_partition, +- SavePackage* save_package); ++ void SaveURL( ++ SaveItemId save_item_id, ++ const GURL& url, ++ const Referrer& referrer, ++ int render_process_host_id, ++ int render_view_routing_id, ++ int render_frame_routing_id, ++ SaveFileCreateInfo::SaveFileSource save_source, ++ const base::FilePath& file_full_path, ++ BrowserContext* context, ++ StoragePartition* storage_partition, ++ SavePackage* save_package, ++ const std::string& client_guid, ++ mojo::PendingRemote remote_quarantine); + + // Notifications sent from the IO thread and run on the file thread: + void StartSave(std::unique_ptr info); +@@ -159,6 +164,21 @@ class CONTENT_EXPORT SaveFileManager + // Help function for sending notification of canceling specific request. + void SendCancelRequest(SaveItemId save_item_id); + ++ // Called on the file thread when the URLLoader completes saving a SaveItem. ++ void OnURLLoaderComplete( ++ SaveItemId save_item_id, ++ SavePackageId save_package_id, ++ const GURL& url, ++ const GURL& referrer_url, ++ const std::string& client_guid, ++ mojo::PendingRemote remote_quarantine, ++ bool is_success); ++ ++ // Called on the file thread when file quarantine finishes on a SaveItem. ++ void OnQuarantineComplete(SaveItemId save_item_id, ++ SavePackageId save_package_id, ++ download::DownloadInterruptReason result); ++ + // Notifications sent from the file thread and run on the UI thread. + + // Lookup the SaveManager for this WebContents' saving browser context and +diff --git a/content/browser/download/save_package.cc b/content/browser/download/save_package.cc +index 4ceea290dcc9b886fb2c65be4ff684854a0f131f..c4653492c8332201f1f6eeb2ce7dbd7fb20c7cc3 100644 +--- a/content/browser/download/save_package.cc ++++ b/content/browser/download/save_package.cc +@@ -843,6 +843,12 @@ void SavePackage::SaveNextFile(bool process_all_remaining_items) { + RenderFrameHostImpl* requester_frame = + requester_frame_tree_node->current_frame_host(); + ++ mojo::PendingRemote quarantine; ++ auto quarantine_callback = ++ download_manager_->GetQuarantineConnectionCallback(); ++ if (quarantine_callback) ++ quarantine_callback.Run(quarantine.InitWithNewPipeAndPassReceiver()); ++ + file_manager_->SaveURL( + save_item_ptr->id(), save_item_ptr->url(), save_item_ptr->referrer(), + requester_frame->GetProcess()->GetID(), +@@ -854,8 +860,8 @@ void SavePackage::SaveNextFile(bool process_all_remaining_items) { + ->GetRenderViewHost() + ->GetProcess() + ->GetStoragePartition(), +- this); +- ++ this, download_manager_->GetApplicationClientIdForFileScanning(), ++ std::move(quarantine)); + } while (process_all_remaining_items && !waiting_item_queue_.empty()); + } + diff --git a/patches/chromium/cherry-pick-096afc1c5428.patch b/patches/chromium/cherry-pick-096afc1c5428.patch new file mode 100644 index 0000000000000..652f651daeb94 --- /dev/null +++ b/patches/chromium/cherry-pick-096afc1c5428.patch @@ -0,0 +1,106 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Rayan Kanso +Date: Tue, 7 Sep 2021 20:14:30 +0000 +Subject: Use less-specific error codes for CORS-failing fetches + +(cherry picked from commit 26be5702dab1d98e4d4b076a73d4688d20c043be) + +Bug: 1245053 +Change-Id: If0343157a3ba41a6c946b5f7401a9d114f834779 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3135676 +Commit-Queue: Rayan Kanso +Reviewed-by: Richard Knoll +Cr-Original-Commit-Position: refs/heads/main@{#918109} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3143786 +Commit-Queue: Richard Knoll +Cr-Commit-Position: refs/branch-heads/4606@{#833} +Cr-Branched-From: 35b0d5a9dc8362adfd44e2614f0d5b7402ef63d0-refs/heads/master@{#911515} + +diff --git a/content/browser/background_fetch/background_fetch_job_controller.cc b/content/browser/background_fetch/background_fetch_job_controller.cc +index f424cadba0f42ce007c85a50b2bdb37a3a3a3499..0d08d1f744edd432c9615be811a60daff3b3c541 100644 +--- a/content/browser/background_fetch/background_fetch_job_controller.cc ++++ b/content/browser/background_fetch/background_fetch_job_controller.cc +@@ -173,6 +173,8 @@ void BackgroundFetchJobController::DidStartRequest( + // TODO(crbug.com/884672): Stop the fetch if the cross origin filter fails. + BackgroundFetchCrossOriginFilter filter(registration_id_.origin(), *request); + request->set_can_populate_body(filter.CanPopulateBody()); ++ if (!request->can_populate_body()) ++ has_failed_cors_request_ = true; + } + + void BackgroundFetchJobController::DidUpdateRequest(const std::string& guid, +@@ -253,7 +255,14 @@ uint64_t BackgroundFetchJobController::GetInProgressUploadedBytes() { + + void BackgroundFetchJobController::AbortFromDelegate( + BackgroundFetchFailureReason failure_reason) { +- failure_reason_ = failure_reason; ++ if (failure_reason == BackgroundFetchFailureReason::DOWNLOAD_TOTAL_EXCEEDED && ++ has_failed_cors_request_) { ++ // Don't expose that the download total has been exceeded. Use a less ++ // specific error. ++ failure_reason_ = BackgroundFetchFailureReason::FETCH_ERROR; ++ } else { ++ failure_reason_ = failure_reason; ++ } + + Finish(failure_reason_, base::DoNothing()); + } +diff --git a/content/browser/background_fetch/background_fetch_job_controller.h b/content/browser/background_fetch/background_fetch_job_controller.h +index e635c86c1eb4237e2b107e3d6fae0242e99dcb4c..66a1c94e9dd79663fbc301c1c91918ef4ac67036 100644 +--- a/content/browser/background_fetch/background_fetch_job_controller.h ++++ b/content/browser/background_fetch/background_fetch_job_controller.h +@@ -210,6 +210,10 @@ class CONTENT_EXPORT BackgroundFetchJobController + blink::mojom::BackgroundFetchFailureReason failure_reason_ = + blink::mojom::BackgroundFetchFailureReason::NONE; + ++ // Whether one of the requests handled by the controller failed ++ // the CORS checks and should not have its response exposed. ++ bool has_failed_cors_request_ = false; ++ + // Custom callback that runs after the controller is finished. + FinishedCallback finished_callback_; + +diff --git a/content/browser/background_fetch/background_fetch_job_controller_unittest.cc b/content/browser/background_fetch/background_fetch_job_controller_unittest.cc +index ad9a31367250f90e5579525f42b8b1bde2eefbb1..eb0e8fc337061181d7764eb03bc420df12528c1a 100644 +--- a/content/browser/background_fetch/background_fetch_job_controller_unittest.cc ++++ b/content/browser/background_fetch/background_fetch_job_controller_unittest.cc +@@ -433,6 +433,39 @@ TEST_F(BackgroundFetchJobControllerTest, Abort) { + GetCompletionStatus(registration_id)); + } + ++TEST_F(BackgroundFetchJobControllerTest, AbortDownloadExceededCrossOrigin) { ++ BackgroundFetchRegistrationId registration_id; ++ ++ auto requests = CreateRegistrationForRequests( ++ ®istration_id, {{GURL("https://example2.com/funny_cat.png"), "GET"}}, ++ /* auto_complete_requests= */ true); ++ ++ EXPECT_EQ(JobCompletionStatus::kRunning, ++ GetCompletionStatus(registration_id)); ++ ++ std::unique_ptr controller = ++ CreateJobController(registration_id, requests.size()); ++ ++ controller->StartRequest(requests[0], base::DoNothing()); ++ ++ controller->DidStartRequest( ++ requests[0]->download_guid(), ++ std::make_unique( ++ std::vector{GURL("https://example2.com/funny_cat.png")}, ++ nullptr)); ++ EXPECT_FALSE(requests[0]->can_populate_body()); ++ ++ controller->AbortFromDelegate( ++ blink::mojom::BackgroundFetchFailureReason::DOWNLOAD_TOTAL_EXCEEDED); ++ ++ base::RunLoop().RunUntilIdle(); ++ ++ EXPECT_EQ(JobCompletionStatus::kAborted, ++ GetCompletionStatus(registration_id)); ++ EXPECT_EQ(finished_requests_[registration_id], ++ blink::mojom::BackgroundFetchFailureReason::FETCH_ERROR); ++} ++ + TEST_F(BackgroundFetchJobControllerTest, Progress) { + BackgroundFetchRegistrationId registration_id; + diff --git a/patches/chromium/cherry-pick-1a8af2da50e4.patch b/patches/chromium/cherry-pick-1a8af2da50e4.patch new file mode 100644 index 0000000000000..1641727627a49 --- /dev/null +++ b/patches/chromium/cherry-pick-1a8af2da50e4.patch @@ -0,0 +1,354 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Lukasz Anforowicz +Date: Mon, 8 Nov 2021 15:05:30 +0000 +Subject: Deleting unused field: `FetchEventPreloadHandle::url_loader`. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The `FetchEventPreloadHandle::url_loader` field is not really used - it +is only needed to keep the URLLoader alive (and this can be accomplished +in a simpler way, by keeping the mojo::PendingRemote in the Browser +process). + +This CL removes the `FetchEventPreloadHandle::url_loader` field and the +FetchEventPreloadHandle and WebFetchEventPreloadHandle types (collapsing +these handle types into their only other remaining field: +mojo::PendingReceiver). + +(cherry picked from commit dbe67ccde52e30acf6a66b1b9cc83768a067fa6a) + +Fixed: 1264477 +Change-Id: I9c9c54900d79e92ac08eeb43536c938fa84a58f8 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3252914 +Reviewed-by: Daniel Cheng +Reviewed-by: Ben Kelly +Reviewed-by: Hiroki Nakagawa +Commit-Queue: Łukasz Anforowicz +Cr-Original-Commit-Position: refs/heads/main@{#937895} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3262600 +Bot-Commit: Rubber Stamper +Commit-Queue: Ben Kelly +Cr-Commit-Position: refs/branch-heads/4664@{#853} +Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512} + +diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.cc b/content/browser/service_worker/service_worker_fetch_dispatcher.cc +index 99753b0b4ba8039818da8732ffc4f03bf0690f81..c0c6f1ecafeaa3dfc211c09e52c9792fe343aadf 100644 +--- a/content/browser/service_worker/service_worker_fetch_dispatcher.cc ++++ b/content/browser/service_worker/service_worker_fetch_dispatcher.cc +@@ -449,8 +449,10 @@ class ServiceWorkerFetchDispatcher::URLLoaderAssets + // NetworkService. + URLLoaderAssets( + scoped_refptr shared_url_loader_factory, ++ mojo::PendingRemote url_loader, + std::unique_ptr url_loader_client) + : shared_url_loader_factory_(std::move(shared_url_loader_factory)), ++ url_loader_(std::move(url_loader)), + url_loader_client_(std::move(url_loader_client)) {} + + void MaybeReportToDevTools(std::pair worker_id, +@@ -467,6 +469,7 @@ class ServiceWorkerFetchDispatcher::URLLoaderAssets + + // NetworkService: + scoped_refptr shared_url_loader_factory_; ++ mojo::PendingRemote url_loader_; + + // Both: + std::unique_ptr url_loader_client_; +@@ -625,7 +628,8 @@ void ServiceWorkerFetchDispatcher::DispatchFetchEvent() { + auto params = blink::mojom::DispatchFetchEventParams::New(); + params->request = std::move(request_); + params->client_id = client_id_; +- params->preload_handle = std::move(preload_handle_); ++ params->preload_url_loader_client_receiver = ++ std::move(preload_url_loader_client_receiver_); + params->is_offline_capability_check = is_offline_capability_check_; + + // TODO(https://crbug.com/900700): Make the remote connected to a receiver +@@ -710,13 +714,9 @@ bool ServiceWorkerFetchDispatcher::MaybeStartNavigationPreload( + // When the fetch event is for an offline capability check, respond to the + // navigation preload with a network disconnected error, to simulate offline. + if (is_offline_capability_check_) { +- mojo::PendingRemote url_loader_to_pass; + mojo::Remote url_loader_client; +- auto dummy_receiver = url_loader_to_pass.InitWithNewPipeAndPassReceiver(); + +- preload_handle_ = blink::mojom::FetchEventPreloadHandle::New(); +- preload_handle_->url_loader = std::move(url_loader_to_pass); +- preload_handle_->url_loader_client_receiver = ++ preload_url_loader_client_receiver_ = + url_loader_client.BindNewPipeAndPassReceiver(); + + url_loader_client->OnComplete( +@@ -755,12 +755,10 @@ bool ServiceWorkerFetchDispatcher::MaybeStartNavigationPreload( + factory = base::MakeRefCounted( + std::move(network_factory)); + +- preload_handle_ = blink::mojom::FetchEventPreloadHandle::New(); +- + // Create the DelegatingURLLoaderClient, which becomes the + // URLLoaderClient for the navigation preload network request. + mojo::PendingRemote inner_url_loader_client; +- preload_handle_->url_loader_client_receiver = ++ preload_url_loader_client_receiver_ = + inner_url_loader_client.InitWithNewPipeAndPassReceiver(); + auto url_loader_client = std::make_unique( + std::move(inner_url_loader_client), resource_request); +@@ -795,11 +793,9 @@ bool ServiceWorkerFetchDispatcher::MaybeStartNavigationPreload( + net::MutableNetworkTrafficAnnotationTag( + kNavigationPreloadTrafficAnnotation)); + +- preload_handle_->url_loader = std::move(url_loader); +- + DCHECK(!url_loader_assets_); + url_loader_assets_ = base::MakeRefCounted( +- std::move(factory), std::move(url_loader_client)); ++ std::move(factory), std::move(url_loader), std::move(url_loader_client)); + return true; + } + +diff --git a/content/browser/service_worker/service_worker_fetch_dispatcher.h b/content/browser/service_worker/service_worker_fetch_dispatcher.h +index d436dbfba3504a1ab3878def051ca12b73affbe4..056b1ec4394189e0b6b1a9ad0fd87cfffb4de374 100644 +--- a/content/browser/service_worker/service_worker_fetch_dispatcher.h ++++ b/content/browser/service_worker/service_worker_fetch_dispatcher.h +@@ -123,10 +123,11 @@ class CONTENT_EXPORT ServiceWorkerFetchDispatcher { + + scoped_refptr url_loader_assets_; + +- // |preload_handle_| holds the URLLoader and URLLoaderClient for the service +- // worker to receive the navigation preload response. It's passed to the +- // service worker along with the fetch event. +- blink::mojom::FetchEventPreloadHandlePtr preload_handle_; ++ // Holds the URLLoaderClient for the service worker to receive the navigation ++ // preload response. It's passed to the service worker along with the fetch ++ // event. ++ mojo::PendingReceiver ++ preload_url_loader_client_receiver_; + + // Whether to dispatch an offline-capability-check fetch event. + const bool is_offline_capability_check_ = false; +diff --git a/content/renderer/service_worker/navigation_preload_request.cc b/content/renderer/service_worker/navigation_preload_request.cc +index 231e947e1592e85d41fa243cdff143065e604199..0e8d77666ede84b94b1a2cbb5eb15dac1a5bb96f 100644 +--- a/content/renderer/service_worker/navigation_preload_request.cc ++++ b/content/renderer/service_worker/navigation_preload_request.cc +@@ -17,12 +17,12 @@ NavigationPreloadRequest::NavigationPreloadRequest( + ServiceWorkerContextClient* owner, + int fetch_event_id, + const GURL& url, +- blink::mojom::FetchEventPreloadHandlePtr preload_handle) ++ mojo::PendingReceiver ++ preload_url_loader_client_receiver) + : owner_(owner), + fetch_event_id_(fetch_event_id), + url_(url), +- url_loader_(std::move(preload_handle->url_loader)), +- receiver_(this, std::move(preload_handle->url_loader_client_receiver)) {} ++ receiver_(this, std::move(preload_url_loader_client_receiver)) {} + + NavigationPreloadRequest::~NavigationPreloadRequest() = default; + +diff --git a/content/renderer/service_worker/navigation_preload_request.h b/content/renderer/service_worker/navigation_preload_request.h +index 639cc6f086d36cab3081c1b7621f1cf20a3379d0..fc9c5c66b4111cffd918974f538b6a7f3699c192 100644 +--- a/content/renderer/service_worker/navigation_preload_request.h ++++ b/content/renderer/service_worker/navigation_preload_request.h +@@ -34,7 +34,8 @@ class NavigationPreloadRequest final : public network::mojom::URLLoaderClient { + ServiceWorkerContextClient* owner, + int fetch_event_id, + const GURL& url, +- blink::mojom::FetchEventPreloadHandlePtr preload_handle); ++ mojo::PendingReceiver ++ preload_url_loader_client_receiver); + ~NavigationPreloadRequest() override; + + // network::mojom::URLLoaderClient: +@@ -58,11 +59,10 @@ class NavigationPreloadRequest final : public network::mojom::URLLoaderClient { + void ReportErrorToOwner(const std::string& message, + blink::WebServiceWorkerError::Mode error_mode); + +- ServiceWorkerContextClient* owner_; ++ ServiceWorkerContextClient* owner_ = nullptr; + +- const int fetch_event_id_; ++ const int fetch_event_id_ = -1; + const GURL url_; +- mojo::Remote url_loader_; + mojo::Receiver receiver_; + + std::unique_ptr response_; +diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc +index 79334c2ebf7fd0000d98a2c73504b48ca1e8673c..9a1e9a6594ef35deee1aec354ccb8eec7b3308e2 100644 +--- a/content/renderer/service_worker/service_worker_context_client.cc ++++ b/content/renderer/service_worker/service_worker_context_client.cc +@@ -475,14 +475,14 @@ void ServiceWorkerContextClient::SendWorkerStarted( + void ServiceWorkerContextClient::SetupNavigationPreload( + int fetch_event_id, + const blink::WebURL& url, +- std::unique_ptr preload_handle) { ++ blink::CrossVariantMojoReceiver< ++ network::mojom::URLLoaderClientInterfaceBase> ++ preload_url_loader_client_receiver) { + DCHECK(worker_task_runner_->RunsTasksInCurrentSequence()); + DCHECK(context_); + auto preload_request = std::make_unique( + this, fetch_event_id, GURL(url), +- blink::mojom::FetchEventPreloadHandle::New( +- std::move(preload_handle->url_loader), +- std::move(preload_handle->url_loader_client_receiver))); ++ std::move(preload_url_loader_client_receiver)); + context_->preload_requests.AddWithID(std::move(preload_request), + fetch_event_id); + } +diff --git a/content/renderer/service_worker/service_worker_context_client.h b/content/renderer/service_worker/service_worker_context_client.h +index 8191aaec6ed37c6a64bcbd9beac720777de3075e..5abd533c6c3b1926efa6b8fc158562468cc96e19 100644 +--- a/content/renderer/service_worker/service_worker_context_client.h ++++ b/content/renderer/service_worker/service_worker_context_client.h +@@ -159,8 +159,9 @@ class CONTENT_EXPORT ServiceWorkerContextClient + const blink::WebString& source_url) override; + void SetupNavigationPreload(int fetch_event_id, + const blink::WebURL& url, +- std::unique_ptr +- preload_handle) override; ++ blink::CrossVariantMojoReceiver< ++ network::mojom::URLLoaderClientInterfaceBase> ++ preload_url_loader_client_receiver) override; + void RequestTermination(RequestTerminationCallback callback) override; + scoped_refptr + CreateWorkerFetchContextOnInitiatorThread() override; +diff --git a/mojo/public/cpp/bindings/README.md b/mojo/public/cpp/bindings/README.md +index 05581aa626490e6c8b4c9b1b38da2d833312ee87..d3ecb7e55a8618b0976e5a3bcffa8b13ec3c2f4f 100644 +--- a/mojo/public/cpp/bindings/README.md ++++ b/mojo/public/cpp/bindings/README.md +@@ -1709,6 +1709,9 @@ C++ sources can depend on shared sources only, by referencing the + `"${target_name}_shared"` target, e.g. `"//foo/mojom:mojom_shared"` in the + example above. + ++For converting between Blink and non-Blink variants, please see ++`//third_party/blink/public/platform/cross_variant_mojo_util.h`. ++ + ## Versioning Considerations + + For general documentation of versioning in the Mojom IDL see +diff --git a/third_party/blink/public/mojom/service_worker/dispatch_fetch_event_params.mojom b/third_party/blink/public/mojom/service_worker/dispatch_fetch_event_params.mojom +index 382be0b3dd042ceadb73e4d514f93ac7c8624b43..c95a2e255166871ff45b6a4c3a8b206e1dace776 100644 +--- a/third_party/blink/public/mojom/service_worker/dispatch_fetch_event_params.mojom ++++ b/third_party/blink/public/mojom/service_worker/dispatch_fetch_event_params.mojom +@@ -9,13 +9,6 @@ import "third_party/blink/public/mojom/blob/blob.mojom"; + import "third_party/blink/public/mojom/fetch/fetch_api_request.mojom"; + import "third_party/blink/public/mojom/timing/worker_timing_container.mojom"; + +-// Used for service worker navigation preload, to create +-// FetchEvent#preloadResponse. +-struct FetchEventPreloadHandle { +- pending_remote url_loader; +- pending_receiver url_loader_client_receiver; +-}; +- + // Parameters used for dispatching a FetchEvent. + struct DispatchFetchEventParams { + // FetchEvent#request. +@@ -23,8 +16,9 @@ struct DispatchFetchEventParams { + + // FetchEvent#clientId. + string client_id; ++ + // FetchEvent#preloadResponse. +- FetchEventPreloadHandle? preload_handle; ++ pending_receiver? preload_url_loader_client_receiver; + + // This is currently null for navigation because it's still being implemented. + // TODO(https://crbug.com/900700): Make this non-nullable when implementation +diff --git a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h +index 48e3e7ecec672b9993dd504a3ac2a681db6284d5..ad64e9ba7fe05a457de6a79c59b4a6fe6bba711d 100644 +--- a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h ++++ b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h +@@ -31,8 +31,6 @@ + #ifndef THIRD_PARTY_BLINK_PUBLIC_WEB_MODULES_SERVICE_WORKER_WEB_SERVICE_WORKER_CONTEXT_CLIENT_H_ + #define THIRD_PARTY_BLINK_PUBLIC_WEB_MODULES_SERVICE_WORKER_WEB_SERVICE_WORKER_CONTEXT_CLIENT_H_ + +-#include +- + #include "base/memory/scoped_refptr.h" + #include "base/time/time.h" + #include "services/network/public/mojom/url_loader.mojom-shared.h" +@@ -54,14 +52,6 @@ namespace blink { + class WebServiceWorkerContextProxy; + class WebString; + +-// Used to pass the mojom struct blink.mojom.FetchEventPreloadHandle across the +-// boundary between //content and Blink. +-struct WebFetchEventPreloadHandle { +- CrossVariantMojoRemote url_loader; +- CrossVariantMojoReceiver +- url_loader_client_receiver; +-}; +- + // WebServiceWorkerContextClient is a "client" of a service worker execution + // context. This interface is implemented by the embedder and allows the + // embedder to communicate with the service worker execution context. It is +@@ -167,7 +157,8 @@ class WebServiceWorkerContextClient { + virtual void SetupNavigationPreload( + int fetch_event_id, + const WebURL& url, +- std::unique_ptr preload_handle) {} ++ CrossVariantMojoReceiver ++ preload_url_loader_client_receiver) {} + + // Called when we need to request to terminate this worker due to idle + // timeout. +diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc +index db4dcc7ad467e0012e08f8d81753f48ff29b27e8..6efa02fad3e7ba78404a92bea25d41a955ed7d80 100644 +--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc ++++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc +@@ -1508,11 +1508,12 @@ void ServiceWorkerGlobalScope::StartFetchEvent( + params->request->url.ElidedString().Utf8()); + + // Set up for navigation preload (FetchEvent#preloadResponse) if needed. +- const bool navigation_preload_sent = !!params->preload_handle; ++ bool navigation_preload_sent = !!params->preload_url_loader_client_receiver; + if (navigation_preload_sent) { + To(ReportingProxy()) +- .SetupNavigationPreload(event_id, params->request->url, +- std::move(params->preload_handle)); ++ .SetupNavigationPreload( ++ event_id, params->request->url, ++ std::move(params->preload_url_loader_client_receiver)); + } + + ScriptState::Scope scope(ScriptController()->GetScriptState()); +diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc +index 397d579ed76c72612e5e5ec2877ccea18fe5ea12..bae1f3ac2ae68d8d818adaeee71b642a37c32228 100644 +--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc ++++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc +@@ -258,14 +258,11 @@ bool ServiceWorkerGlobalScopeProxy::IsServiceWorkerGlobalScopeProxy() const { + void ServiceWorkerGlobalScopeProxy::SetupNavigationPreload( + int fetch_event_id, + const KURL& url, +- mojom::blink::FetchEventPreloadHandlePtr preload_handle) { ++ mojo::PendingReceiver ++ preload_url_loader_client_receiver) { + DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_); +- auto web_preload_handle = std::make_unique(); +- web_preload_handle->url_loader = std::move(preload_handle->url_loader); +- web_preload_handle->url_loader_client_receiver = +- std::move(preload_handle->url_loader_client_receiver); +- Client().SetupNavigationPreload(fetch_event_id, url, +- std::move(web_preload_handle)); ++ Client().SetupNavigationPreload( ++ fetch_event_id, url, std::move(preload_url_loader_client_receiver)); + } + + void ServiceWorkerGlobalScopeProxy::RequestTermination( +diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h +index 783dbe1919d1282f40117aea22b75a8e54e82d89..d54a2449da63f67930cb3d85cfbb27c35c45a8d3 100644 +--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h ++++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.h +@@ -129,7 +129,8 @@ class ServiceWorkerGlobalScopeProxy final : public WebServiceWorkerContextProxy, + void SetupNavigationPreload( + int fetch_event_id, + const KURL& url, +- mojom::blink::FetchEventPreloadHandlePtr preload_handle); ++ mojo::PendingReceiver ++ preload_url_loader_client_receiver); + void RequestTermination(WTF::CrossThreadOnceFunction callback); + + // Detaches this proxy object entirely from the outside world, clearing out diff --git a/patches/chromium/cherry-pick-27eb11a28555.patch b/patches/chromium/cherry-pick-27eb11a28555.patch new file mode 100644 index 0000000000000..e8085626605cb --- /dev/null +++ b/patches/chromium/cherry-pick-27eb11a28555.patch @@ -0,0 +1,71 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Yutaka Hirano +Date: Wed, 29 Sep 2021 07:58:26 +0000 +Subject: Run CORS check for manual redirects + +...to prevent status code leak. + +Bug: 1251179 +Change-Id: I7fcab0daf49e16305ed53702f42d1d1eacc933e5 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3193481 +Reviewed-by: Yoav Weiss +Commit-Queue: Yutaka Hirano +Cr-Commit-Position: refs/heads/main@{#926166} + +diff --git a/services/network/cors/cors_url_loader.cc b/services/network/cors/cors_url_loader.cc +index bc60ad917243aae143c9de16670f10358ff98689..2eaa10e4763745ff434ac249b92d353d0dd82a69 100644 +--- a/services/network/cors/cors_url_loader.cc ++++ b/services/network/cors/cors_url_loader.cc +@@ -300,13 +300,6 @@ void CorsURLLoader::OnReceiveRedirect(const net::RedirectInfo& redirect_info, + DCHECK(forwarding_client_); + DCHECK(!deferred_redirect_url_); + +- if (request_.redirect_mode == mojom::RedirectMode::kManual) { +- deferred_redirect_url_ = std::make_unique(redirect_info.new_url); +- forwarding_client_->OnReceiveRedirect(redirect_info, +- std::move(response_head)); +- return; +- } +- + // If |CORS flag| is set and a CORS check for |request| and |response| returns + // failure, then return a network error. + if (fetch_cors_flag_ && IsCorsEnabledRequestMode(request_.mode)) { +@@ -324,6 +317,13 @@ void CorsURLLoader::OnReceiveRedirect(const net::RedirectInfo& redirect_info, + } + } + ++ if (request_.redirect_mode == mojom::RedirectMode::kManual) { ++ deferred_redirect_url_ = std::make_unique(redirect_info.new_url); ++ forwarding_client_->OnReceiveRedirect(redirect_info, ++ std::move(response_head)); ++ return; ++ } ++ + timing_allow_failed_flag_ = !PassesTimingAllowOriginCheck(*response_head); + + // Because we initiate a new request on redirect in some cases, we cannot +diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-mode.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-mode.any.js +index eed44e0414cb8947c9b7c21df6ef288f733f8994..9f1ff98c65af97bcf185867ac6c6e128dbd77715 100644 +--- a/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-mode.any.js ++++ b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-mode.any.js +@@ -1,6 +1,7 @@ + // META: script=/common/get-host-info.sub.js + + var redirectLocation = "cors-top.txt"; ++const { ORIGIN, REMOTE_ORIGIN } = get_host_info(); + + function testRedirect(origin, redirectStatus, redirectMode, corsMode) { + var url = new URL("../resources/redirect.py", self.location); +@@ -47,4 +48,12 @@ for (var origin of ["same-origin", "cross-origin"]) { + } + } + ++promise_test(async (t) => { ++ const destination = `${ORIGIN}/common/blank.html`; ++ // We use /common/redirect.py intentionally, as we want a CORS error. ++ const url = ++ `${REMOTE_ORIGIN}/common/redirect.py?location=${destination}`; ++ await promise_rejects_js(t, TypeError, fetch(url, { redirect: "manual" })); ++}, "manual redirect with a CORS error should be rejected"); ++ + done(); diff --git a/patches/chromium/cherry-pick-3a5bafa35def.patch b/patches/chromium/cherry-pick-3a5bafa35def.patch new file mode 100644 index 0000000000000..6a2b2d8759e5a --- /dev/null +++ b/patches/chromium/cherry-pick-3a5bafa35def.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Alex Gough +Date: Fri, 1 Oct 2021 23:30:09 +0000 +Subject: Tell clang not to devirtualize TargetServices + +Before this change in official builds a child process's delayed +integrity level was not being set correctly. With this change +renderers run at Untrusted IL as intended. + +(cherry picked from commit 19d2be5d47e0edc406ef7d93096f54009e47937f) + +Tests: https://bugs.chromium.org/p/chromium/issues/detail?id=1254631#c13 +Bug: 1254631 +Change-Id: I52c149cca3de5218033ed0f37d9f76782b9a6302 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3198382 +Reviewed-by: Will Harris +Commit-Queue: Will Harris +Cr-Original-Commit-Position: refs/heads/main@{#926934} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3200146 +Commit-Queue: Alex Gough +Cr-Commit-Position: refs/branch-heads/4606@{#1285} +Cr-Branched-From: 35b0d5a9dc8362adfd44e2614f0d5b7402ef63d0-refs/heads/master@{#911515} + +diff --git a/sandbox/win/src/sandbox.h b/sandbox/win/src/sandbox.h +index 9dfebfcc1721a2c2c34397666976e67b78812d7b..d4ab27f084aeb1b9db54eacf227250cf2364c4e2 100644 +--- a/sandbox/win/src/sandbox.h ++++ b/sandbox/win/src/sandbox.h +@@ -140,7 +140,7 @@ class BrokerServices { + // } + // + // For more information see the BrokerServices API documentation. +-class TargetServices { ++class [[clang::lto_visibility_public]] TargetServices { + public: + // Initializes the target. Must call this function before any other. + // returns ALL_OK if successful. All other return values imply failure. diff --git a/patches/chromium/cherry-pick-4e528a5a8d83.patch b/patches/chromium/cherry-pick-4e528a5a8d83.patch new file mode 100644 index 0000000000000..1c4f743939801 --- /dev/null +++ b/patches/chromium/cherry-pick-4e528a5a8d83.patch @@ -0,0 +1,62 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Austin Sullivan +Date: Wed, 15 Sep 2021 23:57:27 +0000 +Subject: FSA: Fix race condition in manager + +(cherry picked from commit 951339b41022b08a67ad94ba5960b05c84bf4cf2) + +Bug: 1248030 +Change-Id: I1ea819d1d6ac63ec8f400a45c893da49596235ef +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3154425 +Commit-Queue: Marijn Kruisselbrink +Auto-Submit: Austin Sullivan +Reviewed-by: Marijn Kruisselbrink +Cr-Original-Commit-Position: refs/heads/main@{#920376} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3160301 +Commit-Queue: Austin Sullivan +Cr-Commit-Position: refs/branch-heads/4606@{#1077} +Cr-Branched-From: 35b0d5a9dc8362adfd44e2614f0d5b7402ef63d0-refs/heads/master@{#911515} + +diff --git a/content/browser/file_system_access/file_system_access_manager_impl.cc b/content/browser/file_system_access/file_system_access_manager_impl.cc +index e58be73ae495dbc3c04802caf8fd163bcafaf992..a47eceba374b2c589fe8a0d007e4e1c803baab32 100644 +--- a/content/browser/file_system_access/file_system_access_manager_impl.cc ++++ b/content/browser/file_system_access/file_system_access_manager_impl.cc +@@ -448,6 +448,11 @@ void FileSystemAccessManagerImpl::ResolveDefaultDirectory( + std::move(callback)))); + } + ++void FileSystemAccessManagerImpl::Shutdown() { ++ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); ++ permission_context_ = nullptr; ++} ++ + void FileSystemAccessManagerImpl::SetDefaultPathAndShowPicker( + const BindingContext& context, + blink::mojom::FilePickerOptionsPtr options, +diff --git a/content/browser/file_system_access/file_system_access_manager_impl.h b/content/browser/file_system_access/file_system_access_manager_impl.h +index 4c9303aa11349f8de5181ca1dcd92f20f2b74a99..e06a3d347f2af5f62ade1fc70e8ad49ca878628f 100644 +--- a/content/browser/file_system_access/file_system_access_manager_impl.h ++++ b/content/browser/file_system_access/file_system_access_manager_impl.h +@@ -257,6 +257,8 @@ class CONTENT_EXPORT FileSystemAccessManagerImpl + PathType path_type, + const base::FilePath& path); + ++ void Shutdown(); ++ + private: + friend class FileSystemAccessFileHandleImpl; + +diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc +index 7ffcbd0ac22164d5e268f28e0e434a08e3eb120b..f851627cf33ac4bc2aa56eb3d7b21170eb5c0d16 100644 +--- a/content/browser/storage_partition_impl.cc ++++ b/content/browser/storage_partition_impl.cc +@@ -1078,6 +1078,9 @@ StoragePartitionImpl::~StoragePartitionImpl() { + GetDatabaseTracker())); + } + ++ if (GetFileSystemAccessManager()) ++ GetFileSystemAccessManager()->Shutdown(); ++ + if (GetFileSystemContext()) + GetFileSystemContext()->Shutdown(); + diff --git a/patches/chromium/cherry-pick-6048fcd52f42.patch b/patches/chromium/cherry-pick-6048fcd52f42.patch new file mode 100644 index 0000000000000..0734fc6d3fb54 --- /dev/null +++ b/patches/chromium/cherry-pick-6048fcd52f42.patch @@ -0,0 +1,65 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Koji Ishii +Date: Thu, 9 Sep 2021 23:25:48 +0000 +Subject: Merge 4577: Apply list item quirks only when the nested list is + block-level + +This patch changes to apply quirks for a list-item occupying +the whole line only if the nested list is block-level. + +When applying this quirks, list markers are handled like a +regular child. r883403 crrev.com/c/2885398 changed to handle +list markers at |NGBlockLayoutAlgorithm| to support NG block +fragmentation. These two when combined causes the list marker +not laid out if the nested list is not block-level. + +This may change some visual behaviors, but I think this is ok: +a) This quirks is not in the quirks spec[1] and not + implemented in Gecko. +b) The previous CL had a visual difference in this case in M92 + but no reports so far. + +[1]: https://quirks.spec.whatwg.org/ + +(cherry picked from commit 6f5d97da873f0e193a732fb7281d3484258aef6d) + +Bug: 1246932, 1206409 +Change-Id: Ia58a1b788313d3d9f221fd010cdd1a906551ab8b +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3145018 +Reviewed-by: Yoshifumi Inoue +Commit-Queue: Koji Ishii +Cr-Original-Commit-Position: refs/heads/main@{#919158} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3151681 +Auto-Submit: Koji Ishii +Reviewed-by: Ian Kilpatrick +Cr-Commit-Position: refs/branch-heads/4577@{#1225} +Cr-Branched-From: 761ddde228655e313424edec06497d0c56b0f3c4-refs/heads/master@{#902210} + +diff --git a/third_party/blink/renderer/core/layout/ng/list/layout_ng_outside_list_marker.cc b/third_party/blink/renderer/core/layout/ng/list/layout_ng_outside_list_marker.cc +index 15a3c0a3018301e40d336c8893e987b491da66d3..9b7c0e075cb5a89108c22824c5522de26eb904da 100644 +--- a/third_party/blink/renderer/core/layout/ng/list/layout_ng_outside_list_marker.cc ++++ b/third_party/blink/renderer/core/layout/ng/list/layout_ng_outside_list_marker.cc +@@ -26,8 +26,11 @@ bool LayoutNGOutsideListMarker::NeedsOccupyWholeLine() const { + if (!GetDocument().InQuirksMode()) + return false; + ++ // Apply the quirks when the next sibling is a block-level `
    ` or `
      `. + LayoutObject* next_sibling = NextSibling(); +- if (next_sibling && next_sibling->GetNode() && ++ if (next_sibling && !next_sibling->IsInline() && ++ !next_sibling->IsFloatingOrOutOfFlowPositioned() && ++ next_sibling->GetNode() && + (IsA(*next_sibling->GetNode()) || + IsA(*next_sibling->GetNode()))) + return true; +diff --git a/third_party/blink/web_tests/external/wpt/quirks/crashtests/list-item-whole-line-quirks-crash.html b/third_party/blink/web_tests/external/wpt/quirks/crashtests/list-item-whole-line-quirks-crash.html +new file mode 100644 +index 0000000000000000000000000000000000000000..b91b09db0e37727e2d3a3e13ca2c7cae25b8d761 +--- /dev/null ++++ b/third_party/blink/web_tests/external/wpt/quirks/crashtests/list-item-whole-line-quirks-crash.html +@@ -0,0 +1,5 @@ ++ ++
      a
        ++
        a
          ++
          a
            ++
            a
              diff --git a/patches/chromium/cherry-pick-6215793f008f.patch b/patches/chromium/cherry-pick-6215793f008f.patch new file mode 100644 index 0000000000000..f1a971be7afa9 --- /dev/null +++ b/patches/chromium/cherry-pick-6215793f008f.patch @@ -0,0 +1,121 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Scott Violet +Date: Wed, 8 Sep 2021 18:45:42 +0000 +Subject: compositor: fix bug in sending damage regions + +Specifically if a layer is added when sending damaged regions the +iterator would be invalidated. This converts to iterating over the +size. + +BUG=1242257 +TEST=CompositorTestWithMessageLoop.AddLayerDuringUpdateVisualState + +(cherry picked from commit 7c0b0577c3ac1060945b7d05ad69f0dec33479b4) + +Change-Id: I09f2bd34afce5d3c9402ef470f14923bbc76b8ae +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3140178 +Reviewed-by: Ian Vollick +Commit-Queue: Scott Violet +Cr-Original-Commit-Position: refs/heads/main@{#917886} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3149110 +Commit-Queue: enne +Auto-Submit: Scott Violet +Reviewed-by: enne +Cr-Commit-Position: refs/branch-heads/4577@{#1206} +Cr-Branched-From: 761ddde228655e313424edec06497d0c56b0f3c4-refs/heads/master@{#902210} + +diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc +index 34f84bbdc2c21e3f8b8085edaf3fcad86c584672..350efae9200e1646449902e201c985b09ad47e0d 100644 +--- a/ui/compositor/compositor.cc ++++ b/ui/compositor/compositor.cc +@@ -653,8 +653,10 @@ void Compositor::BeginMainFrameNotExpectedUntil(base::TimeTicks time) {} + + static void SendDamagedRectsRecursive(ui::Layer* layer) { + layer->SendDamagedRects(); +- for (auto* child : layer->children()) +- SendDamagedRectsRecursive(child); ++ // Iterate using the size for the case of mutation during sending damaged ++ // regions. https://crbug.com/1242257. ++ for (size_t i = 0; i < layer->children().size(); ++i) ++ SendDamagedRectsRecursive(layer->children()[i]); + } + + void Compositor::UpdateLayerTreeHost() { +diff --git a/ui/compositor/compositor_unittest.cc b/ui/compositor/compositor_unittest.cc +index 7eaa8bbe4ab34e455c2afc67511c867a1d6d7e39..389b8630b4db323458aae65b61ef0b7d91a9797c 100644 +--- a/ui/compositor/compositor_unittest.cc ++++ b/ui/compositor/compositor_unittest.cc +@@ -12,12 +12,14 @@ + #include "base/test/test_mock_time_task_runner.h" + #include "base/threading/thread_task_runner_handle.h" + #include "base/time/time.h" ++#include "build/build_config.h" + #include "cc/metrics/frame_sequence_tracker.h" + #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h" + #include "testing/gmock/include/gmock/gmock.h" + #include "testing/gtest/include/gtest/gtest.h" + #include "ui/compositor/compositor.h" + #include "ui/compositor/layer.h" ++#include "ui/compositor/layer_delegate.h" + #include "ui/compositor/test/draw_waiter_for_test.h" + #include "ui/compositor/test/in_process_context_factory.h" + #include "ui/compositor/test/test_context_factories.h" +@@ -356,4 +358,58 @@ TEST_F(CompositorTestWithMessageLoop, MAYBE_CreateAndReleaseOutputSurface) { + compositor()->SetRootLayer(nullptr); + } + ++class LayerDelegateThatAddsDuringUpdateVisualState : public LayerDelegate { ++ public: ++ explicit LayerDelegateThatAddsDuringUpdateVisualState(Layer* parent) ++ : parent_(parent) {} ++ ++ bool update_visual_state_called() const { ++ return update_visual_state_called_; ++ } ++ ++ // LayerDelegate: ++ void UpdateVisualState() override { ++ added_layers_.push_back(std::make_unique(ui::LAYER_SOLID_COLOR)); ++ parent_->Add(added_layers_.back().get()); ++ update_visual_state_called_ = true; ++ } ++ void OnPaintLayer(const PaintContext& context) override {} ++ void OnDeviceScaleFactorChanged(float old_device_scale_factor, ++ float new_device_scale_factor) override {} ++ ++ private: ++ Layer* parent_; ++ std::vector> added_layers_; ++ bool update_visual_state_called_ = false; ++}; ++ ++TEST_F(CompositorTestWithMessageLoop, AddLayerDuringUpdateVisualState) { ++ std::unique_ptr root_layer = ++ std::make_unique(ui::LAYER_SOLID_COLOR); ++ std::unique_ptr child_layer = ++ std::make_unique(ui::LAYER_TEXTURED); ++ std::unique_ptr child_layer2 = ++ std::make_unique(ui::LAYER_SOLID_COLOR); ++ LayerDelegateThatAddsDuringUpdateVisualState child_layer_delegate( ++ root_layer.get()); ++ child_layer->set_delegate(&child_layer_delegate); ++ root_layer->Add(child_layer.get()); ++ root_layer->Add(child_layer2.get()); ++ ++ viz::ParentLocalSurfaceIdAllocator allocator; ++ allocator.GenerateId(); ++ root_layer->SetBounds(gfx::Rect(10, 10)); ++ compositor()->SetRootLayer(root_layer.get()); ++ compositor()->SetScaleAndSize(1.0f, gfx::Size(10, 10), ++ allocator.GetCurrentLocalSurfaceId()); ++ ASSERT_TRUE(compositor()->IsVisible()); ++ compositor()->ScheduleDraw(); ++ DrawWaiterForTest::WaitForCompositingEnded(compositor()); ++ EXPECT_TRUE(child_layer_delegate.update_visual_state_called()); ++ compositor()->SetRootLayer(nullptr); ++ child_layer2.reset(); ++ child_layer.reset(); ++ root_layer.reset(); ++} ++ + } // namespace ui diff --git a/patches/chromium/cherry-pick-6a8a2098f9fa.patch b/patches/chromium/cherry-pick-6a8a2098f9fa.patch new file mode 100644 index 0000000000000..5fa97b1b41e53 --- /dev/null +++ b/patches/chromium/cherry-pick-6a8a2098f9fa.patch @@ -0,0 +1,230 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Erik Chen +Date: Wed, 29 Sep 2021 21:16:47 +0000 +Subject: Prevents non-browser processes from requesting memory dumps. + +This CL makes several changes: + +(1) Causes the browser to reset non-browser +mojo::PendingReceiver. This means that non-browser +processes will never be able to use the Coordinator interface. + +(2) Add CHECKs to existing code to prevent non-browser processes from +attempting to use the Coordinator interface. + +A code audit shows that all Coordinator usages should already only be +from the browser process. + +Note that (2) is important since attempting to use an unbound interface +will trigger a nullptr dereference, which is undefined behavior. + +(cherry picked from commit d9cc471e122e9a2391a68fa7cd72ea50587d8d97) + +Bug: 1251787 +Change-Id: Ifbe9610cc0e373edaaa60fad46b447e8bdb3ec04 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3174305 +Reviewed-by: Kinuko Yasuda +Reviewed-by: ssid +Auto-Submit: Erik Chen +Commit-Queue: Erik Chen +Cr-Original-Commit-Position: refs/heads/main@{#923693} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3194811 +Reviewed-by: Avi Drissman +Reviewed-by: Krishna Govind +Commit-Queue: Krishna Govind +Owners-Override: Krishna Govind +Cr-Commit-Position: refs/branch-heads/4606@{#1253} +Cr-Branched-From: 35b0d5a9dc8362adfd44e2614f0d5b7402ef63d0-refs/heads/master@{#911515} + +diff --git a/content/browser/browser_child_process_host_impl.cc b/content/browser/browser_child_process_host_impl.cc +index 562eb4c2e1341b9aeb77ce3cfaf6740fa4876a61..8d155fa573c5b67f282d43b6fc8bfc0b98cbfeb1 100644 +--- a/content/browser/browser_child_process_host_impl.cc ++++ b/content/browser/browser_child_process_host_impl.cc +@@ -704,6 +704,9 @@ void BrowserChildProcessHostImpl::RegisterCoordinatorClient( + mojo::PendingReceiver receiver, + mojo::PendingRemote + client_process) { ++ // Intentionally disallow non-browser processes from getting a Coordinator. ++ receiver.reset(); ++ + // The child process may have already terminated by the time this message is + // dispatched. We do nothing in that case. + if (!IsProcessLaunched()) +diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc +index c2341d7e2b4149c5a83676b237f4c21ba5e9798a..be4a24917f9c5f8cf6c7c68761b3a9873d9b35aa 100644 +--- a/content/browser/renderer_host/render_process_host_impl.cc ++++ b/content/browser/renderer_host/render_process_host_impl.cc +@@ -2632,6 +2632,9 @@ void RenderProcessHostImpl::RegisterCoordinatorClient( + mojo::PendingReceiver receiver, + mojo::PendingRemote + client_process) { ++ // Intentionally disallow non-browser processes from getting a Coordinator. ++ receiver.reset(); ++ + if (!GetProcess().IsValid()) { + // If the process dies before we get this message. we have no valid PID + // and there's nothing to register. +diff --git a/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc b/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc +index 77cd931b5fe94dc11440c1f67c17d653db11bbb1..c16affe3949505d6144d4c4db6ece453005d6fea 100644 +--- a/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc ++++ b/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc +@@ -105,7 +105,8 @@ void CoordinatorImpl::RegisterClientProcess( + const base::Optional& service_name) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + mojo::Remote process(std::move(client_process)); +- coordinator_receivers_.Add(this, std::move(receiver), process_id); ++ if (receiver.is_valid()) ++ coordinator_receivers_.Add(this, std::move(receiver), process_id); + process.set_disconnect_handler( + base::BindOnce(&CoordinatorImpl::UnregisterClientProcess, + base::Unretained(this), process_id)); +diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.cc b/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.cc +index ca0e8d8441a53fce370b375930b149a0b8dd6974..ae9ef93eafe0196c7a16743211f04eebe2c87d34 100644 +--- a/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.cc ++++ b/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.cc +@@ -24,6 +24,11 @@ void ClientProcessImpl::CreateInstance( + mojo::PendingReceiver receiver, + mojo::PendingRemote coordinator, + bool is_browser_process) { ++ // Intentionally disallow non-browser processes from ever holding a ++ // Coordinator. ++ if (!is_browser_process) ++ coordinator.reset(); ++ + static ClientProcessImpl* instance = nullptr; + if (!instance) { + instance = new ClientProcessImpl( +@@ -39,10 +44,12 @@ ClientProcessImpl::ClientProcessImpl( + mojo::PendingRemote coordinator, + bool is_browser_process, + bool initialize_memory_instrumentation) +- : receiver_(this, std::move(receiver)) { ++ : receiver_(this, std::move(receiver)), ++ is_browser_process_(is_browser_process) { + if (initialize_memory_instrumentation) { + // Initialize the public-facing MemoryInstrumentation helper. +- MemoryInstrumentation::CreateInstance(std::move(coordinator)); ++ MemoryInstrumentation::CreateInstance(std::move(coordinator), ++ is_browser_process); + } else { + coordinator_.Bind(std::move(coordinator)); + } +@@ -109,6 +116,8 @@ void ClientProcessImpl::OnChromeMemoryDumpDone( + void ClientProcessImpl::RequestGlobalMemoryDump_NoCallback( + base::trace_event::MemoryDumpType dump_type, + base::trace_event::MemoryDumpLevelOfDetail level_of_detail) { ++ CHECK(is_browser_process_); ++ + if (!task_runner_->RunsTasksInCurrentSequence()) { + task_runner_->PostTask( + FROM_HERE, +diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.h b/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.h +index 6dd8c55823de34ccef4244036b4d4c8cda92f74a..8c2c20c449a2e3bf8c7465ccbc2fba6fd1cb402b 100644 +--- a/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.h ++++ b/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.h +@@ -96,6 +96,9 @@ class COMPONENT_EXPORT(RESOURCE_COORDINATOR_PUBLIC_MEMORY_INSTRUMENTATION) + mojo::Remote coordinator_; + scoped_refptr task_runner_; + ++ // Only browser process is allowed to request memory dumps. ++ const bool is_browser_process_; ++ + // TODO(crbug.com/728199): The observer is only used to setup and tear down + // MemoryDumpManager in each process. Setting up MemoryDumpManager should + // be moved away from TracingObserver. +diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.cc b/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.cc +index c81d5f83bf9e1ad5e7a77d7c187fa33bd02812d5..ec90ab9211ede586d441f40e3e2bc2c820658fb1 100644 +--- a/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.cc ++++ b/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.cc +@@ -21,10 +21,11 @@ void WrapGlobalMemoryDump( + + // static + void MemoryInstrumentation::CreateInstance( +- mojo::PendingRemote +- coordinator) { ++ mojo::PendingRemote coordinator, ++ bool is_browser_process) { + DCHECK(!g_instance); +- g_instance = new MemoryInstrumentation(std::move(coordinator)); ++ g_instance = ++ new MemoryInstrumentation(std::move(coordinator), is_browser_process); + } + + // static +@@ -33,8 +34,10 @@ MemoryInstrumentation* MemoryInstrumentation::GetInstance() { + } + + MemoryInstrumentation::MemoryInstrumentation( +- mojo::PendingRemote coordinator) +- : coordinator_(std::move(coordinator)) {} ++ mojo::PendingRemote coordinator, ++ bool is_browser_process) ++ : coordinator_(std::move(coordinator)), ++ is_browser_process_(is_browser_process) {} + + MemoryInstrumentation::~MemoryInstrumentation() { + g_instance = nullptr; +@@ -43,6 +46,7 @@ MemoryInstrumentation::~MemoryInstrumentation() { + void MemoryInstrumentation::RequestGlobalDump( + const std::vector& allocator_dump_names, + RequestGlobalDumpCallback callback) { ++ CHECK(is_browser_process_); + coordinator_->RequestGlobalMemoryDump( + MemoryDumpType::SUMMARY_ONLY, MemoryDumpLevelOfDetail::BACKGROUND, + MemoryDumpDeterminism::NONE, allocator_dump_names, +@@ -52,6 +56,7 @@ void MemoryInstrumentation::RequestGlobalDump( + void MemoryInstrumentation::RequestPrivateMemoryFootprint( + base::ProcessId pid, + RequestGlobalDumpCallback callback) { ++ CHECK(is_browser_process_); + coordinator_->RequestPrivateMemoryFootprint( + pid, base::BindOnce(&WrapGlobalMemoryDump, std::move(callback))); + } +@@ -60,6 +65,7 @@ void MemoryInstrumentation::RequestGlobalDumpForPid( + base::ProcessId pid, + const std::vector& allocator_dump_names, + RequestGlobalDumpCallback callback) { ++ CHECK(is_browser_process_); + coordinator_->RequestGlobalMemoryDumpForPid( + pid, allocator_dump_names, + base::BindOnce(&WrapGlobalMemoryDump, std::move(callback))); +@@ -70,6 +76,7 @@ void MemoryInstrumentation::RequestGlobalDumpAndAppendToTrace( + MemoryDumpLevelOfDetail level_of_detail, + MemoryDumpDeterminism determinism, + RequestGlobalMemoryDumpAndAppendToTraceCallback callback) { ++ CHECK(is_browser_process_); + coordinator_->RequestGlobalMemoryDumpAndAppendToTrace( + dump_type, level_of_detail, determinism, std::move(callback)); + } +diff --git a/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h b/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h +index 3264917890cc30179c4477657158fd359a9d1e01..72157b5345fb003452f67045e2b2c984e748958a 100644 +--- a/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h ++++ b/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h +@@ -34,7 +34,8 @@ class COMPONENT_EXPORT(RESOURCE_COORDINATOR_PUBLIC_MEMORY_INSTRUMENTATION) + + static void CreateInstance( + mojo::PendingRemote +- coordinator); ++ coordinator, ++ bool is_browser_process); + static MemoryInstrumentation* GetInstance(); + + // Retrieves a Coordinator interface to communicate with the service. This is +@@ -100,12 +101,16 @@ class COMPONENT_EXPORT(RESOURCE_COORDINATOR_PUBLIC_MEMORY_INSTRUMENTATION) + private: + explicit MemoryInstrumentation( + mojo::PendingRemote +- coordinator); ++ coordinator, ++ bool is_browser_process); + ~MemoryInstrumentation(); + + const mojo::SharedRemote + coordinator_; + ++ // Only browser process is allowed to request memory dumps. ++ const bool is_browser_process_; ++ + DISALLOW_COPY_AND_ASSIGN(MemoryInstrumentation); + }; + diff --git a/patches/chromium/cherry-pick-6bb320d134b1.patch b/patches/chromium/cherry-pick-6bb320d134b1.patch new file mode 100644 index 0000000000000..e4fdcf090cfe9 --- /dev/null +++ b/patches/chromium/cherry-pick-6bb320d134b1.patch @@ -0,0 +1,765 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Victor Costan +Date: Thu, 11 Nov 2021 00:22:30 +0000 +Subject: M96: Storage Foundation: Share FileState ownership with I/O threads. + +blink::NativeIOFile methods implementing the Storage Foundation +JavaScript API pass raw pointers to NativeIOFile::FileState instances to +their corresponding blink::NativeIOFile::Do*() methods, which rely on +that CrossThreadPersistent arguments to keep the +underlying NativeIOFile::FileState instances alive. + +CrossThreadPersistent can be used across threads to keep a garbage +collected object alive, together with any non-garbage-collected objects +that it owns. However, relying on CrossThreadPersistent existence to +access the owned objects on a different thread is not safe. +cppgc::subtle::CrossThreadPersistent (blink::CrossThreadPersistent is an +alias to that) has comments explaining that the garbage collected heap +can go away while the CrossThreadPersistent instance exists. + +This CL fixes the problem by having the ownership of +NativeIOFile::FileState be shared between the corresponding NativeIOFile +instance and any threads doing I/O on the FileState. + +(cherry picked from commit 7dc02206707362f3f92cea93f8eb2fa4af0d375f) + +Bug: 1240593 +Change-Id: I5c9c818bcb23316fe1fd5afa57ed9c3fdb034377 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3269947 +Commit-Queue: Victor Costan +Reviewed-by: Austin Sullivan +Reviewed-by: Marijn Kruisselbrink +Reviewed-by: enne +Cr-Original-Commit-Position: refs/heads/main@{#940130} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3272672 +Bot-Commit: Rubber Stamper +Cr-Commit-Position: refs/branch-heads/4664@{#945} +Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512} + +diff --git a/third_party/blink/renderer/modules/native_io/native_io_file.cc b/third_party/blink/renderer/modules/native_io/native_io_file.cc +index 4d5aa4efa13930aea4886bac0fd8ba892ce8b5a5..615c1d3a20cba732a3d981bf6b2df181e56d2727 100644 +--- a/third_party/blink/renderer/modules/native_io/native_io_file.cc ++++ b/third_party/blink/renderer/modules/native_io/native_io_file.cc +@@ -9,6 +9,7 @@ + #include "base/check.h" + #include "base/files/file.h" + #include "base/location.h" ++#include "base/memory/scoped_refptr.h" + #include "base/numerics/checked_math.h" + #include "base/sequenced_task_runner.h" + #include "base/task/thread_pool.h" +@@ -47,31 +48,167 @@ + + namespace blink { + +-struct NativeIOFile::FileState { +- explicit FileState(base::File file) : file(std::move(file)) {} ++// State and logic for performing file I/O off the JavaScript thread. ++// ++// Instances are allocated on the PartitionAlloc heap. Instances cannot be ++// garbage-collected, because garbage collected heaps get deallocated when the ++// underlying threads are terminated, and we need a guarantee that each ++// instance remains alive while it is used by a thread performing file I/O. ++// ++// Instances are initially constructed on a Blink thread that executes ++// JavaScript, which can be Blink's main thread, or a worker thread. Afterwards, ++// instances are (mostly*) only accessed on dedicated threads that do blocking ++// file I/O. ++// ++// Mostly*: On macOS < 10.15, SetLength() synchronously accesses FileState on ++// the JavaScript thread. This could be fixed with extra thread hopping. We're ++// not currently planning to invest in the fix. ++class NativeIOFile::FileState ++ : public base::RefCountedThreadSafe { ++ public: ++ explicit FileState(base::File file) : file_(std::move(file)) { ++ DCHECK(file_.IsValid()); ++ } + + FileState(const FileState&) = delete; + FileState& operator=(const FileState&) = delete; + + ~FileState() = default; + ++ // Returns true until Close() is called. Returns false afterwards. ++ // ++ // On macOS < 10.15, returns false between a TakeFile() call and the ++ // corresponding SetFile() call. ++ bool IsValid() { ++ DCHECK(!IsMainThread()); ++ ++ WTF::MutexLocker locker(mutex_); ++ return file_.IsValid(); ++ } ++ ++ void Close() { ++ DCHECK(!IsMainThread()); ++ ++ WTF::MutexLocker locker(mutex_); ++ DCHECK(file_.IsValid()) << __func__ << " called on invalid file"; ++ ++ file_.Close(); ++ } ++ ++ // Returns {length, base::File::FILE_OK} in case of success. ++ // Returns {invalid number, error} in case of failure. ++ std::pair GetLength() { ++ DCHECK(!IsMainThread()); ++ ++ WTF::MutexLocker mutex_locker(mutex_); ++ DCHECK(file_.IsValid()) << __func__ << " called on invalid file"; ++ ++ int64_t length = file_.GetLength(); ++ base::File::Error error = ++ (length < 0) ? file_.GetLastFileError() : base::File::FILE_OK; ++ ++ return {length, error}; ++ } ++ ++ // Returns {expected_length, base::File::FILE_OK} in case of success. ++ // Returns {actual file length, error} in case of failure. ++ std::pair SetLength(int64_t expected_length) { ++ DCHECK(!IsMainThread()); ++ DCHECK_GE(expected_length, 0); ++ ++ WTF::MutexLocker mutex_locker(mutex_); ++ DCHECK(file_.IsValid()) << __func__ << " called on invalid file"; ++ ++ bool success = file_.SetLength(expected_length); ++ base::File::Error error = ++ success ? base::File::FILE_OK : file_.GetLastFileError(); ++ int64_t actual_length = success ? expected_length : file_.GetLength(); ++ ++ return {actual_length, error}; ++ } ++ ++#if defined(OS_MAC) ++ // Used to implement browser-side SetLength() on macOS < 10.15. ++ base::File TakeFile() { ++ WTF::MutexLocker mutex_locker(mutex_); ++ DCHECK(file_.IsValid()) << __func__ << " called on invalid file"; ++ ++ return std::move(file_); ++ } ++ ++ // Used to implement browser-side SetLength() on macOS < 10.15. ++ void SetFile(base::File file) { ++ WTF::MutexLocker locker(mutex_); ++ DCHECK(!file_.IsValid()) << __func__ << " called on valid file"; ++ ++ file_ = std::move(file); ++ } ++#endif // defined(OS_MAC) ++ ++ // Returns {read byte count, base::File::FILE_OK} in case of success. ++ // Returns {invalid number, error} in case of failure. ++ std::pair Read(NativeIODataBuffer* buffer, ++ int64_t file_offset, ++ int read_size) { ++ DCHECK(!IsMainThread()); ++ DCHECK(buffer); ++ DCHECK_GE(file_offset, 0); ++ DCHECK_GE(read_size, 0); ++ ++ WTF::MutexLocker mutex_locker(mutex_); ++ DCHECK(file_.IsValid()) << __func__ << " called on invalid file"; ++ ++ int read_bytes = file_.Read(file_offset, buffer->Data(), read_size); ++ base::File::Error error = ++ (read_bytes < 0) ? file_.GetLastFileError() : base::File::FILE_OK; ++ ++ return {read_bytes, error}; ++ } ++ ++ // Returns {0, write_size, base::File::FILE_OK} in case of success. ++ // Returns {actual file length, written bytes, base::File::OK} in case of a ++ // short write. ++ // Returns {actual file length, invalid number, error} in case of failure. ++ std::tuple Write(NativeIODataBuffer* buffer, ++ int64_t file_offset, ++ int write_size) { ++ DCHECK(!IsMainThread()); ++ DCHECK(buffer); ++ DCHECK_GE(file_offset, 0); ++ DCHECK_GE(write_size, 0); ++ ++ WTF::MutexLocker mutex_locker(mutex_); ++ DCHECK(file_.IsValid()) << __func__ << " called on invalid file"; ++ ++ int written_bytes = file_.Write(file_offset, buffer->Data(), write_size); ++ base::File::Error error = ++ (written_bytes < 0) ? file_.GetLastFileError() : base::File::FILE_OK; ++ int64_t actual_file_length_on_failure = 0; ++ if (written_bytes < write_size || error != base::File::FILE_OK) { ++ actual_file_length_on_failure = file_.GetLength(); ++ if (actual_file_length_on_failure < 0 && error != base::File::FILE_OK) ++ error = file_.GetLastFileError(); ++ } ++ ++ return {actual_file_length_on_failure, written_bytes, error}; ++ } ++ ++ base::File::Error Flush() { ++ DCHECK(!IsMainThread()); ++ ++ WTF::MutexLocker mutex_locker(mutex_); ++ DCHECK(file_.IsValid()) << __func__ << " called on invalid file"; ++ ++ bool success = file_.Flush(); ++ return success ? base::File::FILE_OK : file_.GetLastFileError(); ++ } ++ ++ private: + // Lock coordinating cross-thread access to the state. +- WTF::Mutex mutex; ++ WTF::Mutex mutex_; ++ + // The file on disk backing this NativeIOFile. +- // +- // The mutex is there to protect us against using the file after it was +- // closed, and against OS-specific behavior around concurrent file access. It +- // should never cause the main (JS) thread to block. This is because the mutex +- // is only taken on the main thread in CloseBackingFile(), which is called +- // when the NativeIOFile is destroyed (which implies there's no pending I/O +- // operation, because all I/O operations hold onto a Persistent) +- // and when the mojo pipe is closed, which currently only happens when the JS +- // context is being torn down. +- // +- // TODO(rstz): Is it possible and worthwhile to remove the mutex and rely +- // exclusively on |NativeIOFile::io_pending_|, or remove +- // |NativeIOFile::io_pending_| in favor of the mutex (might be harder)? +- base::File file GUARDED_BY(mutex); ++ base::File file_ GUARDED_BY(mutex_); + }; + + NativeIOFile::NativeIOFile( +@@ -81,7 +218,7 @@ NativeIOFile::NativeIOFile( + NativeIOCapacityTracker* capacity_tracker, + ExecutionContext* execution_context) + : file_length_(backing_file_length), +- file_state_(std::make_unique(std::move(backing_file))), ++ file_state_(base::MakeRefCounted(std::move(backing_file))), + // TODO(pwnall): Get a dedicated queue when the specification matures. + resolver_task_runner_( + execution_context->GetTaskRunner(TaskType::kMiscPlatformAPI)), +@@ -94,7 +231,7 @@ NativeIOFile::NativeIOFile( + } + + NativeIOFile::~NativeIOFile() { +- // Needed to avoid having the base::File destructor close the file descriptor ++ // Needed to avoid having the FileState destructor close the file descriptor + // synchronously on the main thread. + CloseBackingFile(); + } +@@ -114,6 +251,9 @@ ScriptPromise NativeIOFile::close(ScriptState* script_state) { + queued_close_resolver_ = resolver; + + if (!io_pending_) { ++ DCHECK(file_state_) ++ << "file_state_ nulled out without setting closed_ or io_pending_"; ++ + // Pretend that a close() promise was queued behind an I/O operation, and + // the operation just finished. This is less logic than handling the + // non-queued case separately. +@@ -138,18 +278,15 @@ ScriptPromise NativeIOFile::getLength(ScriptState* script_state, + "The file was already closed")); + return ScriptPromise(); + } +- io_pending_ = true; ++ DCHECK(file_state_) ++ << "file_state_ nulled out without setting closed_ or io_pending_"; + ++ io_pending_ = true; + auto* resolver = MakeGarbageCollected(script_state); +- // CrossThreadUnretained() is safe here because the NativeIOFile::FileState +- // instance is owned by this NativeIOFile, which is also passed to the task +- // via WrapCrossThreadPersistent. Therefore, the FileState instance is +- // guaranteed to remain alive during the task's execution. + worker_pool::PostTask( + FROM_HERE, {base::MayBlock()}, + CrossThreadBindOnce(&DoGetLength, WrapCrossThreadPersistent(this), +- WrapCrossThreadPersistent(resolver), +- CrossThreadUnretained(file_state_.get()), ++ WrapCrossThreadPersistent(resolver), file_state_, + resolver_task_runner_)); + return resolver->Promise(); + } +@@ -175,6 +312,9 @@ ScriptPromise NativeIOFile::setLength(ScriptState* script_state, + "The file was already closed")); + return ScriptPromise(); + } ++ DCHECK(file_state_) ++ << "file_state_ nulled out without setting closed_ or io_pending_"; ++ + int64_t expected_length = base::as_signed(new_length); + + DCHECK_GE(expected_length, 0); +@@ -201,8 +341,8 @@ ScriptPromise NativeIOFile::setLength(ScriptState* script_state, + } + file_length_ = expected_length; + } +- io_pending_ = true; + ++ io_pending_ = true; + auto* resolver = MakeGarbageCollected(script_state); + + #if defined(OS_MAC) +@@ -217,26 +357,19 @@ ScriptPromise NativeIOFile::setLength(ScriptState* script_state, + // To preserve this invariant, we pass this file's handle to the browser + // process during the SetLength() mojo call, and the browser passes it back + // when the call completes. +- { +- WTF::MutexLocker locker(file_state_->mutex); +- backend_file_->SetLength( +- expected_length, std::move(file_state_->file), +- WTF::Bind(&NativeIOFile::DidSetLengthIpc, WrapPersistent(this), +- WrapPersistent(resolver))); +- } ++ base::File file = file_state_->TakeFile(); ++ backend_file_->SetLength( ++ expected_length, std::move(file), ++ WTF::Bind(&NativeIOFile::DidSetLengthIpc, WrapPersistent(this), ++ WrapPersistent(resolver))); + return resolver->Promise(); + } + #endif // defined(OS_MAC) + +- // CrossThreadUnretained() is safe here because the NativeIOFile::FileState +- // instance is owned by this NativeIOFile, which is also passed to the task +- // via WrapCrossThreadPersistent. Therefore, the FileState instance is +- // guaranteed to remain alive during the task's execution. + worker_pool::PostTask( + FROM_HERE, {base::MayBlock()}, + CrossThreadBindOnce(&DoSetLength, WrapCrossThreadPersistent(this), +- WrapCrossThreadPersistent(resolver), +- CrossThreadUnretained(file_state_.get()), ++ WrapCrossThreadPersistent(resolver), file_state_, + resolver_task_runner_, expected_length)); + return resolver->Promise(); + } +@@ -258,6 +391,8 @@ ScriptPromise NativeIOFile::read(ScriptState* script_state, + "The file was already closed")); + return ScriptPromise(); + } ++ DCHECK(file_state_) ++ << "file_state_ nulled out without setting closed_ or io_pending_"; + + // TODO(pwnall): This assignment should move right before the + // worker_pool::PostTask() call. +@@ -281,16 +416,10 @@ ScriptPromise NativeIOFile::read(ScriptState* script_state, + DCHECK(buffer->IsDetached()); + + auto* resolver = MakeGarbageCollected(script_state); +- // The first CrossThreadUnretained() is safe here because the +- // NativeIOFile::FileState instance is owned by this NativeIOFile, which is +- // also passed to the task via WrapCrossThreadPersistent. Therefore, the +- // FileState instance is guaranteed to remain alive during the task's +- // execution. + worker_pool::PostTask( + FROM_HERE, {base::MayBlock()}, + CrossThreadBindOnce(&DoRead, WrapCrossThreadPersistent(this), +- WrapCrossThreadPersistent(resolver), +- CrossThreadUnretained(file_state_.get()), ++ WrapCrossThreadPersistent(resolver), file_state_, + resolver_task_runner_, std::move(result_buffer_data), + file_offset, read_size)); + return resolver->Promise(); +@@ -313,6 +442,8 @@ ScriptPromise NativeIOFile::write(ScriptState* script_state, + "The file was already closed")); + return ScriptPromise(); + } ++ DCHECK(file_state_) ++ << "file_state_ nulled out without setting closed_ or io_pending_"; + + int write_size = NativeIOOperationSize(*buffer); + int64_t write_end_offset; +@@ -346,6 +477,14 @@ ScriptPromise NativeIOFile::write(ScriptState* script_state, + file_length_ = write_end_offset; + } + ++ // TODO(pwnall): This assignment should move right before the ++ // worker_pool::PostTask() call. ++ // ++ // `io_pending_` should only be set to true when we know for sure we'll post a ++ // task that eventually results in getting `io_pending_` set back to false. ++ // Having `io_pending_` set to true in an early return case (rejecting with an ++ // exception) leaves the NativeIOFile "stuck" in a state where all future I/O ++ // method calls will reject. + io_pending_ = true; + + std::unique_ptr result_buffer_data = +@@ -358,16 +497,10 @@ ScriptPromise NativeIOFile::write(ScriptState* script_state, + DCHECK(buffer->IsDetached()); + + auto* resolver = MakeGarbageCollected(script_state); +- // The first CrossThreadUnretained() is safe here because the +- // NativeIOFile::FileState instance is owned by this NativeIOFile, which is +- // also passed to the task via WrapCrossThreadPersistent. Therefore, the +- // FileState instance is guaranteed to remain alive during the task's +- // execution. + worker_pool::PostTask( + FROM_HERE, {base::MayBlock()}, + CrossThreadBindOnce(&DoWrite, WrapCrossThreadPersistent(this), +- WrapCrossThreadPersistent(resolver), +- CrossThreadUnretained(file_state_.get()), ++ WrapCrossThreadPersistent(resolver), file_state_, + resolver_task_runner_, std::move(result_buffer_data), + file_offset, write_size)); + return resolver->Promise(); +@@ -391,18 +524,15 @@ ScriptPromise NativeIOFile::flush(ScriptState* script_state, + "The file was already closed")); + return ScriptPromise(); + } +- io_pending_ = true; ++ DCHECK(file_state_) ++ << "file_state_ nulled out without setting closed_ or io_pending_"; + ++ io_pending_ = true; + auto* resolver = MakeGarbageCollected(script_state); +- // CrossThreadUnretained() is safe here because the NativeIOFile::FileState +- // instance is owned by this NativeIOFile, which is also passed to the task +- // via WrapCrossThreadPersistent. Therefore, the FileState instance is +- // guaranteed to remain alive during the task's execution. + worker_pool::PostTask( + FROM_HERE, {base::MayBlock()}, + CrossThreadBindOnce(&DoFlush, WrapCrossThreadPersistent(this), +- WrapCrossThreadPersistent(resolver), +- CrossThreadUnretained(file_state_.get()), ++ WrapCrossThreadPersistent(resolver), file_state_, + resolver_task_runner_)); + return resolver->Promise(); + } +@@ -430,28 +560,29 @@ void NativeIOFile::DispatchQueuedClose() { + ScriptPromiseResolver* resolver = queued_close_resolver_; + queued_close_resolver_ = nullptr; + ++ scoped_refptr file_state = std::move(file_state_); ++ DCHECK(!file_state_); ++ + worker_pool::PostTask( + FROM_HERE, {base::MayBlock()}, + CrossThreadBindOnce(&DoClose, WrapCrossThreadPersistent(this), + WrapCrossThreadPersistent(resolver), +- CrossThreadUnretained(file_state_.get()), +- resolver_task_runner_)); ++ std::move(file_state), resolver_task_runner_)); + } + + // static + void NativeIOFile::DoClose( + CrossThreadPersistent native_io_file, + CrossThreadPersistent resolver, +- NativeIOFile::FileState* file_state, ++ scoped_refptr file_state, + scoped_refptr resolver_task_runner) { + DCHECK(!IsMainThread()) << "File I/O should not happen on the main thread"; ++ DCHECK(file_state); ++ DCHECK(file_state->IsValid()) ++ << "File I/O operation queued after file closed"; ++ DCHECK(resolver_task_runner); + +- { +- WTF::MutexLocker locker(file_state->mutex); +- DCHECK(file_state->file.IsValid()) +- << "file I/O operation queued after file closed"; +- file_state->file.Close(); +- } ++ file_state->Close(); + + PostCrossThreadTask( + *resolver_task_runner, FROM_HERE, +@@ -482,19 +613,17 @@ void NativeIOFile::DidClose( + void NativeIOFile::DoGetLength( + CrossThreadPersistent native_io_file, + CrossThreadPersistent resolver, +- NativeIOFile::FileState* file_state, ++ scoped_refptr file_state, + scoped_refptr resolver_task_runner) { + DCHECK(!IsMainThread()) << "File I/O should not happen on the main thread"; ++ DCHECK(file_state); ++ DCHECK(file_state->IsValid()) ++ << "File I/O operation queued after file closed"; ++ DCHECK(resolver_task_runner); ++ ++ int64_t length; + base::File::Error get_length_error; +- int64_t length = -1; +- { +- WTF::MutexLocker mutex_locker(file_state->mutex); +- DCHECK(file_state->file.IsValid()) +- << "file I/O operation queued after file closed"; +- length = file_state->file.GetLength(); +- get_length_error = (length < 0) ? file_state->file.GetLastFileError() +- : base::File::FILE_OK; +- } ++ std::tie(length, get_length_error) = file_state->GetLength(); + + PostCrossThreadTask( + *resolver_task_runner, FROM_HERE, +@@ -541,22 +670,20 @@ void NativeIOFile::DidGetLength( + void NativeIOFile::DoSetLength( + CrossThreadPersistent native_io_file, + CrossThreadPersistent resolver, +- NativeIOFile::FileState* file_state, ++ scoped_refptr file_state, + scoped_refptr resolver_task_runner, + int64_t expected_length) { + DCHECK(!IsMainThread()) << "File I/O should not happen on the main thread"; ++ DCHECK(file_state); ++ DCHECK(file_state->IsValid()) ++ << "File I/O operation queued after file closed"; ++ DCHECK(resolver_task_runner); ++ DCHECK_GE(expected_length, 0); + +- base::File::Error set_length_error; + int64_t actual_length; +- { +- WTF::MutexLocker mutex_locker(file_state->mutex); +- DCHECK(file_state->file.IsValid()) +- << "file I/O operation queued after file closed"; +- bool success = file_state->file.SetLength(expected_length); +- set_length_error = +- success ? base::File::FILE_OK : file_state->file.GetLastFileError(); +- actual_length = success ? expected_length : file_state->file.GetLength(); +- } ++ base::File::Error set_length_error; ++ std::tie(actual_length, set_length_error) = ++ file_state->SetLength(expected_length); + + PostCrossThreadTask( + *resolver_task_runner, FROM_HERE, +@@ -619,10 +746,7 @@ void NativeIOFile::DidSetLengthIpc( + int64_t actual_length, + mojom::blink::NativeIOErrorPtr set_length_error) { + DCHECK(backing_file.IsValid()) << "browser returned closed file"; +- { +- WTF::MutexLocker locker(file_state_->mutex); +- file_state_->file = std::move(backing_file); +- } ++ file_state_->SetFile(std::move(backing_file)); + ScriptState* script_state = resolver->GetScriptState(); + + DCHECK(io_pending_) << "I/O operation performed without io_pending_ set"; +@@ -673,13 +797,15 @@ void NativeIOFile::DidSetLengthIpc( + void NativeIOFile::DoRead( + CrossThreadPersistent native_io_file, + CrossThreadPersistent resolver, +- NativeIOFile::FileState* file_state, ++ scoped_refptr file_state, + scoped_refptr resolver_task_runner, + std::unique_ptr result_buffer_data, + uint64_t file_offset, + int read_size) { + DCHECK(!IsMainThread()) << "File I/O should not happen on the main thread"; +- ++ DCHECK(file_state); ++ DCHECK(file_state->IsValid()) ++ << "File I/O operation queued after file closed"; + DCHECK(resolver_task_runner); + DCHECK(result_buffer_data); + DCHECK(result_buffer_data->IsValid()); +@@ -690,15 +816,8 @@ void NativeIOFile::DoRead( + + int read_bytes; + base::File::Error read_error; +- { +- WTF::MutexLocker mutex_locker(file_state->mutex); +- DCHECK(file_state->file.IsValid()) +- << "file I/O operation queued after file closed"; +- read_bytes = file_state->file.Read(file_offset, result_buffer_data->Data(), +- read_size); +- read_error = (read_bytes < 0) ? file_state->file.GetLastFileError() +- : base::File::FILE_OK; +- } ++ std::tie(read_bytes, read_error) = ++ file_state->Read(result_buffer_data.get(), file_offset, read_size); + + PostCrossThreadTask( + *resolver_task_runner, FROM_HERE, +@@ -743,12 +862,15 @@ void NativeIOFile::DidRead( + void NativeIOFile::DoWrite( + CrossThreadPersistent native_io_file, + CrossThreadPersistent resolver, +- NativeIOFile::FileState* file_state, ++ scoped_refptr file_state, + scoped_refptr resolver_task_runner, + std::unique_ptr result_buffer_data, + uint64_t file_offset, + int write_size) { + DCHECK(!IsMainThread()) << "File I/O should not happen on the main thread"; ++ DCHECK(file_state); ++ DCHECK(file_state->IsValid()) ++ << "File I/O operation queued after file closed"; + DCHECK(resolver_task_runner); + DCHECK(result_buffer_data); + DCHECK(result_buffer_data->IsValid()); +@@ -760,22 +882,8 @@ void NativeIOFile::DoWrite( + int written_bytes; + int64_t actual_file_length_on_failure = 0; + base::File::Error write_error; +- { +- WTF::MutexLocker mutex_locker(file_state->mutex); +- DCHECK(file_state->file.IsValid()) +- << "file I/O operation queued after file closed"; +- written_bytes = file_state->file.Write( +- file_offset, result_buffer_data->Data(), write_size); +- write_error = (written_bytes < 0) ? file_state->file.GetLastFileError() +- : base::File::FILE_OK; +- if (written_bytes < write_size || write_error != base::File::FILE_OK) { +- actual_file_length_on_failure = file_state->file.GetLength(); +- if (actual_file_length_on_failure < 0 && +- write_error != base::File::FILE_OK) { +- write_error = file_state->file.GetLastFileError(); +- } +- } +- } ++ std::tie(actual_file_length_on_failure, written_bytes, write_error) = ++ file_state->Write(result_buffer_data.get(), file_offset, write_size); + + PostCrossThreadTask( + *resolver_task_runner, FROM_HERE, +@@ -846,18 +954,14 @@ void NativeIOFile::DidWrite( + void NativeIOFile::DoFlush( + CrossThreadPersistent native_io_file, + CrossThreadPersistent resolver, +- NativeIOFile::FileState* file_state, ++ scoped_refptr file_state, + scoped_refptr resolver_task_runner) { + DCHECK(!IsMainThread()) << "File I/O should not happen on the main thread"; +- base::File::Error flush_error; +- { +- WTF::MutexLocker mutex_locker(file_state->mutex); +- DCHECK(file_state->file.IsValid()) +- << "file I/O operation queued after file closed"; +- bool success = file_state->file.Flush(); +- flush_error = +- success ? base::File::FILE_OK : file_state->file.GetLastFileError(); +- } ++ DCHECK(file_state); ++ DCHECK(file_state->IsValid()) ++ << "File I/O operation queued after file closed"; ++ ++ base::File::Error flush_error = file_state->Flush(); + + PostCrossThreadTask( + *resolver_task_runner, FROM_HERE, +@@ -887,20 +991,23 @@ void NativeIOFile::DidFlush( + + void NativeIOFile::CloseBackingFile() { + closed_ = true; +- file_state_->mutex.lock(); +- base::File backing_file = std::move(file_state_->file); +- file_state_->mutex.unlock(); + +- if (!backing_file.IsValid()) { ++ if (!file_state_) { + // Avoid posting a cross-thread task if the file is already closed. This is + // the expected path. + return; + } + +- worker_pool::PostTask( +- FROM_HERE, {base::MayBlock()}, +- CrossThreadBindOnce([](base::File file) { file.Close(); }, +- std::move(backing_file))); ++ scoped_refptr file_state = std::move(file_state_); ++ DCHECK(!file_state_); ++ ++ worker_pool::PostTask(FROM_HERE, {base::MayBlock()}, ++ CrossThreadBindOnce( ++ [](scoped_refptr file_state) { ++ DCHECK(file_state); ++ file_state->Close(); ++ }, ++ std::move(file_state))); + } + + } // namespace blink +diff --git a/third_party/blink/renderer/modules/native_io/native_io_file.h b/third_party/blink/renderer/modules/native_io/native_io_file.h +index 8ae49ebc2d36d547d152d4e56192e30f8cacd641..95d2da4ac3e1859a0abc21ea15d269758eed1681 100644 +--- a/third_party/blink/renderer/modules/native_io/native_io_file.h ++++ b/third_party/blink/renderer/modules/native_io/native_io_file.h +@@ -67,12 +67,7 @@ class NativeIOFile final : public ScriptWrappable { + void Trace(Visitor* visitor) const override; + + private: +- // Data accessed on the threads that do file I/O. +- // +- // Instances are allocated on the PartitionAlloc heap. Instances are initially +- // constructed on Blink's main thread, or on a worker thread. Afterwards, +- // instances are only accessed on dedicated threads that do blocking file I/O. +- struct FileState; ++ class FileState; + + // Called when the mojo backend disconnects. + void OnBackendDisconnect(); +@@ -84,7 +79,7 @@ class NativeIOFile final : public ScriptWrappable { + static void DoClose( + CrossThreadPersistent native_io_file, + CrossThreadPersistent resolver, +- NativeIOFile::FileState* file_state, ++ scoped_refptr file_state, + scoped_refptr file_task_runner); + // Performs the post file I/O part of close(), on the main thread. + void DidClose(CrossThreadPersistent resolver); +@@ -93,7 +88,7 @@ class NativeIOFile final : public ScriptWrappable { + static void DoGetLength( + CrossThreadPersistent native_io_file, + CrossThreadPersistent resolver, +- NativeIOFile::FileState* file_state, ++ scoped_refptr file_state, + scoped_refptr file_task_runner); + // Performs the post file I/O part of getLength(), on the main thread. + void DidGetLength(CrossThreadPersistent resolver, +@@ -104,7 +99,7 @@ class NativeIOFile final : public ScriptWrappable { + static void DoSetLength( + CrossThreadPersistent native_io_file, + CrossThreadPersistent resolver, +- NativeIOFile::FileState* file_state, ++ scoped_refptr file_state, + scoped_refptr file_task_runner, + int64_t expected_length); + // Performs the post file I/O part of setLength(), on the main thread. +@@ -128,7 +123,7 @@ class NativeIOFile final : public ScriptWrappable { + // Performs the file I/O part of read(), off the main thread. + static void DoRead(CrossThreadPersistent native_io_file, + CrossThreadPersistent resolver, +- NativeIOFile::FileState* file_state, ++ scoped_refptr file_state, + scoped_refptr file_task_runner, + std::unique_ptr result_buffer_data, + uint64_t file_offset, +@@ -143,7 +138,7 @@ class NativeIOFile final : public ScriptWrappable { + static void DoWrite( + CrossThreadPersistent native_io_file, + CrossThreadPersistent resolver, +- NativeIOFile::FileState* file_state, ++ scoped_refptr file_state, + scoped_refptr resolver_task_runner, + std::unique_ptr result_buffer_data, + uint64_t file_offset, +@@ -163,7 +158,7 @@ class NativeIOFile final : public ScriptWrappable { + static void DoFlush( + CrossThreadPersistent native_io_file, + CrossThreadPersistent resolver, +- NativeIOFile::FileState* file_state, ++ scoped_refptr file_state, + scoped_refptr file_task_runner); + // Performs the post file-I/O part of flush(), on the main thread. + void DidFlush(CrossThreadPersistent resolver, +@@ -210,8 +205,13 @@ class NativeIOFile final : public ScriptWrappable { + // TODO(rstz): Consider moving this variable into `file_state_` + int64_t file_length_ = 0; + +- // See NativeIOFile::FileState, declared above. +- const std::unique_ptr file_state_; ++ // Points to a NativeIOFile::FileState while the underlying file is open. ++ // ++ // When the underlying file is closed, this pointer is nulled out, and the ++ // FileState instance is passed to a different thread, where the closing ++ // happens. This avoids having any I/O performed by the base::File::Close() ++ // jank the JavaScript thread that owns this NativeIOFile instance. ++ scoped_refptr file_state_; + + // Schedules resolving Promises with file I/O results. + const scoped_refptr resolver_task_runner_; diff --git a/patches/chromium/cherry-pick-8623d711677d.patch b/patches/chromium/cherry-pick-8623d711677d.patch new file mode 100644 index 0000000000000..aa6100b392b7a --- /dev/null +++ b/patches/chromium/cherry-pick-8623d711677d.patch @@ -0,0 +1,274 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Ian Kilpatrick +Date: Thu, 9 Sep 2021 23:20:48 +0000 +Subject: Remove limit from LayoutInline::SplitInlines. + +After 200 elements the code "gave up" causing the layout tree to be +"strange". + +This caused a To to fail in the OOF code. Relaxing this +To<> to a DynamicTo<> caused additional CHECKs / DCHECKs all over the +place (not just in NG but in Legacy as well). + +This patch removes the limit at which we "give up". This may cause +additional render hangs. + +However we currently have a project "block-in-inline" which will (for +most cases) stop inline-splitting for occuring (except in legacy +fallback). + +(cherry picked from commit bbd315efb49a4ae257509dd0f0d85c6b5906e0e4) + +(cherry picked from commit d760d2ae1d51c0b4fda87a0a3af4e7ed30d2ff4c) + +Bug: 1245786 +Change-Id: I5f1c4d6a4b81a8345974de40c0c50a27a839b7b4 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3140144 +Reviewed-by: Koji Ishii +Commit-Queue: Ian Kilpatrick +Cr-Original-Original-Commit-Position: refs/heads/main@{#917771} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3149698 +Cr-Original-Commit-Position: refs/branch-heads/4606@{#876} +Cr-Original-Branched-From: 35b0d5a9dc8362adfd44e2614f0d5b7402ef63d0-refs/heads/master@{#911515} +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3152301 +Bot-Commit: Rubber Stamper +Cr-Commit-Position: refs/branch-heads/4577@{#1224} +Cr-Branched-From: 761ddde228655e313424edec06497d0c56b0f3c4-refs/heads/master@{#902210} + +diff --git a/third_party/blink/renderer/core/layout/layout_inline.cc b/third_party/blink/renderer/core/layout/layout_inline.cc +index e59adae1204e5ecb6e399f4fe0ca8a3642701717..d3fa773216bc507208fc6bde3e216e1b8bacf390 100644 +--- a/third_party/blink/renderer/core/layout/layout_inline.cc ++++ b/third_party/blink/renderer/core/layout/layout_inline.cc +@@ -574,15 +574,13 @@ void LayoutInline::SplitInlines(LayoutBlockFlow* from_block, + // nest to a much greater depth (see bugzilla bug 13430) but for now we have a + // limit. This *will* result in incorrect rendering, but the alternative is to + // hang forever. +- const unsigned kCMaxSplitDepth = 200; + Vector inlines_to_clone; + LayoutInline* top_most_inline = this; + for (LayoutObject* o = this; o != from_block; o = o->Parent()) { + if (o->IsLayoutNGInsideListMarker()) + continue; + top_most_inline = To(o); +- if (inlines_to_clone.size() < kCMaxSplitDepth) +- inlines_to_clone.push_back(top_most_inline); ++ inlines_to_clone.push_back(top_most_inline); + // Keep walking up the chain to ensure |topMostInline| is a child of + // |fromBlock|, to avoid assertion failure when |fromBlock|'s children are + // moved to |toBlock| below. +diff --git a/third_party/blink/web_tests/external/wpt/css/css-inline/inline-crash.html b/third_party/blink/web_tests/external/wpt/css/css-inline/inline-crash.html +new file mode 100644 +index 0000000000000000000000000000000000000000..65008f74ce6e0b4397a5b333099c692382d64353 +--- /dev/null ++++ b/third_party/blink/web_tests/external/wpt/css/css-inline/inline-crash.html +@@ -0,0 +1,210 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++
              ++