Bogor: An Extensible and Highly-Modular
Software Model Checking Framework
∗
Robby
Matthew B. Dwyer
John Hatcliff
Department of CIS
Kansas State University
Department of CIS
Kansas State University
Department of CIS
Kansas State University
robby@cis.ksu.edu
dwyer@cis.ksu.edu
hatcliff@cis.ksu.edu
ABSTRACT
Model checking is emerging as a popular technology for reasoning about behavior properties of a wide variety of software artifacts including: requirements models, architectural
descriptions, designs, implementations, and process models.
The complexity of model checking is well-known, yet costeffective analyses have been achieved by exploiting, for example, naturally occurring abstractions and semantic properties of a target software artifact. Adapting a model checking tool to exploit this kind of domain knowledge often requires in-depth knowledge of the tool’s implementation.
We believe that with appropriate tool support, domain experts will be able to develop efficient model checking-based
analyses for a variety of software-related models. To explore
this hypothesis, we have developed Bogor, a model checking
framework with an extensible input language for defining
domain-specific constructs and a modular interface design
to ease the optimization of domain-specific state-space encodings, reductions and search algorithms. We present the
pattern-oriented design of Bogor and discuss our experiences
adapting it to efficiently model check Java programs and
event-driven component-based designs.
1. INTRODUCTION
The development of modern software systems involves a
rich complex of software artifacts. Artifacts may represent
aspects of the process by which software is developed or
the various products that are outcomes of stages of process
phases. Disciplined approaches to software development will
apply criteria to determine essential properties of such artifacts, for example, a requirements model should be checked
for completeness and consistency prior to commencement
of system design. For large complex software systems such
criteria should be formalized and their checks automated.
While reasoning about structural properties of artifacts is
∗
This work was supported in part by the U.S. Army Research Office (DAAD190110564), by DARPA/IXO’s PCES
program (AFRL Contract F33615-00-C-3044), by RockwellCollins and by Intel Corporation (Grant 11462).
Permission to make digital or hard copies of all or part of this work for
personal or classroom use is granted without fee provided that copies are
not made or distributed for profit or commercial advantage and that copies
bear this notice and the full citation on the first page. To copy otherwise, to
republish, to post on servers or to redistribute to lists, requires prior specific
permission and/or a fee.
Copyright 200X ACM X-XXXXX-XX-X/XX/XX ...$5.00.
efficient and can be useful (e.g., interface signatures, connection conformity), behavioral reasoning is the ultimate
goal.
Temporal logic model checking [10] is a powerful framework for reasoning about the behavior of finite-state system
descriptions and it has been applied, in various forms, to
reasoning about a wide-variety of software artifacts. For example, model checking frameworks have been applied to reason about software process models, (e.g., [29, 31]), different
families of software requirements models (e.g., [3, 8]), architectural frameworks (e.g., [21, 30]), design models, (e.g., [1,
24]), and system implementations (e.g., [5, 11, 22]). The
effectiveness of these efforts has in most cases relied on detailed knowledge of the model checking framework being
applied. In some cases, a new framework was developed
targeted to the semantics of a family of artifacts [5, 22],
while in other cases it was necessary to study an existing
model checking framework in detail in order to customize
it [8, 13]. Unfortunately, this level of knowledge and effort
currently prevents many domain experts from successfully
applying model checking to software analysis. Experts in
different areas of software engineering have significant domain knowledge about the semantic primitives and properties of families of artifacts that could be brought to bear to
produce cost-effective semantic reasoning via model checking. However, in order to leverage this domain knowledge
in model-checking, these domain experts should not be required to build their own model-checker or to pour over the
details of an existing model-checker implementation while
carrying out substantial modifications.
In this paper, we describe a new model checking framework called Bogor that is designed to make it easy to extend the model checker with new semantic primitives and
to optimize the state-space storage and exploration strategies for particular domains. Existing model checkers, such as
SPIN [26], FDR2 [19], and NuSMV [9], were designed to support a fixed input language using a fixed collection of statespace representations, reduction and exploration algorithms.
The capabilities of these tools has evolved over time, but
that evolution has been limited to the capabilities that the
tool developer found useful or desirable. While such model
checking frameworks are in widespread use, there are multiple difficulties in applying them to reason about a broad
range of software artifacts. Below we describe in greater detail the challenges of working with existing model-checkers
and how Bogor addresses these challenges.
The input language gap: Semantic primitives used in
defining software artifacts cover a broad range from typical
arithmetic and logical operations, which are well-supported
by existing model checkers, to domain-specific large-grain
operations [21, 24]. It is not always possible to map domain
constructs efficiently onto model checker input languages.
For example, most model checking frameworks do not support systems whose state evolves dynamically (e.g., dynamic
creation of data or threads of control) and the few systems
that have attempted to address these kinds of features have
built special purpose model checkers [5, 13] or settled for
bounded static approximations of dynamic behavior [11].
Analysis developers should be able to define domain-specific
primitives to adapt the model checker to a family of software
artifacts.
Property language overhead: Model checking frameworks typically come with the ability to check implicit properties, such as deadlock, system-specific invariants, and temporal logic formulae. It is often the case, however, that
reasoning about a family of software artifacts requires a
property language, for example safety properties, that may
be much simpler to check than a full temporal logic. Furthermore, encoding properties with the limited features of
model checker expression languages can require the addition
of state variables [12] that unnecessarily expand the state
space. Analysis developers should be able to customize the
property checking component of a model checker to optimize
its performance for targeted properties.
Fixed state encodings: Most model checking frameworks, with the exception of [6], employ a small fixed set
of strategies for encoding system data. Knowledge about
domain-specific data, components and properties may suggest opportunities for particularly efficient encodings that
cannot be easily incorporated in existing model checking
frameworks. Analysis developers should be free to tailor the
encoding of system data to achieve state space reductions.
Fixed search algorithms: Model checking typically involves a stateful search of a system’s reachable state-space.
For defect detection one may perform a less complete heuristic search [18, 23, 32] and for certain classes of systems stateless search may be an attractive alternative [22]. Analysis
developers should be able to configure the search mode of the
model checker based on the kinds of reasoning desired and
on the nature of the artifact.
Fixed reduction strategies: There exists an enormous
body of literature on state space reduction strategies. For
example, partial order reductions which exploit information
about independence between transitions (e.g., [10, Chapter
10]) and abstraction-driven-refinement (e.g., [25]) are techniques that have proven quite effective in reducing model
checking costs. Interestingly, the theoretical presentation of
these techniques is often parameterized by, e.g., the independence relations or counter-example feasibility analyses, but
actual implementations are usually hard-wired to a particular notion of independence or a particular notion of feasibility. However, parameterizing the implementation on particular strategies or going beyond this to allow the strategies
to be changed dynamically during checking (e.g., to dynamically calculate independence information [15]) can lead to
significant improvements in reduction techniques. Analysis
developers should be able to combine collections of reductions
to target a specific family of software artifacts and thereby
maximize state-space reduction without incurring unnecessary overhead.
Bogor has grown out of our significant experience developing model checking frameworks that translate software artifacts to the input languages of existing model checking tools.
Two such frameworks are Bandera [11], which extracts abstract finite-state models Java programs and produces input
for model checkers such as SPIN, and Cadena [24], which
translates extended CORBA Component Model (CCM) designs of event-driven systems to the input language of the
dSPIN model checker. In both of these systems we found
that the deficiencies, highlighted above, of existing model
checkers forced us to produce models whose analysis was
less-efficient than we knew was possible based on our understanding of the two domains. Furthermore, our experience
suggests that no fixed input language or collection of capabilities would suffice, since it is not possible to anticipate all
of the kinds of artifact analyses that developers might want.
We have also been inspired by our experiences working
with Java Path Finder (JPF) [5] – a model-checker that
works directly on Java byte-code. JPF stands in contrast
to many existing model-checkers in that it has proven to be
a very flexible framework for incorporating a wide variety
of state space exploration algorithms. Thus, JPF provides
flexibility along several axes (flexibility in search algorithms,
flexibility in reduction strategies), but it is strongly tied to
byte-code (i.e., it is not flexible with respect to input language) and is thus not well-suited for analyzing other kinds
of software artifacts.
These experiences have led us to develop a novel model
checking framework that is explicitly designed to support
the analysis of a wide-variety of software artifacts related to
modern, dynamic, concurrent software systems. This paper
makes the following specific contributions:
1. we describe the design of Bogor’s extension interface
that allows the model checkers input language to be
extended to form a virtual machine that is adapted to
different families of software artifacts;
2. we describe how Bogor’s module and plug-in interfaces
are engineered using design patterns that encapsulate
and reduce dependencies between core modules and
that allow the components of the model checking engine to be customized to a family of software artifacts;
3. we illustrate how Bogor can be customized to efficiently support checking properties of two families of
software artifacts: Java programs and CCM-based designs from Cadena;
4. we demonstrate that even though Bogor is designed
for flexibility, this flexibility need not degrade performance – in particular, domain-specific optimizations
that can be incorporated through Bogor’s flexibility
yield performance numbers that often dramatically improve upon the performance of existing non-customized
model-checkers.
Bogor is implemented as an Eclipse plug-in [17] and comes
with an integrated editor and counter-example visualization
component; for more information visit the Bogor web-site
[33].
The paper proceeds in the next section with a detailed description of Bogor’s input language and presents the architecture of the model checking framework. Section 3 presents
a detailed example illustrating how Bogor can be extended.
Section 4 gives an overview of how Bogor is being used in
the Bandera [11] and Cadena [24] model checking tool-sets.
Section 5 discusses related work and we conclude in Section 6.
2. BOGOR OVERVIEW
2.1
BIR Modeling Language
Bogor checks systems specified in a revised version of the
Bandera Intermediate Representation (BIR). The previous
version of BIR was designed to be an intermediate language used by Bandera for translating Java programs to
the input languages of existing model-checkers such as Spin.
Thus, this earlier version provided direct support for modeling Java features such as threads, Java locks (supporting
wait/notify), and a bounded form of heap allocation. To
facilitate the construction of translators to back-end modelcheckers like Spin, BIR control-flow and actions are stated
in a guarded command format which it quite close to the
format used to specify systems in model-checker input languages like Promela.
As explained in the introduction, our experience with
Bandera and other tools such as JPF and dSpin has led
us to conclude that software model-checking can be more
effectively supported by a new infrastructure that has at its
core an extensible model-checker that is designed to support software directly rather than relying on translations to
model-checkers that do not provide direct support for modeling many of the language features found in modern software.
As part of this transition to a new infrastructure, we have
revised the definition of BIR to include a number of new features such as the BIR extension mechanism, generic types
and polymorphic functions, type-safe function pointers, virtual function/method tables, and unbounded dynamic allocation of heap objects and threads supported by garbage
collection.
Here are some language design goals that drove our revision of BIR.
1. Provide support for modeling of a variety of software
artifacts including code (e.g., Java, C#), designs (e.g.,
state-charts, high-level transition systems), and abstractions of software layers (e.g., CORBA middleware services and asynchronous communication mechanisms).
2. Provide type-safe modeling that supports OO typestructures and makes a clear distinction between sideeffecting and non-side-effecting constructs.
3. Design the language to serve as the target of automatic
translations.
4. Provide support for capturing a variety of property
specification forms (e.g., temporal logic, automata, assertions, invariants) used in software model-checking.
5. Provide mechanisms that (a) support abstraction along
multiple dimensions and (b) allow state data that is irrelevant to the property being verified to be shifted out
of the model-checker’s state-storage mechanisms.
6. Provide support for user-defined type-safe extensions
of the language to include new types, expressions, and
actions (commands).
The BIR data model: There are two categories of BIR
data types: primitive types (e.g., boolean, int, long, float,
double, enum), and non-primitive types (e.g., null, record,
array, lock). BIR’s type system is designed to support modeling of Java programs but not to be hard-wired to the Java
type system (design Goal 1 above). For example, BIR does
not include the Java notion of ’class’ directly, but instead
models class data and virtual methods using records and
type safe function pointers. This flexibility makes it easier
to model structures found in other software artifacts such
as the high-level component-based designs from Cadena [24].
Java’s inheritance-based sub-typing and virtual methods are
supported by explicit BIR sub-typing declarations on record
types and by virtual method tables which are included as
primitives in BIR. In addition, BIR adopts the Java memory model (i.e., pointer arithmetic is disallowed and object
reclamation is achieved through garbage collection). Although this appears to go against Goal 1, it is necessary
to achieve our goals for safety (Goal 2). Moreover, most
applications domains that seek to apply model-checking to
achieve high-assurance disallow pointer arithmetic anyway.
BIR emphasizes strong static typing (Goal 2) for several reasons. Strong static typing minimizes the amount
of dynamic type checking that the model checker needs to
perform, thus, it reduces overhead during model-checking.
Additionally, strong static typing provides earlier feedback
concerning the well-formedness of models, and this aids in
the correct design of translators targeting BIR and manual
model construction.
For flexibility, BIR supports generic abstract data types
(ADTs) and polymorphically typed functions. However, Bogor does not currently provide polymorphic type-inference as
in SML or Haskell. Instead, type variables for functions and
ADTs must be instantiated explicitly. We have chosen this
approach because BIR automatic translation can easily supply explicit polymorphic types and instantiation (Goal 3),
and because sophisticated polymorphic type inference for
OO-like type systems includes a number of non-trivial issues
that are peripheral to our central theme of model-checking.
In contrast to the input languages used in almost all other
model-checkers (including SPIN [26], NuSMV [9], SLAM [2],
BLAST [25]), BIR supports dynamic creation of both thread
and heap objects with automatic reclamation by garbage
collection. Moreover, BIR provides a state-of-the-art canonical heap representation that seems essential for effective
checking of highly dynamic concurrent software systems.
Such systems generate many heap instances that differ in
the relative position of allocated objects but that are actually observationally equivalent (i.e., the heap instances can
not be distinguished by any Java memory operations). Due
to positional differences of object placement in heaps, conventional representations of heaps as e.g., arrays of memory
cells would yield different states for these heaps. However,
Bogor’s canonical heap representation (based on work by
Iosif on dSpin [13]) ensures that heaps that are observationally equivalent map to the same state. This dramatically reduces the number of states generated when checking highly
dynamic systems.
The BIR control model: BIR’s guarded commands are
formed using two classes of constructs: guard expressions
which evaluate to values but produce no side-effects, and
actions (commands) which modify the system’s data state
(Goal 2). The rich expression language includes function expressions and value bindings as found in functional programming languages. BIR provides exception handling mechanisms that would be otherwise tedious to model using the
traditional control-flow jump instructions (Goal 1).
BIR Extensions: BIR’s extension facility allows modelers
to add new types, expressions, and actions (Goal 6). An
extension declaration consists of (1) a signature declaration
which specifies the new symbols and associated arities to be
introduced into the name-spaces for types, expressions, and
actions, and (2) the name of a Java package that implements
s ystem R e s o u r c e C o n t e n t i o n {
e x t e n s i o n S e t f o r myPackage . S e t M o d u l e {
t y p e d e f t y p e <’a >;
e x p d e f S e t . t y p e <’a> c r e a t e <’a >( ’ a . . . ) ;
e x p d e f ’ a c h o o s e <’a>( S e t . t y p e <’a >);
e x p d e f b o o l e a n isE mp ty <’a>( S e t . t y p e <’a >);
e x p d e f b o o l e a n f o r A l l <’a >( ’ a −> b o o l e a n ,
S e t . t y p e <’a >);
a c t i o n d e f add <’a>( S e t . t y p e <’a > , ’ a ) ;
a c t i o n d e f remove <’a>( S e t . t y p e <’a > , ’ a ) ;
}
thread Process () {
loc loc1 :
invoke run ( )
return ;
}
f u n c t i o n run ( ) {
Resource resource ;
loc loc2 :
when ! S e t . i sEm pt y<R e s o u r c e >( r e s o u r c e s )
do { / / c h o o s e an e l e m e n t and remove i t
r e s o u r c e : = S e t . c h o o s e<R e s o u r c e >
( resourcePool );
S e t . remove<R e s o u r c e >( r e s o u r c e P o o l ,
resource );
} goto l o c 3 ;
loc loc3 :
do { / / r e s o u r c e i n u s e
resource . isFree := f a l s e ;
} goto l o c 4 ;
loc loc4 :
do { / / r e s o u r c e f r e e
resource . isFree := true ;
} goto l o c 5 ;
loc loc5 :
do { / / add t h e r e s o u r c e ba ck t o p o o l
S e t . add<R e s o u r c e >( r e s o u r c e P o o l ,
resource );
} goto l o c 2 ;
do { / / empty t r a n s f o r m a t i o n
} goto l o c 2 ;
}
record Resource { boolean i s F r e e ; }
record Disk extends Resource { }
record Display extends Resource { }
S e t . t y p e<R e s o u r c e > r e s o u r c e P o o l ;
fun i s R e s o u r c e F r e e ( Resource r e s o u r c e )
r e t u r n s boolean = r e s o u r c e . i s F r e e ;
fun A r e A l l R e s o u r c e s I n P o o l F r e e I n v ( )
r e t u r n s boolean =
S e t . f o r A l l <R e s o u r c e >( i s R e s o u r c e F r e e ,
resourcePool );
main t h r e a d MAIN ( ) {
loc loc0 :
do { / / c r e a t e t h e p o o l and c r e a t e s two p r o c e s s e s
r e s o u r c e P o o l : = S e t . c r e a t e <R e s o u r c e >
( new D i sk , new D i s k , new D i s p l a y ) ;
start Process ( ) ; start Process ( ) ;
} return ;
}
}
Figure 1: Resource Contention Example
the semantics of the extension. Note that the extension
does not extend the BIR grammar, but only adds names to
the set of names of built-in expressions, actions, etc. This
means that the developer does not need to extend the parser
or other syntactic support facilities. Rather, the developer
traverses the extension structure and implements the extension semantics using well-defined APIs for BIR’s existing
abstract syntax trees and Bogor model-checker components.
Extensions provide a convinient way to realize domainspecific abstractions of software components or layers, and
to address the input language gap for modeling domainspecific software artifacts (Goal 5). Often times, there are
component/layers of the software that have a significant
amount of state that is irrelevant to the properties being
checked. Rather than maintaining a complete implementation of a software component/layer using BIR’s variables,
the Java package implementing the extension can hold the
state associated with the complex component/layer and only
expose as much as is relevant at the BIR level. Since only
the BIR variables are held in Bogor’s state vector during
model-checking, this can dramatically reduce the costs of
representing portions of a software system.
Hiding complex portions of the state in this manner is not
novel. For example, when modeling communication protocols using Spin [26], channel data types (chan) are often
used to model message-passing channel in networks. This
can be done because the specific implementation of the network channels is irrelevant with respect to the properties
being checked. The properties are usually only concerned
with the functional behavior of the channels, i.e., rendevouz,
asynchronous, synchronous, and sending and receiving messages. Furthermore, properties are usually only concerned
with a channel’s abstract states, i.e., the specific channel
implementation state, for example, the state of message retransmission protocols used to provide the channel service,
does not need to be exposed in the model state. What is
novel about BIR is that it does not a priori hard-code such
abstraction mechanisms for a particular domain – rather,
BIR’s extension facility provides an open-ended mechanism
for adding any number of domain-specific abstractions. For
example, BIR extensions are used to represent the functionality of the Real-Time CORBA Event Service in our work
on checking CCM designs [24].
BIR Example: Figure 1 presents a BIR model of concurrent processes that acquire and release resources from a resource pool. The code begins with an extension declaration
of a generic set type used to represent the set of resources.
We will show the implementation details of the SetModule
as a Bogor plug-in in Section 3, and for now simply comment
on aspects of its signature. The new type variable ’a represents the element type of the set. The extension includes
both expression extensions (create, choose, isEmpty, forAll)
and action extensions (add, remove). The create expression
creates and returns a new set (this is considered non-sideeffecting since it does not modify any BIR variables). The
ellipses (...) in the argument of choose indicate that it has
variable arity. The choose expression non-deterministically
picks one element of the argument set to return (the nondeterminism is implemented internally by calling a Bogor
primitive that causes the model-checker scheduler to explore multiple paths that correspond to the return every
element of the argument set). The forAll expression takes
a predicate (represented as a boolean function) and a set
and determines whether all elements of the set satisfy the
predicate. In general, an expression extension may perform
complex computations atomically and it can use any information available to the model checker such as the state in
which it is currently being. However, it must not modify the
stored states of the model-checker. In general, an action extension can do whatever an expression can do (except return
Bogor
Front−End
Lexer
.bir
Model Checking Components
IActionTaker
IBacktrackIF
IStateMgr
IExpEval
ITransformer
ISearcher
Verified
Parser
Type Checking
.config
Semantics
Analyses
counter
example
IValueFactory
ISchedulingS
IStateFactory
Figure 2: Bogor Architecture
a value), and it can also modify the current state.
A record type declaration begins with a declaration of its
name (e.g. Resource) followed by the declaration of its fields.
A record may extend another record (e.g., Disk extends Resource and in this case Disk is said to be a sub-record of
Resource). All the fields of a record are implicitly present
in its sub-records. This feature is useful when modeling a
type hierarchy such as the class hierarchy in Java. BIR does
not impose a restriction that there must a unique top record
such as in Java with its java.lang.Object class.
BIR supports functions with expression bodies (e.g., IsResourceFree and AreAllResourcesInPoolFreeInv). A function is
allowed to be recursive. If recursive calls cause the stackdepth to exceed a user-specified bound, the model-checking
process truncates the search along the current path, and a
warning is issued indicating the search has not explored all
possible states.
A BIR thread contains local variable declarations and a
sequence of locations with guarded transformations (transitions) between those locations. A thread with the main
modifier is the only thread that is active in the initial state
of the system. There are two kinds of guarded transformations in BIR: (1) block transformation consisting a sequence of actions that are executed atomically (e.g., do ...
in loc0) and, (2) invocation transformation for function call
(e.g. invoke in loc1). A transformation is enabled when
the program counter for the thread is at the location of
the transformation, and the transformation’s guard holds
(if no guard is stated, then the transformation is always
enabled when control reaches it). If there are several enabled transformations in a state, then the model checker
non-deterministically choose which transformation that will
be executed next. If there are no enabled transformation at
a state where there are still active threads, then the state is
a deadlock state.
In Figure 1, the MAIN thread creates a resource pool with
three elements, and starts two Process threads. Each Process thread begins by non-deterministically choosing a resource from the pool. Note that at loc5, the process nondeterministically chooses to add the acquired resource back
to the pool, or to bypass this action and proceed directly
to loc2. If the processes keep refusing to relinquish the resources, then eventually the system will reach a deadlock
state because the pool is empty (the guard at loc2 is false).
If the second transformation at loc5 is removed, the system
is deadlock free. One can then try to verify the invariant
that all resources in the pool should be free (the following
subsection explains how Bogor’s configuration file is used to
specify that the AreAllResourcesInPoolFreeInv should be
treated as an invariant to be verified).
2.2
Bogor Architecture
Figure 2 presents the Bogor architecture. The architecture of Bogor can be divided into two parts: (1) a front-end
that processes a given model expressed in the BIR modeling language, and (2) the actual model checker components.
The front-end builds the abstract syntax tree (AST) from
the input model, and it then checks the well-formedness of
the model, for example, by type checking, and extensions
interface checking.
All model-checking tools include functional aspects for
state-space search, scheduling, and managing seen before
states. However, in their implementations, these aspects are
often tangled, and thus insertion of alternate strategies or
other customizations is often quite difficult. One of the contributions of our work is not just to present a non-tangled
implementation, but moreover to present core components
using widely-used and well-documented design patterns [20]
that hide irrelevant implementation details by encapsulation, that reduce dependences between components, and
that build in strategies for parameterization, adaptation,
and extension. Bogor modules need to interact with each
other. However, they should only be dependent on the interfaces of other modules. We will describe each Bogor module
and the intuition behind its interface, and we will frequently
refer to design patterns (or their variations) from [20] using
a small caps font, e.g., Abstract Factory. We will only
describe the basic capability of each module. Modules can
be extended to provide more capabilities via Decorators.
A complete listing of the Bogor module APIs and examples
of their use can be found on the Bogor web-site [33].
Following the common functional aspects above, the Bogor model checker components consists of three major modules: (1) search module, (2) scheduling module, and (3) state
manager module, as well as other modules such as the module that manages backtracking and extensions.
The ISearcher is a Strategy for the search method used.
For example, if depth-first search is used, then at any given
state, its children states will be explored first before exploring its sibling states.
The IStateManager is a Facade for managing states.
Specifically, the interface dictates that given a state, the
ddddd IValue YYYYYYYYYY
ddddddd
YYYY )/
un $dddddd
INonPrimitiveValue
IPrimitiveValue
WWWWW
VVVV
l
hnhnn
l
h
VVVV
l
h
W
h
l
WW
_
_
pw (hh. .h.s{ .nnn
zr ,ll
'.
."* . . W '.
IIntValue
ILongValue
IPrimitiveExtValue
INullValue
IRecordValue
INonPrimitiveExtValue
Figure 3: Bogor Value Interface Hierarchy (excerpts)
Figure 3 presents the hierarchy of BIR values. BIR valmodule determines whether the state has been visited beues are divided into two categories (reflecting BIR types):
fore. There is no constraint on how it achieves that as long
(1) primitive values, and (2) non-primitive values. When a
as it does not make an assumption that the instance of each
primitive (non-primitive) type extension is declared, then its
state is different. For example, in depth-first search mode
corresponding value should implement the IPrimitiveExtValue
there is only one active state at any given time; this is anal(INonPrimitiveValue) interface (this is illustrated in the
ogous to having one state at runtime. The state is modified
next section). Non-extension values, their creation, and the
by each action and the search relies on the backtracking
determination of their default values are managed by the
ability (i.e., undo) to restore the state to the previously visited state. Thus, the module cannot rely on the actual state
IValueFactory interface. Thus, the specific implementarepresentation because it changes as program traces are extion of the values depends on the implementation of the
value factory. However, Bogor requires that a primitive
plored.
value implementation be immutable, i.e., once created, it
The ISchedulingStrategist is a Strategy for the schedcannot be changed. Immutability opens the opportunity for
uler. The most basic scheduling strategy employed by modelcheckers is to generate all possible interleavings of thread exobject pooling (via the Flyweight pattern) whenever appropriate.
ecutions. Other strategies include incorporation of support
A BIR state interface (IState) is a Facade providing the
for priority based scheduling. In addition, when processing
interface to access the global values, thread locations and
any inner-thread non-deterministic choice (e.g., associated
with multiply-enabled transitions within the same thread),
local values at each of a thread’s stack frame.
this module should be consulted to determine which transiBogor is configured through its configuration file. A Bogor configuration defines the implementation of each Bogor
tion to execute next. For example, in a full-state exploration
module along with their options. For example,
mode, the scheduler should make sure that every branch of
a non-deterministic choice should be explored. This modISearcher=myPackage.MySearcher
ule is also consulted to determine which transformations are
ISearcher.maxErrors=3
enabled in a given state.
IStateManager=myPackage.MyStateManager
The IActionTaker is an Interpreter for BIR actions
such as assignment actions. The module is also a Visitor for
specifies that the Java class myPackage.MySearcher is the
BIR actions, which enables new actions to be incorporated
search module, and the maxErrors option that specifies the
easily if necessary. Given the context of the action (e.g., the
maximum number of errors that the search should try to
state in which it is being interpreted, the thread that exefind before it stops is passed to myPackage.MySearcher.
cutes it, etc.), the module is responsible for executing the
Given a configuration file and a model file, the Bogor
action — thus, this module potentially changes the state.
front-end will check the well-formedness of the model, and it
For a depth-first search mode, the module is required to prothen instantiates each module (including extension modules)
duce backtracking information for each action it executes. It
as Singletons. It then wraps them in the IBogorConfiguration
is also responsible for managing invocations of all the action
interface. Each module is then passed the options that are
extensions that are defined. The IExpEvaluator and the
specified in the configuration file, and then the connections
ITransformer are similar to IActionTaker except that they
between modules are initiated. If there is no error, then
are responsible for executing BIR expressions and transforthe search begins. If the search finds an error, then Bogor
mations, respectively. Furthermore, the ITransformer is
produces a counter-example that shows the states along the
also responsible for exception handling.
error trace.
The IBacktrackingInfoFactory is an Abstract Factory for creating backtracking information for each BIR
3. SET EXTENSION AS BOGOR PLUG-IN
non-extension action. For example, for a depth-first search,
Figure 4 presents the implementation of the set extension
backtracking information consists of method that implements
whose
interface is defined in Figure 1. MySet implements
the “undo-ing” of a particular action. The IStateFactory
and the IValueFactory are similar to IBacktrackingInfoFactory a BIR value that provides the semantics for Set.type and
the SetModule class implements the expression and action
except that they are responsible for creating BIR states and
extensions
declared in Set.
values, respectively.
In developing extensions, the user has complete control
Note that all these modules extend the IModule interface
over how to encode the state of the extensions. In the set exthat governs, for example, how to establish connection beample, we reuse a Java set implementation (e.g. java.util.HashSet)
tween the modules, or how to access each module’s options.
to implement the MySet. From another perspective, MySet
When an extension is declared in the BIR model, the declaserves
as an Adapter for the Java set collection library
ration also includes the fully-qualified name of the Java class
(e.g., the add method is an adapter method for HashSet).
that implements it. This Java class should also implement
The linearize method is a Decorator that encodes the
the IModule interface as well as all the expression or action
state vector of the set value. As with communication layextensions that are declared.
ers abstracted by Promela’s channel states, we do not need
package myPackage ;
public c l a s s MySet
implements I N o n P r i m i t i v e E x t V a l u e {
protected HashSet s e t = new HashSet ( ) ;
protected boolean i s N o n P r i m i t i v e E l e m e n t ;
public void add ( I V a l u e v ) { s e t . add ( v ) ; }
public byte [ ] [ ] l i n e a r i z e ( . . . ,
i n t bitsPerNPV , O b j e c t I n t T a b l e npvIdMap ) {
Object [ ] elements = s e t . toArray ( ) ;
B i t B u f f e r bb = new B i t B u f f e r ( ) ;
i f ( isNonPrimitiveElement ) {
i n t [ ] e l e m e n t I d s = new i n t [ e l e m e n t s . l e n g t h ] ;
f o r ( i n t i = 0 ; i < e l e m e n t s . l e n g t h ; i ++)
e l e m e n t I d s [ i ] = npvIdMap . g e t ( e l e m e n t s [ i ] ) ;
Arrays . s o r t ( elementIds ) ;
f o r ( i n t i = 0 ; i < e l e m e n t s . l e n g t h ; i ++)
bb . append ( e l e m e n t I d s [ i ] , bitsPerNPV ) ;
} else . . .
return new byte [ ] [ ] { bb . t o B y t e A r r a y ( ) } ;
}
}
public c l a s s SetModule implements IModule {
protected I E x p E v a l u a t o r e e ;
protected I S c h e d u l i n g S t r a t e g i s t s s ; . . .
public I V a l u e c h o o s e ( IExtArguments a r g ) {
MySet s e t = ( MySet ) a r g . getArgument ( 0 ) ;
IValue [ ] elements = s e t . elements ( ) ;
orderValues ( elements ) ;
int index = s s . advise ( . . . , elements ,
arg . g e t S c h e d u l i n g S t r a t e g y I n f o ( ) ) ;
return e l e m e n t s [ i n d e x ] ;
}
public I V a l u e f o r A l l ( IExtArguments a r g ) {
S t r i n g predFunId = . .
MySet s e t = ( MySet ) a r g . getArgument ( 1 ) ;
IValue [ ] elements = s e t . elements ( ) ;
f o r ( i n t i = 0 ; i < e l e m e n t s . l e n g t h ; i ++) {
I V a l u e v a l = e e . e v a l u a t e A p p l y ( predFunId ,
new I V a l u e [ ] { e l e m e n t s [ i ] } ) ;
i f ( i s F a l s e ( v a l ) ) return g e t B o o l e a n V a l u e ( f a l s e ) ;
}
return g e t B o o l e a n V a l u e ( true ) ;
}
public I B a c k t r a c k i n g I n f o [ ]
add ( IExtArguments a r g ) {
f i n a l MySet s e t = ( MySet ) a r g . getArgument ( 0 ) ;
f i n a l I V a l u e e l e m e n t = a r g . getArgument ( 1 ) ;
i f ( ! s e t . con tains ( element ) ) {
s e t . add ( e l e m e n t ) ;
return new I B a c k t r a c k i n g I n f o [ ] {
new I B a c k t r a c k i n g I n f o ( ) {
public void b a c k t r a c k ( I S t a t e s t a t e ) {
s e t . remove ( e l e m e n t ) ;
} ...
}
};
} e l s e return new I B a c k t r a c k i n g I n f o [ 0 ] ;
}
Figure 4: Set Extension Implementation (excerpts)
to hold in the state vector the specific HashSet implementation of a set. Rather, the relevant information that we
should store is the abstract state of the set, i.e., some compact representation of the members of the set at the current
state. The encoding of the members of the set is different
for each BIR type. When encoding non-primitive values,
Bogor provides a mapping from each non-primitive value to
a unique id (npvIdMap) and to the number of bits needed
to encode each id (bitsPerNPV). Using this information, the
state vector of the set value is a sequence of the unique
ids of non-primitive values. In order to preserve set semantics, the ids are ordered, thus, two sets containing the same
elements will have the same state vector. The symmetry reduction achieved by storing a canonical representative of a
given HashSet can significantly reduce model checking costs.
The ability to reuse existing Java code in Bogor extensions
dramatically reduces implementation costs.
The SetModule implements the expression and action extensions in Set extension. The SetModule.choose() method
implements the choose expression extension from Figure 1.
An expression extension implementation takes an IExtArguments
and returns an IValue. The IExtArguments provides the
context of the expression evaluation such as the current state
and the arguments to the extension expression. The implementation of the choose method extracts the set from
the argument list, retrieves its elements, and then uses the
ISchedulingStrategist to select the set element to be returned for the current execution trace. In essence, the
ISchedulingStrategist is a stateful component that “remembers” what has been previously scheduled at this particular choice point (e.g., it remembers what set elements
have been returned to generate previously explored execution traces leading out of this control point). In a full-state
exploration, the ISchedulingStrategist makes sure that
all set elements will eventually be considered. The forAll()
method applies a predicate to each element in the set. If one
element does not satisfy the predicate, then it returns false.
The add() method adds an element to the set. Since add is
an action, it must provide backtracking information, i.e., it
must provide a method for “undoing” its state transformation. In this example, this is achieved by removing the set
element that was inserted by the add operation. Note that
each executions of add is treated as a single atomic action by
the model checker. We believe that analysts should exploit
extensions as a means of achieving both an appropriate level
of abstraction in modeling and as a means of reducing the
state space by controlling atomicity.
As can be seen from this example, implementing extensions does require some knowledge of the internal mechanisms of Bogor. Typically, the most challenging decisions to
make are (a) how to implement the linearization function for
producing the state vector representation, and (b) how to
implement the undo operation required for backtracking. To
guide extension developers, we have built a fairly extensive
collection of documented examples that illustrate common
approaches to obtaining linearization and undo methods. In
addition, Bogor provides several facilities to help automate
the testing and validation of extensions. In debugging mode,
Bogor automatically checks the correctness of undo methods by checking that the state before an action is executed
is equivalent to the state that results from executing the
action and then immediately backtracking. Furthermore,
one can validate various properties of extensions using Bogor by writing and checking small, but general, models. For
example, to test our set extension, we created a model that
non-deterministically adds and removes elements from a set.
After each element addition, we assert that the element is
a member of the set, and after each element removal, we
assert that the element is not a member of the set.
4. BOGOR APPLICATIONS
In this section we describe our experiences using Bogor to
develop customized model checkers for two quite different
kinds of software descriptions. The first author, the main
developer of Bogor, has implemented a collection of state
space encoding and reduction techniques as Bogor plug-ins
that together represent a significant advance in model checking properties of Java programs. This customization of Bogor took approximately 4 weeks, and, over a small range
of Java programs, resulted in state space reductions of more
than a factor of 20 [15] relative to the best-known techniques
[5, 28]. Furthermore, this work has identified additional avenues for further state space reduction as discussed below.
One could argue that this experiences is not representative
of the effort that would be required of someone less familiar with Bogor and the implementation of model checkers in
general. Perhaps more representative is another experience
of a colleague of ours who has a basic knowledge of model
checking (but not an in-depth knowledge of the implementation of model checkers or Bogor) and has significant domain
knowledge about component-based systems, CORBA middleware, and real-time systems. He started from our existing
approach to modeling event-driven CCM-based designs that
involved translating them to the input language of the dSpin
model checker, an extension of Promela [24]. That translation was developed in over 3 months by a different person.
Using the ideas embodied by that translation, he developed,
in approximately 1 month, a customization of Bogor that is
able to achieve 1000-fold reductions in the size of the state
space [14]. We believe this is strong evidence that extension
and customization Bogor by domain experts is very costeffective.
In the rest of this section, we outline the key features of
Bogor that were used in these two efforts and then describe
how those efforts led to the evolution of Bogor APIs.
4.1
Verification of Java Programs
We have applied Bogor to successfully check real-world
size Java programs [15] including a parallel programming
framework written in Java that has been used in dozens of
real scientific and engineering applications [16]. The task
is made easier because BIR can express all features of the
Java programming language. The presence of BIR features
that directly support, for example, dynamic thread and object creation, exception handling, virtual functions, recursive function, which are lacking in most model checkers,
greatly simplified the mapping of Java features. These features of new BIR significantly reduced the cost of implementing the translation from Java to BIR compared to the
development of Bandera [11] which translated directly to the
older “less featureful” BIR and then on to Promela for the
SPIN model checker.
The features of new BIR also make it possible to check a
broader range of properties than is possible with the version
of the Bandera Specification Language (BSL) [12] that is
used in the current distribution version of Bandera. BSL was
designed to bridge the gap between a Java-oriented property
specification language and the expression and temporal logic
language of model checkers like SPIN. The limitations of
those expression languages put properties, such as the invariant in Figure 1, beyond the reach of what can be expressed
without resorting to the addition of state-space expanding
variables. Many complex heap properties, such as, “field x
only points to an acyclic sorted list where the element contained in each list node is distinct”, are not expressible in
BSL or any existing model checker input language. Bogor
enables these and other complex properties to be expressed
without expansion of the state space.
We have implemented various reduction techniques by
customizing BIR modules. Specifically, we have implemented
heap symmetry [28], thread symmetry [4] reductions, and
collapse compression [27] by customizing the IStateManager
module of Bogor without affecting other modules. We have
also implemented a novel partial-order reduction that uses
information from a dynamic escape analysis. The idea is
that accesses (read/write) to objects that are non-escaping,
i.e., reachable only by one thread, do not affect the computation of other threads. We customized the ISearcher so
that it inspects the heap to determine whether there is an
escaping object that will be accessed in the next transition.
If that is not the case, then we apply partial-order reduction. This strategy showed upwards of 20 times state-space
reduction, over and above the above mentioned reductions,
in checking properties of several real Java applications.
4.2
Verification of Cadena Models
Cadena is a design and verification environment for CORBA
component model (CCM) systems [24]. CCM systems execute on a CORBA-compliant middleware that provides an
event-service (i.e., a framework for implicit invocation). Cadena enriches CCM’s component interface definition language (IDL) with specification forms for describing component interconnections, intra-component dependences, and
state transition semantics for component methods and event
handlers.
While it is possible to produce model checking based analyses of general CCM system designs, we have found that
focusing on a specific class of CCM systems allows for significantly more efficient checking tools. Specifically, we focus on the Boeing Bold Stroke architecture which supports
the development of real-time component-based embedded
systems. Cadena, as described in [24], supports analysis of
global behavioral properties of systems by translation to the
dSpin model checker. One of the novelties of that approach
is the encoding of an abstract semantic model of middleware services in the input language of dSpin. Our Bogor
encoding embeds this semantic model in a collection of BIR
extensions. Translating Cadena models to this Bold-Strokeenhanced version of BIR greatly simplifies model development. Furthermore, the BIR extensions separate the static
system state (which, because it is not changing, does not
need to be held in the state vector) from the mutable statespace. This has a significant impact on memory consumption, and hence performance.
Bold Stroke applications are priority scheduled based on
the results of rate monotonic analysis (RMA). In our previous models, we encoded priority scheduling in the dSpin input model, but there were two limitations: additional state
variables had to be added to the state space to track the
current priority, and for certain compound transitions, e.g.,
function call and return, priority could not be enforced by
our scheme. In Bogor, the input model is completely independent of scheduling information. We simply define a
priority assignment for components and then extend the
ISchedulingStrategist to filter the set of enabled transitions to produce the highest-priority enabled transition. The
ease with which the scheduler can be extended in Bogor led
us to develop several variant extensions, including an extension of ISearcher that keep tracks of an abstraction of the
temporal relationship between the period of time-triggered
events and the duration of event handlers. The knowledge
that drove these extensions was based on observations that
are quite natural for a Bold Stroke/CCM domain expert to
make, and Bogor provided a mechanism by which they could
be easily incorporated into the analysis.
In addition to customizing parts of Bogor to efficiently reason about Cadena designs, we were able to reuse existing Bogor components. Some of these, for example Bogor’s collapse
compression component, provide a significant reduction over
what could be obtained with existing model checkers. Preliminary performance data suggests that this customization
allows for orders of magnitude reductions in the state-space
[14] over what could be achieved using translation approach
[24]. While it is possible to modify the implementation of
dSpin to achieve similar results, this would require gaining
in-depth knowledge of dSpin’s implementation which is a
significant effort. We believe this experience demonstrates
that customizing Bogor produced what amounts to a dedicated model checker for Cadena, but without paying the
cost of implementing it from the scratch.
4.3
The Evolution of APIs
We do not claim that Bogor has the ideal collection of
APIs. By designing for extension, we hope that the current
set of APIs will admit a wide variety of uses for Bogor, but
we expect that the APIs will evolve as users gain experience in customizing Bogor. In the two projects described
above we identified a common form of reduction that was
extremely useful; we call it dynamic atomicity. Most model
checker languages allow a fragment of the input to be marked
as atomic and that fragment will be treated as a single indivisible transition in state space exploration. This static
decision of what should be considered atomic is a limitation. A more general approach is to define a predicate over
a system state and a transition that when true allows the
atomic execution of the transition. The customizations of
Bogor described above both use this idea but each of them
had to implement the mechanism that applies the predicate
and then drives the atomic transition execution. We are
redesigning Bogor’s APIs to factor this common functionality and to require only the predicate definition in order to
achieve dynamic atomicity reductions.
5. RELATED WORK
There exists a large body of work on tools for finite-state
verification of software. The Spin [26] model checker was
initially designed to verify communication protocols. However, it has been succesfully applied for other software artifacts such as Java programs, for example, as the back-end of
the Bandera project [11]. Similarly, the NuSMV [9] model
checker is designed for checking hardware, but it has also
been used in the Bandera project to verify Java programs.
Both model-checkers have been widely used due to their level
of maturity and efficiency. However, they lack some features essential for checking modern, dynamic, and concurrent software such as Java programs. When using them with
Bandera, we resorted to bounded-static approximations of
dynamic behaviors of the programs. In addition, because
they lack of features such as dynamic heap object creation
and management, many reductions strategies [28, 15] that
have proven to be useful for verifying dynamic software cannot be easily incorporated. Furthermore, the designs of the
tools are not flexible and their internal functional aspects
are not decoupled enough to enable customization without
knowing the details of how the tools are implemented.
The SLAM [2], BLAST [25], and MAGIC [7] model checkers work on ”well-behaved” (e.g., no pointer arithmetic) sequential C programs with minimal support for dynamically
allocated structures. Although these tools are similar to
Bandera in that they support the checking of source code,
the research programs for these projects are fairly different since they emphasize support for automatic abstraction
based on counter-example driven predicate abstraction refinement. In contrast, the research program for Bandera has
focused on support checking of highly-dynamic concurrent
object-oriented source code. None of the tools mentioned
above has an emphasis on extensibility nor do they have a
goal of checking a variety of types of software artifacts.
The closest projects to ours are dSpin [13] and JPF [5].
Iosif’s dSpin model checker is a version of Spin extended
with features such as dynamic creation of heap objects and
garbage collection, and support for more features such as
exception handling is under development. The significant
contribution of dSpin is its ground-breaking approach to
canonical heap representation upon which Bogor’s heap representation is based. Customizing dSpin is fairly difficult
since it is built on top of an old non-modular code-base
(the implementation of Spin) and since it takes an indirect
generative approach to model-checker implementation. (i.e.,
given a Promela specification, it produces the C code for a
model-checker dedicated to the given specification). When
using dSpin for checking Cadena models, because it was an
overwhelming challenge to modify the internals of dSpin,
we had to resort to explicitly guarding each transition with
priorities in the model and to adding extra state variables
to hold the priority-based scheduling information. In addition, we had to model the CORBA event-service directly
using dSpin basic constructs instead of hiding portions of the
state in extensions. Using Bogor results in much greater efficiency because we are able to easily customize the scheduling and search modules, and because we introduce abstract
constructs that are specific to CORBA.
JPF was ground-breaking in the area of software modelchecking in that it demonstrated that a model-checker can
be built to work directly on a very semantically rich language
like Java byte-code. JPF is well-designed, and its flexibility
has been demonstrated by the incorporation of a variety of
search modes such as heuristic searches [23, 32]. The direct
support for Java features and the flexibility of JPF has been
a significant source of inspiration for our work on Bogor.
In fact, Willem Visser, the primary developer of JPF was
the person who originally suggested that we should write a
model-checker to work directly on BIR. In some settings, the
fact that JPF works directly on Java byte-code is an advantage: javac implements the translation to the model-checker
input language, and one can claim to some extent that the
code being checked is the code that is actually going to be
run (modulo differences in virtual machines). However, in
many applications that we wish to support, working directly
on byte-codes is a disadvantage. Our goals with Bogor are
to provide an extensible modeling language that can support checking of artifacts at different levels of abstraction.
Thus, Bogor offers a compromise: it supports checking of
Java, and yet, it is flexible enough to be adapted to obtain
dedicated checkers for different families of software artifacts.
6. CONCLUSIONS
As model checking continues to grow in popularity as a
software analysis framework, model checking tools need to
adapt so that they will effectively support a broad range of
system descriptions and property languages. One approach
to overcoming the significant cost of model checking is to
exploit available domain knowledge of specific software artifacts to develop highly-optimized state space representations, reductions and search algorithms. We believe that
Bogor’s extensible, customizable tool architecture will help
minimize the amount of model checking-specific knowledge
that a domain expert will need to build cost-effective analysis capabilities.
We are making Bogor publicly available,1 along with extensive API documentation and examples of plug-ins and
extensions, as a means of catalyzing the use of model checking in the broader software analysis community. Up to date
information on Bogor is available at [33].
7. REFERENCES
[1] R. Alur and M. Yannakakis. Model checking of hierarchical
state machines. In Proceedings of the 6th European
Software Engineering Conference, pages 175–188, Nov.
1998.
[2] T. Ball, R. Majumdar, T. Millstein, and S. Rajamani.
Automatic predicate abstraction of C programs. In
Proceedings of the ACM SIGPLAN ’01 Conference on
Programming Language Design and Implementation
(PLDI-01), pages 203–213, June 2001.
[3] R. Bharadwaj and C. L. Heitmeyer. Model checking
complete requirements specifications using abstraction.
Automated Software Engineering: An International
Journal, 6(1):37–68, Jan. 1999.
[4] D. Bosnacki, D. Dams, and L. Holenderski. Symmetric
spin. In International Journal on Software Tools for
Technology Transfer. Springer-Verlag, 2002.
[5] G. Brat, K. Havelund, S. Park, and W. Visser. Java
PathFinder – a second generation of a Java model-checker.
In Proceedings of the Workshop on Advances in
Verification, July 2000.
[6] T. Bultan, R. Gerber, and C. League. Composite
model-checking: verification with type-specific symbolic
representations. ACM Transactions on Software
Engineering and Methodology, 9(1):3–50, Jan. 2000.
[7] S. Chaki, E. Clarke, A. Groce, S. Jha, and H. Veith.
Modular verification of software components in c. In
Proceedings of the 25th International Conference on
Software Engineering (to appear), 2003.
[8] W. Chan, R. J. Anderson, P. Beame, D. Notkin, D. H.
Jones, and W. E. Warner. Optimizing symbolic model
checking for statecharts. IEEE Transactions on Software
Engineering, 27(2):170–190, 2001.
[9] A. Cimatti, E. Clarke, F. Giunchiglia, and M. Roveri.
NuSMV : a new symbolic model checker. International
Journal on Software Tools for Technology Transfer,
2(4):410–425, 2000.
[10] E. Clarke, O. Grumberg, and D. Peled. Model Checking.
MIT Press, 2000.
[11] J. C. Corbett, M. B. Dwyer, J. Hatcliff, S. Laubach, C. S.
Păsăreanu, Robby, and H. Zheng. Bandera : Extracting
finite-state models from Java source code. In Proceedings of
the 22nd International Conference on Software
Engineering, June 2000.
[12] J. C. Corbett, M. B. Dwyer, J. Hatcliff, and Robby.
Expressing checkable properties of dynamic systems: The
Bandera Specification Language. International Journal on
Software Tools for Technology Transfer, 2002.
[13] C. Demartini, R. Iosif, and R. Sisto. dspin : A dynamic
extension of SPIN. In Theoretical and Applied Aspects of
SPIN Model Checking (LNCS 1680), Sept. 1999.
[14] W. Deng, M. B. Dwyer, J. Hatcliff, G. Jung, Robby, and
G. Singh. Model-checking middleware-based event-driven
real-time embedded software. Technical report, Kansas
State University, 2003. (submitted for publication).
[15] M. B. Dwyer, J. Hatcliff, V. R. Prasad, and Robby. Using
static and dynamic escape analysis to enable model
1
An initial release is scheduled for the Summer of 2003.
[16]
[17]
[18]
[19]
[20]
[21]
[22]
[23]
[24]
[25]
[26]
[27]
[28]
[29]
[30]
[31]
[32]
[33]
reductions in model-checking concurrent object-oriented
programs. Technical report, Kansas State University, 2003.
(submitted for publication).
M. B. Dwyer and V. Wallentine. A framework for parallel
adaptive grid simulations. Concurrency : Practice and
Experience, 9(11):1293–1310, Nov. 1997.
Eclipse Consortium. Eclipse website.
http://www.eclipse.org, 2001.
S. Edelkamp, A. L. Lafuente, and S. Leue. Directed explicit
model checking with hsf-spin. In Model Checking Software,
Proceedings of the 8th International SPIN Workshop,
volume 2057 of Lecture Notes in Computer Science, May
2001.
FormalSystems. FDR2 website. http://www.fsel.com/,
2003.
E. Gamma, R. Helm, R. Johnson, and J. Vlissides. Design
Patterns. Addison-Wesley Pub. Co., 1995.
D. Garlan, S. Khersonsky, and J. S. Kim. Model checking
publish-subscribe systems. In Proceedings of the 10th
International SPIN Workshop on Model Checking of
Software (to appear), May 2003.
P. Godefroid. Model-checking for programming languages
using VeriSoft. In Proceedings of the 24th ACM Symposium
on Principles of Programming Languages (POPL’97),
pages 174–186, Jan. 1997.
A. Groce and W. Visser. Model checking java programs
using structural heuristics. In Proceedings of the
International Symposium on Software Testing and
Analysis, pages 12–21. ACM Press, 2002.
J. Hatcliff, W. Deng, M. Dwyer, G. Jung, and V. Prasad.
Cadena: An integrated development, analysis, and
verification environment for component-based systems. In
Proceedings of the 25th International Conference on
Software Engineering (to appear), 2003.
T. A. Henzinger, R. Jhala, R. Majumdar, and G. Sutre.
Lazy abstraction. In Proceedings of the 29th ACM
Symposium on Principles of Programming Languages,
pages 58–70, Jan. 2002.
G. J. Holzmann. The model checker SPIN. IEEE
Transactions on Software Engineering, 23(5):279–294, May
1997.
G. J. Holzmann. State compression in spin: Recursive
indexing and compression training runs. In Proceedings of
Third International SPIN Workshop, Apr. 1997.
R. Iosif. Symmetry reduction criteria for software model
checking. In Proceedings of Ninth International SPIN
Workshop, volume 2318 of Lecture Notes in Computer
Science, pages 22–41. Springer-Verlag, Apr. 2002.
C. T. Karamanolis, D. Giannakopolou, J. Magee, and S. M.
Wheather. Model checking of workflow schemas. In
Proceedings of the 4th International Enterprise Distributed
Object Computing Conference, pages 170–181, Sept. 2000.
N. Kaveh. Model checking distributed objects design. In
Proceedings of the 23rd International Conference on
Software Engineering, May 2001.
G. Naumovich, G. S. Avrunin, and L. A. Clarke. An
efficient algorithm for computing MHP information for
concurrent java program. In Proceedings of the 7th
European Software Engineering Conference, pages 338–354,
Sept. 1999.
C. S. Păsăreanu, M. B. Dwyer, and W. Visser. Finding
feasible counter-examples when model checking abstracted
Java programs. In Proceedings of the 7th International
Conference on Tools and Algorithms for the Construction
and Analysis of Systems, volume 2031 of Lecture Notes in
Computer Science, Apr. 2001.
Robby, M. B. Dwyer, and J. Hatcliff. Bogor Website.
http://www.cis.ksu.edu/bandera/bogor, 2003.