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

Topic: Can `T: 'static` really never point to the stack?


RalfJ (May 16 2019 at 17:19, on Zulip):

See https://github.com/japaric/microamp/issues/6: we have some unsafe code that relies on T: 'static types never having stack pointers. I think this is far from obvious. Is it something we want to guarantee?

gnzlbg (May 16 2019 at 17:28, on Zulip):

We have that same problem in CUDA

gnzlbg (May 16 2019 at 17:28, on Zulip):

And the safest bet was not to use references

gnzlbg (May 16 2019 at 17:29, on Zulip):

Reference implies dereferenceable, but if you can access a static from, e.g., a different core, where addresses map to different memory, that reference is not dereferenceable

gnzlbg (May 16 2019 at 17:30, on Zulip):

AFAICT one does not need to access the reference to trigger the UB, the mere possibility of being able to access it is UB

gnzlbg (May 16 2019 at 17:31, on Zulip):

in other words, if you have a target that has "segmented" memory (e.g. where some cores can only access some memory), putting addresses to the segment into static references that can be read by code that does not have access to the segment is UB - you have to use raw pointers instead

gnzlbg (May 16 2019 at 17:38, on Zulip):

This is like being able to write code like this:

pub static mut GLOBAL: &'static u32 = rust

    // some thread:
    thread_local! {
        pub static LOCAL: u32 = 0;
    }
    LOCAL.with(|f| {
      unsafe { GLOBAL = &*(f as *const _) };
    });

    // some other thread can access GLOBAL
    // but GLOBAL is not dereferenceable from that thread

Is this UB, even if no other thread actually access GLOBAL, just from being able to access it?

RalfJ (May 16 2019 at 18:17, on Zulip):

so basically, do we have derefencable on globals? good question. I don't know.

RalfJ (May 16 2019 at 18:17, on Zulip):

but the problem here is a different one

rkruppe (May 16 2019 at 18:20, on Zulip):

There was also talk in the past about considering the locals of main to be loanable for 'static if panics abort (if it unwinds, I'm pretty sure it's unsound, but I forget the actual argument)

rkruppe (May 16 2019 at 18:22, on Zulip):

Ah no, it was functions that loop infinitely, i.e., those that diverge not because of panics but because of control flow. (https://internals.rust-lang.org/t/set-static-lifetime-for-local-variables-of-diverging-functions/9649) so basically the example Ralf gave in the issue linked at the start.

RalfJ (May 16 2019 at 18:27, on Zulip):

(and indeed my example as given is unsound with panic=unwind, but that can be fixed by moving the loop to a drop guard)

gnzlbg (May 16 2019 at 18:57, on Zulip):

@RalfJ well here you don't have globals, just whether the assumption that T: 'static implies no references to the stack or nor

gnzlbg (May 16 2019 at 18:58, on Zulip):

AFAICT it doesn't, but I don't see how that matters, because the case being considered here (segmented memory) is one that we don't support in the "references" part of the type system at all AFAICT

gnzlbg (May 16 2019 at 18:59, on Zulip):

you can create a reference to a thread stack (or its heap), and as long as that reference lives long enough, pass it to another thread

gnzlbg (May 16 2019 at 19:00, on Zulip):

if that other thread cannot dereference that address because of "reasons" (e.g. the address space associated with it is a different one), well, that's UB

gnzlbg (May 16 2019 at 19:02, on Zulip):

the unsafe code that creates that thread, and allows you to pass it non-dereferenceable references is at fault

RalfJ (May 16 2019 at 19:03, on Zulip):

well it doesnt imply no references (because it can be refs to statics). but it might imply no references to the stack.

gnzlbg (May 16 2019 at 19:04, on Zulip):

Can't you heap allocate something, create a &'static to it, and leak it ? (isn't that safe?)

RalfJ (May 16 2019 at 19:05, on Zulip):

and then its heap allocated and not stack allocated...?

gnzlbg (May 16 2019 at 19:05, on Zulip):

yeah, and then instead of a thread that cannot access some other thread stack because of "reasons", you have threads that cannot access some other thread heap because of "reasons"

gnzlbg (May 16 2019 at 19:07, on Zulip):

we could call these thread "processes", and that would be alright

gnzlbg (May 16 2019 at 19:07, on Zulip):

but it could also be the CPU heap, and a thread of execution on the GPU, which can only access the GPUs heap

RalfJ (May 21 2019 at 11:35, on Zulip):

have you read the issue I linked above? this is specifically about the stack.

gnzlbg (May 22 2019 at 15:11, on Zulip):

the stack of different threads of execution

gnzlbg (May 22 2019 at 15:13, on Zulip):

where each thread can only access its own stack

gnzlbg (May 22 2019 at 15:14, on Zulip):

i don't see how this is any different for an application where each thread has its own thread-local heap, and you can't access anything on that heap from a different thread

gnzlbg (May 22 2019 at 15:17, on Zulip):

is there anything that makes the stack here special as opposed to a thread-local variable ?

RalfJ (May 22 2019 at 20:03, on Zulip):

yes -- that in safe Rust + libstd it is not possible to get a 'static reference to the stack, while Box::leak does provide a safe way to get a 'static to the heap

RalfJ (May 22 2019 at 20:04, on Zulip):

so for the stack it seems like T: 'static successfully excludes such references

RalfJ (May 22 2019 at 20:04, on Zulip):

but I think that is an "accident" and we should not endorse such a pattern. at the same time there is clearly a need and I dont know if we have an answer.

gnzlbg (May 23 2019 at 15:48, on Zulip):

@RalfJ FYI by thread-local heap i actually mean literally that. As in, you spawn a couple of threads, and give each a thread_local! { HEAP } (what HEAP actually is does not matter much, it could be just a Box that gets destroyed when the thread joins). The API of thread-local will ensure that you can't let references into your thread-local heap escape.

gnzlbg (May 23 2019 at 15:49, on Zulip):

I think there is not much difference between using thread_local! in that way, and what Jorge is doing

gnzlbg (May 23 2019 at 15:49, on Zulip):

the issue is that the assumption that T: 'static prevents references to the stack is incorrect.

gnzlbg (May 23 2019 at 15:50, on Zulip):

while the API of thread_local! prevents letting references escape using other means

RalfJ (May 23 2019 at 15:57, on Zulip):

ah, T: 'static also "prevents" (or rather, does not) references to thread-local data

gnzlbg (May 23 2019 at 16:26, on Zulip):

I mean, if two threads run on different cores, and they can't dereference pointers to each other stack frames, then their stack frames are essentially "thread-local"

Last update: Nov 20 2019 at 11:30UTC