Skip to content

Commit 6120c17

Browse files
author
Vojtech Forejt
committed
Changes to the reachability slicer
* Add forwards reachability to the slicer, in addition to the backwards reachability currently implemented. * Add command-line options for the slicer in jbmc and cbmc. * Refactor the way reachability is computed in the slicer, using grapht rather than own implementation
1 parent 7161f17 commit 6120c17

19 files changed

+299
-38
lines changed
318 Bytes
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
public class A {
2+
3+
public void foo(int i ) {
4+
// We use integer constants that we grep for later in a goto program.
5+
int x = 1001 + i;
6+
if (i > 0) {
7+
x = 1002 + i; // property "java::A.foo:(I)V.coverage.3", see https://github.com/diffblue/cbmc/pull/1943#discussion_r175367063 for a discusison.
8+
x = 1003 + i;
9+
}
10+
else
11+
x = 1004 + i;
12+
x = 1005 + i;
13+
}
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
A.class
3+
--reachability-slice --show-goto-functions --property 'java::A.foo:(I)V.coverage.3' --cover location
4+
1001
5+
--
6+
1003
7+
1004
8+
1005
9+
--
10+
Note: 1002 might and might not be removed, based on where the assertion for coverage resides.
11+
At the time of writing of this test, 1002 is removed.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
A.class
3+
--reachability-slice-fb --show-goto-functions --property 'java::A.foo:(I)V.coverage.3' --cover location
4+
1001
5+
1002
6+
1003
7+
1005
8+
--
9+
1004
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
A.class
3+
--reachability-slice --show-goto-functions --cover location
4+
1001
5+
1002
6+
1003
7+
1004
8+
1005
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
void foo(int i)
2+
{
3+
// We use integer constants that we grep for later in a goto program.
4+
int x = 1001 + i;
5+
if(i > 0)
6+
{ //foo.coverage.2
7+
x = 1002 + i;
8+
x = 1003 + i;
9+
}
10+
else
11+
x = 1004 + i;
12+
x = 1005 + i;
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
test.c
3+
--reachability-slice --show-goto-functions --cover location --property foo.coverage.2
4+
1001
5+
--
6+
1004
7+
1005
8+
--
9+
We do not include 1002 and 1003, whether this is hit depends on where assertion is put
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
test.c
3+
--reachability-slice-fb --show-goto-functions --cover location --property foo.coverage.2
4+
1001
5+
1002
6+
1003
7+
1005
8+
--
9+
1004
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
test.c
3+
--reachability-slice --show-goto-functions --cover location
4+
1001
5+
1002
6+
1003
7+
1004
8+
--
9+
--
10+
We do not include 1005 since it might or might not be present based on where the assertion is in the block.

src/cbmc/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ OBJ += ../ansi-c/ansi-c$(LIBEXT) \
3131
../pointer-analysis/add_failed_symbols$(OBJEXT) \
3232
../pointer-analysis/rewrite_index$(OBJEXT) \
3333
../pointer-analysis/goto_program_dereference$(OBJEXT) \
34+
../goto-instrument/reachability_slicer$(OBJEXT) \
3435
../goto-instrument/full_slicer$(OBJEXT) \
3536
../goto-instrument/nondet_static$(OBJEXT) \
3637
../goto-instrument/cover$(OBJEXT) \

src/cbmc/cbmc_parse_options.cpp

+29
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ Author: Daniel Kroening, [email protected]
5454
#include <goto-symex/rewrite_union.h>
5555
#include <goto-symex/adjust_float_expressions.h>
5656

57+
#include <goto-instrument/reachability_slicer.h>
5758
#include <goto-instrument/full_slicer.h>
5859
#include <goto-instrument/nondet_static.h>
5960
#include <goto-instrument/cover.h>
@@ -801,6 +802,32 @@ bool cbmc_parse_optionst::process_goto_program(
801802
// this would cause the property identifiers to change.
802803
label_properties(goto_model);
803804

805+
// reachability slice?
806+
if(cmdline.isset("reachability-slice-fb"))
807+
{
808+
if(cmdline.isset("reachability-slice"))
809+
{
810+
error() << "--reachability-slice and --reachability-slice-fb "
811+
<< "must not be given together" << eom;
812+
return true;
813+
}
814+
815+
status() << "Performing a forwards-backwards reachability slice" << eom;
816+
if(cmdline.isset("property"))
817+
reachability_slicer(goto_model, cmdline.get_values("property"), true);
818+
else
819+
reachability_slicer(goto_model, true);
820+
}
821+
822+
if(cmdline.isset("reachability-slice"))
823+
{
824+
status() << "Performing a reachability slice" << eom;
825+
if(cmdline.isset("property"))
826+
reachability_slicer(goto_model, cmdline.get_values("property"));
827+
else
828+
reachability_slicer(goto_model);
829+
}
830+
804831
// full slice?
805832
if(cmdline.isset("full-slice"))
806833
{
@@ -926,6 +953,8 @@ void cbmc_parse_optionst::help()
926953
" --error-label label check that label is unreachable\n"
927954
" --cover CC create test-suite with coverage criterion CC\n" // NOLINT(*)
928955
" --mm MM memory consistency model for concurrent programs\n" // NOLINT(*)
956+
HELP_REACHABILITY_SLICER
957+
" --full-slice run full slicer (experimental)\n" // NOLINT(*)
929958
"\n"
930959
"Semantic transformations:\n"
931960
// NOLINTNEXTLINE(whitespace/line_length)

src/cbmc/cbmc_parse_options.h

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class optionst;
3636
"(preprocess)(slice-by-trace):" \
3737
OPT_FUNCTIONS \
3838
"(no-simplify)(full-slice)" \
39+
OPT_REACHABILITY_SLICER \
3940
"(debug-level):(no-propagation)(no-simplify-if)" \
4041
"(document-subgoals)(outfile):(test-preprocessor)" \
4142
"D:I:(c89)(c99)(c11)(cpp98)(cpp03)(cpp11)" \

src/goto-instrument/reachability_slicer.cpp

+95-32
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ Author: Daniel Kroening, [email protected]
77
\*******************************************************************/
88

99
/// \file
10-
/// Slicer
10+
/// Reachability Slicer
11+
/// Consider the control flow graph of the goto program and a criterion, and
12+
/// remove the parts of the graph from which the criterion is not reachable
13+
/// (and possibly, depending on the parameters, keep those that can be reached
14+
/// from the criterion).
1115

1216
#include "reachability_slicer.h"
1317

@@ -20,41 +24,62 @@ Author: Daniel Kroening, [email protected]
2024
#include "full_slicer_class.h"
2125
#include "reachability_slicer_class.h"
2226

23-
void reachability_slicert::fixedpoint_assertions(
27+
/// Get the set of nodes that correspond to the given criterion, or that can
28+
/// appear in concurrent execution. None of these should be sliced away so
29+
/// they are used as a basis for the search.
30+
/// \param is_threaded Instructions that might be executed concurrently
31+
/// \param criterion The criterion we care about
32+
std::vector<reachability_slicert::cfgt::node_indext>
33+
reachability_slicert::get_sources(
2434
const is_threadedt &is_threaded,
2535
slicing_criteriont &criterion)
2636
{
27-
queuet queue;
37+
std::vector<cfgt::node_indext> sources;
38+
for(const auto &e_it : cfg.entry_map)
39+
{
40+
if(criterion(e_it.first) || is_threaded(e_it.first))
41+
sources.push_back(e_it.second);
42+
}
2843

29-
for(cfgt::entry_mapt::iterator
30-
e_it=cfg.entry_map.begin();
31-
e_it!=cfg.entry_map.end();
32-
e_it++)
33-
if(criterion(e_it->first) ||
34-
is_threaded(e_it->first))
35-
queue.push(e_it->second);
44+
return sources;
45+
}
3646

37-
while(!queue.empty())
38-
{
39-
cfgt::entryt e=queue.top();
40-
cfgt::nodet &node=cfg[e];
41-
queue.pop();
47+
/// Perform backwards depth-first search of the control-flow graph of the
48+
/// goto program, starting from the nodes corresponding to the criterion and
49+
/// the instructions that might be executed concurrently. Set reaches_assertion
50+
/// to true for every instruction visited.
51+
/// \param is_threaded Instructions that might be executed concurrently
52+
/// \param criterion the criterion we are trying to hit
53+
void reachability_slicert::fixedpoint_to_assertions(
54+
const is_threadedt &is_threaded,
55+
slicing_criteriont &criterion)
56+
{
57+
std::vector<cfgt::node_indext> src = get_sources(is_threaded, criterion);
4258

43-
if(node.reaches_assertion)
44-
continue;
59+
std::vector<cfgt::node_indext> reachable = cfg.get_reachable(src, false);
60+
for(const auto index : reachable)
61+
cfg[index].reaches_assertion = true;
62+
}
4563

46-
node.reaches_assertion=true;
64+
/// Perform forwards depth-first search of the control-flow graph of the
65+
/// goto program, starting from the nodes corresponding to the criterion and
66+
/// the instructions that might be executed concurrently. Set reaches_assertion
67+
/// to true for every instruction visited.
68+
/// \param is_threaded Instructions that might be executed concurrently
69+
/// \param criterion the criterion we are trying to hit
70+
void reachability_slicert::fixedpoint_from_assertions(
71+
const is_threadedt &is_threaded,
72+
slicing_criteriont &criterion)
73+
{
74+
std::vector<cfgt::node_indext> src = get_sources(is_threaded, criterion);
4775

48-
for(cfgt::edgest::const_iterator
49-
p_it=node.in.begin();
50-
p_it!=node.in.end();
51-
p_it++)
52-
{
53-
queue.push(p_it->first);
54-
}
55-
}
76+
const std::vector<cfgt::node_indext> reachable = cfg.get_reachable(src, true);
77+
for(const auto index : reachable)
78+
cfg[index].reachable_from_assertion = true;
5679
}
5780

81+
/// This function removes all instructions that have the flag
82+
/// reaches_assertion or reachable_from_assertion set to true;
5883
void reachability_slicert::slice(goto_functionst &goto_functions)
5984
{
6085
// now replace those instructions that do not reach any assertions
@@ -66,8 +91,9 @@ void reachability_slicert::slice(goto_functionst &goto_functions)
6691
Forall_goto_program_instructions(i_it, f_it->second.body)
6792
{
6893
const cfgt::nodet &e=cfg[cfg.entry_map[i_it]];
69-
if(!e.reaches_assertion &&
70-
!i_it->is_end_function())
94+
if(
95+
!e.reaches_assertion && !e.reachable_from_assertion &&
96+
!i_it->is_end_function())
7197
i_it->make_assumption(false_exprt());
7298
}
7399

@@ -80,18 +106,55 @@ void reachability_slicert::slice(goto_functionst &goto_functions)
80106
goto_functions.update();
81107
}
82108

83-
void reachability_slicer(goto_modelt &goto_model)
109+
/// Perform reachability slicing on goto_model, with respect to the
110+
/// criterion given by all properties.
111+
/// \param goto_model Goto program to slice
112+
/// \param include_forward_reachability Determines if only instructions
113+
/// from which the criterion is reachable should be kept (false) or also
114+
/// those reachable from the criterion (true)
115+
void reachability_slicer(
116+
goto_modelt &goto_model,
117+
const bool include_forward_reachability)
84118
{
85119
reachability_slicert s;
86120
assert_criteriont a;
87-
s(goto_model.goto_functions, a);
121+
s(goto_model.goto_functions, a, include_forward_reachability);
88122
}
89123

124+
/// Perform reachability slicing on goto_model for selected properties.
125+
/// \param goto_model Goto program to slice
126+
/// \param properties The properties relevant for the slicing (i.e. starting
127+
/// point for the search in the cfg)
128+
/// \param include_forward_reachability Determines if only instructions
129+
/// from which the criterion is reachable should be kept (false) or also
130+
/// those reachable from the criterion (true)
90131
void reachability_slicer(
91132
goto_modelt &goto_model,
92-
const std::list<std::string> &properties)
133+
const std::list<std::string> &properties,
134+
const bool include_forward_reachability)
93135
{
94136
reachability_slicert s;
95137
properties_criteriont p(properties);
96-
s(goto_model.goto_functions, p);
138+
s(goto_model.goto_functions, p, include_forward_reachability);
139+
}
140+
141+
/// Perform reachability slicing on goto_model, with respect to criterion
142+
/// comprising all properties. Only instructions from which the criterion
143+
/// is reachable will be kept.
144+
/// \param goto_model Goto program to slice
145+
void reachability_slicer(goto_modelt &goto_model)
146+
{
147+
reachability_slicer(goto_model, false);
148+
}
149+
150+
/// Perform reachability slicing on goto_model for selected properties. Only
151+
/// instructions from which the criterion is reachable will be kept.
152+
/// \param goto_model Goto program to slice
153+
/// \param properties The properties relevant for the slicing (i.e. starting
154+
/// point for the search in the cfg)
155+
void reachability_slicer(
156+
goto_modelt &goto_model,
157+
const std::list<std::string> &properties)
158+
{
159+
reachability_slicer(goto_model, properties, false);
97160
}

src/goto-instrument/reachability_slicer.h

+18
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,22 @@ void reachability_slicer(
2323
goto_modelt &,
2424
const std::list<std::string> &properties);
2525

26+
void reachability_slicer(
27+
goto_modelt &,
28+
const bool include_forward_reachability);
29+
30+
void reachability_slicer(
31+
goto_modelt &,
32+
const std::list<std::string> &properties,
33+
const bool include_forward_reachability);
34+
35+
#define OPT_REACHABILITY_SLICER \
36+
"(reachability-slice)(reachability-slice-fb)" // NOLINT(*)
37+
38+
#define HELP_REACHABILITY_SLICER \
39+
" --reachability-slice remove instructions that cannot appear on a " \
40+
"trace from entry point to a property\n" \
41+
" --reachability-slice-fb remove instructions that cannot appear on a " \
42+
"trace from entry point through a property\n" // NOLINT(*)
43+
2644
#endif // CPROVER_GOTO_INSTRUMENT_REACHABILITY_SLICER_H

0 commit comments

Comments
 (0)