Skip to content

Commit ae3a515

Browse files
Avoid hash_slice in VecDeque's Hash implementation
Fixes #80303.
1 parent 66eb982 commit ae3a515

File tree

2 files changed

+47
-3
lines changed

2 files changed

+47
-3
lines changed

library/alloc/src/collections/vec_deque/mod.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -2646,9 +2646,13 @@ impl<A: Ord> Ord for VecDeque<A> {
26462646
impl<A: Hash> Hash for VecDeque<A> {
26472647
fn hash<H: Hasher>(&self, state: &mut H) {
26482648
self.len().hash(state);
2649-
let (a, b) = self.as_slices();
2650-
Hash::hash_slice(a, state);
2651-
Hash::hash_slice(b, state);
2649+
// It's not possible to use Hash::hash_slice on slices
2650+
// returned by as_slices method as their length can vary
2651+
// in otherwise identical deques.
2652+
//
2653+
// Hasher only guarantees equivalence for the exact same
2654+
// set of calls to its methods.
2655+
self.iter().for_each(|elem| elem.hash(state));
26522656
}
26532657
}
26542658

library/alloc/src/collections/vec_deque/tests.rs

+40
Original file line numberDiff line numberDiff line change
@@ -599,3 +599,43 @@ fn issue_53529() {
599599
assert_eq!(*a, 2);
600600
}
601601
}
602+
603+
#[test]
604+
fn issue_80303() {
605+
use core::iter;
606+
use core::num::Wrapping;
607+
608+
// This is a valid, albeit rather bad hash function implementation.
609+
struct SimpleHasher(Wrapping<u64>);
610+
611+
impl Hasher for SimpleHasher {
612+
fn finish(&self) -> u64 {
613+
self.0.0
614+
}
615+
616+
fn write(&mut self, bytes: &[u8]) {
617+
// This particular implementation hashes value 24 in addition to bytes.
618+
// Such an implementation is valid as Hasher only guarantees equivalence
619+
// for the exact same set of calls to its methods.
620+
for &v in iter::once(&24).chain(bytes) {
621+
self.0 = Wrapping(31) * self.0 + Wrapping(u64::from(v));
622+
}
623+
}
624+
}
625+
626+
fn hash_code(value: impl Hash) -> u64 {
627+
let mut hasher = SimpleHasher(Wrapping(1));
628+
value.hash(&mut hasher);
629+
hasher.finish()
630+
}
631+
632+
// This creates two deques for which values returned by as_slices
633+
// method differ.
634+
let vda: VecDeque<u8> = (0..10).collect();
635+
let mut vdb = VecDeque::with_capacity(10);
636+
vdb.extend(5..10);
637+
(0..5).rev().for_each(|elem| vdb.push_front(elem));
638+
assert_ne!(vda.as_slices(), vdb.as_slices());
639+
assert_eq!(vda, vdb);
640+
assert_eq!(hash_code(vda), hash_code(vdb));
641+
}

0 commit comments

Comments
 (0)