Skip to content

Evaluating sizeof over __CPROVER_bool requires special cases #3183

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

Merged
merged 1 commit into from
Oct 29, 2018
Merged
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
46 changes: 46 additions & 0 deletions regression/ansi-c/cprover_bool1/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#define STATIC_ASSERT(condition) int some_array##__LINE__[(condition) ? 1 : -1]

struct bits
{
__CPROVER_bool b1;
__CPROVER_bool b2;
__CPROVER_bool b3;
__CPROVER_bool b4;
__CPROVER_bool b5;
__CPROVER_bool b6;
__CPROVER_bool b7;
__CPROVER_bool b8;
int i;
};

STATIC_ASSERT(sizeof(struct bits) == 2 * sizeof(int));

#include <limits.h>

#if CHAR_BIT >= 8
#pragma pack(1)
struct packed_bits
{
__CPROVER_bool b1;
__CPROVER_bool b2;
__CPROVER_bool b3;
__CPROVER_bool b4;
__CPROVER_bool b5;
__CPROVER_bool b6;
__CPROVER_bool b7;
__CPROVER_bool b8;
int i;
};
#pragma pack()

STATIC_ASSERT(sizeof(struct packed_bits) == sizeof(int) + 1);
#endif

// a _Bool is at least one byte wide
STATIC_ASSERT(sizeof(_Bool[CHAR_BIT]) >= CHAR_BIT);
// __CPROVER_bool is just a single bit
STATIC_ASSERT(sizeof(__CPROVER_bool[CHAR_BIT]) == 1);

int main()
{
}
8 changes: 8 additions & 0 deletions regression/ansi-c/cprover_bool1/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CORE
main.c

^EXIT=0$
^SIGNAL=0$
--
^warning: ignoring
^CONVERSION ERROR$
13 changes: 13 additions & 0 deletions src/ansi-c/c_typecheck_expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -985,6 +985,12 @@ void c_typecheck_baset::typecheck_expr_sizeof(exprt &expr)
error() << "sizeof cannot be applied to bit fields" << eom;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message may be a bit confusing -- I'd give this a separate case.

throw 0;
}
else if(type.id() == ID_bool)
{
err_location(expr);
error() << "sizeof cannot be applied to single bits" << eom;
throw 0;
}
else if(type.id() == ID_empty)
{
// This is a gcc extension.
Expand Down Expand Up @@ -1740,6 +1746,13 @@ void c_typecheck_baset::typecheck_expr_address_of(exprt &expr)
throw 0;
}

if(op.type().id() == ID_bool)
{
err_location(expr);
error() << "cannot take address of a single bit" << eom;
throw 0;
}

// special case: address of label
if(op.id()==ID_label)
{
Expand Down
20 changes: 20 additions & 0 deletions src/ansi-c/padding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,10 @@ static void add_padding_msvc(struct_typet &type, const namespacet &ns)
const auto width = to_c_bit_field_type(it->type()).get_width();
bit_field_bits += width;
}
else if(it->type().id() == ID_bool)
{
++bit_field_bits;
}
else
{
// keep track of offset
Expand Down Expand Up @@ -281,6 +285,10 @@ static void add_padding_gcc(struct_typet &type, const namespacet &ns)
const std::size_t width = to_c_bit_field_type(it->type()).get_width();
bit_field_bits+=width;
}
else if(it->type().id() == ID_bool)
{
++bit_field_bits;
}
else if(bit_field_bits!=0)
{
// not on a byte-boundary?
Expand Down Expand Up @@ -347,6 +355,18 @@ static void add_padding_gcc(struct_typet &type, const namespacet &ns)
continue;
}
}
else if(it_type.id() == ID_bool)
{
a = alignment(it_type, ns);
if(max_alignment < a)
max_alignment = a;

++bit_field_bits;
const std::size_t bytes = bit_field_bits / config.ansi_c.char_width;
bit_field_bits %= config.ansi_c.char_width;
offset += bytes;
continue;
}
else
a=alignment(it_type, ns);

Expand Down
50 changes: 47 additions & 3 deletions src/util/pointer_offset_size.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ member_offset_iterator &member_offset_iterator::operator++()
current.second += bit_field_bits / 8;
bit_field_bits %= 8;
}
else if(comp.type().id() == ID_bool)
{
++bit_field_bits;
current.second += bit_field_bits / 8;
bit_field_bits %= 8;
}
else
{
DATA_INVARIANT(
Expand Down Expand Up @@ -288,7 +294,16 @@ exprt member_offset_expr(
bit_field_bits += w;
const std::size_t bytes = bit_field_bits / 8;
bit_field_bits %= 8;
result=plus_exprt(result, from_integer(bytes, result.type()));
if(bytes > 0)
result = plus_exprt(result, from_integer(bytes, result.type()));
}
else if(c.type().id() == ID_bool)
{
++bit_field_bits;
const std::size_t bytes = bit_field_bits / 8;
bit_field_bits %= 8;
if(bytes > 0)
result = plus_exprt(result, from_integer(bytes, result.type()));
}
else
{
Expand All @@ -315,6 +330,15 @@ exprt size_of_expr(
{
const auto &array_type = to_array_type(type);

// special-case arrays of bits
if(array_type.subtype().id() == ID_bool)
{
auto bits = pointer_offset_bits(array_type, ns);

if(bits.has_value())
return from_integer((*bits + 7) / 8, size_type());
}

exprt sub = size_of_expr(array_type.subtype(), ns);
if(sub.is_nil())
return nil_exprt();
Expand All @@ -335,7 +359,18 @@ exprt size_of_expr(
}
else if(type.id()==ID_vector)
{
exprt sub = size_of_expr(to_vector_type(type).subtype(), ns);
const auto &vector_type = to_vector_type(type);

// special-case vectors of bits
if(vector_type.subtype().id() == ID_bool)
{
auto bits = pointer_offset_bits(vector_type, ns);

if(bits.has_value())
return from_integer((*bits + 7) / 8, size_type());
}

exprt sub = size_of_expr(vector_type.subtype(), ns);
if(sub.is_nil())
return nil_exprt();

Expand Down Expand Up @@ -381,7 +416,16 @@ exprt size_of_expr(
bit_field_bits += w;
const std::size_t bytes = bit_field_bits / 8;
bit_field_bits %= 8;
result=plus_exprt(result, from_integer(bytes, result.type()));
if(bytes > 0)
result = plus_exprt(result, from_integer(bytes, result.type()));
}
else if(c.type().id() == ID_bool)
{
++bit_field_bits;
const std::size_t bytes = bit_field_bits / 8;
bit_field_bits %= 8;
if(bytes > 0)
result = plus_exprt(result, from_integer(bytes, result.type()));
}
else
{
Expand Down
4 changes: 2 additions & 2 deletions src/util/simplify_expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1947,10 +1947,10 @@ bool simplify_exprt::simplify_byte_update(byte_update_exprt &expr)
{
const struct_typet &struct_type=to_struct_type(tp);
const irep_idt &component_name=with.where().get(ID_component_name);
const typet &c_type = struct_type.get_component(component_name).type();

// is this a bit field?
if(struct_type.get_component(component_name).type().id()==
ID_c_bit_field)
if(c_type.id() == ID_c_bit_field || c_type.id() == ID_bool)
{
// don't touch -- might not be byte-aligned
}
Expand Down
6 changes: 5 additions & 1 deletion src/util/simplify_expr_struct.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,12 @@ bool simplify_exprt::simplify_member(exprt &expr)
const struct_typet::componentt &component=
struct_type.get_component(component_name);

if(component.is_nil() || component.type().id()==ID_c_bit_field)
if(
component.is_nil() || component.type().id() == ID_c_bit_field ||
component.type().id() == ID_bool)
{
return true;
}

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