Effective Race Detection for Event-Driven Programs
Effective Race Detection for Event-Driven Programs
*
en
O O * C on *
AE ll Doc Ev
*
t
sis
PS L A
We
C *
se
um
eu
e
nt R
ed
* Easy to
alu
*
at e d
Abstract 1. Introduction
Like shared-memory multi-threaded programs, event-driven Event-driven applications are vulnerable to concurrency er-
programs such as client-side web applications are suscep- rors similar to those in standard multi-threaded applications.
tible to data races that are hard to reproduce and debug. In a typical event-driven program, event handlers are exe-
Race detection for such programs is hampered by their per- cuted by an event dispatcher as a result of event firing. Event
vasive use of ad hoc synchronization, which can lead to a handlers usually execute atomically in a single thread, so
prohibitive number of false positives. Race detection also handler code can assume that no other handlers execute con-
faces a scalability challenge, as a large number of short- currently. However, such systems allow for events to be fired
running event handlers can quickly overwhelm standard non-deterministically (due to user actions, I/O timing, etc.),
vector-clock-based techniques. which may cause the corresponding event handlers to run in
This paper presents several novel contributions that ad- a non-deterministic order. This non-determinism can cause
dress both of these challenges. First, we introduce race cov- serious errors when event handlers share mutable state.
erage, a systematic method for exposing ad hoc synchroniza- Client-side web applications are an important class of
tion and other (potentially harmful) races to the user, signif- event-driven programs susceptible to such errors, as dis-
icantly reducing false positives. Second, we present an ef- cussed in recent work [15]. Modern web applications make
ficient connectivity algorithm for computing race coverage. extensive use of asynchrony, via so-called “AJAX” requests
The algorithm is based on chain decomposition and lever- and also of asynchronous code loading to speed up per-
ages the structure of event-driven programs to dramatically ceived page load time. This asynchrony can lead to non-
decrease the overhead of vector clocks. deterministic errors, which can have severe consequences for
We implemented our techniques in a tool called E VENT- users: e.g., the Hotmail email service was temporarily bro-
R ACER and evaluated it on a number of public web sites. ken in the Firefox web browser due to a data race, potentially
The results indicate substantial performance and precision causing loss of message content [11].
improvements of our approach over the state-of-the-art. Us- The web platform provides few synchronization primi-
ing E VENT R ACER, we found many harmful races, most of tives to programmers. Hence, web applications are forced
which are beyond the reach of current techniques. to coordinate event handler execution via standard shared
variables, i.e., ad hoc synchronization. The atomic execution
Categories and Subject Descriptors D.2.4 [Software Engi-
of event handlers makes such coordination safe. However,
neering]: Software/Program Verification; D.2.5 [Software
lacking knowledge of this synchronization, existing dynamic
Engineering]: Testing and Debugging – Testing tools; F.3.1
race detectors [4, 15, 16] report an overwhelming number of
[Logics and Meaning of Programs]: Specifying and Verify-
races on web applications, exceeding 3000 for some of the
ing and Reasoning about Programs
sites we tested. The vast majority of these races are harm-
General Terms Algorithms, Verification less: they are either used for ad hoc synchronization or are
Keywords Asynchrony; Concurrency; Nondeterminism; infeasible. Manual examination of such a large set of races
Race Detection; Web is nearly impossible, particularly due to the complex control
flow typically found in event-driven programs.
In this paper, we present two advances in concurrency
Permission to make digital or hard copies of all or part of this work for personal or analysis for event-driven applications, making dynamic race
classroom use is granted without fee provided that copies are not made or distributed
for profit or commercial advantage and that copies bear this notice and the full citation detection for such applications more practical. We first in-
on the first page. Copyrights for components of this work owned by others than ACM troduce the notion of race coverage and show how it can be
must be honored. Abstracting with credit is permitted. To copy otherwise, or republish,
to post on servers or to redistribute to lists, requires prior specific permission and/or a used to quickly expose ad hoc synchronization. Intuitively,
fee. Request permissions from permissions@acm.org. race a covers race b iff treating a as synchronization elim-
OOPSLA ’13, October 29–31, 2013, Indianapolis, Indiana, USA.
Copyright c 2013 ACM 978-1-4503-2374-1/13/10. . . $15.00.
inates b as a race. Importantly, uncovered races are defined
http://dx.doi.org/10.1145/2509136.2509538 and computed in a way which guarantees that both execution
orderings of the corresponding memory accesses are possi- • Based on the above algorithm, we present a fast algorithm
ble. Since synchronization is employed to handle multiple that computes uncovered races in an execution of an
possible execution orderings, this guarantee makes it very event-driven program.
likely that races on synchronization variables will be uncov- • We describe a set of filters for common harmless or
ered. By inspecting uncovered races first, a user can quickly synchronization races in web applications.
identify races on synchronization variables and completely
• We present an extensive evaluation of race coverage and
avoid inspecting false positives covered by those races. Our
evaluation found the set of variables with uncovered races to filters on a large set of web sites. Our experimental results
be 14X smaller on average than the set of all variables with confirm that variables with uncovered, unfiltered races
races, and we found that many uncovered races were in fact are more than 35 times fewer than all variables with
harmful. races. We also found 75 harmful races in the set of web
Second, we present a dynamic analysis algorithm that ef- sites which we analyzed.
ficiently computes races in event-driven programs by keep-
ing the width of its vector clocks much smaller than the The paper is organized as follows. Section 2 motivates
standard approach. Our technique employs chain decompo- the problem and describes a core language that enables us
sition [7] to discover cases where different event handlers to cleanly capture the essential features of event-driven pro-
can safely re-use the same vector clock slot. This optimiza- grams. It also shows how to adapt existing state-of-the-art
tion dramatically reduces the sizes of the vector clocks in dynamic race detectors to our language and discusses their
practice, significantly improving performance. Using this limitations. Section 3 formalizes the concept of race cov-
algorithm as a building block, we present a second algo- erage and states an important theorem on the feasibility of
rithm which efficiently discovers all variables with uncov- uncovered races. Section 4 discusses efficient connectivity
ered races in an execution trace. algorithms for finding uncovered races. In Section 5, we dis-
To further reduce triage effort for races in web applica- cuss our implementation in WebKit as well as our race fil-
tions, we performed an extensive study of thousands of races ters. Experimental results are discussed and summarized in
and developed six filters for common types of harmless or Section 6. Finally, Section 7 discusses related work and Sec-
synchronization races. In our experiments, the filters addi- tion 8 concludes.
tionally (beyond coverage) reduced the number of races to
inspect by a factor of 2.5. 2. Setting
We implemented our dynamic analysis by first modifying
In this section, we first give a small example web application
the WebKit browser [20] to log a trace of relevant events
to motivate our techniques. Then, we define a simple parallel
from a web application run to disk. Then, our tool ana-
language called Event which enables us to cleanly model the
lyzes the log, computes coverage, classifies discovered races
essential concepts necessary for our analysis. We also define
based on our filters, and displays results in a rich browser-
necessary preliminaries such as races and vector clocks.
based user interface. In our experimental evaluation, we ran
Finally, we show how to adapt current state-of-the-art race
the tool on a wide variety of web sites. Despite the obfus-
detection algorithms to Event, and discuss their limitations.
cated code on many of the sites, we were able to inspect
the uncovered races and manually identify many harmful
2.1 Example
races and synchronization variables. Using E VENT R ACER,
we have found harmful races on the front pages of 21 For- Consider the example in Fig. 1. The web page has an input
tune 100 companies. Our tool is usable by web developers, button, two script nodes with JavaScript code, and many
scalable to real web applications, and available open source other elements which have been elided. Web browsers inter-
at http://www.eventracer.org. leave HTML parsing with handling of other events like user
We believe that the techniques described in this work actions; here, this means that the button can be clicked as
may be applicable in other settings which involve heavy user soon as the input element is parsed, potentially before or
interface manipulations (e.g. Android, iOS). between execution of the other scripts. This leads to po-
tential timing-dependent behaviors:
Main Contributions The contributions of this work are:
• If the button is clicked before the first script runs, the f
• We introduce the concept of race coverage, which en- function invoked by the button’s onclick handler will
ables identification of ad hoc synchronization and greatly not yet have been declared, causing a JavaScript inter-
reduces the number of false positive races reported in preter crash. The interpreter crash is not directly visible
event-driven programs. to the user; however, the user will see no effect from the
• We present a fast dynamic race detection algorithm based button click, a usability bug.
on vector clocks which uses chain decomposition to re- • If the click occurs between execution of the two scripts,
duce the width of the used vector clocks significantly. "not ready" will be displayed, as init is still false.
< html > < body > S ::= S; S | rd(t, x) | wr(t, x) |
< input type = " button " id = " b1 "
f ork(t, u, EventAction)
onclick = " javascript : f () " >
... <! -- many e l e m e n t s -- >
Browser User EventAction ::= Joins; begin(t); S; end(t)
< script >
function f () { Parse input type=”button”
if ( init ) Joins ::= Joins; Joins | join(t, u)
alert ( y . g ) ;
show button
else
alert ( " not ready " ) ; P rogram ::= EventAction
} click
var init = false , y = null ; f() - crash! Operation ::= rd(t, x) | wr(t, x) | begin(t) | end(t) |
</ script > f ork(t, u, EventAction) | join(t, u)
...
Parse script
< script >
y = { g : 42 }; define f t, u ∈ EventIds
init = true ; x ∈ V ars
</ script > a, b ∈ Operation
</ body > </ html >
2.3 Order, Races, and Vector Clocks For simplicity, we define join on a set of vector clocks
The execution of a program is defined via traces, where a {V Ci } by t{V Ci } to be V C1 t V C2 t ... for a non-empty
finite trace π = a0 ·a1 ·...·an ∈ Operation∗ (with n ≥ 0) is set {V Ci } and ⊥V otherwise.
a sequence of operations in our language. Here, we abstract 2.4 Adapting Existing Online Dynamic Race Detectors
away the configurations (states) of the program and only
keep the operations. We use the notation [[P]] to denote the A naı̈ve approach to applying existing vector-clock based
set of all traces for a given program P. online dynamic race detectors to our language is to create
a happen-before order between begin and end operations
Trace Order For a given trace π, if operation a occurs encountered in the trace (essentially, mapping these opera-
before operation b in π, we say that a <π b. To simplify tions to global lock/unlock operations). However, while this
exposition we assume that each operation appears only once translation maintains the atomic execution of event actions,
in the trace (if it appears multiple times, we can always no races will be reported as all operations will be treated as
assign a unique identifier to each appearance). Similarly, we “ordered” by a standard race detector. Another, more fruitful
say that event action t precedes event action u in the trace, approach is to: i) avoid introducing happens-before arcs be-
denoted t <π u (we overload the operator), if begin(t) <π tween begin and end operations of different event actions,
begin(u). and ii) only explore traces where event actions do not in-
terleave. In this way, the race detector will not introduce un-
Happens-Before Given a trace π, the happens-before rela- wanted orderings and it will not observe infeasible interleav-
tion over pairs of event actions t and u in π is the minimal ings.
transitively closed relation, such that t u holds if t = u,
f ork(t, u, ) ∈ π, or join(u, t) ∈ π (here we used to mean Limitations Two problems arise when applying online
any value is allowed). We denote the event action of an oper- race detectors to event-driven programs, which our tech-
ation a by ev(a). Given a trace π, a happens-before relation niques address:
between two operations a and b occurring in the trace, de- Too many races In our experiments, we found that applying
noted a b (again, we overload the operator), is true if: race detectors to web programs directly leads to too many
races reported by the analysis (in the thousands). Many
• ev(a) 6= ev(b) and ev(a) ev(b), or
of these races implement ad hoc synchronization or are
• ev(a) = ev(b) and a <π b infeasible. For Fig. 1, the init variable is used for ad
hoc synchronization, to ensure y is initialized before it is Event action 1
HTML tag (see Section 2.2) and short-running event han- if(i1)
dlers.
Event action 3
d2 c2 i2=true
if(i2)
b alert(y.f)
The concepts presented in the next section (Section 3)
aim to address the first limitation. The second limitation is Figure 5. An example with a race R = (a, b) covered by
addressed in Section 4. two races S1 = (c1 , d1 ) and S2 = (c2 , d2 )
3. Race coverage create a happens-before edge between c and d, then the race
In this section we address a key problem which arises in race R will disappear, that is, R will no longer be a race.
detection: the race detector produces too many races to be
Definition 3.1 (Covered race). We say that a race R = (a, b)
practically useful. This problem is significantly exacerbated
is covered by race S = (c, d) if the following conditions
for programs in languages such as Event, as Event has no
hold:
synchronization primitives except joining to other event ac-
tions. This means that any synchronization between event 1. ev(a) ev(c), and
actions needs to be implemented by coordinating via shared 2. d b
variables, which in turns means that a race detector will pro- We denote that race S covers race R by {S} J R. Note
duce many false positives. These false positives can be cate- that we need d b and it is not enough to say ev(d) ev(b)
gorized as follows: as d must come before b, even if they are part of the same
• Synchronization races: these are races which implement event action. Similarly, if we say a c, then that would be
synchronization and are required for the program to work too restrictive as c can come before a if they are in the same
correctly. event action.
• Races covered by synchronization: these are races that Example Fig. 4 shows an example of the conditions in
can never occur since other synchronization races in fact the above definition, based on the scripts in Fig. 1. The
introduce a happens-before edge. dashed lines denote the two races. On its own, the race
R on y may seem harmful: if the read of y.f executes
Indeed, in our experiments in Section 6, we found that the before initialization, an exception will be thrown. However,
vast majority of races on a web site reported by a standard the synchronization on variable init (the covering race S)
race detector are false positives: many of them are either syn- prevents R from ever executing in a “bad” order, i.e., R is
chronization races or they are covered by synchronization not really a race.
races. The total number of races is often so large that manu- Next, we generalize Definition 3.1 to the case where
ally inspecting all of them is almost impossible. Ideally, we a race is covered by multiple races. The intuition behind
would like to focus only on real races, which are not ordered this generalization in that enforced ordering constraints via
by synchronization. Using race coverage, we were able to (multiple) synchronization races are transitive.
report only races uncovered by synchronization, decreasing
Definition 3.2 (Multi-covered race). We say that a race
the number of races reported by an order of magnitude.
R = (a, b) is covered by a set of races {Si = (ci , di )}ni=1 if
3.1 Race coverage and multi-coverage the following conditions hold: