Skip to content

rust: fix whole-runtime deadlock in escape_to_async on multi-thread runtimes - #950

Open
kamalesh0406 wants to merge 1 commit into
aws:mainlinefrom
kamalesh0406:fix-escape-to-async-deadlock
Open

rust: fix whole-runtime deadlock in escape_to_async on multi-thread runtimes#950
kamalesh0406 wants to merge 1 commit into
aws:mainlinefrom
kamalesh0406:fix-escape-to-async-deadlock

Conversation

@kamalesh0406

Copy link
Copy Markdown

Issue #899, if available:

Description of changes:

escape_to_async bridges sync Dafny code back to async on multi-thread tokio runtimes with block_in_place + Handle::block_on, which parks the calling worker on a future that the caller's own runtime must drive. When that worker is the last active one — every other worker parked and the shared IO/timer driver unowned — the bridged future can never make progress and the entire runtime deadlocks permanently: no timers, no IO, no task is ever polled again, unrecoverable without killing the process. tokio's documentation explicitly warns that a future passed to Handle::block_on from within a runtime must not depend on that runtime for progress.

Run the future on a scoped thread with a fresh current-thread runtime instead — the same pattern the CurrentThread arm already uses — so the bridged future never depends on the caller's runtime for progress on any flavor. The cost is one thread spawn + runtime build per escaped call, which only happens on key-material cache misses.

Squash/merge commit message, if applicable:

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

…untimes

escape_to_async bridges sync Dafny code back to async on multi-thread
tokio runtimes with block_in_place + Handle::block_on, which parks the
calling worker on a future that the caller's own runtime must drive.
When that worker is the last active one — every other worker parked and
the shared IO/timer driver unowned — the bridged future can never make
progress and the entire runtime deadlocks permanently: no timers, no
IO, no task is ever polled again, unrecoverable without killing the
process. tokio's documentation explicitly warns that a future passed
to Handle::block_on from within a runtime must not depend on that
runtime for progress.

Run the future on a scoped thread with a fresh current-thread runtime
instead — the same pattern the CurrentThread arm already uses — so the
bridged future never depends on the caller's runtime for progress on
any flavor. The cost is one thread spawn + runtime build per escaped
call, which only happens on key-material cache misses.

Fixes the deadlock reported in aws#899.
@kamalesh0406
kamalesh0406 requested a review from a team as a code owner August 13, 2026 03:56
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