Skip to content

Revert "Explicitly annotate lifetime of entry methods (#1141)" - #1271

Merged
taiki-e merged 1 commit into
mainfrom
revert-1141
Jun 25, 2026
Merged

Revert "Explicitly annotate lifetime of entry methods (#1141)"#1271
taiki-e merged 1 commit into
mainfrom
revert-1141

Conversation

@taiki-e

@taiki-e taiki-e commented Jun 25, 2026

Copy link
Copy Markdown
Member

This reverts unreleased unsound #1141.

report by Codex Security, repro by Claude Opus 4.6.

#[test]
fn repro() {
    use std::thread;

    use crossbeam_skiplist::SkipMap;

    let map: SkipMap<i32, String> = SkipMap::new();

    // Step 1: Insert a heap-allocated value.
    map.insert(
        1,
        "hello world, this is a long string to ensure heap allocation".to_string(),
    );

    // Step 2: Get a reference with lifetime 'a (lifetime of `map`).
    // With the buggy signature `value(&self) -> &'a V`, this reference outlives the Entry.
    let value_ref: &String = {
        let entry = map.get(&1).unwrap();
        entry.value() // Returns &'a String, not &'entry String
        // entry is dropped here — ref count decremented
    };

    // Step 3: The entry has been dropped. The node's ref count from the Entry is gone.
    // But value_ref is still valid according to the type system (lifetime = 'a = lifetime of map).

    // Step 4: Remove the key from the map — marks the node's tower.
    map.remove(&1);

    // Step 5: Force epoch advancement to reclaim the node.
    // Spawn threads that pin/unpin to advance the global epoch and trigger deferred cleanup.
    let handles: Vec<_> = (0..8)
        .map(|_| {
            thread::spawn(|| {
                for _ in 0..128 {
                    let guard = crossbeam_epoch::pin();
                    guard.flush();
                    drop(guard);
                }
            })
        })
        .collect();
    for h in handles {
        h.join().unwrap();
    }

    // Also do it on the current thread.
    for _ in 0..256 {
        let guard = crossbeam_epoch::pin();
        guard.flush();
        drop(guard);
    }

    // Allocate some memory to overwrite the freed node's memory.
    let _overwrite: Vec<String> = (0..1000).map(|i| format!("OVERWRITTEN {}", i)).collect();

    // Step 6: Use-after-free! The node backing value_ref has been deallocated.
    // This is undefined behavior — in practice it may print garbage, crash, or
    // appear to work (stale data still in memory).
    println!("value_ref = {:?}", value_ref);
    println!("length = {}", value_ref.len());
}
error: Undefined Behavior: constructing invalid value of type &std::string::String: encountered a dangling reference (use-after-free)
    --> /Users/taiki/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/fmt/mod.rs:2874:71
     |
2874 |             fn fmt(&self, f: &mut Formatter<'_>) -> Result { $tr::fmt(&**self, f) }
     |                                                                       ^^^^^^^ Undefined Behavior occurred here
...
2884 | fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperExp }
     | ----------------------------------------------------------------------------------- in this macro invocation
     |
     = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
     = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
     = note: this is on thread `repro`
     = note: stack backtrace:
             0: <&std::string::String as std::fmt::Debug>::fmt
                 at /Users/taiki/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/fmt/mod.rs:2874:71: 2874:78
             1: core::fmt::rt::Argument::<'_>::fmt
                 at /Users/taiki/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/fmt/rt.rs:152:76: 152:95
             2: std::fmt::write
                 at /Users/taiki/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/fmt/mod.rs:1687:17: 1689:80
             3: std::io::default_write_fmt::<std::vec::Vec<u8>>
                 at /Users/taiki/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/std/src/io/mod.rs:623:11: 623:40
             4: <std::vec::Vec<u8> as std::io::Write>::write_fmt
                 at /Users/taiki/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/std/src/io/mod.rs:1727:13: 1727:42
             5: std::io::stdio::print_to_buffer_if_capture_used::{closure#0}::{closure#0}
                 at /Users/taiki/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/std/src/io/stdio.rs:1177:25: 1177:84
             6: std::option::Option::<std::sync::Arc<std::sync::Mutex<std::vec::Vec<u8>>>>::map::<(), {closure@std::io::stdio::print_to_buffer_if_capture_used::{closure#0}::{closure#0}}>
                 at /Users/taiki/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/option.rs:1162:29: 1162:33
             7: std::io::stdio::print_to_buffer_if_capture_used::{closure#0}
                 at /Users/taiki/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/std/src/io/stdio.rs:1176:13: 1179:15
             8: std::thread::LocalKey::<std::cell::Cell<std::option::Option<std::sync::Arc<std::sync::Mutex<std::vec::Vec<u8>>>>>>::try_with::<{closure@std::io::stdio::print_to_buffer_if_capture_used::{closure#0}}, std::option::Option<()>>
                 at /Users/taiki/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/std/src/thread/local.rs:463:12: 463:27
             9: std::io::stdio::print_to_buffer_if_capture_used
                 at /Users/taiki/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/std/src/io/stdio.rs:1172:12: 1180:11
             10: std::io::stdio::print_to::<std::io::Stdout>
                 at /Users/taiki/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/std/src/io/stdio.rs:1160:8: 1160:45
             11: std::io::_print
                 at /Users/taiki/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/std/src/io/stdio.rs:1273:5: 1273:37
             12: repro
                 at /Users/taiki/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/std/src/macros.rs:146:9: 146:62
             13: repro::{closure#0}
                 at crossbeam-skiplist/tests/map.rs:11:11: 11:11
     = note: this error originates in the macro `fmt_refs` (in Nightly builds, run with -Z macro-backtrace for more info)

@taiki-e
taiki-e merged commit 6195355 into main Jun 25, 2026
61 of 62 checks passed
@taiki-e
taiki-e deleted the revert-1141 branch June 25, 2026 20:24
@thynson

thynson commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

😨

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

2 participants