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

Topic: stacked borrows and data races


bjorn3 (Mar 31 2020 at 16:34, on Zulip):

Copying the discussion at #70598 here to discuss further:

@vakeras asked on github:

By the way, do stacked borrows rule out data-races except on UnsafeCell?

@bjorn3 responded:

With raw pointers it is possible to create data-races even with stacked borrows.

@RalfJ responded:

If you also exclude raw pointers (as pointed out by @bjorn3), I think so, but have not formally proven it.

@bjorn3 responded:

@RalfJung I may be wrong with my understanding of stacked borrows, but I don't think stacked borrows rules out data races:

```rust
fn main() {
// First create a mutable reference to some memory.
let ref1: &'static /0/ mut u8 = Box::leak(Box::new(42u8));
// alloc0: Unique(0)

// Then derive a new mutable reference from the previous reference without borrowck knowing about it.
// alloc0: Unique(0)
let ref2: &'static /*1*/ mut u8 = unsafe { std::mem::transmute::<&'_ mut u8, &'static mut u8>(&mut *ref1) };
// alloc0: Unique(0) Unique(1)

// Next write using one of the references from a new thread.
std::thread::spawn(move || {
    // alloc0: Unique(0) Unique(1)
    *ref2 = 0;
    // alloc0: Unique(0) Unique(1)
});

// Ensure the new thread runs first, so `Unique(1)` doesn't get popped before the new thread runs.
std::thread::sleep_ms(10);

// Finally write using the other reference in the current thread.
// Both writes happened without synchronization, so this is a data race.
// alloc0: Unique(0) Unique(1)
*ref1 = 1;
// alloc0: Unique(0)
println!("{}", ref1);

}
```

@RalfJ Finally responded:

@bjorn3 this is getting off-topic, but this is still UB as the first thread might take longer than 10ms to spawn. So the execution where *ref1 = 1 happens first is still possible, and then *ref2 = 0 fails because the item is not on the stack any more.

Let's continue this elsewhere though.

bjorn3 (Mar 31 2020 at 16:41, on Zulip):

@RalfJ I guess you are right. I can't think of a way to never pop the item before it is used in the other thread without synchronization.

comex (Mar 31 2020 at 23:06, on Zulip):

You can do it using a relaxed atomic, which communicates information from one thread to another without fully synchronizing them.

RalfJ (Apr 01 2020 at 07:20, on Zulip):

I am not sure if being able to communicate information is sufficient for the race, though

Last update: Jun 05 2020 at 23:00UTC