From a04932c4eb1d451692e21cf22daa59044c846bc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E5=B1=B1=E9=A2=A8=E9=9C=B2?= Date: Tue, 12 Mar 2024 00:28:18 +0900 Subject: [PATCH] Windows: fix crash with unhandled window (#9164) On Windows, some windows may be created that are not managed by the application. For example, the Japanese IME creates pop-ups like this one. image The internal data associated with such a window is different from `WindowsWindowInner` and will crash if referenced. Therefore, before calling `try_get_window_inner`, it checks if it is an owned window. Release Notes: - N/A --- crates/gpui/src/platform/windows/platform.rs | 34 ++++++++++++++++---- crates/gpui/src/platform/windows/window.rs | 9 ++++-- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index 5e7768b7e1b797c5c416e7d27e7dd40c655fd6f6..4e08aff282a53da62d360131dd71caa82888185c 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -72,13 +72,15 @@ pub(crate) struct WindowsPlatformSystemSettings { pub(crate) wheel_scroll_lines: u32, } +type WindowHandleValues = HashSet; + pub(crate) struct WindowsPlatformInner { background_executor: BackgroundExecutor, pub(crate) foreground_executor: ForegroundExecutor, main_receiver: flume::Receiver, text_system: Arc, callbacks: Mutex, - pub(crate) window_handles: RefCell>, + pub(crate) window_handle_values: RefCell, pub(crate) event: HANDLE, pub(crate) settings: RefCell, } @@ -165,7 +167,7 @@ impl WindowsPlatform { let foreground_executor = ForegroundExecutor::new(dispatcher); let text_system = Arc::new(WindowsTextSystem::new()); let callbacks = Mutex::new(Callbacks::default()); - let window_handles = RefCell::new(HashSet::new()); + let window_handle_values = RefCell::new(HashSet::new()); let settings = RefCell::new(WindowsPlatformSystemSettings::new()); let inner = Rc::new(WindowsPlatformInner { background_executor, @@ -173,7 +175,7 @@ impl WindowsPlatform { main_receiver, text_system, callbacks, - window_handles, + window_handle_values, event, settings, }); @@ -188,6 +190,15 @@ impl WindowsPlatform { return true; } + if !self + .inner + .window_handle_values + .borrow() + .contains(&msg.hwnd.0) + { + return false; + } + if let Some(inner) = try_get_window_inner(msg.hwnd) { inner.handle_immediate_msg(msg.message, msg.wParam, msg.lParam) } else { @@ -202,7 +213,11 @@ impl WindowsPlatform { } } -unsafe extern "system" fn invalidate_window_callback(hwnd: HWND, _: LPARAM) -> BOOL { +unsafe extern "system" fn invalidate_window_callback(hwnd: HWND, lparam: LPARAM) -> BOOL { + let window_handle_values = unsafe { &*(lparam.0 as *const WindowHandleValues) }; + if !window_handle_values.contains(&hwnd.0) { + return TRUE; + } if let Some(inner) = try_get_window_inner(hwnd) { inner.invalidate_client_area(); } @@ -210,12 +225,12 @@ unsafe extern "system" fn invalidate_window_callback(hwnd: HWND, _: LPARAM) -> B } /// invalidates all windows belonging to a thread causing a paint message to be scheduled -fn invalidate_thread_windows(win32_thread_id: u32) { +fn invalidate_thread_windows(win32_thread_id: u32, window_handle_values: &WindowHandleValues) { unsafe { EnumThreadWindows( win32_thread_id, Some(invalidate_window_callback), - LPARAM::default(), + LPARAM(window_handle_values as *const _ as isize), ) }; } @@ -244,7 +259,12 @@ impl Platform for WindowsPlatform { // compositor clock ticked so we should draw a frame if wait_result == 1 { - unsafe { invalidate_thread_windows(GetCurrentThreadId()) }; + unsafe { + invalidate_thread_windows( + GetCurrentThreadId(), + &self.inner.window_handle_values.borrow(), + ) + }; while unsafe { PeekMessageW(&mut msg, HWND::default(), 0, 0, PM_REMOVE) }.as_bool() { diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index 505e785d2c750e271ab25d950148341f5ea11664..1caceef751b7a4959311509522e5c2bd8e6c4efd 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -302,8 +302,8 @@ impl WindowsWindowInner { if let Some(callback) = callbacks.close.take() { callback() } - let mut window_handles = self.platform_inner.window_handles.borrow_mut(); - window_handles.remove(&self.handle); + let mut window_handles = self.platform_inner.window_handle_values.borrow_mut(); + window_handles.remove(&self.hwnd.0); if window_handles.is_empty() { self.platform_inner .foreground_executor @@ -680,7 +680,10 @@ impl WindowsWindow { inner: context.inner.unwrap(), drag_drop_handler, }; - platform_inner.window_handles.borrow_mut().insert(handle); + platform_inner + .window_handle_values + .borrow_mut() + .insert(wnd.inner.hwnd.0); match options.bounds { WindowBounds::Fullscreen => wnd.toggle_full_screen(), WindowBounds::Maximized => wnd.maximize(),