Skip to content

Commit 25ea7b3

Browse files
committed
Fix reachability slicer when used with recursive or unreachable functions
1 parent 3705a60 commit 25ea7b3

File tree

4 files changed

+65
-9
lines changed

4 files changed

+65
-9
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
void b();
2+
3+
void c()
4+
{
5+
__CPROVER_assert(0, "");
6+
b();
7+
}
8+
9+
void b()
10+
{
11+
a();
12+
c();
13+
}
14+
15+
void a()
16+
{
17+
c();
18+
}
19+
20+
int main()
21+
{
22+
a();
23+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
--reachability-slice --show-goto-functions
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
main\(\)
7+
--
8+
^warning: ignoring

src/goto-instrument/reachability_slicer.cpp

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ static bool is_same_target(
5555

5656
/// Perform backwards depth-first search of the control-flow graph of the
5757
/// goto program, starting from the nodes corresponding to the criterion and
58-
/// the instructions that might be executed concurrently. Set reaches_assertion
58+
/// the instructions that might be executed concurrently. Set backward_state
5959
/// to true for every instruction visited.
6060
/// \param is_threaded Instructions that might be executed concurrently
6161
/// \param criterion the criterion we are trying to hit
@@ -74,9 +74,18 @@ void reachability_slicert::fixedpoint_to_assertions(
7474
const auto caller_is_known = stack.back().caller_is_known;
7575
stack.pop_back();
7676

77-
if(node.reaches_assertion)
77+
if(
78+
node.backward_state ==
79+
slicer_entryt::dfs_statust::BODY_AND_CALLERS_SEEN ||
80+
(caller_is_known &&
81+
node.backward_state == slicer_entryt::dfs_statust::BODY_SEEN))
82+
{
7883
continue;
79-
node.reaches_assertion = true;
84+
}
85+
node.backward_state =
86+
caller_is_known ?
87+
slicer_entryt::dfs_statust::BODY_SEEN :
88+
slicer_entryt::dfs_statust::BODY_AND_CALLERS_SEEN;
8089

8190
for(const auto &edge : node.in)
8291
{
@@ -111,8 +120,8 @@ void reachability_slicert::fixedpoint_to_assertions(
111120

112121
/// Perform forwards depth-first search of the control-flow graph of the
113122
/// goto program, starting from the nodes corresponding to the criterion and
114-
/// the instructions that might be executed concurrently. Set reaches_assertion
115-
/// to true for every instruction visited.
123+
/// the instructions that might be executed concurrently. Set
124+
/// reachable_from_assertion to true for every instruction visited.
116125
/// \param is_threaded Instructions that might be executed concurrently
117126
/// \param criterion the criterion we are trying to hit
118127
void reachability_slicert::fixedpoint_from_assertions(
@@ -182,7 +191,7 @@ void reachability_slicert::fixedpoint_from_assertions(
182191
}
183192

184193
/// This function removes all instructions that have the flag
185-
/// reaches_assertion or reachable_from_assertion set to true;
194+
/// backward_state or reachable_from_assertion set to true;
186195
void reachability_slicert::slice(goto_functionst &goto_functions)
187196
{
188197
// now replace those instructions that do not reach any assertions
@@ -195,9 +204,12 @@ void reachability_slicert::slice(goto_functionst &goto_functions)
195204
{
196205
const cfgt::nodet &e=cfg[cfg.entry_map[i_it]];
197206
if(
198-
!e.reaches_assertion && !e.reachable_from_assertion &&
207+
e.backward_state == slicer_entryt::dfs_statust::NOT_SEEN &&
208+
!e.reachable_from_assertion &&
199209
!i_it->is_end_function())
210+
{
200211
i_it->make_assumption(false_exprt());
212+
}
201213
}
202214

203215
// replace unreachable code by skip

src/goto-instrument/reachability_slicer_class.h

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,24 @@ class reachability_slicert
3838
protected:
3939
struct slicer_entryt
4040
{
41-
slicer_entryt() : reaches_assertion(false), reachable_from_assertion(false)
41+
slicer_entryt()
42+
: backward_state(dfs_statust::NOT_SEEN),
43+
reachable_from_assertion(false)
4244
{
4345
}
4446

45-
bool reaches_assertion;
47+
/// The status of each node during backwards depth-first traversal:
48+
/// A functions starts out NOT_SEEN, is raised to BODY_SEEN if we have seen
49+
/// a call to this function but know where it was called from (at this point
50+
/// we mark the function and anything reachable from it), then may finally
51+
/// be raised to BODY_AND_CALLERS_SEEN if we don't know what function calls
52+
/// this function, and therefore mark all of its callers as well.
53+
enum class dfs_statust
54+
{
55+
NOT_SEEN,
56+
BODY_SEEN,
57+
BODY_AND_CALLERS_SEEN
58+
} backward_state;
4659
bool reachable_from_assertion;
4760
};
4861

0 commit comments

Comments
 (0)