Skip to content

passing self referential struct by value creates strong protector #3456

Closed
@leddoo

Description

@leddoo

i have a self referential Builder.
something like this:

struct Builder {
    data: Vec<u8>,
    // points into `data`, only used internally.
    some_slice: &'static [u8],
}

impl Builder {
    fn new(data: &[u8]) -> Builder {
        let data = Vec::from(data);

        let some_slice = unsafe {
            let the_slice = &data[0..4];
            core::mem::transmute::<&[u8], &[u8]>(the_slice)
        };

        return Builder { data, some_slice };
    }

    fn build(self) {
        drop(self.data);
    }
}

fn main() {
    Builder::new(b"1234hello").build();
}

(the real thing uses a bump allocator and some_slice is a "leaked" allocation in that allocator)

the problem is, dropping self.data in build triggers undefined behavior:

error: Undefined Behavior: not granting access to tag <3378> because that would remove [SharedRead
Only for <3599>] which is strongly protected because it is an argument of call 865
   --> /Users/leddoo/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/
core/src/ptr/mod.rs:514:1
    |
514 | pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag <3378> be
cause that would remove [SharedReadOnly for <3599>] which is strongly protected because it is an a
rgument of call 865
    |
help: <3378> was created here, as the base tag for alloc1476
   --> src/main.rs:9:20
    |
9   |         let data = Vec::from(data);
    |                    ^^^^^^^^^^^^^^^
help: <3599> is this argument
   --> src/main.rs:20:14
    |
20  |     fn build(this: Self) {

(in the real code, build returns a Result, and on error, the bump allocator is dropped, while "some_slice" protects the bump allocator's memory)

i've read stacked borrows section 4.1, so i know what's going on.
best thing i've come up with so far would be an UnprotectedRefs wrapper type, that just tells miri to not create stack protectors for references contained in that wrapper (and tells the compiler to not rely on those references being valid for the duration of the call).

right now, the only workaround i've found is boxing that slice, which isn't ideal.

is there anything like UnprotectedRefs or a different workaround on stable right now?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions