Skip to content

fix: reply to unknown XPC routes and make request timeout cancellable#1862

Open
radheradhe01 wants to merge 1 commit into
apple:mainfrom
radheradhe01:fix/xpc-unknown-route-and-timeout
Open

fix: reply to unknown XPC routes and make request timeout cancellable#1862
radheradhe01 wants to merge 1 commit into
apple:mainfrom
radheradhe01:fix/xpc-unknown-route-and-timeout

Conversation

@radheradhe01

@radheradhe01 radheradhe01 commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

Motivation and Context

Two related issues in the XPC request path:

  1. Unknown route hangs the client. XPCServer dispatches with if let handler = routes[route] { ... } and no else. An unknown route produces no reply at all, so the client blocks until its timeout (or forever, if it sent none).
  2. The client timeout is illusory. XPCClient.send races a timeout task against the reply task in a withThrowingTaskGroup. The reply task uses withCheckedThrowingContinuation, which is not cancellation-aware. When the timeout fires, the group tears down and awaits the reply task — which only completes when the daemon actually replies. Against a live-but-hung daemon the "timeout" never returns.

This change:

  • XPCServer: adds the else branch and replies with an invalidArgument error for unknown routes.
  • XPCClient: wraps the reply task in withTaskCancellationHandler and bridges the continuation through a small resume-once box (XPCReplyBox). On cancellation the continuation is resumed promptly; a late XPC reply becomes a no-op. The box guarantees the continuation is resumed exactly once. The connection is left intact on timeout; only the pending request is abandoned.

Testing

  • Tested locally
  • Added/updated tests
  • Added/updated docs

Verified by static / code-level review; not built locally (no macOS 26 toolchain available here) — CI build will validate.

…ncel the waiter

### Problem
Two related issues in the XPC request path:

1. **Unknown route hangs the client.** `XPCServer` dispatches with `if let handler = routes[route] { ... }` and **no `else`**. An unknown route produces no reply at all, so the client blocks until its timeout (or forever, if it sent none).

2. **The client timeout is illusory.** `XPCClient.send` races a timeout task against the reply task in a `withThrowingTaskGroup`. The reply task uses `withCheckedThrowingContinuation`, which is **not** cancellation-aware. When the timeout fires, the group tears down and awaits the reply task — which only completes when the daemon actually replies. Against a live-but-hung daemon the "timeout" never returns.

### Fix
- `XPCServer`: add the `else` branch and reply with an `invalidArgument` error for unknown routes.
- `XPCClient`: wrap the reply task in `withTaskCancellationHandler` and bridge the continuation through a small resume-once box (`XPCReplyBox`). On cancellation the continuation is resumed promptly; a late XPC reply becomes a no-op. The box guarantees the continuation is resumed exactly once.

### Notes
The connection is left intact on timeout; only the pending request is abandoned.
@radheradhe01 radheradhe01 changed the title XPC: reply to unknown routes and make the request timeout actually cancel the waiter fix: reply to unknown XPC routes and make request timeout cancellable Jun 30, 2026
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