Skip to content

Commit 3e1d602

Browse files
committed
BTreeMap: share panicky test code & test panic during clear, clone
1 parent 6d2247e commit 3e1d602

File tree

4 files changed

+303
-183
lines changed

4 files changed

+303
-183
lines changed

library/alloc/src/collections/btree/map/tests.rs

+152-127
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use super::super::testing::crash_test::{CrashTestDummy, Panic};
12
use super::super::testing::ord_chaos::{Cyclic3, Governed, Governor};
23
use super::super::testing::rng::DeterministicRng;
34
use super::Entry::{Occupied, Vacant};
@@ -1134,103 +1135,78 @@ mod test_drain_filter {
11341135

11351136
#[test]
11361137
fn drop_panic_leak() {
1137-
static PREDS: AtomicUsize = AtomicUsize::new(0);
1138-
static DROPS: AtomicUsize = AtomicUsize::new(0);
1139-
1140-
struct D;
1141-
impl Drop for D {
1142-
fn drop(&mut self) {
1143-
if DROPS.fetch_add(1, SeqCst) == 1 {
1144-
panic!("panic in `drop`");
1145-
}
1146-
}
1147-
}
1148-
1149-
// Keys are multiples of 4, so that each key is counted by a hexadecimal digit.
1150-
let mut map = (0..3).map(|i| (i * 4, D)).collect::<BTreeMap<_, _>>();
1138+
let a = CrashTestDummy::new(0);
1139+
let b = CrashTestDummy::new(1);
1140+
let c = CrashTestDummy::new(2);
1141+
let mut map = BTreeMap::new();
1142+
map.insert(a.spawn(Panic::Never), ());
1143+
map.insert(b.spawn(Panic::InDrop), ());
1144+
map.insert(c.spawn(Panic::Never), ());
11511145

1152-
catch_unwind(move || {
1153-
drop(map.drain_filter(|i, _| {
1154-
PREDS.fetch_add(1usize << i, SeqCst);
1155-
true
1156-
}))
1157-
})
1158-
.unwrap_err();
1146+
catch_unwind(move || drop(map.drain_filter(|dummy, _| dummy.query(true)))).unwrap_err();
11591147

1160-
assert_eq!(PREDS.load(SeqCst), 0x011);
1161-
assert_eq!(DROPS.load(SeqCst), 3);
1148+
assert_eq!(a.queried(), 1);
1149+
assert_eq!(b.queried(), 1);
1150+
assert_eq!(c.queried(), 0);
1151+
assert_eq!(a.dropped(), 1);
1152+
assert_eq!(b.dropped(), 1);
1153+
assert_eq!(c.dropped(), 1);
11621154
}
11631155

11641156
#[test]
11651157
fn pred_panic_leak() {
1166-
static PREDS: AtomicUsize = AtomicUsize::new(0);
1167-
static DROPS: AtomicUsize = AtomicUsize::new(0);
1168-
1169-
struct D;
1170-
impl Drop for D {
1171-
fn drop(&mut self) {
1172-
DROPS.fetch_add(1, SeqCst);
1173-
}
1174-
}
1175-
1176-
// Keys are multiples of 4, so that each key is counted by a hexadecimal digit.
1177-
let mut map = (0..3).map(|i| (i * 4, D)).collect::<BTreeMap<_, _>>();
1178-
1179-
catch_unwind(AssertUnwindSafe(|| {
1180-
drop(map.drain_filter(|i, _| {
1181-
PREDS.fetch_add(1usize << i, SeqCst);
1182-
match i {
1183-
0 => true,
1184-
_ => panic!(),
1185-
}
1186-
}))
1187-
}))
1188-
.unwrap_err();
1189-
1190-
assert_eq!(PREDS.load(SeqCst), 0x011);
1191-
assert_eq!(DROPS.load(SeqCst), 1);
1158+
let a = CrashTestDummy::new(0);
1159+
let b = CrashTestDummy::new(1);
1160+
let c = CrashTestDummy::new(2);
1161+
let mut map = BTreeMap::new();
1162+
map.insert(a.spawn(Panic::Never), ());
1163+
map.insert(b.spawn(Panic::InQuery), ());
1164+
map.insert(c.spawn(Panic::InQuery), ());
1165+
1166+
catch_unwind(AssertUnwindSafe(|| drop(map.drain_filter(|dummy, _| dummy.query(true)))))
1167+
.unwrap_err();
1168+
1169+
assert_eq!(a.queried(), 1);
1170+
assert_eq!(b.queried(), 1);
1171+
assert_eq!(c.queried(), 0);
1172+
assert_eq!(a.dropped(), 1);
1173+
assert_eq!(b.dropped(), 0);
1174+
assert_eq!(c.dropped(), 0);
11921175
assert_eq!(map.len(), 2);
1193-
assert_eq!(map.first_entry().unwrap().key(), &4);
1194-
assert_eq!(map.last_entry().unwrap().key(), &8);
1176+
assert_eq!(map.first_entry().unwrap().key().id(), 1);
1177+
assert_eq!(map.last_entry().unwrap().key().id(), 2);
11951178
map.check();
11961179
}
11971180

11981181
// Same as above, but attempt to use the iterator again after the panic in the predicate
11991182
#[test]
12001183
fn pred_panic_reuse() {
1201-
static PREDS: AtomicUsize = AtomicUsize::new(0);
1202-
static DROPS: AtomicUsize = AtomicUsize::new(0);
1203-
1204-
struct D;
1205-
impl Drop for D {
1206-
fn drop(&mut self) {
1207-
DROPS.fetch_add(1, SeqCst);
1208-
}
1209-
}
1210-
1211-
// Keys are multiples of 4, so that each key is counted by a hexadecimal digit.
1212-
let mut map = (0..3).map(|i| (i * 4, D)).collect::<BTreeMap<_, _>>();
1184+
let a = CrashTestDummy::new(0);
1185+
let b = CrashTestDummy::new(1);
1186+
let c = CrashTestDummy::new(2);
1187+
let mut map = BTreeMap::new();
1188+
map.insert(a.spawn(Panic::Never), ());
1189+
map.insert(b.spawn(Panic::InQuery), ());
1190+
map.insert(c.spawn(Panic::InQuery), ());
12131191

12141192
{
1215-
let mut it = map.drain_filter(|i, _| {
1216-
PREDS.fetch_add(1usize << i, SeqCst);
1217-
match i {
1218-
0 => true,
1219-
_ => panic!(),
1220-
}
1221-
});
1193+
let mut it = map.drain_filter(|dummy, _| dummy.query(true));
12221194
catch_unwind(AssertUnwindSafe(|| while it.next().is_some() {})).unwrap_err();
12231195
// Iterator behaviour after a panic is explicitly unspecified,
12241196
// so this is just the current implementation:
12251197
let result = catch_unwind(AssertUnwindSafe(|| it.next()));
12261198
assert!(matches!(result, Ok(None)));
12271199
}
12281200

1229-
assert_eq!(PREDS.load(SeqCst), 0x011);
1230-
assert_eq!(DROPS.load(SeqCst), 1);
1201+
assert_eq!(a.queried(), 1);
1202+
assert_eq!(b.queried(), 1);
1203+
assert_eq!(c.queried(), 0);
1204+
assert_eq!(a.dropped(), 1);
1205+
assert_eq!(b.dropped(), 0);
1206+
assert_eq!(c.dropped(), 0);
12311207
assert_eq!(map.len(), 2);
1232-
assert_eq!(map.first_entry().unwrap().key(), &4);
1233-
assert_eq!(map.last_entry().unwrap().key(), &8);
1208+
assert_eq!(map.first_entry().unwrap().key().id(), 1);
1209+
assert_eq!(map.last_entry().unwrap().key().id(), 2);
12341210
map.check();
12351211
}
12361212
}
@@ -1437,6 +1413,43 @@ fn test_bad_zst() {
14371413
m.check();
14381414
}
14391415

1416+
#[test]
1417+
fn test_clear() {
1418+
let mut map = BTreeMap::new();
1419+
for &len in &[MIN_INSERTS_HEIGHT_1, MIN_INSERTS_HEIGHT_2, 0, NODE_CAPACITY] {
1420+
for i in 0..len {
1421+
map.insert(i, ());
1422+
}
1423+
assert_eq!(map.len(), len);
1424+
map.clear();
1425+
map.check();
1426+
assert!(map.is_empty());
1427+
}
1428+
}
1429+
1430+
#[test]
1431+
fn test_clear_drop_panic_leak() {
1432+
let a = CrashTestDummy::new(0);
1433+
let b = CrashTestDummy::new(1);
1434+
let c = CrashTestDummy::new(2);
1435+
1436+
let mut map = BTreeMap::new();
1437+
map.insert(a.spawn(Panic::Never), ());
1438+
map.insert(b.spawn(Panic::InDrop), ());
1439+
map.insert(c.spawn(Panic::Never), ());
1440+
1441+
catch_unwind(AssertUnwindSafe(|| map.clear())).unwrap_err();
1442+
assert_eq!(a.dropped(), 1);
1443+
assert_eq!(b.dropped(), 1);
1444+
assert_eq!(c.dropped(), 1);
1445+
assert_eq!(map.len(), 0);
1446+
1447+
drop(map);
1448+
assert_eq!(a.dropped(), 1);
1449+
assert_eq!(b.dropped(), 1);
1450+
assert_eq!(c.dropped(), 1);
1451+
}
1452+
14401453
#[test]
14411454
fn test_clone() {
14421455
let mut map = BTreeMap::new();
@@ -1482,6 +1495,35 @@ fn test_clone() {
14821495
map.check();
14831496
}
14841497

1498+
#[test]
1499+
fn test_clone_panic_leak() {
1500+
let a = CrashTestDummy::new(0);
1501+
let b = CrashTestDummy::new(1);
1502+
let c = CrashTestDummy::new(2);
1503+
1504+
let mut map = BTreeMap::new();
1505+
map.insert(a.spawn(Panic::Never), ());
1506+
map.insert(b.spawn(Panic::InClone), ());
1507+
map.insert(c.spawn(Panic::Never), ());
1508+
1509+
catch_unwind(|| map.clone()).unwrap_err();
1510+
assert_eq!(a.cloned(), 1);
1511+
assert_eq!(b.cloned(), 1);
1512+
assert_eq!(c.cloned(), 0);
1513+
assert_eq!(a.dropped(), 1);
1514+
assert_eq!(b.dropped(), 0);
1515+
assert_eq!(c.dropped(), 0);
1516+
assert_eq!(map.len(), 3);
1517+
1518+
drop(map);
1519+
assert_eq!(a.cloned(), 1);
1520+
assert_eq!(b.cloned(), 1);
1521+
assert_eq!(c.cloned(), 0);
1522+
assert_eq!(a.dropped(), 2);
1523+
assert_eq!(b.dropped(), 1);
1524+
assert_eq!(c.dropped(), 1);
1525+
}
1526+
14851527
#[test]
14861528
fn test_clone_from() {
14871529
let mut map1 = BTreeMap::new();
@@ -1899,29 +1941,21 @@ create_append_test!(test_append_1700, 1700);
18991941

19001942
#[test]
19011943
fn test_append_drop_leak() {
1902-
static DROPS: AtomicUsize = AtomicUsize::new(0);
1903-
1904-
struct D;
1905-
1906-
impl Drop for D {
1907-
fn drop(&mut self) {
1908-
if DROPS.fetch_add(1, SeqCst) == 0 {
1909-
panic!("panic in `drop`");
1910-
}
1911-
}
1912-
}
1913-
1944+
let a = CrashTestDummy::new(0);
1945+
let b = CrashTestDummy::new(1);
1946+
let c = CrashTestDummy::new(2);
19141947
let mut left = BTreeMap::new();
19151948
let mut right = BTreeMap::new();
1916-
left.insert(0, D);
1917-
left.insert(1, D); // first to be dropped during append
1918-
left.insert(2, D);
1919-
right.insert(1, D);
1920-
right.insert(2, D);
1949+
left.insert(a.spawn(Panic::Never), ());
1950+
left.insert(b.spawn(Panic::InDrop), ()); // first duplicate key, dropped during append
1951+
left.insert(c.spawn(Panic::Never), ());
1952+
right.insert(b.spawn(Panic::Never), ());
1953+
right.insert(c.spawn(Panic::Never), ());
19211954

19221955
catch_unwind(move || left.append(&mut right)).unwrap_err();
1923-
1924-
assert_eq!(DROPS.load(SeqCst), 4); // Rust issue #47949 ate one little piggy
1956+
assert_eq!(a.dropped(), 1);
1957+
assert_eq!(b.dropped(), 1); // should be 2 were it not for Rust issue #47949
1958+
assert_eq!(c.dropped(), 2);
19251959
}
19261960

19271961
#[test]
@@ -2048,51 +2082,42 @@ fn test_split_off_large_random_sorted() {
20482082

20492083
#[test]
20502084
fn test_into_iter_drop_leak_height_0() {
2051-
static DROPS: AtomicUsize = AtomicUsize::new(0);
2052-
2053-
struct D;
2054-
2055-
impl Drop for D {
2056-
fn drop(&mut self) {
2057-
if DROPS.fetch_add(1, SeqCst) == 3 {
2058-
panic!("panic in `drop`");
2059-
}
2060-
}
2061-
}
2062-
2085+
let a = CrashTestDummy::new(0);
2086+
let b = CrashTestDummy::new(1);
2087+
let c = CrashTestDummy::new(2);
2088+
let d = CrashTestDummy::new(3);
2089+
let e = CrashTestDummy::new(4);
20632090
let mut map = BTreeMap::new();
2064-
map.insert("a", D);
2065-
map.insert("b", D);
2066-
map.insert("c", D);
2067-
map.insert("d", D);
2068-
map.insert("e", D);
2091+
map.insert("a", a.spawn(Panic::Never));
2092+
map.insert("b", b.spawn(Panic::Never));
2093+
map.insert("c", c.spawn(Panic::Never));
2094+
map.insert("d", d.spawn(Panic::InDrop));
2095+
map.insert("e", e.spawn(Panic::Never));
20692096

20702097
catch_unwind(move || drop(map.into_iter())).unwrap_err();
20712098

2072-
assert_eq!(DROPS.load(SeqCst), 5);
2099+
assert_eq!(a.dropped(), 1);
2100+
assert_eq!(b.dropped(), 1);
2101+
assert_eq!(c.dropped(), 1);
2102+
assert_eq!(d.dropped(), 1);
2103+
assert_eq!(e.dropped(), 1);
20732104
}
20742105

20752106
#[test]
20762107
fn test_into_iter_drop_leak_height_1() {
20772108
let size = MIN_INSERTS_HEIGHT_1;
2078-
static DROPS: AtomicUsize = AtomicUsize::new(0);
2079-
static PANIC_POINT: AtomicUsize = AtomicUsize::new(0);
2080-
2081-
struct D;
2082-
impl Drop for D {
2083-
fn drop(&mut self) {
2084-
if DROPS.fetch_add(1, SeqCst) == PANIC_POINT.load(SeqCst) {
2085-
panic!("panic in `drop`");
2086-
}
2087-
}
2088-
}
2089-
20902109
for panic_point in vec![0, 1, size - 2, size - 1] {
2091-
DROPS.store(0, SeqCst);
2092-
PANIC_POINT.store(panic_point, SeqCst);
2093-
let map: BTreeMap<_, _> = (0..size).map(|i| (i, D)).collect();
2110+
let dummies: Vec<_> = (0..size).map(|i| CrashTestDummy::new(i)).collect();
2111+
let map: BTreeMap<_, _> = (0..size)
2112+
.map(|i| {
2113+
let panic = if i == panic_point { Panic::InDrop } else { Panic::Never };
2114+
(dummies[i].spawn(Panic::Never), dummies[i].spawn(panic))
2115+
})
2116+
.collect();
20942117
catch_unwind(move || drop(map.into_iter())).unwrap_err();
2095-
assert_eq!(DROPS.load(SeqCst), size);
2118+
for i in 0..size {
2119+
assert_eq!(dummies[i].dropped(), 2);
2120+
}
20962121
}
20972122
}
20982123

0 commit comments

Comments
 (0)