Skip to content

ir: Fix wrong condition in bitfield alignment. #1326

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

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions bindgen-integration/cpp/Test.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "Test.h"

#include <stdio.h>

const int Test::COUNTDOWN[] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
const int* Test::COUNTDOWN_PTR = Test::COUNTDOWN;

Expand Down Expand Up @@ -130,4 +132,17 @@ Seventh::assert(bool first,
this->seventh_thirty_bits == seventh;
};

bool
Eight::assert(char a, unsigned b) const
{
printf("{ a: %u, b: %u }\n", this->a, this->b);
return this->a == a && this->b == b;
}

bool
Ninth::assert(char a, unsigned short b) const
{
return this->a == a && this->b == b;
}

} // namespace bitfields
16 changes: 16 additions & 0 deletions bindgen-integration/cpp/Test.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,22 @@ struct Seventh {
int seventh);
};

struct Eight {
unsigned char a;
unsigned b : 15;

/// Returns true if the bitfields match the arguments, false otherwise.
bool assert(char a, unsigned b) const;
};

struct Ninth {
unsigned char a;
unsigned short b : 15;

/// Returns true if the bitfields match the arguments, false otherwise.
bool assert(char a, unsigned short b) const;
};

} // namespace bitfields

struct AutoRestoreBool {
Expand Down
28 changes: 28 additions & 0 deletions bindgen-integration/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,34 @@ fn test_bitfields_seventh() {
assert_eq!(large.seventh_thirty_bits(), 1061657575);
}

#[test]
fn test_bitfields_eight() {
let mut s: bindings::bitfields::Eight = unsafe { mem::zeroed() };
assert!(unsafe { s.assert(0, 0) });

s.a = 10;
s.set_b(1);

assert!(unsafe { s.assert(10, 1) });

assert_eq!(s.a, 10);
assert_eq!(s.b(), 1);
}

#[test]
fn test_bitfields_ninth() {
let mut s: bindings::bitfields::Ninth = unsafe { mem::zeroed() };
assert!(unsafe { s.assert(0, 0) });

s.a = 10;
s.set_b(656);

assert!(unsafe { s.assert(10, 656) });

assert_eq!(s.a, 10);
assert_eq!(s.b(), 656);
}

#[test]
fn test_bitfield_constructors() {
use std::mem;
Expand Down
6 changes: 3 additions & 3 deletions src/ir/comp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,7 @@ where
let bitfield_size = bitfield_layout.size;
let bitfield_align = bitfield_layout.align;

debug!("{:?}, {:?}", bitfield, bitfield_layout);
let mut offset = unit_size_in_bits;
if is_ms_struct {
if unit_size_in_bits != 0 &&
Expand All @@ -627,10 +628,9 @@ where
unit_align = 0;
}
} else {
if offset != 0 &&
(bitfield_width == 0 ||
if bitfield_width == 0 ||
(offset & (bitfield_align * 8 - 1)) + bitfield_width >
bitfield_size * 8)
bitfield_size * 8
{
offset = align_to(offset, bitfield_align * 8);
}
Expand Down
179 changes: 179 additions & 0 deletions tests/expectations/tests/issue-1314-bitfield-align.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
/* automatically generated by rust-bindgen */

#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]

#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct __BindgenBitfieldUnit<Storage, Align>
where
Storage: AsRef<[u8]> + AsMut<[u8]>,
{
storage: Storage,
align: [Align; 0],
}

impl<Storage, Align> __BindgenBitfieldUnit<Storage, Align>
where
Storage: AsRef<[u8]> + AsMut<[u8]>,
{
#[inline]
pub fn new(storage: Storage) -> Self {
Self { storage, align: [] }
}

#[inline]
pub fn get_bit(&self, index: usize) -> bool {
debug_assert!(index / 8 < self.storage.as_ref().len());

let byte_index = index / 8;
let byte = self.storage.as_ref()[byte_index];

let bit_index = index % 8;
let mask = 1 << bit_index;

byte & mask == mask
}

#[inline]
pub fn set_bit(&mut self, index: usize, val: bool) {
debug_assert!(index / 8 < self.storage.as_ref().len());

let byte_index = index / 8;
let byte = &mut self.storage.as_mut()[byte_index];

let bit_index = index % 8;
let mask = 1 << bit_index;

if val {
*byte |= mask;
} else {
*byte &= !mask;
}
}

#[inline]
pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 {
debug_assert!(bit_width <= 64);
debug_assert!(bit_offset / 8 < self.storage.as_ref().len());
debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len());

let mut val = 0;

for i in 0..(bit_width as usize) {
if self.get_bit(i + bit_offset) {
val |= 1 << i;
}
}

val
}

#[inline]
pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) {
debug_assert!(bit_width <= 64);
debug_assert!(bit_offset / 8 < self.storage.as_ref().len());
debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len());

for i in 0..(bit_width as usize) {
let mask = 1 << i;
let val_bit_is_set = val & mask == mask;
self.set_bit(i + bit_offset, val_bit_is_set);
}
}
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct S {
pub a: u8,
pub _bitfield_1: __BindgenBitfieldUnit<[u8; 2usize], u16>,
pub __bindgen_align: [u32; 0usize],
}
#[test]
fn bindgen_test_layout_S() {
assert_eq!(
::std::mem::size_of::<S>(),
4usize,
concat!("Size of: ", stringify!(S))
);
assert_eq!(
::std::mem::align_of::<S>(),
4usize,
concat!("Alignment of ", stringify!(S))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<S>())).a as *const _ as usize },
0usize,
concat!("Offset of field: ", stringify!(S), "::", stringify!(a))
);
}
impl S {
#[inline]
pub fn b(&self) -> u32 {
unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 15u8) as u32) }
}
#[inline]
pub fn set_b(&mut self, val: u32) {
unsafe {
let val: u32 = ::std::mem::transmute(val);
self._bitfield_1.set(0usize, 15u8, val as u64)
}
}
#[inline]
pub fn new_bitfield_1(b: u32) -> __BindgenBitfieldUnit<[u8; 2usize], u16> {
let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 2usize], u16> =
Default::default();
__bindgen_bitfield_unit.set(0usize, 15u8, {
let b: u32 = unsafe { ::std::mem::transmute(b) };
b as u64
});
__bindgen_bitfield_unit
}
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct S2 {
pub a: u8,
pub _bitfield_1: __BindgenBitfieldUnit<[u8; 2usize], u16>,
pub __bindgen_align: [u16; 0usize],
}
#[test]
fn bindgen_test_layout_S2() {
assert_eq!(
::std::mem::size_of::<S2>(),
4usize,
concat!("Size of: ", stringify!(S2))
);
assert_eq!(
::std::mem::align_of::<S2>(),
2usize,
concat!("Alignment of ", stringify!(S2))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<S2>())).a as *const _ as usize },
0usize,
concat!("Offset of field: ", stringify!(S2), "::", stringify!(a))
);
}
impl S2 {
#[inline]
pub fn b(&self) -> u16 {
unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 15u8) as u16) }
}
#[inline]
pub fn set_b(&mut self, val: u16) {
unsafe {
let val: u16 = ::std::mem::transmute(val);
self._bitfield_1.set(0usize, 15u8, val as u64)
}
}
#[inline]
pub fn new_bitfield_1(b: u16) -> __BindgenBitfieldUnit<[u8; 2usize], u16> {
let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 2usize], u16> =
Default::default();
__bindgen_bitfield_unit.set(0usize, 15u8, {
let b: u16 = unsafe { ::std::mem::transmute(b) };
b as u64
});
__bindgen_bitfield_unit
}
}
13 changes: 13 additions & 0 deletions tests/headers/issue-1314-bitfield-align.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned uint32_t;

typedef struct {
uint8_t a;
uint32_t b : 15;
} S;

typedef struct {
uint8_t a;
uint16_t b : 15;
} S2;