Open
Description
// 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));
}
The program gets optimized into ud2
.
original example:
I tried this code:
#![feature(strict_provenance)]
pub fn bad(r: &mut u8) -> bool {
let ptr: *mut u8 = r;
let addr = ptr.expose_addr();
let null_with_provenance = core::ptr::from_exposed_addr_mut::<u8>(0);
let ptr2 = null_with_provenance.wrapping_add(addr);
let val_before = unsafe { *ptr };
unsafe { *ptr2 = 2; }
let val_after = unsafe { *ptr };
return val_before == val_after;
}
fn main() {
println!("{}", bad(&mut 1));
}
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 guess ptr.with_addr(0)
here.
Miri does not detect undefined behavior in the program.
Meta
playground nightly (2023-01-25 c18a5e8)
Metadata
Metadata
Assignees
Labels
Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.Area: Documentation for any part of the project, including the compiler, standard library, and toolsArea: Strict provenance for raw pointersCategory: This is a bug.Relevant to the compiler team, which will review and decide on the PR/issue.