Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Will destructors create &mut references only when Drop::drop() is called? #542

Open
theemathas opened this issue Oct 30, 2024 · 2 comments

Comments

@theemathas
Copy link

Consider this code, which implements a construct similar to Arc, but points to the stack, and will abort the program if you try to deallocate the backing allocation while there are still outstanding references.

The parts of the code that is relevant to the question is as follows:

struct StorageGuard {
    // omitted
}

struct StorageInner<T> {
    data: T,
    // omitted
    _phantom: PhantomPinned,
}

pub struct Storage<T> {
    guard: StorageGuard,
    inner: StorageInner<T>,
}

impl Drop for StorageGuard {
    // omitted
}

The Storage type has public methods that effectively hands out &T references to the data inside, but with an unbound lifetime. To make this sound, the Drop impl of StorageGuard checks whether there are any outstanding references to the data, and will abort the program if there are.

The destructor of Storage<T> consists of two steps:

  1. Call <StorageGuard as Drop>::drop().
  2. Call <T as Drop>::drop().

Note that step 1 checks whether there are any &T references, and step 2 creates a &mut T that would potentially alias with any such references. Therefore, this unsafe code assumes that the &mut T is only created on step 2. Note that &mut Storage<T> is never created, since Storage doesn't implement Drop.

Is it OK for unsafe code to assume that the destructor will never create any &mut T references until the point where Drop::drop is called?

@theemathas theemathas changed the title Will destructors only create &mut references when Drop is implemented? Will destructors create &mut references only when Drop::drop() is called? Oct 30, 2024
@RalfJung
Copy link
Member

Is it OK for unsafe code to assume that the destructor will never create any &mut T references until the point where Drop::drop is called?

IIRC, drop_in_place acts like it basically takes an &mut argument. So, the answer to your question is "no".

@RalfJung
Copy link
Member

Also see #373

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants