memory safety checks and trust

mipri mipri at minimaltype.com
Wed Apr 15 05:45:05 UTC 2020


On Saturday, 11 April 2020 at 01:21:56 UTC, Adam D. Ruppe wrote:
> ```
> void main() {
>         int a;
>         b ~= &a;
> }
>
> int*[] b;
> ```
>
> trust.d(3): Error: copying & a into allocated memory escapes a 
> reference to local variable a
>
>
> (Interestingly, `b = [&a]` instead of ~= passes muster. What's 
> the difference? Just another bug in this?)
>
>
> But the inconsistency isn't why I'm posting right now, it is my 
> fear that D is losing faith in me. There seems to be no way to 
> say "trust me" to the compiler. Note that I'm not even using 
> any switches to dmd, and adding @trusted had no effect.

Meanwhile, in Rust:

static mut b: Vec<*mut i32> = Vec::new();

fn bad() {
     let mut a = 0;
     unsafe { b.push(&mut a as *mut i32) };
}

fn main() {
     bad();
     println!("{:?}", unsafe { &b });
}

which outputs (for a particular run): [0x7ffc6e4b23b8]

So you have to say "trust me" a couple of times (or more than
twice, if you count the muts and the cast), but you *can* say
that. You can faithfully implement this bug in Rust.

Part of why you can do that, is that this code is using
pointers. The same code with only references fails despite the
unsafe{} blocks:

5 |     unsafe { b.push(&mut a) };
   |              -------^^^^^^-
   |              |      |
   |              |      borrowed value does not live long enough
   |              argument requires that `a` is borrowed for 
`'static`
6 | }
   | - `a` dropped here while still borrowed

Pointers in Rust lack safety and liveness guarantees. That
stuff is for references. D has references too...

| Rust     | D             |
|----------+---------------|
| &i32     | const ref int |
| &mut i32 | ref int       |
| *i32     | const(int)*   |
| *mut i32 | int*          |

... but not really. You can't declare them ("only parameters or
foreach declarations can be ref"), and you can't take a
reference of a variable, and you can't cast a pointer to a ref.

So it's not enough to say "Rust has normal vs. unsafe{} code,
and D has @safe vs. normal code, and the difference is only a
matter of defaults." It's also the case that Rust has unsafe
pointers and safe references, but D only has pointers, so any
memory protection that D gets must fall on its pointers.

With @live the protection only applies to pointers within
@safe code, and with @safe-as-default it might be even easier
to do things that way, or even to remove protections that
formerly applied to @system code. So the trend is not
necessarily towards it one day being more appropriate to say
that Rust has pointers and references, but D only has
references which it calls pointers.



More information about the Digitalmars-d mailing list