Skip to content

Commit f3cab77

Browse files
committed
properly implement shrink_to_fit.
For whatever reason it treated 1 as the minimum number of blocks and would corrupt itself if it was already at 0 blocks. It also never actualy did a shrink_to_fit, it just told the underlying bit_vec that it had less initialized blocks. So all around just a buggy mess. Thankfully although the bit_set code is 'unsafe' it wasn't ever actually a memory-safety issue. The unsafe here is a reservation from bit_vec to be more dangerous, but the implementation never actually has any unsafe code of its own, so this was just state corruption that would crash, similar to feeding a bad Ord impl into a BTreeMap. Bad, but not a vulnerability. Fixes #25
1 parent 39cdb58 commit f3cab77

File tree

1 file changed

+88
-2
lines changed

1 file changed

+88
-2
lines changed

src/lib.rs

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -412,11 +412,12 @@ impl<B: BitBlock> BitSet<B> {
412412
.rev()
413413
.take_while(|&&n| n == B::zero())
414414
.count();
415-
// Truncate
416-
let trunc_len = cmp::max(old_len - n, 1);
415+
// Truncate away all empty trailing blocks, then shrink_to_fit
416+
let trunc_len = old_len - n;
417417
unsafe {
418418
bit_vec.storage_mut().truncate(trunc_len);
419419
bit_vec.set_len(trunc_len * B::bits());
420+
bit_vec.shrink_to_fit();
420421
}
421422
}
422423

@@ -1371,6 +1372,91 @@ mod tests {
13711372
assert_eq!(c.cmp(&b), Equal);
13721373
}
13731374

1375+
#[test]
1376+
fn test_bit_set_shrink_to_fit_new() {
1377+
// There was a strange bug where we refused to truncate to 0
1378+
// and this would end up actually growing the array in a way
1379+
// that (safely corrupted the state).
1380+
let mut a = BitSet::new();
1381+
assert_eq!(a.len(), 0);
1382+
assert_eq!(a.capacity(), 0);
1383+
a.shrink_to_fit();
1384+
assert_eq!(a.len(), 0);
1385+
assert_eq!(a.capacity(), 0);
1386+
assert!(!a.contains(1));
1387+
a.insert(3);
1388+
assert!(a.contains(3));
1389+
assert_eq!(a.len(), 1);
1390+
assert!(a.capacity() > 0);
1391+
a.shrink_to_fit();
1392+
assert!(a.contains(3));
1393+
assert_eq!(a.len(), 1);
1394+
assert!(a.capacity() > 0);
1395+
}
1396+
1397+
#[test]
1398+
fn test_bit_set_shrink_to_fit() {
1399+
let mut a = BitSet::new();
1400+
assert_eq!(a.len(), 0);
1401+
assert_eq!(a.capacity(), 0);
1402+
a.insert(259);
1403+
a.insert(98);
1404+
a.insert(3);
1405+
assert_eq!(a.len(), 3);
1406+
assert!(a.capacity() > 0);
1407+
assert!(!a.contains(1));
1408+
assert!(a.contains(259));
1409+
assert!(a.contains(98));
1410+
assert!(a.contains(3));
1411+
1412+
a.shrink_to_fit();
1413+
assert!(!a.contains(1));
1414+
assert!(a.contains(259));
1415+
assert!(a.contains(98));
1416+
assert!(a.contains(3));
1417+
assert_eq!(a.len(), 3);
1418+
assert!(a.capacity() > 0);
1419+
1420+
let old_cap = a.capacity();
1421+
assert!(a.remove(259));
1422+
a.shrink_to_fit();
1423+
assert!(a.capacity() < old_cap, "{} {}", a.capacity(), old_cap);
1424+
assert!(!a.contains(1));
1425+
assert!(!a.contains(259));
1426+
assert!(a.contains(98));
1427+
assert!(a.contains(3));
1428+
assert_eq!(a.len(), 2);
1429+
1430+
let old_cap2 = a.capacity();
1431+
a.clear();
1432+
assert_eq!(a.capacity(), old_cap2);
1433+
assert_eq!(a.len(), 0);
1434+
assert!(!a.contains(1));
1435+
assert!(!a.contains(259));
1436+
assert!(!a.contains(98));
1437+
assert!(!a.contains(3));
1438+
1439+
a.insert(512);
1440+
assert!(a.capacity() > 0);
1441+
assert_eq!(a.len(), 1);
1442+
assert!(a.contains(512));
1443+
assert!(!a.contains(1));
1444+
assert!(!a.contains(259));
1445+
assert!(!a.contains(98));
1446+
assert!(!a.contains(3));
1447+
1448+
a.remove(512);
1449+
a.shrink_to_fit();
1450+
assert_eq!(a.capacity(), 0);
1451+
assert_eq!(a.len(), 0);
1452+
assert!(!a.contains(512));
1453+
assert!(!a.contains(1));
1454+
assert!(!a.contains(259));
1455+
assert!(!a.contains(98));
1456+
assert!(!a.contains(3));
1457+
assert!(!a.contains(0));
1458+
}
1459+
13741460
#[test]
13751461
fn test_bit_vec_remove() {
13761462
let mut a = BitSet::new();

0 commit comments

Comments
 (0)