]> Untitled Git - bdk/commitdiff
test(core): test `Drop` implementation of `CPInner`
authorvalued mammal <valuedmammal@protonmail.com>
Tue, 19 Nov 2024 15:43:15 +0000 (10:43 -0500)
committervalued mammal <valuedmammal@protonmail.com>
Tue, 19 Nov 2024 15:43:15 +0000 (10:43 -0500)
Check that dropping `CheckPoint` does not cause nasty behavior
by creating a large linked list in memory and then destroying it.

crates/core/src/checkpoint.rs
crates/core/tests/test_checkpoint.rs

index 9b5b0bbd46e766eff6672542cdba972b6d427d6f..9bfdf2eede63a5f3255f29451f5b19d706164b75 100644 (file)
@@ -38,7 +38,7 @@ impl Drop for CPInner {
             // that no recursive drop calls can happen even with multiple threads.
             match Arc::try_unwrap(arc_node).ok() {
                 Some(mut node) => {
-                    // Keep goign backwards
+                    // Keep going backwards
                     current = node.prev.take();
                     // Don't call `drop` on `CPInner` since that risks it becoming recursive.
                     core::mem::forget(node);
index 2ec96c1530a4205644d23363be1caa9a8c2f4d22..a5194e5b9c525c7b8549481b63d13d890eab70c6 100644 (file)
@@ -1,5 +1,5 @@
-use bdk_core::CheckPoint;
-use bdk_testenv::block_id;
+use bdk_core::{BlockId, CheckPoint};
+use bdk_testenv::{block_id, hash};
 
 /// Inserting a block that already exists in the checkpoint chain must always succeed.
 #[test]
@@ -32,3 +32,22 @@ fn checkpoint_insert_existing() {
         }
     }
 }
+
+#[test]
+fn checkpoint_destruction_is_sound() {
+    // Prior to the fix in https://github.com/bitcoindevkit/bdk/pull/1731
+    // this could have caused a stack overflow due to drop recursion in Arc.
+    // We test that a long linked list can clean itself up without blowing
+    // out the stack.
+    let mut cp = CheckPoint::new(BlockId {
+        height: 0,
+        hash: hash!("g"),
+    });
+    let end = 10_000;
+    for height in 1u32..end {
+        let hash = bitcoin::hashes::Hash::hash(height.to_be_bytes().as_slice());
+        let block = BlockId { height, hash };
+        cp = cp.push(block).unwrap();
+    }
+    assert_eq!(cp.iter().count() as u32, end);
+}