scispace - formally typeset
Open AccessJournal ArticleDOI

Model Checking JAVA Programs Using Java Pathfinder

Reads0
Chats0
TLDR
An effort to formally analyze, using Spin, a multi-threaded operating system for the Deep-Space 1 space craft, and of previous work in applying existing model checkers and theorem provers to real applications.
Abstract
This paper describes a translator called Java PathFinder (Jpf), which translates from Java to Promela, the modeling language of the Spin model checker. Jpf translates a given Java program into a Promela model, which then can be model checked using Spin. The Java program may contain assertions, which are translated into similar assertions in the Promela model. The Spin model checker will then look for deadlocks and violations of any stated assertions. Jpf generates a Promela model with the same state space characteristics as the Java program. Hence, the Java program must have a finite and tractable state space. This work should be seen in a broader attempt to make formal methods applicable within NASA’s areas such as space, aviation, and robotics. The work is a continuation of an effort to formally analyze, using Spin, a multi-threaded operating system for the Deep-Space 1 space craft, and of previous work in applying existing model checkers and theorem provers to real applications.

read more

Content maybe subject to copyright    Report

I Software Tools for Technology Transfer manuscript No.
(will be inserted by the editor)
Model Checking Java Programs
Using Java PathFinder
Klaus Havelund, Thomas Pressburger
NASA Ames Research Center,
Recom Technologies,
Moffett Field, California, USA.
e-mail: {havelund, ttp}©ptolemy, arc. nasa. gov
url: http ://ase. arc. nasa. gov/{havelund, ttp}
March 12, 1999
Abstract. This paper describes a translator called JAVA
PATHFINDER from JAVA to PROMELA, the "program-
ming language" of the SPIN model checker. The purpose
is to establish a framework for verification and debug-
ging of JAVA programs based on model checking. This
work should be seen in a broader attempt to make formal
methods applicable "in the loop" of programming within
NASA's areas such as space, aviation, and robotics. Our
main goal is to create automated formal methods such
that programmers themselves can apply these in their
daily work (in the loop) without the need for specialists
to manually reformulate a program into a different no-
tation in order to analyze the program. This work is a
continuation of an effort to formally verify, using SPIN,
a multi-threaded operating system programmed in LISP
for the Deep-Space 1 space craft, and of previous work
in applying existing model checkers and theorem provers
to real applications.
Key words: Program verification- JAVA model check-
ing - SPIN - concurrent programming - assertions -
deadlocks:

1 Introduction
In this paper we describe JAVA PATttFINDER (JPF), a
translator from JAVA to PROMELA, the programming
language of the SPIN model checker. The purpose is
to establish a framework for verification and debugging
of JAVA programs based on model checking. The work
should be seen in a broader attempt to make formal
methods applicabIe "in the loop" of programming within
NASA's areas such as space, aviation, and robotics. Our
main long term goal is to create an automated formal
methods workbench for JAVA programming such that
programmers themselves can apply them in their daily
work (in the loop) without the need for specialists to
manually reformulate a program in a different notation
in order to analyze it.
The tool we are developing is named after the rover
operating on Mars in 1997 called the "Mars PathFinder".
Although this mission was generally regarded as a big
success, the rover did in fact contain a number of soft-
ware bugs (causing repeated rebootings and panic at
NASA headquarters) that could potentially have been
found beforehand using proper verification tools. The
JAVA PATttFINDER name is a play on words: it finds the
paths of a JAVA program that lead to errors.
JAVA [6, 1] is a general purpose object-oriented pro-
gramming language with built in mechanisms for nmlti-
threaded programming [16]. It was originally designed to
support internet programming, but goes well beyond this
domain. JAVA is a relatively simple language compared
to C++, and it is regarded as a much safer language,
amongst other things due to its automatic garbage col-
lection and lack of general pointers. In spite of its sim-
plicity it appears to be a powerful language.
SPIN [15] is a verification system that supports the
design and verification of finite state asynchronous pro-
cess systems. Programs are formulated in the PROMELA
programming language, which is quite similar to an or-
dinary programming language, except for certain non-
deterministic specification oriented constructs. Processes
communicate either via shared variables or via message
passing through buffered channels. Properties to be veri-
fied are stated as assertions in the code, or as formulae in
the linear temporal logic LTL. The SPIN model checker
can automatically determine whether a program satis-
fies a property, and, in case the property does not hold,
generate an error trace. SPIN also finds deadlocks.
In an earlier effort we formally verified, using SPIN,
a multi-threaded operating system for a spacecraft [9].
The operating system is one component of NASA's New
Millennium Remote Agent (RA) [17], an artificial in-
telligence based spacecraft control system architecture
launched October 24, 1998, as part of the Deep-Space 1
mission to an asteroid to validate the potential of arti-
ficial intelligence, ion propulsion, and other technologies
for future space crafts. The operating system is imple-
mented in a multi-threaded version of COMMON LISP.
The verification effort consisted of hand translating parts
of the LIsP code into the PROMELA language of SPIN. A
total of 5 errors were identified, a very successful result.
It is often claimed that model checkers of today can-
not handle real sized programs, and consequently can-
not handle real sized JAVA programs. This is certainly
true. However, there are two aspects that make our ef-
fort worthwhile anyway. First, by providing an abstrac-
tion workbench we will make it possible to cut down the
state space of a JAVA program. Second, one can imag-
ine model checking being applied for unit testing, where
one focuses on a single class (or a few classes) and puts
this (these) in parallel with an aggressive environment
represented by a number of threads. Finally, JAVA can
be used as a design Ianguage, just as PROMELA.
Few attempts have been made to automatically ver-
ify programs written in real programming languages.
The most recent attempt we can mention is the one re-
ported in [2], which also translates JAVA programs into
PROMELA, however not handling exceptions or polymor-
phism as we do. The work in [3] defines a translator from
a concurrent extension of a very limited subset of C++.
The drawback of this solution is that the concurrency
extensions are not broadly used by C++ programmers.
In [5] is described what is called Extended static check-
ing, a technique for detecting, at compile-time, common
programming errors. The technique uses program ver-
ification technology, but feels to a programmer like a
type checker. By using an underlying automatic theorem
prover, the technique is more semantically thorough than
decidable static analysis techniques. At the same time,
by only trying to detect certain kinds of errors, not prove
the program's correctness, the technique is more auto-
matic than program verification. Finally, [4] describes a
theory of translating JAVA to a transition model, making
use of static pointer analysis to aid virtual coarsening,
which reduces the size of the model.
A significant subset of JAVA version 1.0 is supported
by JPF: dynamic creation of objects with data and meth-
ods, class inheritance, threads and synchronization prim-
itives for modeling monitors (synchronized statements,
and the wait and notify methods), exceptions, thread
interrupts, and most of the standard programming lan-
guage constructs such as assignment statements, condi-
tional statements and loops. However, the translator is
still a prototype and misses some features, such as pack-
ages, overloading, method overriding, recursion, strings,
floating point numbers, static variables and static meth-
ods, some thread operations like suspend and resume,
and some control constructs, such as the continue state-
ment. In addition, arrays are not objects as they are in
JAVA, but are modeled using PROMELA'S own arrays to
obtain efficient verification. Finally, we do not translate
the predefined class library.
Note that many of these features can be avoided by
small modifications to tim input code. In addition, the
tool is currently being improved to cover more of JAVA.

Despitetheomissions,weexpectthecurrentversionof
JPFto beusefulona largeclass of software. A front-
end to the translator checks that the program is in the
allowed subset and prints out error messages when not.
The translator is developed in COMMON LISP, having a
JAVA parser written in MoscowML as front end. Ger-
ard Holzmann supported our efforts by changing the se-
mantics for the PROMELA unless construct in order to
simplify the translation of exceptions.
The paper is organized around an example JAVA pro-
gram that has been translated automatically by JAVA
PATHFINDER and verified automatically by SPIN. In Sec-
tion 2 we describe this program, a bounded buffer. In
Section 3 we describe what the resulting PROMELA code
looks like. In Section 4 we present an experiment where
we seeded 21 errors into the example program, and ran
the SPIN model checker on the code generated by JPF.
Section 5 ends with conclusions and suggestions for fu-
ture work.
2 The Bounded Buffer Program
The translation scheme will be illustrated by translation
of a complete, small, but non-trivial JAvA.program that
covers many of the features of JAVA that we can trans-
late. After translation by JPF, SPIN can be applied to
prove or disprove that the program satisfies given prop-
erties stated as assertions in the program, and that it is
deadlock free.
2.1 The Buffer Class
The JAVA program that we are interested in verifying
properties about is a bounded buffer, represented by a
single class. An object of this class can store objects of
any kind (objects of subclasses of the general top level
class Object). Figure 1 shows the declared interface of
this class. It contains a put method, a get method and
a halt method. Typically there will be one or more pro-
ducer threads that call the put method, and one or more
consumer threads that call the get method. The halt
method can be invoked by a producer to inform con-
sumers that it will no longer produce values to the buffer.
Consumers are allowed to empty the buffer safely after
a halt, but if a consumer calls the get method after the
halt method has been called, and the buffer is empty, an
exception object of class HaltException will be thrown.
A class is an exception class if it is a subclass of the class
Throwable. In particular, class Exception is a subclass
of Throwable.
Figure 2 contains the Buffer class annotated with
line numbers for later reference. A JAVA class is gener-
ally speaking described by a name, a set of data vari-
ables, zero or more constructor methods (with different
argument types if more than one) with the same name
class HaltException extends Exception{}
interface BufferInterface {
public void put(0bject x);
public Dbject get() throws HaltException;
public void halt();
}
Fig. 1. The JAVABuffer interfaze
as the class, and a collection of methods. One of the con-
structors is executed when an object is created with the
new construct. Note that the Buffer class has no such
user-defined constructors. The class declares an array of
length 3 to hold the objects in the buffer. A cleaner way
of writing this program would be to declare a constant
"final int SIZE = 3" and then refer to SIZE rather
than to 3 throughout the program. The translator, how-
ever, currently requires an integer literal as the dimen-
sion of an array. In addition to the array, a couple of
pointers are declared, one pointing to the next fi'ee loca-
tion, and one pointing to the next object to be returned
by the get method. The variable usedSlots keeps track
of the current number of elements in the buffer. Finally,
the variable halted will become true when the halt
method is called.
The three methods of the class are all synchronized
(note the synchronized keyword). Hence, each of these
methods will have exclusive access to the object when
executed. That is, when one of these methods is called
on the buffer object by a thread, the buffer gets locked
to serve that thread, and it is unlocked again at the end
of the method call. The put method takes as parameter
the object to be stored in the buffer and has no return
value (void). It enters a loop testing whether the buffer
is full (i.e. having 3 elements) in which case it calls the
built in wait method. Calling the wait method within
a synchronized method suspends the current thread and
allows other threads to execute synchronized methods on
the object. Such another thread can then call the notify
method which will wake up an arbitrarily chosen waiting
thread to continue past its wait () call. The notifyAll
method wakes up all such waiting threads.
The call of wait is put inside a try construct, which
is JAVA's exception handling construct. A general try
construct has the form:
try T
catch{El el) C1
catch(E2 en) Cn
finally F
where each T,C1 ..... Cn, F is a block (a statement or a
sequence of statements enclosed by {...}) and each Ei is
an exception type (class). The body T of the try state-
ment is executed until either an exception is thrown or it
finishes successfully. If an exception is thrown, the catch

3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38. }
1. class Buffer implements BufferInterface {
2. protected Object[] array = new Object[3];
protected int putPtr = O;
protected int getPtr = O;
protected int usedSlots = O;
protected boolean halted;
public synchronized void put(0bject x) {
while (usedSlots == 3)
try {wait();}
catch(InterruptedException ex) {};
array[putPtr] = x;
putPtr = (putPtr + I) _ 3;
if (usedSlots == O) notifyAllO;
usedSlots++;
public synchronized Object get()
throws HaltException{
while (usedSlots == 0 & !halted)
try {wait();}
catch(InterruptedException ex) {};
if (usedSlots == O) {
throw(new HaltException());
};
Object x = array[getPtr];
array[getPtr] = null;
getPtr = (getPtr + 1) Z 3;
if (usedSlots == 3) notifyAll();
usedSlots--;
return x;
public synchronized void halt(){
halted = true;
notifyAll();
}
Fig. 2. The JAVA Buffer class
clauses are examined from top to bottom in order to find
one where the thrown exception is of the corresponding
class Ei or of a subclass thereof. If such a catch is found,
the corresponding block Ci is executed. If no appropri-
ate catch is found, the exception "flows out" of the try
statement into an outer try that might handle it. There
can be any number of catch clauses in a try including
none. If no catch clause in the method catches the ex-
ception, the exception is thrown to the code that invoked
this method. If a finally clause is present in a try, its
code is executed after all other processing in the try is
complete. This happens no matter how the completion
was achieved, whether normally, through an exception,
or through a control flow statement like return.
Normally an exception is thrown explicitly within a
thread using the throw(e) statement, where e is an ex-
ception object (a normal object of an exception class
which may include data and methods). However, one
thread S may throw an exception in another thread T by
class Main {
public static void main(String[] args) {
Buffer b = new Buffer();
Producer p = new Producer(b);
consumer c = new Consumer(b);
}
Fig. 3. The JAVA main program
executing T. interrupt (), which throws an
InterruptedException, or T.stop(), which throws a
ThreadDeath exception. The try construct around the
wait call is supposed to catch exactly such interrupts
from other threads. As we see, nothing is done in this
case (lines 11 and 22), but the try statement is neces-
sary in order for the JAVA type checker to accept the
program. We shall later see a real use of exceptions. One
of the main results in this paper is that we can in fact
prove properties of programs that throw exceptions.
When finally the put method gets past the while
loop, it is known that the buffer has free space, and the
insertion of the new object can be completed. In case
the buffer was in fact empty, all waiting consumers are
notified.
The get method is a little bit more complicated be-
cause it also takes into account whether the buffer has
been halted. Basically, it will wait uutil there is some-
thing in the buffer, and return this element, unless the
buffer is empty and at the same time ha_ been halted.
In this case, a HaltException is thrown. Otherwise, the
next buffer element is returned, and producers are noti-
fied if the buffer beforehand was full, in which case they
may be waiting.
2.2 Setting up an Environment
In order to verify properties about this class, without
looking at a complete application within which it oc-
curs, we can create a small application using the buffer.
We say that we set up an environment consisting of a
number of threads accessing the buffer, and then we
prove properties about this small system. This can be
regarded as unit testing the buffer. Concretely, we shall
define two thread classes: a Producer and a Consumer
class, and then start the whole system as shown in the
main method in Figure 3.
First, in order to illustrate the translator's capabili-
ties to translate inheritance, we define the objects that
are to be stored in the buffer, see Figure 4. A class
Attribute is defined, which contains one integer vari-
able. The constructor method with the same name as
the class takes a parameter and stores it in this variable.
The class httrData extends this class with another field,
and defines a constructor, which takes two parameters,
and then calls the super class constructor with the first
parameter.

class Attribute{
public int attr;
public Attribute(int attr){
this.attr = attr;
}
}
class AttrData extends Attribute{
public int data;
public AttrData(int attr,int data){
super(attr);
this.data = data;
}
}
Fig. 4. The JAVA Attribute and AttrData classes
class Producer extends Thread {
private Buffer buffer;
public Producer(Buffer b) {
buffer = b;
this.start();
}
public void run() {
for (int i = O; i < 6; i++) {
AttrData ad = new AttrData(i,i*i);
buffer.put(ad);
yield();
};
buffer.halt();
The producer and consumer threads that are actu-
ally going to use the buffer are defined in Figure 5. The
Producer class extends the Thread class, which means
that it must have a run method, which is then executed
when an object of this class is started with the start
method. As can be seen, the constructor of the class in
fact calls this start method in addition to storing locally
the buffer for which elements will be produced. The run
method adds 6 AttrData objects to the buffer, with at-
tributes 0... 5 (in that order) and squares as data, and
then calls the halt method on the buffer.
The Consumer class also extends the Thread class.
The run method stores all received objects in the
received array (or at most 10 of them). Note how the
receiving loop is written inside a try construct, which
catches and prevents a HaltException from going fur-
ther.
2.3 Property Specifications
JPF allows a programmer to annotate his JAVA program
with assertions and verify them using the SPIN model
checker. In addition, deadlocks can be identified. An as-
sert statement is expressed as a call to the static method
assert in the Verify class shown in Figure 6. The fact
that it is static means that we can call this method di-
rectly using the class name Verify as prefix, without
making an object instance first. The body of this method
is of no real importance for the verification since only
the call of this method (and not its definition) will be
translated into a corresponding PROMELA assert state-
ment. A meaningful body, like print!ng an error message
as in this example, can be useful during normal testing
though, but it will not be translated into PROMELA.
The first assertion in Figure 5 states that the con-
sumer receives exactly 6 elements from the buffer. The
second assertion within the for loop states that the re-
ceived elements are the correct ones (at least wrt. the
attr value).
class Consumer extends Thread {
private Buffer buffer;
public Consumer(Buffer b) {
buffer = b;
this.start();
}
public void run() {
int count = O;
AttrData[] received = new AttrData[lO];
try{
while (count < 10){
received[count] = (AttrData)buffer.getO;
count++;
}
}
catch(HaltException e){};
Verify.assert(count == 6);
for (int i = O; i < count; i++){
Verify.assert(received[i].attr == i);}
Fig. 5. The JAVA Producer and Consumer classes
class Verify{
public static void assert(boolean b){
if (!b)
System.out.println("assertion broken");
}
Fig. 6. The JAVA Verify class
One can consider other kinds of Verify methods, in
general methods corresponding to the operators in LTL,
the linear temporal logic of SPIN. Since these methods
can be called wherever statements can occur, this kind of
logic represents what could be called an embedded tempo-
ral logic. As an example, one could consider a statement
of the form: Verify.eventually(count == 6) inserted

Citations
More filters
Book

Principles of Model Checking

TL;DR: Principles of Model Checking offers a comprehensive introduction to model checking that is not only a text suitable for classroom use but also a valuable reference for researchers and practitioners in the field.
Book

The SPIN Model Checker: Primer and Reference Manual

TL;DR: The SPIN Model Checker as mentioned in this paper is used for both teaching software verification techniques, and for validating large scale applications, and it has been estimated that up to three-quarters of the $400 billion spent annually to hire programmers in the United States is ultimately spent on debugging.
Journal ArticleDOI

Model checking programs

TL;DR: A verification and testing environment for Java, called Java PathFinder (JPF), which integrates model checking, program analysis and testing, and uses state compression to handle big states and partial order and symmetry reduction, slicing, abstraction, and runtime analysis techniques to reduce the state space.
Proceedings ArticleDOI

Lazy abstraction

TL;DR: This work presents an algorithm for model checking safety properties using lazy abstraction and describes an implementation of the algorithm applied to C programs and provides sufficient conditions for the termination of the method.
Proceedings ArticleDOI

Bandera: extracting finite-state models from Java source code

TL;DR: An integrated collection of program analysis and transformation components, called Bandera, that enables the automatic extraction of safe, compact finite-state models from program source code.
References
More filters
Book

The Java Language Specification

TL;DR: The Java Language Specification, Second Edition is the definitive technical reference for the Java programming language and provides complete, accurate, and detailed coverage of the syntax and semantics of the Java language.
Journal ArticleDOI

The model checker SPIN

TL;DR: An overview of the design and structure of the verifier, its theoretical foundation, and an overview of significant practical applications are given.
Book

The Java Programming Language

TL;DR: The Java (TM)Programming Language, Second Edition, is the definitive resource for all serious Java programmers and lets you in on the rationale behind Java's design, direct from the language's creator, as well as the tradeoffs involved in using specific features.
Book

Design and validation of computer protocols

TL;DR: Part 1 Basic: introduction protocol structure error control flow control and design tools: a protocol simulator a protocol validator using the validator.
Book ChapterDOI

Extended static checking

TL;DR: This talk reports on some of the research results of and the current state of the Extended Static Checking project at DEC SRC.