> The only thing unsafe does is let you have an unbounded lifetime.
No, you're wrong: You can create any lifetime. Proof:
fn oof<'desired>(x: &u32) -> &'desired u32 {
let ptr = x as *const u32;
unsafe { &*ptr }
}
This will take a reference and return it with any lifetime specified by the caller.> You don't disable anything.
I said "effectively disable". For example:
fn trust_me_bro<'a>(x: mut u32) -> &'a mut u32 { unsafe { &mut x } }
fn main() {
let mut x = 1_u32;
let reference_a = &mut x;
let reference_b = trust_me_bro(reference_a);
*reference_b = 2; -- Whoops
println!("reference_a: {reference_a} reference_b: {reference_b}");
}
After the call to trust_me_bro, two aliasing, mutable references exist simultaneously. This would usually be prevented by the borrow checker, but the unsafe code has effectively disabled it.
> Proof:
You just listed examples of unbounded lifetimes.
> I said "effectively disable". For example:
Not sure what you meant by this example since it doesn't compile. It seems the borrow checker caught your mischief. So much for effectively disabling stuff :P
You haven't effectively disabled anything; you just (tried to) wrote unsound code that washes one mutable ref as another. This stuff is allowed provided shared refs are never accessed at the same time (for example, panicking upon reading reference_b).
What you probably meant is https://play.rust-lang.org/?version=stable&mode=debug&editio...
But you know what? If you're dabbling in unsafe, you have this big button called Tools in the playground. Choose Miri, then run your code; it will display large Undefined behavior. It even highlights the `trust_me_bro` function.
Hell, run this with UBSAN, ASAN, and other C tools. They will probably catch any such behavior.
> You just listed examples of unbounded lifetimes.
You're just splitting hairs and trying to weasel around the fact that yes, you really can create any lifetime you want using unsafe.
> Not sure what you meant by this example since it doesn't compile.
That's because the crappy HN formatting ate some of the characters. Here's the original version:
https://play.rust-lang.org/?version=stable&mode=debug&editio...
> What you probably meant is […]
If you know what I meant, then what's up with your snarky comment about "So much for effectively disabling stuff"? In your playground link, you did effectively disable the borrow checker in safe parts of the code. Next thing you're moving the goalpost, now it's not about external, static analysis tools: "run this with UBSAN, ASAN, and other C tools". I don't think you're arguing in good faith here. Goodbye.
> You're just splitting hairs and trying to weasel around the fact
No. I said borrow checker allows unbound lifetime. I didn't disagree with you. I noted you didn't read the argument.
> If you know what I meant, then what's up with your snarky comment about "So much for effectively disabling stuff"?
Because your original code looked like trying to cast mut u32 to pointer.
> you did effectively disable the borrow checker in safe parts
So this code (https://play.rust-lang.org/?version=stable&mode=debug&editio...) runs now?
Effectively means achieving the goal in satisfying manner.
Writing unsound code is less of effectively disabling borrow checker and more of a hack.
Think about it, if using Java unsafe I gain access to underlying HashMap array and do weird stuff to the HashMap invariants am I effectively turning HashMap into Array or am I doing a hack job?
Edit: By that logic since there is so much unsafe in the code base isn't borrow checker effectively already disabled? You can argue semantics but no, borrow checker isn't de facto or de jure invalidated by unsafe blocks.
It's invalidated by unsound unsafe and that's on code writer to fix.