bugfix(win32): Only return win handle on OK thread

On Windows, it is generally unsafe to use the HWND outside of the thread
that it originates from. In reality, the HWND is an index into a
thread-local table, so using it outside of the GUI thread can result in
another window being used instead, following by code unsoundness. This
is why the WindowHandle type is !Send. However, Window is Send and Sync,
which means we have to account for this.

Thus far the best solution seems to be to check if we are not in the GUI
thread. If we aren't, refuse the return the window handle.

For users who want to ensure the safety themselves, the unsafe API
was added.

Signed-off-by: John Nunley <dev@notgull.net>
This commit is contained in:
John Nunley 2024-04-26 09:28:10 -07:00 committed by GitHub
parent bdd80c8af2
commit 1682703b5c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 169 additions and 1 deletions

View file

@ -365,7 +365,9 @@ impl Window {
#[cfg(feature = "rwh_06")]
#[inline]
pub fn raw_window_handle_rwh_06(&self) -> Result<rwh_06::RawWindowHandle, rwh_06::HandleError> {
pub unsafe fn rwh_06_no_thread_check(
&self,
) -> Result<rwh_06::RawWindowHandle, rwh_06::HandleError> {
let mut window_handle = rwh_06::Win32WindowHandle::new(unsafe {
// SAFETY: Handle will never be zero.
std::num::NonZeroIsize::new_unchecked(self.window)
@ -375,6 +377,20 @@ impl Window {
Ok(rwh_06::RawWindowHandle::Win32(window_handle))
}
#[cfg(feature = "rwh_06")]
#[inline]
pub fn raw_window_handle_rwh_06(&self) -> Result<rwh_06::RawWindowHandle, rwh_06::HandleError> {
// TODO: Write a test once integration framework is ready to ensure that it holds.
// If we aren't in the GUI thread, we can't return the window.
if !self.thread_executor.in_event_loop_thread() {
tracing::error!("tried to access window handle outside of the main thread");
return Err(rwh_06::HandleError::Unavailable);
}
// SAFETY: We are on the correct thread.
unsafe { self.rwh_06_no_thread_check() }
}
#[cfg(feature = "rwh_06")]
#[inline]
pub fn raw_display_handle_rwh_06(