Skip to content

Commit f154d16

Browse files
author
Matthias Güdemann
authored
Merge pull request #1487 from martin-cs/goto-analyzer-6-part2
Goto analyzer 6 part2
2 parents 4955417 + eef32db commit f154d16

15 files changed

+320
-76
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#include <assert.h>
2+
3+
int bar(int other)
4+
{
5+
if(other > 0)
6+
{
7+
int value = bar(other - 1);
8+
return value + 1;
9+
}
10+
else
11+
{
12+
return 0;
13+
}
14+
}
15+
16+
int bar_clean(int other)
17+
{
18+
if(other > 0)
19+
{
20+
int value = bar_clean(other - 1);
21+
return value + 1;
22+
}
23+
else
24+
{
25+
return 0;
26+
}
27+
}
28+
29+
int fun(int changing, int constant)
30+
{
31+
if(changing > 0)
32+
{
33+
int value = fun(changing - 1, constant);
34+
return value;
35+
}
36+
else
37+
{
38+
return constant;
39+
}
40+
}
41+
42+
int main(int argc, char *argv[])
43+
{
44+
int x=3;
45+
int y=bar(x+1);
46+
assert(y==4); // Unknown in the constants domain
47+
48+
int y2 = bar(0);
49+
assert(y2==0); // Unknown since we are not sensitive to call domain
50+
51+
int z = bar_clean(0);
52+
assert(z==0); // Unknown as the function has parameter as top
53+
54+
int w = fun(5, 18);
55+
assert(w==18);
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
KNOWNBUG
2+
main.c
3+
--variable --pointers --arrays --structs --verify
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^\[main\.assertion\.1\] .* assertion y==4: Unknown$
7+
^\[main\.assertion\.2\] .* assertion y2==0: Unknown$
8+
^\[main\.assertion\.3\] .* assertion z==0: Success$
9+
^\[main\.assertion\.4\] .* assertion w==18: Success$
10+
--
11+
^warning: ignoring

src/analyses/ai.cpp

+8-13
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ xmlt ai_domain_baset::output_xml(
3737
{
3838
std::ostringstream out;
3939
output(out, ai, ns);
40-
xmlt xml("domain");
40+
xmlt xml("abstract_state");
4141
xml.data=out.str();
4242
return xml;
4343
}
@@ -170,7 +170,7 @@ jsont ai_baset::output_json(
170170
json_numbert(std::to_string(i_it->location_number));
171171
location["sourceLocation"]=
172172
json_stringt(i_it->source_location.as_string());
173-
location["domain"]=find_state(i_it).output_json(*this, ns);
173+
location["abstractState"]=find_state(i_it).output_json(*this, ns);
174174

175175
// Ideally we need output_instruction_json
176176
std::ostringstream out;
@@ -431,7 +431,12 @@ bool ai_baset::do_function_call(
431431
assert(l_end->is_end_function());
432432

433433
// do edge from end of function to instruction after call
434-
std::unique_ptr<statet> tmp_state(make_temporary_state(get_state(l_end)));
434+
const statet &end_state=get_state(l_end);
435+
436+
if(end_state.is_bottom())
437+
return false; // function exit point not reachable
438+
439+
std::unique_ptr<statet> tmp_state(make_temporary_state(end_state));
435440
tmp_state->transform(l_end, l_return, *this, ns);
436441

437442
// Propagate those
@@ -454,14 +459,6 @@ bool ai_baset::do_function_call_rec(
454459
{
455460
const irep_idt &identifier=function.get(ID_identifier);
456461

457-
if(recursion_set.find(identifier)!=recursion_set.end())
458-
{
459-
// recursion detected!
460-
return new_data;
461-
}
462-
else
463-
recursion_set.insert(identifier);
464-
465462
goto_functionst::function_mapt::const_iterator it=
466463
goto_functions.function_map.find(identifier);
467464

@@ -474,8 +471,6 @@ bool ai_baset::do_function_call_rec(
474471
it,
475472
arguments,
476473
ns);
477-
478-
recursion_set.erase(identifier);
479474
}
480475
else if(function.id()==ID_if)
481476
{

src/analyses/ai.h

+21-3
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ class ai_domain_baset
8080
// a reasonable entry-point state
8181
virtual void make_entry()=0;
8282

83+
virtual bool is_bottom() const=0;
84+
85+
virtual bool is_top() const=0;
86+
8387
// also add
8488
//
8589
// bool merge(const T &b, locationt from, locationt to);
@@ -158,6 +162,17 @@ class ai_baset
158162
fixedpoint(goto_function.body, goto_functions, ns);
159163
}
160164

165+
/// Returns the abstract state before the given instruction
166+
virtual const ai_domain_baset & abstract_state_before(
167+
goto_programt::const_targett t) const = 0;
168+
169+
/// Returns the abstract state after the given instruction
170+
virtual const ai_domain_baset & abstract_state_after(
171+
goto_programt::const_targett t) const
172+
{
173+
return abstract_state_before(std::next(t));
174+
}
175+
161176
virtual void clear()
162177
{
163178
}
@@ -307,9 +322,6 @@ class ai_baset
307322
const goto_functionst &goto_functions,
308323
const namespacet &ns);
309324

310-
typedef std::set<irep_idt> recursion_sett;
311-
recursion_sett recursion_set;
312-
313325
// function calls
314326
bool do_function_call_rec(
315327
locationt l_call, locationt l_return,
@@ -369,6 +381,12 @@ class ait:public ai_baset
369381
return it->second;
370382
}
371383

384+
const ai_domain_baset & abstract_state_before(
385+
goto_programt::const_targett t) const override
386+
{
387+
return (*this)[t];
388+
}
389+
372390
void clear() override
373391
{
374392
state_map.clear();

src/analyses/constant_propagator.h

+29-9
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class constant_propagator_domaint:public ai_domain_baset
2525
locationt from,
2626
locationt to,
2727
ai_baset &ai_base,
28-
const namespacet &ns) override;
28+
const namespacet &ns) final override;
2929

3030
virtual void output(
3131
std::ostream &out,
@@ -39,23 +39,33 @@ class constant_propagator_domaint:public ai_domain_baset
3939

4040
virtual bool ai_simplify(
4141
exprt &condition,
42-
const namespacet &ns) const override;
42+
const namespacet &ns) const final override;
4343

44-
virtual void make_bottom() override
44+
virtual void make_bottom() final override
4545
{
4646
values.set_to_bottom();
4747
}
4848

49-
virtual void make_top() override
49+
virtual void make_top() final override
5050
{
5151
values.set_to_top();
5252
}
5353

54-
virtual void make_entry() override
54+
virtual void make_entry() final override
5555
{
5656
make_top();
5757
}
5858

59+
virtual bool is_bottom() const final override
60+
{
61+
return values.is_bot();
62+
}
63+
64+
virtual bool is_top() const final override
65+
{
66+
return values.is_top();
67+
}
68+
5969
struct valuest
6070
{
6171
public:
@@ -70,27 +80,37 @@ class constant_propagator_domaint:public ai_domain_baset
7080

7181
// set whole state
7282

73-
inline void set_to_bottom()
83+
void set_to_bottom()
7484
{
7585
replace_const.clear();
7686
is_bottom=true;
7787
}
7888

79-
inline void set_to_top()
89+
void set_to_top()
8090
{
8191
replace_const.clear();
8292
is_bottom=false;
8393
}
8494

95+
bool is_bot() const
96+
{
97+
return is_bottom && replace_const.empty();
98+
}
99+
100+
bool is_top() const
101+
{
102+
return !is_bottom && replace_const.empty();
103+
}
104+
85105
// set single identifier
86106

87-
inline void set_to(const irep_idt &lhs, const exprt &rhs)
107+
void set_to(const irep_idt &lhs, const exprt &rhs)
88108
{
89109
replace_const.expr_map[lhs]=rhs;
90110
is_bottom=false;
91111
}
92112

93-
inline void set_to(const symbol_exprt &lhs, const exprt &rhs)
113+
void set_to(const symbol_exprt &lhs, const exprt &rhs)
94114
{
95115
set_to(lhs.get_identifier(), rhs);
96116
}

src/analyses/custom_bitvector_analysis.h

+21-5
Original file line numberDiff line numberDiff line change
@@ -27,32 +27,48 @@ class custom_bitvector_domaint:public ai_domain_baset
2727
locationt from,
2828
locationt to,
2929
ai_baset &ai,
30-
const namespacet &ns) final;
30+
const namespacet &ns) final override;
3131

3232
void output(
3333
std::ostream &out,
3434
const ai_baset &ai,
35-
const namespacet &ns) const final;
35+
const namespacet &ns) const final override;
3636

37-
void make_bottom() final
37+
void make_bottom() final override
3838
{
3939
may_bits.clear();
4040
must_bits.clear();
4141
has_values=tvt(false);
4242
}
4343

44-
void make_top() final
44+
void make_top() final override
4545
{
4646
may_bits.clear();
4747
must_bits.clear();
4848
has_values=tvt(true);
4949
}
5050

51-
void make_entry() final
51+
void make_entry() final override
5252
{
5353
make_top();
5454
}
5555

56+
bool is_bottom() const final override
57+
{
58+
DATA_INVARIANT(!has_values.is_false() ||
59+
(may_bits.empty() && must_bits.empty()),
60+
"If the domain is bottom, it must have no bits set");
61+
return has_values.is_false();
62+
}
63+
64+
bool is_top() const final override
65+
{
66+
DATA_INVARIANT(!has_values.is_true() ||
67+
(may_bits.empty() && must_bits.empty()),
68+
"If the domain is top, it must have no bits set");
69+
return has_values.is_true();
70+
}
71+
5672
bool merge(
5773
const custom_bitvector_domaint &b,
5874
locationt from,

src/analyses/dependence_graph.h

+32-6
Original file line numberDiff line numberDiff line change
@@ -83,40 +83,66 @@ class dep_graph_domaint:public ai_domain_baset
8383
goto_programt::const_targett from,
8484
goto_programt::const_targett to,
8585
ai_baset &ai,
86-
const namespacet &ns) final;
86+
const namespacet &ns) final override;
8787

8888
void output(
8989
std::ostream &out,
9090
const ai_baset &ai,
91-
const namespacet &ns) const final;
91+
const namespacet &ns) const final override;
9292

9393
jsont output_json(
9494
const ai_baset &ai,
9595
const namespacet &ns) const override;
9696

9797
void make_top() final override
9898
{
99-
assert(node_id!=std::numeric_limits<node_indext>::max());
99+
DATA_INVARIANT(node_id!=std::numeric_limits<node_indext>::max(),
100+
"node_id must not be valid");
100101

101102
has_values=tvt(true);
102103
control_deps.clear();
103104
data_deps.clear();
104105
}
105106

106-
void make_bottom() final
107+
void make_bottom() final override
107108
{
108-
assert(node_id!=std::numeric_limits<node_indext>::max());
109+
DATA_INVARIANT(node_id!=std::numeric_limits<node_indext>::max(),
110+
"node_id must be valid");
109111

110112
has_values=tvt(false);
111113
control_deps.clear();
112114
data_deps.clear();
113115
}
114116

115-
void make_entry() final
117+
void make_entry() final override
116118
{
117119
make_top();
118120
}
119121

122+
bool is_top() const final override
123+
{
124+
DATA_INVARIANT(node_id!=std::numeric_limits<node_indext>::max(),
125+
"node_id must be valid");
126+
127+
DATA_INVARIANT(!has_values.is_true() ||
128+
(control_deps.empty() && data_deps.empty()),
129+
"If the domain is top, it must have no dependencies");
130+
131+
return has_values.is_true();
132+
}
133+
134+
bool is_bottom() const final override
135+
{
136+
DATA_INVARIANT(node_id!=std::numeric_limits<node_indext>::max(),
137+
"node_id must be valid");
138+
139+
DATA_INVARIANT(!has_values.is_false() ||
140+
(control_deps.empty() && data_deps.empty()),
141+
"If the domain is bottom, it must have no dependencies");
142+
143+
return has_values.is_false();
144+
}
145+
120146
void set_node_id(node_indext id)
121147
{
122148
node_id=id;

0 commit comments

Comments
 (0)