Skip to content

Miscompilation with pointer address rountrip through address 0 #107326

Open
@lukas-code

Description

@lukas-code

playground

// 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

No one assigned

    Labels

    A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.A-docsArea: Documentation for any part of the project, including the compiler, standard library, and toolsA-strict-provenanceArea: Strict provenance for raw pointersC-bugCategory: This is a bug.T-compilerRelevant to the compiler 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