IntroductionThe goal of the project is to implement a small static analyzer by abstract interpretation for a simple language. The analyzer will be based on the same numeric abstract domains as the ones seen in the course and lab sessions. But, it will compute the abstract semantics using a different iteration method. In the project, the program is first converted into a controlflow graph by a frontend. Then, abstract values corresponding to sets of possible memory environments are attached to graph nodes (program locations) and propagated along the graph arcs (program instructions) until stabilization. This makes it easy to support nonstructured controlflow (such as gotos) as well as interprocedural analysis. The analyzer comprises three parts:
See also the presentation slides for the project. (available on moodle) OrganizationThe project must be delivered before Sunday, June 4th, 18h00. You can work alone or in group of 2. Please, favor the latter. The project must be delivered by email to the teaching assistant, in the form of a compressed archive (with This directory must contains the source files of your analyzer. Typing If you use another programming langage (than OCaml), please write a short The analyzer itself is expected to be a standalone program that takes as argument a source file containing a
Since the soundness and precision of your analyzer will be tested automatically, make sure that possible assertions failures are reported in the following format:
The directory should also contains:
Language and frontendThe language syntax is a simple subset of C, a description of the syntax is available. The sources of the frontend are available on the moodle. The frontend works as follows:
The Please read the description of the controlflow graph datastructure. The datastructure is defined in the file Expected workIteratorYou must implement an iterator, able to traverse the controlflow graph and compute an abstract information at each node. Note that you don’t need to support procedure calls as a core feature: this is one of several possible extensions. However, you must support arbitrary gotos, including backward gotos (which can be used to disguise loops). The iterator should be generic in the choice of the abstract domain: i.e., a functor parameterized by a module obeying the DOMAIN signature discussed below. Make sure that your iterator always terminates (employing widening if needed). Hints We suggest employing a classic worklist algorithm, which maintains a map from nodes to abstract values as well as a set of nodes to update. At each step, a node is extracted from the worklist and updated. The update consists in:
Other iteration algorithms exist, in particular those proposed by François Bourdoncle. In case of loops or backward gotos, the controlflow graph will have cycles, causing the same nodes to be considered many times. In order for the algorithm to finish in finite time and be efficient in practice, you will need to apply widening at selected widening points to enforce convergence. It is sufficient that any cycle in the controlflow graph has at least one node where widening is applied. You can for instance select as widening nodes all loop heads and the destination of backward gotos. Abstract domainsYou must implement at least two numeric abstract domains seen in the course:
Calling the analyzer with the Hints In order to test your iterator before you design your abstract domains, you can start by implementing a concrete domain first as we did in the practical sessions, i.e., a domain manipulating sets of program environments without any abstraction. Note that, in this case, the analyzer may not always terminate. The concrete interpretation is optional. The file
We suggest that you first program abstract domains able to abstract sets of integers (e.g., a single interval), following the signature
The Modeling a In case of more complex expressions, featuring arithmetic operators, such as As the guards are more complex, you are only required to support As hinted above, the implementation of a ExtensionsYou must implement at least one of the following extensions. Backward analysisThis extension should be performed when a The analysis considered in part 2 is forward: given the memory environment at the beginning of the program, an abstraction of the environments reachable during program execution is computed. The analysis outputs a map from graph nodes to abstract invariants. A backward analysis starts form this map, and considers some target location in the middle of the program and a target abstract environment. It then traces backward the program execution from the target location to refine the result of the forward analysis by only considering executions that will reach the target location with the target environment. In this extension, we target the environments that do not satisfy an assertion. The analysis will thus help discovering which program executions cause the assertion to fail. You should provide examples illustrating how your backward analysis achieves this. Hints Building a backward analysis requires two changes with respect to a forward analysis:
Interprocedural analysisThis extension consists in implementing the support for function calls. To simplify, you can assume that there are not recursive calls. Hence, at any point of the execution, there exists at most a single instance of each local variable and formal function argument (as opposed to a stack of such variables, required to implement recursivity). This is compatible with the way programs are translated into graphs in the frontend: all variables and function arguments are considered as global variables. Supporting recursivity is more complex and requires some changes to the frontend. You should provide a few examples and discuss the results of your analysis on these examples. Hints We suggest implementing a simple interprocedural analysis where abstract environments flow from call sites (source nodes of a call instruction arc) to the entry node of the called function, and back from the exit node of the called function to the return site (destination nodes of a call instruction arc). Polyhedral analysisCalling the analyzer with This extension requires you to implement an analysis using the polyhedra abstract domain. You will use the Apron library that already implements all
the polyhedral abstract operators, and use to implement a module obeying the Relational analyses such as polyhedra are especially useful in the presence of loops, where a relational invariant must be found (which is not possible with nonrelational domains such as intervals). You should provide a few examples illustrating this point and discuss the results of your analysis on these examples, comparing in particular the polyhedral and interval analyses. Disjunctive analysisThis extension requires you to implement an abstract domain functor able to represent disjunctions of abstract elements of a base domain, for instance, associate several intervals to a variable. This is especially useful to avoid loosing precision at controlflow joins, and to represent nonconvex invariants. We will see in the course several ways to design a disjunctive domain, and you can choose whichever way you wish (disjunctive completion, state partitioning, trace partitioning). Other IdeaAfter discussing it with the teacher ! Resources and BibliographyFrontendSoftware:
On the HC4revise algorithm:
On backwards analysis:
On polyhedral analyses and Apron:
On disjunctive analyses:
