scispace - formally typeset

Book ChapterDOI

Applying Jlint to Space Exploration Software

11 Jan 2004-Vol. 2937, pp 297-308

TL;DR: The results show that a few analysis techniques are sufficient to avoid almost all false positives in the multi-threading warnings, and these techniques include investigating all possible callers and a few code idioms.

AbstractJava is a very successful programming language which is also becoming widespread in embedded systems, where software correctness is critical. Jlint is a simple but highly efficient static analyzer that checks a Java program for several common errors, such as null pointer exceptions, and overflow errors. It also includes checks for multi-threading problems, such as deadlocks and data races. The case study described here shows the effectiveness of Jlint in finding certain faults, including multi-threading problems. Analyzing the reasons for false positives in the multi-threading warnings gives an insight into design patterns commonly used in multi-threaded code. The results show that a few analysis techniques are sufficient to avoid almost all false positives. These techniques include investigating all possible callers and a few code idioms. Verifying the correct application of these patterns is still crucial, because their correct usage is not trivial.

Summary (2 min read)

1 Introduction

  • Therefore an automated tool which can detect faults easily, preferably early in the lifecycle of software, can be very useful to find defects.
  • Among similar tools geared towards Java, it is one of the most suitable with respect to ease of use (no annotations required) and free availability (the tool is Open Source) [I]. . . .

13 Outline

  • This text is organized as follows: Section 2 describes Jlint and how it was used for this project.
  • Sections 3 and 4 show the results of applying Jlint to space exploration program code.
  • Design patterns which are common among these two projects are analyzed in Section 5.
  • Section 6 summarizes the results and concludes.

2.1 Tool description

  • Typical warnings about possible faults issued by Jlint are n u l l pointer dereferences, array bounds overflows, and value overflows.
  • The latter may occur if one multiplies two 32 bit integer values without converting them to 64 bit fist Many warnings that Jlint issues are code guidelines:.

I

  • Jlint also includes many analyses for multi-threaded programs.
  • Some of Jlint's warnings for multi-threaded programs are overly cautious.
  • Possible data race warnings for method calls or variable accesses do not necessarily imply a data race.
  • The reason for such false positives are both difficulties inherent to static analysis, such as pointer aliasing across method calls, and limitations in Jlint itself, where its algorithms could be refined with known techniques.

2.2 Warning review process

  • During the review process, Jlint's warnings were categorized to see whether they refer to the same problem.
  • Such situations constitute calls to the same method from different callers, the same variable used in different contexts, or the same design pattern applied throughout the class.
  • In a separate count, counting the number of distinct problems rather than individual warnings, all such cases were counted once.
  • Furthermore, the time required for this process was recorded.
  • Note that the review activity was often interrupted by other activities such as writing this paper.

3.2 Jlint evaluation

  • The 30 deadlock warnings all referred to the same two classes.
  • There were two sets of warnings, the first set containing ten, the second one 20 warnings.
  • The first ten warnings, all of them false positives, showed incomplete loops in the call graph.
  • Another lock was used that makes a deadlock possible.
  • Therefore these warnings referred to actual faults in the code.

Results:

  • While reviewing the multi-threading warnings was time-consuming due to the complex interactions in the code, it was feasible and helped to highlight the critical parts of the source code.
  • The effort was justifiable for a project of this complexity.

3.3 Comparison to other projects

  • The eleven new bugs found by J h t were a great success, even considering that the seven deadlocks correspond to two classes where other deadlocks have been known to occur.
  • Jlint reported different methods than those reported in otiier analyses.

4 DS1

  • The second case study consisted of an attitude control system and a fault protection system for the Deep Space 1 @SI) space craft.
  • For the DS1 code base, it took 0.17 seconds to check the entire code base on the same PowerPC G4 with a clock frequency of 500 MHz.

4.1 Description of DSI

  • DS1 was a technology-testing mission, which was launched October 24 1998, and which ended its primary mission in September 1999.
  • DS1 contained and tested twelve new kinds of space-travel technologies, for example, ion propulsion and artificial intelligence for autonomous control.
  • The attitudecontrol system monitors and controls the space craft's attitude, that is, its position in 3dimensional space.
  • The fault-protection system monitors the operation of the space craft and initiates corrective actions in case errors occur.
  • The original C code was re-designed in Java, using best practices in object-oriented design.

4.2 Jlint evaluation

  • This study indicates that four design patterns prevail in cases where code is apparently not thread-safe: Synchronization of all callers, use of read-only values, threadlocal copies of data, and the use of thread-safe container classes.
  • Some of the data race warnings for the Rover code pointed out cases where it was attempted to use the read-only pattern, but the use was not carried out consistently throughout the project.
  • Such a small mistake violates the property that guarantees thread-safety.

6 Conclusions

  • An analysis of the false positives showed that in apparently thread-unsafe code, four common design patterns ensure thread-safety in all cases.
  • Static analysis tools should therefore be extended with specific algorithms geared towards these patterns to reduce false positives.
  • Furthermore, these patterns were not always applied correctly and are still a significant source of programming errors.
  • This calls for tools that verify the correct application of these patterns, thereby pointing out even more subtle errors than previously possible.

Did you find this useful? Give us your feedback

...read more

Content maybe subject to copyright    Report

Applying Jlint to Space Exploration Software
Cyrille
Artho‘
and Klaus Havelund2
Computer Systems Institute,
ETH
Zurich, Switzerland
Keseel Technology, NASA Ames Research Center, Moffett Field, California USA
Abstract.
Java is a very successful programming language which is also
be-
coming widespread in embedded systems, where software correctness is critical.
Jlint is a simple
but
highly efficient static analyzer that checks a Java program
for several common errors,
such
as
null
pointer exceptions, and overflow er-
rors. It also includes checks for multi-threading problems, such
as
deadlocks and
data races. The case study described here shows the effectiveness
of
Jhnt in find-
false positives in the muIti-threading warnings gives
an
insight
into
design
pat-
terns commonly used
in
multi-threaded code. The results show that a few analy-
sis techniques are sufficient to avoid almost all false positives. These techniques
include investigating all possible callers and a few code idioms. Verifying the
comect application of these patterns is still crucial, because their correct usage
is
not trivial.
k.?g
ccittii
faiiYt,
kc!nding
iiiiiYt-*&-e&ig
piobkiii;.
Analyzing the ieasaiis
fai
1
Introduction
Java is becoming more widespread
in
the
area of embedded systems,
both
as
a
scaled-
down “Micro Edition”
[20]
or
by having real-time extensions
[6,5].
In
such systems,
software failures
are
very costly, because the software cannot always be replaced on a
running system, and failures may have expensive
or
even catastrophic consequences..
These costs
are
obviously prohibitively high when
a
software-related problem causes
the
failure of
a
space craft
[14].
Therefore
an
automated tool which
can
detect faults easily, preferably early
in
the
lifecycle of software, can be very useful
to
find
defects. One tool that allows fault de-
tection easily,
even
in
incomplete systems,
is
Jlint.
Among
similar tools geared towards
Java, it is one of the most suitable with respect to
ease
of use
(no
annotations required)
and free availability (the tool is
Open
Source)
[I].
.
..
1.1
The
Java
programming
langgage
Java is
a
modem, object-oriented programtning language that has had a large success
in
the
past few
years.
It
was
one of
the
first
languages where the source code was not
compiled to machine code, but to a different form,
the
byrecode.
This bytecode
runs
in
a
dedicated environment,
the
virrual
machine.
In
order to guarantee
the
integrity of
the
system,
each
class
file containing bytecode is checked prior to execution
[II,
19,211.
The Java language allows each object
to
have any number offields, which are at-
tributes of
each
object.
These
may
be
static,
Le.,
shared among all instances of a certain
,

class, or dynamic, Le., each instance has its own fields.
In
contrast to that,
local
vari-
ables
are thread-local and only visible within one method.
Java allows inheritance: a method of a given class may be
overridden
by a method
of the same name. Similarly, fields in
a
subclass
shadow
those with the same name
in
the superclass.
In
general, these mechanisms work well for small code examples
but are dangerous in larger projects. Methods overriding other methods must ensure
they do
not
violate invariants of the Superclass. Similar problems occur with variable
shadowing. The programmer is not always aware that a variable with the same name
already exists
on
a different level, such as the superclass.
In
order to prevent incorrect programs from corrupting the system, Java’s virtual
machine has various safety mechanisms built in. Each variable access is guarded against
manipulating memory outside the allocated area.
In
particular, pointers must not
be
null
when dereferenced, and array indices must be in a valid range. If these properties
are violated,
an
exception
is thrown indicating a programming error. This is a highly
undesirable behavior
in
most cases. Ideally, such errors should be prevented by static
analysis, rather than caught at run-time.
Furthermore, Java offers mechanisms to write multi-threaded programs. The two
key mechanisms are locking primitives, using the
synchronized
keyword, and inter-
thread synchronization with the
wait
and
notify
methods.
A
method or block which
is declared
synchronized
is only entered after the exclusive lock for that critical sec-
tion
has
been obtained. Lock usage for shared data is specified by the programmer.
Incorrect lock usage using too many locks may lead to
deud1ock.s.
For
example, if two
threads each wait
on
a lock held by the other thread, both threads cannot continue their
execution.
On
the other hand, if a value is accessed with insufficient lock protection,
data
races
may occur:
two
threads may access the same value concurrently, and the
results
of
the operations are
no
longer deterministic.
Java’s message passing mechanisms for threads also
is
a source of problems.
A
call
to
wait
allows a thread to suspend
until
a condition becomes true, which must
be signaled by
notify
by
another thread. When calling
wait
the calling thread must
ensure that it owns
the
lock it
waits
on,
and
also
release any other locks before the call.
Otherwise, remaining locks held are unavailable to other threads, which may in
turn
block when trying to obtain them. This can prevent them from calling
notify
which
would allow the waiting thread to release
its
lock. This situation is also a deadlock.
1.2
Related
work
Much
effort
has gone into fault-finding in Java programs, single-threaded and multi-
threaded. The approaches can be separated into
static
checkers,
which
check a program
at compile-time and try to approximate its run-time behavior, and
dynamic
checkers,
which
try
to catch and analyze anomaiies during program execution.
Several static analysis tools exist that examine
a
program for faults such as
null
pointer dereferences
or
data races. The ESC/Java
[9]
tool is, like nint,
also
based on
static analysis, or more generally
on
theorem proving- It, however, requires annotation
of
the
program. While it is more precise than Jlint, it is not nearly as fast and requires a
large effort from the user to fully exploit the power of this tool
[9].
2

Dynamic tools have the advantage of having more precise information available
in
the execution trace. The Eraser algorithm [22], which has been implemented in the
Visual Threads tool [12] to analyze
C
and
C++
programs, is an example of
a
such
an
algorithm that examines a program execution trace for locking patterns and variable
accesses in order to predict potential data races. It also checks for deadlocks and several
other errors.
The Java PathExplorer tool (JPaX)
[
161 performs deadlock analysis and the Eraser
data race analysis
on
Java programs. It furthermore recently has been extended with the
high-level data race detection algorithm described in [3]. This algorithm analyzes how
collections
of
variables are accessed by multiple threads.
More heavyweight dynamic approaches include model checking, which explores
all possible schedules
in
a program. Recently, model checkers have been developed
that apply directly to programs (instead of just models thereof).
This
includes the Java
PathFinder system
(JPF)
developed by
NASA
[15,24], and similar systems [lo, 8,17,4,
231. Such systems, however, suffer from the state space explosion problem. In [13] we
describe an extension of Java PathFiider which performs data race analysis (and dead-
lock analysis) in simulation mode, whereafter the model checker
is
used to demonstrate
whether the data race (deadlock) warnings are real or
not.
This paper focuses
on
applying Jlint
[2]
to the software for detecting errors stat-
ically. JLint uses static analysis and abstract interpretation
to
find difficult errors at
compile-time.
A
similar case study with Kit has been made before, applying it to large
projects [2]. The difference to this case study is that the other case study had scalability
in mind. Jlint had been applied to packages containing several hundred thousand lines
of code, generating hundreds of warning messages. Because of this, the warnings had
been evaluated selectively, omitting some hard-to-check deadlock warnings. In
this
case
study, an effort was made to analyze every single warning and also see what kinds of
design patterns cause false positives?
13
Outline
This text is organized
as
follows: Section
2
describes Jlint and how it was used for this
project. Sections
3
and 4 show the results
of
applying Jlint to space exploration program
code. Design patterns which are common among these
two
projects are analyzed
in
Section
5.
Section
6
summarizes the results and concludes.
2
Jlint
2.1
Tool
description
Jlint checks Java code and finds bugs, inconsistencies and synchronization problems
by
performing a data flow analysis, abstract interpretation, and building the lock graph. It
issues warnings about potential problems. These warnings do
not
imply that
an
actual
Design patterns
commonly
denote compositions
of
objects
in
software.
In
this
paper, the notion
of
composition is different.
It
indudes lock patterns
and
sometimes
only
applies to a small part
of
the program.
In
that context, we
also
use the term “code idiom”.
3

error exists. This makes Jlint unsound
as
a program prover. Moreover, Jlint can also
miss errors, making it incomplete. The reason for
this
is that the goal was to make Jlint
practical, scalable, and possible to implement it in
a
short time.
Typical warnings about possible faults issued by Jlint are
null
pointer dereferences,
array bounds overflows, and value overflows. The latter may occur if one multiplies two
32
bit integer values without converting them to
64
bit
fist
Many warnings that Jlint issues are code guidelines:
A
local variable should never
have the same name as a field of the same class or
a
superclass. When a method of a
given name
is
overridden, all its variants should be ovemdden,
in
order to guarantee
a
consistent behavior of the subclass.
I
Jlint also includes many analyses for multi-threaded programs. Some of Jlint’s
warnings for multi-threaded programs are overly cautious. For instance, possible data
race warnings for method calls or variable accesses do not necessarily imply a data
race. The reason for such false positives are both difficulties inherent to static analysis,
such
as
pointer aliasing across method calls, and limitations in Jlint itself, where its
algorithms could be refined with known techniques.
2.2 Warning
review
process
Jlint gives fairly descriptive warnings for each problem found. The context given is
limited to the class
in
which the error occurs,
the
line number, and fields used or meth-
ods called.
This
is always sufficient to find
the
source of simple warnings, which con-
cern
sequentid
properties
such
as
null
pointer dereferences. These warnings are easy
to
review and were considered in a first pass. The other warnings, concerning multi-
threading problems,
take
much more time
to
consider, and were evaluated in a second
phase.
The review process essentially checks whether
the
problems described in the warn-
ings cm actually occur at run-time.
In
simple cases, warnings may be ruled out given
the
algorithmic properties of the program. Complex cases include reviewing callers to
the method in question.
Data race and deadlock warnings fall
in
this
category. They require constructing a
part of
the
call graph including locks owned by callers when a method is called. If it
can be ensured that all calls to non-synchronized shared methods
are
made only through
methods that already employ lock protection then there cannot be
a
data race:
This review process can be rather time-consuming and took up to twelve minutes for
one problem instance in the experiments carried out. Many warnings occur in similar
contexts,
so
warnings referring
to
the same problem can usually be easily confirmed as
duplicates. This part of the review process was not yet automated
in
any way but could
be automated to a large extent with known techniques. Both cases studies were done
without prior knowledge of
the
program code. It can be assumed that the time to review
the
warnings is shorter for the author of
the
code, especially when reviewing data race
or deadlock warnings.
Methods
that
access
a
shared
field
are
also
considered “shared”
in
this
context. The
lock
used
for
ensuring
mutual exclusion
must
be
the
same lock
for
all
calls.
4

During the review process, Jlint’s warnings were categorized to see whether they
refer to the same problem. Such situations constitute calls to the same method from
different callers, the same variable used in different contexts, or the same design pattern
applied throughout the class.
In
a separate count, counting the number of distinct prob-
lems rather than individual warnings,
all
such cases were counted once. Furthermore,
the time required for this process was recorded. Note that the review activity was often
interrupted by other activities such as writing this paper. We believe this reduced the
overall time required because manual code reviews require much attention, and cannot
be canied out in one run without a degradation of the concentration required.
3
First
case
study:
Rover
code
The first case study is a software module, called the Executive, for controlling the move-
ment of the planetary wheeled rover
K9,
developed at NASA Ames Research Center.
The run time for analyzing the code with Jlint was
0.10
seconds
on
a PowerPC
G4
with
a clock frequency of
500
MHz.
3.1
K9
is a hardware platform for experimenting with rover technology for exploration of
the Martian surface. The Executive is
a
software module for controlling the rover, and is
essentially an interpreter
of
plans, where a plan is a special form of a program. Plans are
constructed from high-level constructs, such as sequential composition and condition-
als, but
no
while loops. The effect of while
loops
is achieved by assuming that plans are
generated
on
the fly during rover operation as environment conditions change. The low-
est level nodes of a plan
are
tasks to be directly executed by the rover hardware.
A
node
in
a plan can be further constrained by a set of conditions, which when failing during
exzcution, cailse the Executive
to
abort the execution of the subsequent sibling nodes,
unless specified otherwise through options. Examples of conditions are pre-conditions
and post-conditions, as well
as
invariants to be maintained during the execution of the
node. The examined Executive consists of
7,300
lines of Java code. This code was ex-
tracted by a colleague from the original rover code, written
in
35,000
lines of
Cti-.
The code is highly multi-threaded, and hence provides a risk for concurrency errors.
The Java version of the code was extracted as part of a different project, the purpose of
which was to compare various formal methods, such as model checking, static analysis,
runtime analysis, and simple testing
[7].
The code contained
a
number seeded of errors.
Description
of
the Rover project
3.2
Jlint evaluation
Jlint issues
249
warnings when checking the Rover code. Table
1
summarizes Jlint’s
output. The first
two
columns show how each type
of
problem and how many warnings
Jlint generated for them. The third, forth and fifth column show the result of the manual
source code analysis: how many actual, distinct faults, or at least serious problems,
in the code were found, how many warnings described such actual faults, and how
many were considered
to
be false positives. The last column shows the time spent
on
5

Citations
More filters

Proceedings ArticleDOI
12 Jun 2008
TL;DR: The design of Parfait is presented, a static layered program analysis framework for bug checking, designed for scalability and precision by improving false positive rates and scale to millions of lines of code.
Abstract: We present the design of Parfait, a static layered program analysis framework for bug checking, designed for scalability and precision by improving false positive rates and scale to millions of lines of code. The Parfait framework is inherently parallelizable and makes use of demand driven analyses.In this paper we provide an example of several layers of analyses for buffer overflow, summarize our initial implementation for C, and provide preliminary results. Results are quantified in terms of correctly-reported, false positive and false negative rates against the NIST SAMATE synthetic benchmarks for C code.

47 citations


Cites methods from "Applying Jlint to Space Exploration..."

  • ...Tools that support both timing and state, and input validation and representation bugs include: ESC [8], a Modula-3 and Java checker that uses a theorem prover (Simplify) to reason about the semantics of language constructs, driven by annotations in the code; Coverity [10, 11], a C, C++ and Java checker based on \may belief" analysis; Jlint [1, 2 ], a checker of Java classles that is based on data ow and abstract interpretation; ......

    [...]

  • ...The program initializes two buers: the stack buer buf is initialized to the \AAA...A" string with a trailing C end-of-string character, and the heap buer buf2 is initialized to the input data provided as the third parameter to the program (argv[ 2 ]), after allocating data from the heap of size equal to the second parameter (argv[1])....

    [...]

  • ...In the example there are two user inputs: the length of the data (argv[1]) and the string of data (argv[ 2 ])....

    [...]


Proceedings ArticleDOI
24 Mar 2009
TL;DR: The Software Quality Assessment and Visualization Toolset (SQuAVisiT), a flexible tool for visual software analytics that allows for integration of multiple programming languages and variety of analysis and visualization tools, is presented.
Abstract: We present the Software Quality Assessment and Visualization Toolset (SQuAVisiT), a flexible tool for visual software analytics. Visual software analytics supports analytical reasoning about software systems facilitated by interactive visual interfaces. In particular, SQuAVisiT assists software developers, maintainers and assessors in performing quality assurance and maintenance tasks. Flexibility ofSQuAVisiT allows for integration of multiple programming languages and variety of analysis and visualization tools.SQuAVisiT has been successfully applied in a number of case studies, ranging from hundreds to thousands KLOC,from homogeneous to heterogeneous systems.

26 citations


Cites background from "Applying Jlint to Space Exploration..."

  • ...Remainder of this paper is organized as follows....

    [...]


Proceedings ArticleDOI
09 Nov 2008
TL;DR: A non-null annotations inferencer for the Java bytecode language and a substantial improvement in the precision is shown and, despite being a whole-program analysis, production applications can be analyzed within minutes.
Abstract: We present a non-null annotations inferencer for the Java bytecode language. We previously proposed an analysis to infer non-null annotations and proved it soundness and completeness with respect to a state of the art type system. This paper proposes extensions to our former analysis in order to deal with the Java bytecode language. We have implemented both analyses and compared their behaviour on several benchmarks. The results show a substantial improvement in the precision and, despite being a whole-program analysis, production applications can be analyzed within minutes.

18 citations


DissertationDOI
01 Jan 2005
TL;DR: A new kind of generic analysis has been implemented in the JNuke framework presented here, which can utilize the same algorithm in both a static and dynamic setting by abstracting differences between the two scenarios into a corresponding environment.
Abstract: Multi-threaded programming gives rise to errors that do not occur in sequential programs. Such errors are hard to find using traditional testing. In this context, verification of the locking and data access discipline of a program is very promising, as it finds many kinds of errors quickly, without requiring a user-defined specification. Run-time verification utilizes such rules in order to detect possible failures, which do not have to actually occur in a given program execution. A common such failure is a data race, which results from inadequate synchronization between threads during access to shared data. Data races do not always result in a visible failure and are thus hard to detect. Traditional data races denote direct accesses to shared data. In addition to this, a new kind of high-level data race is introduced, where accesses to sets of data are not protected consistently. Such inconsistencies can lead to further failures that cannot be detected by other algorithms. Finally, data races leave other errors untouched which concern atomicity. Atomicity relates to sequences of actions that have to be executed atomically, with no other thread changing the global program state such that the outcome differs from serial execution. A data-flow-based approach is presented here, which detects stale values, where local copies of data are outdated. The latter property can be analyzed efficiently using static analysis. In order to allow for comparison between static and dynamic analysis, a new kind of generic analysis has been implemented in the JNuke framework presented here. This generic analysis can utilize the same algorithm in both a static and dynamic setting. By abstracting differences between the two scenarios into a corresponding environment, common structures such as analysis logics and context can be used twofold. The architecture and other implementation aspects of JNuke are also described in this work.

13 citations


Journal ArticleDOI
TL;DR: This work proposes a novel approach for generating random benchmarks for evaluating program analysis and testing tools and compilers that uses stochastic parse trees, where language grammar production rules are assigned probabilities that specify the frequencies with which instantiations of these rules will appear in the generated programs.
Abstract: Benchmarks are heavily used in different areas of computer science to evaluate algorithms and tools. In program analysis and testing, open-source and commercial programs are routinely used as benchmarks to evaluate different aspects of algorithms and tools. Unfortunately, many of these programs are written by programmers who introduce different biases, not to mention that it is very difficult to find programs that can serve as benchmarks with high reproducibility of results. We propose a novel approach for generating random benchmarks for evaluating program analysis and testing tools and compilers. Our approach uses stochastic parse trees, where language grammar production rules are assigned probabilities that specify the frequencies with which instantiations of these rules will appear in the generated programs. We implemented our tool for Java and applied it to generate a set of large benchmark programs of up to 5Mlines of code each with which we evaluated different program analysis and testing tools and compilers. The generated benchmarks let us independently rediscover several issues in the evaluated tools. Copyright © 2014 John Wiley & Sons, Ltd.

11 citations


Cites methods from "Applying Jlint to Space Exploration..."

  • ...Like FindBugs, JLint [41] applies syntactic bug patterns and dataflow analysis on AUT bytecode, but it is not easy to expand [21]....

    [...]

  • ...JLint Like FindBugs, JLint [41] applies syntactic bug patterns and dataflow analysis on AUT bytecode, but it is not easy to expand [21]....

    [...]


References
More filters

Book ChapterDOI
29 Mar 2004
TL;DR: This work introduces a temporal logic of calls and returns (CaRet) for specification and algorithmic verification of correctness requirements of structured programs and presents a tableau construction that reduces the model checking problem to the emptiness problem for a Buchi pushdown system.
Abstract: Model checking of linear temporal logic (LTL) specifications with respect to pushdown systems has been shown to be a useful tool for analysis of programs with potentially recursive procedures. LTL, however, can specify only regular properties, and properties such as correctness of procedures with respect to pre and post conditions, that require matching of calls and returns, are not regular. We introduce a temporal logic of calls and returns (CaRet) for specification and algorithmic verification of correctness requirements of structured programs. The formulas of CaRet are interpreted over sequences of propositional valuations tagged with special symbols call and ret. Besides the standard global temporal modalities, CaRet admits the abstract-next operator that allows a path to jump from a call to the matching return. This operator can be used to specify a variety of non-regular properties such as partial and total correctness of program blocks with respect to pre and post conditions. The abstract versions of the other temporal modalities can be used to specify regular properties of local paths within a procedure that skip over calls to other procedures. CaRet also admits the caller modality that jumps to the most recent pending call, and such caller modalities allow specification of a variety of security properties that involve inspection of the call-stack. Even though verifying context-free properties of pushdown systems is undecidable, we show that model checking CaRet formulas against a pushdown model is decidable. We present a tableau construction that reduces our model checking problem to the emptiness problem for a Buchi pushdown system. The complexity of model checking CaRet formulas is the same as that of checking LTL formulas, namely, polynomial in the model and singly exponential in the size of the specification.

3,507 citations


Book
19 Sep 1996
Abstract: Preface. 1. Introduction. A Bit of History. The Java Virtual Machine. Summary of Chapters. Notation. 2. Java Programming Language Concepts. Unicode. Identifiers. Literals. Types and Values. Primitive Types and Values. Operators on Integral Values. Floating-Point Types, Value Sets, and Values. Operators on Floating-Point Values. Operators on boolean Values. Reference Types, Objects, and Reference Values. The Class Object. The Class String. Operators on Objects. Variables. Initial Values of Variables. Variables Have Types, Objects Have Classes. Conversions and Promotions. Identity Conversions. Widening Primitive Conversions. Narrowing Primitive Conversions. Widening Reference Conversions. Narrowing Reference Conversions. Value Set Conversion. Assignment Conversion. Method Invocation Conversion. Casting Conversion. Numeric Promotion. Names and Packages. Names. Packages. Members. Package Members. The Members of a Class Type. The Members of an Interface Type. The Members of an Array Type. Qualified Names and Access Control. Fully Qualified Names. Classes. Class Names. Class Modifiers. Superclasses and Subclasses. The Class Members. Fields. Field Modifiers. Initialization of Fields. Methods. Formal Parameters. Method Signature. Method Modifiers. Static Initializers. Constructors. Constructor Modifiers. Interfaces. Interface Modifiers. Superinterfaces. Interface Members. Interface (Constant) Fields. Interface (Abstract) Methods. Overriding, Inheritance, and Overloading in Interfaces. Nested Classes and Interfaces. Arrays. Array Types. Array Variables. Array Creation. Array Access. Exceptions. The Causes of Exceptions. Handling an Exception. The Exception Hierarchy. The Classes Exception and RuntimeException. Execution. Virtual Machine Start-up. Loading. Linking: Verification, Preparation, and Resolution. Initialization. Detailed Initialization Procedure. Creation of New Class Instances. Finalization of Class Instances. Unloading of Classes and Interfaces. Virtual Machine Exit. FP-strict Expressions. Threads. 3. The Structure of the Java Virtual Machine. The class File Format. Data Types. Primitive Types and Values. Integral Types and Values. Floating-Point Types, Value Sets, and Values. The returnAddress Type and Values. The boolean Type. Reference Types and Values. Runtime Data Areas. The pc Register. Java Virtual Machine Stacks. Heap. Method Area. Runtime Constant Pool. Native Method Stacks. Frames. Local Variables. Operand Stacks. Dynamic Linking. Normal Method Invocation Completion. Abrupt Method Invocation Completion. Additional Information. Representation of Objects. Floating-Point Arithmetic. Java Virtual Machine Floating-Point Arithmetic and IEEE 754. Floating-Point Modes. Value Set Conversion. Specially Named Initialization Methods. Exceptions. Instruction Set Summary. Types and the Java Virtual Machine. Load and Store Instructions. Arithmetic Instructions. Type Conversion Instructions. Object Creation and Manipulation. Operand Stack Management Instructions. Control Transfer Instructions. Method Invocation and Return Instructions. Throwing Exceptions. Implementing finally. Synchronization. Class Libraries. Public Design, Private Implementation. 4. The class File Format. The ClassFile Structure. The Internal Form of Fully Qualified Class and Interface Names. Descriptors. Grammar Notation. Field Descriptors. Method Descriptors. The Constant Pool. The CONSTANT_Class_info Structure. The CONSTANT_Fieldref_info, CONSTANT_Methodref_info, and CONSTANT_InterfaceMethodref_info Structures. The CONSTANT_String_info Structure. The CONSTANT_Integer_info and CONSTANT_Float_info Structures. The CONSTANT_Long_info and CONSTANT_Double_info Structures. The CONSTANT_NameAndType_info Structure. The CONSTANT_Utf8_info Structure. Fields. Methods. Attributes. Defining and Naming New Attributes. The ConstantValue Attribute. The Code Attribute. The Exceptions Attribute. The InnerClasses Attribute. The Synthetic Attribute. The SourceFile Attribute. The LineNumberTable Attribute. The LocalVariableTable Attribute. The Deprecated Attribute. Constraints on Java Virtual Machine Code. Static Constraints. Structural Constraints. Verification of class Files. The Verification Process. The Bytecode Verifier. Values of Types long and double. Instance Initialization Methods and Newly Created Objects. Exception Handlers. Exceptions and finally. Limitations of the Java Virtual Machine. 5. Loading, Linking, and Initializing. The Runtime Constant Pool. Virtual Machine Start-up. Creation and Loading. Loading Using the Bootstrap Class Loader. Loading Using a User-defined Class Loader. Creating Array Classes. Loading Constraints. Deriving a Class from a class File Representation. Linking. Verification. Preparation. Resolution. Access Control. Initialization. Binding Native Method Implementations. 6. The Java Virtual Machine Instruction Set. Assumptions: The Meaning of "Must." Reserved Opcodes. Virtual Machine Errors. Format of Instruction Descriptions. 7. Compiling for the Java Virtual Machine. Format of Examples. Use of Constants, Local Variables, and Control Constructs. Arithmetic. Accessing the Runtime Constant Pool. More Control Examples. Receiving Arguments. Invoking Methods. Working with Class Instances. Arrays. Compiling Switches. Operations on the Operand Stack. Throwing and Handling Exceptions. Compiling finally. Synchronization. Compiling Nested Classes and Interfaces. 8. Threads and Locks. Terminology and Framework. Execution Order and Consistency. Rules About Variables. Nonatomic Treatment of double and long Variables. Rules About Locks. Rules About the Interaction of Locks and Variables. Rules for volatile Variables. Prescient Store Operations. Discussion. Example: Possible Swap. Example: Out-of-Order Writes. Threads. Locks and Synchronization. Wait Sets and Notification. 9. Opcode Mnemonics by Opcode. Appendix: Summary of Clarifications and Amendments. Index. 0201432943T04062001

3,111 citations


Journal ArticleDOI
TL;DR: A new tool, called Eraser, is described, for dynamically detecting data races in lock-based multithreaded programs, which uses binary rewriting techniques to monitor every shared-monory reference and verify that consistent locking behavior is observed.
Abstract: Multithreaded programming is difficult and error prone. It is easy to make a mistake in synchronization that produces a data race, yet it can be extremely hard to locate this mistake during debugging. This article describes a new tool, called Eraser, for dynamically detecting data races in lock-based multithreaded programs. Eraser uses binary rewriting techniques to monitor every shared-monory reference and verify that consistent locking behavior is observed. We present several case studies, including undergraduate coursework and a multithreaded Web search engine, that demonstrate the effectiveness of this approach.

1,500 citations


Journal ArticleDOI
11 Sep 2000
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.
Abstract: The majority of the work carried out in the formal methods community throughout the last three decades has (for good reasons) been devoted to special languages designed to make it easier to experiment with mechanized formal methods such as theorem provers and model checkers. In this paper, we give arguments for why we believe it is time for the formal methods community to shift some of its attention towards the analysis of programs written in modern programming languages. In keeping with this philosophy, we have developed a verification and testing environment for Java, called Java PathFinder (JPF), which integrates model checking, program analysis and testing. Part of this work has consisted of building a new Java Virtual Machine that interprets Java bytecode. JPF uses state compression to handle large states, and partial order reduction, slicing, abstraction and run-time analysis techniques to reduce the state space. JPF has been applied to a real-time avionics operating system developed at Honeywell, illustrating an intricate error, and to a model of a spacecraft controller, illustrating the combination of abstraction, run-time analysis and slicing with model checking.

1,429 citations


Proceedings ArticleDOI
01 Oct 1997
Abstract: Multi-threaded programming is difficult and error prone. It is easy to make a mistake in synchronization that produces a data race, yet it can be extremely hard to locate this mistake during debugging. This paper describes a new tool, called Eraser, for dynamically detecting data races in lock-based multi-threaded programs. Eraser uses binary rewriting techniques to monitor every shared memory reference and verify that consistent locking behavior is observed. We present several case studies, including undergraduate coursework and a multi-threaded Web search engine, that demonstrate the effectiveness of this approach.

1,417 citations