2007 Janota
2007 Janota
Mikolas Janota
Publication date
01-01-2007
Published in
Proceedings of 1st International Workshop on Invariant Generation (WING 2007) collocated with the 14th
Symposium on the Integration of Symbolic Computation and Mechanized Reasoning;2007
Licence
This work is made available under the CC BY-NC-SA 1.0 licence and should only be used in accordance with
that licence. For more information on the specific terms, consult the repository record for this item.
Document Version
1
This work was downloaded from the University of Limerick research repository.
For more information on this work, the University of Limerick research repository or to report an issue, you can
contact the repository administrators at [email protected]. If you feel that this work breaches copyright, please provide
details and we will remove access to the work immediately while we investigate your claim.
Assertion-based Loop Invariant Generation
Mikoláš Janota?
1 Introduction
Automated invariant generation techniques face two major challenges. The first
challenge is the invariant itself, i.e., which formulas should be suggested as in-
variants. The second challenge is time complexity. Programs in practice require
nontrivial, e.g., quantified, invariants; to be able to reason about such invariants,
techniques commonly rely on an automated theorem prover. Since invocations of
a theorem prover are time expensive, it is necessary to carefully limit the number
of calls to the prover. In this article we introduce a light-weight technique that
derives loop invariants from assertions, which express desired properties of the
program. We have implemented the algorithm in the extended static checker ES-
C/Java2 [11]. The implementation operates on the intermediate representation
of the program, where program annotations are translated into assertions and
assumptions. Thus, the implementation takes into account both the program
code and its specification.
The rest of the paper is structured as follows. Section 2 introduces the prob-
lem and its context. Section 3 describes the basic version of the loop invariant
generation algorithm and Sections 4 illustrates the algorithm on an example.
Section 5 describes an extension of the algorithm. Section 6 discusses the im-
plementation and Section 7 lists related work. Finally, Section 8 concludes and
proposes future work.
?
This work was funded by Science Foundation Ireland under grant number
03/CE2/I303-1, “LERO: the Irish Software Engineering Research Centre.” This
work was partially supported by the Information Society Technologies programme of
the European Commission, Future and Emerging Technologies under the IST-2005-
015905 MOBIUS project.
2 Janota
2 Background
The Java Modeling Language (JML) is a first–order logic annotation language
for Java programs [12]. JML is embedded into Java programs as a special form of
comments. The sign ’@’ indicates that a particular comment is a JML annotation.
Figure 1 illustrates the use of JML.
where v10 , . . . , v20 are fresh variables. And, let targets(C) be a function that returns
all variables that might be modified by the command C. The desugaring is
captured by the function desugar defined as follows:
desugar ({I}while c do B) ≡
assert I;
havoc(targets(B)); assume I;
((assume c; desugar(B); assert I; assume false) 8 (assume ¬c))
desugar(C1 8 C2 ) ≡ desugar(C1 ) 8 desugar(C2 )
desugar(C1 ; C2 ) ≡ desugar(C1 ); desugar(C2 )
desugar(C) ≡ C, all other commands
1
ESC/Java2 supports full Java 1.4 source code.
4 Janota
wlp(skip, N, W ) ≡ N
wlp(x ← expr, N, W ) ≡ N [x 7→ expr]
wlp(assume f, N, W ) ≡ f ⇒N
wlp(assert f, N, W ) ≡ (f ⇒ N ) ∧ (¬f ⇒ W )
wlp(C1 ; C2 , N, W ) ≡ wlp(C1 , wlp(C2 , N, W ), W )
wlp(C1 8 C2 , N, W ) ≡ wlp(C1 , N, W ) ∧ wlp(C2 , N, W )
Intuitively, the initial assertion in the desugaring of a loop is a check for the
invariant when the execution reaches the loop. The left branch of the choice
command represents an arbitrary iteration of the loop and the assume ¬c rep-
resents the termination of the loop.
The predicate transformer wlp(C, N, W ) defined in Figure 2 captures the se-
mantics of the desugared guarded command language. For a command C and
predicates N and W , if wlp(C, N, W ) holds then N holds if C terminates nor-
mally, W holds if C goes wrong or C does not terminate at all. For example,
assume false never terminates or goes wrong.
In this context, the verification condition is defined so that the given program
does not go wrong for any possible output. This is captured by the following
definition.
Definition 21 1. For a program C, the verification condition is the formula:
loop Li hosts the command C if and only if Li contains C and there is no loop
Lk with k > i that contains C. We will say that a loop L preserves a formula
f to express that if f held before an arbitrary iteration of L then it will hold
once the iteration terminates; we will discuss the exact meaning of this term and
back-propagation in Section 3.1.
The heart of the algorithm is the derivation of invariants from a given asser-
tion. Consider the following. An assertion assert f is hosted by a loop Li . And
let L0 , . . . , Li be a sequence of nested loops, i.e., Lk hosts Lk+1 for k ∈ 0 . . . i − 1.
In this scenario, we use the asserted formula f to infer invariants for the loops
L0 , . . . , Li . This inference process starts by back-propagating the formula f to
the top of Li yielding a formula fi . Subsequently, we determine whether fi is pre-
served by Li . If that is true, the process continues by back-propagating fi to the
top of Li−1 , yielding a formula fi−1 . This is repeated until the outermost loop
L0 is reached with the formula f0 . Finally, to verify that the suggested formulas
are indeed invariants, we test whether f0 holds at the entry of the loop-nest L0 .
This process is captured by the pseudo-code in Figure 3.
Up to this point we have described how to infer an invariant from a single
assertion. The whole analysis infers invariants from all assertions that are con-
tained in any loop starting from the assertions in the innermost layers. This is
captured by the following pseudo-code.
Analyze(C : command)
for each loop-nest L0 in C, using breadth-first search
do Analyze(L0 )
6 Janota
Analyze(L0 , . . . , Li : loop)
for each loop K hosted in L, using breadth-first search
do Analyze(L0 , . . . , Li , K)
for each assert f hosted in L, using breadth-first search
do Infer-Invariants(L0 , . . . , Li , assert f )
So far we have not explained the following: how expressions are back-
propagated, how it is determined that a formula preserves a loop, and that a
formula holds at the entry of a loop-nest. The following section provides details
on these subjects.
where C is the loop’s context, i.e., the preceding commands in the desuagared
version of the program. For example, the inner loop in the program
4 Example of Back-propagation
This section illustrates the analysis presented in the last section on an example.
Consider the program in Figure 4, written in pseudo-code, which takes a two-
dimensional array as its input and sets all its elements to zero.
The assignment to an element of the array requires that the values of i and
j are in the bounds of the array a. This is captured by the two assertions. We
will illustrate the steps of the algorithm on the first assertion.
The algorithm first back-propagates the assertion to the top of the inner
loop, which results in the following formula:
(j ≤ M ) ⇒ (1 ≤ i ∧ i ≤ N )
(i ≤ N ) ⇒ (1 ≤ M ) ⇒ (1 ≤ i ∧ i ≤ N )
8 Janota
(i ≤ N ) ⇒ (1 ≤ M ) ⇒ (1 ≤ i)
Further, the algorithm tests whether the outer loop preserves the simplified
formula. This follows from our previous result that the inner loop preserves the
desired property and that i is increased.
The final step tests whether the suggested invariant is established by the
code preceding the outer loop, i.e., the validity:
T |= (1 ≤ N ) ⇒ (1 ≤ M ) ⇒ (1 ≤ 1)
(i ≤ N ) ⇒ (1 ≤ M ) ⇒ (1 ≤ i)
(j ≤ M ) ⇒ (1 ≤ i ∧ i ≤ N )
is an invariant for the inner loop. Together, these invariants guarantee that the
first assertion is not violated (does not go wrong).
5 Invariant Alterations
All these alterations are stronger than the original formula f . Therefore, if we
can show that one of these alterations is an invariant, it will still guarantee that
the original assertion does not go wrong.
The rest of this section illustrates the use of alterations on an example. Con-
sider the Java code in Figure 1 without the loop invariants. The assertions that
this code yields are captured in the pseudo-code in Figure 5. Please note that
any access to a pointer or array has to be prepended with the pertaining asser-
tion, including the loop guards. The precondition of the method is translated
into assume commands.
Assertion-based Loop Invariant Generation 9
6 Implementation
We have implemented the technique described by the method Analyze (Sec-
tion 3) with the extension of the alterations described in Section 5. The imple-
mentation is build as a subcomponent of ESC/Java2, and utilizes the automated
10 Janota
theorem prover Simplify [6]. Based on our initial experiments with the imple-
mentation we have added the following enhancements to the algorithm.
7 Related Work
Invariant alterations. What are the alternations useful in practice? Can other
invariant inference techniques be exploited?
Loop postcondition. In the presented work we utilize only the assertions that are
inside the investigated loop. This approach could be leveraged by taking into
account the assertions after the loop, i.e., the desired postcondition of the loop.
References
1. Mike Barnett, K. Rustan M. Leino, and Wolfram Schulte. The Spec# programming
system: An overview. In Proceeding of CASSIS 2004, volume 3362 of Lecture Notes
in Computer Science. Springer–Verlag, 2004.
2. Bor-Yuh Evan Chang and K. Rustan M. Leino. Abstract interpretation with alien
expressions and heap structures. In Proceeding of 6th International Conference on
Verification, Model Checking, and Abstract Interpretation (VMCAI 2005), volume
3385 of Lecture Notes in Computer Science. Springer–Verlag, 2005.
3. Bor-Yuh Evan Chang and K. Rustan M. Leino. Inferring object invariants, 2005.
4. Edmund Clarke, Daniel Kroening, Natasha Sharygina, and Karen Yorav. Predicate
abstraction of ANSI–C programs using SAT. Formal Methods in System Design
(FMSD), 25, 2004.
5. P. Cousot and R. Cousot. Abstract interpretation: a unified lattice model for static
analysis of programs by construction or approximation of fixpoints. In Conference
Record of the Fourth Annual ACM SIGPLAN-SIGACT Symposium on Principles
of Programming Languages, pages 238–252, Los Angeles, California, 1977. ACM
Press.
6. David Detlefs, Greg Nelson, and James B. Saxe. Simplify: a theorem prover for
program checking. J. ACM, 52(3):365–473, 2005.
7. Extended Static Checker for Java version 2 (ESC/Java2). At
http://secure.ucd.ie/products/opensource/ESCJava2/.
8. Cormac Flanagan and Shaz Qadeer. Predicate abstraction for software verification.
In POPL ’02: Proceedings of the 29th ACM SIGPLAN-SIGACT symposium on
Principles of programming languages. ACM Press, 2002.
9. Suzanne Graf and Hassen Hassen Saı̈di. Construction of abstract state graphs
with PVS. In Proceedings of 9th International Conference on Computer Aided
Verification (CAV’97). Springer–Verlag, 1997.
10. Thomas A. Henzinger, Ranjit Jhala, Rupak Majumdar, and Gregoire Sutre. Lazy
abstraction. In Proceedings of the 29th Annual Symposium on Principles of Pro-
gramming Languages (POPL). ACM Press, 2002.
11. Joseph R. Kiniry and David R. Cok. ESC/Java2: Uniting ESC/Java and JML:
Progress and issues in building and using ESC/Java2 and a report on a case study
involving the use of ESC/Java2 to verify portions of an Internet voting tally system.
In Construction and Analysis of Safe, Secure and Interoperable Smart Devices:
International Workshop, CASSIS 2004, volume 3362 of Lecture Notes in Computer
Science. Springer–Verlag, January 2005.
12. Gary T. Leavens, Albert L. Baker, and Clyde Ruby. Behavioral Specifications of
Business and Systems, chapter JML: A Notation for Detailed Design, pages 175–
188. Kluwer Academic Publishing, 1999.
13. K. Rustan M. Leino, James B. Saxe, and Raymie Stata. Checking Java programs
via guarded commands. Technical Note 1999-002, Compaq SRC, May 1999.
14. Norihisa Suzuki and Kiyoshi Ishihata. Implementation of an array bound checker.
In POPL’77: Proceedings of the 4th ACM SIGACT-SIGPLAN symposium on Prin-
ciples of programming languages. ACM Press, 1977.