Skip to content

fix(runtime-wry)!: query monitors on main thread from runtime handle - #15630

Merged
Legend-Master merged 7 commits into
tauri-apps:devfrom
tenderdeve:fix/15170-monitor-queries-off-thread
Aug 12, 2026
Merged

fix(runtime-wry)!: query monitors on main thread from runtime handle#15630
Legend-Master merged 7 commits into
tauri-apps:devfrom
tenderdeve:fix/15170-monitor-queries-off-thread

Conversation

@tenderdeve

Copy link
Copy Markdown
Contributor

Closes #15170

WryHandle (the app/AppHandle-level runtime handle) implemented primary_monitor, monitor_from_point and available_monitors by reading self.context.main_thread.window_target directly on the calling thread. The tao EventLoopWindowTarget is not thread safe (GTK on Linux, Win32 on Windows), so calling these from a background thread races with the UI thread — the reporter sees Aborted (core dumped), Segmentation fault, and malloc(): unaligned fastbin chunk within seconds.

cursor_position on the same handle already avoids this by marshalling through the event loop. This routes the three monitor queries the same way, via new EventLoopWindowTargetMessage variants handled on the main thread. send_user_message runs inline when already on the main thread, so no deadlock and no behavior change for main-thread callers.

The main-thread Runtime impl keeps its direct access — it already runs on the UI thread.

No repro on my machine (crash is Linux/Windows only), but the fix removes the off-thread window_target access that is the documented cause, mirroring the existing cursor_position path.

@tenderdeve
tenderdeve requested a review from a team as a code owner July 1, 2026 10:47
Comment thread crates/tauri-runtime-wry/src/lib.rs Outdated
@tenderdeve

Copy link
Copy Markdown
Contributor Author

@FabianLars done in fc2078b — switched all three (primary_monitor, monitor_from_point, available_monitors) to event_loop_window_getter! like cursor_position.

One wrinkle: the macro expands to send_user_message(..)?, so it needs a Result/Option-returning scope. cursor_position returns Result, but these three RuntimeHandle methods return a bare Option<Monitor> / Vec<Monitor> (the Dispatcher versions return Result<..>, which is why they use it directly). So I wrapped each call in a small (|| ..)() closure to absorb the ?, then .ok().flatten(). monitor_from_point also passes a |tx| .. closure for the extra point arg.

Reads cleaner for primary_monitor/available_monitors; monitor_from_point ends up slightly nested. If you'd rather keep that one explicit (or want the trait methods changed to return Result — bigger change), say the word.

@FabianLars

Copy link
Copy Markdown
Member

Ah shit i didn't see the ? in the macro. I think the previous version was better than the closure wrapper then - sorry for the back and forth. Please revert the last commit then, and while you're at it i think it'd be better to return None if send_user_message returns an error, otherwise there's a chance we're getting stuck on the recv() call.

@tenderdeve

Copy link
Copy Markdown
Contributor Author

@FabianLars done in a989173 (revert in 57bd57c) — no worries on the back-and-forth. Back to the explicit send_user_message + recv() version, and now each of the three bails out early (None / empty Vec) if the send fails, so a dropped message can no longer leave the caller blocked on recv(). cargo check -p tauri-runtime-wry is green.

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Package Changes Through cd7a619

There are 14 changes which include tauri with minor, tauri-cli with minor, @tauri-apps/cli with minor, tauri-runtime with minor, tauri-runtime-wry with minor, tauri-utils with minor, tauri-bundler with minor, tauri-build with minor, tauri-macos-sign with minor, tauri-codegen with minor, tauri-macros with minor, tauri-plugin with minor, tauri-driver with minor, @tauri-apps/api with minor

Planned Package Versions

The following package releases are the planned based on the context of changes in this pull request.

package current next
@tauri-apps/api 2.11.1 2.12.0
tauri-utils 2.9.3 2.10.0
tauri-macos-sign 2.3.4 2.4.0
tauri-bundler 2.9.4 2.10.0
tauri-runtime 2.11.3 2.12.0
tauri-runtime-wry 2.11.4 2.12.0
tauri-codegen 2.6.3 2.7.0
tauri-macros 2.6.3 2.7.0
tauri-plugin 2.6.3 2.7.0
tauri-build 2.6.3 2.7.0
tauri 2.11.5 2.12.0
@tauri-apps/cli 2.11.4 2.12.0
tauri-cli 2.11.4 2.12.0
tauri-driver 2.0.6 2.1.0

Add another change file through the GitHub UI by following this link.


Read about change files or the docs at github.com/jbolda/covector

@Legend-Master

Copy link
Copy Markdown
Contributor

Please sign your commits.

@tenderdeve
tenderdeve force-pushed the fix/15170-monitor-queries-off-thread branch from a989173 to 09bf1e6 Compare July 24, 2026 05:11
@tenderdeve

Copy link
Copy Markdown
Contributor Author

@Legend-Master done — re-signed all four commits with SSH and force-pushed, they're showing Verified now. Also rebased onto latest dev while I was at it.

WryHandle::primary_monitor, monitor_from_point and available_monitors
read the event loop's window target directly on the calling thread. That
window target is not thread safe, so calling these functions from a
background thread races with the UI thread and can segfault or corrupt
the heap.

Route the three queries through the event loop like cursor_position
already does, so the window target is only accessed on the main thread.

Closes tauri-apps#15170
Reuse the existing event_loop_window_getter! macro (as cursor_position does)
instead of hand-rolling the channel + send_user_message boilerplate in
primary_monitor, monitor_from_point and available_monitors. These methods
return bare Option/Vec, so a small closure absorbs the macro's internal `?`.
If send_user_message errors the event loop will never reply, so recv()
would block the calling thread forever. Return None / an empty Vec on a
send error instead of waiting.
@tenderdeve
tenderdeve force-pushed the fix/15170-monitor-queries-off-thread branch from 09bf1e6 to 50bd1a8 Compare July 24, 2026 05:12
@FabianLars FabianLars added this to the 2.12 milestone Aug 6, 2026
@Legend-Master
Legend-Master force-pushed the fix/15170-monitor-queries-off-thread branch from 833169a to 6f03948 Compare August 10, 2026 05:32
@Legend-Master Legend-Master changed the title fix(runtime-wry): query monitors on main thread from runtime handle fix(runtime-wry)!: query monitors on main thread from runtime handle Aug 10, 2026
@Legend-Master

Legend-Master commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

@FabianLars Since the runtime and runtime-wry crates are not stable, I have gone ahead made them return results. I think this should be fine since the only consumer of the runtime crates is tauri and the implementers of the runtime crate need updates in respond to the added functions we do in minor functions anyways. Let me know your takes on this.

@FabianLars

Copy link
Copy Markdown
Member

Let me know your takes on this.

this can always cause issues if packages are updated independently but since i've been pushing breaking changes for tauri-utils i can't complain about that here 😂 so lgtm

@Legend-Master

Copy link
Copy Markdown
Contributor

I'm thinking to depend on minor versions after we get #15412 in for tauri

@Legend-Master
Legend-Master merged commit d727d63 into tauri-apps:dev Aug 12, 2026
23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[bug] Multiple app handle functions can crash Tauri, including available_monitors and cursor_position

3 participants