types against races
play

Types Against Races Atomicity Analysis of Concurrent Software - PDF document

Types Against Races Atomicity Analysis of Concurrent Software Cormac Flanagan Stephen N. Freund UC Santa Cruz Williams College Shaz Qadeer Microsoft Research Moore s Law Moore s Law is Over Transistors per chip doubles every 18


  1. Types Against Races Atomicity Analysis of Concurrent Software Cormac Flanagan Stephen N. Freund UC Santa Cruz Williams College Shaz Qadeer Microsoft Research Moore ’ s Law Moore ’ s Law is Over • Transistors per chip doubles every 18 months • Sure, we can pack more transistors ... – ... but can ’ t use them effectively to make single- threaded programs faster • Single-threaded performance doubles every 2 years • Multi-core is the future of hardware – faster clocks, deep pipelines, multiple issue – wonderful! • Multi-threading is the future of software Programming With Threads • Decompose program into parallel threads • Advantages – exploit multiple cores/processors – some threads progress, even if others block • Increasingly common (Java, C#, GUIs, servers) Web Server Thread 1 network database Thread 2 1

  2. Security vulnerabilities involving Concurrency is a problem race conditions • Windows 2000 hot fixes • Buffer overruns – Concurrency errors most common defects among “detectable errors” • Phishing attacks – Incorrect synchronization and protocol errors most – “A systematic approach to uncover visual ambiguity common defects among all coding errors vulnerabilities ” , MSR Technical Report MSR-TR- • Windows Server 2003 late cycle defects 2006-48 by Chen et al. – Synchronization errors second in the list, next to buffer overruns Economic Impact Non-Determinism, Heisenbugs • NIST study – On CNN.com - April 27, 2003 • Multithreaded programs are non-deterministic – behavior depends on interleaving of threads • Extremely difficult to test – exponentially many interleavings – during testing, many interleavings behave correctly – post-deployment, other interleavings fail http://www.nist.gov/director/prog-ofc/report02-3.pdf • Complicates code reviews, static analysis, ... 400 horses Mars, July 4, 1997 100 microprocessors Lost contact due to real-time priority inversion bug 2

  3. Bank Account Implementation Bank Account Implementation class Account { class Account { private int bal = 0; private int bal = 0; public void deposit(int n) { public void deposit(int n) { int j = bal; int j = bal; bal = j + n; bal = j + n; } } } } bal = bal = j1 = bal j2 = bal j1 + 10 j2 + 10 bal = 0 bal = 20 bal = bal = j1 = bal j2 = bal j1 + 10 j2 + 10 bal = 0 bal = 10 Bank Account Implementation Race Conditions A race condition occurs if two threads access a class Ref { shared variable at the same time, and at least one of int i; the accesses is a write void add(Ref r) { i = i + r.i; } } bal = bal = j1 = bal j2 = bal j1 + 10 j2 + 10 bal = 0 bal = 20 bal = bal = j1 = bal j2 = bal j1 + 10 j2 + 10 bal = 0 bal = 10 Race Conditions Race Conditions class Ref { class Ref { int i; int i; Race condition on x.i void add(Ref r) { void add(Ref r) { i = i i = i + r.i; + r.i; } } } } Ref x = new Ref(0); Ref x = new Ref(0); Ref y = new Ref(3); Ref y = new Ref(3); parallel { x.add(y); x.add(y); // two calls happen x.add(y); x.add(y); // in parallel } Assertion may fail assert x.i == 6; assert x.i == 6; 3

  4. Lock-Based Synchronization When Locking Goes Bad ... • Hesienbugs (race conditions, etc) are common and class Ref { problematic int i; // guarded by this • Every shared memory void add(Ref r) { – forget to acquire lock, acquire wrong lock, etc location protected by a i = i lock – extremely hard to detect and isolate + r.i; } } • Traditional type systems are great for catching • Lock must be held before Ref x = new Ref(0); any read or write of that certain errors Ref y = new Ref(3); memory location parallel { synchronized (x,y) { x.add(y); } • Type systems for multithreaded software synchronized (x,y) { x.add(y); } – detect race conditions, atomicity violations, ... } assert x.i == 6; Verifying Race Freedom with Types Verifying Race Freedom with Types class Ref { class Ref { int i; int i guarded_by this; void add(Ref r) { void add(Ref r) requires this, r { check: this ∈ { this, r } i = i i = i + r.i; + r.i; } } } } Ref x = new Ref(0); Ref x = new Ref(0); Ref y = new Ref(3); Ref y = new Ref(3); parallel { parallel { synchronized (x,y) { x.add(y); } synchronized (x,y) { x.add(y); } synchronized (x,y) { x.add(y); } synchronized (x,y) { x.add(y); } } } assert x.i == 6; assert x.i == 6; Verifying Race Freedom with Types Verifying Race Freedom with Types class Ref { class Ref { int i guarded_by this; int i guarded_by this; void add(Ref r) requires this, r { void add(Ref r) requires this, r { check: this ∈ { this, r } check: this ∈ { this, r }   i = i i = i check: this[this:=r] = r ∈ { this, r } check: this[this:=r] = r ∈ { this, r } + r.i;  + r.i;  } } } } replace this by r Ref x = new Ref(0); Ref x = new Ref(0); Ref y = new Ref(3); Ref y = new Ref(3); replace formals this,r by actuals x,y parallel { parallel { check: {this,r}[this:=x,r:=y] ∈ { x, y } synchronized (x,y) { x.add(y); } synchronized (x,y) { x.add(y); }  synchronized (x,y) { x.add(y); } synchronized (x,y) { x.add(y); } } } assert x.i == 6; assert x.i == 6; 4

  5. Verifying Race Freedom with Types One Problem ... class Ref { Object o; int i guarded_by this; int x guarded_by o; void add(Ref r) requires this, r { check: this ∈ { this, r }  i = i check: this[this:=r] = r ∈ { this, r } fork { sync(o) { x++; } } + r.i;  } } fork { o = new Object(); sync(o) { x++; } Ref x = new Ref(0); Ref y = new Ref(3); replace formals this,r } by actuals x,y parallel { synchronized (x,y) { x.add(y); } check: {this,r}[this:=x,r:=y] ∈ { x, y }  check: {this,r}[this:=x,r:=y] ∈ { x, y } synchronized (x,y) { x.add(y); }  • Lock expressions must be constant } assert x.i == 6; Soundness Theorem: Well-typed programs are race-free Lock Equality Lock Equality • Approximate (undecidable) semantic equality by • Type system checks if lock is in lock set syntactic equality – r ∈ { this, r } – two locks expressions are considered equal only if – same as r = this ∨ r = r syntactically identical • Conservative approximation class A { • Semantic equality void f() requires this { ... } – e 1 = e 2 if e 1 and e 2 refer to same object } – need to test whether two program expressions evaluate A p = new A(); to same value q = p; this[this:=p] = p ∈ { q } X synch(q) { p.f(); } – undecidable in general • Not a major source of imprecision RaceFreeJava Typing Rules • Concurrent extension of CLASSICJAVA • Thread creation [Flatt-Krishnamurthi-Felleisen 99] • Judgement for typing expressions • Synchronization lock is constant add to lock set Program Environment Lock set 5

  6. java.util.Vector 0 1 2 a b Field Access 2 class Vector { Object elementData[] /*# guarded_by this */; e has class c int elementCount /*# guarded_by this */; fd is declared in c synchronized int lastIndexOf(Object elem, int n) { lock l is held for (int i = n ; i >= 0 ; i--) if (elem.equals(elementData[i])) return i; return -1; } int lastIndexOf(Object elem) { return lastIndexOf(elem, elementCount - 1); } synchronized void trimToSize() { ... } synchronized boolean remove(int index) { ... } } java.util.Vector 0 a Validation of rccjava 1 class Vector { Object elementData[] /*# guarded_by this */; int elementCount /*# guarded_by this */; Number of Annotation Races synchronized int lastIndexOf(Object elem, int n) { Program Size (lines) annotations time (hrs) Found for (int i = n ; i >= 0 ; i--) Hashtable 434 60 0.5 0 if (elem.equals(elementData[i])) return i; return -1; Vector 440 10 0.5 1 } java.io 16,000 139 16.0 4 Ambit 4,500 38 4.0 4 int lastIndexOf(Object elem) { return lastIndexOf(elem, elementCount - 1); WebL 20,000 358 12.0 5 } synchronized void trimToSize() { ... } synchronized boolean remove(int index) { ... } } Basic Type Inference Basic Type Inference static final Object m =new Object(); Iterative GFP algorithm: class Ref { class Ref { • [Flanagan-Freund, PASTE ’ 01] int i; int i; • Start with maximum set of void add(Ref r) { void add(Ref r) { annotations i = i + r.i; i = i + r.i; } } } } Ref x = new Ref(0); Ref x = new Ref(0); Ref y = new Ref(3); Ref y = new Ref(3); parallel { parallel { synchronized (x,y) { x.add(y); } synchronized (x,y) { x.add(y); } synchronized (x,y) { x.add(y); } synchronized (x,y) { x.add(y); } } } assert x.i == 6; assert x.i == 6; 6

Recommend


More recommend