Skip to content

Commit dd9bf17

Browse files
martinmartin
authored andcommitted
Update the documentation in the key abstract interpreter classes
This reflects the changes in the structure and best practice that result from this series of patches.
1 parent 1587143 commit dd9bf17

File tree

3 files changed

+139
-45
lines changed

3 files changed

+139
-45
lines changed

src/analyses/ai.h

Lines changed: 101 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,39 @@ Author: Daniel Kroening, [email protected]
88

99
/// \file
1010
/// Abstract Interpretation
11+
///
12+
/// This is the core of the abstract interpretation framework.
13+
/// To run an analysis you need four components:
14+
///
15+
/// 1. An abstract interpreter, derived from ai_baset.
16+
/// This performs that actual analysis. There are a number of alternative
17+
/// to choose from, primarily giving different ways of handling function
18+
/// calls / interprocedural analysis.
19+
/// More information is given in this file.
20+
///
21+
/// 2. A history factory, derived from ai_history_factory_baset.
22+
/// This generates history objects (derived from ai_history_baset) which
23+
/// control the number of steps that the analysis performs. These can be
24+
/// simple, just tracking location, or they can be complex, tracking
25+
/// location, function calls, branches (forwards and backwards), even
26+
/// threading.
27+
/// See ai_history.h for more information.
28+
///
29+
/// 3. A domain factory, derived from ai_domain_factory_baset.
30+
/// This generates domain objects (derived from ai_domain_baset) which
31+
/// represent the sets of possible valuations that the variables can take at
32+
/// a given point (given history). These can be very simple, just tracking
33+
/// whether a location is reachable or not, or they can be very
34+
/// sophisticated tracking relations between variables, pointers, etc.
35+
/// See ai_domain.h for more information.
36+
///
37+
/// 4. A storage object, derived from ai_storage_baset.
38+
/// This stores the history and domain objects and manages the link.
39+
/// The simplest case is to store one domain per history
40+
/// (see history_sensitive_storaget). However this can require a large
41+
/// amount of memory being used, so there are options to share / merge
42+
/// domains between different histories, reducing precision in return for
43+
/// better performance.
1144

1245
#ifndef CPROVER_ANALYSES_AI_H
1346
#define CPROVER_ANALYSES_AI_H
@@ -28,10 +61,60 @@ Author: Daniel Kroening, [email protected]
2861
#include "ai_storage.h"
2962
#include "is_threaded.h"
3063

31-
/// The basic interface of an abstract interpreter. This should be enough
32-
/// to create, run and query an abstract interpreter.
64+
/// This is the basic interface of the abstract interpreter with default
65+
/// implementations of the core functionality.
66+
///
67+
/// Users of abstract interpreters should use the interface given by this class.
68+
/// It breaks into three categories:
69+
///
70+
/// 1. Running an analysis, via
71+
/// \ref ai_baset#operator()(const irep_idt&,const goto_programt&, <!--
72+
/// --> const namespacet&),
73+
/// \ref ai_baset#operator()(const goto_functionst&,const namespacet&)
74+
/// and \ref ai_baset#operator()(const abstract_goto_modelt&)
75+
/// 2. Accessing the results of an analysis, by looking up the history objects
76+
/// for a given location \p l using
77+
/// \ref ai_baset#abstract_traces_before(locationt)const
78+
/// or the domains using
79+
/// \ref ai_baset#abstract_state_before(locationt)const
80+
/// 3. Outputting the results of the analysis; see
81+
/// \ref ai_baset#output(const namespacet&, const irep_idt&,
82+
/// const goto_programt&, std::ostream&)const et cetera.
83+
///
84+
/// Where possible, uses should be agnostic of the particular configuration of
85+
/// the abstract interpreter. The "tasks" that goto-analyze uses are good
86+
/// examples of how to do this.
87+
///
88+
/// From a development point of view, there are several directions in which
89+
/// this can be extended by inheriting from ai_baset or one of its children:
90+
///
91+
/// A. To change how single edges are computed
92+
/// \ref ait#visit_edge and \ref ait#visit_edge_function_call
93+
/// ai_recursive_interproceduralt uses this to recurse to evaluate
94+
/// function calls rather than approximating them as ai_baset does.
95+
///
96+
/// B. To change how individual instructions are handled
97+
/// \ref ait#visit() and related functions.
3398
///
34-
/// Note: this is just a base class. \ref ait should be used instead.
99+
/// C. To change the way that the fixed point is computed
100+
/// \ref ait#fixedpoint()
101+
/// concurrency_aware_ait does this to compute a fixed point over threads.
102+
///
103+
/// D. For pre-analysis initialization
104+
/// \ref ait#initialize(const irep_idt&, const goto_programt&),
105+
/// \ref ait#initialize(const irep_idt&,
106+
/// const goto_functionst::goto_functiont&) and
107+
/// \ref ait#initialize(const goto_functionst&),
108+
///
109+
/// E. For post-analysis cleanup
110+
/// \ref ait#finalize(),
111+
///
112+
/// Historically, uses of abstract interpretation inherited from ait<domainT>
113+
/// and added the necessary functionality. This works (although care must be
114+
/// taken to respect the APIs of the various components -- there are some hacks
115+
/// to support older analyses that didn't) but is discouraged in favour of
116+
/// having an object for the abstract interpreter and using its public API.
117+
35118
class ai_baset
36119
{
37120
public:
@@ -336,7 +419,7 @@ class ai_baset
336419

337420
/// Run the fixedpoint algorithm until it reaches a fixed point
338421
/// \return True if we found something new
339-
bool fixedpoint(
422+
virtual bool fixedpoint(
340423
const irep_idt &function_id,
341424
const goto_programt &goto_program,
342425
const goto_functionst &goto_functions,
@@ -349,7 +432,7 @@ class ai_baset
349432
/// Depending on the instruction type it may compute a number of "edges"
350433
/// or applications of the abstract transformer
351434
/// \return True if the state was changed
352-
bool visit(
435+
virtual bool visit(
353436
const irep_idt &function_id,
354437
trace_ptrt p,
355438
working_sett &working_set,
@@ -453,45 +536,12 @@ class ai_recursive_interproceduralt : public ai_baset
453536
const namespacet &ns) override;
454537
};
455538

456-
/// Base class for abstract interpretation. An actual analysis
457-
/// must (a) inherit from this class and (b) provide a domain class as a
458-
/// type argument, which must, in turn, inherit from \ref ai_domain_baset.
459-
///
460-
/// From a user's perspective, this class provides three main groups of
461-
/// functions:
462-
///
463-
/// 1. Running an analysis, via
464-
/// \ref ai_baset#operator()(const irep_idt&,const goto_programt&, <!--
465-
/// --> const namespacet&),
466-
/// \ref ai_baset#operator()(const goto_functionst&,const namespacet&)
467-
/// and \ref ai_baset#operator()(const abstract_goto_modelt&)
468-
/// 2. Accessing the results of an analysis, by looking up the result
469-
/// for a given location \p l using
470-
/// \ref ait#abstract_state_before(goto_programt::const_targett).
471-
/// 3. Outputting the results of the analysis; see
472-
/// \ref ai_baset#output(const namespacet&, const irep_idt&,
473-
/// const goto_programt&, std::ostream&)const et cetera.
474-
///
475-
/// A typical usage pattern would be to call the analysis first,
476-
/// and use `abstract_state_before` to retrieve the results. The fixed
477-
/// point algorithm used is a standard worklist algorithm; ait
478-
/// implementation is flow- and path-sensitive, but not context-sensitive.
479-
///
480-
/// From an analysis developer's perspective, an analysis is implemented by
481-
/// inheriting from this class (or, if a concurrency-sensitive analysis is
482-
/// required, from \ref concurrency_aware_ait), providing a class implementing
483-
/// the abstract domain as the type for the \p domainT parameter. Most of the
484-
/// actual analysis functions (in particular, the minimal element, the lattice
485-
/// join, and the state transformer) are supplied using \p domainT.
486-
///
487-
/// To control the analysis in more detail, you can also override the following
488-
/// methods:
489-
/// - \ref ait#initialize(const irep_idt&, const goto_programt&),
490-
/// \ref ait#initialize(const irep_idt&,
491-
/// const goto_functionst::goto_functiont&) and
492-
/// \ref ait#initialize(const goto_functionst&), for pre-analysis
493-
/// initialization
494-
/// - \ref ait#finalize(), for post-analysis cleanup.
539+
/// ait supplies three of the four components needed: an abstract interpreter
540+
/// (in this case handling function calls via recursion), a history factory
541+
/// (using the simplest possible history objects) and storage (one domain per
542+
/// location). The fourth component, the domain, is provided by the template
543+
/// parameter. This is gives a "classical" abstract interpreter and is
544+
/// backwards compatible with older code.
495545
///
496546
/// \tparam domainT A type derived from ai_domain_baset that represents the
497547
/// values in the AI domain
@@ -572,6 +622,13 @@ class ait : public ai_recursive_interproceduralt
572622
///
573623
/// \tparam domainT A type derived from ai_domain_baset that represents the
574624
/// values in the AI domain
625+
///
626+
/// It is important to note that the domains used by this need an extra merge
627+
/// method, but, far more critically, they need the property that it is not
628+
/// possible to "undo" changes to the domain. Tracking last modified location
629+
/// has this property, numerical domains such as constants and intervals do not
630+
/// and using this kind of concurrent analysis for these domains may miss
631+
/// significant behaviours.
575632
template<typename domainT>
576633
class concurrency_aware_ait:public ait<domainT>
577634
{

src/analyses/ai_domain.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,34 @@ Author: Daniel Kroening, [email protected]
88

99
/// \file
1010
/// Abstract Interpretation Domain
11+
///
12+
/// An abstract domain is an over-approximation of a set of possible valuations
13+
/// that the variables in a program may take at a given point in the program.
14+
/// For example if you have two variables, x and y and at a given point they
15+
/// can take the following values:
16+
///
17+
/// (x = 1, y = -1), (x = -1, y = -1), (x = 1, y = 0)
18+
///
19+
/// then you could represent this with a pair of intervals:
20+
///
21+
/// x in [-1,1], y in [-1,0]
22+
///
23+
/// this is an over-approximation as it also describes valuations, like,
24+
/// (x = 0, y = 0) which are not in the set. It also omits things like the
25+
/// link between the variables, such as knowning x >= y.
26+
/// However, in return for some imprecision (in a known direction), it gains
27+
/// scalability. A pair of intervals can represent sets of valuations that
28+
/// might contain millions or billions of pairs.
29+
///
30+
/// The abstract interpretation framework is modular in terms of the domain
31+
/// used. Inherit from ai_domain_baset, implement the pure virtual functions
32+
/// and add a merge method and your domain can be plugged in to the analysis.
33+
/// The actual "glue" is a factory so that you can have domains with non-trivial
34+
/// constructors. These inherit from ai_domain_factory_baset, but
35+
/// ai_domain_factory_default_constructort<your_domain> will be fine if the
36+
/// default constructor is fine and inheriting from
37+
/// ai_domain_factoryt<your_domain> will be fine if non-trivial constructors
38+
/// are needed.
1139

1240
#ifndef CPROVER_ANALYSES_AI_DOMAIN_H
1341
#define CPROVER_ANALYSES_AI_DOMAIN_H
@@ -54,6 +82,9 @@ class ai_domain_baset
5482
/// of the function to the instruction _following_ the call site
5583
/// (this also needs to set the LHS, if applicable)
5684
///
85+
/// in some cases, function calls are skipped, in which case:
86+
/// c) there is an edge from the call instruction to the instruction after
87+
///
5788
/// "this" is the domain before the instruction "from"
5889
/// "from" is the instruction to be interpreted
5990
/// "to" is the next instruction (for GOTO, FUNCTION_CALL, END_FUNCTION)

src/analyses/ai_storage.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,18 @@ Author: Martin Brain, [email protected]
77
\*******************************************************************/
88

99
/// \file
10+
/// Abstract Interpretation Storage
11+
///
1012
/// An interface for the storage of domains in the abstract interpreter.
11-
/// Conceptually this is a map from location -> domain.
13+
/// Conceptually this is a map from history -> domain.
1214
/// However in some cases we may wish to share domains between locations
1315
/// so a simple map interface is not sufficient.
1416
/// Also any domain that has not been previously accessed or stored is
1517
/// automatically bottom.
18+
/// There is a constant interface which returns shared pointers to const
19+
/// domains, allowing these to either be stored domains, or things created
20+
/// on-the-fly. The non-constant interace returns a reference as it can
21+
/// create and initialise the domains as needed.
1622

1723
#ifndef CPROVER_ANALYSES_AI_STORAGE_H
1824
#define CPROVER_ANALYSES_AI_STORAGE_H

0 commit comments

Comments
 (0)