Raw pointer field projection

If you have a raw pointer to a struct like *mut Range<_>, such as one might obtain from MaybeUininit::<Range<_>>::as_mut_ptr then we incur an unsafe operations when projecting from the raw pointer to a field:

unsafe fn partial_default(self: &mut MaybeUninit<Self>) {
    let self = self.as_mut_ptr();
    let start = 0;
    let start_ptr = unsafe { &mut (*self).start as *mut T };  // Maybe avoidable unsafe?
    unsafe { core::ptr::write(start_ptr,start) };  // Unavoidable unsafe

Are there proc macro that facilitate this? Should rustc provide an easier method somehow? Could self.start be given type *mut T here? Or is projection too risky somehow?

I noticed this in one of the optional fields discussions.

Can't help you with avoiding unsafe, but I have some criticisms of the code you wrote here.

let self = unsafe { self.assume_init_mut() }


Calling this when the content is not yet fully initialized causes undefined behavior

unsafe { &mut (*self).start as *mut T };

There's a better way to do this now, with std:::ptr::addr_of_mut. That line of code you wrote could be UB for uninitialized fields, I don't know if that's been decided yet.

I contributed some docs for how to initialize a MaybeUninit<Struct> in the Initializing a struct field-by-field section


Can't you use this instead?

use core::mem::MaybeUninit;

pub struct Range {
	pub start: i32

pub unsafe fn partial_default(this: &mut MaybeUninit<Range>) {
    let this = unsafe { &mut *this.assume_init_mut() };
    let start = 0;
    let start_ptr = &mut this.start;
    *start_ptr = start;

I made a copy-paste error from the other discussion, oops. Avoiding assume_init_mut is actually the point.

I'd missed that even *self breaks, not sure if it breaks Drop. Yes, addr_of_mut heads the right direction, thanks!

See also: Need for -> operator for Unsafe Code Guidelines

1 Like