-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Fix potential deadlock in CacheState::lock
#15698
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
Is there any chance this fix could make it into Thursday's release? (Sorry if this is a crazy or unreasonable ask.) |
Despite the forge saying 1.89 beta will be branched on the 20th, it doesn't look like its been created yet, so this should at least make that without a beta backport. We have 3 days before 1.88 is released. We just did a submodule update for rust-lang/rust (rust-lang/rust#142898). So to do this we'd need to feel comfortable enough with this PR with little testing, get a beta backport merged, and update the submodule. I'm not even sure what the exact cut off for a change like this is. This problem was introduced in #12706 which was released in 1.75. I feel like we can live for 6 more weeks with this but I'll bring it up with the team. |
Thanks very much for the explanation. |
Looks like we did miss the 1.89 window so I backported this in #15699. |
Thanks for keeping me informed, and thanks for going to all of this trouble. 🙏 |
Update cargo 2 commits in 84709f085062cbf3c51fa507527c1b2334015178..409fed7dc1553d49cb9a8c0637d12d65571346ce 2025-06-22 23:58:39 +0000 to 2025-06-23 15:55:04 +0000 - Fix potential deadlock in `CacheState::lock` (rust-lang/cargo#15698) - feat(toml): Parse support for multiple build scripts (rust-lang/cargo#15630)
Update cargo 2 commits in 84709f085062cbf3c51fa507527c1b2334015178..409fed7dc1553d49cb9a8c0637d12d65571346ce 2025-06-22 23:58:39 +0000 to 2025-06-23 15:55:04 +0000 - Fix potential deadlock in `CacheState::lock` (rust-lang/cargo#15698) - feat(toml): Parse support for multiple build scripts (rust-lang/cargo#15630)
Rollup merge of #142993 - ehuss:update-cargo, r=ehuss Update cargo 2 commits in 84709f085062cbf3c51fa507527c1b2334015178..409fed7dc1553d49cb9a8c0637d12d65571346ce 2025-06-22 23:58:39 +0000 to 2025-06-23 15:55:04 +0000 - Fix potential deadlock in `CacheState::lock` (rust-lang/cargo#15698) - feat(toml): Parse support for multiple build scripts (rust-lang/cargo#15630)
This PR fixes a potential source of deadlock in the
CacheState::lock
function (here), as explained below.I ran into this deadlock while testing Dylint. For example, in this GitHub run, two jobs were killed after running for six hours. This fix seems to resolve the deadlock (e.g., see this run, which uses the fix).
Until this fix (or a similar one) appears in
rustup
-installable Cargo, is there an easy workaround?A
CacheState
struct holds two recursive locks:mutate_lock
andcache_lock
.When
MutateExclusive
is passed toCacheState::lock
, it tries to acquire both locks. First, it tries to acquiremutate_lock
, then it tries to acquirecache_lock
.The problematic case is when it acquires the first, but not the second.
Note that if the second cannot be acquired because of an error, the
mutate_lock
recursive lock is decremented:cargo/src/cargo/util/cache_lock.rs
Lines 412 to 415 in 84709f0
However, if the second would simply block,
LockingResult::WouldBlock
is returned.CacheState::lock
is called from two places. One of those locations is inCacheLocker::try_lock
:1cargo/src/cargo/util/cache_lock.rs
Lines 502 to 506 in 84709f0
Note that
CacheLocker::try_lock
creates aCacheLock
if and only ifLockingResult::LockAcquired
is returned.Furthermore, when a
CacheLock
is dropped, it decrements bothmutate_lock
andcache_lock
:cargo/src/cargo/util/cache_lock.rs
Lines 443 to 446 in 84709f0
A scan of
cache_lock.rs
shows that there are only three places2 wheremutate_lock.decrement()
is called: the error location inCacheState::lock
(referenced above), and two places inCacheLock::drop
.Thus, if
LockingResult::WouldBlock
is returned fromCacheState::lock
,mutate_lock
is never decremented.Footnotes
The other location is in
CacheLocker::lock
, which callsCacheState::lock
withBlockingMode::Blocking
. For that reason,CacheLocker::lock
should not returnWouldBlock
when called from this location. ↩https://github.com/rust-lang/cargo/blob/84709f085062cbf3c51fa507527c1b2334015178/src/cargo/util/cache_lock.rs#L413, https://github.com/rust-lang/cargo/blob/84709f085062cbf3c51fa507527c1b2334015178/src/cargo/util/cache_lock.rs#L438, and https://github.com/rust-lang/cargo/blob/84709f085062cbf3c51fa507527c1b2334015178/src/cargo/util/cache_lock.rs#L445 ↩