Skip to content

Eq, is_empty have false positives on races #358

@purplesyringa

Description

@purplesyringa

It is possible to have two concurrently modified sets A, B, such that neither version of A is equal to any version of B, but == returns true.

Set equality is implemented like this:

dashmap/src/set.rs

Lines 386 to 390 in 366ce7e

impl<K: Eq + Hash, S: BuildHasher + Clone> PartialEq for DashSet<K, S> {
fn eq(&self, other: &Self) -> bool {
self.len() == other.len() && self.iter().all(|r| other.contains(r.key()))
}
}

Consider the following sequence of operations:

  1. We start with A = {1}, B = {2}.
  2. Thread 1 starts the comparison, verifying A.len() == B.len().
  3. Thread 2 inserts 1 into B, resulting in B = {1, 2}.
  4. Thread 1 finishes the comparison, verifying that the sole element 1 of A is present in B.

A similar counterexample exists for maps.

This means that PartialEq is not just inefficient, but strictly speaking incorrect. If the intention is testing code, perhaps eq should lock the whole map/set before performing comparison? I'm guessing consistently locking the shards in order should avoid deadlocks.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions