Skip to content

Clarify semantics of wrapping_offset when leaving object bounds #45719

Closed
@RalfJung

Description

@RalfJung

The documentation of wrapping_offset should clarify whether it is legal to use this function to move from one object to another. Concretely, is the following a "safe" function in the sense that it is safe to call by any safe client?

fn is_this_safe(x: &mut i32, y: &mut i32) {
    let x_ptr = x as *mut _; drop({x});
    let y_ptr = y as *mut _; drop({y});
    let diff  = x_ptr.offset_to(y_ptr).unwrap();
    let x_alias = x_ptr.wrapping_offset(diff);
    unsafe { *x_alias = 42; }
}

(The funny drop just make sure that the original x and y are gone, side-stepping some memory model questions.)

I see two possible options:

  • We say this is safe. Then we have to change the implementation of wrapping_offset; currently, it compiles to a getelementptr which (even without inbounds) is documented to possibly return a pointer that cannot be dereferenced even if it is equal to a valid pointer. The intention behind this is probably for getelementptr to preserve aliasing information. As a consequence, getelementptr cannot cross object boundaries.
  • We say this is not safe. Then the documentation of wrapping_offset should get a big fat warning saying so.

Given that wrapping_offset is a safe function, I think I would prefer the least surprising option, which is to make this safe. One possible implementation would be to cast the pointer to an integer, do the arithmetic there, and cast back.

Cc @eddyb @arielb1 @gankro

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-enhancementCategory: An issue proposing an enhancement or a PR with one.T-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions