Skip to content

When are references allowed to be deallocated while a function they were passed to runs? #433

Open
@RalfJung

Description

@RalfJung

Generally, this is UB:

fn f(x: &i32) {
  cause_x_to_be_deallocated();
}

This lets us use the dereferenceable attribute of LLVM, which means "dereferenceable for the entire duration this function runs". That is quite useful for e.g. hoisting memory accesses out of a loop without having to figure out if some other operation deallocated x.

However, we have an exception to that rule: if x is a reference to UnsafeCell<T> (or a newtype around that), then the memory is allowed to be deallocated while the function runs. (The reference must still be dereferenceable when the function starts.) This was done to resolve rust-lang/rust#55005; the PR that manifested this change is rust-lang/rust#98017.

IMO this was absolutely required; without a change like this, Atomic*::compare_exchange cannot be used as a signal to another thread "you may now free this memory". We would need to provide raw pointer alternatives to even implement something like Arc. However @JakobDegen indicated they disagree so this is part 1 of the issue tracked here. (Though I will note that this will be hard to take back since it has been FCP'd and documented.)

Part 2 is the problem that there are still footguns: with a type like

struct S {
  b: AtomicBool,
  i: AtomicUsize,
}

if we have a method on &S that sets a flag to indicate "this can be deallocated", we still have UB. This is because there is padding, and the rules say only memory inside the UnsafeCell is allowed to be deallocated.

There are a bunch of options here. Just to list a few:

  • Accept the current rules and tell people to use raw pointers instead.
  • Follow Tree Borrows and just don't care about where in a type the UnsafeCell lives ever (Cc Stacked Borrows: How precise should UnsafeCell be tracked? #236). Even if we track UnsafeCell precisely for mutation, we could say that deallocation is allowed the moment T: !Freeze.
  • Somehow treat padding that is adjacent to an UnsafeCell as also being inside the UnsafeCell.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-aliasing-modelTopic: Related to the aliasing model (e.g. Stacked/Tree Borrows)

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions