Skip to content

Commit bf54161

Browse files
author
Remi Delmas
committed
Disable unnecessary pointer checks, enable necessary pointer checks in the instrumentation for assigns clause
1 parent e27dba6 commit bf54161

File tree

32 files changed

+738
-127
lines changed

32 files changed

+738
-127
lines changed

doc/cprover-manual/properties.md

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -134,19 +134,73 @@ 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
143+
at the top of the stack
144+
- `#pragma CPROVER check enable "<name_of_check>"` adds a enable pragma
145+
at the top of the stack
146+
- an `enable` or `disable` pragma for a given check present at the top level
147+
of the stack shadows other pragmas for the same in lower levels of the stack
148+
- adding both `enable` and `disable` pragmas for a same check in a same level
149+
of the stack creates a PARSING_ERROR.
150+
- `#pragma CPROVER check pop` pops a level in the stack and restores the state
151+
of pragmas at the sub level
152+
141153
For example, for unsigned overflow checks, use
154+
142155
```
143156
unsigned foo(unsigned x)
144157
{
145158
#pragma CPROVER check push
159+
#pragma CPROVER check enable "unsigned-overflow"
160+
// unsigned overflow check apply here
161+
x = x + 1;
162+
#pragma CPROVER check pop
163+
// unsigned overflow checks do not apply here
164+
x = x + 2;
165+
```
166+
167+
```
168+
unsigned foo(unsigned x)
169+
{
170+
#pragma CPROVER check push
171+
#pragma CPROVER check enable "unsigned-overflow"
172+
#pragma CPROVER check enable "signed-overflow"
173+
// unsigned and signed overflow check apply here
174+
x = x + 1;
175+
#pragma CPROVER check push
146176
#pragma CPROVER check disable "unsigned-overflow"
147-
x = x + 1; // immediately follows the pragma, no unsigned overflow check here
177+
// only signed overflow check apply here
178+
x = x + 2;
179+
#pragma CPROVER check pop
180+
// unsigned and signed overflow check apply here
181+
x = x + 3;
182+
#pragma CPROVER check pop
183+
// unsigned overflow checks do not apply here
184+
x = x + 2;
185+
```
186+
187+
```
188+
unsigned foo(unsigned x)
189+
{
190+
#pragma CPROVER check push
191+
#pragma CPROVER check enable "unsigned-overflow"
192+
#pragma CPROVER check enable "signed-overflow"
193+
// unsigned and signed overflow check apply here
194+
x = x + 1;
195+
#pragma CPROVER check push
196+
#pragma CPROVER check disable "unsigned-overflow"
197+
#pragma CPROVER check enable "unsigned-overflow"
198+
// PARSING_ERROR Found enable and disable pragmas for unsigned-overflow-check
199+
x = x + 2;
200+
#pragma CPROVER check pop
201+
x = x + 3;
148202
#pragma CPROVER check pop
149-
x = x + 2; // unsigned overflow checks are generated here
203+
x = x + 2;
150204
```
151205
152206
#### Flag --nan-check limitations

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+
ui_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+
ui_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, ui_message_handler);
282282

283283
// checks don't know about adjusted float expressions
284284
adjust_float_expressions(goto_model);
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
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+
#pragma CPROVER check pop
12+
// but do not generate assertions for this one
13+
x = y[1];
14+
return x;
15+
}
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: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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+
#pragma CPROVER check pop
19+
// but do not generate assertions for these
20+
x = n + n;
21+
foo(x + n);
22+
return x;
23+
}
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)