Skip to content

Commit 735900a

Browse files
tautschnigDaniel Kroening
authored and
Daniel Kroening
committed
Limit dereferencing checks to actual access size
For member accesses, access to other components need not be valid as shown in the included regression test Malloc23. Also do not require --bounds-check for full dereferencing checks. Fixes #219.
1 parent d8ba38f commit 735900a

File tree

7 files changed

+196
-63
lines changed

7 files changed

+196
-63
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

src/analyses/goto_check.cpp

+68-34
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;
@@ -1047,42 +1054,44 @@ void goto_checkt::pointer_validity_check(
10471054
expr,
10481055
guard);
10491056

1050-
if(enable_bounds_check)
1057+
if(flags.is_unknown() || flags.is_dynamic_heap())
10511058
{
1052-
if(flags.is_unknown() || flags.is_dynamic_heap())
1053-
{
1054-
exprt dynamic_bounds=
1055-
or_exprt(dynamic_object_lower_bound(pointer),
1056-
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));
10571066

1058-
add_guarded_claim(
1059-
implies_exprt(malloc_object(pointer, ns), not_exprt(dynamic_bounds)),
1060-
"dereference failure: dynamic object bounds",
1061-
"pointer dereference",
1062-
expr.find_source_location(),
1063-
expr,
1064-
guard);
1065-
}
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);
10661074
}
10671075

1068-
if(enable_bounds_check)
1076+
if(flags.is_unknown() ||
1077+
flags.is_dynamic_local() ||
1078+
flags.is_static_lifetime())
10691079
{
1070-
if(flags.is_unknown() ||
1071-
flags.is_dynamic_local() ||
1072-
flags.is_static_lifetime())
1073-
{
1074-
exprt object_bounds=
1075-
or_exprt(object_lower_bound(pointer),
1076-
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));
10771087

1078-
add_guarded_claim(
1079-
or_exprt(dynamic_object(pointer), not_exprt(object_bounds)),
1080-
"dereference failure: object bounds",
1081-
"pointer dereference",
1082-
expr.find_source_location(),
1083-
expr,
1084-
guard);
1085-
}
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);
10861095
}
10871096
}
10881097
}
@@ -1130,7 +1139,7 @@ void goto_checkt::bounds_check(
11301139
typet array_type=ns.follow(expr.array().type());
11311140

11321141
if(array_type.id()==ID_pointer)
1133-
return; // done by the pointer code
1142+
throw "index got pointer as array type";
11341143
else if(array_type.id()==ID_incomplete_array)
11351144
throw "index got incomplete array";
11361145
else if(array_type.id()!=ID_array && array_type.id()!=ID_vector)
@@ -1434,6 +1443,27 @@ void goto_checkt::check_rec(
14341443

14351444
return;
14361445
}
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+
}
14371467

14381468
forall_operands(it, expr)
14391469
check_rec(*it, guard, false);
@@ -1491,7 +1521,11 @@ void goto_checkt::check_rec(
14911521
expr.id()==ID_ge || expr.id()==ID_gt)
14921522
pointer_rel_check(expr, guard);
14931523
else if(expr.id()==ID_dereference)
1494-
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));
14951529
}
14961530

14971531
/*******************************************************************\

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);

src/util/pointer_predicates.cpp

+61-22
Original file line numberDiff line numberDiff line change
@@ -241,8 +241,15 @@ exprt good_pointer_def(
241241
exprt good_dynamic_tmp1=
242242
or_exprt(
243243
not_exprt(malloc_object(pointer, ns)),
244-
and_exprt(not_exprt(dynamic_object_lower_bound(pointer)),
245-
not_exprt(dynamic_object_upper_bound(pointer, dereference_type, ns))));
244+
and_exprt(not_exprt(dynamic_object_lower_bound(
245+
pointer,
246+
ns,
247+
nil_exprt())),
248+
not_exprt(dynamic_object_upper_bound(
249+
pointer,
250+
dereference_type,
251+
ns,
252+
size_of_expr(dereference_type, ns)))));
246253

247254
exprt good_dynamic_tmp2=
248255
and_exprt(not_exprt(deallocated(pointer, ns)),
@@ -259,8 +266,12 @@ exprt good_pointer_def(
259266
not_exprt(invalid_pointer(pointer));
260267

261268
exprt bad_other=
262-
or_exprt(object_lower_bound(pointer),
263-
object_upper_bound(pointer, dereference_type, ns));
269+
or_exprt(object_lower_bound(pointer, ns, nil_exprt()),
270+
object_upper_bound(
271+
pointer,
272+
dereference_type,
273+
ns,
274+
size_of_expr(dereference_type, ns)));
264275

265276
exprt good_other=
266277
or_exprt(dynamic_object(pointer),
@@ -357,9 +368,12 @@ Function: dynamic_object_lower_bound
357368
358369
\*******************************************************************/
359370

360-
exprt dynamic_object_lower_bound(const exprt &pointer)
371+
exprt dynamic_object_lower_bound(
372+
const exprt &pointer,
373+
const namespacet &ns,
374+
const exprt &offset)
361375
{
362-
return object_lower_bound(pointer);
376+
return object_lower_bound(pointer, ns, offset);
363377
}
364378

365379
/*******************************************************************\
@@ -377,25 +391,31 @@ Function: dynamic_object_upper_bound
377391
exprt dynamic_object_upper_bound(
378392
const exprt &pointer,
379393
const typet &dereference_type,
380-
const namespacet &ns)
394+
const namespacet &ns,
395+
const exprt &access_size)
381396
{
382397
// this is
383-
// POINTER_OFFSET(p)+size>__CPROVER_malloc_size
398+
// POINTER_OFFSET(p)+access_size>__CPROVER_malloc_size
384399

385400
exprt malloc_size=dynamic_size(ns);
386401

387402
exprt object_offset=pointer_offset(pointer);
388403

389-
exprt size=size_of_expr(dereference_type, ns);
390-
391404
// need to add size
392-
exprt sum=plus_exprt(object_offset, size);
405+
irep_idt op=ID_ge;
406+
exprt sum=object_offset;
407+
408+
if(access_size.is_not_nil())
409+
{
410+
op=ID_gt;
411+
sum=plus_exprt(object_offset, access_size);
412+
}
393413

394414
if(ns.follow(sum.type())!=
395415
ns.follow(malloc_size.type()))
396416
sum.make_typecast(malloc_size.type());
397417

398-
return binary_relation_exprt(sum, ID_gt, malloc_size);
418+
return binary_relation_exprt(sum, op, malloc_size);
399419
}
400420

401421
/*******************************************************************\
@@ -413,25 +433,32 @@ Function: object_upper_bound
413433
exprt object_upper_bound(
414434
const exprt &pointer,
415435
const typet &dereference_type,
416-
const namespacet &ns)
436+
const namespacet &ns,
437+
const exprt &access_size)
417438
{
418439
// this is
419-
// POINTER_OFFSET(p)+size>OBJECT_SIZE(pointer)
440+
// POINTER_OFFSET(p)+access_size>OBJECT_SIZE(pointer)
420441

421442
exprt object_size_expr=object_size(pointer);
422443

423444
exprt object_offset=pointer_offset(pointer);
424445

425-
exprt size=size_of_expr(dereference_type, ns);
426-
427446
// need to add size
428-
exprt sum=plus_exprt(object_offset, size);
447+
irep_idt op=ID_ge;
448+
exprt sum=object_offset;
449+
450+
if(access_size.is_not_nil())
451+
{
452+
op=ID_gt;
453+
sum=plus_exprt(object_offset, access_size);
454+
}
455+
429456

430457
if(ns.follow(sum.type())!=
431458
ns.follow(object_size_expr.type()))
432459
sum.make_typecast(object_size_expr.type());
433460

434-
return binary_relation_exprt(sum, ID_gt, object_size_expr);
461+
return binary_relation_exprt(sum, op, object_size_expr);
435462
}
436463

437464
/*******************************************************************\
@@ -446,12 +473,24 @@ Function: object_lower_bound
446473
447474
\*******************************************************************/
448475

449-
exprt object_lower_bound(const exprt &pointer)
476+
exprt object_lower_bound(
477+
const exprt &pointer,
478+
const namespacet &ns,
479+
const exprt &offset)
450480
{
451-
exprt offset=pointer_offset(pointer);
481+
exprt p_offset=pointer_offset(pointer);
452482

453-
exprt zero=from_integer(0, offset.type());
483+
exprt zero=from_integer(0, p_offset.type());
454484
assert(zero.is_not_nil());
455485

456-
return binary_relation_exprt(offset, ID_lt, zero);
486+
if(offset.is_not_nil())
487+
{
488+
if(ns.follow(p_offset.type())!=ns.follow(offset.type()))
489+
p_offset=
490+
plus_exprt(p_offset, typecast_exprt(offset, p_offset.type()));
491+
else
492+
p_offset=plus_exprt(p_offset, offset);
493+
}
494+
495+
return binary_relation_exprt(p_offset, ID_lt, zero);
457496
}

0 commit comments

Comments
 (0)