Skip to content

Commit 7164e6e

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 d21b20b commit 7164e6e

File tree

7 files changed

+135
-4
lines changed

7 files changed

+135
-4
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: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -985,6 +985,12 @@ void c_typecheck_baset::typecheck_expr_sizeof(exprt &expr)
985985
error() << "sizeof cannot be applied to bit fields" << eom;
986986
throw 0;
987987
}
988+
else if(type.id() == ID_bool)
989+
{
990+
err_location(expr);
991+
error() << "sizeof cannot be applied to single bits" << eom;
992+
throw 0;
993+
}
988994
else if(type.id() == ID_empty)
989995
{
990996
// This is a gcc extension.
@@ -1740,6 +1746,13 @@ void c_typecheck_baset::typecheck_expr_address_of(exprt &expr)
17401746
throw 0;
17411747
}
17421748

1749+
if(op.type().id() == ID_bool)
1750+
{
1751+
err_location(expr);
1752+
error() << "cannot take address of a single bit" << eom;
1753+
throw 0;
1754+
}
1755+
17431756
// special case: address of label
17441757
if(op.id()==ID_label)
17451758
{

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: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ member_offset_iterator &member_offset_iterator::operator++()
4242
current.second += bit_field_bits / 8;
4343
bit_field_bits %= 8;
4444
}
45+
else if(comp.type().id() == ID_bool)
46+
{
47+
++bit_field_bits;
48+
current.second += bit_field_bits / 8;
49+
bit_field_bits %= 8;
50+
}
4551
else
4652
{
4753
DATA_INVARIANT(
@@ -290,6 +296,13 @@ exprt member_offset_expr(
290296
bit_field_bits %= 8;
291297
result=plus_exprt(result, from_integer(bytes, result.type()));
292298
}
299+
else if(c.type().id() == ID_bool)
300+
{
301+
++bit_field_bits;
302+
const std::size_t bytes = bit_field_bits / 8;
303+
bit_field_bits %= 8;
304+
result = plus_exprt(result, from_integer(bytes, result.type()));
305+
}
293306
else
294307
{
295308
DATA_INVARIANT(
@@ -315,6 +328,15 @@ exprt size_of_expr(
315328
{
316329
const auto &array_type = to_array_type(type);
317330

331+
// special-case arrays of bits
332+
if(array_type.subtype().id() == ID_bool)
333+
{
334+
auto bits = pointer_offset_bits(array_type, ns);
335+
336+
if(bits.has_value())
337+
return from_integer((*bits + 7) / 8, size_type());
338+
}
339+
318340
exprt sub = size_of_expr(array_type.subtype(), ns);
319341
if(sub.is_nil())
320342
return nil_exprt();
@@ -335,7 +357,18 @@ exprt size_of_expr(
335357
}
336358
else if(type.id()==ID_vector)
337359
{
338-
exprt sub = size_of_expr(to_vector_type(type).subtype(), ns);
360+
const auto &vector_type = to_vector_type(type);
361+
362+
// special-case vectors of bits
363+
if(vector_type.subtype().id() == ID_bool)
364+
{
365+
auto bits = pointer_offset_bits(vector_type, ns);
366+
367+
if(bits.has_value())
368+
return from_integer((*bits + 7) / 8, size_type());
369+
}
370+
371+
exprt sub = size_of_expr(vector_type.subtype(), ns);
339372
if(sub.is_nil())
340373
return nil_exprt();
341374

@@ -383,6 +416,13 @@ exprt size_of_expr(
383416
bit_field_bits %= 8;
384417
result=plus_exprt(result, from_integer(bytes, result.type()));
385418
}
419+
else if(c.type().id() == ID_bool)
420+
{
421+
++bit_field_bits;
422+
const std::size_t bytes = bit_field_bits / 8;
423+
bit_field_bits %= 8;
424+
result = plus_exprt(result, from_integer(bytes, result.type()));
425+
}
386426
else
387427
{
388428
DATA_INVARIANT(

src/util/simplify_expr.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1947,10 +1947,10 @@ bool simplify_exprt::simplify_byte_update(byte_update_exprt &expr)
19471947
{
19481948
const struct_typet &struct_type=to_struct_type(tp);
19491949
const irep_idt &component_name=with.where().get(ID_component_name);
1950+
const typet &c_type = struct_type.get_component(component_name).type();
19501951

19511952
// is this a bit field?
1952-
if(struct_type.get_component(component_name).type().id()==
1953-
ID_c_bit_field)
1953+
if(c_type.id() == ID_c_bit_field || c_type.id() == ID_bool)
19541954
{
19551955
// don't touch -- might not be byte-aligned
19561956
}

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)