Skip to content
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

What are the exact semantics of pointer comparison? #239

Closed
RalfJung opened this issue Jun 17, 2020 · 7 comments
Closed

What are the exact semantics of pointer comparison? #239

RalfJung opened this issue Jun 17, 2020 · 7 comments
Labels
A-provenance Topic: Related to when which values have which provenance (but not which alias restrictions follow) A-ptr-eq Topic: pointer equality C-open-question Category: An open question that we should revisit

Comments

@RalfJung
Copy link
Member

RalfJung commented Jun 17, 2020

Pointer comparison is complicated. However, for better or worse, Rust lets you safely compare any raw pointers, so we need to assign this some reasonable semantics. I wanted a place to centrally track all questions related to this, so here we go. (I never know whether to open such issues here in the UCG repo, or over in the rustc repo.)

There are two ways in which pointer comparison is "interesting": provenance, and objects without a guaranteed stable address.

Provenance

Does provenance affect whether pointers are equal? One major concern here is figuring out the semantics of pointer comparison in LLVM, and then likely we have no choice but to inherit that. Some data points:

  • Eli Friedman writes

    icmp is defined to just take the raw pointer bits as an integer. This is described in LangRef. If the text of LangRef describing icmp isn't sufficiently clear, suggestions welcome. If some transform isn't consistent with this, please file a bug.

  • In our LLVM semantics paper, we made pointer comparison non-deterministic under some conditions (when the addresses are equal but provenance differs), so that pointers derived from different calls to malloc can always compare inequal even if they are physically equal. This directly contradicts Eli's statement above.

I am trying to figure out if LLVM optimizations clearly indicate one or the other choice; so far that has been inconclusive.

Unstable objects

Functions, vtables, and consts do not have a unique stable address, also leading to interesting problems.

function address equality

vtable equality

const address equality

@RalfJung RalfJung added C-open-question Category: An open question that we should revisit A-provenance Topic: Related to when which values have which provenance (but not which alias restrictions follow) labels Jun 17, 2020
@RalfJung
Copy link
Member Author

This is a somewhat interesting example:

extern crate libc;
use std::mem;
pub fn test(ext: bool) -> bool { unsafe {
    let x = libc::malloc(mem::size_of::<i32>()) as *mut i32;
    *x = 0;
    if ext { libc::free(x as *mut _); }
    let y = libc::malloc(mem::size_of::<i32>()) as *mut i32;
    *y = 0;
    return x == y;
} }

It gets optimized to return false, so this looks a bit like ptr comparison does not look at the actual address, since ptr reuse could have happened. But then, ptr reuse also could have not happened, and LLVM assumes that the allocator itself is not observable. (I don't know if it assumes that just for malloc or also for e.g. custom Rust allocators. In case of the latter, that would be an interesting and so far undocumented piece of possible UB.) So arguably, even under the strict "compare int addresses", this optimization is correct.

@RalfJung
Copy link
Member Author

Also see this LLVM bug.

@tmiasko
Copy link

tmiasko commented Jul 10, 2020

The optimization from #239 (comment) is based on the assumption that LLVM is allowed to substitute its own allocation function and guarantee particular outcome of the comparison.

Those kind of optimizations are also applicable to Rust allocation functions, since rustc explicitly opt ins for this behaviour for rust_alloc, rust_dealloc and rust_realloc.

@RalfJung
Copy link
Member Author

Right. But it is unclear to me howto actually make that formally precise. Like, how could we implement support for custom allocators in Miri in a way that it detects UB when the allocator works in a way that breaks the above optimization?

@RalfJung
Copy link
Member Author

RalfJung commented Aug 8, 2020

I updated the OP to also link to various issues about function pointer and vtable equality.

@RalfJung
Copy link
Member Author

I entirely forgot that const are another example of objects without stable addresses; that can lead to some interesting effects as well.

@RalfJung
Copy link
Member Author

RalfJung commented Aug 4, 2024

I think the interactions with provenance are largely clear at this point -- provenance does not affect comparison (except maybe as part of the resolution to #328).
I opened #522 to track the question of what we guarantee about the pointer identity of compile-time-created objects.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-provenance Topic: Related to when which values have which provenance (but not which alias restrictions follow) A-ptr-eq Topic: pointer equality C-open-question Category: An open question that we should revisit
Projects
None yet
Development

No branches or pull requests

2 participants