diff options
| author | Konrad Borowski <konrad@borowski.pw> | 2021-01-18 17:56:06 +0100 |
|---|---|---|
| committer | Konrad Borowski <konrad@borowski.pw> | 2021-01-18 17:56:06 +0100 |
| commit | ae3a5153377f2271ba7dfe686a9b5bca1632c32b (patch) | |
| tree | bfeb06c3979a4d0e464b5923fa9f5de2ba1ac461 | |
| parent | 66eb9821666e0672a69a998d2331733c7a8996a5 (diff) | |
| download | rust-ae3a5153377f2271ba7dfe686a9b5bca1632c32b.tar.gz rust-ae3a5153377f2271ba7dfe686a9b5bca1632c32b.zip | |
Avoid hash_slice in VecDeque's Hash implementation
Fixes #80303.
| -rw-r--r-- | library/alloc/src/collections/vec_deque/mod.rs | 10 | ||||
| -rw-r--r-- | library/alloc/src/collections/vec_deque/tests.rs | 40 |
2 files changed, 47 insertions, 3 deletions
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 5b61e8911a5..6f9133e2811 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -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)); } } diff --git a/library/alloc/src/collections/vec_deque/tests.rs b/library/alloc/src/collections/vec_deque/tests.rs index 27dc59ae644..87e06fa394d 100644 --- a/library/alloc/src/collections/vec_deque/tests.rs +++ b/library/alloc/src/collections/vec_deque/tests.rs @@ -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)); +} |
