-
Notifications
You must be signed in to change notification settings - Fork 61
Description
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 = barThat 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.