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

Topic: stacked-borrows


RalfJ (Aug 09 2018 at 09:31, on Zulip):

An interesting question: https://www.reddit.com/r/rust/comments/95f4xi/stacked_borrows_an_aliasing_model_for_rust/e3u0749/?context=3

RalfJ (Aug 09 2018 at 09:31, on Zulip):

@nikomatsakis are there still plans to change MIR to not allow "nested path expressions" like a.b.c.d or (*a.f).f2?

nikomatsakis (Aug 09 2018 at 10:03, on Zulip):

vague plans, yes

nikomatsakis (Aug 09 2018 at 10:03, on Zulip):

no action has been taken

RalfJ (Aug 09 2018 at 10:09, on Zulip):

At least when it comes to nested fields, I am not convinced any more that we want that. would still be nice to have for deref, though.

RalfJ (Aug 09 2018 at 10:10, on Zulip):

or at least, if we do this even for field accesses, that should probably mean that when accessing t.b we actually activate all of t

nikomatsakis (Aug 09 2018 at 10:13, on Zulip):

I envision these being a special sort of operation -- sort of like GEP in LLVM -- that ends with some kind of "bless" operation

nikomatsakis (Aug 09 2018 at 10:13, on Zulip):

that indicates the final path the user wrote

nikomatsakis (Aug 09 2018 at 10:13, on Zulip):

it seems like that would be important to the borrowck

nikomatsakis (Aug 09 2018 at 10:13, on Zulip):

in particular we need to be able to permit access to disjoint fields

nikomatsakis (Aug 09 2018 at 10:14, on Zulip):

e.g.

let x: &mut (u32, u32);
let y = &mut (*x).0;
let z = &mut (*x).1;
RalfJ (Aug 09 2018 at 10:22, on Zulip):

hm, yeah

nikomatsakis (Aug 09 2018 at 10:23, on Zulip):

so point is I could imagine that the "GEP" part of it somehow has less validation?

nikomatsakis (Aug 09 2018 at 10:24, on Zulip):

that was an interesting question though (the one from reddit)

nikomatsakis (Aug 09 2018 at 10:24, on Zulip):

I feel like the "tagging" question also comes into play?

nikomatsakis (Aug 09 2018 at 10:25, on Zulip):

e.g., does let t = &*s; retag the data in s? oh, well, I guess there are no references in there

RalfJ (Aug 09 2018 at 10:31, on Zulip):

no this doesn't load anything from memory, no retagging

RalfJ (Aug 09 2018 at 10:31, on Zulip):

but of course a new ref is created, which gets a fresh tag

nikomatsakis (Aug 09 2018 at 10:38, on Zulip):

I see

RalfJ (Aug 13 2018 at 21:36, on Zulip):

@alercah

    pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
        let len = self.len();
        let ptr = self.as_mut_ptr(); // here a Raw gets pushed onto the stack for the entire slice

        unsafe {
            assert!(mid <= len);

            (from_raw_parts_mut(ptr, mid), // now the first half of the slice has a new Uniq pushed
             from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) // and now the second part follows suit
           // using `self` again here would be possible, but that would invalidate the two `from_raw_parts`! I.e., if you returned
           // them (which activates references), that would be UB. But since `self` is not used again, this code is fine.
        }
    }
RalfJ (Aug 13 2018 at 23:01, on Zulip):

@alercah (if you click my message before replying, your reply should go to the right topic. we should try not to be too much off-topic in the exhaustiveness discussion.)
How would it create the subslices without calling from_raw_parts_mut?

alercah (Aug 21 2018 at 11:29, on Zulip):

Ah, I forgot I replied to this but I didn't. It would require different aliasing rules.

RalfJ (Oct 17 2018 at 13:19, on Zulip):

Got a first implementation of stacked borrows (without barriers or retagging). That went much smoother than I expected :D

Jake Goulding (Oct 17 2018 at 13:20, on Zulip):

"implementation" in... what?

RalfJ (Oct 17 2018 at 13:25, on Zulip):

@Jake Goulding in miri

RalfJ (Oct 17 2018 at 13:25, on Zulip):

ah dang, not seeing some of the errors I was expecting though

RalfJ (Oct 17 2018 at 13:25, on Zulip):

something is not being tracked enough

RalfJ (Oct 17 2018 at 13:30, on Zulip):

@nikomatsakis

ps is there stacked borrow code I can review?

https://github.com/RalfJung/miri/commits/stacked-borrows

RalfJ (Oct 17 2018 at 13:30, on Zulip):

and https://github.com/rust-lang/rust/pull/55125

nikomatsakis (Oct 17 2018 at 13:37, on Zulip):

@RalfJ <3 thanks!

RalfJ (Oct 17 2018 at 13:38, on Zulip):

ah dang... we optimize away &*x to just x even when they don't have the same type, I forgot about that

nikomatsakis (Oct 17 2018 at 13:38, on Zulip):

are those overlapping?

nikomatsakis (Oct 17 2018 at 13:38, on Zulip):

that is, if I review #55125, does that suffice?

RalfJ (Oct 17 2018 at 13:38, on Zulip):

namely we do that even when x is a mutable ref and we are turning it into a shared ref

RalfJ (Oct 17 2018 at 13:38, on Zulip):

so there is no Ref left for me to hook...

nikomatsakis (Oct 17 2018 at 13:38, on Zulip):

interesting

RalfJ (Oct 17 2018 at 13:38, on Zulip):

I knew that. and forgot.^^

RalfJ (Oct 17 2018 at 13:38, on Zulip):

@nikomatsakis one is the rustc changes and the other is the miri changes. no overlap.

RalfJ (Oct 17 2018 at 13:39, on Zulip):

dang that makes things much harder

RalfJ (Oct 17 2018 at 13:39, on Zulip):

basically we are transmuting &mut to & all the time, even if the original source didn't

nikomatsakis (Oct 17 2018 at 13:42, on Zulip):

I think it's "ok" to remove that, or at least only do it if validation is disabled or something.. but I guess that's annoying because libstd?

nikomatsakis (Oct 17 2018 at 13:43, on Zulip):

that is, it is not clearly a "valid" optimization for us to be doing

RalfJ (Oct 17 2018 at 13:43, on Zulip):

well depends. people have been asking for more details on transmutes anyway

RalfJ (Oct 17 2018 at 13:44, on Zulip):

I just hoped I could get a basic model working that just looks at &, *, casts and memory accesses

RalfJ (Oct 17 2018 at 13:44, on Zulip):

no retagging, no recursing over the types

RalfJ (Oct 17 2018 at 13:45, on Zulip):

and, well, it works with -Zmir-opt-level=0^^

nikomatsakis (Oct 17 2018 at 13:45, on Zulip):

well depends. people have been asking for more details on transmutes anyway

confirm

nikomatsakis (Oct 17 2018 at 13:45, on Zulip):

I guess if transmutes are "silent"

RalfJ (Oct 17 2018 at 13:45, on Zulip):

what should I confirm?

nikomatsakis (Oct 17 2018 at 13:45, on Zulip):

sorry, that means "I agree, you are correct" :)

RalfJ (Oct 17 2018 at 13:46, on Zulip):

oh. I thought it was an imperative. ^^

RalfJ (Oct 17 2018 at 13:59, on Zulip):

well back on topic though, I'll work with mir-opt-level=0 for now

RalfJ (Oct 17 2018 at 14:00, on Zulip):

retagging is annoying because it has to happen after every... well not sure after every what. every assignment, likely? plus fn calls and return?

RalfJ (Oct 17 2018 at 14:00, on Zulip):

it has some logic that's similar to validation

RalfJ (Oct 17 2018 at 14:00, on Zulip):

but unlike validation it needs to be able to actually mutate stuff, validation works on operands that you cannot mutate

RalfJ (Oct 17 2018 at 14:01, on Zulip):

so all in all, not nice

RalfJ (Oct 17 2018 at 14:01, on Zulip):

oh wait someone siwtched the topic

RalfJ (Oct 17 2018 at 14:01, on Zulip):

when did that happen^^

nikomatsakis (Oct 17 2018 at 14:01, on Zulip):

heh that was me :P

nikomatsakis (Oct 17 2018 at 14:01, on Zulip):

you can change it back quite easily

RalfJ (Oct 17 2018 at 14:02, on Zulip):

for just my msgs?

nikomatsakis (Oct 17 2018 at 14:02, on Zulip):

just click the "edit" next to your msg

nikomatsakis (Oct 17 2018 at 14:02, on Zulip):

and you can select "this message and all ones after it"

nikomatsakis (Oct 17 2018 at 14:02, on Zulip):

yes

RalfJ (Oct 17 2018 at 14:02, on Zulip):

wow technology

RalfJ (Oct 17 2018 at 14:02, on Zulip):

no autocompletion for the topic name though

RalfJ (Oct 19 2018 at 12:43, on Zulip):

@nikomatsakis I just realized (seems rather obvious now) that optimizing away x as *const _ to just a transmute is not legal. we do want to rule out using raw ptrs to access locations that never got "leaked" by being cast to raw. So I will assume that such optimizations don't happen. (I think currently they don't, but who knows which ideas people have.)

RalfJ (Oct 19 2018 at 12:44, on Zulip):

that leaves optimizing away &[mut] *x, where x might be a ref or a raw ptr -- but at least the output of the transmutes we want to support are restricted to references.

nikomatsakis (Oct 19 2018 at 12:45, on Zulip):

@RalfJ makes sense

RalfJ (Oct 19 2018 at 14:45, on Zulip):

also, at least the way I have implemented this now, &mut's validaity invariant actually says that the tag must be a Uniq. everything else is insta-UB. That makes some things simpler...

RalfJ (Oct 19 2018 at 14:57, on Zulip):

actually it can also be a Raw, which pretty much behaves like a raw ref... it's not really unique. but that seems okay; for unique refs we didnt retag we also cannot know if their tag is really unique.

RalfJ (Oct 19 2018 at 14:57, on Zulip):

an &mut with a Frz tag however is insta-UB, for now.

RalfJ (Oct 19 2018 at 16:42, on Zulip):

@nikomatsakis I have a rather surprising case: https://github.com/RalfJung/miri/blob/stacked-borrows/tests/compile-fail/stacked_borrows/illegal_write4.rs
I really want this to fail earlier, but cannot find a way to make that happen without breaking code we probably want to allow.

RalfJ (Oct 22 2018 at 16:11, on Zulip):

@nikomatsakis here's another interesting problem: Doing &slice[0] as *const _ only leaks the first element of the slice to a raw pointer, so you cannot access the other elements even after you did that...

rkruppe (Oct 22 2018 at 16:21, on Zulip):

oh, that's an interesting reason to prefer as_ptr

nikomatsakis (Oct 22 2018 at 16:27, on Zulip):

@RalfJ regarding your first example: do you have a sense of where you want it to fail? It seems like pursuing transmute is having the effect that creating references becomes far less significant until they are used...does that seem accurate?

RalfJ (Oct 22 2018 at 16:36, on Zulip):

oh, that's an interesting reason to prefer as_ptr

only that as_ptr would be to be a primitive MIR operation to make this actually work

RalfJ (Oct 22 2018 at 16:41, on Zulip):

@RalfJ regarding your first example: do you have a sense of where you want it to fail? It seems like pursuing transmute is having the effect that creating references becomes far less significant until they are used...does that seem accurate?

I had hoped that and use of an &mut would give you basically that it is still exercising its exclusive access. And we could maybe still get there but we'd have to say that a non-exclusively-reborrowed &mut T is allowed to point only to memory with its tag being the top of the stack, ignoring freezing and barriers. Currently, we check if it is anywhere on the stack, i.e., we check if reactivating it would be possible at all.

Nicole Mazzuca (Oct 22 2018 at 16:44, on Zulip):

only that as_ptr would be to be a primitive MIR operation to make this actually work

Not necessarily - &[T] as *const [T] as *const T should work.

RalfJ (Oct 22 2018 at 16:44, on Zulip):

actually what I said above is wrong, we have to also allow an &mut pointing to sth that is currently raw because if there is interior mutability, that#s what happens

RalfJ (Oct 22 2018 at 16:44, on Zulip):

@Nicole Mazzuca good point! I'll try that immediately.

RalfJ (Oct 22 2018 at 16:51, on Zulip):

@Nicole Mazzuca this actually works :-)

Nicole Mazzuca (Oct 22 2018 at 17:14, on Zulip):

good! I'd hope so :P

Last update: Nov 19 2019 at 17:35UTC