Description
This supersedes #44367 - after #47743 the unsoundness has been restricted to C FFI. The Rust ABI for vector types currently passes all types by memory.
There are sadly many C libraries that use vector types in their ABIs, some of which are pretty much "fundamental" like some of the short-vector math libraries: libmvec
, SVML, etc.
As a summary of the previous issue, currently, the behavior of calling bar
, `the following snippet of Rust code is sometimes undefined:
#![feature(repr_simd, simd_ffi)]
#[repr(simd)]
struct F32x8(f32, f32, f32, f32, f32, f32, f32, f32);
impl F32x8 { fn splat(x: f32) -> Self { F32x8(x, x, x, x, x, x, x, x) } }
#[allow(improper_ctypes)]
extern "C" {
fn foo(x: F32x8) -> F32x8;
}
fn main() {
unsafe {
foo(F32x8::splat(0.)); // UB ?
}
}
When both the Rust program and the C library exposing foo are compiled with the same set of target-features such that their ABIs match, then the program above will work as expected.
When the C library is compiled with say AVX2, but the Rust program is compiled with SSE4.2, then Rust will try to pass the F32x8 in two 128-bit wide vector registers to C, while the C code only expects a single 256-bit wide vector. A similar problem occurs in the opposite case.
cc @rkruppe @parched @alexcrichton @eddyb - did I correctly represent the problem ?
A potential solution discussed in #44367 would be to completely forbid vector types in FFI functions that do not specify their vector ABI:
extern "C" {
extern "vector-256" fn foo(x: F32x8) -> F32x8;
extern "vector-128" fn bar(x: F32x8) -> F32x8;
// fn baz(x: F32x8) -> F32x8; // ERROR: repr(simd) in C-FFI with unspecified vector ABI
}
let x = F32x8::splat(0.);
foo(x); // x is passed in a single 256-bit wide register
bar(x); // x is passed in two 128-bit wide registers
If the C library linked does not expose the specified ABIs for foo
and bar
, the program would fail to link, preventing undefined behavior.