Skip to content

Commit e05d813

Browse files
committed
Change goto_checkt::address_check() dynamic memory bounds checking
This changes the dynamic memory bounds checking predicate in address_check(). It now uses OBJECT_SIZE() instead of the variables __CPROVER_malloc_size and __CPROVER_malloc_object that are set in the malloc() model. This also means that the predicates __CPROVER_r_ok()/__CPROVER_w_ok() will be more precise. In the previous approach, the following assertion could not be proven for example: void main() { char *c = malloc(1); assert(!__CPROVER_r_ok(c, 2)); }
1 parent cd2c65b commit e05d813

File tree

9 files changed

+134
-4
lines changed

9 files changed

+134
-4
lines changed

regression/cbmc/r_w_ok5/main.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
void main()
5+
{
6+
char c[2];
7+
assert(__CPROVER_r_ok(c, 2));
8+
assert(!__CPROVER_r_ok(c, 2));
9+
assert(__CPROVER_r_ok(c, 3));
10+
assert(!__CPROVER_r_ok(c, 3));
11+
12+
char *p = malloc(2);
13+
assert(__CPROVER_r_ok(c, 2));
14+
assert(!__CPROVER_r_ok(c, 2));
15+
assert(__CPROVER_r_ok(p, 3));
16+
assert(!__CPROVER_r_ok(p, 3));
17+
}

regression/cbmc/r_w_ok5/test.desc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
CORE
2+
main.c
3+
4+
\[main.assertion.1\] .*: SUCCESS
5+
\[main.assertion.2\] .*: FAILURE
6+
\[main.assertion.3\] .*: FAILURE
7+
\[main.assertion.4\] .*: SUCCESS
8+
\[main.assertion.5\] .*: SUCCESS
9+
\[main.assertion.6\] .*: FAILURE
10+
\[main.assertion.7\] .*: FAILURE
11+
\[main.assertion.8\] .*: SUCCESS
12+
^EXIT=10$
13+
^SIGNAL=0$
14+
--
15+
^warning: ignoring

regression/cbmc/r_w_ok6/main.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
void main()
5+
{
6+
char *p;
7+
int choice;
8+
9+
if(choice)
10+
{
11+
p = malloc(2);
12+
}
13+
else
14+
{
15+
p = malloc(3);
16+
}
17+
18+
assert(__CPROVER_r_ok(p, 2));
19+
assert(!__CPROVER_r_ok(p, 2));
20+
21+
assert(__CPROVER_r_ok(p, 3));
22+
assert(!__CPROVER_r_ok(p, 3));
23+
24+
assert(__CPROVER_r_ok(p, 4));
25+
assert(!__CPROVER_r_ok(p, 4));
26+
}

regression/cbmc/r_w_ok6/test.desc

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+
4+
\[main.assertion.1\] .*: SUCCESS
5+
\[main.assertion.2\] .*: FAILURE
6+
\[main.assertion.3\] .*: FAILURE
7+
\[main.assertion.4\] .*: FAILURE
8+
\[main.assertion.5\] .*: FAILURE
9+
\[main.assertion.6\] .*: SUCCESS
10+
^EXIT=10$
11+
^SIGNAL=0$
12+
--
13+
^warning: ignoring
14+
--
15+
This test checks that __CPROVER_r_ok() gives the correct result when the given
16+
pointer can point to different memory segments of different sizes

regression/cbmc/r_w_ok7/main.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#include <assert.h>
2+
#include <stdint.h>
3+
#include <stdlib.h>
4+
5+
int main()
6+
{
7+
size_t x;
8+
size_t y;
9+
uint8_t *a;
10+
11+
__CPROVER_assume(x > 0);
12+
__CPROVER_assume(y > x);
13+
14+
a = malloc(sizeof(uint8_t) * x);
15+
16+
assert(__CPROVER_w_ok(a, x));
17+
assert(!__CPROVER_w_ok(a, y));
18+
}

regression/cbmc/r_w_ok7/test.desc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE
2+
main.c
3+
4+
\[main.assertion.1\] .*: SUCCESS
5+
\[main.assertion.2\] .*: SUCCESS
6+
VERIFICATION SUCCESSFUL
7+
^EXIT=0$
8+
^SIGNAL=0$
9+
--
10+
^warning: ignoring
11+
--
12+
This test checks that __CPROVER_r_ok() works with nondet sizes

regression/cbmc/r_w_ok8/main.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
int main()
5+
{
6+
int *x = malloc(2);
7+
int *y = malloc(2);
8+
assert(!__CPROVER_r_ok(x, 3));
9+
assert(__CPROVER_r_ok(x, 3) == __CPROVER_r_ok(y, 3));
10+
}

regression/cbmc/r_w_ok8/test.desc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
CORE
2+
main.c
3+
4+
\[main.assertion.1\] .*: SUCCESS
5+
\[main.assertion.2\] .*: SUCCESS
6+
VERIFICATION SUCCESSFUL
7+
^EXIT=0$
8+
^SIGNAL=0$
9+
--
10+
^warning: ignoring
11+
--
12+
This test checks that two usages of the primitive __CPROVER_r_ok() can be false
13+
simultaneously in the encoding of the program. Previously, at most one call
14+
could be false at a time. This was imprecise, however, it was sufficient to
15+
guarantee soundness when the __CPROVER_r_ok() primitive was used directly in an
16+
assertion (i.e., as assert(__CPROVER_r_ok(p, size)). See issue #5194.

src/analyses/goto_check.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,15 +1249,15 @@ goto_checkt::address_check(const exprt &address, const exprt &size)
12491249

12501250
if(flags.is_unknown() || flags.is_dynamic_heap())
12511251
{
1252-
const or_exprt dynamic_bounds_violation(
1253-
dynamic_object_lower_bound(address, nil_exprt()),
1254-
dynamic_object_upper_bound(address, ns, size));
1252+
const or_exprt object_bounds_violation(
1253+
object_lower_bound(address, nil_exprt()),
1254+
object_upper_bound(address, size));
12551255

12561256
conditions.push_back(conditiont(
12571257
or_exprt(
12581258
in_bounds_of_some_explicit_allocation,
12591259
implies_exprt(
1260-
malloc_object(address, ns), not_exprt(dynamic_bounds_violation))),
1260+
dynamic_object(address), not_exprt(object_bounds_violation))),
12611261
"pointer outside dynamic object bounds"));
12621262
}
12631263

0 commit comments

Comments
 (0)