Skip to content

feat(core): ask_timeout — bounded-wait request-reply (closes the ask liveness hole) - #6

Merged
mash180sx merged 1 commit into
mainfrom
feat/ask-timeout
Jul 19, 2026
Merged

feat(core): ask_timeout — bounded-wait request-reply (closes the ask liveness hole)#6
mash180sx merged 1 commit into
mainfrom
feat/ask-timeout

Conversation

@mash180sx

Copy link
Copy Markdown
Contributor

ask blocks forever if an actor stores the Responder instead of replying — a real liveness hole a reviewer would poke at. ask_timeout(dur, ..) bounds the wait and returns Err(AskError::Timeout).

Design

  • The fast ask stays zero-alloc (reply cell on the caller's stack). Only ask_timeout holds the cell in an Arc, so a late reply after the timeout writes to live memory instead of a freed stack frame.
  • A CONSUMED state + ReplyCell::Drop guard ensure the orphaned value (late reply, caller already gone) is dropped exactly once — no use-after-free, no double-drop, no leak.

Verification

  • Miri: all 6 ask tests pass under Miri, including ask_timeout_late_reply_is_dropped_without_uaf (drives the exact UAF/double-drop path). Required a #[cfg(miri)] no-op in pinning::pin_current_thread_to (Miri can't emulate affinity/QoS syscalls; placement is a benchmark concern, irrelevant to correctness).
  • build (default + net), tests (incl. 3 new timeout tests), doctests, Loom, clippy — all green.

Docs (English + Japanese, parallel)

  • ask.rs written in English; ask_timeout re-added to guide.md / guide.ja.md and both READMEs; the "ask liveness" known-limitation now points to ask_timeout as the bounded-wait escape hatch.

Note: this reconciles work that had been stranded on an unmerged pre-English branch onto current English main.

🤖 Generated with Claude Code

…liveness hole)

ask blocks forever if an actor stores the Responder instead of replying. ask_timeout bounds the
wait and returns Err(AskError::Timeout). The fast ask stays zero-alloc (stack cell); only the
timeout path holds the cell in an Arc so a late reply after the timeout writes to live memory, not
freed. A CONSUMED state + ReplyCell::Drop guard drop the orphaned value exactly once (no UAF, no
double-drop, no leak).

- Miri-verified: the late-reply/UAF/double-drop test and all ask tests pass under Miri (needed a
  #[cfg(miri)] no-op in pinning::pin_current_thread_to, since Miri can't emulate affinity/QoS
  syscalls — placement is a bench concern, irrelevant to correctness).
- Reconciled onto current English main (this work had been stranded on an unmerged pre-English
  branch): ask.rs written in English, guides/README re-add ask_timeout (EN + JA), README known-
  limitations updated to reflect the bounded-wait escape hatch.

Verified: build (default+net), tests (incl. 3 new timeout tests), doctests, Loom, Miri, clippy.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mash180sx
mash180sx merged commit 4442a62 into main Jul 19, 2026
3 checks passed
@mash180sx
mash180sx deleted the feat/ask-timeout branch July 19, 2026 00:39
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