-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Miscompilation with pointer address rountrip through address 0 #107326
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
Comments
Under the proposed provenance model for C, PNVI-ae-udi, this code contains undefined behavior, as Also for Miri, it doesn't really check int2ptr casts much and has false negatives if you use them, allowing obviously invalid code to pass. cc @RalfJung |
I found another case of this without int-to-ptr casts: (playground link) // SAFETY: The pointer must be null.
pub unsafe fn assert_null(ptr: *mut u8) -> *mut u8 {
if !ptr.is_null() {
// SAFETY: The caller guarantees that the pointer is null.
unsafe { core::hint::unreachable_unchecked() }
}
ptr
}
pub fn bad(r: &mut u8) -> u8 {
let ptr: *mut u8 = r;
let addr = ptr as usize;
let null = ptr.wrapping_sub(addr);
// SAFETY: `ptr - ptr == null`
let definitely_null = unsafe { assert_null(null) };
let ptr2 = definitely_null.wrapping_add(addr);
// SAFETY: `ptr2` has the same address and provenance as `ptr`
// and `ptr` was derived from a safe reference
unsafe { *ptr2 }
}
fn main() {
println!("{}", bad(&mut 42));
} This should probably work, but LLVM will just "optimize" the entire program to |
We've run into this one before, I think @nikic fixed it in LLVM at the time - this seems like another case of LLVM incorrectly assuming that address == 0 implies pointer == null. |
I edited your example from the comment into the main post and changed the title to reflect that int2ptr casts are not really at the core of this but that the issue is much simpler. |
The issue from the original description and the one from the comment are different ones. The original one is that |
Are you sure that is the case? My recollection was that any previously exposed provenance can be picked up, independent of its address. I think it is not uncommon to cast ptr2int, do arithmetic, and cast back, and such code is intended to be allowed. The intended semantics for Rust also allow picking up provenance exposed at a different address. |
Are there LLVM issues tracking these? |
@RalfJung The equality replacement issue is llvm/llvm-project#34577 (it might be familiar to you!) I don't think the |
Quoting from N3005:
|
@lukas-code that doesn't require the pointer to be at the exact address it was exposed at. However C generally does not allow any pointers to exist that are not in-bounds of their provenance, so I guess the issue of |
playground
The program gets optimized into
ud2
.original example:
I tried this code:
I expected to see this happen: The program always prints
false
.Instead, this happened: The program prints
true
if optimizations are enabled.The documentation of
from_exposed_addr_mut
says that the function will "guess" the correct provenance if able, so I expected it to guessptr.with_addr(0)
here.Miri does not detect undefined behavior in the program.
Meta
playground nightly (2023-01-25 c18a5e8)
The text was updated successfully, but these errors were encountered: