As of #126770
|
let self_start = self.as_ptr() as usize; |
|
let elem_start = element as *const T as usize; |
|
|
|
let byte_offset = elem_start.wrapping_sub(self_start); |
|
|
|
if byte_offset % mem::size_of::<T>() != 0 { |
|
return None; |
|
} |
|
|
|
let offset = byte_offset / mem::size_of::<T>(); |
|
|
|
if offset < self.len() { Some(offset) } else { None } |
the element_offset method is implemented by comparing the addresses of two pointers. For elements within the same allocation, this has the correct behaviour, however address equality and ordering between independent allocations have no guarantees via LLVM and I expect the intended rust opsem. For example, we want to be able to alias immutable allocations with the same data, and we want to be able to elide mallocs that are detected to not escape a scope, and the compiler invents addresses for the objects in that malloc: This is capable of producing pointers to independent live allocations with the same address.
With pointer comparison defined to ignore provenance, it cannot observe this distinction so can give a false positive, identifying an arbitrary element in a slice as having the "same address" as a pointer in a different allocation.
An example of a false positive would be
fn foo(x: &[u32]) -> &u32 {
assert!(x.len() > 0);
x.element_offset(&10).unwrap()
}
// it is legitimate to transform this into
fn foo(x: &[u32]) -> &u32 {
assert!(x.len() > 0);
// decide that the address of the temporary is == x.as_ptr().addr(), and simplify
&x[0]
}
(edit for clarification: I'm not aware of rust's semantics here, I just know that in the past llvm has had independent allocations be incomparable in this way, and while talking with nia we found a series of examples of llvm treating them as such)
As of #126770
rust/library/core/src/slice/mod.rs
Lines 4573 to 4584 in d6080a1
the element_offset method is implemented by comparing the addresses of two pointers. For elements within the same allocation, this has the correct behaviour, however address equality and ordering between independent allocations have no guarantees via LLVM and I expect the intended rust opsem. For example, we want to be able to alias immutable allocations with the same data, and we want to be able to elide mallocs that are detected to not escape a scope, and the compiler invents addresses for the objects in that malloc: This is capable of producing pointers to independent live allocations with the same address.
With pointer comparison defined to ignore provenance, it cannot observe this distinction so can give a false positive, identifying an arbitrary element in a slice as having the "same address" as a pointer in a different allocation.
An example of a false positive would be
(edit for clarification: I'm not aware of rust's semantics here, I just know that in the past llvm has had independent allocations be incomparable in this way, and while talking with nia we found a series of examples of llvm treating them as such)