Lang Team Design Meeting: & and Dereferenceable

Topic

This design meeting will cover problems around `&` and the dereferenceable attribute, such as https://github.com/rust-lang/rust/issues/55005 and MMIO.

Links

  • Ref and RefCell lifetimes are a “lie”, and a similar issue with VecDeque::Drain
  • Zulip conversation about dereferenceable attributes and LLVM (link)

Agenda

  • Current behavior:
  • The meaning of the “dereferenceable” attribute in LLVM
  • we have this attribute, using it to model C++ references, but realized that it is not what people need
  • the intended semantics was vaguely “this thing will be dereferenceable through the function call”
  • but the C++ spec doesn’t say that, the function can deallocate the memory backing a T& during course of the function, it just has to be “dereferenceable initially”
  • they intend to fix this
  • there has been discussion of how best to fix, so that you can express that something is dereferenceable initially 
  • What changes are being considered in the future from LLVM’s perspective?
  • a “nofree” function indicates that it doesn’t free anything 
  • so maintains dereferenceability (if you ignore concurrency)
  • with concurrency, you have more problems (c.f. Arc)
  • a “nosync” function doesn’t “interact with other threads” (no atomic ops, no loads/stores, no synchronizes-with edges introduced)
  • “nofree” can also be put on parameters, perhaps, to indicate that data behind a particular pointer is not freed
  • dereferenceable will change to have the weaker semantics to (ret-con) compatibility
  • dereference_globally means it will never be derefered ever? maybe useful, but not for Rust
  • How do we justify “derefenceable” in stacked borrows?
  • Context: We intend to justify emitting derefenceable because of UB caused under stacked borrows. If we were going to try to stop emitting dereferenceable, we’d presumably also have to adjust stacked borrows to make the pattern not UB. Right?
  • Answer: we justify by introducing these “protectors” on entry/exit from function
  • when you push something onto the stack, there’s an optional flag to say “this is protected by that function item”
  • when you pop an item that is “protected by” a fn that is ongoing, that is UB
  • this is “per item” — i.e., per element on the “stacked borrows stack”
  • a side effect of protectors is that having two `&mut` arguments that wind up being given the same value by caller, that is UB due to adding the protectors
  • What kinds of bugs do we run into
  • thread A has an AtomicUsize, it does a decrement (and ref count reaches 1)
  • thread B does a decrement (and ref count reaches 0) and 

Quoting Ralf: “They want to define structs like…

struct MyRegisters {
  reg1: ReadOnly,
  reg2: WriteOnly,