Skip to content

Commit 54499fe

Browse files
committed
with_next() and forget_next_*() created for Cursor* to handle panic behavior for conflict func
1 parent a7fa7dd commit 54499fe

File tree

2 files changed

+239
-24
lines changed

2 files changed

+239
-24
lines changed

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

Lines changed: 200 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1306,29 +1306,25 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
13061306
let mut other_iter = other.into_iter();
13071307
let (first_other_key, first_other_val) = other_iter.next().unwrap();
13081308

1309-
// find the first gap that has the smallest key greater than the first key from other
1309+
// find the first gap that has the smallest key greater than or equal to
1310+
// the first key from other
13101311
let mut self_cursor = self.lower_bound_mut(Bound::Included(&first_other_key));
13111312

1312-
if let Some((self_key, self_val)) = self_cursor.peek_next() {
1313+
if let Some((self_key, _)) = self_cursor.peek_next() {
13131314
match K::cmp(&first_other_key, self_key) {
13141315
Ordering::Equal => {
1315-
// SAFETY: We read in self_val's and hand it over to our conflict function
1316-
// which will always return a value that we can use to overwrite what's
1317-
// in self_val
1318-
unsafe {
1319-
let val = ptr::read(self_val);
1320-
let next_val = (conflict)(self_key, val, first_other_val);
1321-
ptr::write(self_val, next_val);
1322-
}
1316+
self_cursor.with_next(|self_key, self_val| {
1317+
conflict(self_key, self_val, first_other_val)
1318+
});
13231319
}
13241320
Ordering::Less =>
1325-
// SAFETY: we know our other_key's ordering is less than self_key,
1321+
// Safety: we know our other_key's ordering is less than self_key,
13261322
// so inserting before will guarantee sorted order
13271323
unsafe {
13281324
self_cursor.insert_before_unchecked(first_other_key, first_other_val);
13291325
},
13301326
Ordering::Greater => {
1331-
unreachable!("cursor's peek_next would return None in this case");
1327+
unreachable!("Cursor's peek_next should return None.");
13321328
}
13331329
}
13341330
} else {
@@ -1345,33 +1341,29 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
13451341
if self_cursor.peek_next().is_some() {
13461342
loop {
13471343
let self_entry = self_cursor.peek_next();
1348-
if let Some((self_key, self_val)) = self_entry {
1344+
if let Some((self_key, _)) = self_entry {
13491345
match K::cmp(&other_key, self_key) {
13501346
Ordering::Equal => {
1351-
// SAFETY: We read in self_val's and hand it over to our conflict function
1352-
// which will always return a value that we can use to overwrite what's
1353-
// in self_val
1354-
unsafe {
1355-
let val = ptr::read(self_val);
1356-
let next_val = (conflict)(self_key, val, other_val);
1357-
ptr::write(self_val, next_val);
1358-
}
1347+
self_cursor.with_next(|self_key, self_val| {
1348+
conflict(self_key, self_val, other_val)
1349+
});
13591350
break;
13601351
}
13611352
Ordering::Less => {
1362-
// SAFETY: we know our other_key's ordering is less than self_key,
1353+
// Safety: we know our other_key's ordering is less than self_key,
13631354
// so inserting before will guarantee sorted order
13641355
unsafe {
13651356
self_cursor.insert_before_unchecked(other_key, other_val);
13661357
}
13671358
break;
13681359
}
13691360
Ordering::Greater => {
1361+
// advance the cursor forward
13701362
self_cursor.next();
13711363
}
13721364
}
13731365
} else {
1374-
// SAFETY: if we reach here, that means our cursor has reached
1366+
// Safety: if we reach here, that means our cursor has reached
13751367
// the end of self BTreeMap, (other_key is greater than all the
13761368
// previous self BTreeMap keys) so we just insert other_key here
13771369
// at the end of the Cursor
@@ -1383,7 +1375,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
13831375
}
13841376
}
13851377
} else {
1386-
// SAFETY: if we reach here, that means our cursor has reached
1378+
// Safety: if we reach here, that means our cursor has reached
13871379
// the end of self BTreeMap, (other_key is greater than all the
13881380
// previous self BTreeMap keys) so we just insert the rest of
13891381
// other_keys here at the end of CursorMut
@@ -3417,6 +3409,100 @@ impl<'a, K, V, A> CursorMutKey<'a, K, V, A> {
34173409

34183410
// Now the tree editing operations
34193411
impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> {
3412+
/// Calls a function with ownership of the next element's key and
3413+
/// and value and expects it to return a value to write
3414+
/// back to the next element's key and value. The cursor is not
3415+
/// advanced forward.
3416+
///
3417+
/// If the cursor is at the end of the map then the function is not called
3418+
/// and this essentially does not do anything.
3419+
#[allow(dead_code)] /* This function exists for consistency with CursorMut */
3420+
pub(super) fn with_next(&mut self, f: impl FnOnce(K, V) -> (K, V)) {
3421+
/// Call `f` with the next entry's key and value, replacing the
3422+
/// next entry's key and value with the returned key and value.
3423+
/// if `f` unwinds, the next entry is removed.
3424+
/// Equivalent to a more efficient version of:
3425+
/// ```ignore (this is an example equivalent)
3426+
/// if let Some((k, v)) = self.remove_next() {
3427+
/// let (k, v) = f(k, v);
3428+
/// // Safety: key is unmodified
3429+
/// unsafe { self.insert_after_unchecked(k, v) };
3430+
/// }
3431+
/// ```
3432+
struct RemoveNextOnDrop<'a, 'b, K, V, A = Global>
3433+
where
3434+
K: Ord,
3435+
A: Allocator + Clone,
3436+
{
3437+
cursor: &'a mut CursorMutKey<'b, K, V, A>,
3438+
forget_next: bool,
3439+
}
3440+
3441+
impl<K: Ord, V, A: Allocator + Clone> Drop for RemoveNextOnDrop<'_, '_, K, V, A> {
3442+
fn drop(&mut self) {
3443+
if self.forget_next {
3444+
// Removes the next entry of the Cursor without running
3445+
// running the destructor on the key and value (prevents double
3446+
// free)
3447+
self.cursor.forget_next_key_and_value();
3448+
}
3449+
}
3450+
}
3451+
3452+
let mut remove_next_on_drop = RemoveNextOnDrop {
3453+
cursor: self,
3454+
forget_next: false, // next value is not known yet
3455+
};
3456+
3457+
if let Some((k_mut, v_mut)) = remove_next_on_drop.cursor.peek_next() {
3458+
remove_next_on_drop.forget_next = true;
3459+
// Safety: we move the K, V out of the next entry,
3460+
// we marked the entry's value to be forgotten
3461+
// when remove_next_on_drop is dropped that
3462+
// way we avoid returning to the caller leaving
3463+
// a moved-out invalid value if `f` unwinds.
3464+
let k = unsafe { ptr::read(k_mut) };
3465+
let v = unsafe { ptr::read(v_mut) };
3466+
let (k, v) = f(k, v);
3467+
unsafe { ptr::write(k_mut, k) };
3468+
unsafe { ptr::write(v_mut, v) };
3469+
3470+
remove_next_on_drop.forget_next = false;
3471+
}
3472+
}
3473+
3474+
/// Forgets the next element's key and value from the `BTreeMap`.
3475+
///
3476+
/// The element's key and value does not run its destructor. The cursor position is
3477+
/// unchanged (before the forgotten element).
3478+
fn forget_next_key_and_value(&mut self) {
3479+
let current = match self.current.take() {
3480+
Some(current) => current,
3481+
None => return,
3482+
};
3483+
3484+
if current.reborrow().next_kv().is_err() {
3485+
self.current = Some(current);
3486+
return;
3487+
}
3488+
3489+
let mut emptied_internal_root = false;
3490+
if let Ok(next_kv) = current.next_kv() {
3491+
let ((_, val), pos) =
3492+
next_kv.remove_kv_tracking(|| emptied_internal_root = true, self.alloc.clone());
3493+
// Don't run destructor on next element's value
3494+
mem::forget(val);
3495+
self.current = Some(pos);
3496+
*self.length -= 1;
3497+
if emptied_internal_root {
3498+
// SAFETY: This is safe since current does not point within the now
3499+
// empty root node.
3500+
let root = unsafe { self.root.reborrow().as_mut().unwrap() };
3501+
root.pop_internal_level(self.alloc.clone());
3502+
}
3503+
}
3504+
}
3505+
34203506
/// Inserts a new key-value pair into the map in the gap that the
34213507
/// cursor is currently pointing to.
34223508
///
@@ -3622,6 +3708,96 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> {
36223708
}
36233709

36243710
impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> {
3711+
/// Calls a function with a reference to the next element's key and
3712+
/// ownership of its value. The function is expected to return a value
3713+
/// to write back to the next element's value. The cursor is not
3714+
/// advanced forward.
3715+
///
3716+
/// If the cursor is at the end of the map then the function is not called
3717+
/// and this essentially does not do anything.
3718+
pub(super) fn with_next(&mut self, f: impl FnOnce(&K, V) -> V) {
3719+
/// Call `f` with the next entry's key and value, replacing the
3720+
/// next entry's value with the returned value. if `f` unwinds,
3721+
/// the next entry is removed.
3722+
/// Equivalent to a more efficient version of:
3723+
/// ```ignore (this is an example equivalent)
3724+
/// if let Some((k, v)) = self.remove_next() {
3725+
/// let v = f(&k, v);
3726+
/// // Safety: key is unmodified
3727+
/// unsafe { self.insert_after_unchecked(k, v) };
3728+
/// }
3729+
/// ```
3730+
struct RemoveNextOnDrop<'a, 'b, K, V, A = Global>
3731+
where
3732+
K: Ord,
3733+
A: Allocator + Clone,
3734+
{
3735+
cursor: &'a mut CursorMut<'b, K, V, A>,
3736+
forget_next: bool,
3737+
}
3738+
3739+
impl<K: Ord, V, A: Allocator + Clone> Drop for RemoveNextOnDrop<'_, '_, K, V, A> {
3740+
fn drop(&mut self) {
3741+
if self.forget_next {
3742+
// Removes the next entry of the Cursor without running
3743+
// running the destructor on the value (prevents double
3744+
// free)
3745+
self.cursor.forget_next_value();
3746+
}
3747+
}
3748+
}
3749+
3750+
let mut remove_next_on_drop = RemoveNextOnDrop {
3751+
cursor: self,
3752+
forget_next: false, // next value is not known yet
3753+
};
3754+
3755+
if let Some((k, v_mut)) = remove_next_on_drop.cursor.peek_next() {
3756+
remove_next_on_drop.forget_next = true;
3757+
// Safety: we move the V out of the next entry,
3758+
// we marked the entry's value to be forgotten
3759+
// when remove_next_on_drop is dropped that
3760+
// way we avoid returning to the caller leaving
3761+
// a moved-out invalid value if `f` unwinds.
3762+
let v = unsafe { ptr::read(v_mut) };
3763+
let v = f(k, v);
3764+
unsafe { ptr::write(v_mut, v) };
3765+
remove_next_on_drop.forget_next = false;
3766+
}
3767+
}
3768+
3769+
/// Forgets the next element's value from the `BTreeMap`.
3770+
///
3771+
/// The element's value does not run its destructor. The cursor position is
3772+
/// unchanged (before the forgotten element).
3773+
fn forget_next_value(&mut self) {
3774+
let current = match self.inner.current.take() {
3775+
Some(current) => current,
3776+
None => return,
3777+
};
3778+
3779+
if current.reborrow().next_kv().is_err() {
3780+
self.inner.current = Some(current);
3781+
return;
3782+
}
3783+
3784+
let mut emptied_internal_root = false;
3785+
if let Ok(next_kv) = current.next_kv() {
3786+
let ((_, val), pos) = next_kv
3787+
.remove_kv_tracking(|| emptied_internal_root = true, self.inner.alloc.clone());
3788+
// Don't run destructor on next element's value
3789+
mem::forget(val);
3790+
self.inner.current = Some(pos);
3791+
*self.inner.length -= 1;
3792+
if emptied_internal_root {
3793+
// SAFETY: This is safe since current does not point within the now
3794+
// empty root node.
3795+
let root = unsafe { self.inner.root.reborrow().as_mut().unwrap() };
3796+
root.pop_internal_level(self.inner.alloc.clone());
3797+
}
3798+
}
3799+
}
3800+
36253801
/// Inserts a new key-value pair into the map in the gap that the
36263802
/// cursor is currently pointing to.
36273803
///

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

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2239,6 +2239,45 @@ fn test_append_ord_chaos() {
22392239
map2.check();
22402240
}
22412241

2242+
#[test]
2243+
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
2244+
fn test_merge_drop_leak() {
2245+
let a = CrashTestDummy::new(0);
2246+
let b = CrashTestDummy::new(1);
2247+
let c = CrashTestDummy::new(2);
2248+
let mut left = BTreeMap::new();
2249+
let mut right = BTreeMap::new();
2250+
left.insert(a.spawn(Panic::Never), ());
2251+
left.insert(b.spawn(Panic::Never), ());
2252+
left.insert(c.spawn(Panic::Never), ());
2253+
right.insert(b.spawn(Panic::InDrop), ()); // first duplicate key, dropped during append
2254+
right.insert(c.spawn(Panic::Never), ());
2255+
2256+
catch_unwind(move || left.merge(right, |_, _, _| ())).unwrap_err();
2257+
assert_eq!(a.dropped(), 1);
2258+
assert_eq!(b.dropped(), 2);
2259+
assert_eq!(c.dropped(), 2);
2260+
}
2261+
2262+
#[test]
2263+
fn test_merge_ord_chaos() {
2264+
let mut map1 = BTreeMap::new();
2265+
map1.insert(Cyclic3::A, ());
2266+
map1.insert(Cyclic3::B, ());
2267+
let mut map2 = BTreeMap::new();
2268+
map2.insert(Cyclic3::A, ());
2269+
map2.insert(Cyclic3::B, ());
2270+
map2.insert(Cyclic3::C, ()); // lands first, before A
2271+
map2.insert(Cyclic3::B, ()); // lands first, before C
2272+
map1.check();
2273+
map2.check(); // keys are not unique but still strictly ascending
2274+
assert_eq!(map1.len(), 2);
2275+
assert_eq!(map2.len(), 4);
2276+
map1.merge(map2, |_, _, _| ());
2277+
assert_eq!(map1.len(), 5);
2278+
map1.check();
2279+
}
2280+
22422281
fn rand_data(len: usize) -> Vec<(u32, u32)> {
22432282
let mut rng = DeterministicRng::new();
22442283
Vec::from_iter((0..len).map(|_| (rng.next(), rng.next())))

0 commit comments

Comments
 (0)