Skip to content

Commit 0aba4e8

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 5b56469 commit 0aba4e8

File tree

11 files changed

+105
-12
lines changed

11 files changed

+105
-12
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
__CPROVER_bool x;
2+
3+
int main()
4+
{
5+
void *p = &x; // should error
6+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
pointer-to-bool.c
3+
4+
cannot take address of a proper Boolean$
5+
^EXIT=(1|64)$
6+
^SIGNAL=0$
7+
--
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
__CPROVER_bitvector[123] z[10];
2+
3+
int main()
4+
{
5+
void *p = z; // should error
6+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
pointer-to-bv-array1.c
3+
4+
bitvector must have width that is a multiple of CHAR_BIT$
5+
^EXIT=(1|64)$
6+
^SIGNAL=0$
7+
--
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
__CPROVER_bitvector[123] z[10];
2+
3+
int main()
4+
{
5+
void *p = (int *)z; // should error
6+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
pointer-to-bv-array2.c
3+
4+
bitvector must have width that is a multiple of CHAR_BIT$
5+
^EXIT=(1|64)$
6+
^SIGNAL=0$
7+
--
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
__CPROVER_bitvector[15] y;
2+
3+
int main()
4+
{
5+
void *p = &y; // should error
6+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
pointer-to-bv.c
3+
4+
bitvector must have width that is a multiple of CHAR_BIT$
5+
^EXIT=(1|64)$
6+
^SIGNAL=0$
7+
--

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(can_cast_type<bitvector_typet>(type))
788+
{
789+
// The width of the bitvector must be a multiple of CHAR_BIT.
790+
auto width = to_bitvector_type(type).get_width();
791+
if(width % config.ansi_c.char_width != 0)
792+
{
793+
return std::string(
794+
"bitvector must have width that is a multiple of CHAR_BIT");
795+
}
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, [email protected]
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: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ Author: Daniel Kroening, [email protected]
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,12 @@ 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+
throw invalid_source_file_exceptiont{*error_opt, expr.source_location()};
1196+
11901197
index_exprt index(op, from_integer(0, c_index_type()));
11911198
op=address_of_exprt(index);
11921199
}
@@ -1710,19 +1717,10 @@ void c_typecheck_baset::typecheck_expr_address_of(exprt &expr)
17101717
{
17111718
exprt &op = to_unary_expr(expr).op();
17121719

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-
}
1720+
auto error_opt = c_typecastt::check_address_can_be_taken(op.type());
17191721

1720-
if(op.is_boolean())
1721-
{
1722-
error().source_location = expr.source_location();
1723-
error() << "cannot take address of a single bit" << eom;
1724-
throw 0;
1725-
}
1722+
if(error_opt.has_value())
1723+
throw invalid_source_file_exceptiont{*error_opt, expr.source_location()};
17261724

17271725
// special case: address of label
17281726
if(op.id()==ID_label)

0 commit comments

Comments
 (0)