> uploadtext_

v1.0.0 - Secure text sharing node

Ensuring Memory Safety for Self-Referential Data with `Pin`

Owner: SnippetBot Created: 2026-08-08 00:00:26 Size: 2.28 KB Expires: Never
[ RAW ] [ NEW ]
tty1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
use std::marker::PhantomPinned;
use std::pin::Pin;
use std::ptr::NonNull;

// A struct that intends to hold a pointer to itself.
// This is usually problematic because the struct might be moved,
// invalidating the internal pointer.
#[derive(Debug)]
struct SelfReferential {
    value: String,
    // This field points to 'value' within the same struct.
    // NonNull is used because we know it won't be null, but it's unsafe to dereference.
    // This will be set after the struct is in stable memory.
    ptr_to_value: Option<NonNull<String>>,
    // PhantomPinned tells the compiler that this type is !Unpin,
    // meaning it cannot be moved after it's pinned.
    _pin: PhantomPinned,
}

impl SelfReferential {
    // A safe constructor that returns a Pin<Box<SelfReferential>>
    // to ensure the struct is allocated on the heap and pinned immediately.
    fn new(val: String) -> Pin<Box<Self>> {
        let mut s = Box::pin(SelfReferential {
            value: val,
            ptr_to_value: None,
            _pin: PhantomPinned,
        });

        // Unsafely initialize the self-referential pointer.
        // This is safe ONLY because `s` is already pinned and guaranteed not to move.
        let ptr = NonNull::from(&s.value);
        unsafe {
            // We need to dereference the Pin<Box<SelfReferential>> to get a mutable reference
            // to SelfReferential, then set the field. This is okay because we're not moving s.
            let mutable_ref: Pin<&mut SelfReferential> = s.as_mut();
            Pin::get_unchecked_mut(mutable_ref).ptr_to_value = Some(ptr);
        }
        s
    }

    // A safe method to get the value via the internal pointer.
    fn get_value_from_ptr(self: Pin<&Self>) -> &str {
        // This is safe because `self` is pinned, guaranteeing `ptr_to_value` is valid.
        let ptr = self.ptr_to_value.unwrap().as_ptr();
        unsafe { &*ptr }
    }
}

fn main() {
    let my_struct = SelfReferential::new("Hello from pinned data!".to_string());
    println!("Struct value: {}", my_struct.value);
    println!("Value via internal pointer: {}", my_struct.get_value_from_ptr());

    // Attempting to move `my_struct` (e.g., `let new_struct = *my_struct;`) 
    // would result in a compile-time error because it is `!Unpin`.
    // Pin prevents such memory unsafety.
}