Skip to content

Commit 3701933

Browse files
author
Remi Delmas
committed
CAR inclusion checking optimisation:
- Readable names for instrumentation variables - Use pointer offsets in CAR bounds checking instead of whole pointers - Disable pointer, pointer-overflow and pointer-primitive checks on CAR inclusion checks - Enable pointer-overflow checks on CAR upperbound computation
1 parent d0e6b9a commit 3701933

File tree

36 files changed

+886
-198
lines changed

36 files changed

+886
-198
lines changed

doc/cprover-manual/properties.md

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -134,21 +134,64 @@ As all of these checks apply across the entire input program, we may wish to
134134
disable them for selected statements in the program. For example, unsigned
135135
overflows can be expected and acceptable in certain instructions even when
136136
elsewhere we do not expect them. As of version 5.12, CBMC supports selectively
137-
disabling automatically generated properties. To disable property generation,
138-
use `#pragma CPROVER check disable "<name_of_check>"`, which remains in effect
139-
until a `#pragma CPROVER check pop` (to re-enable all properties
140-
disabled before or since the last `#pragma CPROVER check push`) is provided.
137+
disabling or enabling automatically generated properties using pragmas.
138+
139+
140+
CPROVER pragmas are handled using a stack:
141+
- `#pragma CPROVER check push` pushes a new level on the pragma stack
142+
- `#pragma CPROVER check disable "<name_of_check>"` adds a disable pragma at the top of the stack
143+
- `#pragma CPROVER check enable "<name_of_check>"` adds a enable pragma at the top of the stack
144+
- an `enable` or `disable` pragma for a given check present at the top level of the stack shadows other pragmas for the same in lower levels of the stack
145+
- adding both `enable` and `disable` pragmas for a same check in a same level of the stack creates a PARSING_ERROR.
146+
- `#pragma CPROVER check pop` pops a level in the stack and restores the state of pragmas at the sub level
147+
141148
For example, for unsigned overflow checks, use
149+
150+
```
151+
unsigned foo(unsigned x)
152+
{
153+
#pragma CPROVER check push
154+
#pragma CPROVER check enable "unsigned-overflow"
155+
x = x + 1; // immediately follows the pragma, unsigned overflow check apply here
156+
#pragma CPROVER check pop
157+
x = x + 2; // unsigned overflow checks do not apply here
158+
```
159+
160+
```
161+
unsigned foo(unsigned x)
162+
{
163+
#pragma CPROVER check push
164+
#pragma CPROVER check enable "unsigned-overflow"
165+
#pragma CPROVER check enable "signed-overflow"
166+
x = x + 1; // unsigned and signed overflow check apply here
167+
#pragma CPROVER check push
168+
#pragma CPROVER check disable "unsigned-overflow"
169+
x = x + 2; // only signed overflow check apply here
170+
#pragma CPROVER check pop
171+
x = x + 3; // unsigned and signed overflow check apply here
172+
#pragma CPROVER check pop
173+
x = x + 2; // unsigned overflow checks do not apply here
174+
```
175+
142176
```
143177
unsigned foo(unsigned x)
144178
{
145179
#pragma CPROVER check push
180+
#pragma CPROVER check enable "unsigned-overflow"
181+
#pragma CPROVER check enable "signed-overflow"
182+
x = x + 1; // unsigned and signed overflow check apply here
183+
#pragma CPROVER check push
146184
#pragma CPROVER check disable "unsigned-overflow"
147-
x = x + 1; // immediately follows the pragma, no unsigned overflow check here
185+
#pragma CPROVER check enable "unsigned-overflow"
186+
// PARSING_ERROR ... Found enable and disable pragmas for unsigned-overflow-check
187+
x = x + 2;
188+
#pragma CPROVER check pop
189+
x = x + 3;
148190
#pragma CPROVER check pop
149-
x = x + 2; // unsigned overflow checks are generated here
191+
x = x + 2;
150192
```
151193
194+
152195
#### Flag --nan-check limitations
153196
154197
Please note that `--nan-check` flag is adding not-a-number checks only for

jbmc/src/janalyzer/janalyzer_parse_options.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,11 @@ void janalyzer_parse_optionst::process_goto_function(
705705

706706
// add generic checks
707707
goto_check(
708-
function.get_function_id(), function.get_goto_function(), ns, options);
708+
function.get_function_id(),
709+
function.get_goto_function(),
710+
ns,
711+
options,
712+
log.get_message_handler());
709713
}
710714

711715
bool janalyzer_parse_optionst::can_generate_function_body(const irep_idt &name)

jbmc/src/jbmc/jbmc_parse_options.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -812,7 +812,11 @@ void jbmc_parse_optionst::process_goto_function(
812812

813813
// add generic checks
814814
goto_check(
815-
function.get_function_id(), function.get_goto_function(), ns, options);
815+
function.get_function_id(),
816+
function.get_goto_function(),
817+
ns,
818+
options,
819+
log.get_message_handler());
816820

817821
// Replace Java new side effects
818822
remove_java_new(

jbmc/src/jdiff/jdiff_parse_options.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ bool jdiff_parse_optionst::process_goto_program(
278278

279279
// add generic checks
280280
log.status() << "Generic Property Instrumentation" << messaget::eom;
281-
goto_check(options, goto_model);
281+
goto_check(options, goto_model, log.get_message_handler());
282282

283283
// checks don't know about adjusted float expressions
284284
adjust_float_expressions(goto_model);
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
int main()
2+
{
3+
int x;
4+
int y[1];
5+
6+
#pragma CPROVER check push
7+
#pragma CPROVER check enable "bounds"
8+
#pragma CPROVER check enable "signed-overflow"
9+
// generate assertions for the following statement
10+
x = x + y[1];
11+
// pop all annotations
12+
#pragma CPROVER check pop
13+
// but do not generate assertions for this one
14+
x = y[1];
15+
return x;
16+
}
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\.array_bounds\.1\] line \d+ array 'y' upper bound.*FAILURE$
5+
^\[main\.overflow\.1\] line \d+ arithmetic overflow on signed.*FAILURE$
6+
^\*\* 2 of 2 failed
7+
^VERIFICATION FAILED$
8+
^EXIT=10$
9+
^SIGNAL=0$
10+
--
11+
--
12+
Checks that we can selectively activate checks using pragmas.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
int foo(int x)
2+
{
3+
return x;
4+
}
5+
6+
int main()
7+
{
8+
int m, n;
9+
10+
#pragma CPROVER check push
11+
#pragma CPROVER check enable "signed-overflow"
12+
// generate assertions for the following statements
13+
int x = m = n + n;
14+
++n;
15+
n++;
16+
n += 1;
17+
foo(x + n);
18+
// pop all annotations
19+
#pragma CPROVER check pop
20+
// but do not generate assertions for these
21+
x = n + n;
22+
foo(x + n);
23+
return x;
24+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
CORE
2+
main.c
3+
4+
^\[main\.overflow\.1\] line 13 arithmetic overflow on signed \+ in n \+ n: FAILURE$
5+
^\[main\.overflow\.2\] line 14 arithmetic overflow on signed \+ in n \+ 1: FAILURE$
6+
^\[main\.overflow\.3\] line 15 arithmetic overflow on signed \+ in n \+ 1: FAILURE$
7+
^\[main\.overflow\.4\] line 16 arithmetic overflow on signed \+ in n \+ 1: FAILURE$
8+
^\[main\.overflow\.5\] line 17 arithmetic overflow on signed \+ in x \+ n: FAILURE$
9+
^\*\* 5 of 5 failed
10+
^VERIFICATION FAILED$
11+
^EXIT=10$
12+
^SIGNAL=0$
13+
--
14+
^warning: ignoring
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#include <stdlib.h>
2+
3+
int main()
4+
{
5+
char *p = malloc(sizeof(*p));
6+
char *q;
7+
8+
#pragma CPROVER check push
9+
#pragma CPROVER check enable "pointer-primitive"
10+
// generate checks for the following statements and fail
11+
if(__CPROVER_same_object(p, q))
12+
{
13+
}
14+
#pragma CPROVER check pop
15+
16+
// but do not generate checks on the following statements
17+
if(__CPROVER_same_object(p, q))
18+
{
19+
}
20+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
CORE
2+
main.c
3+
4+
^main.c function main$
5+
^\[main.pointer_primitives.\d+\] line 11 pointer invalid in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
6+
^\[main.pointer_primitives.\d+\] line 11 deallocated dynamic object in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
7+
^\[main.pointer_primitives.\d+\] line 11 dead object in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
8+
^\[main.pointer_primitives.\d+\] line 11 pointer outside object bounds in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
9+
^\[main.pointer_primitives.\d+\] line 11 pointer invalid in POINTER_OBJECT\(\(const void \*\)q\): FAILURE$
10+
^\[main.pointer_primitives.\d+\] line 11 deallocated dynamic object in POINTER_OBJECT\(\(const void \*\)q\): SUCCESS$
11+
^\[main.pointer_primitives.\d+\] line 11 dead object in POINTER_OBJECT\(\(const void \*\)q\): SUCCESS$
12+
^\[main.pointer_primitives.\d+\] line 11 pointer outside object bounds in POINTER_OBJECT\(\(const void \*\)q\): FAILURE$
13+
^VERIFICATION FAILED$
14+
^EXIT=10$
15+
^SIGNAL=0$
16+
--
17+
^\[main.pointer_primitives.\d+\] line 17
18+
--
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#include <stdlib.h>
2+
3+
int main()
4+
{
5+
char *p = malloc(sizeof(*p));
6+
char *q;
7+
8+
#pragma CPROVER check push
9+
#pragma CPROVER check enable "pointer-primitive"
10+
// must generate checks
11+
if(__CPROVER_same_object(p, q))
12+
{
13+
}
14+
#pragma CPROVER check push
15+
#pragma CPROVER check disable "pointer-primitive"
16+
// must not generate checks
17+
if(__CPROVER_same_object(p, q))
18+
{
19+
}
20+
#pragma CPROVER check push
21+
#pragma CPROVER check enable "pointer-primitive"
22+
// must generate checks
23+
if(__CPROVER_same_object(p, q))
24+
{
25+
}
26+
#pragma CPROVER check pop
27+
// must not generate generate checks
28+
if(__CPROVER_same_object(p, q))
29+
{
30+
}
31+
#pragma CPROVER check pop
32+
// must generate generate checks
33+
if(__CPROVER_same_object(p, q))
34+
{
35+
}
36+
#pragma CPROVER check pop
37+
// must not generate generate checks
38+
if(__CPROVER_same_object(p, q))
39+
{
40+
}
41+
return 0;
42+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
CORE
2+
main.c
3+
4+
^main.c function main$
5+
^\[main.pointer_primitives.\d+\] line 11 pointer invalid in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
6+
^\[main.pointer_primitives.\d+\] line 11 deallocated dynamic object in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
7+
^\[main.pointer_primitives.\d+\] line 11 dead object in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
8+
^\[main.pointer_primitives.\d+\] line 11 pointer outside object bounds in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
9+
^\[main.pointer_primitives.\d+\] line 11 pointer invalid in POINTER_OBJECT\(\(const void \*\)q\): FAILURE$
10+
^\[main.pointer_primitives.\d+\] line 11 deallocated dynamic object in POINTER_OBJECT\(\(const void \*\)q\): SUCCESS$
11+
^\[main.pointer_primitives.\d+\] line 11 dead object in POINTER_OBJECT\(\(const void \*\)q\): SUCCESS$
12+
^\[main.pointer_primitives.\d+\] line 11 pointer outside object bounds in POINTER_OBJECT\(\(const void \*\)q\): FAILURE$
13+
^\[main.pointer_primitives.\d+\] line 23 pointer invalid in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
14+
^\[main.pointer_primitives.\d+\] line 23 deallocated dynamic object in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
15+
^\[main.pointer_primitives.\d+\] line 23 dead object in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
16+
^\[main.pointer_primitives.\d+\] line 23 pointer outside object bounds in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
17+
^\[main.pointer_primitives.\d+\] line 23 pointer invalid in POINTER_OBJECT\(\(const void \*\)q\): FAILURE$
18+
^\[main.pointer_primitives.\d+\] line 23 deallocated dynamic object in POINTER_OBJECT\(\(const void \*\)q\): SUCCESS$
19+
^\[main.pointer_primitives.\d+\] line 23 dead object in POINTER_OBJECT\(\(const void \*\)q\): SUCCESS$
20+
^\[main.pointer_primitives.\d+\] line 23 pointer outside object bounds in POINTER_OBJECT\(\(const void \*\)q\): FAILURE$
21+
^\[main.pointer_primitives.\d+\] line 33 pointer invalid in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
22+
^\[main.pointer_primitives.\d+\] line 33 deallocated dynamic object in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
23+
^\[main.pointer_primitives.\d+\] line 33 dead object in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
24+
^\[main.pointer_primitives.\d+\] line 33 pointer outside object bounds in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
25+
^\[main.pointer_primitives.\d+\] line 33 pointer invalid in POINTER_OBJECT\(\(const void \*\)q\): FAILURE$
26+
^\[main.pointer_primitives.\d+\] line 33 deallocated dynamic object in POINTER_OBJECT\(\(const void \*\)q\): SUCCESS$
27+
^\[main.pointer_primitives.\d+\] line 33 dead object in POINTER_OBJECT\(\(const void \*\)q\): SUCCESS$
28+
^\[main.pointer_primitives.\d+\] line 33 pointer outside object bounds in POINTER_OBJECT\(\(const void \*\)q\): FAILURE$
29+
^VERIFICATION FAILED$
30+
^EXIT=10$
31+
^SIGNAL=0$
32+
--
33+
^\[main.pointer_primitives.\d+\] line 17
34+
^\[main.pointer_primitives.\d+\] line 28
35+
^\[main.pointer_primitives.\d+\] line 38
36+
--
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#include <stdlib.h>
2+
3+
int main()
4+
{
5+
char *p = malloc(sizeof(*p));
6+
char *q;
7+
8+
#pragma CPROVER check push
9+
#pragma CPROVER check enable "pointer-primitive"
10+
// must generate checks
11+
if(__CPROVER_same_object(p, q))
12+
{
13+
}
14+
#pragma CPROVER check push
15+
#pragma CPROVER check disable "pointer-primitive"
16+
// must not generate checks
17+
if(__CPROVER_same_object(p, q))
18+
{
19+
}
20+
#pragma CPROVER check push
21+
#pragma CPROVER check enable "pointer-primitive"
22+
// must generate checks
23+
if(__CPROVER_same_object(p, q))
24+
{
25+
}
26+
#pragma CPROVER check pop
27+
// must not generate generate checks
28+
if(__CPROVER_same_object(p, q))
29+
{
30+
}
31+
#pragma CPROVER check pop
32+
// must generate generate checks
33+
if(__CPROVER_same_object(p, q))
34+
{
35+
}
36+
#pragma CPROVER check pop
37+
// must generate generate checks
38+
if(__CPROVER_same_object(p, q))
39+
{
40+
}
41+
return 0;
42+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
CORE
2+
main.c
3+
--pointer-primitive-check
4+
^main.c function main$
5+
^\[main.pointer_primitives.\d+\] line 11 pointer invalid in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
6+
^\[main.pointer_primitives.\d+\] line 11 deallocated dynamic object in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
7+
^\[main.pointer_primitives.\d+\] line 11 dead object in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
8+
^\[main.pointer_primitives.\d+\] line 11 pointer outside object bounds in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
9+
^\[main.pointer_primitives.\d+\] line 11 pointer invalid in POINTER_OBJECT\(\(const void \*\)q\): FAILURE$
10+
^\[main.pointer_primitives.\d+\] line 11 deallocated dynamic object in POINTER_OBJECT\(\(const void \*\)q\): SUCCESS$
11+
^\[main.pointer_primitives.\d+\] line 11 dead object in POINTER_OBJECT\(\(const void \*\)q\): SUCCESS$
12+
^\[main.pointer_primitives.\d+\] line 11 pointer outside object bounds in POINTER_OBJECT\(\(const void \*\)q\): FAILURE$
13+
^\[main.pointer_primitives.\d+\] line 23 pointer invalid in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
14+
^\[main.pointer_primitives.\d+\] line 23 deallocated dynamic object in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
15+
^\[main.pointer_primitives.\d+\] line 23 dead object in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
16+
^\[main.pointer_primitives.\d+\] line 23 pointer outside object bounds in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
17+
^\[main.pointer_primitives.\d+\] line 23 pointer invalid in POINTER_OBJECT\(\(const void \*\)q\): FAILURE$
18+
^\[main.pointer_primitives.\d+\] line 23 deallocated dynamic object in POINTER_OBJECT\(\(const void \*\)q\): SUCCESS$
19+
^\[main.pointer_primitives.\d+\] line 23 dead object in POINTER_OBJECT\(\(const void \*\)q\): SUCCESS$
20+
^\[main.pointer_primitives.\d+\] line 23 pointer outside object bounds in POINTER_OBJECT\(\(const void \*\)q\): FAILURE$
21+
^\[main.pointer_primitives.\d+\] line 33 pointer invalid in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
22+
^\[main.pointer_primitives.\d+\] line 33 deallocated dynamic object in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
23+
^\[main.pointer_primitives.\d+\] line 33 dead object in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
24+
^\[main.pointer_primitives.\d+\] line 33 pointer outside object bounds in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
25+
^\[main.pointer_primitives.\d+\] line 33 pointer invalid in POINTER_OBJECT\(\(const void \*\)q\): FAILURE$
26+
^\[main.pointer_primitives.\d+\] line 33 deallocated dynamic object in POINTER_OBJECT\(\(const void \*\)q\): SUCCESS$
27+
^\[main.pointer_primitives.\d+\] line 33 dead object in POINTER_OBJECT\(\(const void \*\)q\): SUCCESS$
28+
^\[main.pointer_primitives.\d+\] line 33 pointer outside object bounds in POINTER_OBJECT\(\(const void \*\)q\): FAILURE$
29+
^\[main.pointer_primitives.\d+\] line 38 pointer invalid in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
30+
^\[main.pointer_primitives.\d+\] line 38 deallocated dynamic object in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
31+
^\[main.pointer_primitives.\d+\] line 38 dead object in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
32+
^\[main.pointer_primitives.\d+\] line 38 pointer outside object bounds in POINTER_OBJECT\(\(const void \*\)p\): SUCCESS$
33+
^\[main.pointer_primitives.\d+\] line 38 pointer invalid in POINTER_OBJECT\(\(const void \*\)q\): FAILURE$
34+
^\[main.pointer_primitives.\d+\] line 38 deallocated dynamic object in POINTER_OBJECT\(\(const void \*\)q\): SUCCESS$
35+
^\[main.pointer_primitives.\d+\] line 38 dead object in POINTER_OBJECT\(\(const void \*\)q\): SUCCESS$
36+
^\[main.pointer_primitives.\d+\] line 38 pointer outside object bounds in POINTER_OBJECT\(\(const void \*\)q\): FAILURE$
37+
^VERIFICATION FAILED$
38+
^EXIT=10$
39+
^SIGNAL=0$
40+
--
41+
^\[main.pointer_primitives.\d+\] line 17
42+
^\[main.pointer_primitives.\d+\] line 28
43+
--

0 commit comments

Comments
 (0)