Yongjian Hu Univ of California Riverside Iulian Neamtiu NJIT Motivation Rise of EventDriven Systems Concurrency is a Serious Issue 66 of highseverity Android bugs are due to concurrency Zhou et al EASE15 ID: 931441
Download Presentation The PPT/PDF document "Static Detection of Event-based Races in..." is the property of its rightful owner. Permission is granted to download and print the materials on this web site for personal, non-commercial use only, and to display it on your personal computer provided you do not modify the materials and that you retain all copyright notices contained in the materials. By downloading content from our website, you accept the terms of this agreement.
Slide1
Static Detection of Event-based Races in Android App
Yongjian HuUniv. of California, Riverside
Iulian Neamtiu
NJIT
Slide2Motivation
Rise of Event-Driven Systems
Concurrency is a Serious Issue
66% of high-severity Android bugs are due to concurrency [Zhou et al., EASE’15]
84% of Android race bugs are event-driven races [Bielik et al., OOPSLA’15; Hsial et al. PLDI’14; Maiya et al., PLDI’14]
Mobile apps
Web apps
Data centers
Slide3Concurrency Error Example
class MainActivity {
DataBase
mDB;
BroadcastReceiver recv
=
new BroadcastReceiver() { void
onReceive(Context ctx
, Intent i) {
Bundle b =
i.getExtras
(); mDB.update(b); } } void onCreate(...) { mDB = new DataBase(); registerReceiver(recv, ...); } void onStart() { mDB.open(); } void onStop() { mDB.close(); } void onDestroy() { unregisterReceiver(recv); mDB = null; }}
Main Thread
Broadcast Receiver
onCreate
()
register
unregister
update
onStart
()
onReceive
()
onStop
()
onDestroy
()
update()
before
close()OK
not ordered
Slide4Concurrency Error Example
class MainActivity {
DataBase
mDB;
BroadcastReceiver recv
=
new BroadcastReceiver() { void
onReceive(Context ctx
, Intent i) {
Bundle b =
i.getExtras
(); mDB.update(b); } } void onCreate(...) { mDB = new DataBase(); registerReceiver(recv, ...); } void onStart() { mDB.open(); } void onStop() { mDB.close(); } void onDestroy() { unregisterReceiver(recv); mDB = null; }}
Main Thread
Broadcast Receiver
onCreate
()
register
unregister
update
onStart
()
onReceive
()
onStop
()
onDestroy
()
update()
after
close()Exception!
not ordered
Slide5State-of-the-art in (Android) Race Detection
Prior Android race detectors: all are dynamic
DroidRacer
[
Maiya et al., PLDI’14]; CAFA [Hsiao et al., PLDI’14]; EventRacer [Bielik et al., OOPSLA’15]LimitationsCoverage issues
→ False negatives; “no run - no see”False positives (imprecise Android modeling)
Static race detection is hard [Hong and Kim, STVR’15]Only 7 out of 43 detectors are static“the accuracy of [static] models is often low because of the imprecision inherent to static analysis methods”
Slide6Our Approach
SIERRA
: the first
static, sound
event-driven race detector for Android appsHighly effectiveFinds 29 true races per app vs. 4 (best dynamic detector)EfficientAnalyzes an app in 31 minutes on average
Slide7SIERRA: StatI
c Event-based Race detectoR for Android
App
Analysis booster
Hybrid
Context
Selector
Call Graph Builder
PA Refiner
Pointer
Analysis
Static HB Graph
Race ReportsRace <rw1,rw1’>Race <rw2,rw2’>. . .
Path/Context Sensitivity Refutation
Race Prioritization
WALA
THRESHER
Building HB Graph
Race Refinement
Race Reporting
Slide8Event Race Definition
Action = context-sensitive event handlingNovel abstraction, reifies
Callbacks (lifecycle, GUI callbacks, etc.)
Thread,
AsyncTask, ExecutorHandler’s SendMessage and PostRunnableHappens-before (HB): A1 ≺ A2A1 is completed before A2
Event race = “racy” pair of memory accessesAccess same location: α(x) = α(y)At least one access is write: α(x):Write ꓦ α(y):Write
Access from two actions: θ(x) = A1 ꓥ θ(y) = A2 ꓥ A1 ≠ A2
No HB between two actions: A1 ⊀ A2 ꓥ A2 ⊀ A1
Slide9“Boosting” Static Analysis with
Fixpoint-based Callgraph Construction
Manifest.xml
lists all the activities
For each activity:Find lifecycle callbacks, e.g., onCreate
, onStartFind XML registered callbacks, e.g.,
onClickFind system callbacks, e.g.,
onLowMemoryBuild call graph for found actionsFind and add to work list registered UI callbacks, e.g.,
onItemClick, onLongPressAdded to work list if new actions found
Go back to step 4. Iterate until fixpoint
onCreate
onStart
onResumeonClick
onCreateOptionsMenu
onLow
Memory
thread
AsyncTask
onPost
Execution
msg1.
handleMessage
Runnable1
onItemClick
onLongPress
Runnable2
……
……
Slide10Action Sensitivity: When Context Sensitivity is Insufficient
Hybrid context sensitivity [Kastrinis et al., PLDI’13]K object sensitivity for dispatch invocations
K call-site sensitivity for static invocations
a
Base64.encodeBytes(byte[] source)
Base64.encodeBytes(byte[] source,
int
offset,
int
length,
int
options)
Base64.encodeBytesToBytes(byte[] source, int offset, int length, int options) { …… os = new OutputStream(…); os.write(…);}Action1c1:
c2:
c3:
Points-to(<[c2::c3],
os>) = {<[c2::c3], new OutputStream
>}Event1:WRITE: <[c2::c3], os>READ: <[c2::c3],
os>
Points-to(<[c2::c3], os>) = {<[c2::c3], new OutputStream>}Event2:
WRITE: <[c2::c3], os>READ: <[c2::c3], os>
Base64.encodeBytes(byte[] source)
Base64.encodeBytes(byte[] source,
int
offset,
int
length,
int
options)
Base64.encodeBytesToBytes(byte[] source,
int
offset,
int
length, int options) { …… os
= new
OutputStream
(…);
os.write
(…);
}
Action2
c1’:
c2:
c3:
Conflated → Imprecise → False positive
K=2
Slide11Action Sensitivity: When Context Sensitivity is Insufficient
Hybrid context sensitivity [Kastrinis et al., PLDI’13]K object sensitivity for dispatch invocations
K call-site sensitivity for static invocations
We add
Action sensitivity
Base64.encodeBytes(byte[] source)
Base64.encodeBytes(byte[] source,
int
offset,
int
length,
int
options)Base64.encodeBytesToBytes(byte[] source, int offset, int length, int options) { …… os = new OutputStream(…); os.write(…);}Action1c1:
c2:
c3:
Points-to (<[c2::c3
@a1],
os>) = {<[c2::c3@a1], new OutputStream>}
Event1:WRITE: <[c2::c3@a1], os>READ: <[c2::c3@a1], os>
Points-to(<[c2::c3
@a2], os>) = {<[c2::c3
@a2], new OutputStream>}Event2:WRITE: <[c2::c3
@a2], os>READ: <[c2::c3
@a2], os>
Base64.encodeBytes(byte[] source)
Base64.encodeBytes(byte[] source,
int
offset,
int
length,
int options)
Base64.encodeBytesToBytes(byte[] source, int offset, int
length, int options) { …… os = new OutputStream(…);
os.write(…);}
Action2
c1’:
c2:
c3:
No race
Slide12Happens-before Rules
e
1
e
2
Method M
A
1
A
2
<
dom
Δe1Δe2A1≺A2
Action invocation rule (sender ≺ receiver) Component lifecycle rule
GUI layout/object orderIntra-procedural dominationIntra-action, inter-procedural dominationInter-action transitivity
Transitivity
onResume()
onPause()
*
onClick1()
onClick2()
onClick3()
onResume
≺
onClick1
onResume
≺
onClick2
onClick2
≺
onClick3
Slide13Symbolic Execution-based Refutation
So far, the analysis is…Context sensitiveField sensitive
Path insensitive
…
and discovers 22% of all possible actions orders Which is not bad!Next, we use symbolic execution-based refutation to further order accessesBonus: on-demand path sensitivity!
Slide14Example
Path
Constraints
Backward symbolic execution
mIsRunning
= true
if (
mIsRunning
)
Method entry
if (*)
Method exit
PostDelayedmIsRunning = falsemAccumTime = …
mIsRunning
= false
mIsRunning
= false
true
if (
mIsRunning
)
mIsRunning
= false
mAccumTime
= …
OpenSudoku
app
Can 𝜶A occur before 𝜶B?
Timer.Runnable runner = {void run() {//action
A if (mIsRunning) { mAccumTime=... // 𝜶
A if (*) { ... postDelayed
(runner,...); } else mIsRunning
=false; }}}void stop(){// action
B if (mIsRunning) {
mIsRunning
= false;
mAccumTime
=... // 𝜶
B
}
}
Yes!
Slide15Example
Path
Constraints
Backward symbolic execution
mIsRunning
= true
if (
mIsRunning
)
mAccumTime
= …
mIsRunning
= false
mIsRunning = false
if (
mIsRunning
)Method entry
Method exit
true
mIsRunning = falsemAccumTime
= …
Race Refuted!
Can
𝜶B occur before 𝜶
A? Timer.Runnable
runner = {void run() {//action
A if (mIsRunning) { mAccumTime=... //
𝜶A if (*) { ... postDelayed
(runner,...); } else mIsRunning=false; }}}
void stop(){// action B if (mIsRunning) {
mIsRunning = false; mAccumTime=... // 𝜶
B }}
No!
Slide16Evaluation
Best priorwork (dynamic)
Basic static analysis (CG,PA)
HB construction
Symbolic Execution
Total
1,310
29
560
1,899
Efficiency (median time, in seconds)
App
Installs(millions)ActionsHB edgesRacy pairsAfter action sensitivityAfter refu- tationTrue racesFalse posi-tivesEvent RacerBarcode Scanner> 1001362,756 (30%)642415114
7VLC
> 1001512,349 (20%)202
7835323
0FB Reader> 10
2594,710 (14%)836
28510693135
K-9> 53125,725 (12%)
1,3473708972
171NPR> 1
490
10,673 (9%)607
13221210
3Across 20
apps1602,755 (22%)43180
332944
≫Effectiveness: races found
Dataset: 194 open-source apps; 20 analyzed manuallyLimitation: bound #paths to 5,000 while still sound (report race, might be false positives)
Slide17Conclusions
Event-based races: most prevalent concurrency errors in AndroidPrior approaches: all dynamicLow coverage, false negatives, false positives
Our approach
First fully static event-based race detector
Novel action sensitive context abstractionStatic happens-before relationStatic backward symbolic execution to refute false racesHighly effective; efficient
Slide18Backup
Slide19Race Prioritization
PriorityHigh priorityRaces in app codeNormal priorityRaces in framework but invoked from app code
Low priority
Purely framework race
Report race ifWitness feasible paths from alternative schedulesCannot refute (to preserve soundness)E.g., Out Of Memory, max paths limit, max time limit (1,500 sec.)Potential false positive
Slide20Context Sensitivity(cont’d)
Object insensitive = imprecision
void
onTouchEvent
(
MotionEvent e1,
MotionEvent e2) { ……
if (e1.getX() – e2.getX() > 120.0f …) { Message msg
= new Message(); msg.what = FLING;
……
this.handler.sendMessage
(
msg); } else { Message msg = new Message(); msg.what = LONG_PRESS; …… this.handler.sendMessage(msg); }}Handler handler = new Handler() { public void handleMessage(Message msg) { …… switch (msg.what) { case FLING: …… case LONG_PRESS: …… } }}
MERGED
O1:
Slide21Context Sensitivity(cont’d)
Object sensitivity in SIERRA = precision
void
onTouchEvent
(MotionEvent
e1, MotionEvent e2) {
…… if (e1.getX() – e2.getX() > 120.0f …) {
Message msg = new Message();
msg.what = FLING; ……
this.handler.sendMessage(
msg
);
} else { Message msg = new Message(); msg.what = LONG_PRESS; …… this.handler.sendMessage(msg); }}Handler handler = new Handler() { public void handleMessage(Message msg) { …… switch (msg.what) { case FLING: …… case LONG_PRESS: …… } }}
Handler handler = new Handler() {
public void handleMessage(Message msg) {
…… switch (msg.what) {
case FLING: …… case LONG_PRESS: ……
} }}
C1:
C2:O
h:K-obj
+ 1-call-site for event posting and message passing
ctx
:<o
h,c1>
ctx
:<oh
,c2>
Slide22Happens-before Rules
Rule 1: Action invocation ruleThe sender action happens-before the recipientRule 2: Component lifecycle rule
Activity.onCreate
<
Activity.onStartActivity.onStart < Activity.onStop……Rule 3: GUI layout/object orderActivity.onResume <
View.onClick < Activity.onPause
Slide23Happens-before Rules (cont’d)
e
1
e
2
Method M
A
1
A
2
<
dom
Δe1Δe2<HBRule 4: Intra-procedural dominationMethod M in action A has two action posts: e1
and e2e1 dominates e2: e
1 <dom e2Δe1 ≤ Δ
e2, Δ is post delayed timeRule 5: Intra-action, inter-procedural dominationMethod M1 Action A, M2 Action A
Action posts: e1 , e2 e1
dominates e2Δe1 ≤ Δe
2, Δ is post delayed timeRule 6: Inter-action transitivityAction A1 < A2A1→post A3, A
2→post A4Rule 7: TransitivityA1
< A2 ꓥ A2 < A3 A1 < A3
A1→post A3, A2→post A
4
Context Sensitivity(cont’d)
Object insensitive = imprecision
void
onTouchEvent
(
MotionEvent e1,
MotionEvent e2) { ……
if (e1.getX() – e2.getX() > 120.0f …) { Message msg
= new Message(); msg.what = FLING;
……
this.handler.sendMessage
(
msg); } else { Message msg = new Message(); msg.what = LONG_PRESS; …… this.handler.sendMessage(msg); }}Handler handler = new Handler() { public void handleMessage(Message msg) { …… switch (msg.what) { case FLING: …… case LONG_PRESS: …… } }}
MERGED
O1:
Slide25Context Sensitivity(cont’d)
Object sensitivity in SIERRA = precision
void
onTouchEvent
(MotionEvent
e1, MotionEvent e2) {
…… if (e1.getX() – e2.getX() > 120.0f …) {
Message msg = new Message();
msg.what = FLING; ……
this.handler.sendMessage(
msg
);
} else { Message msg = new Message(); msg.what = LONG_PRESS; …… this.handler.sendMessage(msg); }}Handler handler = new Handler() { public void handleMessage(Message msg) { …… switch (msg.what) { case FLING: …… case LONG_PRESS: …… } }}
Handler handler = new Handler() {
public void handleMessage(Message msg) {
…… switch (msg.what) {
case FLING: …… case LONG_PRESS: ……
} }}
C1:
C2:O
h:K-obj
+ 1-call-site for event posting and message passing
ctx
:<o
h,c1>
ctx
:<oh
,c2>
Slide26Context Sensitivity (cont’d)
SIERRA’s hybrid context sensitivity<k-obj + action> for normal dispatch methods<k-cfa
+ action> for static methods
<k-
obj + 1-call-site + action> for event posting and message passingSingletonContextFor singleton design patternUse global context instead of adding action sensitivityInflatedViewContextInvoked via
View.findViewById(int viewId
)Use viewId as context item
Slide27Happens-before Rules
Rule 1: Action invocation ruleThe sender action happens-before the recipientRule 2: Component lifecycle rule
Activity.onCreate
<
Activity.onStartActivity.onStart < Activity.onStop……Rule 3: GUI layout/object orderActivity.onResume <
View.onClick < Activity.onPause
Slide28Happens-before Rules (cont’d)
e
1
e
2
Method M
A
1
A
2
<
dom
Δe1Δe2<HBRule 4: Intra-procedural dominationMethod M in action A has two action posts: e1
and e2e1 dominates e2: e
1 <dom e2Δe1 ≤ Δ
e2, Δ is post delayed timeRule 5: Intra-action, inter-procedural dominationMethod M1 Action A, M2 Action A
Action posts: e1 , e2 e1
dominates e2Δe1 ≤ Δe
2, Δ is post delayed timeRule 6: Inter-action transitivityAction A1 < A2A1→post A3, A
2→post A4Rule 7: TransitivityA1
< A2 ꓥ A2 < A3 A1 < A3
A1→post A3, A2→post A
4
Concurrency Error, Example 1
Intra-component Race
Image overridden!
Slide30Concurrency Error, Example 2
Inter-component Race
update()
before
close()
:
OK
Slide31Concurrency Error, Example 2
Inter-component Race
update()
after
close()
:
Exception!
Slide32“Boosting” Static Analysis with Fixpoint
-based Callgraph Construction
Manifest.xml lists all the activities
For each activity:
Find lifecycle callbacks, e.g., onCreate, onStartFind XML registered callbacks, e.g.,
onClickFind system callbacks, e.g.,
onLowMemoryBuild call graph for found actions
Find and add to work list registered UI callbacks, e.g., onItemClick, onLongPress
Added to work list if new actions foundGo back to step 4. Iterate until fixpoint
onCreate
onStart
onResume
onClickonCreateOptionsMenuonLowMemory
thread
AsyncTask
onPost
Execution
msg1.
handleMessage
Runnable1
onItemClick
onLongPress
Runnable2
……
……
onCreate
onStart
onResume
onClick
onCreate
OptionsMenu
onLow
Memory
thread
AsyncTask
onPost
Execution
msg1.
handleMessage
Runnable1
onItemClick
onLongPress
Runnable2
*
*
Prior Android static analyses: imprecise