Safe-to-use macro-free self-referential structs in stable Rust?

Recently ran into a situation where self referential structs would have been a nice solution, and while I found a decent amount of discussion around the topic I didn't find a satisfying solution. So begrudgingly I unpacked to unsafe hammer and got to work.

I'd really appreciate any feedback from API to soundness. Note, the documentation is still very rudimentary and I plan to properly document all functions and traits. But before that it would be great if some more experienced people than me could take a look at the unsafe in https://github.com/Voultapher/once_self_cell/blob/main/src/once_self_cell.rs, going through the nomicon I couldn't find a way this could be used to trigger UB, and so far miri agrees with me https://github.com/Voultapher/once_self_cell/runs/1538569928

One of the core motivations for this was that rental is heavy to compile and no longer maintained, while this is pretty minimal:

Compiling once_cell v1.5.2
Compiling once_self_cell v0.1.0
Completed once_cell v1.5.2 in 0.9s
Completed once_self_cell v0.1.0 in 0.3s

This looks like something going wrong in safe code:

use once_self_cell::sync::OnceSelfCell;
use std::fmt::Debug;

struct Ref<'a, T: Debug>(&'a T);

#[derive(Debug)]
enum Void {}

fn main() {
    OnceSelfCell::new(None::<Vec<Void>>).get_or_init_dependent(Ref);
}

impl<'a, T: Debug> Drop for Ref<'a, T> {
    fn drop(&mut self) {
        println!("{:?}", self.0);
    }
}
$ cargo run
   Compiling testing v0.0.0 (/git/repro)
    Finished dev [unoptimized + debuginfo] target(s) in 0.08s
     Running `target/debug/repro`
Illegal instruction (core dumped)
5 Likes
use once_self_cell::sync::OnceSelfCell;

fn main() {
    let c: OnceSelfCell<()> = OnceSelfCell::new(());
    let () = c.get_or_init_dependent(|_| ());
    let bad: &i32 = c.get_or_init_dependent(|_| 42);
    println!("{}", bad);
}
Segmentation fault (core dumped)

Also note, that such a question is perhaps more fitting on users.rust-lang.org; with the code-review tag.

6 Likes

@dtolnay @steffahn thanks for the feedback. I've published a new version with both problems addressed. And also posted a code-review request here https://users.rust-lang.org/t/safe-to-use-macro-free-self-referential-structs-in-stable-rust/52775

1 Like