You are on page 1of 24

Int J Softw Tools Technol Transfer (2011) 13:495–518

DOI 10.1007/s10009-011-0197-7

VMCAI 2009

Finding concurrency-related bugs using random isolation


Nicholas Kidd · Thomas Reps · Julian Dolby ·
Mandana Vaziri

Published online: 23 April 2011


© Springer-Verlag 2011

Abstract This paper concerns automatically verifying program must represent the unbounded number of concrete
safety properties of concurrent programs. In our work, the objects that the concrete program may allocate, and thus
safety property of interest is to check for multi-location data by the pigeon-hole principle some of the abstract objects
races in concurrent Java programs, where a multi-location must be summary objects—they represent more than one
data race arises when a program is supposed to maintain an concrete object. Because abstract summary objects repre-
invariant over multiple data locations, but accesses/updates sent multiple concrete objects, the program analyzer typically
are not protected correctly by locks. The main technical chal- must perform weak updates on the abstract state of a sum-
lenge that we address is how to generate a program model mary object, where a weak update accumulates information.
that retains (at least some of) the synchronization opera- Because weak updates accumulate rather than overwrite, the
tions of the concrete program, when the concrete program analyzer is only able to determine weak judgements on the
uses dynamic memory allocation. Static analysis of pro- abstract state, i.e., that some property possibly holds, and not
grams typically begins with an abstraction step that gen- that it definitely holds. The problem with weak judgements is
erates an abstract program that operates on a finite set of that determining whether an interleaved execution respects
abstract objects. In the presence of dynamic memory allo- program synchronization requires the ability to determine
cation, the finite number of abstract objects of the abstract strong judgements, i.e., that some lock is definitely held,
and thus the analyzer needs to be able to perform strong
updates—an overwrite of the abstract state—to enable strong
Supported by NSF under grants CCF-0540955, CCF-0810053, and judgements. We present the random-isolation abstraction as
CCF-0904371, by ONR under grants N00014-09-1-0510 and
N00014-09-1-0776, by ARL under grant W911NF-09-1-0413, and by
a new principle for enabling strong updates of special abstract
AFRL under grants FA8750-06-C-0249 and FA9550-09-1-0279. objects. The idea is to associate with a program allocation site
two abstract objects, r  and o , where r  is a non-summary
N. Kidd (B) · T. Reps object and o is a summary object. Abstract object r  models a
University of Wisconsin, Madison, WI, USA
distinguished concrete object that is chosen at random in each
e-mail: kidd@cs.wisc.edu; nkidd@purdue.edu
program execution. Because r  is a non-summary object—
T. Reps i.e, it models only one concrete object—strong updates are
GrammaTech, Inc., Ithaca, NY, USA able to be performed on its abstract state. Because which
e-mail: reps@cs.wisc.edu
concrete object r  models is chosen randomly, a proof that a
J. Dolby · M. Vaziri safety property holds for r  generalizes to all objects modeled
IBM T.J. Watson Research Center, Hawthorne, NY, USA by o . We implemented the random isolation abstraction in a
e-mail: dolby@us.ibm.com tool called Empire, which verifies atomic-set serializability
M. Vaziri of concurrent Java programs (atomic-set serializability is
e-mail: mvaziri@us.ibm.com one notion of multi-location data-race freedom). Random
isolation allows Empire to track lock states in ways that
Present Address:
N. Kidd would not otherwise have been possible with conventional
Google Inc., Mountain View, USA approaches.

123
496 N. Kidd et al.

Keywords Random-isolation abstraction · Atomic sets · Listing 1 java.util.Vector snippet.


Model checking · Verification · Pushdown systems · public class Vector {
Atomicity Object[] elementData;
int elementCount;

Vector(Collection c) {
1 Introduction elementCount = c.size();
elementData = new
Object[elementCount * 110 / 100];
This paper concerns automatically verifying safety prop- c.toArray(elementData);
erties of concurrent programs. Although the problem is }
undecidable in general, in some cases undecidability can }
be side-stepped using the following scheme for obtaining
approximate answers:
elementData, where elementData is an array of
objects and elementCount is an integer field whose
– Step 1: Construct an abstraction of the program of interest
value specifies the number of valid components of a
using a modeling language for which safety checking is
Vector object (i.e., the logical contents of a Vector
decidable.
object are elementData[0]–elementData[element
– Step 2: Invoke the decision procedure to determine
Count − 1]).
whether safety holds.
When a shared Vector object is accessed by concur-
– Step 3: If the answer obtained in Step 2 is “yes” (safety
rently executing threads T1 and T2 , it is clearly desirable
holds), report “safe”; otherwise, report “unknown”.
for T1 to not be able to observe intermittent writes of T2 to
the two fields. Without proper synchronization, the invari-
A safety-checking problem may be theoretically intractable
ant that elementCount specifies the logical boundaries
from the standpoint of worst-case running time; however, in
of elementData could be violated. With an unfortunate
many cases answers can be obtained in a reasonable amount
scheduling of thread executions, such a violation could occur
of time by incorporating fast algorithms and data structures
in the Vector constructor shown in Listing 1. In particu-
for key steps of the decision procedure, or for key heuristics
lar, the following interleaved execution would result in the
that it uses. Other work that adopts this approach includes
invariant being violated:
symbolic model checking [8], SLAM [6], Moped [53], Lam-
mich’s work on the analysis of multi-threaded programs [35],
1. T1 begins executing the Vector constructor shown in
and the recent work on analyzing linked lists by [34], among
Listing 1;
others.
2. T1 initializes elementCount to be c.size();
In our work, the safety property of interest is to check for
3. T2 removes all elements from the shared Vector refer-
multi-location data races in concurrent Java programs, where
enced by the parameter Collection c;
a multi-location data race arises when a program is sup-
4. T1 initializes elementData with Collection c as
posed to maintain an invariant over multiple data locations,
modified by T2 .
but accesses/updates are not protected correctly by locks.
(The precise definition of multi-location data races used by
At this point, if c was initially a non-empty collection,
our checking tool Empire is presented in Sect. 2.) Multi-
elementCount will now be non-zero, but the array
location data races generalize the traditional notion of data
elementData will have at each index position from 0
races (i.e., a single-location data race results from inconsis-
to elementCount − 1 the null reference.2
tent coordination of accesses on a single memory location).
Our goal of checking for multi-location data races (such
The importance of checking for multi-location data races is
as the one just described) directly affects the choice of a mod-
underscored by a study conducted by [37], which showed
eling language. Specifically, the modeling language should
that roughly 30% of the concurrency bugs found in a set of
support multiple threads of execution that communicate via
concurrent open-source applications were due to multiple-
shared memory, and that protect shared-memory accesses
memory-location problems. (Our approach can find classical
with locks. However, if we are not careful, the combination
single-location data races as well as multiple-location races.)
of the first two features alone could result in a modeling lan-
An example of a multi-location data race is found in
guage for which safety checking is undecidable [47].
one of the Vector constructors in Sun’s JDK 1.4.2, which
In our work, decidability is maintained by carefully choos-
is illustrated by the code fragment show in Listing 1.1
ing which aspects of a concurrent Java program will be
The class contains two fields elementCount and

1 The snippet is a simplified version of [54, Fig. 2]. 2 The bug was first reported by [57].

123
Finding concurrency-related bugs 497

modeled precisely and which are abstracted away. The prob- the abstract object represents. Strong updates cannot gener-
lems that were necessary for us to address can be summarized ally be performed on summary objects because a (concrete)
as follows: (1) How are data values modeled? (2) How are update only affects one of the summarized concrete objects.
program locks modeled? (3) How are Java’s reentrant locks To be sound, an analyzer has to use weak updates (i.e., it
modeled? (4) What is the algorithm for analyzing the result- has to accumulate lock states). In particular, it has to use an
ing program model? Below we discuss each issue in turn. abstract lock state that represents {locked, unlocked} and such
an approach generally leads to significant loss of precision:
Abstracting values The first insight is that multi-location
an analysis will typically end up showing that a given sum-
data races are concerned with reads from and writes to fields
mary lock is in the state {locked, unlocked}, which provides
of shared objects, and not with the values of those fields.
no information whatsoever.
Thus, a safe approximation abstracts away the values of all
Our second insight, which is the main technical contri-
variables. Once the actual data values have been abstracted
bution of the paper, is a novel abstraction technique called
away, the reads and writes of an individual thread can no
random isolation. The idea that we introduce is to analyze a
longer be affected by the reads and writes of other threads.
transformed version of the program in which a set of user-
Thus, the tight coupling between threads that typically results
specified allocation sites are transformed so that, during each
in analysis of concurrent programs (or program models)
concrete run of the program, at most one object r will be
being undecidable has been removed. As in many program
randomly tagged as being distinguished for that allocation
analyses, the price one pays is that the set of behaviors of the
site. By this means, an analyzer can keep the abstract rep-
program model is necessarily an over-approximation of the
resentative for r (say r  ) separate from a summary object
set of behaviors of the (concrete) program, and hence one-
that represents the rest of the objects allocated at the spec-
sided answers are obtained: safe/possibly unsafe rather than
ified allocation site.3 The advantage of random isolation
safe/definitely unsafe.
is that because r is selected randomly, properties proved
Abstracting locks Once data values have been abstracted about its abstract representative r  can be generalized to all
away, the resulting program contains no synchronization, objects that are potentially allocated at the same allocation
which is obviously not adequate for checking properties that site. Moreover, because each concrete run can have only one
deal with program synchronization. In general, one cannot instance of r , r  is not a summary object, which means that
simply decide to model the “lock state” of every Java object strong updates can be performed on the abstract state of r  —
o—i.e., whether the lock associated with o is in the locked and hence its lock state can be tracked precisely. In practice,
or unlocked state—because Java programs contain dynamic the analyzer will typically require an additional mechanism
memory allocation, which results in an a priori unbounded to ensure that a reference-type variable (e.g., this in Java)
number of locks. To maintain decidability, we require a mech- refers solely to r  , which can be difficult due to aliasing. We
anism that is able to model the unbounded number of con- address this problem via a source-to-source transformation
crete locks—i.e., the set of all locks that are allocated by all that injects expressions that perform a case analysis on what
dynamic concrete runs of the program—with a finite num- the reference variable points to (Sect. 6.1).
ber of abstract locks. Unfortunately, the typical approach of
Reentrant locks Empire checks concurrent Java programs
using summary objects does not provide the precision nec-
that use reentrant locks (obtained via synchronized
essary to reason about lock-based synchronization.
methods and synchronized blocks). Our third insight
For summary-based analyses, an unbounded set of con-
is that when modeling the locking structure of a program,
crete objects are abstracted into a finite set of abstract objects.
one can (in some sense) ignore nested manipulations of the
One common approach is to use the allocation-site abstrac-
same lock. That is, only outermost lock/unlock pairs are truly
tion of [27], where an abstract object o is defined for each
important.
static allocation site of the program (i.e., a new statement in
The straightforward way to encode a reentrant lock is to
Java), and the abstract state of o is a summary of all possi-
model it with a pushdown automaton (context-free language)
ble concrete objects that could be allocated from that site. It
that tracks the number of successive lock acquisitions on
follows from the pigeon-hole principle that there must be at
the stack. Instead, we apply a transformation that replaces
least one abstract object that represents more than one con-
the context-free language that describes a reentrant lock by
crete object.
a regular language that describes a non-reentrant lock. We
The difficulty is that when abstraction techniques summa-
call this transformation language-strength reduction, and it
rize multiple objects into a single summary object, the ana-
lyzer is unable to perform strong updates (overwrites) when 3 Our convention is to use r for a randomly tagged concrete object, o for
interpreting a lock or unlock operation. A strong update of an arbitrary concrete object, and r  resp. o for their abstract counter-
an abstract object corresponds to a “group kill”: it repre- parts. When an allocation-site Site is specified, we use the subscripted
 
sents a definite change in value to all concrete objects that variants rSite , oSite , rSite , and oSite .

123
498 N. Kidd et al.

is performed in a completely accurate way (i.e., the model’s Listing 2 Concurrent Stack program.
behavior is preserved). Language–strength reduction is fur- class Stack { 1
ther discussed in Sect. 8.3. public static final int MAX=10; 2
@atomic(S) Object[] data = new Object[MAX]; 3
Analyzing abstract programs After program transformation @atomic(S) int count = -1; 4
and abstraction, the resultant program model contains a finite 5
@atomic sync Object pop(){ 6
number of threads, shared memory locations, and shared Object res = data[count]; 7
locks. However, one still is left with the task of analyzing such data[count--] = null; 8
a model. The model-checking engine on which Empire was return res; 9
originally based employed a semi-decision procedure [32]. } 10
@atomic sync void push(Object o) { 11
The reason was that with (i) reentrant locks, (ii) an unbounded data[++count] = o; 12
number of context switches, and (iii) an unbounded number } 13
of lock acquisitions, the problem appeared to be undecid- @atomic sync int size() { 14
able. The actions of each process are modeled by a con- return count+1; 15
} 16
text-free language; any model checker for multiple processes @atomic sync replaceTop(Object o) { 17
is dangerously close to the undecidable problem of deter- pop(); 18
mining whether the intersection of two context-free lan- push(o); 19
guages is empty. Surprisingly, after the problem has been } 20
static Stack makeStack() { 21
transformed by the random-isolation and language-strength- return newSite Stack(); 22
reduction transformations, a decision procedure exists for the } 23
resulting simplified problem. } 24
In essence, the couplings between different processes class SafeWrap { 25
@atomic sync Object popwrap(@atomic Stack s) 26
turned out to be sufficiently weak that the undecidability of { return (s.size() > 0) ? s.pop() : null; 27
checking emptiness of the intersection of two context-free } 28
languages did not come into play; however, that fact was static SafeWrap makeSafeWrap() { 29
obfuscated in a non-trivial way in the conditions of the orig- return new SafeWrap(); 30
} 31
inal problem. We return to this discussion in Sect. 8 where 32
an overview of the decision procedure is presented. (A full static void main(String[] args){ 33
description of the decision procedure is available elsewhere Stack stack = Stack.makeStack(); 34
[31].) stack.push(new Integer(1)); 35
new Thread("1") { 36
Summary The above sequence of ideas allowed us to cre- makeSafeWrap().popwrap(stack); 37
ate a tool that (i) can model concurrent Java programs quite } 38
new Thread("2") { 39
faithfully, and (ii) check them for important kinds of con- makeSafeWrap().popwrap(stack); 40
currency problems: both multi-location and single-location } 41
data races. When we compared the performance of the deci- } 42
sion procedure against the earlier semi-decision procedure } 43
(which represented the current state-of-the-art), we found
that the decision procedure was 34 times faster overall (i.e., location data races. Section 6 presents the random-isolation
comparing the sum of the running times on all queries, with abstraction and describes an implementation of it. Section 7
a 300-second timeout). Moreover, with the 300-second time- presents a sound translation from a concurrent Java pro-
out threshold, for each query where the semi-decision pro- gram abstracted using random isolation to an EML pro-
cedure timed out (roughly 49% of the queries), the decision gram. Section 8 describes the model-checking technique used
procedure succeeded within the allotted time. to verify AS-serializability for an EML program. Section 9
Outline The remainder of this paper is organized as fol- presents the experimental evaluation. Section 10 discusses
lows: Sect. 2 provides background material on atomic sets related work.
and AS-serializability, the notion of multi-location data race
used in the paper. Section 3 presents an overview of Empire,
our tool for checking for multi-location and single-location 2 Atomic-set serializability
data races. Section 4 presents EML, the Empire modeling
language. Section 5 motivates the need for a new abstrac- This section presents atomic sets—the mechanism to spec-
tion by discussing how the commonly used allocation-site ify the fields over which an invariant holds—and atomic-set
abstraction [27] is insufficient when checking for multi- serializability—a data-centric correctness criterion that is

123
Finding concurrency-related bugs 499

used to define both single-location and multi-location data use serializability can be obtained by defining all of memory
races. We present both atomic sets and atomic-set serializ- to be in one atomic set.4
ability (AS-serializability) via the example program shown
in Listing 2. (In Listing 2, assume that all methods are pub- Example (AS-serializable) Consider the method
lic. The Java keyword public has been omitted to save Stack.replaceTop, whose body merely invokes the
space. Moreover, the Java keyword synchronized has methods Stack.pop and Stack.push. Each of the three
been abbreviated as sync.) methods are synchronized methods, and the atomic
An atomic set is defined with respect to a Java class C and set with respect to which they must execute atomically
specifies that an invariant holds over a subset of the fields is “S”. Because the methods are synchronized, no other
defined by C. C may define as many atomic sets as fields, thread can access the fields that are members of “S” until
however, each field is allowed to be a member of at most one Stack.replaceTop completes execution. Thus, all exe-
atomic set (i.e., the atomic sets are disjoint). cutions of Stack.replaceTop must be AS-serializable.

Example (Atomic sets) Listing 2 presents a simple Java pro- Atomic sets can be dynamically extended to include the
gram that defines a class Stack that implements a stack atomic sets of method parameters, which are referred to as
data structure using an array Stack.data for storage and unit for parameters. This is specified by an @atomic anno-
an integer Stack.count whose current value is the top-of- tation on a method parameter.5 Dynamic extension of an
stack index into the array Stack.data. (For now, ignore the atomic set captures the fact that if a unit of work is dependent
class SafeWrap.) The annotations @atomic(S) on fields on a method parameter, execution of that unit of work must
Stack.data and Stack.count indicate that those fields (appear to) be atomic for the atomic sets of the parameter as
are members of the atomic set “S”. The (unspecified) invari- well.
ant over data and count is that the current value of count
Example (Unit for parameters) Class SafeWrap does not
is the index of the position in data where the top-of-stack
define an atomic set; however, method popwrap is defined
item is stored. The existence of this relationship is reflected
as a unit of work and parameter Stack s as a unit for param-
by both fields being members of the atomic set “S”.
eter. Thus, popwrap should execute atomically with respect
Associated with atomic sets are units of work; a unit- to the units of work of class Stack, namely the atomic set S.
of-work annotation is a programmer assertion that a method
guarantees to maintain the invariant of an atomic set when 2.1 AS-serializability violations
executed serially (i.e., the unit-of-work is executed to com-
pletion and all other threads wait for it to complete). We call An execution that is not AS-serializable is said to have an
a unit of work that writes to all members of an atomic set a AS-serializability violation. A result from [54] is that if all
write-complete unit of work. units of work are write-complete, then AS-serializability vio-
lations can be completely characterized by a set of fourteen
Example (Units of work) In Listing 2, the units of work problematic access patterns. Table 1 presents the 14 problem-
are methods that have the @atomic annotation (e.g., atic access patterns.6 Each pattern consists of a sequence of
the method Stack.pop). The write-complete units of reads (R) and writes (W ) to an atomic-set member l, or to two
work are the methods Stack.pop, Stack.push, and atomic-set members l1 and l2 . Problematic access patterns
Stack.replaceTop. 1–5 capture single-location data-consistency errors, while
problematic access patterns 6–14 capture multi-location
The correctness criterion associated with atomic sets is data-consistency errors. Each memory access occurs dur-
atomic-set serializability (AS-serializability). AS-serializ- ing a unit of work u; the subscript on the memory access
ability is a generalization of serializability. In general, a denotes which unit of work it belongs to. For example, prob-
code region that should appear to execute atomically forms lematic access pattern 1 is defined as “Ru (l) Wu  (l) Wu (l)”,
a transaction (i.e., represents a logically atomic operation). which describes an AS-serializability violation that involves
An interleaved program execution is then serializable if it is an atomic-set member l. The first read and last write belong
equivalent to an execution in which the transactions are exe- to unit of work u. The intervening write belongs to a unit of
cuted in some serial order. For AS-serializability, the atomic- work u  that is executed by another thread.
code regions (i.e., transactions) are the unit-of-work methods.
An execution is said to be AS-serializable if its projection on 4 Defining serializability in terms of AS-serializability requires the abil-
each atomic set is serializable, where the projection of an ity for atomic sets to span class definitions.
execution with respect to an atomic set S removes all reads 5 Vaziri et al. [54] use the annotation “unitfor” to mark method param-
and writes to memory locations that are not members of S. eters that should be dynamically absorbed into an atomic set.
AS-serializability is a generalization of serializability beca- 6 The patterns in Table 1 appear in [22] and [54].

123
500 N. Kidd et al.

Table 1 14 problematic access patterns


Id Problematic access pattern Description

1 Ru (l) Wu  (l) Wu (l) Value read is stale by the time an update is made in u
2 Ru (l) Wu  (l) Ru (l) Two reads of the same location can yield different values in u
3 Wu (l) Ru  (l) Wu (l) An intermediate state is observed by u 
4 Wu (l) Wu  (l) Ru (l) Value read may not be the same as the one written last in u
5 Wu (l) Wu  (l) Wu (l) Value written by u  can be lost
6 Wu (l1 ) Wu  (l1 ) Wu  (l2 ) Wu (l2 ) Memory can be left in an inconsistent state
7 Wu (l1 ) Wu  (l2 ) Wu  (l1 ) Wu (l2 ) Same as above
8 Wu (l1 ) Wu  (l2 ) Wu (l2 ) Wu  (l1 ) Same as above
9 Wu (l1 ) Ru  (l1 ) Ru  (l2 ) Wu (l2 ) State observed can be inconsistent
10 Wu (l1 ) Ru  (l2 ) Ru  (l1 ) Wu (l2 ) Same as above
11 Ru (l1 ) Wu  (l1 ) Wu  (l2 ) Ru (l2 ) Same as above
12 Ru (l1 ) Wu  (l2 ) Wu  (l1 ) Ru (l2 ) Same as above
13 Ru (l1 ) Wu  (l2 ) Ru (l2 ) Wu  (l1 ) Same as above
14 Wu (l1 ) Ru  (l2 ) Wu (l2 ) Ru  (l1 ) Same as above
Patterns 1–5 involve a single memory location; patterns 6–14 involve a pair of memory locations

To give a concrete illustration of an AS-serializability have been written to synchronize on the parameter Stack s.
violation, let us return to the program in Listing 2. The Thus, the interleaved execution shown in Fig. 1 is valid.
method Stack.pop performs no safety checking. That The interleaved execution shown in Fig. 1 contains prob-
is, Stack.pop does not verify that the stack is non- lematic access pattern 12. The data accesses that are involved
empty before attempting to remove the top-of-stack item. in the pattern are underlined in Fig. 1. Because of the
If Stack.pop is invoked on an empty stack, then the AS-serializability violation, the method SafeWrap.pop
field Stack.count will be −1. The array access to wrap can raise an ArrayIndexOutOfBounds
the field Stack.data will result in an ArrayIndex Exception even when it is invoked on a non-empty stack.
OutOfBoundsException being raised because The interleaved execution shown in Fig. 1 illustrates how
Stack.count has the value −1. that can happen. Initially, the stack contains one item. Thread
The class SafeWrap defined below Stack in List- T1 begins execution and checks that the stack is non-empty
ing 2 addresses this oversight by defining the method by invoking Stack.size. The check succeeds, and so
SafeWrap.popwrap, which first checks that the param- T1 ’s next action is to invoke Stack.pop. Before doing
eter Stack s is not empty before invoking the method so, thread T2 successfully executes SafeWrap.popwrap,
Stack.pop. For the class SafeWrap, the method which removes the item from the stack, leaving it empty.
SafeWrap.popwrap is a unit of work, indicated by the When T1 resumes execution, it invokes Stack.pop on an
@atomic annotation on the method, and the parame- empty stack, which raises an exception. The point at which
ter “Stack s” is a unitfor parameter, indicated by the the exception is raised is denoted by the symbol  at the end
@atomic annotation on parameter s. (Note that the of thread T1 ’s execution sequence.
@atomic annotation provides a specification of the desired
behavior, and not an implementation of it.) Recall that the
atomic sets of a unitfor parameter are dynamically incorpo- 3 E MPIRE
rated into the atomic sets of the invoking object, i.e., the this
parameter, for the duration of a unit of work. Because class Empire is a tool to verify that errors such as the one described
SafeWrap does not define any atomic sets, the atomic set at the end of Sect. 2 do not occur in a concurrent Java program
with respect to which SafeWrap.popwrap must execute Prog. Empire returns answers of the form “the problematic
atomically is the atomic set S defined by class Stack. access pattern p is definitely not present” or “the problem-
Unfortunately, the attempt to “harden” the code by adding atic access pattern p may be present”, where p is an integer
error checking has introduced an AS-serializability violation. in the range 1–14 that specifies the particular problematic
The problem is that the program synchronizes on the wrong access pattern of interest (cf. Table 1). Empire uses abstrac-
object. In this case, the method SafeWrap.popwrap has tion to generate an abstract program Prog such that the set of
the synchronized annotation, whereas the method should behaviors of Prog is a sound over-approximation of the set

123
Finding concurrency-related bugs 501

Fig. 1 An interleaved execution of thread T1 and T2 that contains an work. The subscripts “1” and “2” are thread ids. “(s ” and “)s ” denote
AS-serializability violation. R and W denote a read and write access, the acquire and release operations, respectively, of the lock of Stack s
respectively. c and d denote fields count and data, respectively. that is the input parameter to SafeWrap.popwrap
“[” and “]” denote the beginning and end, respectively, of a unit of

of behaviors of Prog. The challenge is to define a finite-data SLocks ; and (iii) a finite number of concurrently executing
abstraction such that Prog is able to disallow certain thread processes SProcs .
interleavings by modeling the synchronization of Prog’s pro-
Memory An EML shared-memory location m is an abstract
cesses, and yet analysis of Prog remains decidable. These
memory location: abstract reads and writes can be made on m;
two properties are closely intertwined: if the program model
however, EML does not have a notion of a value held by m.
becomes more precise it likely implies that a more powerful
The lack of values stored at shared-memory locations is
decision procedure will be required.
an artifact of Empire’s goal of verifying AS-serializability,
The Empire toolchain is shown in Fig. 2. The input to
which is a property of the order of interleaved reads and
Empire is a concurrent Java program Prog along with a set
writes of an application, and not of the values read and writ-
of user-specified allocation sites. The allocation sites direct
ten. Moreover, abstracting away values is required to ensure
Empire to (attempt to) verify that all executions are AS-
that the analysis of an EML program remains decidable.
serializable with respect to the objects that can be allocated
from those sites. We will generally refer to a specified allo- Locks An EML lock is reentrant, meaning that the lock can be
cation site by Site. reacquired by the EML process that currently owns the lock,
and also that the lock must be released the same number of
Example (Specified allocation site) In Listing 2, the alloca- times as it was acquired to become free. EML restricts the
tion site of interest is signified by the subscripted newSite acquisition and release of an EML lock to occur within the
statement on line 22. body of a function, i.e., an EML lock cannot be acquired in a
function f and released in another function f  . In addition,
Empire’s abstraction process proceeds in two stages. First, the acquisition of multiple EML locks by an EML process
a source-to-source program transformation (abbreviated as must be properly nested: an EML process must release a set
“Src-to-Src” in Fig. 2) bootstraps the implementation of the of held locks in the order opposite to their acquisition order.
random-isolation abstraction. Second, the transformed pro- The two restrictions are naturally fulfilled when EML is used
gram is abstracted via random-isolation abstraction (“RIA” to model synchronized methods and blocks of a Java thread.7
in Fig. 2) to generate an EML program. From one EML pro- An EML lock l can begin in an “unallocated” state and will
gram, multiple queries are generated for the Ipamc model remain unallocated until an EML process makes a transition
checker that implements our decision procedure. The input on an edge alloc l (see Table 2). Lock allocation is used to sig-
to Ipamc is a multi-pushdown system and an indexed phase nify whether or not the randomly isolated object that is asso-
automaton that specifies the safety property. We defer the ciated with l has been allocated. In Sect. 6.1, which discusses
definitions of these last two entities until Sect. 8. the implementation of random-isolation, alloc lSiteRi is used
Before getting to random isolation, we begin by defining to implement (in EML) the setting of the global flag FSiteRi .
the Empire Modeling Language (EML). Defining EML first EML does not have “objects” and object allocation does not
serves to motivate the need for a new abstraction technique. occur—there is a finite set of shared memory locations SMem .

7 Java programs that use the synchronization primitives provided by the


java.util.concurrent library need not satisfy the restriction that
4 EML lock usage is properly nested. To analyze such programs, one would
need to bypass EML and generate an Ipamc query (Sect. 8) directly—
the caveat being that any results obtained from analyzing an Ipamc
An EML program EProg consists of (i) a finite set of shared- query that does not use properly nested locks is meaningless because
memory locations SMem ; (ii) a finite set of reentrant locks the input query lies outside the domain of allowable queries.

123
502 N. Kidd et al.

IPA
Multi-PDS IPAMC

...

...
IPA

eml2pds
SAFE/
Prog Src-to-Src Prog' RIA EML Multi-PDS IPAMC UNSAFE?

...

...
IPA
Multi-PDS IPAMC

Fig. 2 The Empire toolchain. “EML” stands for Empire Mod- system (Sect. 8); “IPA” stands for indexed-phase automaton
eling Language (Sect. 4); “RIA” stands for random-isolation (Sect. 8); and “IPAMC” is our model checker for multi-PDSs
abstraction (Sect. 6); “Multi-PDS” stands for multi-pushdown [31]

Table 2 The edge labels Labels of an EML flow graph that represents having multiple outgoing edges from the same node. (EML
an EML function and their corresponding semantics programs have only non-deterministic branches.) The label
Labels Semantics a ∈ Labels represents a semantic action that the EML pro-
cess performs when transferring control from node n to node
call f Invoke function f
n  . EML supports the labels listed in Table 2.
read m Read from memory location m ∈ SMem
An edge labeled “start Proc” starts the EML process
write m Write to memory location m ∈ SMem named Proc. This is used to model the fact that when a
alloc l Allocate the EML lock l ∈ SLocks Java program begins, only one thread is executing its main
lock l Acquire the EML lock l ∈ SLocks method, and all other threads cannot begin execution until
unlock l Release the EML lock l ∈ SLocks they have been started by an already executing thread.
unit begin Begin a unit of work The design of EML is strictly motivated by the desire to
unit end End a unit of work detect AS-serializability violations, and thus we do not give
start Proc Start EML process Proc a formal specification of its semantics. Instead, the meaning
skip A statement whose semantic action is not modeled of an EML program is defined by its translation into a set
of Ipamc queries. In some sense, Ipamc is a virtual machine
for running an EML program and monitoring its behavior
The choice of the word alloc reflects the fact that, in the with respect to indexed phase automata (IPAs, which will be
concrete Java program, a randomly isolated object needs to defined in Sect. 8.1). The translation from EML to a multi-
be allocated before its lock can be acquired. Moreover, it PDS (Sect. 8) is viewed as compilation, and IPAs for the
can be allocated at most one time. To summarize, alloc l is set of fourteen problematic access patterns define a language
a semantic action in the EML program; it denotes that the of disallowed program behaviors. An EML program is com-
EML execution models a path in the concrete Java program piled into a multi-PDS, and, in effect, the decision procedure
that allocates a randomly isolated (concrete) object. implemented by Ipamc exhaustively runs the EML program
on all possible inputs and checks whether any of the runs is in
Processes An EML process Proc is defined by a set of (pos- the language of problematic access paths. We defer discus-
sibly) recursive functions, one of which is designated as the sion of the details of this process until Sect. 8, and explain in
main function of the process. An EML function f is defined Sects. 5–7 how an EML program is generated. Ipamc itself
by a labeled-flow graph G f . A labeled-flow graph is a tuple is structured as a tool for checking an EML program with
G f = (Nodes f , Labels, Edges f , n entry , n exit ), where: respect to an arbitrary IPA, and hence could be applied to
problems other than detecting AS-serializability violations.
– Nodes f is a set of nodes;
– Labels is defined with respect to the set of memory loca-
tions SMem and set of locks SLocks as shown in Table 2; 5 The allocation-site abstraction
– Edges f ⊆ Nodes f × Labels × Nodes f is a set of
edges; n entry ∈ Nodes f is the distinct entry node; and The definition of EML in Sect. 4 makes explicit the con-
– n exit ∈ Nodes f is the distinct exit node. straints that the result of program abstraction should satisfy:
there must be a finite number of shared memory locations, a
An edge e = (n, a, n  ) ∈ Edges f models the flow of control finite number of threads, and a finite number of reentrant
from node n to node n  . Non-determinism is introduced by locks that are acquired and released in a properly nested

123
Finding concurrency-related bugs 503

   
fashion. A concurrent Java program, however, will typically Listing 2, the abstract objects o22 , o30 , o35 , and o37 each
only satisfy the requirement that locks are acquired and represent a singleton set because the program only executes
released in a properly nested fashion (synchronized meth- the associated allocation statement once (as discussed above).

ods naturally satisfy this requirement).8 However, the abstract object o30 represents two concrete
To address the incompatibilities between a concrete Java objects because the method SafeWrap.makeSafeWrap
program and EML, we use program abstraction, and, in par- is invoked twice, once by threads T1 and T2 , respectively.
ticular, the random-isolation abstraction. Before presenting
the random-isolation abstraction, we motivate the need for For the allocation-site abstraction to be sound, an anal-
a new abstraction by first discussing why the allocation-site ysis generally has to perform weak updates on each sum-
abstraction [27]—a commonly used technique for model- mary object. That is, information for the summary object
ing the unbounded set of dynamically allocated concrete must be accumulated rather than overwritten. In contrast,
objects with a finite set of abstract objects—is unsatisfac- a strong update—the alternative to a weak update—over-
tory. Specifically, we highlight the allocation-site abstrac- writes an abstract object’s abstract state. Such an over-
tion’s limitations when analyzing a concurrent program write corresponds to a “group kill” when the abstract
that uses an unbounded number of dynamically allocated object is a summary object. Thus, a strong update of the
locks. Intuitively, the reason why locks pose such a prob- abstract state generally can only be performed when the
lem is that modeling synchronization in the abstract program analysis can prove that there is at most one object allo-
requires definite (must) information—i.e., information that cated at Site, i.e., |Conc(Site)| = 1. For the program
an abstract lock, and hence all concrete locks represented by in Listing 2, strong updates could be performed on all
 
the abstract lock, is definitely in the locked state. When using abstract objects except o30 because abstract object o30 rep-
the allocation-site abstraction, an analysis typically only has resents two concrete SafeWrap objects. Note that an in-
indefinite (may) information available. We make these con- terprocedural analysis would be required to determine that

cepts more concrete in the following discussion. the abstract object o22 —the abstract object representing
Given an allocation site Site for class T , let Conc(Site) objects allocated by the Stack.makeStack method—rep-

denote the set of all concrete objects of class T that can resents a singleton set. The problem is that o22 is used
be allocated at Site. The allocation-site abstraction uses a to allocate all Stack objects, and thus an interprocedur-

single abstract object oSite to summarize all of the concrete al analysis would be required to prove that the method
objects in Conc(Site). When the size of Conc(Site), denoted Stack.makeStack is invoked exactly one time for all

by |Conc(Site)|, is greater than 1, the abstract object oSite executions of the program. Because of this difficulty, analy-
is referred to as a summary object. Thus, for each field f ses that make use of the allocation-site abstraction typically

defined by T , field oSite . f is a summary field for the set of resort to the assumption that every abstract object is a sum-
fields {o. f | o ∈ Conc(Site)}. Because the program has mary object.
a finite number of program points, and each class defines a An AS-serializability violation is defined in terms of
finite number of fields, this results in a finite-data abstraction. reads and writes to the fields of the T object allocated
at a specified allocation site Site. Thus, to detect an
Example (Allocation-site abstraction) There are five allo-
AS-serializability violation, Empire must track reads and
cation sites in Listing 2: line 22 allocates a Stack object;
writes to these fields. In Listing 2, the allocation site of inter-
line 30 allocates a SafeWrap object; line 35 allocates an
est is on line 22. This is denoted by the subscripted newSite
Integer object; and lines 37 and 40 allocate Thread
statement. The allocation-site abstraction is a sound over-
objects T1 and T2 , respectively. All allocation sites except
approximation for modeling reads and writes because a read
the one on line 30 are executed exactly one time for all exe- 
from (write to) the abstract field oSite . f corresponds to a
cutions of the program shown in Listing 2. The allocation site
possible read from (write to) o. f , for one concrete object
on line 30 allocates two concrete objects because the method
o in Conc(Site). For the progam shown in Listing 2, the
SafeWrap.makeSafeWrap is invoked once by thread T1
reads and writes of interest are to the fields Stack.data
and once by thread T2 .
and Stack.count. The @atomic(S) annotation on the
The allocation-site abstraction would define the five
     two fields specifies that each field is a member of the atomic
abstract objects o22 , o30 , o35 , o37 , and o40 , where abstract

set S.
object oi represents all concrete objects that could be allo- Checking for AS-serializability violations also requires
cated at the allocation site on line i. For the program in Empire to model program synchronization. If Empire did
8
not model synchronization operations, it would likely be use-
We assume that an analyzed Java program is restricted to use
less because the number of abstract executions would grossly
synchronized methods and blocks and not other synchronization
mechanisms. In particular, the non-syntactically restricted locks pro- over-approximate the number of valid concrete executions,
vided by the java.util.concurrent package are not used. which would typically result in a large number of false

123
504 N. Kidd et al.

positives. Modeling Prog’s synchronization is accomplished 6 Random-isolation abstraction


by defining EML locks. There are two possibilities for defin-
ing the semantics of an EML lock: To address the deficiencies of using the allocation-site
abstraction, we developed a new abstraction technique,
1. The first possibility is to interpret a lock acquire as a random-isolation, which is a novel extension of allocation-
strong update, i.e., the program has definitely acquired site abstraction. The random-isolation abstraction is moti-
a particular lock. This would correspond to acquiring vated by the following observation:
the locks of all possible instances in Conc(Site), which
Observation 1 The concrete objects that can be allocated
in most circumstances—including the one here—would
at a given allocation site Site, Conc(Site), cannot be distin-
be unsound. In the example of Listing 2, this interpreta-
guished by the allocation-site abstraction.
tion of locking combined with the allocation-site abstrac-
tion would preclude the interleaved program execution Observation 1 states that if one chooses to isolate a ran-
shown in Fig. 1 that contains the bug, because the two dom concrete object rSite from Conc(Site), the allocation-
SafeWrap objects would effectively get the same lock, site abstraction would not be able to distinguish the randomly
and the two SafeWrap.popwrap methods would exe- chosen concrete object from any of the other concrete objects

cute without interleaving. that are represented by oSite .
2. The second possibility for defining the semantics of EML The random-isolation abstraction leverages Observation 1
locks is to interpret a lock acquire as a weak update, i.e., by randomly isolating one of the concrete objects allo-
the program may have acquired a particular lock. A weak cated at allocation site Site and tracking it specially in
update would leave the lock in a “possibly held” state. the abstraction. Whereas allocation-site abstraction would

When an EML process Proc attempts to acquire a lock use one summary object oSite to represent all concrete
that is in the “possibly held” state, two cases must be objects Conc(Site) that can be allocated at Site, ran-

considered. dom isolation uses two objects: one summary, oSite , and
 
(a) The lock is actually held by another EML process one non-summary, rSite . The object rSite is a non-sum-
Proc and thus Proc must block until Proc releases mary object because it alone represents the randomly iso-

the lock. lated concrete object rSite . Because rSite is a non-sum-
(b) The lock is not held by another EML process Proc mary object, it is safe to perform strong updates to its
and thus Proc may acquire the lock. (abstract) state, which gives us Random-isolation principle
1.
This semantics is sound because all possible cases are
considered. However, the overall effect of this semantics Random-isolation principle 1 (Updates) Let rSite ∈ Conc
is, in essence, equivalent to an EML program without (Site) be a randomly isolated concrete object. Because rSite

locks because the program can never reason definitively is modeled by a special abstract object rSite , the random-
whether or not a lock is actually held. That is, in the isolation abstraction enables an analysis to perform strong

abstract program a thread is always able to acquire a updates on the abstract state of rSite .
lock, which in essence means that the abstract program
operates as if there are no synchronization constraints. In Random isolation also provides a powerful methodol-
general, this possibility would greatly increase the num- ogy for proving properties of a program, which is captured
ber of false positives. For instance, in the example of by following Proofs Principle. In plain English, to estab-
Listing 2, if we were to fix the code by adding an addi- lish that a universally quantified safety property φ holds
tional synchronization block on the parameter Stack s for all objects oSite ∈ Conc(Site), it suffices to estab-
inside the body of SafeWrap.popwrap, the analysis lish the property for only the randomly isolated object r ∈
would still report a bug because locking behavior was Conc(Site).
modeled imprecisely. Random-isolation principle 2 (Proofs) Given allocation
site Site and safety property φ over concrete objects, to
In summary, neither of the two possible semantics for establish that ∀o : Conc(Site).φ(o) holds, it is sufficient
locks with the allocation-site abstraction is satisfactory: the to establish that the augmented formula ∀o : Conc(Site).
first leads to an unsound analysis and the second leads to is_ri(o) → φ(o) holds, where the predicate is_ri is true for
an analysis that would be useless in practice. Thus, a new the randomly isolated object (allocated at site Site).
abstraction mechanism is required, one that is sound, but
allows strong updates to be performed on at least some of Proof The proof is by contradiction. Let Prog be a (concrete)
the abstract locks (so that the analysis can (partially) reason concurrent program, Prog be an (abstract) concurrent pro-
about program synchronization). gram obtained via the random-isolation abstraction, where

123
Finding concurrency-related bugs 505

the set of behaviors of Prog over-approximates the set of 2. Formula ψ3 is reinterpreted in the abstraction:
behaviors of Prog, i.e., Prog is a sound abstraction of Prog.
  
Consider the case where the abstract program analyzer— ψ3 = ∀x  ∈ {rSite , oSite } . ¬is_ri(x  ) ∨ φ(x  ).
i.e., the software model checker—has verified that φ holds
for the randomly isolated object in Prog , and also that The universal quantification is now over the two abstract
there exists a concrete trace where for some object oSite ∈ objects defined by the abstract program.10
Conc(Site), φ(oSite ) does not hold. Because of random iso- 3. Model checker Ipamc is used to check if there exists an
lation, the randomly isolated object rSite is just as likely to be execution of the abstract program Prog that satisfies the
oSite as it is to be any other concrete object. Thus, the model negation of the formula. If Ipamc reports that no such

checker must consider the case that rSite is oSite . Because the execution exists, then the original formula ψ3 holds. The
 
property holds for rSite , and because rSite represents oSite negation is defined as:
in the trace under consideration, then the property must also
  
hold for oSite , which is a contradiction under the above listed ¬ψ3 = ∃x  ∈ {rSite , oSite } . is_ri(x  ) ∧ ¬φ(x  ).
assumptions. 


To use Ipamc to determine if an execution satisfies ¬ψ3 ,
Random-isolation principle 2 is crucial for applying soft-
Empire must actually make fourteen separate queries.
ware model checking to the analysis of concurrent programs.
The reason being that the negated formula, ¬φ(x  ),
In particular, it allows the model checker to consider only
is precisely defined by the fourteen problematic access
finite-data abstract programs yet still be able to prove safety
patterns listed in Table 1.
properties of infinite-data concrete programs.9 (Sect. 10
discusses related techiques for proving safety properties of
The motivation for random isolation is to allow strong
infinite-data programs.)
updates on the abstract lock of an abstract object, where a
Random isolation in Empire Before describing the technical
strong update corresponds to a definite lock acquire or def-
details of how random isolation is implemented, we highlight
inite lock release. Strong updates are enabled in EML by
the benefits of random isolation as used in Empire.
defining an EML lock for each non-summary object. Because
Empire attempts to establish that all executions of a con-
of random isolation, the state of the Java lock that is associ-
current Java program Prog are AS-serializable with respect
ated with the randomly isolated instance rSite can be mod-
to the objects allocated at a user-specified allocation site Site. 
eled precisely by the state of the special abstract object rSite .
Formally, let φ(oSite ) be a formula stating that an execution
That is, the acquiring and releasing of the lock for rSite by a
is AS-serializable with respect to the concrete object oSite .
thread of execution can be modeled by a strong update on the
Empire’s goal is then to establish that for all executions, 
state of rSite , thus allowing the analyzer to disallow certain
thread interleavings when performing state-space explora-
ψ1 = ∀x ∈ Conc(Site) . φ(x). tion on the generated EML program, and thereby improving
the precision of the analysis.
Applying random-isolation abstraction allows us, via Ran- In contrast, because sound tracking of the lock state for a
dom Isolation Principle 2, to change the goal to that of summary object generally would result in the “possibly held”
establishing the property: state, EML programs have no locks for summary objects:
their modeled behaviors are not restricted by synchronization
ψ2 = ∀x ∈ Conc(Site) . is_ri(x) → φ(x). primitives. This approach provides a sound, finite model of
the locking behavior of Prog . (It is an over-approximation
Eliminating the implication, we rewrite ψ2 as follows: because the absence of locks on summary objects can cause
the abstract program to have thread interleavings not found
ψ3 = ∀x : Conc(Site) . ¬is_ri(x) ∨ φ(x). in the concrete Java program.)

Finally, to establish ψ3 via a software model checker, we 6.1 Implementing random isolation
perform the following steps:
Random isolation can be implemented via a source-to-
source transformation of the concrete Java program. For
1. An abstract program Prog is generated via the random-
isolation abstraction. 
10 The concrete and abstract formulas, ψ3 resp. ψ3 , are related via the
Embedding Theorem [50]. The reader is referred to [23, Lemma 1 and
9 We say finite-data and not finite-state because each thread has an Theorem 1] for correctness proofs in the context of three-valued logic
unbounded-sized stack, giving rise to an infinite-state space. and universal quantification in abstractions of logical structures.

123
506 N. Kidd et al.

expository purposes, we break down the discussion of the of a new allocation site in the program’s source code causes
source-to-source transformation into three separate rewriting the allocation-site abstraction to have an additional abstract
steps and a step in which the abstract program is generated: object. In essence, our implementation of the random-isola-
tion abstraction extends the allocation-site abstraction with
1. Random tagging The first transformation produces a special semantics to abstract objects that correspond to the
residual program that for any execution of the original newly introduced allocation sites—namely, the allocation-
program Prog, at most one concrete object is randomly site abstraction is extended with the knowledge that the cor-
chosen to be tagged as special, i.e., at most one concrete responding abstract objects are non-summary objects.
object r is randomly isolated. Concretely, let us consider the random-tagging transfor-
2. Synchronized-method elimination The second transfor- mation in the context of the example program in Listing 2,
mation makes explicit the synchronization operation where the allocation site of interest is on line 22 and is
for a Java synchronized method. Recall that a repeated below for convenience.
synchronized method implicitly acquires the lock return newSite Stack(); (1)
associated with the implicit this parameter. This trans-
formation makes the synchronization explicit by erasing The random-tagging transformation involves transforming
synchronized from method declarations and intro- the newSite statement into
ducing their semantically equivalent synchronized
(rand() && FSiteRi .compareAndSet(false, true))
blocks.
3. Synchronized-block case analysis Finally, synchronized ? newSiteRi Stack() : newSite Stack();
blocks are the only source of lock and unlock operations. (2)
When analyzing the program model, the lock-state of
Site Site from code fragment (1) is transformed into a condi-
a lock can generally only be determined precisely for
tional-allocation site, where the conditional performs a com-
randomly isolated objects, i.e., those introduced by the
pareAndSet of a newly introduced global flag FSiteRi .11
first transformation above. However, due to aliasing it
The global flag FSiteRi can be set to true at most once, thus
might not be possible to determine statically whether a
ensuring that at most one concrete object rSite can ever be
reference uniquely refers to a randomly isolated object
allocated at the generated site SiteRi. That is, FSiteRi guar-
or not. The final transformation introduces case-analy-
antees that |Conc(SiteRi)| ≤ 1 for all possible executions
sis expressions to determine whether an object reference
of the program; consequently, the size of the set that is the
ref in a Java expression “synchronized(ref){...}” 
concretization of rSite must also be less than or equal to one.
solely refers to a randomly isolated object or not.
The observant reader might be concerned that an
4. Defining the abstract program After the source-to-source
AS-serializability violation could occur on an object allo-
transformation steps, an abstract program Prog is gen-
cated from Site that is not tagged. For example, an execu-
erated from the transformed concrete Java program
tion that contains an AS-serializability violation but never
Prog.
allocates an object from the fresh allocation site SiteRi
would satisfy this criteria. Fortunately, this is not a problem
We now discuss each transformation step in turn. To assist because our analysis considers all executions of the abstract
the reader, the transformation steps are illustrated for the program. The following corollary makes formal why such
example program shown in Listing 2. executions—those where the fresh allocation site is never
Random tagging As explained above, the purpose of the executed—need not be considered:
first source-to-source transformation is to modify the pro- Corollary 1 For performing AS-serializability violation
gram so that at most one concrete object is randomly tagged detection, we only have to be concerned with executions in
on any given run of a program. Because we do not wish to which rSite is eventually allocated.
modify class definitions (e.g., by instrumenting each class to
have an additional “tag” field), our approach to random tag- Proof The claimed property is a consequence of the use of
ging is to (i) generate a fresh allocation site; and (ii) ensure randomness in code fragment 2. If there were a trace in which
that at most one object can be allocated from the fresh allo-
cation site for any given run of the program. Thus, random 11 b.compareAndSet(expect,update) is supported by class
tagging corresponds to being allocated from the new allo- java.util.concurrent.atomic.AtomicBoolean. It atomi-
cation site. An additional benefit of this transformation is cally sets Boolean value b to update if the current value of b is the
expected value expect. It is important to use an atomic operation in the
that it plays nicely with the allocation-site abstraction, the
test in (2); if FSiteRi were not set atomically, the source-to-source trans-
basis for the random-isolation abstraction. Specifically, by formation would introduce a race condition that would allow multiple
definition of the allocation-site abstraction, the introduction objects to be allocated at the newly introduced allocation site SiteRi.

123
Finding concurrency-related bugs 507

rSite was not allocated but the trace did in fact contain an The size method could be invoked on either the randomly
AS-serializability violation, then because of the use of ran- tagged object rSiteRi or an object allocated from the origi-
domness, there must exist a similar trace in which the rSite nal allocation site oSite . When analyzing the program under
object was allocated and the violation occurred on that object. random-isolation semantics, the analysis can generally only

That is, the need to only consider traces in which rSite is prove that the abstract object rSiteRi corresponding to the ran-
(eventually) allocated is a corollary of Random-isolation domly tagged object rSiteRi is a non-summary object. Thus,
principle 2. All such traces have the property that the global locking operations, which constitute strong updates to the

flag FSiteRi must eventually be set to true (see ¬ψ3 in item abstract state of a lock object, can generally only be per-
3 on page 505). 
 formed on the object referred to by a Java reference if the
analysis can prove that the reference only refers to a ran-
Synchronized-method elimination We now discuss the sec- domly tagged object. In points-to analysis terms, where the
ond transformation, which makes explicit all lock acquisi- set of abstract objects that a reference (e.g, this) may point
tions and releases in the Java program Prog. It is desirable to is denoted by Pts(this), acquiring and releasing a lock
to have explicit locking operations because the analysis is generally only possible when the analysis can prove that

requires the ability to distinguish between locking opera- Pts(this) = {rSiteRi }.
tions performed on randomly tagged objects—i.e., concrete Our final transformation embeds a case analysis that
objects whose abstract counterpart is guaranteed to be a enables such a distinction to be made. The key observation is

non-summary object—versus all other objects. Making the that the desired case—that Pts(this) = {rSiteRi }—can be
locking operations explicit allows uniform treatment of the precisely checked for dynamically. Specifically, the dynamic
case analysis, which is the subject of the third transforma- check tests whether or not the reference refers to the ran-
tion. Because this transformation is trivial, we describe it by domly tagged (concrete) object rSiteRi . We call the checking
example. method is_ri because it is a test whether a reference is a
Consider the method Stack.size() in Listing 2, reference to a randomly isolated object. The concrete seman-
repeated below for convenience: tics of is_ri is as follows:

@atomic sync int size() { return count + 1; } is_ri(t) =def FSiteRi ∧ t = rSiteRi

The lock associated with the this object is implicitly The final transformation for a synchronized block on ref-
acquired when size() is invoked, and released upon return. erence t is as follows:
To make the acquisition and release explicit, the method is //is_ri(t) = tr ue implies Pts(t) = {rSiteRi }
transformed as follows:
if (is_ri(t)) { sync(t) { body } }
@atomic int size() { sync(this) { return count + 1; }} //is_ri(t) = f alse implies Pts(t)  rSiteRi
else { sync(t) { body } }
Observe that the synchronized keyword has been removed
from the method declaration, and the entire body of the
method has been enclosed in a synchronized block that Observe that the true and false branches of the is_ri test
acquires the lock associated with the (implicit) this param- perform the same concrete actions. This is crucial because
eter. (For static synchronized methods, i.e., for synchronized the transformation must not alter the concrete semantics of
class methods, the this parameter to the synchronized the program. That is, one should view is_ri as performing
block is replaced with the name of the Java class in which a metadata test, where the metadata of interest is whether or
the method declaration occurs.) not the referred to object has been randomly tagged. Dur-
Synchronized-block case analysis The last transformation ing EML generation (discussed in Sect. 7), the metadata test
performs a case analysis on the points-to information asso- determines whether or not the generated EML program will
ciated with the reference parameter to a synchronized block. contain an action that changes the state of an abstract lock.
Consider the body of the transformed size method just During points-to analysis, the interpretation of the call
described: on is_ri performs a case analysis on Pts(t). Specifically,
the abstract interpretation of is_ri performs the abstract
sync(this) { return count + 1; } 
test “FSiteRi ∧ t = rSiteRi ”, which is just the correspond-
in the context of the program with a transformed allocation ing abstract semantics of the concrete semantics of is_ri
site as described in the Random-Tagging transformation. given above. We extend the points-to analysis to interpret
the is_ri method call as follows: when following the true
(rand() && testAndSet(FSiteRi )) branch of the condition, the points-to analysis performs an

? newSiteRi Stack() : newSite Stack(); “assume Pts(t) = {rSiteRi }”; and when following the false

123
508 N. Kidd et al.

branch of the condition, the points-to analysis performs an of any analysis that must reason about an unbounded

“assume Pts(t) = Pts(t) \ {rSiteRi }”. set of indistinguishable objects, especially analyses that
already use the allocation-site abstraction. Moreover,
Remark 2 The final transformation can be avoided, i.e., the
random isolation is particularly effective when an anal-
transformation that implements a case analysis via is_ri,
 ysis needs the ability to perform strong updates on the
when the analysis can already prove that Pts(t) = {rSiteRi }.
abstract state of an object.
Such a property can often be established by means of an
3. Even though the transformations have been presented
object-sensitive interprocedural control-flow graph (ICFG).
in the context of AS-serializability violation detection,
For readers familiar with object-sensitive analysis in the style
random isolation is a generic approach that can be applied
of [40], and its corresponding object-sensitive call graph, 
wherever an analysis needs to distinguish between rSiteRi
the technique we use is similar to [40]. Briefly, an object- 
sensitive call graph CG models the interprocedural control and oSite to perform a strong update. In particular, the
flow of a program, qualified by the identities of the receiver splitting of allocation sites to distinguish a random indi-
objects of methods: there is a node in CG for each method vidual and the injection of case-analysis expressions to
of the program for each context—i.e., each abstract object isolate the actions performed on that individual has appli-
that can act as the receiver of the invocation—in which it can cations outside of AS-serializability violation detection.
be invoked [40]. An object-sensitive points-to analysis asso-
ciates points-to facts with the nodes of CG, thus computing
different points-to facts for different object contexts of the 7 EML generation
same method. Because these two analysis artifacts are object-
sensitive, their respective dataflow facts make a distinction Once the abstract program Prog has been generated from
between objects allocated at SiteRi and objects allocated at a concurrent Java program Prog, the next step in Empire is
Site. For example, referring back to the program in Listing 2, to generate an EML program EProg. We now discuss the
there would be two copies of the control-flow graph (CFG) EML-generation process.
 
for the method Stack.size, one for object context oSite To model the randomly isolated abstract object rSite ,
 EProg defines a shared memory location m f for each field
and one for object context rSiteRi . Thus, inside of the CFG
 f of the class T , and also an EML lock lSiteRi to model
for Stack.size with object context rSiteRi , an analysis is 
the lock associated with rSite . The status of the global flag
able to take advantage of the fact that the special Java this
 FSiteRi is modeled by the EML lock lSiteRi being allocated
variable refers solely to the non-summary object rSiteRi .
or not. As shown in Sect. 6.1 (see Corollary 1), we are only
concerned with executions in which lSiteRi is eventually allo-
Defining the abstract program After the source-to-source
cated. Hence we need only be concerned with traces of the
transformations have been performed, the resulting program
EML program in which “alloc lSiteRi ” appears somewhere.
is ready for abstraction; the corresponding abstract program
Let Threads be the set of all subclasses of java.lang.
Prog will operate over a set of abstract objects consisting of
 Thread. For each θ ∈ Threads, and for each allocation site
oSite for each allocation site Site in the program (including

Siteθ that allocates an instance of θ , EProg defines an EML
the special abstract object rSiteRi for the generated allocation process ProcSiteθ that models the behavior of one instance
site SiteRi). Because threads in Java are objects themselves, of θ that is allocated at Siteθ . Also, EProg defines an EML
Prog now has a finite number of abstract threads, where process Procmain that models the Java thread that begins
each thread is associated with an allocation site. (We can, of execution of the main method.
course, generate multiple copies of each thread as needed. The functions of an EML process Proc correspond one-to-
That is, the number of threads is actually a parameter of one with the methods of the Java program, i.e., for each Java
Prog .) method m there is an EML function f m . The labeled-flow
graph G fm is defined from the control-flow graph CFGm that
6.2 Summary is associated with m.12 The control-flow graph CFGm con-
sists of a set of Java statements Stmts, a successor relation
We conclude with three points about random isolation and Succ ⊆ Stmts×Stmts, and has distinct entry and exit state-
its implementation via source-to-source transformations: ments. The translation from CFGm to G fm is straightforward.
There is a node n stmt ∈ Nodes fm for each stmt ∈ Stmts.
1. Observe that if the randomly isolated abstract object There is a labeled edge (n stmt , astmt , n stmt ) for each pair of
 
rSiteRi is folded into the summary object oSite , then the
abstraction reduces to the allocation-site abstraction. 12 When using an object-sensitive analysis as discussed in Remark 2,
2. From the above observation, we can conclude that ran- there will be multiple labeled-flow graphs for a Java method m, one for
dom isolation can be used to improve the precision each object context in which it could be invoked.

123
Finding concurrency-related bugs 509

Table 3 Java statement types


for CFGm , their corresponding stmt astmt Condition
EML labels, and the condition
o.m() call m
necessary to generate the EML

label entry unitbegin this= rSite , CFGm is a unit of work

exit unitend this= rSite , CFGm is a unit of work

x = o.f, x = o.f[i] read m f rSite ∈ Pts(o)

o.f = x, o.f[i] = x write m f rSite ∈ Pts(o)
newSiteRi T alloc lr 
Site

The final row is a catch all for monitorenter o lock lr  Pts(o) = {rSite }
Site

the Java statements that are monitorexit o unlock lr  Pts(o) = {rSite }
Site
either not modeled in EML or 
that do not satisfy the listed o.start() start ProcSiteθ oSite ∈ Pts(o)
θ
condition * skip

statements (stmt, stmt ) ∈ Succ. The label astmt models the Table 4 The encoding of a call graph’s and CFG’s edges as PDS rules
execution of the Java statement stmt. Table 3 shows the label Rule Control flow modeled
astmt that is generated for a Java statement stmt. Note that
s1
(i) synchronized blocks have been compiled down to the  p, n 1  −→  p, n 2  Intraprocedural edge n 1 → n 2
lower-level Java bytecode statements monitorenter and sc
 p, n c  −→  p, e f rc  Call to f , with entry e f ,
monitorexit; (ii) label generation must know if a method from n c that returns to rc
is a unit of work; and (iii) a read or write access to the con- sf
tents of array field f of T is treated as a read or write access  p, x f  −→  p,  Return from f at exit x f
to the field f .13 The action a denotes the abstract behavior of executing that edge

8 Verifying AS-serializability of EML programs


it is performed with respect to an individual EML process
An EML program has a set of shared-memory locations, Proc. In total, Empire generates O(|SProcs |∗14∗(|SMem |2 ))
SMem , a set of EML locks, SLocks , and a set of EML pro- queries for an EML program.
cesses, SProcs . To verify AS-serializability of an EML pro- A generated query  consists of a (i) pushdown sys-
gram, Empire generates a number of queries that are then tem (PDS) for each EML process (Sect. 8.2), and (ii) an
answered by Ipamc [31,33]—a model checker for multi- indexed phase automaton (IPA)—a restricted kind of non-
PDSs with reentrant locks, whose decision procedure can deterministic finite automaton (NFA)—that recognizes EML
answer the types of queries required by Empire. execution traces containing an AS-serializability violation
involving one or two memory locations (Sect. 8.4). The
Remark 3 Even though many analyses for multi-PDSs are remainder of this section proceeds as follows: Sect. 8.1 for-
undecidable [28] showed that property checking for cer- mally defines PDSs, multi-PDSs, and IPAs; Sect. 8.2 defines
tain fragments of temporal logic is decidable. For a detailed the translation from an EML process to a PDS; Sect. 8.3
account of the decision procedure of [31] and the character- describes how Ipamc handles reentrant locks; and Sect. 8.4
istics of the problem that render it decidable, the reader is defines the IPA for an atomic-set/problematic-access-pattern
referred to [29]. pair.

A query is generated for each pair (m, m  ) ∈ SMem ×SMem


for the fourteen interleaving scenarios. Pairs are used because 8.1 Definitions
the interleaving scenarios are defined in terms of at most
two locations from an atomic set (cf. Table 1). Moreover, A pushdown system (PDS) naturally models the interpro-
AS-serializability violation detection is asymmetric in that cedural control flow of an EML process (see Table 4).
In essence, a PDS is an NFA equipped with a stack. The
13 control states of the NFA portion of a PDS models the global
Our decision to treat an array and its contents as one field is not
strictly necessary. Using a more-refined analysis that can reason about state of an EML process, while the stack is used to ensure
arrays [13,21,50], a more precise model could be generated. that only interprocedurally valid paths are modeled.

123
510 N. Kidd et al.

Definition 1 A pushdown system (PDS) is a tuple P = reacquired by the PDS that owns the lock. In particular, two
(P, , Lab, , c0 ), where P is a finite set of control loca- global configurations g and g  are in the relation , denoted
tions; is a finite set of stack symbols; Lab is a finite set of by g  g  , iff g = (c1 , . . . , c j , . . . , cn , ō) and one of the
labels (or actions); ⊆ (P × ) × Lab × (P × ∗ ) is a following holds:
finite set of labeled-transition rules, where a rule is denoted
a
by r =  p, γ  −→  p  , u  ; and c0 =  p0 , γ0  is the
→ cj , a ∈ , and g  = (c1 . . . , cj , . . . , cn , ō).
a
initial configuration of P. A configuration c of P is a pair 1. c j −
a (
 p ∈ P, u ∈ ∗ . For a rule r =  p, γ  −→  p  , u  , we 2. c j −
→i
cj , ō[i] = (⊥, 0),
use lab(r ) to denote r ’s label a. Without loss of generality, we and g = (c1 , . . . , cj , . . . , cn , ō[i → ( j, 1)]).

restrict there to be at most two right-hand-side stack symbols (
3. c j −
→i
cj , ō[i] = ( j, z),
of a rule. A rule with zero, one, and two right-hand-side stack
symbols is called a pop, step, and push rule, respectively. and g = (c1 , . . . , cj , . . . , cn , ō[i → ( j, z + 1)]).


)
4. c j −
→i
cj , ō[i] = ( j, z), z > 1,
A concurrent program that synchronizes via locks, i.e., and g = (c1 , . . . , cj , . . . , cn , ō[i → ( j, z − 1)]).

an EML program, is modeled by a multi-PDS. Informally, a )
multi-PDS consists of a finite set of PDSs and a finite set 5. c j −
→i
cj , ō[i] = ( j, 1),
of locks. The intention is that each PDS models a thread, and g  = (c1 , . . . , cj , . . . , cn , ō[i → (⊥, 0)]).
and that the PDSs acquire and release locks to perform
global synchronization. We assume that locks are acquired
and released in a well-nested fashion—locks are released in The reflexive transitive closure of  is denoted by g ∗
the opposite order in which they are acquired—and in syn- g  . A multi-PDS execution π is a finite sequence steps
chrony with a PDS’s push and pop rules. In fact, the latter g0  g1  · · ·  gk . The word w assocated with π is
assumption is all that is necessary as it implies the former. the sequence of actions from —locking operations are not
exposed—that correspond to each transition step by item 1
Definition 2 A multi-PDS consists of a finite number of above.
PDSs P1 , . . . , Pn , where each PDS P j = (P j , j , Lab j ,
j
j , c0 ), that synchronize via a finite set of locks SLocks =
Given a multi-PDS, Ipamc is a model checker that deter-
{l1 , . . . , l|SLocks | }. The actions Lab of each PDS consist of
mines whether there exists an interleaved execution π of a
lock-acquires (“(i ”) and releases (“)i ”) for 1 ≤ i ≤ |SLocks |,
multi-PDS such that the word w associated with π is recog-
plus symbols from , a finite alphabet of non-parenthesis
nized by an indexed phase automaton (IPA).
symbols. A global configuration (c1 , . . . , cn , ō) is a tuple
consisting of:
Definition 4 An indexed phase automaton (IPA) is a tuple
– a local configuration c j for each PDS Pi , 1 ≤ j ≤ n; (Q, Id, , δ), where Q is a finite, totally ordered set of states
and {q1 , . . . , q|Q| }, Id is a finite set of thread identifiers, is a
– an ownership array ō of length |SLocks |, in which each finite alphabet, and δ ⊆ Q × Id × × Q is a transition rela-
entry indicates the owner of a given lock: for each 1 ≤ tion. The transition relation δ is restricted to respect the order
i ≤ |SLocks |, ō[i] ∈ ({⊥, 1, . . . , n} × N ) is a pair where on states: for each transition (qx , i, a, q y ) ∈ δ, either y = x
the first component indicates the identity j of the PDS or y = x + 1. We call a transition of the form (qx , i, a, qx+1 )
P j that holds lock li (⊥ signifies that li is currently not a phase transition. The initial state is q1 , and the final state
held by any PDS), and the second component is a non- is q|Q| .
negative number that indicates the number of times that
a PDS has (re)acquired a lock. The restriction on δ in Definition 4 ensures that the only
loops in an IPA are self-loops on states, which is crucial for
The initial global configuration g0 = (c01 , . . . , c0n , ō0 ), where keeping the checking problem decidable [29]. We assume
c0i is the initial configuration of PDS Pi , 1 ≤ i ≤ n, and ō0 that for every x, 1 ≤ x < |Q|, there is only one phase transi-
is the initial ownership array that maps each entry ō[i], 1 ≤ tion of the form (qx , i, a, qx+1 ) ∈ δ. (An IPA that has multiple
i ≤ |SLocks |, to the ownership pair (⊥, 0). For an ownership such transitions can be factored into a set of IPAs, each of
array ō, an update at position i for lock li to a new ownership which satisfy this property.) Finally, we only consider IPAs
pair p is denoted by ō[i → p]. that recognize a non-empty language, which means that an
IPA must have exactly (|Q| − 1) phase transitions, i.e., any
Definition 3 For multi-PDS  = (P1 , . . . , Pn , SLocks , ), accepting run of an IPA will contain only a bounded number
the Reentrant Semantics allows for a lock l ∈ SLocks to be of phase transitions.

123
Finding concurrency-related bugs 511

8.2 Modeling an EML process Formally, PDS P2 = (P2 , Lab2 , 2, 2 , ∅, emain ),
where
We now discuss the generation of a PDS for an EML process
Proc. For expository purposes, we break the translation into – P2 = 2 SLocks : a control location is a set of flags s denot-
two steps. ing which locks have been allocated. The set of control
locations P1 is not used because it is the singleton set { p}.
– Step 1: a PDS P1 is generated that models the interpro- – Lab2 = Lab1 ∪ {P  .alloc l | P  ∈ (SProcs \ {Proc}), l ∈
cedural control flow of Proc. In this stage, all locking SLocks }: Lab2 is Lab1 augmented to include actions that
operations—i.e., inter-process communication—are not allow for P2 to guess when another EML process Proc
modeled by P1 . allocates a lock.
– Step 2: from PDS P1 a PDS P2 is generated that accounts – 2 = 1 ∪ {guess}: 2 includes the stack symbol guess
for locking operations and thus implements the necessary that implements the guessing procedure.
interprocess communication that restricts the set of allow- – 2 is defined from 1 as shown in Table 5. Row 2 ensures
able schedules. that no lock is allocated more than once; row 3 ensures
that a lock is not used before being allocated; and rows
4 and 5 ensure that the shared-memory locations are not
Step 1: The first step is straightforward: a single-state 
accessed before rSite has been allocated. Row 6 defines
PDS P1 = (P1 = { p}, Lab1 , 1 , 1 ,  p, emain ) is gen-
rules that invoke the “guessing” procedure for each con-
erated using the rule templates depicted in Table 4, with
figuration of P2 . Guessing is necessary because an EML
Lab1 being the set of all distinct EML statements used by
process cannot know when another EML process allo-
Proc prefixed with the EML process’s name. For example, if
cates a lock. Row 7 defines rules that implement the guess-
the EML statement is “read m” and the EML process’s name
ing procedure: from control location s, s ⊆ SLocks , guess
is Proc, then Lab1 will contain “Proc.read m”. Including
that EML process P  ∈ (SProcs \ {P}) allocates a lock
the EML process’s name in the PDS action enables the vio-
l ∈ (SLocks \s), and return back to the caller in the control
lation monitor and locks to know which EML process per-
location s ∪ {l}. The guessing rule is then labeled with
forms an action (cf. the PDS rules for an EML lock above).
action P  .alloc l.
P1 captures the interprocedural control flow of Proc. There
is one exception, the EML statement “start ProcSiteθ ” does
The multi-PDS that models an EML program then has,
not include Proc as a prefix because a thread can be started
for each EML process, a PDS P defined as just described,
by any other thread (but only started one time).
and the set of locks is merely the set of locks SLocks of the
EML program.
Step 2: PDS P2 is PDS P1 augmented to account for
lock allocation. (Recall that a lock must be allocated before it 8.3 Modeling an EML Lock
can be used.) The set of control locations P1 of P1 is expanded
to include a boolean flag for each lock l. If the flag is true The translation from an EML lock to a multi-PDS lock that
then l has been allocated, otherwise an EML process has yet is used by Ipamc is straightforward: there is a one-to-one
to allocate l. correspondence between EML locks and the set of multi-
From Proc’s point of view, there are two ways that a lock PDS locks. The use of the notation SLocks to represent both
can be allocated: either Proc allocates a lock or another EML the set of EML locks and multi-PDS locks emphasizes this
process Proc allocates the lock. If Proc allocates the lock l, correspondence.
Proc.alloc l
then there will be a PDS rule of the form  p, γ  −→ We next briefly describe how Ipamc replaces reentrant
 p  , u. The corresponding rule in PDS P2 ’s rule set 2 locks with non-reentrant locks via a transformation called
must ensure that the control location on the left-hand-side language-strength reduction [30]. The transformation relies
has the flag for l set to false, and the control location on on the fact that lock acquisitions and releases are synchro-
the right-hand-side has the flag for l set to true. Otherwise nized with a PDS’s stack. Briefly, the technique involves
Proc allocates l. In this case, Proc has no way of knowing transforming a PDS so that it pushes a special marker onto
when Proc allocates l, and therefore must guess when the the stack the first time a lock is acquired, and also records
allocation occurred. Guessing is modeled by non-determin- the fact that the PDS acquired the lock in the PDS’s state
istically invoking the guess method, which simply guesses space. All subsequent lock acquisitions and and their match-
that another EML process allocates l. Because of non-deter- ing releases do not change the state of the PDS. When the
minism, the guess method causes Proc to consider all pos- special marker is seen again on the stack, the PDS is about
sibilities of lock allocation (i.e., the cross product of SProcs to execute the matching release for the initial lock acquisi-
and SLocks ). tion, and thus actually release the lock. In essence, for PDS

123
512 N. Kidd et al.

Table 5 Each row defines a set a


of PDS rules in 2 from a rule Action a Rule  p, γ  −→  p, w ∈ 1
in 1
a
τ , start P  { s, γ  −→ s, w | s ∈ 2 SLocks }
The control location p from a P.a
alloc l { s, γ  −→ s ∪ {l}, w |s∈ 2 SLocks ∧l ∈
/s }
rule in 1 is not repeated
P.a
because all rules in 1 are lock/unlock l { s, γ  −→ s, w |s∈ 2 SLocks ∧l ∈ s }
single-control-location rules. P.a
The condition for generating a read/write m { s, γ  −→ s, w | s ∈ 2 SLocks ∧ lSiteRi ∈ s }
rule reflects that certain actions P.a
can only occur when a lock has ubegin/uend { s, γ  −→ s, w | s ∈ 2 SLocks ∧ lSiteRi ∈ s }
τ
been allocated, e.g., acquiring a  { s, γ  −→ s, guess γ  |s∈ 2 SLocks }
lock l can only occur after l has
P  .alloc l
been allocated (see Sect. 8.2)  { s, guess −→ s ∪ {l},  |s∈ 2 SLocks ∧l ∈
/s∧ P ∈ (SProcs \ {P}) }

→ cj , a ∈
a
P = (P, Lab, , , c0 ), the transformation defines a new 1. c j − / { (i , )i },
PDS P  = (P  , Lab,  ,  , c0 ), where and g  = (c1 . . . , cj , . . . , cn , ō).
(
2. c j −
→i
cj , ō[i] = ⊥,
– P  = P × 2 SLocks , where a member ( p, s) of P  includes and g  = (c1 , . . . , cj , . . . , cn , ō[i → j]).
the original control state p of P and a set s that records )
3. c j −
→i
cj , ō[i] = j,
the set of locks that P  currently holds.
 = and g = (c1 , . . . , cj , . . . , cn , ō[i → ⊥]).

– ∪ ( × SLocks ) consists of the original stack
alphabet , and, in addition, a new set of symbols that
enables P  to record on the stack the first time that a lock Note that items 1,2, and 3 correspond to items 1,2, and 5 of
l ∈ SLocks has been acquired. the Reentrant Semantics. The word w that for an execution
–  contains, for each rule r ∈ , a set of rules that main- π is defined the same as in the Reentrant Semantics.
tain and update the set of held locks s for a control state
( p, s), and record on the stack via a symbol (γ , l) that a 8.4 Violation monitor
lock has been acquired for the first time. The exact def-
inition of  is beyond the scope of this paper, and we The IPA Amon acts as a violation monitor that detects when
refer the reader to [30] for further details. one of the problematic access patterns occurs during a unit
– c0 = ( p0 , ∅), γ0  is the initial configuration paired with of work for a specific EML process Proc. To do so, it must
∅ to indicate that P  does not hold any locks. track (i) the reads and writes to the shared-memory locations
SMem by each EML process, and (ii) whether or not the target
EML process Proc is executing a unit of work.
After transforming P to be P  , all nested lock acquisi- Tracking the reads and writes of EML processes requires
tions and releases have been removed. Hence, we can refine only a finite amount of state, i.e., state to track which reads
the Reentrant Semantics to disallow configurations where and writes of interest have been seen. Recall that units of work
an ownership array ō contains at position i for lock li an are reentrant because unit-of-work methods may be recur-
ownership pair ( j, z) such that z > 1, which gives the sive or invoke other unit-of-work methods. Thus, tracking
Non-Reentrant Semantics. To distinguish between the Non- the unit-of-work status of Proc requires an infinite amount
Reentrant and Reentrant Semantics, we will use j and ⊥ to of state. Fortunately, the stack of the PDS for Proc is
denote the ownership pair ( j, 1) and (⊥, 0), respectively. The infinite-state, and the language-strength-reduction transfor-
shorthand is sound because there can be no ambiguity, i.e., mation [30] can be used to fuse the unit-of-work depth count
( j, z) where z > 1 is not allowed. Moreover, to distinguish with the PDS stack. The transformation is analogous to the
the Non-Reentrant Semantics, we will use − →instead of  to one discussed in Sect. 8.3. After applying the transforma-
denote the transition relation between global configurations. tion, tracking the unit-of-work status for Proc requires only
a finite amount of state, namely a Boolean flag, and thus track-
Definition 5 The Non-Reentrant Semantics of a multi-PDS ing both the reads and writes of interest and the unit-of-work
C P is defined by a transition relation − →on global configura- status of Proc can be performed by an IPA Amon .
tions. Two global configurations g and g  are in − →, denoted The IPA Amon accepts interleaved executions (traces) that
by g −→g  , iff g = (c1 , . . . , c j , . . . , cn , ō) and one of the contain the memory accesses specified by the problematic
following holds: access pattern of interest. To make the discussion more

123
Finding concurrency-related bugs 513

Fig. 3 The NFA A12 that recognizes traces of interleaved read and field Stack.data. The symbols [ and ] denote Proc beginning and
write memory accesses containing problematic access pattern 12 for ending a unit of work, respectively. denotes the input alphabet of
the program shown in Listing 2. The edge labeled alloc denotes allo- A12 , and  is defined as \ {]}. Once A12 guesses that a violation
cating the randomly isolated object. An edge labeled R1 (c) (W2 (c)) will occur by making a transition to state q3 , it must observe a violation
denotes a read from (write to) the field Stack.count by thread T1 before the unit-of-work end symbol “]” appears in a trace. Otherwise,
(T2 ). Similarly, edges labeled R1 (d) and W2 (d) denote accesses to the it will become stuck in a state q3−6

concrete, we focus on the IPA A12 shown in Fig. 3, which Otherwise, Ipamc returns false, and the EML program does
tracks the problematic access pattern “R1 (c); W2 (d); W2 (c); not have an AS-serializability violation for the given scenario
R1 (d)” for the AS-serializability violation from the program defined over a single or double-memory location for scenar-
shown in Listing 2. For a generic problematic access pattern ios 1–5 and 6–14, respectively, and the target EML process
p, the definition of the NFA Amon that recognizes traces Proc.
containing p follows naturally.
Figure 3 gives a graphical depiction of A12 . The initial
state is q1 and the final state is q7 . For a trace to be accepted
9 Experiments
by A12 , it must make a transition through each state q1–7 . That
is, the states q1–7 track the memory accesses that make up
Empire is implemented using the WALA [25] program-
problematic access pattern 12. The transition (q1 , alloc, q2 )
analysis framework. Random isolation is implemented using
models the allocation of the randomly isolated object. Once
WALA’s facilities for rewriting the abstract-syntax tree
the randomly isolated object has been allocated, A12 ignores
(AST) of a Java program. The default object-sensitive call
reads and writes by following the self-loop on state q2 until
graph construction and points-to analyses are modified to
the target EML process Proc begins a unit of work—mod-
implement the semantic reinterpretation of “is_ri”, as
eled by the transition (q2 , [, q3 ).
described in Sect. 6.1. After rewriting the ASTs, Empire
A12 makes use of non-determinism. For each state qi ,
emits an EML program from the input Java program.
3 ≤ i ≤ 6, there is a self-loop labeled with [Ri Wi . The sym-
The EML program is then translated into multiple multi-
bol [ models reentrant calls to units of work. The state does
PDS/IPA pairs, for which reachability queries are answered
not change because Proc must be executing a unit of work
using Ipamc [31,33]. All experiments were run on a dual-
for A12 to be in state qi . The symbols Ri and Wi denote read
core 3 GHz Pentium Xeon processor with 4 GB of memory.
and write accesses to any memory location by either thread.
The goal of the experiments was to determine whether
The use of non-determinism enables A12 to “guess” which
the techniques developed and implemented in Empire could
memory accesses are actually involved in problematic access
detect both single- and multi-location AS-serializability vio-
pattern 12. For example, if A12 is in state q3 and observes the
lations. We evaluated Empire on eight programs from the
action R1 (c), it can make a transition to state q4 —-the action
ConTest suite [15], which is a set of small benchmarks with
is part of problematic access pattern 12—or it can follow the
known concurrency bugs. Empire requires that the alloca-
self-loop and remain in state q3 —the action is not part of
tion site of interest be annotated in the source program. We
problematic access pattern 12. Non-determinism is required
annotated eleven of the twenty-seven programs that Con-
because a thread may perform multiple memory accesses
Test documentation identifies as having “non-atomic” bugs.
during a unit of work.
Our front-end currently handles eight of the eleven (the AST
rewriting currently does not support certain Java constructs).
8.5 Queries When analyzing a program with the user-specified alloca-
tion site Site that allocates an object of type T , we used the
Once a multi-PDS  and IPA Amon have been generated default assumptions that (i) all fields declared by T are in
for an EML program EProg, a query is given to the model one atomic set, and (ii) each public method defined by T is
checker Ipamc to determine if an interleaved execution of  a unit of work.
is recognized by Amon . If Ipamc returns true, meaning that To reduce the size of the generated models, we made minor
there is an interleaved execution of  recognized by Amon , modifications to the benchmark programs. For the programs
then the EML program has an AS-serializability violation. analyzed, file I/O is used to output debugging and scheduling

123
514 N. Kidd et al.

information, and to receive input that specifies the number of Table 7 presents a breakdown of the problematic-access-
threads. We removed these operations, and manually unrolled pattern numbers of the AS-serializability violations that
loops that allocate Thread objects 2 times. When a bench- were found for each benchmark program. For 7 of the 8
mark used a shared object of type java.lang.Object benchmarks listed in Table 7, Empire found multiple actual
as a lock, the type was changed to java.lang.Integer AS-serializability violations (indicated by ⊗), where by
because our implementation uses selective object-sensitivity, actual AS-serializability violation we mean a true AS-
for which the use of java.lang.Object as a shared lock serializability violation in the concrete concurrent Java pro-
removes all selectivity and severely degrades performance.14 gram listed. The false positives (denoted by ) reported for
The programs SoftwareVerificationHW and shop PingPong are due to an over-approximation of a thread’s
define each thread’s run() method to consist of a loop that control flow—exceptional-control-flow paths are allowed in
repeatedly executes one unit of work. For these programs, the model that cannot occur during a real execution of the
the code in the body of the loop was extracted out into its program. Table 7 entries marked by “?” indicate problematic
own method so that the default unit-of-work assumptions access patterns for which there is an AS-serializability vio-
would be correct. Each modification had no impact on the lation in the EML program, but has not been verified in the
AS-serializability violations that could occur in a benchmark. original Java program.16
The difficulty in automating these transformations is deter- Overall, the experiments show that Empire is able to
mining programmer intent. For example, removing debug- detect both single-and multi-location AS-serializability vio-
ging output is easy for an analyst who can use comments, lations. It is interesting to note that for benchmarks where a
variable names, and generated output to determine that cer- multi-location AS-serializability violation was found, a sin-
tain output statements are not relevant to program correct- gle-location AS-serializability violation also occurred. This
ness. The use of Java annotations to decorate such statements can be explained by the fact that Java methods typically read
would greatly simplify that task. That is, given annotations and write to a field multiple times, which allows for both sin-
such as @debug or @lock on program statements and gle- and multi-location AS-serializability violations to occur.
fields, respectively, manual transformations would no longer
be necessary.
In total, Empire generated 4583 Ipamc queries. Each 10 Related work
query was analyzed using a 300-second timeout, and com-
pleted successfully within that threshold. Table 6 presents a Strong updates on an isolated non-summary object The idea
summary of the analysis results. The dividing line that sep- of identifying non-summary objects so that strong updates
arates the first four benchmarks from the latter four bench- can be performed on them has a long history in shape-analy-
marks pertains to lock usage. Each generated EML program sis algorithms. Originally, some non-summary objects could
consists of a single lock, namely, the lock for the randomly be identified as a fortuitous byproduct of the abstraction
isolated object.15 However, for the first four benchmarks, the in use. For instance, with approaches based on k-limiting
code does not contain synchronized methods, and hence does [24,26] non-summary nodes are maintained along selector-
not acquire and release the lock associated with the randomly edge paths of length ≤ k from program variables. The shape
isolated object. For the latter four benchmarks, the code con- abstraction of Chase et al. [11] tracked which node merges
tains synchronized methods, and the generated EML pro- in an abstract memory configuration preserved the property
grams for these four contain lock and unlock operations. In that the resulting abstract node represents a single concrete
total, Empire: node in each store that the abstract memory configuration
represents.
1. found 212 (possible) AS-serializability violations (col. Plevyak et al. [44] introduced the idea of deliberately iso-
“# Violations Found”); and lating a non-summary node that represents only the memory
2. determined that 4371 queries did not contain an location that will be updated during a transition. They called
AS-serializability violation (col. “# Queries Verified”). this operation deconstruction. Deconstruction has turned out
to be essential, both for developing analyses that are tolerant

14 By selective object-sensitivity, we mean that a full object-sensitive 16 Due to a limitation of our implementation in not producing witness
call graph is not constructed because doing so exhausts memory traces for failed queries (sometimes called “counterexamples”), we are
resources. Instead, the call graph is only object sensitive with respect not able to check whether the AS-serializability violations found using
to a few key object types: the type T of the specified allocation site, the Ipamc but not by our previous approach [32] using the model checker
types of all of T ’s fields, and the type of all subclasses of threads. Cpdsmc [10] are actual bugs or false positives. The lack of witness
15 Empire can generate multi-lock EML programs when the Java pro- traces is not a fundamental limitation of the approach used in Ipamc,
gram makes use of global locks that are guaranteed to be unique, such just of our current implementation; in principle, it is possible to extend
as the lock that is associated with a Class object. Ipamc to produce witness traces.

123
Finding concurrency-related bugs 515

Table 6 For each benchmark, column “# Queries” gives the number of queries that were generated (i.e., the number of IPAs generated for a
benchmark’s model )
Benchmark Number of queries Number of violations found Number of queries verified

Account 642 38 604


AirlineTickets 900 18 882
PingPong 384 35 349
ProducerConsumer 512 72 440
SoftwareVerification HW 15 6 9
BugTester 615 0 615
BuggyProgram 615 16 599
Shop 900 27 873
Totals 4,583 212 4,371
Columns “# Violations Found” and “# Queries Verified” give the breakdown of query satisfaction (i.e., an execution of  is and is not, respectively,
recognized by a generated IPA). The horizontal line after row 4 separates the benchmarks that did not contain any synchronization operations after
abstraction from those that still did contain synchronization operations

Table 7 Marked entries denote


violations reported by Empire, Program 1 2 3 4 5 6 7 8 9 10 11 12 13 14
with ⊗ being a true positive; 
Account ⊗ ⊗ ? ⊗ ⊗ ? ? ?
a false positive; and ? being a
reported violation that we have AirlineTickets ⊗ ⊗ ⊗ ⊗ ⊗ ⊗ ? ? ?
not determined whether or not it PingPong ⊗ ⊗ ⊗ ⊗         
is a true positive
ProducerConsumer ⊗ ⊗ ⊗ ⊗ ⊗ ? ? ? ? ? ⊗ ⊗ ⊗ ?
SoftwareVerification HW ? ? ? ?
BugTester
BuggyProgram ⊗ ⊗ ⊗ ⊗ ⊗
Scenarios 6–16 involve two
memory locations Shop ⊗ ⊗ ? ? ? ? ? ? ⊗ ? ? ?

of temporary violations of data-structure invariants, as well deconstruction in terms of logic, and showed that the essence
as for developing analyses that are capable of synthesizing of deconstruction involves a step, called focus, which forces
data-structure invariants while analyzing loops that traverse the values of certain formulas (e.g., one that specifies which
linked data structures. Ordinarily, deconstruction is used to memory location will be updated during a transition) from
isolate the current node m being operated on, which is often an indefinite value (unknown) to a definite value (true or
the only node that does not satisfy some node-centric prop- false). Focus is a semantic reduction [12]: it has the effect
erty ϕ(n) that holds for all other nodes n i of the data struc- of converting an abstract memory configuration into one
ture (often a local connectivity property, but sometimes a or more abstract memory configurations that are more pre-
non-local reachability property). Once “surgery” has been cise than the original one. Moreover, the approach taken by
completed on node m to establish ϕ(m), the loop moves on Sagiv et al. [50] provided the ability to apply deconstruction
to another node, and m is often folded into an existing sum- in every abstraction specifiable using their parametric frame-
mary node—and thus ϕ(·) continues to hold for all concrete work for shape analysis (which is implemented in the TVLA
nodes represented by the summary node. By this means, the system [36]).
fixed-point-finding loop of an abstract-interpretation solver Gopan et al. [19,20] also used the idea of working with a
can perform what amounts to an inductive argument that the non-summary element so that strong updates could be per-
loop (re-)establishes ϕ(·) throughout the data structure. formed, and showed how it could be applied to the analysis
The work of Plevyak et al. [44], and related work by Sagiv of programs that manipulate arrays.
et al. [49], exploited deconstruction in analyses tailored for Work in the type-theory community that uses similar ideas
specific data structures—doubly linked lists in the case of includes that of Walker and Morrisett [55], Foster et al. [18],
Plevyak et al., and singly linked lists in the case of Sagiv Fahndrich and DeLine [16], Aiken et al. [2], Ahmed et al.
et al. Later work by Sagiv et al. [50] gave an account of [1], and Rondon et al. [48].

123
516 N. Kidd et al.

When the analysis methods discussed above also employ Detection of concurrency-related bugs. Traditional work
the allocation-site abstraction [27], each abstract memory on error detection for concurrent programs has focused on
configuration will have some bounded number of abstract classical data races. Static approaches for detecting data
nodes per allocation site. races include type systems, where the programmer indicates
Like random-isolation abstraction, recency abstraction proper synchronization via type annotations (e.g., [7]), model
[5] uses no more than two abstract blocks per alloca- checking (e.g., [46]), and static analysis (e.g., [42]). Dynamic
tion site Site: a non-summary block MRAB[Site], which analyses for detecting data races include those based on the
represents the most-recently allocated block allocated at lockset algorithm [52], on the happens-before relation [41],
Site, and a summary block NMRAB[Site], which repre- or on a combination of the two [43]. A data race is a heu-
sents the non-most-recently allocated blocks allocated at ristic indication that a concurrency bug may exist, and does
Site. As the names indicate, recency abstraction is based not directly correspond to a notion of program correctness.
on tracking a temporal property of a block b: the “is-the- In our approach, we treat atomic-set, unit-of-work, and unit-
most-recent-block-from-Site(b)” property, which serves to for annotations as a specification language that allow a pro-
isolate MRAB[b] from the blocks represented by NMRAB[b]. grammer to state his intensions more precisely. Moreover,
With counter abstraction [39,45,58], numeric information AS-serializability accounts for multi-location consistency
is attached to summary objects to characterize the number of errors that the aforementioned techniques would not be able
concrete objects represented. The information on summary to find.
object u of abstract configuration S describes the number of High-level data races may take the form of view incon-
concrete objects that are mapped to u in any concrete config- sistency [4], where memory is read inconsistently, as well as
uration that S represents. Counter abstraction has been used stale-value errors [3,9], where a value read from a shared
in the analysis of infinite-state systems [39,45], as well as in variable is used beyond the synchronization scope in which
shape analysis [58]. it was acquired. Our problematic interleaving scenarios cap-
In contrast to all of the aforementioned work, random- ture these forms of high-level data races, as well as several
isolation abstraction is based on isolating a random individ- others, in one framework.
ual (so that strong updates can be performed on its abstract Several notions of serializability and associated detec-
counterpart), tracking its properties, and generalizing from tion tools have been presented, including [17,38,51,56].
the properties of the randomly chosen individual to all of These correctness criteria ignore relationships that may exist
the individuals allocated at the same allocation site, accord- between shared memory locations, and treat all locations as
ing to Random-isolation principle 2. The isolation can be forming one atomic set. Therefore, they may not accurately
performed either via (i) a source-to-source transformation reflect the intentions of the programmer for correct behav-
of the original program (as explained in Sect. 6.1); (ii) in ior. Atomic-set serializability takes such relationships into
the concrete operational semantics; or (iii) in the abstract account and provides a finer-grained correctness criterion
semantics. Method (i) facilitates the use of random isolation for concurrent systems. For a detailed discussion and com-
in conjunction with existing analyses as a way to strengthen parison of different notions of serializability, see [22].
them. In addition to the work described in the present paper, AS-serializability was proposed by [54]. That work
random isolation has been used to model check information- focused on inference of locks. A dynamic violation-detection
flow properties of decentralized information flow control tool was proposed in [22] to find errors in legacy code.
(DIFC) systems, which manipulate potentially unbounded Hammer et al. also analyzed programs from the Con-
sets of processes, principals, and communication channels Testbenchmark suite, and their dynamic tool found
[23]. AS-serializability violations in the programs Account,
The work most closely related to random isolation AirlineTcks, BugTester, PingPong, and Software
is the technique of temporal case splitting [14], which VerificationHW. Empire is a static counterpart of their
was developed independently and contemporaneously with tool, with the benefit that Empire considers multiple exe-
random isolation [32]. Temporal case splitting also pro- cutions of a program (symbolically), instead of just one
vides a way to reduce analysis problems that involve an execution like the dynamic tool of Hammer et al. Even
unbounded number of entities and resources to a finite though Empire did not find the AS-serializability viola-
abstraction. In temporal case splitting, manually intro- tion in BugTester because Empire exhausted its available
duced “Skolem variables” serve to name a single, arbi- resources, it did find AS-serializability violations in shop,
trary individual among a given class of individuals. Emmi which the tool of Hammer et al. did not find. The remaining
et al. [14] used temporal case splitting as one of sev- two benchmarks were not analyzed by their tool.
eral techniques in a tool to verify programs that use
reference counting to track resources and schedule their Acknowledgments The authors would like to thank the anonymous
reviewers for their valuable feedback.
deallocation.

123
Finding concurrency-related bugs 517

References 27. Jones, N., Muchnick, S.: A flexible approach to interprocedural


data flow analysis and programs with recursive data structures.
1. Ahmed, A., Fluet, M., Morrisett, G.: L3: a linear language with In: POPL (1982)
locations. Fundam. Inf. 77(4), 397–449 (2007) 28. Kahlon, V., Gupta A.: On the analysis of interacting pushdown
2. Aiken, A., Foster, J., Kodumal, J., Terauchi, T.: Checking and infer- systems. In: POPL, pp. 303–314 (2007)
ring local non-aliasing. In: PLDI. pp. 129–140 (2003) 29. Kidd, N.: Static Verification of Data-Consistency Properties. PhD
3. Artho, C., Biere, A., Havelund, K.: Using block-local atomicity to thesis, University of Wisconsin-Madison (2009)
detect stale-value concurrency errors. In: Proceedings of Second 30. Kidd, N., Lal, A., Reps, T.: Language strength reduction. In:SAS,
International Symposium on Automated Technology for Verifica- pp. 283–298 (2008)
tion and Analysis (ATVA 2004), Taipei, Taiwan. LNCS, vol. 3299, 31. Kidd, N., Lammich, P., Touili, T., Reps, T.: A decision procedure for
pp. 150–164. Springer, Berlin (2004) detecting atomicity violations for communicating processes with
4. Artho, C., Havelund, K., Biere, A.: High-level data races. J. Softw. locks. Int. J. Softw. Tools Tech. Transfer 13(1), 37–60 (2011)
Test. Verif. Reliab. (STVR) 13(4), 207–227 (2003) 32. Kidd, N., Reps, T., Dolby, J., Vaziri, M.: Finding concurrency-
5. Balakrishnan, G., Reps, T.: Recency-abstraction for heap-allocated related bugs using random isolation. In: VMCAI, pp. 198–213
storage. In: SAS, pp. 221–239 (2006) (2009a)
6. Ball, T., Rajamani, S.: Automatically validating temporal safety 33. Kidd, N. A., Lammich, P., Touili, T., Reps, T.: A decision
properties of interfaces. In: SPIN, pp. 103–122 (2001) procedure for detecting atomicity violations for communicating
7. Boyapati, C., Lee, R., Rinard, M.: Ownership types for safe processes with locks. In: SPIN, pp. 125–142 (2009b)
programming: preventing data races and deadlocks. In OOPSLA, 34. Lahiri, S.K., Qadeer, S.: Verifying properties of well-founded
pp. 211–230 (2002) linked lists, pp. 115–126 (2006)
8. Burch, J.R., Clarke, E.M., McMillan, K.L., Dill, D.L., Hwang, L.J.: 35. Lammich, P., Müller-Olm, M.: Conflict analysis of programs
Symbolic model checking: 1020 states and beyond. In LICS, pages with procedures, dynamic thread creation, and monitors. In: SAS,
428–239 (1990) pp. 205–220 (2008)
9. Burrows, M., Leino, K.R.M.: Finding stale-value errors in concur- 36. Lev-Ami, T., Sagiv, M.: TVLA: A system for implementing static
rent programs. Conc. Comp. Prac. Exp. 16(12), 1161–1172 (2004) analyses. In: SAS, pp. 280–301 (2000)
10. Chaki, S., Clarke, E., Kidd, N., Reps, T., Touili, T.: Verifying 37. Lu, S., Park, S., Seo, E., Zhou, Y.: Learning from mistakes—a com-
concurrent message-passing C programs with recursive calls. In: prehensive study on real world concurrency bug characteristics. In:
TACAS, pp. 334–349 (2006) ASPLOS, pp. 329–339 (2008)
11. Chase, D., Wegman, M., Zadeck, F.: Analysis of pointers and struc- 38. Lu, S., Tucek, J., Qin, F., Zhou, Y.: AVIO: Detecting atomicity vio-
tures. In: PLDI, pp. 296–310 (1990) lations via access-interleaving invariants. In: ASPLOS, pp. 37–48
12. Cousot, P., Cousot, R.: Systematic design of program analysis (2006)
frameworks. In: POPL, pp. 269–282 (1979) 39. McMillan, K.: Verification of infinite state systems by composi-
13. Dillig, I., Dillig, T., Aiken, A.: Fluid updates: beyond strong versus tional model checking. In: CHARME, pp. 219–234 (1999)
weak updates. In: ESOP, pp. 246–266 (2010) 40. Milanova, A., Rountev, A., Ryder, B.G.: Parameterized object sen-
14. Emmi, M., Jhala, R., Kohler, E., Majumdar, R.: Verifying reference sitivity for points-to analysis for Java. TOSEM 14(1), 1–41 (2005)
counting implementations. In: TACAS, pp. 352–367 (2009) 41. Min, S.L., Choi, J.-D.: An efficient cache-based access anomaly
15. Eytani, Y., Havelund, K., Stoller, S.D., Ur, S.: Towards a frame- detection scheme. In: ASPLOS, pp. 235–244 (1991)
work and a benchmark for testing tools for multi-threaded 42. Naik, M., Aiken, A.: Conditional must not aliasing for static race
programs. Conc. Comp. Prac. Exp. 19(3), 267–279 (2007) detection. In: POPL, pp. 327–338 (2007)
16. Fahndrich, M., DeLine, R.: Adoption and focus: practical linear 43. O’Callahan, R., Choi, J.-D.: Hybrid dynamic data race detection.
types for imperative programming. In: PLDI, pp. 13–24 (2002) In: PPoPP, pp. 167–178 (2003)
17. Flanagan, C., Freund, S.N.: Atomizer: a dynamic atomicity checker 44. Plevyak, J., Karamcheti, V., Chien, A.: Analysis of dynamic struc-
for multithreaded programs. In: POPL, pp. 256–267 (2004) tures for efficient parallel execution. In: Banerjee, U., Gelernter, D.,
18. Foster, J., Terauchi, T., Aiken, A.: Flow-sensitive type qualifiers. Nicolau, A., Padua, D. (eds.) In: Workshop on Languages and Com-
In: PLDI, pp. 1–12 (2002) pilers for Parallel Computing, Portland, OR. Lecture Notes in Com-
19. Gopan, D., DiMaio, F., Dor, N., Reps, T.W., Sagiv, S.: Numeric puter Science, vol. 768, pp. 37–57. Springer, Berlin (1993)
domains with summarized dimensions. In: TACAS, pp. 512–529 45. Pnueli, A., Xu, J., Zuck, L.: Liveness with (0, 1, ∞)-counter
(2004) abstraction. In: CAV, pp. 107–122 (2002)
20. Gopan, D., Reps, T.W., Sagiv, S.: A framework for numeric anal- 46. Qadeer, S., Wu, D.: KISS: keep it simple and sequential. In: PLDI,
ysis of array operations. In: POPL, pp. 338–350 (2005) pp. 14–24 (2004)
21. Gulwani, S., McCloskey, B., Tiwari, A.: Lifting abstract interpret- 47. Ramalingam, G.: Context-sensitive synchronization-sensitive anal-
ers to quantified logical domains. In: POPL, pp. 235–246 (2008) ysis is undecidable. ACM Trans. Program. Lang. Syst. 22, 416–430
22. Hammer, C., Dolby, J., Vaziri, M., Tip, F.: Dynamic detection of (2000)
atomic-set serializability violations. In: ICSE, pp. 231–240 (2008) 48. Rondon, P., Kawaguchi, M., Jhala, R.: Low-level liquid types. In:
23. Harris, W., Kidd, N., Chaki, S., Jha, S., Reps, T.: Verifying informa- POPL, pp. 131–144 (2010)
tion flow control over unbounded processes. In: FM, pp. 773–789 49. Sagiv, M., Reps, T., Wilhelm, R.: Solving shape-analysis prob-
(2009) lems in languages with destructive updating. ACM Trans. Program.
24. Horwitz, S., Pfeiffer, P., Reps, T.: Dependence analysis for pointer Lang. Syst. 20(1), 1–50 (1998)
variables. In: PLDI, pp. 28–40 (1989) 50. Sagiv, M., Reps, T., Wilhelm, R.: Parametric shape analysis via
25. IBM: Watson Libraries for Analysis (WALA). http://wala. 3-valued logic. ACM Trans. Program. Lang. Syst. 24(3), 217–298
sourceforge.net/wiki/index.php (2009) (2002)
26. Jones, N., Muchnick, S.: Flow analysis and optimization of Lisp- 51. Sasturkar, A., Agarwal, R., Wang, L., Stoller, S.D.: Automated
like structures. In: Program Flow Analysis: Theory and Applica- type-based analysis of data races and atomicity. In: PPoPP,
tions, pp. 66–74. Prentice-Hall, New Jersey (1981) pp. 83–94 (2005)

123
518 N. Kidd et al.

52. Savage, S., Burrows, M., Nelson, G., Sobalvarro, P., Anderson, 56. Wang, L., Stoller, S.D.: Accurate and efficient runtime detection of
T.E.: Eraser: A dynamic data race detector for multithreaded pro- atomicity errors in concurrent programs. In PPoPP, pp. 137–146
grams. Theor. Comput. Sci. 15(4), 391–411 (1997) (2006a)
53. Schwoon, S.: Model-Checking Pushdown Systems. PhD thesis, 57. Wang, L., Stoller, S.D.: Runtime analysis for atomicity of multi-
TUM (2002) threaded programs. IEEE Trans. Softw. Eng. 32, 93–110 (2006)
54. Vaziri, M., Tip, F., Dolby, J.: Associating synchronization con- 58. Yavuz-Kahveci T., Bultan T.: Automated verification of concurrent
straints with data in an object-oriented language. In: POPL, linked lists with counters. In: SAS, pp. 69–84 (2002)
pp. 334–345 (2006)
55. Walker, D., Morrisett, J.: Alias types for recursive data structures.
In: Types in Compilation, pp. 177–206 (2000)

123

You might also like