Skip to content

XPC: reply to unknown routes and make the request timeout actually cancel the waiter#1862

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

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

Conversation

@radheradhe01

Copy link
Copy Markdown
Contributor

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.

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