From 4adcdbb58ba65d0af86c50d77ef42b344b9a5cb2 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Wed, 19 Nov 2025 22:49:44 -0600 Subject: [PATCH 1/2] In `BTreeMap::eq`, do not compare the elements if the sizes are different. Reverts 68a7c250788833305f73f816b284aafa9e62370a in library/ --- library/alloc/src/collections/btree/map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 766f4589177a8..e9d0ad72c1e4c 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -2416,7 +2416,7 @@ impl Default for BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for BTreeMap { fn eq(&self, other: &BTreeMap) -> bool { - self.iter().eq(other) + self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a == b) } } From 907f5c118096eb2e2031f41a5a3337791c7a111e Mon Sep 17 00:00:00 2001 From: Zachary S Date: Thu, 20 Nov 2025 00:09:56 -0600 Subject: [PATCH 2/2] Add regression test for collections' PartialEq::eq impls not comparing elements if lengths are different. --- .../tests/collections/eq_diff_len.rs | 96 +++++++++++++++++++ library/alloctests/tests/collections/mod.rs | 1 + 2 files changed, 97 insertions(+) create mode 100644 library/alloctests/tests/collections/eq_diff_len.rs diff --git a/library/alloctests/tests/collections/eq_diff_len.rs b/library/alloctests/tests/collections/eq_diff_len.rs new file mode 100644 index 0000000000000..ee1e294d37c67 --- /dev/null +++ b/library/alloctests/tests/collections/eq_diff_len.rs @@ -0,0 +1,96 @@ +//! Regression tests which fail if some collections' `PartialEq::eq` impls compare +//! elements when the collections have different sizes. +//! This behavior is not guaranteed either way, so regressing these tests is fine +//! if it is done on purpose. +use std::cmp::Ordering; +use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, LinkedList}; + +/// This intentionally has a panicking `PartialEq` impl, to test that various +/// collections' `PartialEq` impls don't actually compare elements if their sizes +/// are unequal. +/// +/// This is not advisable in normal code. +#[derive(Debug, Clone, Copy, Hash)] +struct Evil; + +impl PartialEq for Evil { + fn eq(&self, _: &Self) -> bool { + panic!("Evil::eq is evil"); + } +} +impl Eq for Evil {} + +impl PartialOrd for Evil { + fn partial_cmp(&self, _: &Self) -> Option { + Some(Ordering::Equal) + } +} + +impl Ord for Evil { + fn cmp(&self, _: &Self) -> Ordering { + // Constructing a `BTreeSet`/`BTreeMap` uses `cmp` on the elements, + // but comparing it with with `==` uses `eq` on the elements, + // so Evil::cmp doesn't need to be evil. + Ordering::Equal + } +} + +// check Evil works +#[test] +#[should_panic = "Evil::eq is evil"] +fn evil_eq_works() { + let v1 = vec![Evil]; + let v2 = vec![Evil]; + + _ = v1 == v2; +} + +// check various containers don't compare if their sizes are different + +#[test] +fn vec_evil_eq() { + let v1 = vec![Evil]; + let v2 = vec![Evil; 2]; + + assert_eq!(false, v1 == v2); +} + +#[test] +fn hashset_evil_eq() { + let s1 = HashSet::from([(0, Evil)]); + let s2 = HashSet::from([(0, Evil), (1, Evil)]); + + assert_eq!(false, s1 == s2); +} + +#[test] +fn hashmap_evil_eq() { + let m1 = HashMap::from([(0, Evil)]); + let m2 = HashMap::from([(0, Evil), (1, Evil)]); + + assert_eq!(false, m1 == m2); +} + +#[test] +fn btreeset_evil_eq() { + let s1 = BTreeSet::from([(0, Evil)]); + let s2 = BTreeSet::from([(0, Evil), (1, Evil)]); + + assert_eq!(false, s1 == s2); +} + +#[test] +fn btreemap_evil_eq() { + let m1 = BTreeMap::from([(0, Evil)]); + let m2 = BTreeMap::from([(0, Evil), (1, Evil)]); + + assert_eq!(false, m1 == m2); +} + +#[test] +fn linkedlist_evil_eq() { + let m1 = LinkedList::from([Evil]); + let m2 = LinkedList::from([Evil; 2]); + + assert_eq!(false, m1 == m2); +} diff --git a/library/alloctests/tests/collections/mod.rs b/library/alloctests/tests/collections/mod.rs index e73f3aaef8c83..2d387f0e77eb5 100644 --- a/library/alloctests/tests/collections/mod.rs +++ b/library/alloctests/tests/collections/mod.rs @@ -1 +1,2 @@ mod binary_heap; +mod eq_diff_len;