Stream: t-lang/wg-unsafe-code-guidelines

Topic: AddressOf and stacked borrows


Matthew Jasper (Mar 11 2019 at 20:49, on Zulip):

@RalfJ I got MIRI's tests running on my branch for this and this case came up:

let mut x = 12;
let x = &mut x;

&*x; // Stack is frozen

let raw = x as *mut i32; // A - No longer creates a temporary `&mut i32`
unsafe { *raw = 42; }

Since the stack is frozen, A doesn't modify the stack, as such the last write isn't valid. Have you considered this already?

RalfJ (Mar 12 2019 at 20:03, on Zulip):

reborrows like &mut *x are accesses currently, even without the retagging

RalfJ (Mar 12 2019 at 20:03, on Zulip):

so I guess we want something similar for reborrows-to-raw

RalfJ (Mar 12 2019 at 20:06, on Zulip):

but, hm making them a write access is not nice... the entire point is that they can be dangling after all

RalfJ (Mar 12 2019 at 20:06, on Zulip):

they certainly must unfreeze though, as your example shows

RalfJ (Mar 12 2019 at 20:08, on Zulip):

maybe it should depend on the src ptr? like, when you come from a raw ptr to nothing, but when you come from a Uniq then pretend a write happened?

RalfJ (Mar 12 2019 at 20:10, on Zulip):

so here's something interesting: I always said that *mut and *const are entirely identical. but then creating a *const would also hev to unfreeze. but the following is safe today:

let mut x = 12;
let x = &mut x;

let shr = &*x; // Stack is frozen

let raw = x as *const i32; // Stack gets unfrozen?

let _val = *shr; // but then this is UB
RalfJ (Mar 12 2019 at 20:12, on Zulip):

so seems loke the two raw ptr types are not identical after all? and creating a *const from an &mut is more like turning it into a shared reference first? but that would make this UB:

let mut x = 12;
let x = &mut x;

&*x; // Stack is frozen
let raw = x as *const i32; // Stack remains frozen?
unsafe { *(raw as *mut i32) = 2; }
RalfJ (Mar 12 2019 at 20:14, on Zulip):

so it would matter if you turn an &mut into a mutable or constant raw ptr

RalfJ (Mar 12 2019 at 20:15, on Zulip):

I mean, it matters for the borrow checker, so maybe this makes sense. but I told people the oppose for so long^^
@Taylor Cramer you mentioned mutating through const raw ptrs is common in your codebase, how does that code usually look like?

Taylor Cramer (Mar 12 2019 at 20:44, on Zulip):

mutating through const raw ptrs is common in your codebase

sorry, I'm not sure what you're referring to

Taylor Cramer (Mar 12 2019 at 20:46, on Zulip):

I know there are lots of places that aren't careful about whether or not they use *const or *mut

Taylor Cramer (Mar 12 2019 at 20:46, on Zulip):

but it's basically always in the context of FFI

RalfJ (Mar 13 2019 at 08:30, on Zulip):

@Taylor Cramer are there places where you do x as *const Foo and then later mutate through that pointer? So it's less about the type on the FFI function but about the type at the cast -- but of course if this is a coercion, the cats type is informed by the function type.

Taylor Cramer (Mar 14 2019 at 16:30, on Zulip):

@RalfJ I'd imagine there are, yes

Taylor Cramer (Mar 14 2019 at 16:31, on Zulip):

@RalfJ I don't think it'd be unreasonable to ask for those to be changed, but historically I'd always thought that *const and *mut were "just a lint"

RalfJ (Mar 14 2019 at 16:36, on Zulip):

historically I'd always thought that *const and *mut were "just a lint"

same here

RalfJ (Mar 14 2019 at 16:36, on Zulip):

but also I dont see another way to handle @Matthew Jasper's example

RalfJ (Mar 14 2019 at 16:36, on Zulip):

and also I did not know that the borrow checker treats them differently

RalfJ (Mar 14 2019 at 16:37, on Zulip):

x as *const T is borrow-checked like &*x and hence allows outstanding shared loans

Matthew Jasper (Mar 14 2019 at 16:47, on Zulip):

Well, it can be modelled with some of the ideas for 2 phase borrows. :grinning_face_with_smiling_eyes:

RalfJ (Mar 14 2019 at 16:48, on Zulip):

uh... you want raw borrows to be two-phase?

Matthew Jasper (Apr 19 2019 at 07:56, on Zulip):

@RalfJ I've tried the new version of stacked borrows on the AddressOf branch and ran into the following issue:

let mut x = 0;
let m = &raw mut x; // The branch is still using the adjusted type, rather than syntax, but you get the idea
let c = &raw const x;

The stack after each line is [U], [U, SRW], [U, SRO, SRW] -> bug. It's not entirely clear to me what the correct thing to do here is. Currently &x as *const _ invalidates the mutable pointer, but that doesn't really seem desirable.

RalfJ (Apr 19 2019 at 11:49, on Zulip):

I think the fix is to never make SRO borrows "weak"

RalfJ (Apr 19 2019 at 11:49, on Zulip):

that just doesn't work very well

RalfJ (Apr 30 2019 at 18:03, on Zulip):

@Matthew Jasper https://github.com/rust-lang/miri/pull/718 should help with this.

RalfJ (Apr 30 2019 at 19:14, on Zulip):

Also, the blog post about the new Stacked Borrows is finally done: https://internals.rust-lang.org/t/stacked-borrows-2/9951

Last update: Nov 20 2019 at 12:55UTC