Skip to content

Commit 16fca94

Browse files
marek-trtiktautschnig
authored andcommitted
Fixing member offset computation in presence of bitfields
The previous algorithm correctly identified the offset of the next non-bitfield member, but would fail on consecutive bit-fields (fitting in one byte) as the offset was eagerly incremented. Also cleanup this computation in all places that used a similar algorithm.
1 parent 988b818 commit 16fca94

File tree

4 files changed

+53
-17
lines changed

4 files changed

+53
-17
lines changed

regression/cbmc/Bitfields3/main.c

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#include <stdlib.h>
2+
#include <assert.h>
3+
4+
#pragma pack(1)
5+
struct A {
6+
unsigned char a;
7+
unsigned char b:2;
8+
unsigned char c:2;
9+
unsigned char d;
10+
};
11+
#pragma pack()
12+
13+
int main(void)
14+
{
15+
assert(sizeof(struct A) == 3);
16+
struct A *p;
17+
p = malloc(2);
18+
assert((unsigned char *)p + 2 == &(p->d));
19+
p->c = 3;
20+
if (p->c != 3) {
21+
free(p);
22+
}
23+
free(p);
24+
}

regression/cbmc/Bitfields3/test.desc

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
--pointer-check --bounds-check
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring

src/ansi-c/padding.cpp

+6-9
Original file line numberDiff line numberDiff line change
@@ -199,16 +199,19 @@ void add_padding(struct_typet &type, const namespacet &ns)
199199
max_alignment=a;
200200

201201
std::size_t w=to_c_bit_field_type(it_type).get_width();
202-
std::size_t bytes;
203-
for(bytes=0; w>bit_field_bits; ++bytes, bit_field_bits+=8) {}
204-
bit_field_bits-=w;
202+
bit_field_bits += w;
203+
const std::size_t bytes = bit_field_bits / 8;
204+
bit_field_bits %= 8;
205205
offset+=bytes;
206206
continue;
207207
}
208208
}
209209
else
210210
a=alignment(it_type, ns);
211211

212+
DATA_INVARIANT(
213+
bit_field_bits == 0, "padding ensures offset at byte boundaries");
214+
212215
// check minimum alignment
213216
if(a<config.ansi_c.alignment && !packed)
214217
a=config.ansi_c.alignment;
@@ -246,12 +249,6 @@ void add_padding(struct_typet &type, const namespacet &ns)
246249
offset+=size;
247250
}
248251

249-
if(bit_field_bits!=0)
250-
{
251-
// these are now assumed to be multiples of 8
252-
offset+=bit_field_bits/8;
253-
}
254-
255252
// any explicit alignment for the struct?
256253
if(type.find(ID_C_alignment).is_not_nil())
257254
{

src/util/pointer_offset_size.cpp

+15-8
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,14 @@ member_offset_iterator &member_offset_iterator::operator++()
4242
{
4343
// take the extra bytes needed
4444
std::size_t w=to_c_bit_field_type(comp.type()).get_width();
45-
for(; w>bit_field_bits; ++current.second, bit_field_bits+=8) {}
46-
bit_field_bits-=w;
45+
bit_field_bits += w;
46+
current.second += bit_field_bits / 8;
47+
bit_field_bits %= 8;
4748
}
4849
else
4950
{
51+
DATA_INVARIANT(
52+
bit_field_bits == 0, "padding ensures offset at byte boundaries");
5053
const typet &subtype=comp.type();
5154
mp_integer sub_size=pointer_offset_size(subtype, ns);
5255
if(sub_size==-1)
@@ -287,13 +290,15 @@ exprt member_offset_expr(
287290
if(it->type().id()==ID_c_bit_field)
288291
{
289292
std::size_t w=to_c_bit_field_type(it->type()).get_width();
290-
std::size_t bytes;
291-
for(bytes=0; w>bit_field_bits; ++bytes, bit_field_bits+=8) {}
292-
bit_field_bits-=w;
293+
bit_field_bits += w;
294+
const std::size_t bytes = bit_field_bits / 8;
295+
bit_field_bits %= 8;
293296
result=plus_exprt(result, from_integer(bytes, result.type()));
294297
}
295298
else
296299
{
300+
DATA_INVARIANT(
301+
bit_field_bits == 0, "padding ensures offset at byte boundaries");
297302
const typet &subtype=it->type();
298303
exprt sub_size=size_of_expr(subtype, ns);
299304
if(sub_size.is_nil())
@@ -381,13 +386,15 @@ exprt size_of_expr(
381386
if(it->type().id()==ID_c_bit_field)
382387
{
383388
std::size_t w=to_c_bit_field_type(it->type()).get_width();
384-
std::size_t bytes;
385-
for(bytes=0; w>bit_field_bits; ++bytes, bit_field_bits+=8) {}
386-
bit_field_bits-=w;
389+
bit_field_bits += w;
390+
const std::size_t bytes = bit_field_bits / 8;
391+
bit_field_bits %= 8;
387392
result=plus_exprt(result, from_integer(bytes, result.type()));
388393
}
389394
else
390395
{
396+
DATA_INVARIANT(
397+
bit_field_bits == 0, "padding ensures offset at byte boundaries");
391398
const typet &subtype=it->type();
392399
exprt sub_size=size_of_expr(subtype, ns);
393400
if(sub_size.is_nil())

0 commit comments

Comments
 (0)