Live data from Hacker News

Rust's Sneaky Deadlock With `if let` Blocks

brooksblog.bearblog.dev

31–40 of 85 posts

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

#31

Is there any explicit reason as to why RWLock can’t simply try to upgrade the read-lock to write-lock given they’re both being held by the same thread?

Would be much more expensive to implement. RwLocks are basically Atomics wrapping a pointer and have no knowledge of who has acquired the lock

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

#33
A lock taken in the conditional test term should lock for the duration of the if-clause. If you release the lock early, you add the risk of a race condition, where some other thread executes between the test and the execution of the if or else clause, changing the state.

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

#34

Is there any explicit reason as to why RWLock can’t simply try to upgrade the read-lock to write-lock given they’re both being held by the same thread?

Yes, allowing this to execute would be very unsound: let lock = RwLock::new(Box::new(111)); let r: &i32 = &**lock.read().unwrap(); // points to 111 *lock.write().unwrap() = Box::new(222); // allocates a new Box and deallocates 111 println!("{}", *r); // use after free

It can be done safely with an upgrade method that requires an owned read guard. The RwLock implementation provided by the parking_lot crate supports this safely:

    let lock = RwLock::new(Box::new(111));
    let read = lock.upgradable_read();
    let r: &i32 = &**read; // points to 111
    *RwLockUpgradableReadGuard::upgrade(read) = Box::new(222); // error[E0505]: cannot move out of `read` because it is borrowed
    println!("{}", *r);

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

#35

Earlier quoted context omitted.

Yes, allowing this to execute would be very unsound: let lock = RwLock::new(Box::new(111)); let r: &i32 = &**lock.read().unwrap(); // points to 111 *lock.write().unwrap() = Box::new(222); // allocates a new Box and deallocates 111 println!("{}", *r); // use after free

It can be done safely with an upgrade method that requires an owned read guard. The RwLock implementation provided by the parking_lot crate supports this safely: let lock = RwLock::new(Box::new(111)); let read = lock.upgradable_read(); let r: &i32 = &**read; // points to 111 *RwLockUpgradableReadGuard::upgrade(read) = Box::new(222); // error[E0505]: cannot move out of `read` because it is borrowed println!("{}", *r);

Of course (but that’s not relevant to the original scenario, where the programmer is hypothetically not aware that the read lock is still being held, let alone that they could manually upgrade it after changing to a different lock library).

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

#36
post #33

A lock taken in the conditional test term should lock for the duration of the if-clause. If you release the lock early, you add the risk of a race condition, where some other thread executes between the test and the execution of the if or else clause, changing the state.

But in Rust, the lock protects the contents inside it and lends the contents only for the lifetime the lock is being held, so if one tries to modify the contents when the lock is already released, you are going to get a compiler error, not a race condition.

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

#37
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.

The weirdest part about rwlock (not rust-specific) is when you end up using it in a case where the writes are the shared case and the reads are the exclusive case.

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

#39

Earlier quoted context omitted.

This really reads like satire but feels like the author is actually being sincere. I’ve seen so many deadlocks happening due to pthread mutexes. Certainly way more than this syntactic corner case. It’s so common in fact that I saw a codebase that made their mutexes recursive to avoid having to think about it.

[flagged]

this is pretty obvious bait

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

#40
post #14

Earlier quoted context omitted.

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.

Why does the behavior make sense in match?
Post reply on HN