Skip to content

Commit

Permalink
Rollup merge of #81170 - xfix:vecdeque-bug-fix, r=sfackler
Browse files Browse the repository at this point in the history
Avoid hash_slice in VecDeque's Hash implementation

Fixes #80303.
  • Loading branch information
jonas-schievink committed Jan 23, 2021
2 parents 57d6553 + ae3a515 commit 05a95a4
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 3 deletions.
10 changes: 7 additions & 3 deletions library/alloc/src/collections/vec_deque/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2646,9 +2646,13 @@ impl<A: Ord> Ord for VecDeque<A> {
impl<A: Hash> Hash for VecDeque<A> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.len().hash(state);
let (a, b) = self.as_slices();
Hash::hash_slice(a, state);
Hash::hash_slice(b, state);
// It's not possible to use Hash::hash_slice on slices
// returned by as_slices method as their length can vary
// in otherwise identical deques.
//
// Hasher only guarantees equivalence for the exact same
// set of calls to its methods.
self.iter().for_each(|elem| elem.hash(state));
}
}

Expand Down
40 changes: 40 additions & 0 deletions library/alloc/src/collections/vec_deque/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -599,3 +599,43 @@ fn issue_53529() {
assert_eq!(*a, 2);
}
}

#[test]
fn issue_80303() {
use core::iter;
use core::num::Wrapping;

// This is a valid, albeit rather bad hash function implementation.
struct SimpleHasher(Wrapping<u64>);

impl Hasher for SimpleHasher {
fn finish(&self) -> u64 {
self.0.0
}

fn write(&mut self, bytes: &[u8]) {
// This particular implementation hashes value 24 in addition to bytes.
// Such an implementation is valid as Hasher only guarantees equivalence
// for the exact same set of calls to its methods.
for &v in iter::once(&24).chain(bytes) {
self.0 = Wrapping(31) * self.0 + Wrapping(u64::from(v));
}
}
}

fn hash_code(value: impl Hash) -> u64 {
let mut hasher = SimpleHasher(Wrapping(1));
value.hash(&mut hasher);
hasher.finish()
}

// This creates two deques for which values returned by as_slices
// method differ.
let vda: VecDeque<u8> = (0..10).collect();
let mut vdb = VecDeque::with_capacity(10);
vdb.extend(5..10);
(0..5).rev().for_each(|elem| vdb.push_front(elem));
assert_ne!(vda.as_slices(), vdb.as_slices());
assert_eq!(vda, vdb);
assert_eq!(hash_code(vda), hash_code(vdb));
}

0 comments on commit 05a95a4

Please sign in to comment.