Skip to content

Commit 2df5861

Browse files
committed
test(core): test Drop implementation of CPInner
Check that dropping `CheckPoint` does not cause nasty behavior by creating a large linked list in memory and then destroying it.
1 parent 67e1dc3 commit 2df5861

File tree

2 files changed

+22
-3
lines changed

2 files changed

+22
-3
lines changed

crates/core/src/checkpoint.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ impl Drop for CPInner {
3838
// that no recursive drop calls can happen even with multiple threads.
3939
match Arc::try_unwrap(arc_node).ok() {
4040
Some(mut node) => {
41-
// Keep goign backwards
41+
// Keep going backwards
4242
current = node.prev.take();
4343
// Don't call `drop` on `CPInner` since that risks it becoming recursive.
4444
core::mem::forget(node);

crates/core/tests/test_checkpoint.rs

+21-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use bdk_core::CheckPoint;
2-
use bdk_testenv::block_id;
1+
use bdk_core::{BlockId, CheckPoint};
2+
use bdk_testenv::{block_id, hash};
33

44
/// Inserting a block that already exists in the checkpoint chain must always succeed.
55
#[test]
@@ -32,3 +32,22 @@ fn checkpoint_insert_existing() {
3232
}
3333
}
3434
}
35+
36+
#[test]
37+
fn checkpoint_destruction_is_sound() {
38+
// Prior to the fix in https://github.com/bitcoindevkit/bdk/pull/1731
39+
// this could have caused a stack overflow due to drop recursion in Arc.
40+
// We test that a long linked list can clean itself up without blowing
41+
// out the stack.
42+
let mut cp = CheckPoint::new(BlockId {
43+
height: 0,
44+
hash: hash!("g"),
45+
});
46+
let end = 10_000;
47+
for height in 1u32..end {
48+
let hash = bitcoin::hashes::Hash::hash(height.to_be_bytes().as_slice());
49+
let block = BlockId { height, hash };
50+
cp = cp.push(block).unwrap();
51+
}
52+
assert_eq!(cp.iter().count() as u32, end);
53+
}

0 commit comments

Comments
 (0)