Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

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.



> a mistake of the 1983 Ada standard ... which has been removed

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.


While that was apparently true in 2015, it doesn't work on today's Rust: https://play.rust-lang.org/?version=stable&mode=debug&editio...

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:

  let uncopied : *const Uncopyable<*const B> =
    match magic {
      Magic::B(b) => &raw const b,

        StorageLive(_4);
        StorageLive(_5);
        _5 = move ((_3 as B).0: Uncopyable<*const B>);
        _4 = &raw const _5;
        StorageDead(_5);
_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.

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:

  1. force us to use ManuallyDrop
  2. the API makes this move explicit, and we get a compile-time error!




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: