Provably Live Exception Handling Bart Jacobs DistriNet, KU Leuven - - PowerPoint PPT Presentation

provably live exception handling
SMART_READER_LITE
LIVE PREVIEW

Provably Live Exception Handling Bart Jacobs DistriNet, KU Leuven - - PowerPoint PPT Presentation

Provably Live Exception Handling Bart Jacobs DistriNet, KU Leuven FTfJP 2015 Bart Jacobs Provably Live Exception Handling Contents Problem and Proposed Fix 1 Verification Approach (Ignoring Exceptions) 2 Verification Approach (With


slide-1
SLIDE 1

Provably Live Exception Handling

Bart Jacobs

DistriNet, KU Leuven

FTfJP 2015

Bart Jacobs Provably Live Exception Handling

slide-2
SLIDE 2

Contents

1

Problem and Proposed Fix

2

Verification Approach (Ignoring Exceptions)

3

Verification Approach (With Exceptions)

Bart Jacobs Provably Live Exception Handling

slide-3
SLIDE 3

Contents

1

Problem and Proposed Fix

2

Verification Approach (Ignoring Exceptions)

3

Verification Approach (With Exceptions)

Bart Jacobs Provably Live Exception Handling

slide-4
SLIDE 4

Problem Statement

Does this Scala program, running on the JVM, always terminate? val queue = new LinkedBlockingQueue[String]() fork { queue.put(”Hello, world”) } queue.take()

Bart Jacobs Provably Live Exception Handling

slide-5
SLIDE 5

Problem Statement

Does this Scala program, running on the JVM, always terminate? val queue = new LinkedBlockingQueue[String]() fork { queue.put(”Hello, world”) } queue.take() What if put fails?

Bart Jacobs Provably Live Exception Handling

slide-6
SLIDE 6

Problem Statement

Does this Scala program, running on the JVM, always terminate? val queue = new LinkedBlockingQueue[String]() fork { queue.put(”Hello, world”) } queue.take() What if put fails? What if the JVM fails?

Bart Jacobs Provably Live Exception Handling

slide-7
SLIDE 7

Problem Statement

The Java Language Specification, Java SE 8 Edition:

Bart Jacobs Provably Live Exception Handling

slide-8
SLIDE 8

First Fix Attempt

val queue = new LinkedBlockingQueue[String]() fork { try { queue.put(”Hello, world”) } catch { case ⇒ System.exit(1) } } queue.take()

Bart Jacobs Provably Live Exception Handling

slide-9
SLIDE 9

Proposed Fix

new Failbox().enter { val queue = new LinkedBlockingQueue[String]() Failbox.fork { queue.put(”Hello, world”) } queue.take() }

Bart Jacobs Provably Live Exception Handling

slide-10
SLIDE 10

Failboxes (Partial)

class Failbox { val threads = new ArrayList[Thread]() def enter(body: ⇒ Unit) { synchronized { threads.add(Thread.currentThread()) } try { try { body } finally { synchronized { threads.remove(Thread.currentThread()) } } } catch { case e ⇒ synchronized { for (t ← threads) t.interrupt() } throw e } } }

Bart Jacobs Provably Live Exception Handling

slide-11
SLIDE 11

Proposed Fix

new Failbox().enter { val queue = new LinkedBlockingQueue[String]() Failbox.fork { queue.put(”Hello, world”) } queue.take() }

Bart Jacobs Provably Live Exception Handling

slide-12
SLIDE 12

Proposed Fix (Alternative)

val fb = new Failbox() val queue = new LinkedBlockingQueue[String]() fb.enter { Failbox.fork { queue.put(”Hello, world”) } } fb.enter { queue.take() }

Bart Jacobs Provably Live Exception Handling

slide-13
SLIDE 13

Failboxes (Partial)

class Failbox { var failed = false val threads = new ArrayList[Thread]() def enter(body: ⇒ Unit) { synchronized

  • if (failed) throw new FailboxException

threads.add(Thread.currentThread())

  • try {

try { body } finally { synchronized { threads.remove(Thread.currentThread()) } } } catch { case e ⇒ failed = true synchronized { for (t ← threads) t.interrupt() } throw e } } }

Bart Jacobs Provably Live Exception Handling

slide-14
SLIDE 14

Proposed Fix (Alternative)

val fb = new Failbox() val queue = new LinkedBlockingQueue[String]() fb.enter { Failbox.fork { queue.put(”Hello, world”) } } fb.enter { queue.take() }

Bart Jacobs Provably Live Exception Handling

slide-15
SLIDE 15

Contents

1

Problem and Proposed Fix

2

Verification Approach (Ignoring Exceptions)

3

Verification Approach (With Exceptions)

Bart Jacobs Provably Live Exception Handling

slide-16
SLIDE 16

Formal Programming Language

c ::= new sema | fork c | x.V | x.P | let x := c in c

Bart Jacobs Provably Live Exception Handling

slide-17
SLIDE 17

Formal Programming Language

c ::= new sema | fork c | x.V | x.P | let x := c in c let s := new sema in fork s.V; s.P

Bart Jacobs Provably Live Exception Handling

slide-18
SLIDE 18

Programming Language Semantics

(h, T ⊎ { [new sema; ξ] }) (h ⊎ {s → 0}, T ⊎ { [s; ξ] }) (h, T ⊎ { [fork c; ξ] }) (h, T ⊎ { [tt; ξ, c; done] }) (h ⊎ {s → n}, T ⊎ { [x.V; ξ] }) (h ⊎ {s → n + 1}, T ⊎ { [tt; ξ] }) (h ⊎ {s → n + 1}, T ⊎ { [x.P; ξ] }) (h ⊎ {s → n}, T ⊎ { [tt; ξ] }) (h, T ⊎ { [let x := c in c′; ξ] }) (h, T ⊎ { [c; let x := [] in c′; ξ] }) (h, T ⊎ { [v; let x := [] in c′; ξ] }) (h, T ⊎ { [c′[v/x]; ξ] }) (h, T ⊎ { [v; done] }) (h, T) c deadlocks ⇔ ∃h, T. (∅, { [c; done] }) ∗ (h, T)∧(h, T) ∧T = ∅

Bart Jacobs Provably Live Exception Handling

slide-19
SLIDE 19

Assertion Language

P ::= b | s.credit | obs(S) | P ∗ P

Bart Jacobs Provably Live Exception Handling

slide-20
SLIDE 20

Ghost Reachability

P ⇒ P′ P ⊑ P′ P ⊑ P′ P ∗ R ⊑ P′ ∗ R

  • bs(S) ⊒⊑ obs(S ⊎ {

[s] }) ∗ s.credit P ⊑ P′ P′ ⊑ P′′ P ⊑ P′′

Bart Jacobs Provably Live Exception Handling

slide-21
SLIDE 21

Proof Rules (1/2)

⊢ {true} new sema {w(res) = w} ⊢ {obs(S′) ∗ P} c {obs(∅) ∗ true} ⊢ {obs(S ⊎ S′) ∗ P} fork c {obs(S)} ⊢ {true} s.V {s.credit} ⊢ {obs(S) ∗ s.credit ∧ w(s) < w(S)} s.P {obs(S)}

Bart Jacobs Provably Live Exception Handling

slide-22
SLIDE 22

Proof Rules (2/2)

⊢ {P} c {Q} ∀v. ⊢ {Q[v/res]} c′[v/x] {R} ⊢ {P} let x := c in c′ {R} ⊢ {P} c {Q} ⊢ {P ∗ R} c {Q ∗ R} P ⊑ P′ ⊢ {P′} c {Q} Q ⊑ Q′ ⊢ {P} c {Q′}

Bart Jacobs Provably Live Exception Handling

slide-23
SLIDE 23

Soundness

Lemma (Invariant) ∀s. #credits(s) ≤ #obligations(s) + value(s) Theorem (Soundness) If ⊢ {obs(∅)} c {obs(∅) ∗ true}, then c does not deadlock. Proof. Deadlock implies cycle in wait graph, implies false.

Bart Jacobs Provably Live Exception Handling

slide-24
SLIDE 24

Example Proof

{obs(∅)} let s := new sema in {obs(∅)} {obs({ [s] }) ∗ s.credit} fork {obs({ [s] })} s.V; {obs({ [s] }) ∗ s.credit} {obs(∅)} {obs(∅) ∗ s.credit} s.P {obs(∅)}

Bart Jacobs Provably Live Exception Handling

slide-25
SLIDE 25

Contents

1

Problem and Proposed Fix

2

Verification Approach (Ignoring Exceptions)

3

Verification Approach (With Exceptions)

Bart Jacobs Provably Live Exception Handling

slide-26
SLIDE 26

Formal Programming Language

c ::= · · · | new failbox | x.enter c | throw | forkx c

Bart Jacobs Provably Live Exception Handling

slide-27
SLIDE 27

Formal Programming Language

c ::= · · · | new failbox | x.enter c | throw | forkx c let fb := new failbox in fb.enter ( let s := new sema in forkfb s.V; s.P )

Bart Jacobs Provably Live Exception Handling

slide-28
SLIDE 28

Programming Language Semantics (1/2)

(h, F, T ⊎ { [(f , new failbox; ξ)] })

  • (h, F ⊎ {f → ok}, T ⊎ {

[(f , f ; ξ)] }) (h, F, T ⊎ { [(f , f .enter c; ξ)] })

  • (h, F, T ⊎ {

[(f · f , c; leavef ; ξ)] }) (h, F, T ⊎ { [(f · f

′, v; leavef ; ξ)]

})

  • (h, F, T ⊎ {

[(f

′, v; ξ)]

}) (h, F, T ⊎ { [(f , forkf

′ c; ξ)]

})

  • (h, F, T ⊎ {

[(f , tt; ξ), (f

′, c; leavef

′; done)]

})

Bart Jacobs Provably Live Exception Handling

slide-29
SLIDE 29

Programming Language Semantics (2/2)

(h, F, T ⊎ { [(f , c; ξ)] })

fail

  • (h, F, T ⊎ {

[(f , throw; ξ)] }) (h, F, T ⊎ { [(f , throw; let x := [] in c′; ξ)] })

  • (h, F, T ⊎ {

[(f , throw; ξ)] }) (h, F, T ⊎ { [(f · f , c; ξ)] })

  • (h, F, T ⊎ {

[(f · f , throw; ξ)] }) if F(f ) = failed (h, F, T ⊎ { [(f · f

′, throw; leavef ; ξ)]

})

  • (h, F[f := failed], T ⊎ {

[(f

′, throw; ξ)]

}) (h, F, T ⊎ { [(ǫ, ˜ v; done)] })

  • (h, F, T)

Bart Jacobs Provably Live Exception Handling

slide-30
SLIDE 30

Assertion Language

P ::= b | s.credit | obs(f , S) | P ∗ P

Bart Jacobs Provably Live Exception Handling

slide-31
SLIDE 31

Ghost Reachability

  • bs(f , S) ∧ f(S′) ⊆ f ⊒⊑ obs(f , S ⊎ S′) ∗ S′.credit

Bart Jacobs Provably Live Exception Handling

slide-32
SLIDE 32

Proof Rules

⊢ {true} new sema {w(res) = w ∧ f(res) = f } f(S′) ⊆ f

⊢ {obs(f

′, S′) ∗ P} c {obs(f ′, ∅) ∗ true}

⊢ {obs(f , S ⊎ S′) ∗ P} forkf

′ c {obs(f , S)}

⊢ {true} s.V {s.credit} ⊢ {obs(f(s) · f , S) ∗ s.credit ∧ w(s) < w(S)} s.P {obs(f(s) · f , S)} ⊢ {true} new failbox {true} ⊢ {obs(f · f , S) ∗ P} c {obs(f · f , S′) ∗ Q ∧ f(S′) ⊆ f } ⊢ {obs(f , S) ∗ P} f .enter c {obs(f , S′) ∗ Q} ⊢ {true} throw {false}

Bart Jacobs Provably Live Exception Handling

slide-33
SLIDE 33

Soundness

Lemma (Invariants) ∀t. t.obs(f , S) ⇒ f(S) ⊆ f ∀s. F(s) = ok ⇒ #credits(s) ≤ #obligations(s) + value(s) Theorem (Soundness) If ⊢ {obs(ǫ, ∅)} c {obs(ǫ, ∅) ∗ true}, then c does not deadlock.

Bart Jacobs Provably Live Exception Handling

slide-34
SLIDE 34

Example Proof

{obs(ǫ, ∅)} let fb := new failbox in {obs(ǫ, ∅)} fb.enter ( {obs(fb, ∅)} let s := new sema in {obs(fb, ∅) ∧ f(s) = fb)} {obs(fb, { [s] }) ∗ s.credit} fork {obs(fb, { [s] })} s.V; {obs(fb, { [s] }) ∗ s.credit} {obs(fb, ∅)} {obs(fb, ∅) ∗ s.credit} s.P {obs(fb, ∅)} ) {obs(ǫ, ∅)}

Bart Jacobs Provably Live Exception Handling

slide-35
SLIDE 35

Conclusion

Contributions First sound verification approach for deadlock-freedom of concurrent Java programs with wait-signal-style synchronisation Encoded as API specs into VeriFast for Java; verified the example program Future Work Integration with locks and thread joining Catching exceptions Further experimentation and validation Acknowledgements Thanks to anonymous reviewer for suggesting using semaphores as

  • bligations instead of wait levels!

Bart Jacobs Provably Live Exception Handling