Skip to content

Commit 26e58d7

Browse files
zhixing-xutautschnig
authored andcommitted
Loop shrinking
Enables proving properties in selected loops without having to unwind them. Based on "Property Checking Array Programs Using Loop Shrinking" by Shrawan Kumar, Amitabha Sanyal, Venkatesh R and Punit Shah, TACAS 2018.
1 parent 673e247 commit 26e58d7

File tree

24 files changed

+1059
-4
lines changed

24 files changed

+1059
-4
lines changed

jbmc/unit/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ CPROVER_LIBS =../src/java_bytecode/java_bytecode$(LIBEXT) \
126126
$(CPROVER_DIR)/src/goto-instrument/reachability_slicer$(OBJEXT) \
127127
$(CPROVER_DIR)/src/goto-instrument/nondet_static$(OBJEXT) \
128128
$(CPROVER_DIR)/src/goto-instrument/full_slicer$(OBJEXT) \
129+
$(CPROVER_DIR)/src/goto-instrument/abstract_loops$(OBJEXT) \
129130
$(CPROVER_DIR)/src/goto-instrument/unwindset$(OBJEXT) \
130131
$(CPROVER_DIR)/src/pointer-analysis/pointer-analysis$(LIBEXT) \
131132
$(CPROVER_DIR)/src/langapi/langapi$(LIBEXT) \
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#define ROW 10
2+
#define COL 10
3+
4+
void main()
5+
{
6+
int sum;
7+
int image[ROW][COL];
8+
9+
// shrinkable
10+
for(int j = 0; j < COL; j++)
11+
image[0][j] = 0;
12+
13+
sum = 0;
14+
// outer loop unshrinkable
15+
// inner loop shrinkable
16+
for(int i = 0; i < ROW; i++)
17+
{
18+
image[i][0] = 0;
19+
sum = sum + i;
20+
for(int j = 0; j < COL; j++)
21+
image[sum][j] = 0;
22+
}
23+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
CORE
2+
main.c
3+
--bounds-check --pointer-check --abstract-loops --show-goto-functions
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
ASSUME j < 10
7+
ASSUME j >= 0
8+
--
9+
ASSUME i < 10
10+
ASSUME i >= 0
11+
^warning: ignoring
12+
--
13+
This test ensures that the loop with loop variable i is not shrunk (so it
14+
appears in unwinding). Loops with loop variable j are shrunk. The test also
15+
checks the constraints to the loop variable are correctly applied.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#define ROW 3
2+
#define COL 10
3+
4+
void boo(int r)
5+
{
6+
int val = 0;
7+
int image[ROW][COL];
8+
;
9+
// shrinkable, and set as shrink target
10+
for(int j = 0; j < COL; j++)
11+
{
12+
int c = j + val;
13+
image[r][c] = val;
14+
}
15+
}
16+
17+
void main()
18+
{
19+
int r;
20+
int buffer[ROW];
21+
// not shrinkable since r is used in mem-safe assertion in boo()
22+
// and r update itself in loop
23+
for(int i = 0; i < ROW; i++)
24+
{
25+
r = r + i;
26+
boo(r);
27+
buffer[i];
28+
}
29+
30+
// shrinkable
31+
for(int i = 0; i < ROW; i++)
32+
{
33+
boo(i);
34+
buffer[i];
35+
}
36+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
CORE
2+
main.c
3+
--bounds-check --pointer-check --abstract-loops --abstractset boo.0,main.0 --show-goto-functions
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
ASSUME j < 10
7+
ASSUME j >= 0
8+
--
9+
ASSUME i < 10
10+
ASSUME i >= 0
11+
^warning: ignoring
12+
--
13+
This test ensures that the loops with loop variable i are not shrunk (so they
14+
appear in unwinding). Although the second loop in main is shrinkable, it is not
15+
in the target loop set provided by --abstractset, thus it shouldn't be shrunk.
16+
The test also ensures the loop in boo() with loop variable j is shrunk and the
17+
constraints are correctly applied.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#include <stdlib.h>
2+
#define ROW 10
3+
4+
void boo(int *x)
5+
{
6+
*x = *x + 1;
7+
}
8+
9+
void main()
10+
{
11+
int *x = (int *)malloc(sizeof(int));
12+
int buffer[ROW];
13+
*x = 2;
14+
// not shrinkable since x has a self-update in boo()
15+
for(int i = 0; i < ROW; i++)
16+
{
17+
boo(x);
18+
buffer[*x] = 1;
19+
}
20+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
KNOWNBUG
2+
main.c
3+
--bounds-check --pointer-check --abstract-loops --abstractset main.0
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^VERIFICATION FAILED$
7+
main\.0
8+
--
9+
ASSUME i < 10
10+
ASSUME i >= 0
11+
^warning: ignoring
12+
--
13+
This test ensures that the loops with loop variable i are not shrunk (so they
14+
appear in unwinding), even when the instruction that makes the loop unshrinkable
15+
is in another function.
16+
17+
Requires #2646, #2694 to work.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#define ROW 10
2+
#define COL 10
3+
4+
void main()
5+
{
6+
int sum;
7+
int image[ROW][COL];
8+
9+
// shrinkable
10+
for(int j = 0; j < COL; j++)
11+
image[0][j] = 0;
12+
13+
sum = 0;
14+
// outer loop unshrinkable
15+
// inner loop shrinkable
16+
for(int i = 0; i < ROW; i++)
17+
{
18+
image[i][0] = 0;
19+
sum = sum + i;
20+
for(int j = 0; j < COL; j++)
21+
image[sum][j] = 0;
22+
}
23+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
CORE
2+
main.c
3+
--bounds-check --pointer-check --abstract-loops
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^VERIFICATION FAILED$
7+
main\.0
8+
ASSUME j < 10
9+
ASSUME j >= 0
10+
--
11+
main\.1
12+
main\.2
13+
ASSUME i < 10
14+
ASSUME i >= 0
15+
^warning: ignoring
16+
--
17+
This test ensures that the loop with loop variable i is not shrunk (so it
18+
appears in unwinding). Loops with loop variable j are shrunk. The test also
19+
checks the constraints to the loop variable are correctly applied.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#define ROW 3
2+
#define COL 10
3+
4+
void boo(int r)
5+
{
6+
int val = 0;
7+
int image[ROW][COL];
8+
;
9+
// shrinkable, and set as shrink target
10+
for(int j = 0; j < COL; j++)
11+
{
12+
int c = j + val;
13+
image[r][c] = val;
14+
}
15+
}
16+
17+
void main()
18+
{
19+
int r;
20+
int buffer[ROW];
21+
// not shrinkable since r is used in mem-safe assertion in boo()
22+
// and r update itself in loop
23+
for(int i = 0; i < ROW; i++)
24+
{
25+
r = r + i;
26+
boo(r);
27+
buffer[i];
28+
}
29+
30+
// shrinkable
31+
for(int i = 0; i < ROW; i++)
32+
{
33+
boo(i);
34+
buffer[i];
35+
}
36+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
CORE
2+
main.c
3+
--bounds-check --pointer-check --abstract-loops --abstractset boo.0,main.0
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^VERIFICATION FAILED$
7+
main\.0
8+
main\.1
9+
ASSUME j < 10
10+
ASSUME j >= 0
11+
--
12+
boo\.0
13+
ASSUME i < 10
14+
ASSUME i >= 0
15+
^warning: ignoring
16+
--
17+
This test ensures that the loops with loop variable i are not shrunk (so they
18+
appear in unwinding). Although the second loop in main is shrinkable, it is not
19+
in the target loop set provided by --abstractset, thus it shouldn't be shrunk.
20+
The test also ensures the loop in boo() with loop variable j is shrunk and the
21+
constraints are correctly applied.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#include <stdlib.h>
2+
#define ROW 10
3+
4+
void boo(int *x)
5+
{
6+
*x = *x + 1;
7+
}
8+
9+
void main()
10+
{
11+
int *x = (int *)malloc(sizeof(int));
12+
int buffer[ROW];
13+
*x = 2;
14+
// not shrinkable since x has a self-update in boo()
15+
for(int i = 0; i < ROW; i++)
16+
{
17+
boo(x);
18+
buffer[*x] = 1;
19+
}
20+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
KNOWNBUG
2+
main.c
3+
--bounds-check --pointer-check --add-library --abstract-loops --abstractset main.0
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^VERIFICATION FAILED$
7+
main\.0
8+
--
9+
ASSUME i < 10
10+
ASSUME i >= 0
11+
^warning: ignoring
12+
--
13+
This test ensures that the loops with loop variable i are not shrunk (so they
14+
appear in unwinding), even when the instruction that makes the loop unshrinkable
15+
is in another function.
16+
17+
Requires #2646, #2694 to work.

src/analyses/dependence_graph.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,16 @@ void dep_graph_domaint::transform(
238238
data_dependencies(from, function_to, to, *dep_graph, ns);
239239
}
240240

241+
dep_graph_domaint::depst dep_graph_domaint::get_data_deps() const
242+
{
243+
return data_deps;
244+
}
245+
246+
dep_graph_domaint::depst dep_graph_domaint::get_control_deps() const
247+
{
248+
return control_deps;
249+
}
250+
241251
void dep_graph_domaint::output(
242252
std::ostream &out,
243253
const ai_baset &,

src/analyses/dependence_graph.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@ class dep_graph_domaint:public ai_domain_baset
9393
const ai_baset &ai,
9494
const namespacet &ns) const final override;
9595

96+
typedef std::set<goto_programt::const_targett> depst;
97+
depst get_data_deps() const;
98+
depst get_control_deps() const;
99+
96100
jsont output_json(
97101
const ai_baset &ai,
98102
const namespacet &ns) const override;
@@ -182,7 +186,6 @@ class dep_graph_domaint:public ai_domain_baset
182186
node_indext node_id;
183187
bool has_changed;
184188

185-
typedef std::set<goto_programt::const_targett> depst;
186189

187190
// Set of locations with control instructions on which the instruction at this
188191
// location has a control dependency on

src/cbmc/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ OBJ += ../ansi-c/ansi-c$(LIBEXT) \
4040
../goto-instrument/reachability_slicer$(OBJEXT) \
4141
../goto-instrument/nondet_static$(OBJEXT) \
4242
../goto-instrument/full_slicer$(OBJEXT) \
43+
../goto-instrument/abstract_loops$(OBJEXT) \
4344
../goto-instrument/unwindset$(OBJEXT) \
4445
../analyses/analyses$(LIBEXT) \
4546
../langapi/langapi$(LIBEXT) \

src/cbmc/cbmc_parse_options.cpp

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,10 @@ Author: Daniel Kroening, [email protected]
6767
#include <goto-programs/string_abstraction.h>
6868
#include <goto-programs/string_instrumentation.h>
6969

70-
#include <goto-instrument/reachability_slicer.h>
70+
#include <goto-instrument/cover.h>
7171
#include <goto-instrument/full_slicer.h>
7272
#include <goto-instrument/nondet_static.h>
73-
#include <goto-instrument/cover.h>
73+
#include <goto-instrument/reachability_slicer.h>
7474

7575
#include <goto-symex/path_storage.h>
7676

@@ -159,6 +159,12 @@ void cbmc_parse_optionst::get_command_line_options(optionst &options)
159159
if(cmdline.isset("full-slice"))
160160
options.set_option("full-slice", true);
161161

162+
if(cmdline.isset("abstract-loops"))
163+
options.set_option("abstract-loops", true);
164+
165+
if(cmdline.isset("abstractset"))
166+
options.set_option("abstractset", cmdline.get_value("abstractset"));
167+
162168
if(cmdline.isset("show-symex-strategies"))
163169
{
164170
status() << show_path_strategies() << eom;
@@ -892,6 +898,24 @@ bool cbmc_parse_optionst::process_goto_program(
892898
reachability_slicer(goto_model);
893899
}
894900

901+
if(options.get_bool_option("abstract-loops"))
902+
{
903+
// make sure location numbers are set
904+
goto_model.goto_functions.update();
905+
906+
log.status() << "Abstracting loops" << eom;
907+
loop_mapt target_loop_map;
908+
if(options.is_set("abstractset"))
909+
{
910+
if(parse_absloopset(options.get_option("abstractset"), target_loop_map))
911+
{
912+
log.error() << "failed to parse input loop" << eom;
913+
return true;
914+
}
915+
}
916+
abstract_loops(goto_model, target_loop_map);
917+
}
918+
895919
// full slice?
896920
if(options.get_bool_option("full-slice"))
897921
{
@@ -990,6 +1014,7 @@ void cbmc_parse_optionst::help()
9901014
HELP_REACHABILITY_SLICER_FB
9911015
" --full-slice run full slicer (experimental)\n" // NOLINT(*)
9921016
" --drop-unused-functions drop functions trivially unreachable from main function\n" // NOLINT(*)
1017+
HELP_ABSTRACT_LOOPS
9931018
"\n"
9941019
"Semantic transformations:\n"
9951020
// NOLINTNEXTLINE(whitespace/line_length)

0 commit comments

Comments
 (0)