From 29d8cf54231b7bb200437798f93157f248ab5592 Mon Sep 17 00:00:00 2001 From: Milan Burda Date: Fri, 7 May 2021 04:15:45 +0200 Subject: [PATCH 1/6] fix: focus / blur events don't work with contextIsolation enabled (#29004) (#29026) --- lib/renderer/web-view/web-view-impl.ts | 2 +- spec-main/webview-spec.ts | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/lib/renderer/web-view/web-view-impl.ts b/lib/renderer/web-view/web-view-impl.ts index c5a5c9269089f..8a141c39c9ad9 100644 --- a/lib/renderer/web-view/web-view-impl.ts +++ b/lib/renderer/web-view/web-view-impl.ts @@ -158,7 +158,7 @@ export class WebViewImpl { // Emits focus/blur events. onFocusChange () { - const hasFocus = document.activeElement === this.webviewNode; + const hasFocus = this.webviewNode.ownerDocument!.activeElement === this.webviewNode; if (hasFocus !== this.hasFocus) { this.hasFocus = hasFocus; this.dispatchEvent(new Event(hasFocus ? 'focus' : 'blur')); diff --git a/spec-main/webview-spec.ts b/spec-main/webview-spec.ts index 8bf015c03e1d5..fedaf2ff82b73 100644 --- a/spec-main/webview-spec.ts +++ b/spec-main/webview-spec.ts @@ -659,4 +659,29 @@ describe(' tag', function () { generateSpecs('without sandbox', false); generateSpecs('with sandbox', true); }); + + describe('DOM events', () => { + afterEach(closeAllWindows); + it('emits focus event when contextIsolation is enabled', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { + webviewTag: true, + contextIsolation: true + } + }); + await w.loadURL('about:blank'); + await w.webContents.executeJavaScript(`new Promise((resolve, reject) => { + const webview = new WebView() + webview.setAttribute('src', 'about:blank') + webview.addEventListener('dom-ready', () => { + webview.focus() + }) + webview.addEventListener('focus', () => { + resolve(); + }) + document.body.appendChild(webview) + })`); + }); + }); }); From ab3e65ae34784483b87baec2a24033e4856ed880 Mon Sep 17 00:00:00 2001 From: Milan Burda Date: Thu, 13 May 2021 23:39:16 +0200 Subject: [PATCH 2/6] fix: [webview] fix missing properties on events when contextIsolation: true (#29143) Co-authored-by: Jeremy Rose --- lib/renderer/web-view/guest-view-internal.ts | 19 ++++++---------- lib/renderer/web-view/web-view-element.ts | 8 ++++++- lib/renderer/web-view/web-view-impl.ts | 23 +++++++++++--------- spec-main/webview-spec.ts | 20 +++++++++++++++++ typings/internal-electron.d.ts | 10 --------- 5 files changed, 47 insertions(+), 33 deletions(-) diff --git a/lib/renderer/web-view/guest-view-internal.ts b/lib/renderer/web-view/guest-view-internal.ts index f84f46e4e6d40..ccdc53f9c1060 100644 --- a/lib/renderer/web-view/guest-view-internal.ts +++ b/lib/renderer/web-view/guest-view-internal.ts @@ -1,4 +1,4 @@ -import { webFrame, IpcMessageEvent } from 'electron'; +import { webFrame } from 'electron'; import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal'; import * as ipcRendererUtils from '@electron/internal/renderer/ipc-renderer-internal-utils'; @@ -52,15 +52,15 @@ const dispatchEvent = function ( dispatchEvent(webView, DEPRECATED_EVENTS[eventName], eventKey, ...args); } - const domEvent = new Event(eventName) as ElectronInternal.WebViewEvent; + const props: Record = {}; WEB_VIEW_EVENTS[eventKey].forEach((prop, index) => { - (domEvent as any)[prop] = args[index]; + props[prop] = args[index]; }); - webView.dispatchEvent(domEvent); + webView.dispatchEvent(eventName, props); if (eventName === 'load-commit') { - webView.onLoadCommit(domEvent); + webView.onLoadCommit(props); } else if (eventName === 'focus-change') { webView.onFocusChange(); } @@ -70,8 +70,7 @@ export function registerEvents (webView: WebViewImpl, viewInstanceId: number) { ipcRendererInternal.onMessageFromMain(`ELECTRON_GUEST_VIEW_INTERNAL_DESTROY_GUEST-${viewInstanceId}`, function () { webView.guestInstanceId = undefined; webView.reset(); - const domEvent = new Event('destroyed'); - webView.dispatchEvent(domEvent); + webView.dispatchEvent('destroyed'); }); ipcRendererInternal.onMessageFromMain(`ELECTRON_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-${viewInstanceId}`, function (event, eventName, ...args) { @@ -79,11 +78,7 @@ export function registerEvents (webView: WebViewImpl, viewInstanceId: number) { }); ipcRendererInternal.onMessageFromMain(`ELECTRON_GUEST_VIEW_INTERNAL_IPC_MESSAGE-${viewInstanceId}`, function (event, channel, ...args) { - const domEvent = new Event('ipc-message') as IpcMessageEvent; - domEvent.channel = channel; - domEvent.args = args; - - webView.dispatchEvent(domEvent); + webView.dispatchEvent('ipc-message', { channel, args }); }); } diff --git a/lib/renderer/web-view/web-view-element.ts b/lib/renderer/web-view/web-view-element.ts index e723ebbbe1076..c63748456abad 100644 --- a/lib/renderer/web-view/web-view-element.ts +++ b/lib/renderer/web-view/web-view-element.ts @@ -39,7 +39,13 @@ const defineWebViewElement = (v8Util: NodeJS.V8UtilBinding, webViewImpl: typeof constructor () { super(); - v8Util.setHiddenValue(this, 'internal', new WebViewImpl(this)); + const internal = new WebViewImpl(this); + internal.dispatchEventInMainWorld = (eventName, props) => { + const event = new Event(eventName); + Object.assign(event, props); + return internal.webviewNode.dispatchEvent(event); + }; + v8Util.setHiddenValue(this, 'internal', internal); } connectedCallback () { diff --git a/lib/renderer/web-view/web-view-impl.ts b/lib/renderer/web-view/web-view-impl.ts index 8a141c39c9ad9..0cac4986f79b3 100644 --- a/lib/renderer/web-view/web-view-impl.ts +++ b/lib/renderer/web-view/web-view-impl.ts @@ -37,6 +37,8 @@ export class WebViewImpl { public attributes = new Map(); public setupWebViewAttributes (): void {} + public dispatchEventInMainWorld?: (eventName: string, props: any) => boolean; + constructor (public webviewNode: HTMLElement) { // Create internal iframe element. this.internalElement = this.createInternalElement(); @@ -107,10 +109,11 @@ export class WebViewImpl { } onElementResize () { - const resizeEvent = new Event('resize') as ElectronInternal.WebFrameResizeEvent; - resizeEvent.newWidth = this.webviewNode.clientWidth; - resizeEvent.newHeight = this.webviewNode.clientHeight; - this.dispatchEvent(resizeEvent); + const props = { + newWidth: this.webviewNode.clientWidth, + newHeight: this.webviewNode.clientHeight + }; + this.dispatchEvent('resize', props); } createGuest () { @@ -119,8 +122,8 @@ export class WebViewImpl { }); } - dispatchEvent (webViewEvent: Electron.Event) { - this.webviewNode.dispatchEvent(webViewEvent); + dispatchEvent (eventName: string, props: Record = {}) { + this.dispatchEventInMainWorld!(eventName, props); } // Adds an 'on' property on the webview, which can be used to set/unset @@ -145,10 +148,10 @@ export class WebViewImpl { } // Updates state upon loadcommit. - onLoadCommit (webViewEvent: ElectronInternal.WebViewEvent) { + onLoadCommit (props: Record) { const oldValue = this.webviewNode.getAttribute(WEB_VIEW_CONSTANTS.ATTRIBUTE_SRC); - const newValue = webViewEvent.url; - if (webViewEvent.isMainFrame && (oldValue !== newValue)) { + const newValue = props.url; + if (props.isMainFrame && (oldValue !== newValue)) { // Touching the src attribute triggers a navigation. To avoid // triggering a page reload on every guest-initiated navigation, // we do not handle this mutation. @@ -161,7 +164,7 @@ export class WebViewImpl { const hasFocus = this.webviewNode.ownerDocument!.activeElement === this.webviewNode; if (hasFocus !== this.hasFocus) { this.hasFocus = hasFocus; - this.dispatchEvent(new Event(hasFocus ? 'focus' : 'blur')); + this.dispatchEvent(hasFocus ? 'focus' : 'blur'); } } diff --git a/spec-main/webview-spec.ts b/spec-main/webview-spec.ts index fedaf2ff82b73..434895b6e55f6 100644 --- a/spec-main/webview-spec.ts +++ b/spec-main/webview-spec.ts @@ -662,6 +662,26 @@ describe(' tag', function () { describe('DOM events', () => { afterEach(closeAllWindows); + it('receives extra properties on DOM events when contextIsolation is enabled', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { + webviewTag: true, + contextIsolation: true + } + }); + await w.loadURL('about:blank'); + const message = await w.webContents.executeJavaScript(`new Promise((resolve, reject) => { + const webview = new WebView() + webview.setAttribute('src', 'data:text/html,') + webview.addEventListener('console-message', (e) => { + resolve(e.message) + }) + document.body.appendChild(webview) + })`); + expect(message).to.equal('hi'); + }); + it('emits focus event when contextIsolation is enabled', async () => { const w = new BrowserWindow({ show: false, diff --git a/typings/internal-electron.d.ts b/typings/internal-electron.d.ts index 99ccb44d9b681..41172a10d46f5 100644 --- a/typings/internal-electron.d.ts +++ b/typings/internal-electron.d.ts @@ -166,16 +166,6 @@ declare namespace ElectronInternal { allowGuestViewElementDefinition(window: Window, context: any): void; } - interface WebFrameResizeEvent extends Electron.Event { - newWidth: number; - newHeight: number; - } - - interface WebViewEvent extends Event { - url: string; - isMainFrame: boolean; - } - class WebViewElement extends HTMLElement { static observedAttributes: Array; From ebe509d24ff79ff4d9390926a3de408632db8f9f Mon Sep 17 00:00:00 2001 From: "trop[bot]" <37223003+trop[bot]@users.noreply.github.com> Date: Mon, 17 May 2021 14:47:19 -0400 Subject: [PATCH 3/6] build: make patch auto fixes come from PatchUp rather than Electron Bot (#29154) Co-authored-by: Samuel Attard --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7098fa8b66360..723b74b6b974a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -238,7 +238,7 @@ step-gclient-sync: &step-gclient-sync if ! git diff-index --quiet HEAD --; then # There are changes to the patches. Make a git commit with the updated patches git add patches - GIT_COMMITTER_NAME="Electron Bot" GIT_COMMITTER_EMAIL="electron@github.com" git commit -m "update patches" --author="Electron Bot " + GIT_COMMITTER_NAME="PatchUp" GIT_COMMITTER_EMAIL="73610968+patchup[bot]@users.noreply.github.com" git commit -m "chore: update patches" --author="PatchUp <73610968+patchup[bot]@users.noreply.github.com>" # Export it mkdir -p ../../patches git format-patch -1 --stdout --keep-subject --no-stat --full-index > ../../patches/update-patches.patch From faa1655880ac1b2ede2d356a19009989cf1cac41 Mon Sep 17 00:00:00 2001 From: Electron Bot Date: Tue, 18 May 2021 14:04:21 -0700 Subject: [PATCH 4/6] Bump v10.4.6 --- ELECTRON_VERSION | 2 +- package.json | 2 +- shell/browser/resources/win/electron.rc | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ELECTRON_VERSION b/ELECTRON_VERSION index 9dd5407ec81c5..d1d23e60aa74d 100644 --- a/ELECTRON_VERSION +++ b/ELECTRON_VERSION @@ -1 +1 @@ -10.4.5 \ No newline at end of file +10.4.6 \ No newline at end of file diff --git a/package.json b/package.json index aef9fc3372268..adb74c706debc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "electron", - "version": "10.4.5", + "version": "10.4.6", "repository": "https://github.com/electron/electron", "description": "Build cross platform desktop apps with JavaScript, HTML, and CSS", "devDependencies": { diff --git a/shell/browser/resources/win/electron.rc b/shell/browser/resources/win/electron.rc index 04353f4f0517f..249418bd6679d 100644 --- a/shell/browser/resources/win/electron.rc +++ b/shell/browser/resources/win/electron.rc @@ -50,8 +50,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 10,4,5,0 - PRODUCTVERSION 10,4,5,0 + FILEVERSION 10,4,6,0 + PRODUCTVERSION 10,4,6,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -68,12 +68,12 @@ BEGIN BEGIN VALUE "CompanyName", "GitHub, Inc." VALUE "FileDescription", "Electron" - VALUE "FileVersion", "10.4.5" + VALUE "FileVersion", "10.4.6" VALUE "InternalName", "electron.exe" VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved." VALUE "OriginalFilename", "electron.exe" VALUE "ProductName", "Electron" - VALUE "ProductVersion", "10.4.5" + VALUE "ProductVersion", "10.4.6" VALUE "SquirrelAwareVersion", "1" END END From fcdd18074f1c41f89c2376171a9eb170ee32226d Mon Sep 17 00:00:00 2001 From: Andrey Belenko Date: Thu, 20 May 2021 19:49:40 +0200 Subject: [PATCH 5/6] chore: backport the security fixes from Chromium release M90-3 (#29249) * Backports of security fixes in Chromium release M90-3 https://chromereleases.googleblog.com/2021/05/stable-channel-update-for-desktop.html Includes backports for the following Chromium issues: https://crbug.com/1204071 https://crbug.com/1203590 (CVE-2021-30518) https://crbug.com/1201446 (CVE-2021-30516) https://crbug.com/1201073 (CVE-2021-30515) https://crbug.com/1200490 (CVE-2021-30513) https://crbug.com/1200019 (CVE-2021-30512) https://crbug.com/1197436 (CVE-2021-30510) https://crbug.com/1195340 (CVE-2021-30508) https://crbug.com/1180126 https://crbug.com/1203667 * chore: update patches Co-authored-by: Andrey Belenko Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com> --- patches/chromium/.patches | 8 + ...utofill_fixed_refill_of_changed_form.patch | 41 ++++ ...der_before_dispatching_onabort_event.patch | 58 +++++ ...loadimage_against_malformed_renderer.patch | 231 ++++++++++++++++++ ...ble_media_feeds_and_related_features.patch | 30 +++ ...oper_action_icons_sent_from_renderer.patch | 148 +++++++++++ ...le_deletion_when_toggling_fullscreen.patch | 149 +++++++++++ ...ks_from_the_middle_of_app_names_when.patch | 50 ++++ ...se_observerlist_to_support_container.patch | 144 +++++++++++ patches/v8/.patches | 2 + ...2_fix_f64x2_min_max_to_use_registers.patch | 40 +++ ...runcation_bugs_in_simplifiedlowering.patch | 137 +++++++++++ 12 files changed, 1038 insertions(+) create mode 100644 patches/chromium/autofill_fixed_refill_of_changed_form.patch create mode 100644 patches/chromium/fileapi_terminate_filereaderloader_before_dispatching_onabort_event.patch create mode 100644 patches/chromium/guard_webcontents_downloadimage_against_malformed_renderer.patch create mode 100644 patches/chromium/media_feeds_disable_media_feeds_and_related_features.patch create mode 100644 patches/chromium/notifications_crash_if_improper_action_icons_sent_from_renderer.patch create mode 100644 patches/chromium/reland_views_handle_deletion_when_toggling_fullscreen.patch create mode 100644 patches/chromium/remove_tabs_and_line_breaks_from_the_middle_of_app_names_when.patch create mode 100644 patches/chromium/replace_std_vector_with_base_observerlist_to_support_container.patch create mode 100644 patches/v8/merged_wasm-simd_ia32_fix_f64x2_min_max_to_use_registers.patch create mode 100644 patches/v8/reland_compiler_fix_more_truncation_bugs_in_simplifiedlowering.patch diff --git a/patches/chromium/.patches b/patches/chromium/.patches index 90aaa1a2bd17e..6da7ce572c8d8 100644 --- a/patches/chromium/.patches +++ b/patches/chromium/.patches @@ -178,3 +178,11 @@ cherry-pick-5745eaf16077.patch cherry-pick-02f5ef8c88d7.patch cherry-pick-668cf831e912.patch cherry-pick-f37149c4434f.patch +replace_std_vector_with_base_observerlist_to_support_container.patch +guard_webcontents_downloadimage_against_malformed_renderer.patch +fileapi_terminate_filereaderloader_before_dispatching_onabort_event.patch +notifications_crash_if_improper_action_icons_sent_from_renderer.patch +reland_views_handle_deletion_when_toggling_fullscreen.patch +media_feeds_disable_media_feeds_and_related_features.patch +remove_tabs_and_line_breaks_from_the_middle_of_app_names_when.patch +autofill_fixed_refill_of_changed_form.patch diff --git a/patches/chromium/autofill_fixed_refill_of_changed_form.patch b/patches/chromium/autofill_fixed_refill_of_changed_form.patch new file mode 100644 index 0000000000000..521b4d1ee0c8f --- /dev/null +++ b/patches/chromium/autofill_fixed_refill_of_changed_form.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrey Belenko +Date: Wed, 19 May 2021 17:24:48 +0200 +Subject: Fixed refill of changed form. + +(cherry picked from commit 533bb3adcfe3499f90e2646fc60312f303b963ac) + +Bug: 1203667 +Change-Id: I2693a024531775e0e60cc330107d77d10558f466 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2867655 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2874611 + +diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc +index ded9c514894eee34a34eb562b08e7484673dfc4a..ca3b53835c2cacfeab893128a75e4d427d7993e8 100644 +--- a/components/autofill/core/browser/autofill_manager.cc ++++ b/components/autofill/core/browser/autofill_manager.cc +@@ -1740,7 +1740,10 @@ void AutofillManager::FillOrPreviewDataModelForm( + form_structure->RationalizePhoneNumbersInSection(autofill_field->section); + + FormData result = form; +- DCHECK_EQ(form_structure->field_count(), form.fields.size()); ++ // TODO(crbug/1203667#c9): Skip if the form has changed in the meantime, which ++ // may happen with refills. ++ if (form_structure->field_count() != form.fields.size()) ++ return; + + if (action == AutofillDriver::FORM_DATA_ACTION_FILL && !is_refill) { + filling_contexts_map_[form_structure->GetIdentifierForRefill()] = +@@ -1784,8 +1787,10 @@ void AutofillManager::FillOrPreviewDataModelForm( + continue; + } + +- // The field order should be the same in |form_structure| and |result|. +- DCHECK(form_structure->field(i)->SameFieldAs(result.fields[i])); ++ // TODO(crbug/1203667#c9): Skip if the form has changed in the meantime, ++ // which may happen with refills. ++ if (!form_structure->field(i)->SameFieldAs(result.fields[i])) ++ continue; + + AutofillField* cached_field = form_structure->field(i); + FieldTypeGroup field_group_type = cached_field->Type().group(); diff --git a/patches/chromium/fileapi_terminate_filereaderloader_before_dispatching_onabort_event.patch b/patches/chromium/fileapi_terminate_filereaderloader_before_dispatching_onabort_event.patch new file mode 100644 index 0000000000000..7adfba2e0c069 --- /dev/null +++ b/patches/chromium/fileapi_terminate_filereaderloader_before_dispatching_onabort_event.patch @@ -0,0 +1,58 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrey Belenko +Date: Wed, 19 May 2021 12:29:29 +0200 +Subject: FileAPI: Terminate FileReaderLoader before dispatching onabort event. + +Otherwise FileReader could end up in an inconsistent state where a load +is still in progress while the state was set to done. + +(cherry picked from commit a74c980df61dd7367ad1b11e6a735be82d2696f0) + +Bug: 1201073 +Change-Id: Ib2c833537e1badc57d125568d5d35f53f12582a8 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2860442 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2871355 + +diff --git a/third_party/blink/renderer/core/fileapi/file_reader.cc b/third_party/blink/renderer/core/fileapi/file_reader.cc +index 978d71510a5a0a790ea86dcd5413665ff624619c..8549fbef76a79cc4eff0fdc262e39720bfff40ba 100644 +--- a/third_party/blink/renderer/core/fileapi/file_reader.cc ++++ b/third_party/blink/renderer/core/fileapi/file_reader.cc +@@ -337,7 +337,10 @@ void FileReader::abort() { + loading_state_ = kLoadingStateAborted; + + DCHECK_NE(kDone, state_); +- state_ = kDone; ++ // Synchronously cancel the loader before dispatching events. This way we make ++ // sure the FileReader internal state stays consistent even if another load ++ // is started from one of the event handlers, or right after abort returns. ++ Terminate(); + + base::AutoReset firing_events(&still_firing_events_, true); + +@@ -349,15 +352,12 @@ void FileReader::abort() { + ThrottlingController::RemoveReader(GetExecutionContext(), this); + + FireEvent(event_type_names::kAbort); ++ // TODO(https://crbug.com/1204139): Only fire loadend event if no new load was ++ // started from the abort event handler. + FireEvent(event_type_names::kLoadend); + + // All possible events have fired and we're done, no more pending activity. + ThrottlingController::FinishReader(GetExecutionContext(), this, final_step); +- +- // Also synchronously cancel the loader, as script might initiate a new load +- // right after this method returns, in which case an async termination would +- // terminate the wrong loader. +- Terminate(); + } + + void FileReader::result(ScriptState* state, +@@ -429,6 +429,8 @@ void FileReader::DidFinishLoading() { + ThrottlingController::RemoveReader(GetExecutionContext(), this); + + FireEvent(event_type_names::kLoad); ++ // TODO(https://crbug.com/1204139): Only fire loadend event if no new load was ++ // started from the abort event handler. + FireEvent(event_type_names::kLoadend); + + // All possible events have fired and we're done, no more pending activity. diff --git a/patches/chromium/guard_webcontents_downloadimage_against_malformed_renderer.patch b/patches/chromium/guard_webcontents_downloadimage_against_malformed_renderer.patch new file mode 100644 index 0000000000000..278e0b8c6a5e3 --- /dev/null +++ b/patches/chromium/guard_webcontents_downloadimage_against_malformed_renderer.patch @@ -0,0 +1,231 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrey Belenko +Date: Wed, 19 May 2021 12:19:16 +0200 +Subject: Guard WebContents::DownloadImage() against malformed renderer + response + +Callers expect that ImageDownloadCallback gets invoked with two vectors +having the same number of elements (one containing the bitmaps and the +other one the corresponding sizes). + +However, these vectors are populated directly from the Mojo response, +so there needs to be some browser-process sanitization to protect +against buggy or compromised renderers. + +In this patch, WebContentsImpl::OnDidDownloadImage() mimics a 400 error +if the response is malformed, similarly to how it's done in other edge +cases (renderer process dead upon download). Because this scenario is +a violation of the Mojo API contract, the browser process also issues +a bad message log (newly-introduced WCI_INVALID_DOWNLOAD_IMAGE_RESULT) +and shuts down the renderer process. + +(cherry picked from commit 034ba14e44f08e8ca84b42350f3238f847e08e5f) + +Change-Id: Ic0843e10efc26809fabd8f1bbe506ba1703d1486 +Fixed: 1201446 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2871796 + +diff --git a/components/favicon/core/favicon_handler.cc b/components/favicon/core/favicon_handler.cc +index 64eab051de73b0b259c1f31e93f750d352724521..410ffc64e8f70a29a39cc4fb228dfd720bfe04d7 100644 +--- a/components/favicon/core/favicon_handler.cc ++++ b/components/favicon/core/favicon_handler.cc +@@ -492,6 +492,8 @@ void FaviconHandler::OnDidDownloadFavicon( + const GURL& image_url, + const std::vector& bitmaps, + const std::vector& original_bitmap_sizes) { ++ DCHECK_EQ(bitmaps.size(), original_bitmap_sizes.size()); ++ + // Mark download as finished. + image_download_request_.Cancel(); + +diff --git a/components/favicon/core/favicon_handler.h b/components/favicon/core/favicon_handler.h +index 8a1cf2ef85745711e94ec6e7f6f27acb1482cbd6..4192138711de470eee713fc1fb200cc29d333342 100644 +--- a/components/favicon/core/favicon_handler.h ++++ b/components/favicon/core/favicon_handler.h +@@ -237,7 +237,9 @@ class FaviconHandler { + void ScheduleImageDownload(const GURL& image_url, + favicon_base::IconType icon_type); + +- // Triggered when a download of an image has finished. ++ // Triggered when a download of an image has finished. |bitmaps| and ++ // |original_bitmap_sizes| must contain the same number of elements (i.e. same ++ // vector size). + void OnDidDownloadFavicon( + favicon_base::IconType icon_type, + int id, +diff --git a/components/favicon/ios/web_favicon_driver.mm b/components/favicon/ios/web_favicon_driver.mm +index 6efaf651bdf939d83e1a7f9df339f714410565ad..71ae020efd8862d2b33cb91df9180ef63df1f6f9 100644 +--- a/components/favicon/ios/web_favicon_driver.mm ++++ b/components/favicon/ios/web_favicon_driver.mm +@@ -75,6 +75,7 @@ int WebFaviconDriver::DownloadImage(const GURL& url, + for (const auto& frame : frames) { + sizes.push_back(gfx::Size(frame.width(), frame.height())); + } ++ DCHECK_EQ(frames.size(), sizes.size()); + } + std::move(local_callback) + .Run(local_download_id, metadata.http_response_code, local_url, +diff --git a/components/favicon_base/select_favicon_frames.cc b/components/favicon_base/select_favicon_frames.cc +index 90b58e621492d0e503f7965de91581c0a451d163..73cd7dd5331a818f413d831b4ae596bc88805a8a 100644 +--- a/components/favicon_base/select_favicon_frames.cc ++++ b/components/favicon_base/select_favicon_frames.cc +@@ -216,6 +216,7 @@ gfx::ImageSkia CreateFaviconImageSkia( + const std::vector& original_sizes, + int desired_size_in_dip, + float* score) { ++ DCHECK_EQ(bitmaps.size(), original_sizes.size()); + + const std::vector& favicon_scales = favicon_base::GetFaviconScales(); + std::vector desired_sizes; +diff --git a/components/favicon_base/select_favicon_frames.h b/components/favicon_base/select_favicon_frames.h +index 573a38c79cddf839622488589b71b4d19fbdfba6..eab1e54466763e5a6a6069a29e877da054972fa8 100644 +--- a/components/favicon_base/select_favicon_frames.h ++++ b/components/favicon_base/select_favicon_frames.h +@@ -38,6 +38,8 @@ extern const float kSelectFaviconFramesInvalidScore; + // it inspired by this method. + // If an unsupported scale (not in the favicon_base::GetFaviconScales()) + // is requested, the ImageSkia will automatically scales using lancoz3. ++// |original_sizes| represents the pixel sizes of the favicon bitmaps in ++// |bitmaps|, which also means both vectors must have the same size. + gfx::ImageSkia CreateFaviconImageSkia( + const std::vector& bitmaps, + const std::vector& original_sizes, +diff --git a/content/browser/bad_message.h b/content/browser/bad_message.h +index ab0a195c2da772ea5825bb97e54743318bd06841..efc803efe24f61012882399035f6d96aed799595 100644 +--- a/content/browser/bad_message.h ++++ b/content/browser/bad_message.h +@@ -256,6 +256,15 @@ enum BadMessageReason { + INPUT_ROUTER_INVALID_EVENT_SOURCE = 228, + RWH_CLOSE_PORTAL = 233, + MSDH_INVALID_STREAM_TYPE = 234, ++ RFH_CREATE_CHILD_FRAME_TOKENS_NOT_FOUND = 235, ++ ASGH_ASSOCIATED_INTERFACE_REQUEST = 236, ++ ASGH_RECEIVED_CONTROL_MESSAGE = 237, ++ CSDH_BAD_OWNER = 238, ++ SYNC_COMPOSITOR_NO_LOCAL_SURFACE_ID = 239, ++ WCI_INVALID_FULLSCREEN_OPTIONS = 240, ++ PAYMENTS_WITHOUT_PERMISSION = 241, ++ WEB_BUNDLE_INVALID_NAVIGATION_URL = 242, ++ WCI_INVALID_DOWNLOAD_IMAGE_RESULT = 243, + + // Please add new elements here. The naming convention is abbreviated class + // name (e.g. RenderFrameHost becomes RFH) plus a unique description of the +diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc +index a7c76413b86fac18f6f1f54c87e67218f094e6b2..67deba5a7ab4265c76fe18990ede82c2705efe70 100644 +--- a/content/browser/web_contents/web_contents_impl.cc ++++ b/content/browser/web_contents/web_contents_impl.cc +@@ -160,6 +160,7 @@ + #include "third_party/blink/public/common/security/security_style.h" + #include "third_party/blink/public/mojom/frame/frame.mojom.h" + #include "third_party/blink/public/mojom/frame/fullscreen.mojom.h" ++#include "third_party/blink/public/mojom/image_downloader/image_downloader.mojom.h" + #include "third_party/blink/public/mojom/loader/pause_subresource_loading_handle.mojom.h" + #include "third_party/blink/public/mojom/mediastream/media_stream.mojom-shared.h" + #include "third_party/skia/include/core/SkBitmap.h" +@@ -4295,18 +4296,18 @@ int WebContentsImpl::DownloadImageInFrame( + // respond with a 400 HTTP error code to indicate that something went wrong. + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, +- base::BindOnce(&WebContentsImpl::OnDidDownloadImage, +- weak_factory_.GetWeakPtr(), std::move(callback), +- download_id, url, 400, std::vector(), +- std::vector())); ++ base::BindOnce( ++ &WebContentsImpl::OnDidDownloadImage, weak_factory_.GetWeakPtr(), ++ initiator_frame->GetWeakPtr(), std::move(callback), download_id, ++ url, 400, std::vector(), std::vector())); + return download_id; + } + + mojo_image_downloader->DownloadImage( + url, is_favicon, preferred_size, max_bitmap_size, bypass_cache, + base::BindOnce(&WebContentsImpl::OnDidDownloadImage, +- weak_factory_.GetWeakPtr(), std::move(callback), +- download_id, url)); ++ weak_factory_.GetWeakPtr(), initiator_frame->GetWeakPtr(), ++ std::move(callback), download_id, url)); + return download_id; + } + +@@ -6829,12 +6830,28 @@ bool WebContentsImpl::CompletedFirstVisuallyNonEmptyPaint() { + } + + void WebContentsImpl::OnDidDownloadImage( ++ base::WeakPtr rfh, + ImageDownloadCallback callback, + int id, + const GURL& image_url, + int32_t http_status_code, + const std::vector& images, + const std::vector& original_image_sizes) { ++ ++ // Guard against buggy or compromised renderers that could violate the API ++ // contract that |images| and |original_image_sizes| must have the same ++ // length. ++ if (images.size() != original_image_sizes.size()) { ++ if (rfh) { ++ ReceivedBadMessage(rfh->GetProcess(), ++ bad_message::WCI_INVALID_DOWNLOAD_IMAGE_RESULT); ++ } ++ // Respond with a 400 to indicate that something went wrong. ++ std::move(callback).Run(id, 400, image_url, std::vector(), ++ std::vector()); ++ return; ++ } ++ + std::move(callback).Run(id, http_status_code, image_url, images, + original_image_sizes); + } +diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h +index 14586316aedab1e99f1b700ecc0e092c86414ee3..ffd53b3dc3ef0553711106f302e9f69b76b49081 100644 +--- a/content/browser/web_contents/web_contents_impl.h ++++ b/content/browser/web_contents/web_contents_impl.h +@@ -1403,7 +1403,8 @@ class CONTENT_EXPORT WebContentsImpl : public WebContents, + std::set& result); + + // Called with the result of a DownloadImage() request. +- void OnDidDownloadImage(ImageDownloadCallback callback, ++ void OnDidDownloadImage(base::WeakPtr rfh, ++ ImageDownloadCallback callback, + int id, + const GURL& image_url, + int32_t http_status_code, +diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h +index ca7651246f812259e43d5dbc429ae4a95ed60e94..a4572de2ee43ef0c2bb3a785f29974ebb8c1362c 100644 +--- a/content/public/browser/web_contents.h ++++ b/content/public/browser/web_contents.h +@@ -896,8 +896,9 @@ class WebContents : public PageNavigator, + // |bitmaps| will be empty on download failure. + // |sizes| are the sizes in pixels of the bitmaps before they were resized due + // to the max bitmap size passed to DownloadImage(). Each entry in the bitmaps +- // vector corresponds to an entry in the sizes vector. If a bitmap was +- // resized, there should be a single returned bitmap. ++ // vector corresponds to an entry in the sizes vector (both vector sizes are ++ // guaranteed to be equal). If a bitmap was resized, there should be a single ++ // returned bitmap. + using ImageDownloadCallback = + base::OnceCallback& unfiltered, + uint32_t max_image_size, +@@ -202,6 +203,8 @@ void ImageDownloaderImpl::DidDownloadImage( + FilterAndResizeImagesForMaximalSize(images, max_image_size, &result_images, + &result_original_image_sizes); + ++ DCHECK_EQ(result_images.size(), result_original_image_sizes.size()); ++ + std::move(callback).Run(http_status_code, result_images, + result_original_image_sizes); + } diff --git a/patches/chromium/media_feeds_disable_media_feeds_and_related_features.patch b/patches/chromium/media_feeds_disable_media_feeds_and_related_features.patch new file mode 100644 index 0000000000000..639577b439c28 --- /dev/null +++ b/patches/chromium/media_feeds_disable_media_feeds_and_related_features.patch @@ -0,0 +1,30 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrey Belenko +Date: Wed, 19 May 2021 14:17:10 +0200 +Subject: Media Feeds: Disable Media Feeds and related features + +Media Feeds is deleted in M91 and later and is unused in previous +versions as well. There is a security issue with Media Feeds though, so +we'd like to force it to be disabled in previous versions, so this CL +turns it off for M90. + +(cherry picked from commit b064a73431541e520d273c227e762983c2f177b7) + +Bug: 1195340 +Change-Id: I29e18be2abe4c1b4560d6324af3b6da93a97d947 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2847504 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2883741 + +diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc +index 162d2e2991aa34c8fc6acb14f8cbad5af27b12b9..e7b5ea2103bdca2faebac1d8d0a86b42418eed6b 100644 +--- a/media/base/media_switches.cc ++++ b/media/base/media_switches.cc +@@ -676,7 +676,7 @@ const base::Feature kMediaFeedsBackgroundFetching{ + + // Enables checking Media Feeds against safe search to prevent adult content. + const base::Feature kMediaFeedsSafeSearch{"MediaFeedsSafeSearch", +- base::FEATURE_ENABLED_BY_DEFAULT}; ++ base::FEATURE_DISABLED_BY_DEFAULT}; + + // Send events to devtools rather than to chrome://media-internals + const base::Feature kMediaInspectorLogging{"MediaInspectorLogging", diff --git a/patches/chromium/notifications_crash_if_improper_action_icons_sent_from_renderer.patch b/patches/chromium/notifications_crash_if_improper_action_icons_sent_from_renderer.patch new file mode 100644 index 0000000000000..f161a8adef2a2 --- /dev/null +++ b/patches/chromium/notifications_crash_if_improper_action_icons_sent_from_renderer.patch @@ -0,0 +1,148 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrey Belenko +Date: Wed, 19 May 2021 12:59:35 +0200 +Subject: Notifications: crash if improper action icons sent from renderer. + +Previously, the code only called DCHECK but as this data is from a +renderer we should probably crash the browser. + +(cherry picked from commit 3b28dc50187b22e080ad9c1e4e6c4f3b08f3136d) + +Bug: 1200019 +Change-Id: If4d9d48c8e18a3ed9c8bb3a50b952591259e0db5 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2838205 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2872493 + +diff --git a/chrome/browser/notifications/platform_notification_service_impl.cc b/chrome/browser/notifications/platform_notification_service_impl.cc +index 9071744d4093180850f2a5d7cf3fccd098138192..4fccc612e3cc761b72b629b5e0bd5da5cb29f71e 100644 +--- a/chrome/browser/notifications/platform_notification_service_impl.cc ++++ b/chrome/browser/notifications/platform_notification_service_impl.cc +@@ -401,8 +401,10 @@ PlatformNotificationServiceImpl::CreateNotificationFromData( + const std::string& notification_id, + const blink::PlatformNotificationData& notification_data, + const blink::NotificationResources& notification_resources) const { +- DCHECK_EQ(notification_data.actions.size(), +- notification_resources.action_icons.size()); ++ // Blink always populates action icons to match the actions, even if no icon ++ // was fetched, so this indicates a compromised renderer. ++ CHECK_EQ(notification_data.actions.size(), ++ notification_resources.action_icons.size()); + + message_center::RichNotificationData optional_fields; + +diff --git a/content/browser/notifications/blink_notification_service_impl.cc b/content/browser/notifications/blink_notification_service_impl.cc +index 7105781e0019b456f287fd0ebb6e309efe2cecad..575017c41e72df1686471b104ccfd06913314e25 100644 +--- a/content/browser/notifications/blink_notification_service_impl.cc ++++ b/content/browser/notifications/blink_notification_service_impl.cc +@@ -39,6 +39,9 @@ const char kBadMessageImproperNotificationImage[] = + "disabled."; + const char kBadMessageInvalidNotificationTriggerTimestamp[] = + "Received an invalid notification trigger timestamp."; ++const char kBadMessageInvalidNotificationActionButtons[] = ++ "Received a notification with a number of action images that does not " ++ "match the number of actions."; + + // Returns the implementation of the PlatformNotificationService. May be NULL. + PlatformNotificationService* GetNotificationService( +@@ -134,7 +137,8 @@ void BlinkNotificationServiceImpl::DisplayNonPersistentNotification( + mojo::PendingRemote + event_listener_remote) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); +- if (!ValidateNotificationResources(notification_resources)) ++ if (!ValidateNotificationDataAndResources(platform_notification_data, ++ notification_resources)) + return; + + if (!GetNotificationService(browser_context_)) +@@ -190,28 +194,31 @@ BlinkNotificationServiceImpl::CheckPermissionStatus() { + origin_.GetURL()); + } + +-bool BlinkNotificationServiceImpl::ValidateNotificationResources( ++bool BlinkNotificationServiceImpl::ValidateNotificationDataAndResources( ++ const blink::PlatformNotificationData& platform_notification_data, + const blink::NotificationResources& notification_resources) { +- if (notification_resources.image.drawsNothing() || +- base::FeatureList::IsEnabled(features::kNotificationContentImage)) +- return true; +- receiver_.ReportBadMessage(kBadMessageImproperNotificationImage); +- // The above ReportBadMessage() closes |binding_| but does not trigger its +- // connection error handler, so we need to call the error handler explicitly +- // here to do some necessary work. +- OnConnectionError(); +- return false; +-} ++ if (platform_notification_data.actions.size() != ++ notification_resources.action_icons.size()) { ++ receiver_.ReportBadMessage(kBadMessageInvalidNotificationActionButtons); ++ OnConnectionError(); ++ return false; ++ } + +-// Checks if this notification has a valid trigger. +-bool BlinkNotificationServiceImpl::ValidateNotificationData( +- const blink::PlatformNotificationData& notification_data) { +- if (!CheckNotificationTriggerRange(notification_data)) { ++ if (!CheckNotificationTriggerRange(platform_notification_data)) { + receiver_.ReportBadMessage(kBadMessageInvalidNotificationTriggerTimestamp); + OnConnectionError(); + return false; + } + ++ if (!notification_resources.image.drawsNothing() && ++ !base::FeatureList::IsEnabled(features::kNotificationContentImage)) { ++ receiver_.ReportBadMessage(kBadMessageImproperNotificationImage); ++ // The above ReportBadMessage() closes |binding_| but does not trigger its ++ // connection error handler, so we need to call the error handler explicitly ++ // here to do some necessary work. ++ OnConnectionError(); ++ return false; ++ } + return true; + } + +@@ -221,10 +228,8 @@ void BlinkNotificationServiceImpl::DisplayPersistentNotification( + const blink::NotificationResources& notification_resources, + DisplayPersistentNotificationCallback callback) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); +- if (!ValidateNotificationResources(notification_resources)) +- return; +- +- if (!ValidateNotificationData(platform_notification_data)) ++ if (!ValidateNotificationDataAndResources(platform_notification_data, ++ notification_resources)) + return; + + if (!GetNotificationService(browser_context_)) { +diff --git a/content/browser/notifications/blink_notification_service_impl.h b/content/browser/notifications/blink_notification_service_impl.h +index dc5307e6500b0bfb5da83e8d8ff8886b91133522..fe1abadd2bc196914cb7b6d9fe29a75435f08988 100644 +--- a/content/browser/notifications/blink_notification_service_impl.h ++++ b/content/browser/notifications/blink_notification_service_impl.h +@@ -72,20 +72,15 @@ class CONTENT_EXPORT BlinkNotificationServiceImpl + // Check the permission status for the current |origin_|. + blink::mojom::PermissionStatus CheckPermissionStatus(); + +- // Validate |notification_resources| received in a Mojo IPC message. +- // If the validation failed, we'd close the Mojo connection |binding_| and +- // destroy |this| by calling OnConnectionError() directly, then return false. +- // So, please do not touch |this| again after you got a false return value. +- bool ValidateNotificationResources( ++ // Validate |notification_data| and |notification_resources| received in a ++ // Mojo IPC message. If the validation failed, we'd close the Mojo connection ++ // |binding_| and destroy |this| by calling OnConnectionError() directly, then ++ // return false. So, please do not touch |this| again after you got a false ++ // return value. ++ bool ValidateNotificationDataAndResources( ++ const blink::PlatformNotificationData& notification_data, + const blink::NotificationResources& notification_resources); + +- // Validate |notification_data| received in a Mojo IPC message. +- // If the validation failed, we'd close the Mojo connection |binding_| and +- // destroy |this| by calling OnConnectionError() directly, then return false. +- // So, please do not touch |this| again after you got a false return value. +- bool ValidateNotificationData( +- const blink::PlatformNotificationData& notification_data); +- + void DidWriteNotificationData(DisplayPersistentNotificationCallback callback, + bool success, + const std::string& notification_id); diff --git a/patches/chromium/reland_views_handle_deletion_when_toggling_fullscreen.patch b/patches/chromium/reland_views_handle_deletion_when_toggling_fullscreen.patch new file mode 100644 index 0000000000000..55fa67c3ea449 --- /dev/null +++ b/patches/chromium/reland_views_handle_deletion_when_toggling_fullscreen.patch @@ -0,0 +1,149 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrey Belenko +Date: Wed, 19 May 2021 13:26:14 +0200 +Subject: views: handle deletion when toggling fullscreen + +This differs from the first in so far as needing to add more early +outs in the windows side if destroyed. This was caught by the asan +bot. + +Toggling fullscreen means the bounds change. There are some +code paths that may delete the Widget when the bounds changes. +This patch ensures the right thing happens if the Widget is +deleted when this happens. + +BUG=1197436 + +(cherry picked from commit 60fe7a686c0620855c28a60721f668a99e409ee4) + +Change-Id: I8ce8f2045878b6f6de530f58e386149189900498 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2857227 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2868317 + +diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc +index aaf1b482f71a9fbf047ce8bd37cefd31d6947770..da6ba0505bbf99c0c7c58e28019c28332b31e490 100644 +--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc ++++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc +@@ -585,7 +585,10 @@ void DesktopWindowTreeHostPlatform::SetFullscreen(bool fullscreen) { + if (IsFullscreen() == fullscreen) + return; + ++ auto weak_ptr = GetWeakPtr(); + platform_window()->ToggleFullscreen(); ++ if (!weak_ptr) ++ return; + + // The state must change synchronously to let media react on fullscreen + // changes. +diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc +index b5430b871cfcc8c9aa54ac1f5aa9ec699c7aac86..1de1f16f61b16966a8a79efc055132804192829d 100644 +--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc ++++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_win.cc +@@ -462,7 +462,10 @@ void DesktopWindowTreeHostWin::FrameTypeChanged() { + } + + void DesktopWindowTreeHostWin::SetFullscreen(bool fullscreen) { ++ auto weak_ptr = GetWeakPtr(); + message_handler_->SetFullscreen(fullscreen); ++ if (!weak_ptr) ++ return; + // TODO(sky): workaround for ScopedFullscreenVisibility showing window + // directly. Instead of this should listen for visibility changes and then + // update window. +diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc +index a06ebe82c33f11fb2cd90382029cb0b5c20ce6de..b590396343e12d92016103720461805372319639 100644 +--- a/ui/views/widget/widget.cc ++++ b/ui/views/widget/widget.cc +@@ -722,7 +722,10 @@ void Widget::SetFullscreen(bool fullscreen) { + if (IsFullscreen() == fullscreen) + return; + ++ auto weak_ptr = GetWeakPtr(); + native_widget_->SetFullscreen(fullscreen); ++ if (!weak_ptr) ++ return; + + if (non_client_view_) + non_client_view_->InvalidateLayout(); +diff --git a/ui/views/win/fullscreen_handler.cc b/ui/views/win/fullscreen_handler.cc +index 8791362556fcd7544b79982dd6535d55ecd25a50..708d28f45028ee10459c7973d51caecfe0d09097 100644 +--- a/ui/views/win/fullscreen_handler.cc ++++ b/ui/views/win/fullscreen_handler.cc +@@ -70,6 +70,7 @@ void FullscreenHandler::SetFullscreenImpl(bool fullscreen) { + + fullscreen_ = fullscreen; + ++ auto ref = weak_ptr_factory_.GetWeakPtr(); + if (fullscreen_) { + // Set new window style and size. + SetWindowLong(hwnd_, GWL_STYLE, +@@ -102,6 +103,8 @@ void FullscreenHandler::SetFullscreenImpl(bool fullscreen) { + new_rect.height(), + SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED); + } ++ if (!ref) ++ return; + + MarkFullscreen(fullscreen); + } +diff --git a/ui/views/win/fullscreen_handler.h b/ui/views/win/fullscreen_handler.h +index fe17c7f0368b1dd35a37006033ddf34d35ea3982..c76ef18a6f59e9239d5a281d26c6e34646b68ee3 100644 +--- a/ui/views/win/fullscreen_handler.h ++++ b/ui/views/win/fullscreen_handler.h +@@ -11,6 +11,7 @@ + #include + + #include "base/macros.h" ++#include "base/memory/weak_ptr.h" + + namespace gfx { + class Rect; +@@ -54,6 +55,8 @@ class FullscreenHandler { + // Used to mark a window as fullscreen. + Microsoft::WRL::ComPtr task_bar_list_; + ++ base::WeakPtrFactory weak_ptr_factory_{this}; ++ + DISALLOW_COPY_AND_ASSIGN(FullscreenHandler); + }; + +diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc +index 39518ac65d091bc52a26cf84b89fa350459e874b..68ed019d5cf6d2af084ce6ec7745b8814ea14a39 100644 +--- a/ui/views/win/hwnd_message_handler.cc ++++ b/ui/views/win/hwnd_message_handler.cc +@@ -900,7 +900,10 @@ void HWNDMessageHandler::SetWindowIcons(const gfx::ImageSkia& window_icon, + + void HWNDMessageHandler::SetFullscreen(bool fullscreen) { + background_fullscreen_hack_ = false; ++ auto ref = msg_handler_weak_factory_.GetWeakPtr(); + fullscreen_handler()->SetFullscreen(fullscreen); ++ if (!ref) ++ return; + + // Add the fullscreen window to the fullscreen window map which is used to + // handle window activations. +@@ -1401,8 +1404,10 @@ void HWNDMessageHandler::ClientAreaSizeChanged() { + // Ignore size changes due to fullscreen windows losing activation. + if (background_fullscreen_hack_ && !sent_window_size_changing_) + return; +- gfx::Size s = GetClientAreaBounds().size(); +- delegate_->HandleClientSizeChanged(s); ++ auto ref = msg_handler_weak_factory_.GetWeakPtr(); ++ delegate_->HandleClientSizeChanged(GetClientAreaBounds().size()); ++ if (!ref) ++ return; + + current_window_size_message_++; + sent_window_size_changing_ = false; +@@ -2925,8 +2930,11 @@ void HWNDMessageHandler::OnWindowPosChanging(WINDOWPOS* window_pos) { + void HWNDMessageHandler::OnWindowPosChanged(WINDOWPOS* window_pos) { + TRACE_EVENT0("ui", "HWNDMessageHandler::OnWindowPosChanged"); + ++ base::WeakPtr ref(msg_handler_weak_factory_.GetWeakPtr()); + if (DidClientAreaSizeChange(window_pos)) + ClientAreaSizeChanged(); ++ if (!ref) ++ return; + if (window_pos->flags & SWP_FRAMECHANGED) + SetDwmFrameExtension(DwmFrameState::kOn); + if (window_pos->flags & SWP_SHOWWINDOW) { diff --git a/patches/chromium/remove_tabs_and_line_breaks_from_the_middle_of_app_names_when.patch b/patches/chromium/remove_tabs_and_line_breaks_from_the_middle_of_app_names_when.patch new file mode 100644 index 0000000000000..ccc1a3b450b8f --- /dev/null +++ b/patches/chromium/remove_tabs_and_line_breaks_from_the_middle_of_app_names_when.patch @@ -0,0 +1,50 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrey Belenko +Date: Wed, 19 May 2021 17:13:11 +0200 +Subject: Remove tabs and line breaks from the middle of app names when + parsing. + +(cherry picked from commit f9b0a09d60acabadfcb9ddeacc9d943cc9811199) + +Bug: 1180126 +Change-Id: Ie6f08d45f97214c4f1ab766aa8af001b8fb8599c +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2821876 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2877715 + +diff --git a/third_party/blink/renderer/modules/manifest/manifest_parser.cc b/third_party/blink/renderer/modules/manifest/manifest_parser.cc +index 8a80176fb4626f2e916176412ba0a8a518de80e6..0cf2d9e04cabbd69af7a7a66c5a07e69508e6d24 100644 +--- a/third_party/blink/renderer/modules/manifest/manifest_parser.cc ++++ b/third_party/blink/renderer/modules/manifest/manifest_parser.cc +@@ -40,6 +40,10 @@ bool VerifyFiles(const Vector& files) { + return true; + } + ++static bool IsCrLfOrTabChar(UChar c) { ++ return c == '\n' || c == '\r' || c == '\t'; ++} ++ + } // anonymous namespace + + ManifestParser::ManifestParser(const String& data, +@@ -238,11 +242,21 @@ KURL ManifestParser::ParseURL(const JSONObject* object, + + String ManifestParser::ParseName(const JSONObject* object) { + base::Optional name = ParseString(object, "name", Trim); ++ if (name.has_value()) { ++ name = name->RemoveCharacters(IsCrLfOrTabChar); ++ if (name->length() == 0) ++ name = base::nullopt; ++ } + return name.has_value() ? *name : String(); + } + + String ManifestParser::ParseShortName(const JSONObject* object) { + base::Optional short_name = ParseString(object, "short_name", Trim); ++ if (short_name.has_value()) { ++ short_name = short_name->RemoveCharacters(IsCrLfOrTabChar); ++ if (short_name->length() == 0) ++ short_name = base::nullopt; ++ } + return short_name.has_value() ? *short_name : String(); + } + diff --git a/patches/chromium/replace_std_vector_with_base_observerlist_to_support_container.patch b/patches/chromium/replace_std_vector_with_base_observerlist_to_support_container.patch new file mode 100644 index 0000000000000..d7edab9e08864 --- /dev/null +++ b/patches/chromium/replace_std_vector_with_base_observerlist_to_support_container.patch @@ -0,0 +1,144 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrey Belenko +Date: Tue, 18 May 2021 23:22:53 +0200 +Subject: Replace std::vector with base::ObserverList to support container + modification while iterating + +TaskTracker saves list of viewers in vector, that needs to be notified +when distillation is completed. At the time of notifying the viewers, +we are indirectly erasing viewers from vector while iterating. + +This is causing container-overflow in asan build when vector has more +than one viewer while notifying. + +This change is to replace vector with ObserverList that can be modified +during iteration without invalidating the iterator. + +(cherry picked from commit be19f42dab0706d5fdd74acd6eaa424e9277e9c4) + +Bug: 1203590 +Change-Id: I7c7b8237584c48c9ebc2639b9268a6a78c2db4b2 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2856118 +Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2883743 + +diff --git a/base/observer_list.h b/base/observer_list.h +index 52c8fad0d2a0a24e4daa52ec5659906085660b77..536e0bcd846e3cb9f38e28e61865aad7b7e04a25 100644 +--- a/base/observer_list.h ++++ b/base/observer_list.h +@@ -272,6 +272,7 @@ class ObserverList { + NOTREACHED() << "Observers can only be added once!"; + return; + } ++ observers_count_++; + observers_.emplace_back(ObserverStorageType(obs)); + } + +@@ -284,7 +285,8 @@ class ObserverList { + [obs](const auto& o) { return o.IsEqual(obs); }); + if (it == observers_.end()) + return; +- ++ if (!it->IsMarkedForRemoval()) ++ observers_count_--; + if (live_iterators_.empty()) { + observers_.erase(it); + } else { +@@ -314,8 +316,12 @@ class ObserverList { + for (auto& observer : observers_) + observer.MarkForRemoval(); + } ++ ++ observers_count_ = 0; + } + ++ bool empty() const { return !observers_count_; } ++ + bool might_have_observers() const { return !observers_.empty(); } + + private: +@@ -334,6 +340,8 @@ class ObserverList { + + base::LinkedList> live_iterators_; + ++ size_t observers_count_{0}; ++ + const ObserverListPolicy policy_; + + SEQUENCE_CHECKER(iteration_sequence_checker_); +diff --git a/components/dom_distiller/core/task_tracker.cc b/components/dom_distiller/core/task_tracker.cc +index e66a62c4091e44183253ba7221db6dedcca4a1a2..f22c88967bc7d7b1a32339657b5fc2bf8248bbde 100644 +--- a/components/dom_distiller/core/task_tracker.cc ++++ b/components/dom_distiller/core/task_tracker.cc +@@ -85,7 +85,7 @@ void TaskTracker::AddSaveCallback(SaveCallback callback) { + + std::unique_ptr TaskTracker::AddViewer( + ViewRequestDelegate* delegate) { +- viewers_.push_back(delegate); ++ viewers_.AddObserver(delegate); + if (content_ready_) { + // Distillation for this task has already completed, and so the delegate can + // be immediately told of the result. +@@ -115,7 +115,7 @@ bool TaskTracker::HasUrl(const GURL& url) const { + } + + void TaskTracker::RemoveViewer(ViewRequestDelegate* delegate) { +- base::Erase(viewers_, delegate); ++ viewers_.RemoveObserver(delegate); + if (viewers_.empty()) { + MaybeCancel(); + } +@@ -219,8 +219,8 @@ void TaskTracker::DistilledArticleReady( + } + + void TaskTracker::NotifyViewersAndCallbacks() { +- for (auto* viewer : viewers_) { +- NotifyViewer(viewer); ++ for (auto& viewer : viewers_) { ++ NotifyViewer(&viewer); + } + + // Already inside a callback run SaveCallbacks directly. +@@ -242,8 +242,8 @@ void TaskTracker::DoSaveCallbacks(bool success) { + + void TaskTracker::OnArticleDistillationUpdated( + const ArticleDistillationUpdate& article_update) { +- for (auto* viewer : viewers_) { +- viewer->OnArticleUpdated(article_update); ++ for (auto& viewer : viewers_) { ++ viewer.OnArticleUpdated(article_update); + } + } + +diff --git a/components/dom_distiller/core/task_tracker.h b/components/dom_distiller/core/task_tracker.h +index 484145cf7d176fd0c3f2fa73da4cf94c23cc0bda..cc13e7272923ec3de52bcea186fdc30391c8cd2b 100644 +--- a/components/dom_distiller/core/task_tracker.h ++++ b/components/dom_distiller/core/task_tracker.h +@@ -11,6 +11,7 @@ + #include "base/bind.h" + #include "base/callback.h" + #include "base/memory/weak_ptr.h" ++#include "base/observer_list.h" + #include "components/dom_distiller/core/article_distillation_update.h" + #include "components/dom_distiller/core/article_entry.h" + #include "components/dom_distiller/core/distiller.h" +@@ -40,9 +41,9 @@ class ViewerHandle { + + // Interface for a DOM distiller entry viewer. Implement this to make a view + // request and receive the data for an entry when it becomes available. +-class ViewRequestDelegate { ++class ViewRequestDelegate : public base::CheckedObserver { + public: +- virtual ~ViewRequestDelegate() = default; ++ ~ViewRequestDelegate() override = default; + + // Called when the distilled article contents are available. The + // DistilledArticleProto is owned by a TaskTracker instance and is invalidated +@@ -140,7 +141,7 @@ class TaskTracker { + std::vector save_callbacks_; + // A ViewRequestDelegate will be added to this list when a view request is + // made and removed when the corresponding ViewerHandle is destroyed. +- std::vector viewers_; ++ base::ObserverList viewers_; + + std::unique_ptr distiller_; + bool blob_fetcher_running_; diff --git a/patches/v8/.patches b/patches/v8/.patches index 16c1e2ed92040..06243fedc3888 100644 --- a/patches/v8/.patches +++ b/patches/v8/.patches @@ -34,3 +34,5 @@ merged_squashed_multiple_commits.patch merged_compiler_fix_a_bug_in_visitspeculativeintegeradditiveop.patch merged_turbofan_harden_arrayprototypepop_and_arrayprototypeshift.patch m86-lts_compiler_fix_off-by-one_error_in_kadditivesafeinteger.patch +merged_wasm-simd_ia32_fix_f64x2_min_max_to_use_registers.patch +reland_compiler_fix_more_truncation_bugs_in_simplifiedlowering.patch diff --git a/patches/v8/merged_wasm-simd_ia32_fix_f64x2_min_max_to_use_registers.patch b/patches/v8/merged_wasm-simd_ia32_fix_f64x2_min_max_to_use_registers.patch new file mode 100644 index 0000000000000..cdb18dbe35a80 --- /dev/null +++ b/patches/v8/merged_wasm-simd_ia32_fix_f64x2_min_max_to_use_registers.patch @@ -0,0 +1,40 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrey Belenko +Date: Tue, 18 May 2021 17:58:48 +0200 +Subject: Merged: [wasm-simd][ia32] Fix f64x2 min max to use registers + +We don't have memory alignment yet, so using memory operands will cause +segv if we try to access the unaligned operands (on non-AVX systems). + +The fix here is kept simple (the logic can be cleaned up a bit and +optimized to not use unique registers), in order to keep the cherry-pick +and back-merge as small and safe as possible. + +(cherry picked from commit 7f2d41fa3748ecc8fc888d93f82d77718b1dd6b0) + +Bug: chromium:1204071 +Change-Id: I7d7d177ff096ebd3de399fcf1ec7d9ac57bbb80b +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2872565 + +diff --git a/src/compiler/backend/ia32/instruction-selector-ia32.cc b/src/compiler/backend/ia32/instruction-selector-ia32.cc +index 5ed7c24e6bf4d955f126d96b8b4cd467b81ec94b..618a171d834c3e9ac3e2352877a7dfd0c1799431 100644 +--- a/src/compiler/backend/ia32/instruction-selector-ia32.cc ++++ b/src/compiler/backend/ia32/instruction-selector-ia32.cc +@@ -2181,7 +2181,7 @@ void InstructionSelector::VisitF64x2Min(Node* node) { + IA32OperandGenerator g(this); + InstructionOperand temps[] = {g.TempSimd128Register()}; + InstructionOperand operand0 = g.UseUniqueRegister(node->InputAt(0)); +- InstructionOperand operand1 = g.UseUnique(node->InputAt(1)); ++ InstructionOperand operand1 = g.UseUniqueRegister(node->InputAt(1)); + + if (IsSupported(AVX)) { + Emit(kIA32F64x2Min, g.DefineAsRegister(node), operand0, operand1, +@@ -2196,7 +2196,7 @@ void InstructionSelector::VisitF64x2Max(Node* node) { + IA32OperandGenerator g(this); + InstructionOperand temps[] = {g.TempSimd128Register()}; + InstructionOperand operand0 = g.UseUniqueRegister(node->InputAt(0)); +- InstructionOperand operand1 = g.UseUnique(node->InputAt(1)); ++ InstructionOperand operand1 = g.UseUniqueRegister(node->InputAt(1)); + if (IsSupported(AVX)) { + Emit(kIA32F64x2Max, g.DefineAsRegister(node), operand0, operand1, + arraysize(temps), temps); diff --git a/patches/v8/reland_compiler_fix_more_truncation_bugs_in_simplifiedlowering.patch b/patches/v8/reland_compiler_fix_more_truncation_bugs_in_simplifiedlowering.patch new file mode 100644 index 0000000000000..3ab5ef71910cd --- /dev/null +++ b/patches/v8/reland_compiler_fix_more_truncation_bugs_in_simplifiedlowering.patch @@ -0,0 +1,137 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrey Belenko +Date: Tue, 18 May 2021 22:03:37 +0200 +Subject: Reland "[compiler] Fix more truncation bugs in SimplifiedLowering" + +This is a reland of 47077d94492cb604e3a7f02c0d7c3c495ff6b713 without +changes. The revert was false alarm. + +Original change's description: +> [compiler] Fix more truncation bugs in SimplifiedLowering +> +> Bug: chromium:1200490 +> Change-Id: I3555b6d99bdb4b4e7c302a43a82c17e8bff84ebe +> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2840452 + +Bug: chromium:1200490 +Change-Id: I75cac59050bc393d157a1ee5bed776c8986a7bbe +Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2843817 + +diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc +index 97bd328c28e24d25e1813399b798ecdb8a248cfd..df050006ebe07ce263445d0160038c31f19a562c 100644 +--- a/src/compiler/simplified-lowering.cc ++++ b/src/compiler/simplified-lowering.cc +@@ -1401,17 +1401,32 @@ class RepresentationSelector { + return jsgraph_->simplified(); + } + +- void LowerToCheckedInt32Mul(Node* node, Truncation truncation, +- Type input0_type, Type input1_type) { +- // If one of the inputs is positive and/or truncation is being applied, +- // there is no need to return -0. +- CheckForMinusZeroMode mz_mode = +- truncation.IdentifiesZeroAndMinusZero() || +- IsSomePositiveOrderedNumber(input0_type) || +- IsSomePositiveOrderedNumber(input1_type) +- ? CheckForMinusZeroMode::kDontCheckForMinusZero +- : CheckForMinusZeroMode::kCheckForMinusZero; +- NodeProperties::ChangeOp(node, simplified()->CheckedInt32Mul(mz_mode)); ++ template ++ void VisitForCheckedInt32Mul(Node* node, Truncation truncation, ++ Type input0_type, Type input1_type, ++ UseInfo input_use) { ++ DCHECK_EQ(node->opcode(), IrOpcode::kSpeculativeNumberMultiply); ++ // A -0 input is impossible or will cause a deopt. ++ DCHECK(BothInputsAre(node, Type::Signed32()) || ++ !input_use.truncation().IdentifiesZeroAndMinusZero()); ++ ++ CheckForMinusZeroMode mz_mode; ++ Type restriction; ++ if (IsSomePositiveOrderedNumber(input0_type) || ++ IsSomePositiveOrderedNumber(input1_type)) { ++ mz_mode = CheckForMinusZeroMode::kDontCheckForMinusZero; ++ restriction = Type::Signed32(); ++ } else if (truncation.IdentifiesZeroAndMinusZero()) { ++ mz_mode = CheckForMinusZeroMode::kDontCheckForMinusZero; ++ restriction = Type::Signed32OrMinusZero(); ++ } else { ++ mz_mode = CheckForMinusZeroMode::kCheckForMinusZero; ++ restriction = Type::Signed32(); ++ } ++ ++ VisitBinop(node, input_use, MachineRepresentation::kWord32, restriction); ++ if (lower()) ++ NodeProperties::ChangeOp(node, simplified()->CheckedInt32Mul(mz_mode)); + } + + void ChangeToInt32OverflowOp(Node* node) { +@@ -1603,12 +1618,22 @@ class RepresentationSelector { + VisitBinop(node, lhs_use, rhs_use, MachineRepresentation::kWord32); + if (lower()) DeferReplacement(node, lowering->Int32Mod(node)); + } else if (BothInputsAre(node, Type::Unsigned32OrMinusZeroOrNaN())) { ++ Type const restriction = ++ truncation.IdentifiesZeroAndMinusZero() && ++ TypeOf(node->InputAt(0)).Maybe(Type::MinusZero()) ++ ? Type::Unsigned32OrMinusZero() ++ : Type::Unsigned32(); + VisitBinop(node, lhs_use, rhs_use, MachineRepresentation::kWord32, +- Type::Unsigned32()); ++ restriction); + if (lower()) ChangeToUint32OverflowOp(node); + } else { ++ Type const restriction = ++ truncation.IdentifiesZeroAndMinusZero() && ++ TypeOf(node->InputAt(0)).Maybe(Type::MinusZero()) ++ ? Type::Signed32OrMinusZero() ++ : Type::Signed32(); + VisitBinop(node, lhs_use, rhs_use, MachineRepresentation::kWord32, +- Type::Signed32()); ++ restriction); + if (lower()) ChangeToInt32OverflowOp(node); + } + return; +@@ -2172,23 +2197,17 @@ class RepresentationSelector { + // If both inputs and feedback are int32, use the overflow op. + if (hint == NumberOperationHint::kSignedSmall || + hint == NumberOperationHint::kSigned32) { +- VisitBinop(node, UseInfo::TruncatingWord32(), +- MachineRepresentation::kWord32, Type::Signed32()); +- if (lower()) { +- LowerToCheckedInt32Mul(node, truncation, input0_type, +- input1_type); +- } ++ VisitForCheckedInt32Mul(node, truncation, input0_type, ++ input1_type, ++ UseInfo::TruncatingWord32()); + return; + } + } + + if (hint == NumberOperationHint::kSignedSmall || + hint == NumberOperationHint::kSigned32) { +- VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint), +- MachineRepresentation::kWord32, Type::Signed32()); +- if (lower()) { +- LowerToCheckedInt32Mul(node, truncation, input0_type, input1_type); +- } ++ VisitForCheckedInt32Mul(node, truncation, input0_type, input1_type, ++ CheckedUseInfoAsWord32FromHint(hint)); + return; + } + +@@ -3895,7 +3914,6 @@ template <> + void RepresentationSelector::SetOutput( + Node* node, MachineRepresentation representation, Type restriction_type) { + NodeInfo* const info = GetInfo(node); +- DCHECK(info->restriction_type().Is(restriction_type)); + DCHECK(restriction_type.Is(info->restriction_type())); + info->set_output(representation); + } +@@ -3905,7 +3923,6 @@ void RepresentationSelector::SetOutput( + Node* node, MachineRepresentation representation, Type restriction_type) { + NodeInfo* const info = GetInfo(node); + DCHECK_EQ(info->representation(), representation); +- DCHECK(info->restriction_type().Is(restriction_type)); + DCHECK(restriction_type.Is(info->restriction_type())); + USE(info); + } From 9fc28e2296b99a970cc58cdcbf17b0f2a743617a Mon Sep 17 00:00:00 2001 From: Electron Bot Date: Mon, 24 May 2021 08:50:38 -0700 Subject: [PATCH 6/6] Bump v10.4.7 --- ELECTRON_VERSION | 2 +- package.json | 2 +- shell/browser/resources/win/electron.rc | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ELECTRON_VERSION b/ELECTRON_VERSION index d1d23e60aa74d..4ab9d20ad3e80 100644 --- a/ELECTRON_VERSION +++ b/ELECTRON_VERSION @@ -1 +1 @@ -10.4.6 \ No newline at end of file +10.4.7 \ No newline at end of file diff --git a/package.json b/package.json index adb74c706debc..8752e7dc3bb41 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "electron", - "version": "10.4.6", + "version": "10.4.7", "repository": "https://github.com/electron/electron", "description": "Build cross platform desktop apps with JavaScript, HTML, and CSS", "devDependencies": { diff --git a/shell/browser/resources/win/electron.rc b/shell/browser/resources/win/electron.rc index 249418bd6679d..680ea2ad56c18 100644 --- a/shell/browser/resources/win/electron.rc +++ b/shell/browser/resources/win/electron.rc @@ -50,8 +50,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 10,4,6,0 - PRODUCTVERSION 10,4,6,0 + FILEVERSION 10,4,7,0 + PRODUCTVERSION 10,4,7,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -68,12 +68,12 @@ BEGIN BEGIN VALUE "CompanyName", "GitHub, Inc." VALUE "FileDescription", "Electron" - VALUE "FileVersion", "10.4.6" + VALUE "FileVersion", "10.4.7" VALUE "InternalName", "electron.exe" VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved." VALUE "OriginalFilename", "electron.exe" VALUE "ProductName", "Electron" - VALUE "ProductVersion", "10.4.6" + VALUE "ProductVersion", "10.4.7" VALUE "SquirrelAwareVersion", "1" END END