-
Notifications
You must be signed in to change notification settings - Fork 707
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
_bindgen_union_align
field in generated Rust union results in garbage data on AArch64 (e.g. Apple Silicon)
#1973
Comments
@saleemrashid just discovered the root cause and is going to respond here later with a minimal reproducing example and a description of the issue. It does seem to be a bug in bindgen, as the |
_bindgen_union_align
field in generated Rust union causes misalignment on Apple Silicon, and arbitrary data is populated_bindgen_union_align
field in generated Rust union causes arbitrary data to be populated on Apple Silicon
TL;DR: bindgen uses a If you have the following C code: #include <stdint.h>
typedef union {
double v[4];
} coord;
coord make_coord(double x, double y, double z, double t) {
return (coord){.v = {x, y, z, t}};
} On AArch64, make_coord: // @make_coord
ret When bindgen generates bindings for that union, it'll add an opaque member to ensure the union has the correct alignment and size. In this case, it will generate: #[repr(C)]
pub union Coord {
pub v: [f64; 4],
_bindgen_union_align: [u64; 4],
} The typedef union {
double v[4];
uint64_t _bindgen_union_align[4];
} coord; make_coord: // @make_coord
stp d0, d1, [x8]
stp d2, d3, [x8, #16]
ret Because of this, in the example given by @frewsxcv, the |
_bindgen_union_align
field in generated Rust union causes arbitrary data to be populated on Apple Silicon_bindgen_union_align
field in generated Rust union causes arbitrary data to be populated on AArch64 (e.g. Apple Silicon)
_bindgen_union_align
field in generated Rust union causes arbitrary data to be populated on AArch64 (e.g. Apple Silicon)_bindgen_union_align
field in generated Rust union results in garbage on AArch64 (e.g. Apple Silicon)
_bindgen_union_align
field in generated Rust union results in garbage on AArch64 (e.g. Apple Silicon)_bindgen_union_align
field in generated Rust union results in garbage data on AArch64 (e.g. Apple Silicon)
In the compiler, I think this comes from |
Does anyone know how alignment should be done in this case? A special check for this case (floats in a union on AArch64) doesn't feel right to me. |
A ZST |
Also, is it possible to create a regression test for this in bindgen? My understanding is we'd need to link Rust code with C code to exhibit the behavior, but I don't see that happening anywhere already in the test suite. |
The bug is in Bindgen's opaque blob feature, which is implemented in src/ir/layout.rs and used to implement |
My initial thoughts are that if a type is a homogenous aggregate (i.e. it meets the AArch64 ABI criteria to use the return in registers behaviour), the opaque layout should use the element type rather than a LLVM definitely has the functions to identify homogenous aggregates and retrieve the element types, but I couldn't find them exposed in the LibClang API. |
Based off what I'm hearing, it sounds like the fix for this is to add a check in the opaque blob feature if the current platform is AArch64, and all the |
I wouldn't limit this to AArch64 -- multiple targets have similar ABI differences for homogeneous aggregates. If the union has its own mix of But it's also not clear to me what this added field is solving in the first place, so I'm probably missing something. Don't the union's own fields already set its size and alignment appropriately? |
Gotcha that makes sense. Is there a homogeneous check on the bindgen side? Or is this field unconditionally added to all bindgen generated |
Nevermind my last questions. My understanding is that the field is unconditionally added and the fix is to make the |
I assume the Regardless, the issue is with how Bindgen chooses an opaque layout for a type. So a user might hit this with a |
Hmm, the possibility of omitted members presents a hazard in the other direction -- that the type could appear homogeneous when it shouldn't be. |
This shouldn't be an issue, because Bindgen would get this information from the LibClang type (which is complete and has all the members), as opposed to the type it's emitting (where it might skip members that can't be represented in Rust, etc.) |
Sorry for the lag here. So for the rust union case, just using a ZST seems fine and should be trivial to fix ( I don't have the hardware to test such a fix though. |
@emilio Do you know of a way to create a regression test for this? |
Is there any possibility of only some union fields being emitted? (In which case, the union might have the wrong size if only smaller fields emitted). Then that just leaves solving it for the opaque type use-case, I guess. |
@frewsxcv we don't run integration tests on AArch64, but fixing this bug will change the expectations of a bunch of existing tests, which should prevent future unexpected regressions. |
All the |
I now see there is a separate directory and crate |
Failing regression test added in #1979 |
Opened a pull request for adding AArch64 testing in CI: #1980 |
I'm looking into fixing this now.
@emilio Can you clarify what you mean by "already aligned"? Currently, bindgen does not add rust-bindgen/src/codegen/mod.rs Lines 1824 to 1826 in 0f8ceb6
|
@emilio What is |
Already aligned meaning the fields themselves guarantee the right alignment, so there's no need to explicitly align.
So I looked into this a bit more since this extra explicit alignment also came up in #1983. So basically we should never need to add |
See https://users.rust-lang.org/t/on-apple-silicon-bindgen-union-is-constructed-with-random-data/54469/ for a write-up and context. This may or may not be a security issue, since it's reading arbitrary memory.
The text was updated successfully, but these errors were encountered: