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.

<img width="325" alt="image"
src="https://github.com/zed-industries/zed/assets/6465609/503aaa0a-7568-485a-a138-e689ae67001c">

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
This commit is contained in:
白山風露 2024-03-12 00:28:18 +09:00 committed by GitHub
parent ceadb39c38
commit a04932c4eb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 33 additions and 10 deletions

View File

@ -72,13 +72,15 @@ pub(crate) struct WindowsPlatformSystemSettings {
pub(crate) wheel_scroll_lines: u32,
}
type WindowHandleValues = HashSet<isize>;
pub(crate) struct WindowsPlatformInner {
background_executor: BackgroundExecutor,
pub(crate) foreground_executor: ForegroundExecutor,
main_receiver: flume::Receiver<Runnable>,
text_system: Arc<WindowsTextSystem>,
callbacks: Mutex<Callbacks>,
pub(crate) window_handles: RefCell<HashSet<AnyWindowHandle>>,
pub(crate) window_handle_values: RefCell<WindowHandleValues>,
pub(crate) event: HANDLE,
pub(crate) settings: RefCell<WindowsPlatformSystemSettings>,
}
@ -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()
{

View File

@ -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(),