You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[P3] Kotlin Mutex reentrancy is missed after a waited lock, tryLock or select acquisition #1220
Split out of #1007 by the Kotlin Mutex reentrancy detector PR (feat/kotlin-mutex-reentrancy).
What is missing.KotlinMutexReentrancyDetector knows who holds a kotlinx Mutex only when a woven lock took it without suspending: the hook reads the caller's Job from the continuation before the call and records it once the call returns without COROUTINE_SUSPENDED. Three acquisitions leave the holder unknown (recordHolderUnknown):
a lock that suspended and was resumed later, because the resumption happens inside kotlinx, outside any woven call site;
tryLock, which takes no continuation, so there is no Job to read;
select { mutex.onLock { } }.
A coroutine that then re-enters the mutex it holds hangs exactly as in the detected case, and nothing is reported. Under the contention @AsyncTest creates, many acquisitions wait, so in a given round the uncontended first acquisition is what the finding depends on.
Why not now. Naming the holder of a resumed lock needs a hook at the point kotlinx hands the mutex over (the resumed continuation, or the owner field MutexImpl keeps when an owner token is passed), which is a different weaving shape from the call-site replacement the PR adds. tryLock needs the caller's coroutine from somewhere other than a continuation argument.
What it would take. Weave or wrap the resumption path (or read MutexImpl's owner state at the next woven call), plus a row in the Kotlin fixture where the reentrant lock follows a contended first lock, and one where the first acquisition is tryLock, both of which must report.
Documented as a limit in docs/JVM_LANGUAGES.md and the detector's javadoc.
P3: a missed detection on a narrower path; the uncontended first acquisition in a round still reports, so the reentrancy is caught in most runs. Below #1221 since a miss is cheaper than a false report.
The waited-lock part shipped in #1223. The tryLock part is in the PR from branch fix/1220-mutex-trylock: the weaver passes the enclosing suspend function's or lambda's continuation to the tryLock hook, which records the caller's Job as holder. Still open here: select { onLock }, and a tryLock outside any suspend function (no coroutine to name). Priority stays P3.
Activity
PIsberg commentedon Nov 8, 2026
P3: a missed detection on a narrower path; the uncontended first acquisition in a round still reports, so the reentrancy is caught in most runs. Below #1221 since a miss is cheaper than a false report.
PIsberg commentedon Nov 8, 2026
The waited-lock part shipped in #1223. The tryLock part is in the PR from branch fix/1220-mutex-trylock: the weaver passes the enclosing suspend function's or lambda's continuation to the tryLock hook, which records the caller's Job as holder. Still open here: select { onLock }, and a tryLock outside any suspend function (no coroutine to name). Priority stays P3.
Merge pull request #1226 from PIsberg/fix/1220-mutex-trylock