Skip to content

Commit 74dc576

Browse files
author
Daniel Kroening
authored
Merge pull request #2003 from tautschnig/bitfield-offset
[SV-COMP'18 14/19] Fixing member offset computation in presence of bitfields.
2 parents 8916906 + 495f109 commit 74dc576

File tree

4 files changed

+82
-17
lines changed

4 files changed

+82
-17
lines changed

regression/cbmc/Bitfields3/main.c

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#include <stdlib.h>
2+
#include <assert.h>
3+
4+
#pragma pack(1)
5+
struct A
6+
{
7+
unsigned char a;
8+
unsigned char b : 2;
9+
unsigned char c : 2;
10+
unsigned char d;
11+
};
12+
13+
struct B
14+
{
15+
unsigned char a;
16+
unsigned char b : 2;
17+
unsigned char c;
18+
unsigned char d : 2;
19+
};
20+
21+
struct C
22+
{
23+
unsigned char a;
24+
unsigned char b : 4;
25+
unsigned char c : 4;
26+
unsigned char d;
27+
};
28+
#pragma pack()
29+
30+
int main(void)
31+
{
32+
assert(sizeof(struct A) == 3);
33+
struct A *p = malloc(3);
34+
assert((unsigned char *)p + 2 == &(p->d));
35+
p->c = 3;
36+
if(p->c != 3)
37+
{
38+
free(p);
39+
}
40+
free(p);
41+
42+
assert(sizeof(struct B) == 4);
43+
struct B *pb = malloc(4);
44+
assert((unsigned char *)pb + 2 == &(pb->c));
45+
free(pb);
46+
47+
assert(sizeof(struct C) == 3);
48+
struct C *pc = malloc(3);
49+
assert((unsigned char *)pc + 2 == &(pc->d));
50+
free(pc);
51+
52+
return 0;
53+
}

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)