Skip to content

Fix off-thread accessibility hit-test crash on macOS - #21779

Merged
MrJul merged 3 commits into
AvaloniaUI:mainfrom
VicChelaru:fix/macos-offthread-accessibility-hittest-crash
Jul 20, 2026
Merged

Fix off-thread accessibility hit-test crash on macOS#21779
MrJul merged 3 commits into
AvaloniaUI:mainfrom
VicChelaru:fix/macos-offthread-accessibility-hittest-crash

Conversation

@VicChelaru

@VicChelaru VicChelaru commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

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.

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>
@avaloniaui-bot

Copy link
Copy Markdown

You can test this PR using the following package version. 12.2.999-cibuild0067466-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

@cla-avalonia

cla-avalonia commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator
  • All contributors have signed the CLA.

@VicChelaru

Copy link
Copy Markdown
Contributor Author

@cla-avalonia agree

@Gillibald

Copy link
Copy Markdown
Contributor

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 dispatch_sync

@MrJul

MrJul commented Jul 15, 2026

Copy link
Copy Markdown
Member

I'm going to accept the fix because GetAutomationPeer can definitely return null even on the main thread, so we should not crash. But @Gillibald's comment above is correct: you should dispatch the call to the UI thread. Other bad things may happen otherwise :)

Comment thread native/Avalonia.Native/src/OSX/AvnWindow.mm Outdated
@MrJul MrJul added the backport-candidate-12.1.x Consider this PR for backporting to 12.1 branch label Jul 15, 2026
@VicChelaru

Copy link
Copy Markdown
Contributor Author

I'm going to accept the fix because GetAutomationPeer can definitely return null even on the main thread, so we should not crash. But @Gillibald's comment above is correct: you should dispatch the call to the UI thread. Other bad things may happen otherwise :)

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.

@avaloniaui-bot

Copy link
Copy Markdown

You can test this PR using the following package version. 12.2.999-cibuild0067486-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

@avaloniaui-bot

Copy link
Copy Markdown

You can test this PR using the following package version. 12.2.999-cibuild0067491-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

@MrJul

MrJul commented Jul 20, 2026

Copy link
Copy Markdown
Member

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.

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).

@MrJul MrJul left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@MrJul
MrJul added this pull request to the merge queue Jul 20, 2026
Merged via the queue into AvaloniaUI:main with commit f8dd424 Jul 20, 2026
10 checks passed
MrJul pushed a commit that referenced this pull request Jul 29, 2026
* 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>
@MrJul MrJul added backported-12.1.x and removed backport-candidate-12.1.x Consider this PR for backporting to 12.1 branch labels Jul 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

macOS: off-thread accessibility hit-test into own window crashes (SIGSEGV in -[AvnWindow automationPeer])

5 participants