fix(PartialEq): resolve TOCTOU race condition and prevent self-comparison deadlock#365
fix(PartialEq): resolve TOCTOU race condition and prevent self-comparison deadlock#365p-player wants to merge 1 commit intoxacrimon:masterfrom
Conversation
b10c844 to
de19b99
Compare
src/lib.rs
Outdated
|
|
||
| fn _is_empty(&self) -> bool { | ||
| self._len() == 0 | ||
| self.shards.iter().all(|s| s.read().len() == 0) |
There was a problem hiding this comment.
This doesn't seem to improve anything -- you can still get a race because the shards are never locked at the same time.
| let hash = { | ||
| let mut hasher = other.hasher.build_hasher(); | ||
| k.hash(&mut hasher); | ||
| hasher.finish() | ||
| }; |
There was a problem hiding this comment.
nit: BuildHasher::hash_one was added in 1.71, dashmap's MSRV is 1.70 and was bumped a year ago, so maybe bumping MSRV to use hash_one would be a good idea just from a code readability PoV
|
As @xacrimon said in the issue, I think this fix is somewhat misguided. This fixes races in some functions, like This calls for two functions as opposed to one, or, better yet, a separation of concerns: only make "true" The new issue here is that I can think of a workaround: add a new type This needs to be mulled over some more, but maybe it'll give you (or someone else who stumbles upon this) direction. |
de19b99 to
3255cb6
Compare
…ison deadlock This change acquires read locks on all shards before performing equality checks in DashMap and DashSet, ensuring a consistent snapshot and preventing false positives under concurrent mutation. It also adds a pointer equality check to avoid deadlocks when comparing a map to itself.
3255cb6 to
a5447a2
Compare
|
Thank you for the thorough review, @purplesyringa. I've pushed an update addressing the immediate issues: Changes in this update:
On the broader architectural point: You're right that the implicit locking approach in Your proposed separation of concerns makes much more sense:
A I'm happy to rework this PR in that direction, or close it in favor of a more comprehensive implementation. Let me know how you'd prefer to proceed. |
|
Note that this p-player user is not contributing in good faith in Rust projects as evidenced by their comment in rust-lang/unsafe-code-guidelines#362 (comment) |
|
Ah, I was afraid that was the case. Thanks for the warning! |
Description
This PR addresses the Time-of-Check to Time-of-Use (TOCTOU) race condition in
PartialEqand is_empty implementations, as reported in issue #358.The previous implementation of
PartialEqperformed a length check followed by an element-wise iteration as separate, non-atomic steps. This allowed concurrent mutators to modify the map between these steps, leading to incorrect equality results (false positives).Changes
DashMap::PartialEqto acquire read guards for all shards in both maps simultaneously before performing any comparison. This guarantees an atomic snapshot of the state.std::ptr::eq) at the beginning ofPartialEq. This prevents deadlocks that would otherwise occur when attempting to double-lock the same shards during a self-comparison (e.g.,map == map).Testing
Added new regression and concurrency tests in src/lib.rs:
true.PartialEqunder high concurrency, ensuring no false positives are returned.All 35 existing and new tests passed successfully.
Fixes #358