Skip to content

Commit e2b6761

Browse files
authored
Merge pull request diffblue#48 from diffblue/goto-analyzer-fixes
Goto analyzer fixes
2 parents cf4ff51 + afa3ad1 commit e2b6761

File tree

4 files changed

+192
-35
lines changed

4 files changed

+192
-35
lines changed

src/analyses/variable-sensitivity/abstract_enviroment.cpp

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Function: abstract_environmentt::eval
2626
2727
Inputs:
2828
expr - the expression to evaluate
29+
ns - the current namespace
2930
3031
Outputs: The abstract_object representing the value of the expression
3132
@@ -139,7 +140,7 @@ Function: abstract_environmentt::assign
139140
expr - the expression to assign to
140141
value - the value to assign to the expression
141142
142-
Outputs: ?
143+
Outputs: A boolean, true if the assignment has changed the domain.
143144
144145
Purpose: Assign a value to an expression
145146
@@ -274,34 +275,43 @@ bool abstract_environmentt::assign(
274275
Function: abstract_environmentt::assume
275276
276277
Inputs:
277-
expr - the expression inside the assume
278+
expr - the expression that is to be assumed
279+
ns - the current namespace
278280
279-
Outputs: ?
281+
Outputs: True if the assume changed the domain.
280282
281-
Purpose: ?
283+
Purpose: Reduces the domain to (an over-approximation) of the cases
284+
when the the expression holds. Used to implement assume
285+
statements and conditional branches.
282286
283287
\*******************************************************************/
284288

285289
bool abstract_environmentt::assume(const exprt &expr, const namespacet &ns)
286290
{
291+
// We should only attempt to assume Boolean things
292+
// This should be enforced by the well-structured-ness of the goto-program
293+
assert(expr.type().id()==ID_bool);
294+
295+
// Evaluate the expression
287296
abstract_object_pointert res = eval(expr, ns);
288-
std::string not_implemented_string=__func__;
289-
not_implemented_string.append(" not implemented");
290-
throw not_implemented_string;
291-
// Need abstract_booleant
292-
#if 0
293-
abstract_booleant *b = dynamic_cast<abstract_booleant>(res);
294297

295-
assert(b != NULL);
298+
exprt possibly_constant = res->to_constant();
296299

297-
if (b->to_constant().is_false())
300+
if (possibly_constant.id()!=ID_nil) // I.E. actually a value
298301
{
299-
make_bottom();
300-
return true;
302+
assert(possibly_constant.type().id()==ID_bool); // Should be of the right type
303+
304+
if (possibly_constant.is_false())
305+
{
306+
bool currently_bottom = get_is_bottom();
307+
make_bottom();
308+
return !currently_bottom;
309+
}
301310
}
302-
else
303-
return false;
304-
#endif
311+
312+
// TODO - need a way of converting x==23 into an assign for the value of x
313+
314+
return false;
305315
}
306316

307317

@@ -372,9 +382,9 @@ Function: abstract_environmentt::merge
372382
Inputs:
373383
env - the other environment
374384
375-
Outputs: ?
385+
Outputs: A Boolean, true when the merge has changed something
376386
377-
Purpose: ?
387+
Purpose: Computes the join between "this" and "b"
378388
379389
\*******************************************************************/
380390

@@ -466,7 +476,7 @@ Function: abstract_environmentt::havoc
466476
Inputs:
467477
havoc_string - debug string to track down havoc causing.
468478
469-
Outputs:
479+
Outputs: None
470480
471481
Purpose: Set the domain to top
472482
@@ -482,9 +492,9 @@ void abstract_environmentt::havoc(const std::string &havoc_string)
482492
483493
Function: abstract_environmentt::make_top
484494
485-
Inputs:
495+
Inputs: None
486496
487-
Outputs:
497+
Outputs: None
488498
489499
Purpose: Set the domain to top
490500
@@ -493,7 +503,6 @@ Function: abstract_environmentt::make_top
493503
void abstract_environmentt::make_top()
494504
{
495505
// since we assume anything is not in the map is top this is sufficient
496-
// TODO: need a flag for bottom
497506
map.clear();
498507
is_bottom=false;
499508
}
@@ -502,9 +511,9 @@ void abstract_environmentt::make_top()
502511
503512
Function: abstract_environmentt::make_bottom
504513
505-
Inputs:
514+
Inputs: None
506515
507-
Outputs:
516+
Outputs: None
508517
509518
Purpose: Set the domain to top
510519
@@ -556,10 +565,10 @@ Function: abstract_environmentt::output
556565
557566
Inputs:
558567
out - the stream to write to
559-
ai - ?
560-
ns - ?
568+
ai - the abstract interpreter that contains this domain
569+
ns - the current namespace
561570
562-
Outputs:
571+
Outputs: None
563572
564573
Purpose: Print out all the values in the abstract object map
565574

src/analyses/variable-sensitivity/variable_sensitivity_domain.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,17 +71,15 @@ void variable_sensitivity_domaint::transform(
7171
case GOTO:
7272
{
7373
// TODO(tkiley): add support for flow sensitivity
74-
#if 0
75-
if (flow_sensitivity == FLOW_SENSITIVE)
74+
if (1) // (flow_sensitivity == FLOW_SENSITIVE)
7675
{
7776
locationt next=from;
7877
next++;
7978
if(next==to)
80-
assume(not_exprt(instruction.guard));
79+
abstract_state.assume(not_exprt(instruction.guard), ns);
8180
else
82-
assume(instruction.guard);
81+
abstract_state.assume(instruction.guard, ns);
8382
}
84-
#endif
8583
}
8684
break;
8785

@@ -102,6 +100,8 @@ void variable_sensitivity_domaint::transform(
102100
case ASSERT:
103101
// Conditions on the program, do not alter the data or information
104102
// flow and thus can be ignored.
103+
// Checking of assertions can only be reasonably done once the fix-point
104+
// has been computed, i.e. after all of the calls to transform.
105105
break;
106106

107107
case SKIP:
@@ -233,14 +233,16 @@ bool variable_sensitivity_domaint::merge(
233233
Function: variable_sensitivity_domaint::ai_simplify
234234
235235
Inputs:
236-
condition - the expression to evaluate to true or false
236+
condition - the expression to simplify
237237
ns - the namespace
238238
lhs - is the expression on the left hand side
239239
240240
Outputs: True if simplified the condition. False otherwise. condition
241241
will be updated with the simplified condition if it has worked
242242
243-
Purpose: To resolve a condition down to a possibly known boolean value
243+
Purpose: Use the information in the domain to simplify the expression
244+
with respect to the current location. This may be able to
245+
reduce some values to constants.
244246
245247
\*******************************************************************/
246248

src/analyses/variable-sensitivity/variable_sensitivity_domain.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,60 @@
44
55
Author: Thomas Kiley, [email protected]
66
7+
There are different ways of handling arrays, structures, unions and
8+
pointers. Our existing solution basically ignores them which is
9+
imprecise at best and out-right wrong at worst. For one project we
10+
needed to do better. We could have implemented a particular way of
11+
handling them in an existing domain, created a new one with it, etc.
12+
This would work but it means duplicate code and it is is inflexible when
13+
the same person / the next person comes along and says "actually, we
14+
really care about the pointer precision but less so the array so could
15+
you just ...". Thus the idea was to do this properly:
16+
17+
1. Build a "non-relational domain" and allow the abstractions used for
18+
individual variables to be different.
19+
20+
2. Give the user the option of which abstractions are used for structs,
21+
unions, arrays and pointers. These are the sensitivity options
22+
discussed above.
23+
24+
3. Have the domain options control which kind of abstractions are used
25+
for the individual values, i.e. constants, intervals, etc.
26+
27+
28+
This is implemented in three parts:
29+
30+
abstract_objectt : The base / interface for abstractions of a single
31+
variable. The interface for these is effectively create (as top,
32+
bottom, from a constant or copy), transform, merge, convert to constant
33+
if possible. Child classes add additional bits of interface, for
34+
example array abstractions need a "read element" and a "write element"
35+
method, structures need a "read field" and "write field", etc. These
36+
objects are intended to be immutable and thus operations tend to produce
37+
pointers. This is so that we can easily produce copy-on-write maps of
38+
them which we need for scaling and performance. There are also children
39+
of these for the constant abstraction of one value, the interval
40+
abstraction of one value (to be implemented), etc.
41+
42+
abstract_environment : This contains the map from variable names for
43+
abstract_objectt's (the "non-relational" part of the domain). The map
44+
itself if copy-on-write for performance and scalability but this is all
45+
wrapped up nicely in @danpoe's sharing_map. The interface here is
46+
evaluate (exprt -> abstract_objectt*), assign (name, abstract_objectt*
47+
-> bool), assume (exprt -> bool) and merge. It has a factory to build
48+
abstract_objectt* from types or constants but apart from that, doesn't
49+
know anything about which actual abstract_objectt's are being used. As
50+
long as program variables that are arrays have an abstract_objectt which
51+
has the array interface, and so on for structs, unions, etc. then the
52+
abstractions used for values can be freely mixed and matched in any way
53+
the user can get the factory to build.
54+
55+
variable_sensitivity_domaint : Implements the ai_domain_baset interface
56+
using an abstract_environment. The only real code here is the
57+
'transform' method which looks at the instruction type and converts that
58+
into calls to eval, assume, assign and merge.
59+
60+
761
\*******************************************************************/
862
#ifndef CPROVER_GOTO_ANALYZER_VARIABLE_SENSITIVITY_VARIABLE_SENSITIVITY_DOMAIN_H
963
#define CPROVER_GOTO_ANALYZER_VARIABLE_SENSITIVITY_VARIABLE_SENSITIVITY_DOMAIN_H

src/goto-analyzer/goto_analyzer_parse_options.h

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,98 @@ Module: Goto-Analyser Command Line Option Processing
44
55
Author: Daniel Kroening, [email protected]
66
7+
Goto-analyze is the tool front-end for CPROVER's classic style abstract
8+
interpretation analyses. By "classic style" I mean, domains are C++
9+
objects, transformers are computed using C++ functions and the
10+
fix-points are computed by iteration. This is in contrast to 2LS's
11+
approach where everything is computed using quantifier-elimination.
12+
13+
The analyses are mostly in analyses/ and although they are used in other
14+
places in the code, the goal is that goto-analyze should eventually
15+
provide an executable front-end for all of them.
16+
17+
There are a lot of different analyses and a lot of ways they can be
18+
used. Goto-analyze has five, largely independent, sets of options:
19+
20+
1. Task : What you do once you've computed the domains.
21+
2. Abstract interpreter : What kind of abstract interpretation you do.
22+
3. Domain : What domain you use.
23+
4. Sensitivity : How that domain handles things like arrays, pointers, etc.
24+
(see variable_sensitivity_domain.h)
25+
5. Output : What you do with the results.
26+
27+
Formally speaking, 2, 3 and 4 are an artificial distinction as they are
28+
all really parts of the "what domain" question. However they correspond
29+
to parts of our code architecture, so ... they should stay.
30+
31+
Ideally, the cross product of options should be supported but ... in
32+
practice there will always be ones that are not meaningful. Those
33+
should give errors. In addition there are some analyses which are
34+
currently stand alone as they don't fit directly in to this model. For
35+
example the unwind bounds analysis, which is both the task, the abstract
36+
interpreter and the output. Where possible these should be integrated /
37+
support the other options. In the case of the unwind analysis this
38+
means the domain and it's sensitivity should be configurable.
39+
40+
41+
Task
42+
----
43+
44+
Tasks are implemented by the relevant file in goto-analyze/static_*. At
45+
the moment they are each responsible for building the domain / using the
46+
other options. As much as possible of this code should be shared. Some
47+
of these inherit from messaget. They all probably should.
48+
49+
Show : Prints out the domains for inspection or further use.
50+
51+
Verify : Uses the domain to check all assertions in the code, marking
52+
each one "SUCCESS" (the assertion always holds), "FAILURE if
53+
reachable" (the assertion never holds), "UNKNOWN" (the assertion may or
54+
may not hold). This is implemented using domain_simplify().
55+
56+
Simplify : Generates a new goto program with branch conditions,
57+
assertions, assumptions and assignments simplified using the information
58+
in the domain (again using domain_simplify()). This task is intended to
59+
be used as a preprocessing step for other analysis.
60+
61+
Invariants : (Not implemented yet) Use the domains to add assume()
62+
statements to the code giving invariants generated from the domain.
63+
These assumes don't reduce the space of possible executions; they make
64+
existing invariants explicit. Again, intended as a preprocessing step.
65+
66+
67+
Abstract Interpreter
68+
--------------------
69+
70+
This option is effectively about how we compute the fix-point(s) /
71+
which child class of ai_baset we use. I.E. ait<domainT> or
72+
concurrency_aware_ait<domainT>, etc. For migrating / refactor /
73+
unifying with the pointer analysis code we might want a
74+
location_insensitive_ait<domainT> or something but this is not urgent.
75+
We will need a context_aware_ait<domainT>, quite possibly the one
76+
@danpoe has written elsewhere.
77+
78+
79+
Domain
80+
------
81+
82+
Which child of ai_domain_baset we use to represent the abstract state at
83+
each location / implement the transformers. I expect most of these will
84+
be non-relational (i.e. an abstract object for each variable) due to the
85+
cost of implementing effective non-relational domains in this style vs.
86+
using 2LS. The exception might be equalities, which we could implement
87+
here.
88+
89+
90+
Output
91+
------
92+
93+
Text, XML, JSON plus some others for specific domains such as dependence
94+
graphs in DOT format.
95+
96+
97+
98+
799
\*******************************************************************/
8100

9101
#ifndef CPROVER_GOTO_ANALYZER_GOTO_ANALYZER_PARSE_OPTIONS_H

0 commit comments

Comments
 (0)