Skip to content

Commit ba874a4

Browse files
Merge pull request #339 from smowton/improve_array_bounds_checks
Improve array bounds checks
2 parents ea3a21f + 867f748 commit ba874a4

File tree

8 files changed

+224
-87
lines changed

8 files changed

+224
-87
lines changed

regression/cbmc/Function5/test.desc

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ main.c
33
--pointer-check --bounds-check
44
^SIGNAL=0$
55
^EXIT=10$
6-
^\[.*\] dereference failure: object bounds in \*p: FAILURE$
6+
^\[.*\] dereference failure: pointer outside object bounds in \*p: FAILURE$
77
--
88
^warning: ignoring

regression/cbmc/Malloc23/main.c

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#include <stdlib.h>
2+
3+
struct A
4+
{
5+
int x;
6+
int y;
7+
};
8+
9+
int main()
10+
{
11+
struct A *p=malloc(sizeof(int));
12+
p->x=0; // OK
13+
p->y=0; // out of bounds
14+
15+
struct A o=*p; // out of bounds
16+
17+
int *p2=malloc(sizeof(int));
18+
p2[0]=0; // OK
19+
p2[1]=0; // out of bounds
20+
21+
++p2;
22+
p2[0]=0; // out of bounds
23+
24+
return 0;
25+
}

regression/cbmc/Malloc23/test.desc

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE
2+
main.c
3+
--pointer-check
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
pointer outside dynamic object bounds in \*p: FAILURE
7+
pointer outside dynamic object bounds in \*p: FAILURE
8+
pointer outside dynamic object bounds in p2\[(signed long int)1\]: FAILURE
9+
pointer outside dynamic object bounds in p2\[(signed long int)0\]: FAILURE
10+
\*\* 4 of 36 failed (3 iterations)
11+
--
12+
^warning: ignoring

regression/cbmc/Pointer_byte_extract5/test.desc

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ main.c
33
--bounds-check --32
44
^EXIT=10$
55
^SIGNAL=0$
6-
^\[main\.array_bounds\.5\] array.List upper bound in .*: FAILURE$
7-
^\*\* 1 of 9 failed (2 iterations)$
6+
array\.List dynamic object upper bound in p->List\[2\]: FAILURE
7+
\*\* 1 of 11 failed (2 iterations)
88
--
99
^warning: ignoring

src/analyses/goto_check.cpp

+94-56
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Author: Daniel Kroening, [email protected]
1818
#include <util/std_types.h>
1919
#include <util/guard.h>
2020
#include <util/base_type.h>
21+
#include <util/pointer_offset_size.h>
2122
#include <util/pointer_predicates.h>
2223
#include <util/cprover_prefix.h>
2324
#include <util/options.h>
@@ -73,7 +74,11 @@ class goto_checkt
7374
void undefined_shift_check(const shift_exprt &expr, const guardt &guard);
7475
void pointer_rel_check(const exprt &expr, const guardt &guard);
7576
void pointer_overflow_check(const exprt &expr, const guardt &guard);
76-
void pointer_validity_check(const dereference_exprt &expr, const guardt &guard);
77+
void pointer_validity_check(
78+
const dereference_exprt &expr,
79+
const guardt &guard,
80+
const exprt &access_lb,
81+
const exprt &access_ub);
7782
void integer_overflow_check(const exprt &expr, const guardt &guard);
7883
void conversion_check(const exprt &expr, const guardt &guard);
7984
void float_overflow_check(const exprt &expr, const guardt &guard);
@@ -966,7 +971,9 @@ Function: goto_checkt::pointer_validity_check
966971

967972
void goto_checkt::pointer_validity_check(
968973
const dereference_exprt &expr,
969-
const guardt &guard)
974+
const guardt &guard,
975+
const exprt &access_lb,
976+
const exprt &access_ub)
970977
{
971978
if(!enable_pointer_check)
972979
return;
@@ -1029,63 +1036,62 @@ void goto_checkt::pointer_validity_check(
10291036
expr,
10301037
guard);
10311038

1032-
if(mode != ID_java)
1033-
{
1034-
if(flags.is_unknown() || flags.is_dynamic_heap())
1035-
add_guarded_claim(
1036-
not_exprt(deallocated(pointer, ns)),
1037-
"dereference failure: deallocated dynamic object",
1038-
"pointer dereference",
1039-
expr.find_source_location(),
1040-
expr,
1041-
guard);
1039+
if(flags.is_unknown() || flags.is_dynamic_heap())
1040+
add_guarded_claim(
1041+
not_exprt(deallocated(pointer, ns)),
1042+
"dereference failure: deallocated dynamic object",
1043+
"pointer dereference",
1044+
expr.find_source_location(),
1045+
expr,
1046+
guard);
10421047

1043-
if(flags.is_unknown() || flags.is_dynamic_local())
1044-
add_guarded_claim(
1045-
not_exprt(dead_object(pointer, ns)),
1046-
"dereference failure: dead object",
1047-
"pointer dereference",
1048-
expr.find_source_location(),
1049-
expr,
1050-
guard);
1051-
}
1048+
if(flags.is_unknown() || flags.is_dynamic_local())
1049+
add_guarded_claim(
1050+
not_exprt(dead_object(pointer, ns)),
1051+
"dereference failure: dead object",
1052+
"pointer dereference",
1053+
expr.find_source_location(),
1054+
expr,
1055+
guard);
10521056

1053-
if(enable_bounds_check)
1057+
if(flags.is_unknown() || flags.is_dynamic_heap())
10541058
{
1055-
if(flags.is_unknown() || flags.is_dynamic_heap())
1056-
{
1057-
exprt dynamic_bounds=
1058-
or_exprt(dynamic_object_lower_bound(pointer),
1059-
dynamic_object_upper_bound(pointer, dereference_type, ns));
1059+
exprt dynamic_bounds=
1060+
or_exprt(dynamic_object_lower_bound(pointer, ns, access_lb),
1061+
dynamic_object_upper_bound(
1062+
pointer,
1063+
dereference_type,
1064+
ns,
1065+
access_ub));
10601066

1061-
add_guarded_claim(
1062-
implies_exprt(malloc_object(pointer, ns), not_exprt(dynamic_bounds)),
1063-
"dereference failure: dynamic object bounds",
1064-
"pointer dereference",
1065-
expr.find_source_location(),
1066-
expr,
1067-
guard);
1068-
}
1067+
add_guarded_claim(
1068+
implies_exprt(malloc_object(pointer, ns), not_exprt(dynamic_bounds)),
1069+
"dereference failure: pointer outside dynamic object bounds",
1070+
"pointer dereference",
1071+
expr.find_source_location(),
1072+
expr,
1073+
guard);
10691074
}
10701075

1071-
if(enable_bounds_check)
1076+
if(flags.is_unknown() ||
1077+
flags.is_dynamic_local() ||
1078+
flags.is_static_lifetime())
10721079
{
1073-
if(flags.is_unknown() ||
1074-
flags.is_dynamic_local() ||
1075-
flags.is_static_lifetime())
1076-
{
1077-
exprt object_bounds=
1078-
or_exprt(object_lower_bound(pointer),
1079-
object_upper_bound(pointer, dereference_type, ns));
1080+
exprt object_bounds=
1081+
or_exprt(object_lower_bound(pointer, ns, access_lb),
1082+
object_upper_bound(
1083+
pointer,
1084+
dereference_type,
1085+
ns,
1086+
access_ub));
10801087

1081-
add_guarded_claim(
1082-
or_exprt(dynamic_object(pointer), not_exprt(object_bounds)),
1083-
"dereference failure: object bounds",
1084-
"pointer dereference",
1085-
expr.find_source_location(),
1086-
expr,
1087-
guard);
1088-
}
1088+
add_guarded_claim(
1089+
or_exprt(dynamic_object(pointer), not_exprt(object_bounds)),
1090+
"dereference failure: pointer outside object bounds",
1091+
"pointer dereference",
1092+
expr.find_source_location(),
1093+
expr,
1094+
guard);
10891095
}
10901096
}
10911097
}
@@ -1133,7 +1139,7 @@ void goto_checkt::bounds_check(
11331139
typet array_type=ns.follow(expr.array().type());
11341140

11351141
if(array_type.id()==ID_pointer)
1136-
return; // done by the pointer code
1142+
throw "index got pointer as array type";
11371143
else if(array_type.id()==ID_incomplete_array)
11381144
throw "index got incomplete array";
11391145
else if(array_type.id()!=ID_array && array_type.id()!=ID_vector)
@@ -1193,6 +1199,8 @@ void goto_checkt::bounds_check(
11931199
}
11941200
}
11951201

1202+
exprt type_matches_size=true_exprt();
1203+
11961204
if(ode.root_object().id()==ID_dereference)
11971205
{
11981206
const exprt &pointer=
@@ -1218,13 +1226,18 @@ void goto_checkt::bounds_check(
12181226

12191227
add_guarded_claim(
12201228
precond,
1221-
name+" upper bound",
1229+
name+" dynamic object upper bound",
12221230
"array bounds",
12231231
expr.find_source_location(),
12241232
expr,
12251233
guard);
12261234

1227-
return;
1235+
exprt type_size=size_of_expr(ode.root_object().type(), ns);
1236+
if(type_size.is_not_nil())
1237+
type_matches_size=
1238+
equal_exprt(
1239+
size,
1240+
typecast_exprt(type_size, size.type()));
12281241
}
12291242

12301243
const exprt &size=array_type.id()==ID_array ?
@@ -1257,7 +1270,7 @@ void goto_checkt::bounds_check(
12571270
inequality.op1().make_typecast(inequality.op0().type());
12581271

12591272
add_guarded_claim(
1260-
inequality,
1273+
implies_exprt(type_matches_size, inequality),
12611274
name+" upper bound",
12621275
"array bounds",
12631276
expr.find_source_location(),
@@ -1430,6 +1443,27 @@ void goto_checkt::check_rec(
14301443

14311444
return;
14321445
}
1446+
else if(expr.id()==ID_member &&
1447+
to_member_expr(expr).struct_op().id()==ID_dereference)
1448+
{
1449+
const member_exprt &member=to_member_expr(expr);
1450+
const dereference_exprt &deref=
1451+
to_dereference_expr(member.struct_op());
1452+
1453+
check_rec(deref.op0(), guard, false);
1454+
1455+
exprt access_ub=nil_exprt();
1456+
1457+
exprt member_offset=member_offset_expr(member, ns);
1458+
exprt size=size_of_expr(expr.type(), ns);
1459+
1460+
if(member_offset.is_not_nil() && size.is_not_nil())
1461+
access_ub=plus_exprt(member_offset, size);
1462+
1463+
pointer_validity_check(deref, guard, member_offset, access_ub);
1464+
1465+
return;
1466+
}
14331467

14341468
forall_operands(it, expr)
14351469
check_rec(*it, guard, false);
@@ -1487,7 +1521,11 @@ void goto_checkt::check_rec(
14871521
expr.id()==ID_ge || expr.id()==ID_gt)
14881522
pointer_rel_check(expr, guard);
14891523
else if(expr.id()==ID_dereference)
1490-
pointer_validity_check(to_dereference_expr(expr), guard);
1524+
pointer_validity_check(
1525+
to_dereference_expr(expr),
1526+
guard,
1527+
nil_exprt(),
1528+
size_of_expr(expr.type(), ns));
14911529
}
14921530

14931531
/*******************************************************************\

src/pointer-analysis/value_set_dereference.cpp

+11-2
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,11 @@ value_set_dereferencet::valuet value_set_dereferencet::build_reference_to(
425425
// check lower bound
426426
guardt tmp_guard(guard);
427427
tmp_guard.add(is_malloc_object);
428-
tmp_guard.add(dynamic_object_lower_bound(pointer_expr));
428+
tmp_guard.add(
429+
dynamic_object_lower_bound(
430+
pointer_expr,
431+
ns,
432+
nil_exprt()));
429433
dereference_callback.dereference_failure(
430434
"pointer dereference",
431435
"dynamic object lower bound", tmp_guard);
@@ -439,7 +443,12 @@ value_set_dereferencet::valuet value_set_dereferencet::build_reference_to(
439443

440444
guardt tmp_guard(guard);
441445
tmp_guard.add(is_malloc_object);
442-
tmp_guard.add(dynamic_object_upper_bound(pointer_expr, dereference_type, ns));
446+
tmp_guard.add(
447+
dynamic_object_upper_bound(
448+
pointer_expr,
449+
dereference_type,
450+
ns,
451+
size_of_expr(dereference_type, ns)));
443452
dereference_callback.dereference_failure(
444453
"pointer dereference",
445454
"dynamic object upper bound", tmp_guard);

0 commit comments

Comments
 (0)