Effective Static Race Detection for Java Mayur Alex

  • Slides: 35
Download presentation
Effective Static Race Detection for Java Mayur, Alex, John @ CS Department Stanford University

Effective Static Race Detection for Java Mayur, Alex, John @ CS Department Stanford University Presented by Roy Ganor 14/2/08 Point-To Analysis Seminar Tel Aviv University 1

A Few Definitions (not!) 2

A Few Definitions (not!) 2

Motivation Concurrent = Hard sync (l) { t 1 t 2 = x; t

Motivation Concurrent = Hard sync (l) { t 1 t 2 = x; t 1 t 2 = t 1 t 2 + 1; x = t 1; t 2; x==k t 1=x t 2=x x==k t 1=x t 1++ t 2=x x=t 1 x=t 2 t 2++ t 2=x t 1=x x=t 2 t 2++ t 1++ x=t 2 x=t 1 x==k+2 3 x==k+2 x==k+1 × . . . (20 total)

Definition • Two threads access the same memory location • Without ordering constraints •

Definition • Two threads access the same memory location • Without ordering constraints • At least one is a write Non-deterministic nature of thread difficult to reproduce and fix 4

Dynamic vs. Static Race Detection Dynamic (lock-set*, happens-before*) • Program is executed • Record

Dynamic vs. Static Race Detection Dynamic (lock-set*, happens-before*) • Program is executed • Record analyzing memory accesses and synchronization operations • "post-mortem" - records critical events analyze later Static • Employ compile-time analysis on the program source • Reporting all potential races that could occur in 5 any possible program execution

Pros and Cons Dynamic • Feasible execution Lower false positive rate • Not all

Pros and Cons Dynamic • Feasible execution Lower false positive rate • Not all paths are considered not sound • Cannot certify a program to be race free • Overhead on program execution Static • False positive (reporting a potential data race when none exists) • Scaling is also difficult • Frameworks / Open libraries • Sound? 6

Key Problems • Precision • Scalability • Synchronization Idioms • Open Programs • Counterexamples

Key Problems • Precision • Scalability • Synchronization Idioms • Open Programs • Counterexamples 7

Harness Synthesis • Problem - Detect races in open programs is important – missing

Harness Synthesis • Problem - Detect races in open programs is important – missing callees and callers • Solution - simulating scenarios of program’s exercise its interfaces. For each Interface: 1. declares a local variable of each type 2. Assigns to each local variable of reference type T, an object of each concrete class of type T 3. Invokes each method on each combination of local variables and assigns the return value if any to each local variable respecting the result type of the method 4. Simulates executing each pair of calls in separate threads on shared data. 8

Original Pairs • F – get / set instance field x. f • G

Original Pairs • F – get / set instance field x. f • G – get / set static field Class. f • A – get / set instance field x[i] 9

Algorithm Outline Starting with all (possible) pairs… JDBM - 11, 189, 853 pairs Reduce

Algorithm Outline Starting with all (possible) pairs… JDBM - 11, 189, 853 pairs Reduce pairs “Step-by-Step” JDBM – 33, 443 7, 511 2, 756 91 pairs Each access is reachable from a thread-spawning call site that it itself reacable from main() 10 Both access the same location x. f == y. f Both access thread-shared data Without holding a common lock

Running Example static public void main() { A a; a = new A(); a.

Running Example static public void main() { A a; a = new A(); a. get(); a. inc(); } public A() { f = 0; } public int get() { return rd(); } public sync int inc() { int t = rd() + (new A()). wr(1); return wr(t); } private int rd() { return f; } private int wr(int x) { f = x; return x; } 11

Computing Original Pairs All pairs of accesses such that: – Both access the same

Computing Original Pairs All pairs of accesses such that: – Both access the same instance field or the same static field or array elements – At least one is a write 12

Example: Original Pairs static public void main() { A a; a = new A();

Example: Original Pairs static public void main() { A a; a = new A(); a. get(); a. inc(); } public A() { f = 0; } private int rd() { return f; } private int wr(int x) { f = x; return x; } 13 public int get() { return rd(); } public sync int inc() { int t = rd() + (new A()). wr(1); return wr(t); }

Computing Reachable Pairs • Step 1 – Access pairs with at least one write

Computing Reachable Pairs • Step 1 – Access pairs with at least one write to same field • Step 2 – Consider access pair (e 1, e 2) – To have a race, e 1 must be reachable from a thread-spawning call site s 1 without “switching” threads – And s 1 must be reachable from main – And similarly for e 2 14

Example: Reachable Pairs static public void main() { A a; a = new A();

Example: Reachable Pairs static public void main() { A a; a = new A(); a. get(); a. inc(); } public A() { f = 0; } private int rd() { return f; } private int wr(int x) { f = x; return x; } 15 public int get() { return rd(); } public sync int inc() { int t = rd() + (new A()). wr(1); return wr(t); }

Example: Two Object-Sensitive Contexts static public void main() { A a; a = new

Example: Two Object-Sensitive Contexts static public void main() { A a; a = new A(); a. get(); a. inc(); } public A() { f = 0; } private int rd() { return f; } private int wr(int x) { f = x; return x; } 16 public int get() { return rd(); } public sync int inc() { int t = rd() + (new A()). wr(1); return wr(t); }

Example: 1 st Context static public void main() { A a; a = new

Example: 1 st Context static public void main() { A a; a = new A(); a. get(); a. inc(); } public A() { f = 0; } private int rd() { return f; } private int wr(int x) { f = x; return x; } 17 public int get() { return rd(); } public sync int inc() { int t = rd() + (new A()). wr(1); return wr(t); }

Example: 2 nd Context * static public void main() { A a; a =

Example: 2 nd Context * static public void main() { A a; a = new A(); a. get(); a. inc(); } public A() { f = 0; } private int rd() { return f; } private int wr(int x) { f = x; return x; } 18 public int get() { return rd(); } public sync int inc() { int t = rd() + (new A()). wr(1); return wr(t); }

Example: Reachable Pairs static public void main() { A a; a = new A();

Example: Reachable Pairs static public void main() { A a; a = new A(); a. get(); a. inc(); } public A() { f = 0; } private int rd() { return f; } private int wr(int x) { f = x; return x; } 19 public int get() { return rd(); } public sync int inc() { int t = rd() + (new A()). wr(1); return wr(t); }

Computing Aliasing Pairs • Steps 1 -2 – Access pairs with at least one

Computing Aliasing Pairs • Steps 1 -2 – Access pairs with at least one write to same field – And both are reachable from some thread • Step 3 – To have a race, both must access the same memory location – Use alias analysis 20

Example: Aliasing Pairs static public void main() { A a; a = new A();

Example: Aliasing Pairs static public void main() { A a; a = new A(); a. get(); a. inc(); } public A() { f = 0; } private int rd() { return f; } private int wr(int x) { f = x; return x; } 21 public int get() { return rd(); } public sync int inc() { int t = rd() + (new A()). wr(1); return wr(t); }

Computing Escaping Pairs • Steps 1 -3 – Access pairs with at least one

Computing Escaping Pairs • Steps 1 -3 – Access pairs with at least one write to same field – And both are reachable from some thread – And both can access the same memory location 22 • Step 4 – To have a race, the memory location must also be thread-shared – Use thread-escape analysis

Example: Escaping Pairs static public void main() { A a; a = new A();

Example: Escaping Pairs static public void main() { A a; a = new A(); a. get(); a. inc(); } public A() { f = 0; } private int rd() { return f; } private int wr(int x) { f = x; return x; } 23 public int get() { return rd(); } public sync int inc() { int t = rd() + (new A()). wr(1); return wr(t); }

Computing Unlocked Pairs • Steps 1 -4 – Access pairs with at least one

Computing Unlocked Pairs • Steps 1 -4 – Access pairs with at least one write to same field – And both are reachable from some thread – And both can access the same memory location – And the memory location is thread-shared • Step 5 – Discard pairs where the memory location is guarded by a common lock in both accesses – Needs must-alias analysis – We use approximation of may-alias analysis, which is unsound 24

Example: Unlocked Pairs static public void main() { A a; a = new A();

Example: Unlocked Pairs static public void main() { A a; a = new A(); a. get(); a. inc(); } public A() { f = 0; } private int rd() { return f; } private int wr(int x) { f = x; return x; } 25 public int get() { return rd(); } public sync int inc() { int t = rd() + (new A()). wr(1); return wr(t); }

Alias Analysis // Thread 1: sync (l 1) { … e 1. f …

Alias Analysis // Thread 1: sync (l 1) { … e 1. f … } // Thread 2: sync (l 2) { … e 2. f … } • Field f is race-free if: e 1 and e 2 never refer to the same value ¬ MAY-ALIAS(e 1, e 2) OR l 1 and l 2 always refer to the same value MUST-ALIAS(l 1, l 2) 26

Must Alias Analysis • Small body of work – Much harder problem than may

Must Alias Analysis • Small body of work – Much harder problem than may alias analysis • Impediment to many previous race detection approaches – Folk wisdom: Static race detection is intractable Insight: Must alias analysis not necessary for race detection! 27

New Idea: Conditional Must Not Alias Analysis // Thread 1: sync (l 1) {

New Idea: Conditional Must Not Alias Analysis // Thread 1: sync (l 1) { … e 1. f … } // Thread 2: sync (l 2) { … e 2. f … } • Field f is race-free if: Whenever l 1 and l 2 refer to different values, e 1 and e 2 also refer to different values MUST-NOT-ALIAS(l 1, l 2) => MUST-NOT-ALIAS(e 1, e 2) 28

Example h 0 a = new h 0[N]; for (i = 0; i <

Example h 0 a = new h 0[N]; for (i = 0; i < N; i++) { a[i] = new h 1; a[i]. g = new h 2; } x 1 = a[*]; sync (? ) { x 1. g. f = …; } a[0] a[N-1] a[i] h 1 … g g h 2 … h 1 h 2 … h 2 x 2 = a[*]; sync (? ) { x 2. g. f = …; } MUST-NOT-ALIAS(? , ? ) => MUST-NOT-ALIAS(x 1. g. f, x 1. g. f) 29

Example: Counterexample static public void main() { A a; a = new A(); 4:

Example: Counterexample static public void main() { A a; a = new A(); 4: a. get(); 5: a. inc(); } field reference A. f (A. java: 10) [Rd] A. get(A. java: 4) Harness. main(Harness. java: 4) field reference A. f (A. java: 12) [Wr] A. inc(A. java: 7) Harness. main(Harness. java: 5) 30 public A() { f = 0; } public int get() { 4: return rd(); } public sync int inc() { int t = rd() + (new A()). wr(1); 7: return wr(t); } private int rd() { 10: return f; } private int wr(int x) { 12: f = x; return x; }

Benchmarks vect 1. 1 htbl 1. 4 vect 1. 4 tsp hedc ftp pool

Benchmarks vect 1. 1 htbl 1. 4 vect 1. 4 tsp hedc ftp pool jdbm jdbf jtds derby 31 classes 19 21 366 370 422 493 388 461 465 553 1746 KLOC 3 3 75 76 76 83 103 124 115 122 165 646 description JDK 1. 1 java. util. Vector JDK 1. 1 java. util. Hashtable JDK 1. 4 java. util. Vector Traveling Salesman Problem Web crawler Apache FTP server Apache object pooling library Transaction manager O/R mapping system JDBC driver Apache RDBMS

Pairs Retained After Each Stage 32

Pairs Retained After Each Stage 32

Conclusions • A scalable and precise approach to static race detection – Largest program

Conclusions • A scalable and precise approach to static race detection – Largest program analyzed: ~ 650 KLOC (derby) • Handles common synchronization idioms, analyzes open programs, and generates counterexamples • An example where precise alias analysis is key – Not just any alias analysis (k-object sensitivity) 33

Implementation http: //www. cs. stanford. edu/~mhn/chord. html 34

Implementation http: //www. cs. stanford. edu/~mhn/chord. html 34

References • 35 R. Agarwal, A. Sasturkar, Wang L, and S. Stoller. Optimized run-time

References • 35 R. Agarwal, A. Sasturkar, Wang L, and S. Stoller. Optimized run-time race detection and atomicity checking using partial discovered types. In Proceedings of the 20 th IEEE/ACM International Conference on Automated Software Engineering (ASE’ 05), pages 233– 242, 2005