Skip to content

Commit 17ac3a6

Browse files
committed
prohibit pointers to bit-vectors that are not byte-aligned
This adds checks to the C front-end that prohibit taking the address of objects that cannot be addressed with byte-granularity pointers. This includes proper Booleans (not to be confused with _Bool) and __CPROVER_bitvector-typed objects whose width is not a multiple of 8. Fixes #7104.
1 parent 098ec1e commit 17ac3a6

File tree

3 files changed

+57
-8
lines changed

3 files changed

+57
-8
lines changed

src/ansi-c/c_typecast.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -739,6 +739,15 @@ void c_typecastt::do_typecast(exprt &expr, const typet &dest_type)
739739

740740
if(src_type.id()==ID_array)
741741
{
742+
// This is the promotion from an array
743+
// to a pointer to the first element.
744+
auto error_opt = check_address_can_be_taken(expr.type());
745+
if(error_opt.has_value())
746+
{
747+
errors.push_back(error_opt.value());
748+
return;
749+
}
750+
742751
index_exprt index(expr, from_integer(0, c_index_type()));
743752
expr = typecast_exprt::conditional_cast(address_of_exprt(index), dest_type);
744753
return;
@@ -765,3 +774,31 @@ void c_typecastt::do_typecast(exprt &expr, const typet &dest_type)
765774
}
766775
}
767776
}
777+
778+
optionalt<std::string>
779+
c_typecastt::check_address_can_be_taken(const typet &type)
780+
{
781+
if(type.id() == ID_c_bit_field)
782+
return std::string("cannot take address of a bit field");
783+
784+
if(type.id() == ID_bool)
785+
return std::string("cannot take address of a proper Boolean");
786+
787+
if(
788+
type.id() == ID_unsignedbv || type.id() == ID_signedbv ||
789+
type.id() == ID_bv || type.id() == ID_floatbv)
790+
{
791+
// The width of the bitvector must be a multiple of CHAR_BIT.
792+
auto width = to_bitvector_type(type).get_width();
793+
if(width % config.ansi_c.char_width != 0)
794+
return std::string(
795+
"bitvector must have width that is a multiple of CHAR_BIT");
796+
else
797+
return {};
798+
}
799+
800+
if(type.id() == ID_array)
801+
return check_address_can_be_taken(to_array_type(type).element_type());
802+
803+
return {}; // ok
804+
}

src/ansi-c/c_typecast.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ Author: Daniel Kroening, kroening@kroening.com
1010
#ifndef CPROVER_ANSI_C_C_TYPECAST_H
1111
#define CPROVER_ANSI_C_C_TYPECAST_H
1212

13+
#include <util/optional.h>
14+
1315
#include <list>
1416
#include <string>
1517

@@ -65,6 +67,10 @@ class c_typecastt
6567
std::list<std::string> errors;
6668
std::list<std::string> warnings;
6769

70+
/// \return empty when address can be taken,
71+
/// error message otherwise
72+
static optionalt<std::string> check_address_can_be_taken(const typet &);
73+
6874
protected:
6975
const namespacet &ns;
7076

src/ansi-c/c_typecheck_expr.cpp

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ Author: Daniel Kroening, kroening@kroening.com
3636
#include "builtin_factory.h"
3737
#include "c_expr.h"
3838
#include "c_qualifiers.h"
39+
#include "c_typecast.h"
3940
#include "c_typecheck_base.h"
4041
#include "expr2c.h"
4142
#include "padding.h"
@@ -1187,6 +1188,16 @@ void c_typecheck_baset::typecheck_expr_typecast(exprt &expr)
11871188
}
11881189
else if(op_type.id()==ID_array)
11891190
{
1191+
// This is the promotion from an array
1192+
// to a pointer to the first element.
1193+
auto error_opt = c_typecastt::check_address_can_be_taken(op_type);
1194+
if(error_opt.has_value())
1195+
{
1196+
error().source_location = expr.source_location();
1197+
error() << *error_opt << eom;
1198+
throw 0;
1199+
}
1200+
11901201
index_exprt index(op, from_integer(0, c_index_type()));
11911202
op=address_of_exprt(index);
11921203
}
@@ -1710,17 +1721,12 @@ void c_typecheck_baset::typecheck_expr_address_of(exprt &expr)
17101721
{
17111722
exprt &op = to_unary_expr(expr).op();
17121723

1713-
if(op.type().id()==ID_c_bit_field)
1714-
{
1715-
error().source_location = expr.source_location();
1716-
error() << "cannot take address of a bit field" << eom;
1717-
throw 0;
1718-
}
1724+
auto error_opt = c_typecastt::check_address_can_be_taken(op.type());
17191725

1720-
if(op.is_boolean())
1726+
if(error_opt.has_value())
17211727
{
17221728
error().source_location = expr.source_location();
1723-
error() << "cannot take address of a single bit" << eom;
1729+
error() << *error_opt << eom;
17241730
throw 0;
17251731
}
17261732

0 commit comments

Comments
 (0)