As explained at your link, the example program that is not type-safe is based on a mistake of the 1983 Ada standard regarding the use of "aliased", which has been removed by a later Technical Corrigendum, where the program demonstrated at your link is explicitly classified as erroneous, so any compliant Ada compiler should fail to compile it.
As also explained at your link, the same type-safety breaking technique works in unsafe Rust. Both "unchecked" Ada and "unsafe" Rust do not provide type safety, while the safe subsets of the languages provide it.
_3 is magic, _4 is uncopied, and 5 is b. move here is like ptr::read, which means that uncopied points to a copy of magic, not aliasing magic, and is dangling. Because this is UB, it gets optimized straight into the panic.
After I figured that out, miri started working, I must have made a mistake earlier. It will tell us the same thing:
test test ... error: Undefined Behavior: memory access failed: alloc113986 has been freed, so this pointer is dangling
--> src/lib.rs:24:13
|
24 | assert!((*uncopied).value != std::ptr::null());
| ^^^^^^^^^^^^^^^^^ memory access failed: alloc113986 has been freed, so this pointer is dangling
|
= 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
help: alloc113986 was allocated here:
--> src/lib.rs:18:16
|
18 | Magic::B(b) => &b,
| ^
help: alloc113986 was deallocated here:
--> src/lib.rs:18:23
|
18 | Magic::B(b) => &b,
| ^
= note: BACKTRACE (of the first span) on thread `test`:
= note: inside `magic::<&str, &u8>` at src/lib.rs:24:13: 24:30
note: inside `test`
--> src/lib.rs:36:5
|
36 | magic::<&str, &u8>("magic string");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: inside closure
--> src/lib.rs:35:10
|
34 | #[test]
| ------- in this procedural macro expansion
35 | fn test() {
| ^
= note: this error originates in the attribute macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)
This code started failing in Rust 1.12, when MIR happened, so that's exactly my guess as to what fixed it.
adrian_b|1 year ago
As also explained at your link, the same type-safety breaking technique works in unsafe Rust. Both "unchecked" Ada and "unsafe" Rust do not provide type safety, while the safe subsets of the languages provide it.
trott|1 year ago
The article was written in 2011, and the trick still seems to work in a 2024 version of GNAT.
> Both "unchecked" Ada and "unsafe" Rust
But the `Conversion` function isn't using `Unchecked_*`. That's the point of the article. The type safety hole is in "safe" Ada.
steveklabnik|1 year ago
I'm not sure what the difference was, given that the representations haven't changed, and I'm doing this without invoking the optimizer.
EDIT: I had issues with Miri so I dug into the MIR myself:
_3 is magic, _4 is uncopied, and 5 is b. move here is like ptr::read, which means that uncopied points to a copy of magic, not aliasing magic, and is dangling. Because this is UB, it gets optimized straight into the panic.After I figured that out, miri started working, I must have made a mistake earlier. It will tell us the same thing:
This code started failing in Rust 1.12, when MIR happened, so that's exactly my guess as to what fixed it.Funny enough, if we take the critique in the forum as correct, and try with a union: https://play.rust-lang.org/?version=stable&mode=debug&editio...
Rust will: