We have implemented four plugins in our module pluggable analysis framework.
- A flag plugin, which assigns abstract set membership (and therefore typestate) according to integer or boolean flag values;
- A PALE plugin, which assigns abstract set membership based on shape properties of tree-like pointer-based data structures using the Pointer Analysis Logic Engine tool by Anders Møller and Michael I. Schwartzbach.
- A Bohne plugin, which implements field constraint analysis, a sophisticated shape analysis that is more powerful than PALE and less brittle.
- A theorem proving plugin, which assigns abstract set membership arbitrarily, for example, according to membership in array-based data structures. It generates verification conditions to be discharged using the Isabelle theorem proving environment.
A plugin's basic obligation is to show
1) that every procedure's ensures
is implied at all of its
exit points, given the requires
clause and the statements in
the procedure; and 2) the requires
clause of all callees is
satisfied at the callsite. A plugin may discharge its obligations however
it chooses to.
Flag Plugin
The flag analysis plugin is designed to verify modules that use
integer or boolean flags to indicate the typestates of the objects
that they manipulate, and propagates boolean formulas through
requires
and ensures
clauses of callee
procedures. Flag abstraction sections specify the correspondence
between the concrete flag values and the abstract sets from the
specification, as well as the correspondence between the concrete and
the abstract boolean variables.
The flag plugin uses the boolean algebra libraries implemented in BA.ml
and the transfer function itself is implemented in typestate.ml
.
The main loop is in the analyze_module
procedure, and the
per-statement transfer functions are in analyze_stmt
.
It's a big match
statement, and takes advantage of the
fact that we have an Abstract Syntax Tree. This analysis propagates
boolean formulas directly (the same language we use in the
requires
and ensures
clauses), and it updates
the value of abstract sets whenever values are assigned to fields of
objects.
PALE Plugin
Unlike the flag analysis, which we designed to operate within our analysis framework, the PALE analysis is a previously implemented analysis package that we integrated into our framework. During the course of this adaptation, we did not modify the PALE analysis package itself — our plugin instead takes the form of a translator that enables PALE to work within our analysis framework.
The bulk of the PALE plugin's implementation is in pale.ml
. For each procedure in the module to be analyzed, this
plugin creates a separate PALE output file, which is then fed to the
PALE analysis tool. The common headers for PALE input files are generated by
palestd.ml
, while the code is emitted by
paleprinter.ml
. After emitting PALE output, we spawn
the PALE binary on the emitted output. We did modify PALE to return an output
code of 42 upon success, so that we don't have to parse the output to
figure out whether PALE succeeded or not.
Theorem Proving Plugin
The theorem proving plugin generates verification conditions using weakest preconditions and discharges them using the Isabelle theorem prover. We have chosen this technique as a last resort for verifying arbitrarily complicated data structure implementations. The logic for specifying abstraction functions is based on typed set theory and proof obligations can be discharged using automated theorem proving or a proof checker for manually generated proofs, which means that there is no \emph{a priori} bound on the complexity of the data structures (and data structure consistency properties) that can be verified.
The verification condition generator is implemented in
vcgen.ml
. It uses verification condition formula parsing
libraries (we have a ocamlyacc grammar for these formulas, and the
formula manipulation library is in vcform.ml
). The engine is the
decide_sq
procedure of vcgen.ml
; given
a verification condition, it uses the vclemmas.ml
library to verify
whether the condition is cached as being true. If not, it invokes Isabelle
to attempt to automatically discharge the verification condition.
When using this plugin to prove arbitrarily complicated properties, one
adds lemmas to the proof base until the property goes through.