Skip to content

Commit 5ae5cfa

Browse files
committed
Evaluating sizeof over __CPROVER_bool requires special cases
__CPROVER_bool is just a single bit, and not part of any language standard describing the semantics of sizeof. We can declare arrays of __CPROVER_bool, which will thus have elements that are not aligned on byte boundaries. Using sizeof with such an array thus requires specific handling.
1 parent 6fe723b commit 5ae5cfa

File tree

7 files changed

+118
-6
lines changed

7 files changed

+118
-6
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#define STATIC_ASSERT(condition) int some_array##__LINE__[(condition) ? 1 : -1]
2+
3+
struct bits
4+
{
5+
__CPROVER_bool b1;
6+
__CPROVER_bool b2;
7+
__CPROVER_bool b3;
8+
__CPROVER_bool b4;
9+
__CPROVER_bool b5;
10+
__CPROVER_bool b6;
11+
__CPROVER_bool b7;
12+
__CPROVER_bool b8;
13+
int i;
14+
};
15+
16+
STATIC_ASSERT(sizeof(struct bits) == 2 * sizeof(int));
17+
18+
#include <limits.h>
19+
20+
#if CHAR_BIT >= 8
21+
#pragma pack(1)
22+
struct packed_bits
23+
{
24+
__CPROVER_bool b1;
25+
__CPROVER_bool b2;
26+
__CPROVER_bool b3;
27+
__CPROVER_bool b4;
28+
__CPROVER_bool b5;
29+
__CPROVER_bool b6;
30+
__CPROVER_bool b7;
31+
__CPROVER_bool b8;
32+
int i;
33+
};
34+
#pragma pack()
35+
36+
STATIC_ASSERT(sizeof(struct packed_bits) == sizeof(int) + 1);
37+
#endif
38+
39+
// a _Bool is at least one byte wide
40+
STATIC_ASSERT(sizeof(_Bool[CHAR_BIT]) >= CHAR_BIT);
41+
// __CPROVER_bool is just a single bit
42+
STATIC_ASSERT(sizeof(__CPROVER_bool[CHAR_BIT]) == 1);
43+
44+
int main()
45+
{
46+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
--
7+
^warning: ignoring
8+
^CONVERSION ERROR$

src/ansi-c/c_typecheck_expr.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -977,7 +977,7 @@ void c_typecheck_baset::typecheck_expr_sizeof(exprt &expr)
977977

978978
exprt new_expr;
979979

980-
if(type.id()==ID_c_bit_field)
980+
if(type.id() == ID_c_bit_field || type.id() == ID_bool)
981981
{
982982
err_location(expr);
983983
error() << "sizeof cannot be applied to bit fields" << eom;
@@ -1731,7 +1731,7 @@ void c_typecheck_baset::typecheck_expr_address_of(exprt &expr)
17311731

17321732
exprt &op=expr.op0();
17331733

1734-
if(op.type().id()==ID_c_bit_field)
1734+
if(op.type().id() == ID_c_bit_field || op.type().id() == ID_bool)
17351735
{
17361736
err_location(expr);
17371737
error() << "cannot take address of a bit field" << eom;

src/ansi-c/padding.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,10 @@ static void add_padding_msvc(struct_typet &type, const namespacet &ns)
226226
const auto width = to_c_bit_field_type(it->type()).get_width();
227227
bit_field_bits += width;
228228
}
229+
else if(it->type().id() == ID_bool)
230+
{
231+
++bit_field_bits;
232+
}
229233
else
230234
{
231235
// keep track of offset
@@ -281,6 +285,10 @@ static void add_padding_gcc(struct_typet &type, const namespacet &ns)
281285
const std::size_t width = to_c_bit_field_type(it->type()).get_width();
282286
bit_field_bits+=width;
283287
}
288+
else if(it->type().id() == ID_bool)
289+
{
290+
++bit_field_bits;
291+
}
284292
else if(bit_field_bits!=0)
285293
{
286294
// not on a byte-boundary?
@@ -347,6 +355,18 @@ static void add_padding_gcc(struct_typet &type, const namespacet &ns)
347355
continue;
348356
}
349357
}
358+
else if(it_type.id() == ID_bool)
359+
{
360+
a = alignment(it_type, ns);
361+
if(max_alignment < a)
362+
max_alignment = a;
363+
364+
++bit_field_bits;
365+
const std::size_t bytes = bit_field_bits / config.ansi_c.char_width;
366+
bit_field_bits %= config.ansi_c.char_width;
367+
offset += bytes;
368+
continue;
369+
}
350370
else
351371
a=alignment(it_type, ns);
352372

src/util/pointer_offset_size.cpp

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,13 @@ exprt member_offset_expr(
290290
bit_field_bits %= 8;
291291
result=plus_exprt(result, from_integer(bytes, result.type()));
292292
}
293+
else if(c.type().id() == ID_bool)
294+
{
295+
++bit_field_bits;
296+
const std::size_t bytes = bit_field_bits / 8;
297+
bit_field_bits %= 8;
298+
result = plus_exprt(result, from_integer(bytes, result.type()));
299+
}
293300
else
294301
{
295302
DATA_INVARIANT(
@@ -315,6 +322,15 @@ exprt size_of_expr(
315322
{
316323
const auto &array_type = to_array_type(type);
317324

325+
// special-case arrays of bits
326+
if(array_type.subtype().id() == ID_bool)
327+
{
328+
auto bits = pointer_offset_bits(array_type, ns);
329+
330+
if(bits.has_value())
331+
return from_integer((*bits + 7) / 8, size_type());
332+
}
333+
318334
exprt sub = size_of_expr(array_type.subtype(), ns);
319335
if(sub.is_nil())
320336
return nil_exprt();
@@ -335,7 +351,18 @@ exprt size_of_expr(
335351
}
336352
else if(type.id()==ID_vector)
337353
{
338-
exprt sub = size_of_expr(to_vector_type(type).subtype(), ns);
354+
const auto &vector_type = to_vector_type(type);
355+
356+
// special-case vectors of bits
357+
if(vector_type.subtype().id() == ID_bool)
358+
{
359+
auto bits = pointer_offset_bits(vector_type, ns);
360+
361+
if(bits.has_value())
362+
return from_integer((*bits + 7) / 8, size_type());
363+
}
364+
365+
exprt sub = size_of_expr(vector_type.subtype(), ns);
339366
if(sub.is_nil())
340367
return nil_exprt();
341368

@@ -383,6 +410,13 @@ exprt size_of_expr(
383410
bit_field_bits %= 8;
384411
result=plus_exprt(result, from_integer(bytes, result.type()));
385412
}
413+
else if(c.type().id() == ID_bool)
414+
{
415+
++bit_field_bits;
416+
const std::size_t bytes = bit_field_bits / 8;
417+
bit_field_bits %= 8;
418+
result = plus_exprt(result, from_integer(bytes, result.type()));
419+
}
386420
else
387421
{
388422
DATA_INVARIANT(

src/util/simplify_expr.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1982,10 +1982,10 @@ bool simplify_exprt::simplify_byte_update(byte_update_exprt &expr)
19821982
{
19831983
const struct_typet &struct_type=to_struct_type(tp);
19841984
const irep_idt &component_name=with.where().get(ID_component_name);
1985+
const typet &c_type = struct_type.get_component(component_name).type();
19851986

19861987
// is this a bit field?
1987-
if(struct_type.get_component(component_name).type().id()==
1988-
ID_c_bit_field)
1988+
if(c_type.id() == ID_c_bit_field || c_type.id() == ID_bool)
19891989
{
19901990
// don't touch -- might not be byte-aligned
19911991
}

src/util/simplify_expr_struct.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,12 @@ bool simplify_exprt::simplify_member(exprt &expr)
152152
const struct_typet::componentt &component=
153153
struct_type.get_component(component_name);
154154

155-
if(component.is_nil() || component.type().id()==ID_c_bit_field)
155+
if(
156+
component.is_nil() || component.type().id() == ID_c_bit_field ||
157+
component.type().id() == ID_bool)
158+
{
156159
return true;
160+
}
157161

158162
// add member offset to index
159163
auto offset_int = member_offset(struct_type, component_name, ns);

0 commit comments

Comments
 (0)