Skip to content

Commit 3acdb52

Browse files
committed
Perform pointer validity checks when doing pointer arithmetic
Arithmetic over pointers requires that they point to valid objects (or one past the end of an object). The test uncovered two further problems: 1) there was a typo in subtraction handling in bv_pointerst; 2) redundant assertions are removed, even when they refer to different expressions. Fixes: #5426
1 parent 751c986 commit 3acdb52

File tree

7 files changed

+61
-9
lines changed

7 files changed

+61
-9
lines changed

regression/cbmc/pointer-overflow1/main.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ int main()
1111
p2 = p - other1;
1212
p2 = p - other2 - other1;
1313

14-
p2 = p + sizeof(int);
15-
p2 = p + sizeof(int) + sizeof(int);
14+
p2 = (char *)p + sizeof(int);
15+
p2 = (char *)p + sizeof(int) + sizeof(int);
1616

1717
return 0;
1818
}

regression/cbmc/pointer-overflow1/test.desc

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@ main.c
33
--pointer-overflow-check --unsigned-overflow-check
44
^EXIT=10$
55
^SIGNAL=0$
6-
^\[main\.overflow\.\d+\] line \d+ (pointer )?arithmetic overflow on .*sizeof\(signed int\) .* : SUCCESS
6+
^\[main\.overflow\.\d+\] line 8 (pointer )?arithmetic overflow on .*: FAILURE
7+
^\[main\.overflow\.\d+\] line 9 (pointer )?arithmetic overflow on .*: FAILURE
8+
^\[main\.overflow\.\d+\] line 10 (pointer )?arithmetic overflow on .*: FAILURE
9+
^\[main\.overflow\.\d+\] line 11 (pointer )?arithmetic overflow on .*: FAILURE
10+
^\[main\.overflow\.\d+\] line 12 (pointer )?arithmetic overflow on .*: FAILURE
711
^VERIFICATION FAILED$
8-
^\*\* 8 of 13 failed
912
--
10-
^\[main\.overflow\.\d+\] line \d+ (pointer )?arithmetic overflow on .*sizeof\(signed int\) .* : FAILURE
13+
^\[main\.overflow\.\d+\] line 1[45] (pointer )?arithmetic overflow on .*sizeof\(signed int\) .* : FAILURE
1114
^warning: ignoring

regression/cbmc/pointer-overflow2/main.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22

33
void main()
44
{
5+
__CPROVER_allocated_memory(9, sizeof(char));
56
char *p = (char *)10;
67
p -= 1;
78
p += 1;
8-
p += -1; // spurious pointer overflow report
9-
p -= -1; // spurious pointer overflow report
9+
p += -1; // previously: spurious pointer overflow report
10+
p -= -1; // previously: spurious pointer overflow report
1011
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#include <stdlib.h>
2+
3+
int main()
4+
{
5+
int *p = malloc(sizeof(int) * 5);
6+
int *p2 = p + 10; // undefined behavior for indexing out of bounds
7+
int *p3 = p - 10; // undefined behavior for indexing out of bounds
8+
9+
int arr[5];
10+
int *p4 = arr + 10; // undefined behavior for indexing out of bounds
11+
int *p5 = arr - 10; // undefined behavior for indexing out of bounds
12+
return 0;
13+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
CORE broken-smt-backend
2+
main.c
3+
--pointer-overflow-check --no-simplify
4+
^\[main.pointer_arithmetic.\d+\] line 6 pointer arithmetic: pointer outside dynamic object bounds in p \+ \(signed (long (long )?)?int\)10: FAILURE
5+
^\[main.pointer_arithmetic.\d+\] line 7 pointer arithmetic: pointer outside dynamic object bounds in p - \(signed (long (long )?)?int\)10: FAILURE
6+
^\[main.pointer_arithmetic.\d+\] line 10 pointer arithmetic: pointer outside object bounds in arr \+ \(signed (long (long )?)?int\)10: FAILURE
7+
^\[main.pointer_arithmetic.\d+\] line 11 pointer arithmetic: pointer outside object bounds in arr - \(signed (long (long )?)?int\)10: FAILURE
8+
^\*\* 4 of \d+ failed
9+
^VERIFICATION FAILED$
10+
^EXIT=10$
11+
^SIGNAL=0$
12+
--
13+
^warning: ignoring
14+
Invariant check failed
15+
--
16+
Uses --no-simplify to avoid removing repeated ASSERT FALSE statements.

src/analyses/goto_check.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,8 +286,12 @@ class goto_checkt
286286
void goto_checkt::collect_allocations(
287287
const goto_functionst &goto_functions)
288288
{
289-
if(!enable_pointer_check && !enable_bounds_check)
289+
if(
290+
!enable_pointer_check && !enable_bounds_check &&
291+
!enable_pointer_overflow_check)
292+
{
290293
return;
294+
}
291295

292296
for(const auto &gf_entry : goto_functions.function_map)
293297
{
@@ -1172,6 +1176,21 @@ void goto_checkt::pointer_overflow_check(
11721176
expr.find_source_location(),
11731177
expr,
11741178
guard);
1179+
1180+
// the result must be within object bounds or one past the end
1181+
const auto size = from_integer(0, size_type());
1182+
auto conditions = get_pointer_dereferenceable_conditions(expr, size);
1183+
1184+
for(const auto &c : conditions)
1185+
{
1186+
add_guarded_property(
1187+
c.assertion,
1188+
"pointer arithmetic: " + c.description,
1189+
"pointer arithmetic",
1190+
expr.find_source_location(),
1191+
expr,
1192+
guard);
1193+
}
11751194
}
11761195

11771196
void goto_checkt::pointer_validity_check(

src/solvers/flattening/bv_pointers.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ bvt bv_pointerst::convert_pointer_type(const exprt &expr)
506506

507507
const bvt &bv = convert_bv(minus_expr.lhs());
508508

509-
typet pointer_sub_type = minus_expr.rhs().type().subtype();
509+
typet pointer_sub_type = minus_expr.lhs().type().subtype();
510510
mp_integer element_size;
511511

512512
if(pointer_sub_type.id()==ID_empty)

0 commit comments

Comments
 (0)