Skip to content

Functions called by a may_dangle Drop impl #283

Open
@dtolnay

Description

@dtolnay

Roughly speaking, #[may_dangle] on a generic parameter in an unsafe Drop impl promises that the drop behavior does not interact with data of that type other than possibly by dropping it.

To what extent does this restrict the Drop impl from delegating to other functions that are not annotated with #[may_dangle]?

Canonical example:

#![feature(dropck_eyepatch)]

struct Struct<'a> {
    field: &'a u8,
}

unsafe impl<#[may_dangle] 'a> Drop for Struct<'a> {
    fn drop(&mut self) {
        // may_dangle promises that we do not do the following during the course of Drop:
        // println!("{}", *self.field);

        self.no_read_field(); // is this UB?
    }
}

impl<'a> Struct<'a> {
    fn no_read_field(&self) -> usize {
        // DO NOT: println!("{}", *self.field);
        std::mem::size_of::<Self>()
    }
}

fn main() {
    fn f<'a>(s: &'a mut Struct<'a>) -> Struct<'a> {
        Struct { field: s.field }
    }
    let mut s = Struct { field: &0 };
    f(&mut s); // borrowed value does not live long enough without may_dangle
}

Such code appears to be widespread among uses of #[may_dangle] in the standard library and ecosystem.

My concern is that if inside of no_read_field we have a reference/pointer that is understood to be dereferenceable by the compiler backend as insinuated by #77, in theory the backend would be free to insert a spurious read of *self.field into no_read_field if it so desires. During a Drop in which 'a is already dangling, that seems "bad".

Is it necessary for no_read_field to understand 'a to be may_dangle as well?—

unsafe impl<#[may_dangle] 'a> Struct<'a> {
    fn no_read_field(&self) -> usize {
        // DO NOT: println!("{}", *self.field);
        std::mem::size_of::<Self>()
    }
}

Real world instance from standard library code:

If you imagine a spurious read of that T (suppose T=&u8) inside pop_front_node this is analogous to the example above.

I found vaguely related discussions at #84 and #268 but this seems to me a pretty different case that I haven't found discussed. The salient example in both of those other issues is along the lines of #268 (comment) where a value somewhere contains an invalid bit pattern for its type, whereas the current issue involving may_dangle is an issue even if that never happens.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-dropTopic: related to dropping

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions