Skip to content

TD-5225: reading a window's accessibility tree no longer crashes TST Desk - #111

Merged
captcrock merged 1 commit into
mainfrom
td/5225-ax-read-crash
Nov 3, 2026
Merged

captcrock merged 1 commit into
mainfrom
td/5225-ax-read-crash

Conversation

@captcrock

Copy link
Copy Markdown
Contributor

TD-5225 — Reading a window's accessibility tree crashes TST Desk

Done: ui_snapshot through the host no longer aborts the app. Attribute reads check the CF type before reading (strings as-is, numbers and booleans written out, anything else empty), and elements taken out of a CFArray hold their own reference until the walk is done. Before this, the first checkbox, slider or scroll area in any target window killed the host and the daemon, so every computer-use client lost its tools until the app was reopened.

Acceptance criteria:

  • Attribute reads check the CF type: strings as-is, numbers and booleans written out, anything else empty; boolean reads accept CFBoolean or a number
  • Elements taken from a CFArray hold their own reference until the walk is done; ui_action keeps the element it found alive while acting on it
  • Unit tests on real CF objects, each shown to fail with its fix removed (no type check: the test process aborts with "Rust cannot catch foreign exceptions", the same error that crashed the app; no retain: it segfaults)
  • Live on macOS: ui_snapshot of Finder, of TST Desk itself and of an Electron app returns a tree with path: host, and the app keeps running. Before the fix the same calls killed the app within a second, every time.

Decisions: none (Class A: CF helpers split into cu_cf.rs to keep cu_ax.rs under the size limit).

Files: shell/src/cu_cf.rs (new), shell/src/cu_ax.rs, shell/src/lib.rs, docs/tst-desk-backlog.md

Tests: 6 new unit tests in cu_cf.rs (macOS only, like cu_ax.rs, so Linux CI compiles them out). Run on macOS: cargo test lib 135 passed; daemon_supervision failed once on the first cold run and passed 3/3 on reruns and on main; cargo clippy --all-targets -- -D warnings clean.

Also checked live on the same build: the TD-5223 stop-file path works for an outside client through cu-agent.sock. With the file present, move returns err stopped, an acting json op returns {"ok":false,"stopped":true}, and capture still works. The daemon logs the outside engage and clear. The TD-5224 shortcut registers at launch.

Next: none.

🤖 Generated with Claude Code

https://claude.ai/code/session_01HUthoCrBcxKu4GVj429dwD

…Desk

ui_snapshot through the host's cu-agent.sock aborted the app on macOS for
any target app. The host read every AXValue, AXTitle and similar attribute
as a CFString, but AXValue is a number on a checkbox or slider and an
AXValueRef on a scroll area. CoreFoundation throws on a non-string and Rust
aborts on a foreign exception, so the host died, the daemon followed it,
and every computer-use client lost its tools until the app was reopened.
Children taken out of a CFArray were also used after the array was
released.

The CF reads move to cu_cf.rs. text() and flag() check the CF type first:
strings as-is, numbers and booleans written out, anything else empty.
items() retains each array element, and an Owned wrapper releases every
reference on drop, so cu_ax.rs no longer pairs CFRelease calls by hand.
ui_action keeps the element it found alive while acting on it.

The extern signatures for CFStringCreateWithCString and CFNumberGetValue
match the existing ones in cu_agent.rs and cu_identity.rs, because clippy
rejects clashing declarations.

Tests use real CF objects. With the type check removed the test process
aborts with the same foreign-exception error; with the retain removed it
segfaults.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HUthoCrBcxKu4GVj429dwD
@captcrock
captcrock merged commit 3e0a338 into main Nov 3, 2026
4 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.

1 participant