Skip to content

Semantics of function pointers with equal addresses? #589

@theemathas

Description

@theemathas

Consider the following code:

#[unsafe(no_mangle)]
fn foo(x: *mut i32, y: *mut i32) {
    unsafe {
        let a = &mut *x;
        let b = &mut *y;
        *a = *b;
    }
}

#[unsafe(no_mangle)]
fn bar(x: *mut i32, y: *mut i32) {
    unsafe {
        x.write(y.read());
    }
}

On rust version 1.91.0, the above code compiles to this assembly (Godbolt link):

bar:
        mov     eax, dword ptr [rsi]
        mov     dword ptr [rdi], eax
        ret

foo = bar

That is, the two functions are deduplicated, and therefore have the same address. This happened even though these two functions have different behavior in the abstract machine: the foo function has UB if x and y alias, while the bar function doesn't.

Suppose that some code casts these two functions into usize addresses (which are equal to each other), does some operation with those two usizes, and then transmutes an equal usize back into a function pointer. When calling that created function pointer, what is the behavior of that call? Does the call behave like calling foo or calling bar?

In theory, we probably also want (in the future) to potentially allow LLVM to deduplicate functions with incompatible ABIs, as long as their generated assembly are identical. This complicates the above question even further.

A similar question applies to deduplicated vtables.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions