8
8
9
9
// / \file
10
10
// / 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.
11
44
12
45
#ifndef CPROVER_ANALYSES_AI_H
13
46
#define CPROVER_ANALYSES_AI_H
28
61
#include " ai_storage.h"
29
62
#include " is_threaded.h"
30
63
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.
33
98
// /
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
+
35
118
class ai_baset
36
119
{
37
120
public:
@@ -336,7 +419,7 @@ class ai_baset
336
419
337
420
// / Run the fixedpoint algorithm until it reaches a fixed point
338
421
// / \return True if we found something new
339
- bool fixedpoint (
422
+ virtual bool fixedpoint (
340
423
const irep_idt &function_id,
341
424
const goto_programt &goto_program,
342
425
const goto_functionst &goto_functions,
@@ -349,7 +432,7 @@ class ai_baset
349
432
// / Depending on the instruction type it may compute a number of "edges"
350
433
// / or applications of the abstract transformer
351
434
// / \return True if the state was changed
352
- bool visit (
435
+ virtual bool visit (
353
436
const irep_idt &function_id,
354
437
trace_ptrt p,
355
438
working_sett &working_set,
@@ -453,45 +536,12 @@ class ai_recursive_interproceduralt : public ai_baset
453
536
const namespacet &ns) override ;
454
537
};
455
538
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.
495
545
// /
496
546
// / \tparam domainT A type derived from ai_domain_baset that represents the
497
547
// / values in the AI domain
@@ -572,6 +622,13 @@ class ait : public ai_recursive_interproceduralt
572
622
// /
573
623
// / \tparam domainT A type derived from ai_domain_baset that represents the
574
624
// / 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.
575
632
template <typename domainT>
576
633
class concurrency_aware_ait :public ait <domainT>
577
634
{
0 commit comments