Live data from Hacker News

Rust's Sneaky Deadlock With `if let` Blocks

brooksblog.bearblog.dev

11–20 of 85 posts

Re: Rust's Sneaky Deadlock With `if let` Blocks

#11
post #2

This is why pthread_mutex_lock() and pthread_mutex_unlock() will always be kings - it is clear when things are locked and when they are unlocked. Nobody needs to write articles warning you about pthread_mutex being taken randomly by syntactic sugar and not released till a magic later time due to the same sugar. Ditto for RWlock/XYZloc/ABClock/etc...

There are however many PRs about people ignoring the return values of pthread_mutex_lock(), or missing an unlock on one route through a function.

and nothing prevents you from explicitly dropping lock guards in rust either

actually it's a common pattern in complicated multi threaded code or similar to require that

Re: Rust's Sneaky Deadlock With `if let` Blocks

#12
post #5

Happy to be corrected, but from what I gathered RWLock should mostly be avoided in favour of a simple Mutex unless you have a very read-heavy usecase and even then the performances are subpar compared to mutex.

I agree with you, but the problem the article is talking about is unexpected lifetime with `if let` which is not just limited to RwLock.

Re: Rust's Sneaky Deadlock With `if let` Blocks

#15
post #9

Earlier quoted context omitted.

I see it as a consequence of Rust being too liberal with additions to the language. It's hard to maintain some of these guarantees in the presence of certain syntactic forms. This happens in all languages. It is a little hilarious to see a rustaceon write: > and you can sus out if a program is going to cause a deadlock by just making sure you aren't acquiring multiple simultaneous locks. Ah.. not a problem! You just…

The issue here isn't new features at all. `if let` is more or less syntax sugar for `match`. And match behaves like that, too and has been in rust since 1.0. That match did behaves like that is due to some old, you could say legacy, reasons and had been criticized even in the early rust 1.x days. But changing a behavior which subtle change when locks are released is not something you can easily fix with a rust editio…

Funny you say that: https://github.com/rust-lang/rust/issues/131154

Looks like this is getting fixed in Rust 2024 :)

Re: Rust's Sneaky Deadlock With `if let` Blocks

#16
post #2

This is why pthread_mutex_lock() and pthread_mutex_unlock() will always be kings - it is clear when things are locked and when they are unlocked. Nobody needs to write articles warning you about pthread_mutex being taken randomly by syntactic sugar and not released till a magic later time due to the same sugar. Ditto for RWlock/XYZloc/ABClock/etc...

I think mutexes that own their data are genuinely much easier to reason about than mutexes that don't.

In this case this is a Rust bug that will be fixed in the next edition: https://github.com/rust-lang/rust/issues/124085

Re: Rust's Sneaky Deadlock With `if let` Blocks

#17

Earlier quoted context omitted.

There are however many PRs about people ignoring the return values of pthread_mutex_lock(), or missing an unlock on one route through a function.

and nothing prevents you from explicitly dropping lock guards in rust either actually it's a common pattern in complicated multi threaded code or similar to require that

Dropping a lock guard in rust requires you to have already dropped the borrow — the shared memory under lock is only accessible through the guard, and you can’t drop an object if you have a reference to it. This is not true in C, where you can reference the shared memory after the lock is released.

Re: Rust's Sneaky Deadlock With `if let` Blocks

#18
Clippy already has an error for this pattern with Mutex. It should be trivial to extend it to cover RwLock.

    error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock
      --> src/main.rs:5:5
       |
    5  |       if let Some(num) = *map.lock().unwrap() {
       |       ^                   --- this Mutex will remain locked for the entire `if let`-block...
       |  _____|
       | |
    6  | |         eprintln!("There's a number in there: {num}");
    7  | |     } else {
    8  | |         let mut lock2 = map.lock().unwrap();
       | |                         --- ... and is tried to lock again here, which will always deadlock.
    9  | |         *lock2 = Some(5);
    10 | |         eprintln!("There will now be a number {lock2:?}");
    11 | |     }
       | |_____^
       |
       = help: move the lock call outside of the `if let ...` expression
       = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#if_let_mutex
       = note: `#[deny(clippy::if_let_mutex)]` on by default

Re: Rust's Sneaky Deadlock With `if let` Blocks

#19
post #14

This is going to be fixed in Rust 2024: https://github.com/rust-lang/rust/issues/124085

Did they just miss this in the spec?

From my understanding: The original implementation is consistent with the behavior of `match`. However it was realized that it is both less intuitive than early dropping (as this post suggests) and also gets in the way of understandable semantics for if let chains, so the decision was made to change it in the next edition.

match still retains the old behavior.

Re: Rust's Sneaky Deadlock With `if let` Blocks

#20
post #9

Earlier quoted context omitted.

I see it as a consequence of Rust being too liberal with additions to the language. It's hard to maintain some of these guarantees in the presence of certain syntactic forms. This happens in all languages. It is a little hilarious to see a rustaceon write: > and you can sus out if a program is going to cause a deadlock by just making sure you aren't acquiring multiple simultaneous locks. Ah.. not a problem! You just…

The issue here isn't new features at all. `if let` is more or less syntax sugar for `match`. And match behaves like that, too and has been in rust since 1.0. That match did behaves like that is due to some old, you could say legacy, reasons and had been criticized even in the early rust 1.x days. But changing a behavior which subtle change when locks are released is not something you can easily fix with a rust editio…

> `if let` is more or less syntax sugar for `match`.

Which are new features for systems languages that otherwise rely on RAII for locking. So it's in the class of "original sin."

> so we are pretty much stuck with it.

You could refuse to compile it under some set of flags. Isn't that the basic value premise of the language here?

Post reply on HN