fix: prevent crash when keyboard event immediately precedes calling BrowserWindow.close() (#27359)

* fix: prevent crash when destroyed widget receives keyboard event

Activating a key to close a window will cause a silent crash. Handling the keyboard
event will lead to a nullptr dereferenced in Chromium code if the window widget has
already been destroyed.

* test: ensure BrowserWindow doesn't crash from keyboard events during close

Co-authored-by: samuelmaddock <samuel.maddock@gmail.com>
This commit is contained in:
trop[bot]
2021-01-19 15:51:09 +09:00
committed by GitHub
parent a6af3bd8df
commit 9278459c46
3 changed files with 17 additions and 0 deletions

View File

@@ -1415,6 +1415,10 @@ void NativeWindowViews::OnWidgetDestroying(views::Widget* widget) {
#endif
}
void NativeWindowViews::OnWidgetDestroyed(views::Widget* changed_widget) {
widget_destroyed_ = true;
}
void NativeWindowViews::DeleteDelegate() {
if (is_modal() && this->parent()) {
auto* parent = this->parent();
@@ -1511,6 +1515,9 @@ void NativeWindowViews::OnWidgetMove() {
void NativeWindowViews::HandleKeyboardEvent(
content::WebContents*,
const content::NativeWebKeyboardEvent& event) {
if (widget_destroyed_)
return;
#if defined(OS_LINUX)
if (event.windows_key_code == ui::VKEY_BROWSER_BACK)
NotifyWindowExecuteAppCommand(kBrowserBackward);

View File

@@ -174,6 +174,7 @@ class NativeWindowViews : public NativeWindow,
void OnWidgetBoundsChanged(views::Widget* widget,
const gfx::Rect& bounds) override;
void OnWidgetDestroying(views::Widget* widget) override;
void OnWidgetDestroyed(views::Widget* widget) override;
// views::WidgetDelegate:
void DeleteDelegate() override;
@@ -313,6 +314,7 @@ class NativeWindowViews : public NativeWindow,
std::string title_;
gfx::Size widget_size_;
double opacity_ = 1.0;
bool widget_destroyed_ = false;
DISALLOW_COPY_AND_ASSIGN(NativeWindowViews);
};

View File

@@ -110,6 +110,14 @@ describe('BrowserWindow module', () => {
await emittedOnce(w.webContents, 'before-unload-fired');
});
it('should not crash when keyboard event is sent before closing', async () => {
await w.loadURL('data:text/html,pls no crash');
const closed = emittedOnce(w, 'closed');
w.webContents.sendInputEvent({ type: 'keyDown', keyCode: 'Escape' });
w.close();
await closed;
});
describe('when invoked synchronously inside navigation observer', () => {
let server: http.Server = null as unknown as http.Server;
let url: string = null as unknown as string;