Fix off-thread accessibility hit-test crash on macOS - #21779
Conversation
GetAutomationPeer() returns null when called off the UI thread, but -[AvnWindow automationPeer] called SetNode on it without checking, which segfaults. Guard against the null peer so it returns nil instead. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
You can test this PR using the following package version. |
|
|
@cla-avalonia agree |
|
This might prevent the crash, but in the end, it is not allowed to call these APIs from a background thread. You need to dispatch calls to the AX APIs via |
|
I'm going to accept the fix because |
I'd love to get some details on this. The context is this: If you make AX calls on the non-UI thread, MacOS marshals these to the UI thread before calling it on whatever app you are over. This means that an Avalonia app will always get these calls from the OS if the calling app is not the app itself. If the calling app is itself, then the OS seems to short-circuit this by not marshaling to the OS thread and this results in an exception. Worse yet, it's an exception caused by the app itself which the app cannot handle. In my case, I don't actually care about getting information about the app itself - I care only about other apps, so if I get back null, that's perfectly okay. I want to do this on a different thread so I can await it and not lock the thread for (a default of) 1.5 seconds from AX calls. So, if there's a way to do AX calls on the main thread while not locking my app during the timeout I (and maybe future readers) want to know. The only possible way I can see is to await Task.Run(...). Either way, I apprecaite the attention on this issue and the willingness to merge despite the warning. |
|
You can test this PR using the following package version. |
|
You can test this PR using the following package version. |
Unfortunately, I don't think that's possible. Everything UI-related on macOS is single-threaded and must happen on the main thread. I haven't checked, but I wouldn't be surprised if your AX call from another thread actually resulted in a debug assertion failure in Avalonia's native lib (if it was compiled in debug mode). |
* Fix off-thread accessibility hit-test crash on macOS GetAutomationPeer() returns null when called off the UI thread, but -[AvnWindow automationPeer] called SetNode on it without checking, which segfaults. Guard against the null peer so it returns nil instead. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Removed comment --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fixes #21777
On macOS if the system does an accessibility hit test off the UI thread it crashes with a SIGSEGV in -[AvnWindow automationPeer]. You can hit it by calling AXUIElementCopyElementAtPosition from a background thread over one of the app's own windows.
Reason is GetAutomationPeer() returns null when it gets called off the UI thread, since building the peer walks the visual tree which is thread affine. automationPeer didn't check for that and went straight to SetNode on the null pointer, so it blows up.
Fix is just a null check before SetNode so it returns nil instead. All the callers of automationPeer already handle nil so nothing else had to change. Also flipped the return annotation from _Nonnull to _Nullable since it can obviously be null.
No test on this one, it's all in the native objc code and there's no test project for that side, and I couldn't find a way to repro it from the managed automation tests.