Input C/C++ header
struct __attribute__((packed)) S {
unsigned long long p : 2;
unsigned long long x : 63;
};
Bindgen invocation
$ bindgen input.h \
--rust-target 1.75 \
--rust-edition 2021 \
-- -std=gnu11 > bindings.rs
Actual output
The generated record layout is correct:
#[repr(C, packed)]
#[derive(Debug, Copy, Clone)]
pub struct S {
pub _bitfield_1: __BindgenBitfieldUnit<[u8; 9usize]>,
}
impl S {
#[inline]
pub fn x(&self) -> ::std::os::raw::c_ulonglong {
self._bitfield_1.get_const::<2usize, 63u8>() as u64 as _
}
}
The generated helper calculates a nine-byte window and accumulates it in a
u64:
let bit_shift = BIT_OFFSET % 8;
let bytes_needed = (BIT_WIDTH as usize + bit_shift + 7) / 8;
let mut val = 0u64;
let mut i = 0;
while i < bytes_needed {
val |= (self.storage[start_byte + i].reverse_bits() as u64) << (i * 8);
i += 1;
}
I ran the unchanged binding against the all-ones representation. Clang reports
that x occupies bits 2 through 64 and that S is nine bytes:
0:0-1 | unsigned long long p
0:2-64 | unsigned long long x
| [sizeof=9, align=1]
The C accessor returns:
With overflow checks enabled, the generated Rust getter panics:
attempt to shift left with overflow
With an optimized build and overflow checks disabled, it returns:
What is wrong
x is 63 bits wide but begins at intra-byte offset 2. Its extraction window is
therefore 65 bits and spans nine bytes. When the loop reaches the ninth byte,
it shifts a u64 by 64. The setter paths perform the corresponding right shift
by 64 while extracting the ninth value and mask bytes.
The storage type and record layout are correct. The error is in the generated
getter, setter, raw accessor, and constructor method bodies.
Expected output
The generated accessors should handle a field whose width plus intra-byte
offset exceeds 64 bits without shifting a u64 by 64. Both builds should
produce:
The setters, raw setters, and new_bitfield_1 should also write a value that
the C declaration reads back as 0x7fffffffffffffff.
Impact
With current main, the generated getters, setters, raw accessors, and
constructor panic when overflow checks are enabled. In an optimized build, the
getter loses the highest bit, and the write paths store
0x3fffffffffffffff where C expects 0x7fffffffffffffff.
Bindgen 0.72.1 does not reproduce this regression.
Environment
bindgen: 0.72.0, current main 25b23474496e78f6a1fbf1c02cb66f11e4d176d0
clang/libclang: 15.0.7
rustc: 1.75.0
target: x86_64-unknown-linux-gnu
OS: Ubuntu 22.04.5 LTS, x86_64
Input C/C++ header
Bindgen invocation
Actual output
The generated record layout is correct:
The generated helper calculates a nine-byte window and accumulates it in a
u64:I ran the unchanged binding against the all-ones representation. Clang reports
that
xoccupies bits 2 through 64 and thatSis nine bytes:The C accessor returns:
With overflow checks enabled, the generated Rust getter panics:
With an optimized build and overflow checks disabled, it returns:
What is wrong
xis 63 bits wide but begins at intra-byte offset 2. Its extraction window istherefore 65 bits and spans nine bytes. When the loop reaches the ninth byte,
it shifts a
u64by 64. The setter paths perform the corresponding right shiftby 64 while extracting the ninth value and mask bytes.
The storage type and record layout are correct. The error is in the generated
getter, setter, raw accessor, and constructor method bodies.
Expected output
The generated accessors should handle a field whose width plus intra-byte
offset exceeds 64 bits without shifting a
u64by 64. Both builds shouldproduce:
The setters, raw setters, and
new_bitfield_1should also write a value thatthe C declaration reads back as
0x7fffffffffffffff.Impact
With current main, the generated getters, setters, raw accessors, and
constructor panic when overflow checks are enabled. In an optimized build, the
getter loses the highest bit, and the write paths store
0x3fffffffffffffffwhere C expects0x7fffffffffffffff.Bindgen 0.72.1 does not reproduce this regression.
Environment