Skip to content

LLVM integer/pointer casts are unreliable and observably disagree with the intended Rust semantics #507

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

Open
joboet opened this issue Apr 21, 2024 · 2 comments

Comments

@joboet
Copy link
Member

joboet commented Apr 21, 2024

Per miri's (temporary) "wildcard"-provenance model, this code is considered sound (playground):

fn roundtrip(a: &mut i32) {
    let addr = <*mut i32>::expose_provenance(a);
    let zero = addr - addr;
    let ptr = std::ptr::with_exposed_provenance_mut::<i32>(zero).wrapping_byte_add(addr);
    unsafe { *ptr = 42; }
}

However, LLVM folds the with_exposed_provenance_mut call to null and thus creates undefined behaviour.

Personally, I'd argue that this should be considered an LLVM bug: the LangRef states that:

A pointer value formed by an inttoptr is based on all pointer values that contribute (directly or indirectly) to the computation of the pointer’s value.

though this contradicts with:

A null pointer in the default address-space is associated with no address.

However, I'm filing this here, as it seems bad that miri doesn't report this and it seems unlikely to me that LLVM would fix this, as doing so would probably result in regressions for C code doing the equivalent of map_addr.

I think this would be best fixed by:

  • Rust adopting a different model for exposed provenance (that seems unfortunate to me, having with_exposed_provenance be pure is a cool property)
  • LLVM adding intrinsics/instructions for expose_provenance and with_exposed_provenance
  • Adding something like a black_box to both expose_provenance and with_exposed_provenance that tells LLVM "this does something funky (but results in a pointer with the given address)"
@RalfJung
Copy link
Member

RalfJung commented Apr 21, 2024

LLVM has plenty of bugs around with_exposed_provenance_mut, see e.g. llvm/llvm-project#33896. They don't have a clear enough semantics to even be able to evaluate what the fix should look like -- they first need to decide how provenance interacts with the iN type, and how "exposed" works. Not sure if and how we should track that on our side.

Furthermore, if you run that program in Miri you already get a warning that you are outside the scope where Miri can reliably detect bugs (or you silenced that warning by passing -Zmiri-permissive-provenance).

Adding something like a black_box to both expose_provenance and with_exposed_provenance that tells LLVM "this does something funky (but results in a pointer with the given address)"

Yes, IMO we should do that some time after strict provenance stabilization (also for as casts between pointers and integers).

@RalfJung RalfJung changed the title miri's "wildcard"-provenance disagrees with LLVM LLVM integer/pointer casts are unreliable and observaly disagree with the intended Rust semantics Apr 21, 2024
@RalfJung RalfJung changed the title LLVM integer/pointer casts are unreliable and observaly disagree with the intended Rust semantics LLVM integer/pointer casts are unreliable and observably disagree with the intended Rust semantics Apr 21, 2024
@RalfJung
Copy link
Member

RalfJung commented Apr 21, 2024

Per miri's (temporary) "wildcard"-provenance model, this code is considered sound (playground):

Also note that wildcard provenance is not a sound model. So Miri accepting unsound code is entirely expected. That's why Miri shows a warning when your program does an int2ptr cast. So the part about Miri not showing UB for this program is entirely not-a-bug works-as-intended. There are examples of programs Miri will accept that are unambiguously UB under Rust semantics. That's why strict provenance is a thing -- to let people write code that does messy pointer things while still enabling Miri to reliably find bugs.

Wildcard provenance is a Miri-specific concept and not part of the Rust specification in any way.

However, your program does not just pass Miri, it is actually sound under the intended actual model of with_exposed_provenance_mut, the one sketched in that function's documentation. That's why this is concerning.

Rust adopting a different model for exposed provenance

Wildcard provenance is not Rust's model for exposed provenance. Rust's model for exposed provenance is describred in the with_exposed_provenance_mut docs.

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