exception handling Bart Jacobs and Frank Piessens Katholieke - - PowerPoint PPT Presentation

exception handling
SMART_READER_LITE
LIVE PREVIEW

exception handling Bart Jacobs and Frank Piessens Katholieke - - PowerPoint PPT Presentation

Failboxes: Provably safe exception handling Bart Jacobs and Frank Piessens Katholieke Universiteit Leuven Overview of Presentation Purpose of exceptions: Dependency safety Conflicts with: Non-exception-safe objects and:


slide-1
SLIDE 1

Failboxes: Provably safe exception handling

Bart Jacobs and Frank Piessens Katholieke Universiteit Leuven

slide-2
SLIDE 2

Overview of Presentation

  • Purpose of exceptions: Dependency

safety

  • Conflicts with:

– Non-exception-safe objects and: – Try-catch – Threads and locks – Thread.stop – Try-finally

  • Solution: Failboxes!
slide-3
SLIDE 3

Overview of Presentation

  • Purpose of exceptions: Dependency

safety

  • Conflicts with:

– Non-exception-safe objects and: – Try-catch – Threads and locks – Thread.stop – Try-finally

  • Solution: Failboxes!
slide-4
SLIDE 4

Problem

Purpose of exceptions = Skipping operations that depend on success

  • f failed operations

(dependency safety)

slide-5
SLIDE 5

Dependency safety: Example 1

int* x = malloc(1024 * sizeof(int)); x[1023] = 42;

slide-6
SLIDE 6

Dependency safety: Example 1

int* x = malloc(1024 * sizeof(int)); x[1023] = 42;

depends on

slide-7
SLIDE 7

Dependency safety: Example 1

int* x = malloc(1024 * sizeof(int)); x[1023] = 42;

depends on

Dependency violation!

x == 0

slide-8
SLIDE 8

Dependency Safety: Example 2

int[] x = new int[1024]; x[1023] = 42;

depends on

slide-9
SLIDE 9

Dependency Safety: Example 2

int[] x = new int[1024]; x[1023] = 42;

depends on

Dependency-safe!

slide-10
SLIDE 10

Problem

Dependency safety = Hard to achieve Non-exception-safe objects Try-catch Threads and locks Thread.stop Try-finally

slide-11
SLIDE 11

Overview of Presentation

  • Purpose of exceptions: Dependency

safety

  • Conflicts with:

– Non-exception-safe objects and: – Try-catch – Threads and locks – Thread.stop – Try-finally

  • Solution: Failboxes!
slide-12
SLIDE 12

Exception Safety

Object is exception-safe  A checked or unchecked exception Leaves the object In a consistent state

slide-13
SLIDE 13

Example: ArrayList

class ArrayList { int count; int[] elems; void add(int x) { count++; if (count > elems.length) { int[] elems2 = new int[count * 2]; System.arraycopy(elems, elems2, 0, 0, elems.length); elems = elems2; } elems[count – 1] = x; } }

Not exception-safe!

slide-14
SLIDE 14

Exception Safety

Hard to achieve

Goal:

Achieve

dependency safety

in the absence of

exception safety

slide-15
SLIDE 15

Overview of Presentation

  • Purpose of exceptions: Dependency

safety

  • Conflicts with:

– Non-exception-safe objects and: – Try-catch – Threads and locks – Thread.stop – Try-finally

  • Solution: Failboxes!
slide-16
SLIDE 16

Example: Interpreter 1

while (true) { String cmd = readCommand(); try { … compute(cmd); … } catch (Throwable t) {t.printStackTrace();} }

slide-17
SLIDE 17

Example: Interpreter 1

while (true) { String cmd = readCommand(); try { … compute(cmd); … } catch (Throwable t) {t.printStackTrace();} }

OK!

slide-18
SLIDE 18

Example: Interpreter 2

ArrayList list = new ArrayList(); while (true) { String cmd = readCommand(); try { … compute(cmd); … … list.add(…); … } catch (Throwable t) {t.printStackTrace();} }

slide-19
SLIDE 19

Example: Interpreter 2

ArrayList list = new ArrayList(); while (true) { String cmd = readCommand(); try { … compute(cmd); … … list.add(…); … } catch (Throwable t) {t.printStackTrace();} }

Bad!

slide-20
SLIDE 20

Proposed Solution: Failboxes

= Language extension

  • API class Failbox:

class Failbox { public Failbox(Failbox parent) { … } public static Failbox getCurrent() { … } public boolean hasFailed() { … } … }

  • new statement:

enter (f) { ... } catch (Throwable t) { … }

slide-21
SLIDE 21

Failboxes

public static void main(String[] args) { … } root failbox

slide-22
SLIDE 22

Failboxes

public static void main(String[] args) { Failbox f = Failbox.getCurrent(); … enter (new Failbox(f)) { … } catch (Throwable t) { … } … } root failbox (= f) child failbox

slide-23
SLIDE 23

Failboxes

public static void main(String[] args) { Failbox f = Failbox.getCurrent(); … enter (new Failbox(f)) { throw new RuntimeException(); … … } catch (Throwable t) { … } … } root failbox (= f) child failbox

slide-24
SLIDE 24

Failboxes

public static void main(String[] args) { Failbox f = Failbox.getCurrent(); … enter (new Failbox(f)) { … enter (f) { … } catch (Throwable t) { throw t; } … } catch (Throwable t) { … } … } root failbox (= f) child failbox

slide-25
SLIDE 25

Failboxes

public static void main(String[] args) { Failbox f = Failbox.getCurrent(); … enter (new Failbox(f)) { … enter (f) { throw new RuntimeException(); } catch (Throwable t) { throw t; } … } catch (Throwable t) { … } … } root failbox (= f) child failbox

slide-26
SLIDE 26

Example: Interpreter 2

ArrayList list = new ArrayList(); while (true) { String cmd = readCommand(); try { … compute(cmd); … … list.add(…); … } catch (Throwable t) { t.printStackTrace(); } } ArrayList list = new ArrayList(); Failbox f = Failbox.getCurrent(); while (true) { String cmd = readCommand(); enter (new Failbox(f)) { … compute(cmd); … … enter (f) { list.add(…); } catch (Throwable t) { throw t; } … } catch (Throwable t) { t.printStackTrace(); } }

slide-27
SLIDE 27

Example: Interpreter 2

ArrayList list = new ArrayList(); Failbox f = Failbox.getCurrent(); while (true) { String cmd = readCommand(); enter (new Failbox(f)) { … compute(cmd); … … enter (f) { list.add(…); } catch (Throwable t) { throw t; } … } catch (Throwable t) { t.printStackTrace(); } } root failbox (= f) child failbox

slide-28
SLIDE 28

Syntactic Sugar

try { block1 } catch (Throwable t) { block2 } enter (f) { block } enter (new Failbox(Failbox.getCurrent())) { block1 } catch (Throwable t) { block2 } enter (f) { block } catch (Throwable t) { throw t; }

slide-29
SLIDE 29

Example: Interpreter 2

ArrayList list = new ArrayList(); Failbox f = Failbox.getCurrent(); while (true) { String cmd = readCommand(); try { … compute(cmd); … … enter (f) { list.add(…); } … } catch (Throwable t) { t.printStackTrace(); } } root failbox (= f) child failbox

slide-30
SLIDE 30

Syntactic Sugar (2)

failboxed class C { void foo() { … } void bar() { … } } class C { Failbox f = Failbox.getCurrent(); void foo() { enter (f) { … } } void bar() { enter (f) { … } } }

slide-31
SLIDE 31

Example: Interpreter 2

ArrayList list = new ArrayList(); while (true) { String cmd = readCommand(); try { … compute(cmd); … … list.add(…); … } catch (Throwable t) { t.printStackTrace(); } } root failbox (= f) child failbox

slide-32
SLIDE 32

Overview of Presentation

  • Purpose of exceptions: Dependency

safety

  • Conflicts with:

– Non-exception-safe objects and: – Try-catch – Threads and locks – Thread.stop – Try-finally

  • Solution: Failboxes!
slide-33
SLIDE 33

Example: Concurrent Interpreter

while (true) { String cmd = readCommand(); new Thread() { public void run() { … compute(cmd); … } }.start(); }

slide-34
SLIDE 34

Example: Concurrent Interpreter

while (true) { String cmd = readCommand(); new Thread() { public void run() { … compute(cmd); … } }.start(); }

OK!

slide-35
SLIDE 35

Example: Concurrent Interpreter 2

ArrayList list = new ArrayList(); while (true) { String cmd = readCommand(); new Thread() { public void run() { … compute(cmd); … … synchronized (list) { list.add(…); } … } }.start(); }

slide-36
SLIDE 36

Example: Concurrent Interpreter 2

ArrayList list = new ArrayList(); while (true) { String cmd = readCommand(); new Thread() { public void run() { … compute(cmd); … … synchronized (list) { list.add(…); } … } }.start(); }

Bad!

slide-37
SLIDE 37

Solution: Failboxes

Failbox f = Failbox.getCurrent(); ArrayList list = new ArrayList(); while (true) { String cmd = readCommand(); new Thread() { public void run() { … compute(cmd); … … synchronized (list) { enter (f) { list.add(…); } } … } }.start(); }

slide-38
SLIDE 38

Failboxes and Threads

void run() { … synchronized (o) { enter (f) { ... } } ... } void run() { … synchronized (o) { enter (f) { ... } } ... }

main failbox (= f) job 2 failbox job 1 failbox

slide-39
SLIDE 39

Failboxes and Threads

void run() { throw new RTE(); synchronized (o) { enter (f) { ... } } ... } void run() { … synchronized (o) { enter (f) { ... } } ... }

main failbox (= f) job 2 failbox job 1 failbox

slide-40
SLIDE 40

Failboxes and Threads

void run() { … synchronized (o) { enter (f) { throw new RTE(); } } ... } void run() { … synchronized (o) { enter (f) { ... } } ... }

main failbox (= f) job 2 failbox job 1 failbox

slide-41
SLIDE 41

The need for Fail Fast

Failbox f = Failbox.getCurrent(); ArrayList list = new ArrayList(); while (true) { String cmd = readCommand(); new Thread() { public void run() { … compute(cmd); … … synchronized (list) { enter (f) { list.add(…); } } … } }.start(); }

slide-42
SLIDE 42

Asynchronous failure: Fail Fast

void run() { … synchronized (o) { enter (f) { throw new RTE(); } } ... } public static void main(String[] args) { … serverSocket.accept(); serverSocket.accept(); serverSocket.accept(); serverSocket.accept(); serverSocket.accept(); serverSocket.accept(); serverSocket.accept(); serverSocket.accept(); serverSocket.accept(); serverSocket.accept(); }

main failbox (= f) job 1 failbox async signal

slide-43
SLIDE 43

Solution: Failboxes

Failbox f = Failbox.getCurrent(); ArrayList list = new ArrayList(); while (true) { String cmd = readCommand(); new Thread() { public void run() { … compute(cmd); … … synchronized (list) { enter (f) { list.add(…); } } … } }.start(); }

slide-44
SLIDE 44

Overview of Presentation

  • Purpose of exceptions: Dependency

safety

  • Conflicts with:

– Non-exception-safe objects and: – Try-catch – Threads and locks – Thread.stop – Try-finally

  • Solution: Failboxes!
slide-45
SLIDE 45

Example: Concurrent Interpreter

while (true) { String cmd = readCommand(); new Thread() { public void run() { … compute(cmd); … } }.start(); }

slide-46
SLIDE 46

Example: Concurrent Interpreter

ArrayList<Thread> jobs = new ArrayList<Thread>(); while (true) { String cmd = readCommand(); if (cmd.equals(“cancelAll”)) { for (Thread t : jobs) t.stop(); continue; } Thread t = new Thread() { public void run() { … compute(cmd); … } }; jobs.add(t); t.start(); }

slide-47
SLIDE 47

Example: Concurrent Interpreter

ArrayList<Thread> jobs = new ArrayList<Thread>(); while (true) { String cmd = readCommand(); if (cmd.equals(“cancelAll”)) { for (Thread t : jobs) t.stop(); continue; } Thread t = new Thread() { public void run() { … compute(cmd); … } }; jobs.add(t); t.start(); }

OK!

slide-48
SLIDE 48

Example: Concurrent Interpreter

ArrayList<Thread> jobs = new ArrayList<Thread>(); ArrayList list = new ArrayList(); while (true) { String cmd = readCommand(); if (cmd.equals(“cancelAll”)) { for (Thread t : jobs) t.stop(); continue; } Thread t = new Thread() { public void run() { … compute(cmd); … … synchronized (list) { list.add(…); } … } }; jobs.add(t); t.start(); }

slide-49
SLIDE 49

Example: Concurrent Interpreter

ArrayList<Thread> jobs = new ArrayList<Thread>(); ArrayList list = new ArrayList(); while (true) { String cmd = readCommand(); if (cmd.equals(“cancelAll”)) { for (Thread t : jobs) t.stop(); continue; } Thread t = new Thread() { public void run() { … compute(cmd); … … synchronized (list) { list.add(…); } … } }; jobs.add(t); t.start(); }

Bad!

slide-50
SLIDE 50

Example: Concurrent Interpreter

ArrayList<Thread> jobs = new ArrayList<Thread>(); ArrayList list = new ArrayList(); Failbox f =

Failbox.getCurrent();

while (true) { String cmd = readCommand(); if (cmd.equals(“cancelAll”)) { for (Thread t : jobs) t.stop(); continue; } Thread t = new Thread() { public void run() { … compute(cmd); … … synchronized (list) { enter (f) { list.add(…); } } … } }; jobs.add(t); t.start(); }

slide-51
SLIDE 51

Example: Concurrent Interpreter

ArrayList<Thread> jobs = new ArrayList<Thread>(); ArrayList list = new ArrayList(); Failbox f = Failbox.getCurrent(); while (true) { String cmd = readCommand(); if (cmd.equals(“cancelAll”)) { for (Thread t : jobs) t.stop(); continue; } Thread t = new Thread() { public void run() { … compute(cmd); … … synchronized (list) { enter (f) { list.add(…); } } … } }; jobs.add(t); t.start(); }

Safe, but not OK

slide-52
SLIDE 52

Example: Concurrent Interpreter

ArrayList<Failbox> jobs = new ArrayList<Failbox>(); ArrayList list = new ArrayList(); Failbox f = Failbox.getCurrent(); while (true) { String cmd = readCommand(); Failbox j = new Failbox(null); if (cmd.equals(“cancelAll”)) { for (Failbox j : jobs) j.cancel(); continue; } Thread t = new Thread() { public void run() { … compute(cmd); … … synchronized (list) { enter (f) { list.add(…); } } … } }; jobs.add(j); t.startInFailbox(j); }

slide-53
SLIDE 53

Example: Concurrent Interpreter

ArrayList<Failbox> jobs = new ArrayList<Failbox>(); ArrayList list = new ArrayList(); Failbox f = Failbox.getCurrent(); while (true) { String cmd = readCommand(); Failbox j = new Failbox(null); if (cmd.equals(“cancelAll”)) { for (Failbox j : jobs) j.cancel(); continue; } Thread t = new Thread() { public void run() { … compute(cmd); … … synchronized (list) { enter (f) { list.add(…); } } … } }; jobs.add(j); t.startInFailbox(j); }

OK!

slide-54
SLIDE 54

The problem with Thread.stop

void run() { … synchronized (o) { enter (f) { ... } } ... } public static void main(String[] args) { … t.stop(); }

main failbox (= f) job 1 failbox Async stop signal Fail Fast: Stop f

slide-55
SLIDE 55

Fail Fast for cancellation

void run() { … ... } public static void main(String[] args) { … j.cancel(); }

main failbox (= f) job 1 failbox (= j) async signal: Stop j

slide-56
SLIDE 56

Fail Fast for cancellation

void run() { … synchronized (o) { enter (f) { ... } } ... } public static void main(String[] args) { … j.cancel(); }

main failbox (= f) job 1 failbox (= j) async signal: Stop j

slide-57
SLIDE 57

Example: Concurrent Interpreter

ArrayList<Failbox> jobs = new ArrayList<Failbox>(); ArrayList list = new ArrayList(); Failbox f = Failbox.getCurrent(); while (true) { String cmd = readCommand(); Failbox j = new Failbox(null); if (cmd.equals(“cancelAll”)) { for (Failbox j : jobs) t.cancel(); continue; } Thread t = new Thread() { public void run() { … compute(cmd); … … synchronized (list) { enter (f) { list.add(…); } } … } }; jobs.add(t); t.startInFailbox(j); }

OK!

slide-58
SLIDE 58

Overview of Presentation

  • Purpose of exceptions: Dependency

safety

  • Conflicts with:

– Non-exception-safe objects and: – Try-catch – Threads and locks – Thread.stop – Try-finally

  • Solution: Failboxes!
slide-59
SLIDE 59

Example: Interpreter 1

while (true) { String cmd = readCommand(); try { … compute(cmd); … } catch (Throwable t) {t.printStackTrace();} }

slide-60
SLIDE 60

Example: Interpreter 2

ArrayList list = new ArrayList(); while (true) { String cmd = readCommand(); try { … compute(cmd); … … list.add(…); … } catch (Throwable t) {t.printStackTrace();} }

slide-61
SLIDE 61

Example: Tidy Interpreter

ArrayList list = new ArrayList(); while (true) { String cmd = readCommand(); try { … list.add(x); try { … compute(cmd); … list.sort(); … } finally { list.remove(x); } … } catch (Throwable t) {t.printStackTrace();} }

slide-62
SLIDE 62

Example: Tidy Interpreter

ArrayList list = new ArrayList(); while (true) { String cmd = readCommand(); try { … list.add(x); try { … compute(cmd); … list.sort(); … } finally { list.remove(x); } … } catch (Throwable t) {t.printStackTrace();} }

Bad!

slide-63
SLIDE 63

Failboxes for safe compensation

ArrayList list = new ArrayList(); Failbox f = Failbox.getCurrent(); while (true) { String cmd = readCommand(); try { … Failbox child = Failbox.getCurrent(); enter (f) { list.add(x); enter (child) { … compute(cmd); … enter (f) { list.sort(); } … } catch (Throwable t) { } list.remove(x); } … } catch (Throwable t) {t.printStackTrace();} }

OK!

slide-64
SLIDE 64

Failboxes for safe compensation

public static void main(String[] args) { Failbox f = Failbox.getCurrent(); … try { … Failbox child = Failbox.getCurrent(); enter (f) { … // allocate enter (child) { throw new RuntimeException(); } catch (Throwable t) { } … // clean up } … } catch (Throwable t) { … } … }

root failbox (= f) child failbox (= child)

slide-65
SLIDE 65

Other goodies

  • In paper:

– Separation logic proof rules – Implementation issues

  • On website:

– Prototype implementations as C#, Java libraries – Machine-checked soundness proof in Coq – Prototype program verifier

slide-66
SLIDE 66

Related work

  • Languages as operating systems (e.g. Luna, DrScheme)
  • Async exceptions in Haskell
  • .NET Framework 2.0 reliability features
  • Killing applets [Rudys et al. 2001]
  • Transactions
  • Compensation stacks [Weimer et al. 2004]
  • Erlang
  • Eiffel SCOOP
  • Class handlers [Dony 1990]

Failboxes:

  • Minimal programming overhead
  • Minimal reasoning overhead
  • Minimal run-time overhead
  • Compositional
slide-67
SLIDE 67

Future work

  • Assessing applicability
  • Assessing usability
  • Inferring enter blocks
  • Application to async & callback patterns
slide-68
SLIDE 68

Conclusion

  • Purpose of exceptions: Dependency

safety

  • Conflicts with:

– Non-exception-safe objects and: – Try-catch – Threads and locks – Thread.stop – Try-finally

  • Solution: Failboxes!