Skip to content

Commit a1dd075

Browse files
committed
Move exprt::bounded_size to complexity_limitert
complexity_limitert is really the only user of this method, and may be fine with its implementation details (cf. discussion in #5914). For other potential users such assumptions might not be safe.
1 parent 11149ef commit a1dd075

File tree

7 files changed

+83
-66
lines changed

7 files changed

+83
-66
lines changed

src/goto-symex/complexity_limiter.cpp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,8 @@ complexity_limitert::check_complexity(goto_symex_statet &state)
136136
if(!complexity_limits_active() || !state.reachable)
137137
return complexity_violationt::NONE;
138138

139-
std::size_t complexity = state.guard.as_expr().bounded_size(max_complexity);
139+
std::size_t complexity =
140+
bounded_expr_size(state.guard.as_expr(), max_complexity);
140141
if(complexity == 1)
141142
return complexity_violationt::NONE;
142143

@@ -211,3 +212,29 @@ void complexity_limitert::run_transformations(
211212
for(auto transform_lambda : violation_transformations)
212213
transform_lambda.transform(complexity_violation, current_state);
213214
}
215+
216+
/// Amount of nodes \p expr contains, with a bound on how far to search.
217+
/// Starts with an existing count.
218+
/// \return Size of \p expr added to count without searching significantly
219+
/// beyond the supplied limit.
220+
static std::size_t
221+
bounded_expr_size(const exprt &expr, std::size_t count, std::size_t limit)
222+
{
223+
const auto &ops = expr.operands();
224+
count += ops.size();
225+
for(const auto &op : ops)
226+
{
227+
if(count >= limit)
228+
{
229+
return count;
230+
}
231+
count = bounded_expr_size(op, count, limit);
232+
}
233+
return count;
234+
}
235+
236+
std::size_t
237+
complexity_limitert::bounded_expr_size(const exprt &expr, std::size_t limit)
238+
{
239+
return ::bounded_expr_size(expr, 1, limit);
240+
}

src/goto-symex/complexity_limiter.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ class complexity_limitert
6969
complexity_violationt complexity_violation,
7070
goto_symex_statet &current_state);
7171

72+
/// Amount of nodes in \p expr approximately bounded by limit.
73+
/// This is the size of the actual tree, ignoring memory/sub-tree sharing.
74+
static std::size_t bounded_expr_size(const exprt &expr, std::size_t limit);
75+
7276
protected:
7377
mutable messaget log;
7478

src/util/expr.cpp

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -24,30 +24,6 @@ Author: Daniel Kroening, [email protected]
2424

2525
#include <stack>
2626

27-
/// Returns the size of the exprt added to count without searching significantly
28-
/// beyond the supplied limit.
29-
std::size_t exprt::bounded_size(std::size_t count, std::size_t limit) const
30-
{
31-
const auto &ops = operands();
32-
count += ops.size();
33-
for(const auto &op : ops)
34-
{
35-
if(count >= limit)
36-
{
37-
return count;
38-
}
39-
count = op.bounded_size(count, limit);
40-
}
41-
return count;
42-
}
43-
44-
/// Returns the size of the exprt without significantly searching beyond the
45-
/// supplied limit.
46-
std::size_t exprt::bounded_size(std::size_t limit) const
47-
{
48-
return bounded_size(1, limit);
49-
}
50-
5127
/// Return whether the expression is a constant.
5228
/// \return True if is a constant, false otherwise
5329
bool exprt::is_constant() const

src/util/expr.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,6 @@ class exprt:public irept
8585
return static_cast<const typet &>(find(ID_type));
8686
}
8787

88-
/// Amount of nodes in this expression tree approximately bounded by limit.
89-
/// This is the size of the actual tree, ignoring memory/sub-tree sharing.
90-
std::size_t bounded_size(std::size_t limit) const;
91-
9288
/// Return true if there is at least one operand.
9389
bool has_operands() const
9490
{ return !operands().empty(); }
@@ -124,10 +120,6 @@ class exprt:public irept
124120
const exprt &op3() const
125121
{ return operands()[3]; }
126122

127-
/// Amount of nodes this expression tree contains, with a bound on how far
128-
/// to search. Starts with an existing count.
129-
std::size_t bounded_size(std::size_t count, std::size_t limit) const;
130-
131123
public:
132124
void reserve_operands(operandst::size_type n)
133125
{ operands().reserve(n) ; }

unit/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ SRC += analyses/ai/ai.cpp \
5454
goto-programs/remove_returns.cpp \
5555
goto-programs/xml_expr.cpp \
5656
goto-symex/apply_condition.cpp \
57+
goto-symex/complexity_limiter.cpp \
5758
goto-symex/expr_skeleton.cpp \
5859
goto-symex/goto_symex_state.cpp \
5960
goto-symex/ssa_equation.cpp \
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*******************************************************************\
2+
3+
Module: Unit test for goto-symex/complexity_limiter
4+
5+
Author: Diffblue Ltd
6+
7+
\*******************************************************************/
8+
9+
#include <testing-utils/use_catch.h>
10+
11+
#include <goto-symex/complexity_limiter.h>
12+
13+
TEST_CASE(
14+
"Bounded expression size is computed correctly",
15+
"[core][goto-symex][complexity_limiter]")
16+
{
17+
// Helper types and functions for constructing test expressions.
18+
const typet type = signedbv_typet(32);
19+
std::function<exprt(size_t)> make_expression;
20+
make_expression = [&](size_t size) -> exprt {
21+
PRECONDITION(size != 0);
22+
if(size <= 1)
23+
return from_integer(1, type);
24+
if(size == 2)
25+
return unary_minus_exprt(from_integer(1, type));
26+
return plus_exprt(from_integer(1, type), make_expression(size - 2));
27+
};
28+
// Actual test cases.
29+
REQUIRE(complexity_limitert::bounded_expr_size(make_expression(1), 10) == 1);
30+
REQUIRE(complexity_limitert::bounded_expr_size(make_expression(2), 10) == 2);
31+
REQUIRE(complexity_limitert::bounded_expr_size(make_expression(3), 10) == 3);
32+
33+
REQUIRE(complexity_limitert::bounded_expr_size(make_expression(30), 10) < 13);
34+
REQUIRE(
35+
complexity_limitert::bounded_expr_size(make_expression(30), 10) >= 10);
36+
}
37+
38+
TEST_CASE(
39+
"Bounded expression size versus pathological example",
40+
"[core][goto-symex][complexity_limiter]")
41+
{
42+
const typet type = signedbv_typet(32);
43+
exprt pathology = plus_exprt(from_integer(1, type), from_integer(1, type));
44+
// Create an infinite exprt by self reference!
45+
pathology.add_to_operands(pathology);
46+
// If bounded expression size is not checking the bound this will never
47+
// terminate.
48+
REQUIRE(complexity_limitert::bounded_expr_size(pathology, 10) < 13);
49+
REQUIRE(complexity_limitert::bounded_expr_size(pathology, 10) >= 10);
50+
}

unit/util/expr.cpp

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -36,36 +36,3 @@ SCENARIO("bitfield-expr-is-zero", "[core][util][expr]")
3636
}
3737
}
3838
}
39-
40-
TEST_CASE("Bounded size is computer correctly", "[core][util][expr]")
41-
{
42-
// Helper types and functions for constructing test expressions.
43-
const typet type = signedbv_typet(32);
44-
std::function<exprt(size_t)> make_expression;
45-
make_expression = [&](size_t size) -> exprt {
46-
PRECONDITION(size != 0);
47-
if(size <= 1)
48-
return from_integer(1, type);
49-
if(size == 2)
50-
return unary_minus_exprt(from_integer(1, type));
51-
return plus_exprt(from_integer(1, type), make_expression(size - 2));
52-
};
53-
// Actual test cases.
54-
REQUIRE(make_expression(1).bounded_size(10) == 1);
55-
REQUIRE(make_expression(2).bounded_size(10) == 2);
56-
REQUIRE(make_expression(3).bounded_size(10) == 3);
57-
58-
REQUIRE(make_expression(30).bounded_size(10) < 13);
59-
REQUIRE(make_expression(30).bounded_size(10) >= 10);
60-
}
61-
62-
TEST_CASE("Bounded size versus pathological example", "[core][util][expr]")
63-
{
64-
const typet type = signedbv_typet(32);
65-
exprt pathology = plus_exprt(from_integer(1, type), from_integer(1, type));
66-
// Create an infinite exprt by self reference!
67-
pathology.add_to_operands(pathology);
68-
// If bounded size is not checking the bound this will never terminate.
69-
REQUIRE(pathology.bounded_size(10) < 13);
70-
REQUIRE(pathology.bounded_size(10) >= 10);
71-
}

0 commit comments

Comments
 (0)