-
Notifications
You must be signed in to change notification settings - Fork 14
T2 Temporal Prover
License
mmjb/T2
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
====================================== ====== T2 TEMPORAL LOGIC PROVER ====== ====================================== In this directory you will find the sources for the T2 temporal logic prover. T2 is designed to prove temporal properties of programs, such as safety, termination, or properties specified in the logic CTL. In this document, we first discuss how to use the tool and explain how to build it. Then, we give a rough overview of the implementation, and finally list the developers of the tool and point to some related research papers. ----------- Building T2 ----------- Windows ~~~~~~~ To build T2, we recommend using Visual Studio (2013 or later), but you can also follow the Mono instructions provided below. In Visual Studio, the used NuGet packages are managed through Visual Studio and do not need to be downloaded manually (i.e., skip step (4)). To use the included libz3.dll, you need to install the Visual Studio 2015 C++ run-time from https://www.microsoft.com/en-us/download/details.aspx?id=48145 Using Mono (for Linux and MacOS) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To build T2, you will first need to build the .NET bindings of z3/spacer using mono. For this, you need to get z3 sources from the "spacer-t2" branch of https://bitbucket.org/spacer/code (cf. step (1)). To install some needed .NET libraries, you will need NuGet, which you can obtain from https://nuget.org/nuget.exe. Let $NUGET be the path to your nuget.exe download, $Z3DIR the directory in which you want to store your Z3 sources, and $T2DIR the directory in which you want to store the T2 sources. You can set these environment variables by "export NUGET=/path/to/nuget.exe" in your shell. Then follow these steps: (0) Install software needed for the build process, get T2 sources: * g++ * python * mono for .NET 4.0 * xbuild * fsharp On a Debian (>> squeezy) or Ubuntu (>= 14.04 LTS) system, this suffices: $ sudo apt-get install build-essential python mono-complete mono-xbuild fsharp On OS X, install the Mono MDK for Mac OS from https://www.mono-project.com/download/ and install the XCode development tools (e.g., by executing "gcc" in a Terminal -- if it's not there yet, OS X will offer to install XCode). To download the T2 sources: $ mkdir -p "$T2DIR" $ git clone https://github.com/mmjb/T2.git $ export T2DIR="$T2DIR/T2" (1) Build z3. On Linux, the following recipe retrieves the z3 sources and builds z3: $ mkdir -p "$Z3DIR" $ pushd "$Z3DIR" $ git clone https://bitbucket.org/spacer/code $ cd code $ git checkout spacer-t2 $ ./configure $ cd build $ make $ popd On OS X, you need to enforce a 32bit build (for compatibility with Mono): $ mkdir -p "$Z3DIR" $ pushd "$Z3DIR" $ git clone https://bitbucket.org/spacer/code $ cd code $ git checkout spacer-t2 $ ./configure $ cd build $ perl -i -pe 's/-D_AMD64_/-arch i386/; s/LINK_EXTRA_FLAGS=/$&-arch i386 /' config.mk $ make $ popd (2) Build the .NET bindings for z3: $ pushd "$Z3DIR/src/api/dotnet/" $ xbuild Microsoft.Z3.csproj $ popd (3) Update z3 and its .NET bindings in the T2 source tree: $ cp "$Z3DIR/src/api/dotnet/obj/Debug/Microsoft.Z3.*" "$T2DIR/src/" $ cp "$Z3DIR/build/libz3.*" "$T2DIR/src/" (4) Get required packages via NuGet (may need to import certificates first): $ mozroots --import --sync $ pushd "$T2DIR/src" $ mono $NUGET restore $ chmod +x packages/FsLexYacc.*/build/*exe $ popd (5) Build T2, in Debug mode: $ pushd "$T2DIR/src" && xbuild && popd In Release configuration: $ pushd "$T2DIR/src" && xbuild /property:Configuration=Release && popd (6) Run T2 as follows (replace "Debug" by "Release" for the release build) $ mono "$T2DIR/src/bin/Debug/T2.exe" For example, to execute the testsuite: $ pushd "$T2DIR/test" && mono "$T2DIR/src/bin/Debug/T2.exe" -tests ---------- Running T2 ---------- T2 is run from the command line, and the following command line arguments are used to define the proof goal: -input_t2 <string>: Path of the input file in T2 syntax. For examples, look at test/*.t2. -termination: Try to prove (non)termination. -safety <int>: Try to prove non-reachability of location <int>. -ctl <CTL_Formula>: Try to prove that <CTL_Formula> holds for the program. The formula format is as follows: - Path and temporal quantifiers are enclosed in square brackets, e.g. [AG], [EF], and [AW]. - Subformulas following quantifiers have to be enclosed in parentheses, e.g. [AG](x > 0) and [EF]([AG](y < x)). For more CTL formula examples, see programTests.fs, or the parser definition in absparse.fsy. -ctlstar <CTLStar_Formula>: Try to prove that <CTLStar_Formula> holds for the program. The formula format is as follows: - E F(G ((tt > 0) || (A F (wakend == 0)) )) - One Path and one temporal quantifier can be paired at a time, separated by a space, followed by parantheses e.g. E F(x == 0), E F(G (tt > 0)), and A F(G (E F (x == 0))) . - Subformulas following quantifiers have to be enclosed in parentheses, as shown above. For more CTL formula examples, see programTests.fs, or the parser definition in absparse.fsy. -fairness <Fairness_Condition>: Try to prove termination/a CTL formula under <Fairness_Condition>. The format of <Fairness_Condition> is "(<P>, <Q>)", where a computation is unfair if an infinite number of states in it satisfy <P>, whereas <Q> is only satisfied finitely often. An example is "(P == 1, Q == 1)", and more examples can be found in programTests.fs. Commonly used options that modify T2 output behaviour: -timeout <int>: Set timeout (in seconds). -print_proof: Print an explanation of the result (for termination only). -log: Turn on verbose logging. This will print a lot of output, and may be hard to understand for non-developers. Typical calls of T2 on Windows, with output, look like this: $ src/bin/Debug/T2.exe -input_t2 test/testsuite/small02.t2 -safety 10000 -timeout 42 Safety proof succeeded $ src/bin/Debug/T2.exe -input_t2 test/testsuite/small01.t2 -termination -print_proof Termination proof succeeded Used the following cutpoint-specific lexicographic rank functions: * For cutpoint 7, used the following rank functions/bounds (in descending priority order): - RF x, bound 2 $ src/bin/Debug/T2.exe -input_t2 test/testsuite/heidy1.t2 -CTL "[AG] (x_1 >= y_1)" Temporal proof succeeded $ src/bin/Debug/T2.exe -input_t2 test/bakery.t2 -CTL "[AG](NONCRITICAL <= 0 || ([AF](CRITICAL > 0)))" -fairness "(P == 1, Q == 1)" Temporal proof succeeded Note that T2 creates "defect" files when proofs fail and logging is enabled. A defect.tt file can be viewed with sdvdefect.exe (which comes with the SDV distribution). ------------- Developing T2 ------------- In the following, we discuss several parts of the implementation in slightly more detail, explaining how high-level algorithms (from our papers) are implemented in T2. Basics, glue and tests: ~~~~~~~~~~~~~~~~~~~~~~~ Implementation: * main.fs: Top level file for T2 program prover. * programTests.fs, test/*: The implementation of the T2 testsuite and oru example collection. * arguments.fs: Command-line arguments to the tool, and place where we store parameters. * log.fs: Central mechanism for controlling logging. * utils.fs, gensym.fs: Helper functions, and local extensions of existing F# data structures. * absflex.fsl, absparse.fsy, parseError.fs: F# Lexer/Yacc files for parsing T2 files. * z.fs: F# functions connecting to the Z3 decision procedure. Representation of programs ~~~~~~~~~~~~~~~~~~~~~~~~~~ We use a very simple representation of programs, using control-flow graphs annotated with "assume" and "assign" commands expressed in linear arithmetic over integers. Recursion, procedures, concurrency, heap, non-linearity are unsupported. To deal with more complex programs we use tools such as SLAyer [8] or Thor [17], which can be used to produce arithmetic abstractions of programs useful for proving termination. In the literature we know how to deal with recursion/procedures (e.g. [10]), concurrency (e.g. [10]), and non-linear arithmetic (e.g. [16]) but these features are not implemented here in T2. Implementation: * programs.fs: Simple representation for arithmetic, non-recursive programs. * counterexample.fs: Routines for dealing with counterexamples, which are sequences of program commands. * analysis.fs: Various standard compiler-level program analysis tools (e.g. live variable analysis). * var.fs: Representation of program variables. * input.fs: Interface for loading representations of programs into the tool. * output.fs: Collection of methods to output (intermediate) programs in other formats. * term.fs: Datatype representing terms. * formula.fs, relation.fs, sparselinear.fs: Datatypes representing linear formulae and relations. Many computations are implemented on a sparse representation of terms based on a map from variables to corresponding coefficients. Often, this is confused with a linear inequation, where the term is meant to be smaller or equal to 0. So for example, "2*x <= 4*y" is represented as a map m with m.[x] = 2, m.[y] = -4. * dominators.fs, scc.fs: Dominators computation using the technique from [33], strongly connected components computation. Termination proving algorithm ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Here the tool implements the TERMINATOR-based approach to termination proving (e.g. [6,22,23]) with some modifications as described in [1] and [3]. For those not well versed in formal methods literature the best place to start might be by reading [6]. The idea of the technique is is to reduce the checking of termination arguments to an incrementally evolving safety problem. The refinement of the current termination argument is performed on counterexamples from the safety prover, which give rise to a form of lasso-counterexample. T2 implements the optimizations/extensions/modifications from [1,3], which modify the original technique to search for lexicographic termination arguments as well as adapt techniques from the dependency-pairs approach to termination proving. Implementation: * termination.fs: Contains the main termination proving loop in the function "prover", as described in the original refinement-based termination papers [6,22,23]. It also incorporates the optimizations for lexicographic termination proofs in this setting, as described in [1,3]. * lasso.fs: Implements the subprocedures needed to analyze counterexample lassos to refine termination arguments, as discussed in [1,3,22,23]. * instrumentation.fs: Provides the program modification procedures needed for refinement-based termination analysis. The initial transformation is performed by "instrument_F" (F ~ finally), and subsequent modification steps (for changed termination arguments) are in the instrument_*_RF and switch_to_* functions. * rankfunction.fs: Implements the actual rank function synthesis algorithms (based on Farkas' Lemma) presented in [24,25,26,27]. * recurrentsets.fs: Rudimentary non-termination proving techniques based on [36], adapated to the lasso-setting. Temporal Logic (CTL) proving algorithm ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This version of T2 incorporates the branching-time logic verifier described in [34]. For those unfamiliar with temporal logic verification for infinite-state systems, do refer to [7], where a technique that reduces temporal property verification to a program analysis problem is described. In this CTL model checker for infinite-state programs, we adapt the well-known bottom-up strategy for finite-state CTL model checking [35] to infinite-state programs using precondition synthesis. We leverage techniques for proving safety, termination, and nontermination of programs to synthesize preconditions asserting the satisfaction of CTL sub-formulae of an input property, and then use the preconditions in the remaining proof. Thus, our implementation does not need to consider the case of nested temporal quantifiers explicitly. Implementation: * termination.fs: The main loop in the function "bottomUp" drives the proof process. It starts by initializing the map of preconditions and then calling itself recursively for each CTL sub-formula. The procedure "prover" is then used to return counterexamples to the sub-formulas, which are used to synthesize preconditions. Several preconditions for each program location can then be computed simultaneously. This procedure also propagates found pre-conditions throughout the graph, without recomputing them explicitly, as described in [34]. * instrumentation.fs: Implements the reduction of model checking to safety checking and well-foundedness in the procedures "instrument_(X|F|G|...)", driven by the procedure "mergeProgramAndProperty". Safety/reachability prover ~~~~~~~~~~~~~~~~~~~~~~~~~~ Here we use McMillan's "lazy abstraction with interpolation" technique to prove safety (aka reachability). In our primary application of proving termination the safety problems are encodings of the validity of termination arguments. Our version is incremental, as the termination proof search builds a reachability problem and then, based on counterexamples found, refines the reachability problem and re-checks it. Implementation: * reachability.fs: Interpolation-based safety/reachability prover following the strategy of [28]. * priostack.fs: Priority stack implementation used in safety prover. * interpolantSequence.fs: Farkas Lemma-based interpolant synthesis via Farkas lemma using an extension of the techniques from [29]. * symex.fs: Symbolic execution used in lazy abstraction procedure Abstract interpretation ~~~~~~~~~~~~~~~~~~~~~~~ We use several abstract interpretation techniques [31]. Of particular importance is the use of an Octagon-based [30] abstract interpreter during the analysis of lassos. Implementation: * IIntAbsDom.fs: Interface for abstract domains (i.e. [31]). * IntervalIntDomain.fs: Intervals domain. See [32]. * octagon2.fs: Octagon domain. See [30]. ------ People ------ The following people have contributed to this version of T2: * Josh Berdine (MSR Researcher) * Mary Boeker (12 week undergraduate intern, Queen Mary University of London) * Marc Brockschmidt (MSR Researcher) * Hongyi Chen (12 week PhD intern, Lousiana State University) * Nathan Chong (12 week PhD intern, Imperial College) * Byron Cook (MSR Researcher, University College London) * Ruslan Ledesma Garza (12 week PhD intern, Technical University Munich) * Mihaela Gheorghiu (12 week PhD intern, University of Toronto) * Samin Ishtiaq (MSR Researcher) * Heidy Khlaaf (PhD Contractor, University College London) * Zachary Kincaid (12 week PhD intern, University of Toronto) * Matt Lewis (12 week PhD intern, Oxford) * Abigail See (12 week Undergraduate intern, Cambridge University) * Vlad Shcherbina (12 week PhD intern, Moscow State University) * Christoph Wintersteiger (MSR Researcher) ---------- References ---------- [1] Better termination proving through cooperation Marc Brockschmidt, Byron Cook, Carsten Fuhs CAV 2013 [2] Reasoning about nondeterminism in programs Byron Cook and Eric Koskinen PLDI 2013 [3] Ramsey vs. lexicographic termination proving Byron Cook, Abigail See, and Florian Zuleger TACAS 2013 [4] Temporal property verification as a program analysis task (extended version Byron Cook, Eric Koskinen, Moshe Vardi Formal Methods in System Design (special issue from CAV), 2012 [5] Proving termination of nonlinear command sequences Domagoj Babic, Byron Cook, Alan J. Hu, Zvonimir Rakamaric Formal Aspects of Computing (special issue from SEFM), 2012 [6] Proving program termination (Review article) Byron Cook, Andreas Podelski, Andrey Rybalchenko Communications of the ACM, Volume 54 Issue 5, May 2011 [7] Temporal property verification as a program analysis task Byron Cook, Eric Koskinen, Moshe Vardi CAV 2011 [8] SLAyer: Memory safety for systems-level code Josh Berdine, Byron Cook, Samin Ishtiaq CAV 2011 [9] Making prophecies with decision predicates Byron Cook and Eric Koskinen POPL 2011 [10] Summarization for termination: No return! Byron Cook, Andreas Podelski, Andrey Rybalchenko FMSD (2009) 35:369-387 [11] Proving that non-blocking algorithms don't block Alexey Gotsman, Byron Cook, Matthew Parkinson, and Viktor Vafeiadis POPL 2009 [12] Principles of program termination Byron Cook Notes from the 2008 Marktoberdorf summer school [13] Proving conditional termination Byron Cook et al CAV 2008 [14] Ranking abstractions Aziem Chawdhary et al ESOP 2008 [15] Proving thread termination Byron Cook, Andreas Podelski, and Andrey Rybalchenko PLDI 2007 [16] Proving termination by divergence Domagoj Babic, Byron Cook, Alan Hu, Zvonimir Rakamaric SEFM 2007 [17] Arithmetic strengthening for shape analysis Stephen Magill, Josh Berdine, Edmund Clarke, and Byron Cook. SAS 2007 [18] Proving that programs eventually do something good Byron Cook et al POPL 2007 [19] Variance analyses from invariance analyses Josh Berdine et al POPL 2007 [20] Automatic termination proofs for programs with shape-shifting heaps Josh Berdine, Byron Cook, Dino Distefano, and Peter O'Hearn CAV 2006 [21] Terminator: Beyond safety (short tool description paper) Byron Cook, Andreas Podelski, and Andrey Rybalchenko CAV 2006 [22] Termination proofs for systems code Byron Cook, Andreas Podelski, and Andrey Rybalchenko PLDI 2006 [23] Abstraction refinement for termination Byron Cook, Andreas Podelski, Andrey Rybalchenko SAS 2005 [24] A Complete Method of Sythesis of Linear Ranking Functions Andreas Podelski, Andrey Rybalchenko VMCAI 2004 [25] Multidimensional rankings, program termination, and complexity bounds of flowchart programs. Christophe Alias, Alain Darte, Paul Feautrier, and Laure Gonnord. SAS 2010 [26] Aaron Bradley, Zohar Manna, Henni Sipma The polyranking principle. ICALP 2005 [27] Aaron Bradley, Zohar Manna, Henni Sipma Linear ranking with reachability CAV 2005 [28] Lazy abstraction with interpolants Ken McMillan CAV 2006 [29] Constraint solving for interpolation Andrey Rybalchenko, Viorica Sofronie-Stokkermans VMCAI 2007 [30] The octagon abstract domain Antoine Mine Higher-Order and Symbolic Computation 19(1): 31-100 (2006) [31] Abstract interpretation: A unified lattice model for static analysis of programs by construction or approximation of fixpoints Patrick Cousot, Radhia Cousot POPL 1977 [32] Static determination of dynamic properties of programs Patrick Cousot, Radhia Cousot Int. Symp. on Programming, 1976 [33] A fast algorithm for finding dominators in a flowgraph Thomas Lengauer and Robert Endre Tarjan TOPLAS 1 (1): 121–141, 1979 [34] Faster Temporal Reasoning for Infinite-State Programs Byron Cook, Heidy Khlaaf, and Nir Piterman. FMCAD 2014. To Appear. [35] Design and synthesis of synchronization skeletons using branching time temporal logic E. Clarke and E. Emerson Workshop on Logic of Programs, 1981. [36] Automated Detection of Non-Termination and NullPointerExceptions for Java Bytecode M. Brockschmidt and T. Stroeder and C. Otto and J. Giesl FoVeOOS 2011