Top Banner
Finding and Preventing Run- Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu
46

Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Dec 28, 2015

Download

Documents

Magnus McKenzie
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Finding and Preventing Run-Time Error Handling MistakesWestley WeimerGeorge C. NeculaUniversity of California, Berkeley{weimer,necula}@cs.berkeley.edu

Page 2: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Handling Errors is Difficult

Writing solid error-handling code is hard1) We have a mistake-finding analysis

o And find 800 mistakes in 4M LOC (Java)o We characterize these mistakes

2) Propose a new language featureo Existing language features: insufficiento Track obligations at run-timeo Support it by case studies

Page 3: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Defining Terms

Run-Time Errors: Network problems, DB access errors, OS

resource exhaustion, … Typical Error-Handling:

Resend packet, show dialog box to user, …

Application-specific Error-Handling Handling Mistakes:

One example: a network error occurs and the program forgets to release a database lock with an external shared database, …

Page 4: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Cleanup in Practice

Most common exception handlersDo NothingPrint Stack Trace, Abort Program

High-level invariants should be restoredAside from “handling” the error, the

program should clean up after itself Often this does not happen in practice:

Considering all (error) paths is hard!

Page 5: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Normal Execution Path// Copy to destinationFile without doing any byte conversion.private static void _binaryCopyURLToFile(URL sourceURL, File destinationFile) throws IOException { BufferedInputStream input = new BufferedInputStream(sourceURL.openStream()); BufferedOutputStream output = new BufferedOutputStream( new FileOutputStream(destinationFile)); // The resource pointed to might be a pdf file, which // is binary, so we are careful to read it byte by // byte and not do any conversions of the bytes. int c; while (( c = input.read()) != -1)

output.write(c); output.close(); input.close();} // line 294, ptolemy2’s JNLPUtilities.java

Page 6: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Error Paths - Hazards// Copy to destinationFile without doing any byte conversion.private static void _binaryCopyURLToFile(URL sourceURL, File destinationFile) throws IOException { BufferedInputStream input = new BufferedInputStream(sourceURL.openStream()); BufferedOutputStream output = new BufferedOutputStream( new FileOutputStream(destinationFile)); // The resource pointed to might be a pdf file, which // is binary, so we are careful to read it byte by // byte and not do any conversions of the bytes. int c; while (( c = input.read()) != -1)

output.write(c); output.close(); input.close();} // line 294, ptolemy2’s JNLPUtilities.java

Page 7: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Fix It With Try-Finally// Copy to destinationFile without doing any byte conversion.private static void _binaryCopyURLToFile(…) throws … { BufferedInputStream input; BufferedOutputStream output; input = new BufferedInputStream(…); try { output = new BufferedOutputStream(…); try {

// The resource pointed to might be a pdf file, which// is binary, so we are careful to read it byte by// byte and not do any conversions of the bytes.int c;while (( c = input.read()) != -1) output.write(c);

} finally { output.close(); } } finally { input.close(); } }

Page 8: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Fix It With Run-Time Checks

private static void _binaryCopyURLToFile(…) throws … { BufferedInputStream input = null; BufferedOutputStream output = null; try { input = new BufferedInputStream(sourceURL.openStream()); output = new BufferedOutputStream( new FileOutputStream(destinationFile)); // The resource pointed to might be a pdf file, … int c; while (( c = input.read()) != -1) { output.write(c); } finally { if (input != null) then try { input.close(); } catch (Exception E) { } if (output != null) then try { output.close(); } catch (Exception E) { } } }

Page 9: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Fix It With Flags

int f = 0; // flag tracks progresstry { openX(); f = 1; work(); openY(); f = 2; work(); openZ(); f = 3; work(); } finally { switch (f) { // note fall-through! case 3: try { closeZ(); } catch (Exception e) {} case 2: try { closeY(); } catch (Exception e) {} case 1: try { closeX(); } catch (Exception e) {} }}

Page 10: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Fix It With Flags (Ouch!)

int f = 0; // flag tracks progresstry { openX(); f = 1; work(); if (…) { didY = true; openY(); f = 2; } work(); openZ(); f = 3; work(); } finally { switch (f) { // note fall-through! case 3: try { closeZ(); } catch (Exception e) {} case 2: if (didY) { try { closeY(); } catch … } case 1: try { closeX(); } catch (Exception e) {} }}

Page 11: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Outline

1) Background

2) Bug-Finding Static Analysis

3) Proposed Language Feature

Page 12: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Locating Handling Mistakes

We consider four generic resourcesSockets, files, streams, database locksFrom a survey of Java code

Program should release them along all paths, even those with run-time errors

Run-time errors are rare … So use a static analysis to find

mistakes

Page 13: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Static Dataflow Analysis

Exceptions and run-time errors correlate

Fault model:A called method can terminate normally

or raise any of its declared exceptions Build control-flow graph Symbolically execute each method Abstracting away most data values But tracking outstanding resources

Page 14: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Analysis Example Program

try {Socket s = new Socket();s.send(“GET index.html”);s.close();

} finally { } // bug!

Page 15: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Analysis Example

startnew socket

send

close

end

Page 16: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Analysis Example

startnew socket

send

close

end

{ }

Page 17: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Analysis Example

startnew socket

send

close

end

{ }

{ socket }

Page 18: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Analysis Example

startnew socket

send

close

end

{ }

{ socket }

{ }

Page 19: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Analysis Example

startnew socket

send

close

end

{ }

{ socket }

{ } { socket }

Page 20: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Analysis Example

startnew socket

send

close

end

{ }

{ socket }

{ } { socket }{ socket }

Page 21: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Analysis Example

startnew socket

send

close

end

{ }

{ socket }

{ } { socket }{ socket }

{ }

Page 22: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Analysis Example

startnew socket

send

close

end

{ }

{ socket }

{ } { socket }{ socket }

{ }{ }

Page 23: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Example Bug Report

startnew socket

send

close

end

{ }

{ socket }

{ } { socket }{ socket }

{ }{ }

Page 24: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

False Positives

Simple analysis gives false positivesOf 100 error reports70 would be real bugs30 would be false positives

Each false positive is one of these:if (sock != null) sock.close();socket_field_we_close_later = sock;return sock;

Page 25: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Bug Reporting and Filtering

Filter out reports with those 3 formsIntroduces false negativesFor every 100 real bugs reported There are ~10 real bugs we miss

Removes all false positives Manually verify the rest as bugs

Page 26: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Analysis ResultsProgram Name Lines of

CodeMethods withError-Handling

Mistakes

Forgotten Resources

hibernate2 57k 13 DB

jaxme 58k 6 File

axion 65k 15 File

hsqldb 71k 18 DB, Strm

cayenne 86k 7 File

sablecc 99k 3 Strm

jboss 107k 40 DB, Strm

mckoi-sql 118k 37 Strm, DB

portal 162k 39 DB, File

pcgen 178k 17 File

compiere 230k 322 DB

org.aspectj 319k 27 File, Strm

ptolemy2 362k 27 File, Strm

eclipse 1.6M 126 Strm, File

… 13 others … 347k 121 File, DB

Total 3.9M 818 File, DB

Page 27: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Characterizing Mistakes

Model: aX must be followed by cX1) try { a1; } finally { c1; } ; a1 ; c1; 2) try { a1; a2; } finally { c2; c1; } 3) try { a1; a1; } finally { c1; }4) for (…) { a1; work; c1; } As well as tricky flag-work for

releasing resources early …

Page 28: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Outline

1) Background

2) Bug-Finding Static Analysis

3) Proposed Language Feature

Page 29: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Destructors (C++, C#, …)

Great for stack-allocated objects Error-handling contains arbitrary

codeExample adapted from code which

has 17 unique cleanups, one 34 lines long

try { StartDate = new Date(); // a1try { StartLSN = log.getLastLSN();

// a2work(1); try { DB.getWriteLock();

// a3work(2); // a3

} finally { DB.releaseWriteLock();// c3

work(3); }// c3

} finally { StartLSN = -1; } // c2} finally { StartDate = null; } // c1

Page 30: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Finalizers (Java, …)

Called by the garbage collector Too late!

No ordering guarantees Socket sock = new Socket(); Stream strm = new Stream(sock); sock.finalize may be called before

strm.finalize Programs do not use them

Only 13 user-defined ones in 4M LOC Not all SDKs use them for key resources

Page 31: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Feature Motivation

Avoid forgetting obligations No static program restrictions Optional lexical scoping Optional early or arbitrary cleanup Database / Workflow notions:

Either my actions all succeed (a1 a2 a3)

Or they rollback (a1 a2 error c2 c1)

Page 32: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Compensation Stacks

Store cleanup code in run-time stacksFirst-class objects, pass them around

After “action” succeeds, push “cleanup”“action” and “cleanup” are arbitrary code

(anonymous functions) Pop all cleanup code and run it (LIFO)

When the stack goes out of scopeAt an uncaught exceptionEarly, or when the stack is finalized

Page 33: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Compensation Concepts

Generalized destructors No made-up classes for local cleanup Can be called early, automatic

bookkeeping Can have multiple stacks

• e.g., one for each request in a webserver Annotate interfaces to require them

Cannot make a new socket without putting “this.close()” on a stack of obligations

Will be remembered along all paths Details in paper …

Page 34: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Cinderella Story

CompensationStack CS = new CompensationStack();try { Input in; Output out; Input in = new Input(src); Output out = new Output(dst); while (( x = in.read()) != -1) out.write(x); out.close(); in.close(); return 0;} finally { CS.runAll(); }

Page 35: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

“Assembly Language”

CompensationStack CS = new CompensationStack();try { Input in; Output out; compensate { in = new Input(src); } with (CS) { in.close(); } compensate { out = new Output(dst); } with (CS) { out.close(); } while (( x = in.read()) != -1) out.write(x); return 0;} finally { CS.runAll(); }

Page 36: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

With Annotated Interfaces

CompensationStack CS = new CompensationStack();try {

Input in = new Input(CS,src); Output out = new Output(CS,dst); while (( x = in.read()) != -1) out.write(x); return 0;} finally { CS.runAll(); }

Page 37: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Using Most Recent Stack

CompensationStack CS = new CompensationStack();try {

Input in = new Input(src); Output out = new Output(dst); while (( x = in.read()) != -1) out.write(x); return 0;} finally { CS.runAll(); }

Page 38: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Using “Current Scope Stack”

Input in = new Input(src); Output out = new Output(dst); while (( x = in.read()) != -1) out.write(x); return 0;

Page 39: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Cinderella 2 (Before)

int f = 0; // flag tracks progresstry { openX(); f = 1; work(); if (…) { didY = true; openY(); f = 2; } work(); openZ(); f = 3; work(); } finally { switch (f) { // note fall-through! case 3: try { closeZ(); } catch (Exception e) {} case 2: if (didY) { try { closeY(); } catch … } case 1: try { closeX(); } catch (Exception e) {} }}

Page 40: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Cinderella 2 (After)

compensate { openX(); }with { closeX(); }work(); if (…) compensate { openY(); }

with { closeY(); }work();compensate { openZ(); }with { closeZ(); }work();// using the “current scope stack” by default

Page 41: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Case Studies

Extend Java with compensation stacks

Annotate key interfaces (File, DB, …) Annotate existing programs to use

compensation stacksFor library resourcesAnd for unique cleanup actionsNo new error handling!

Page 42: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Sun’s petstore

“Amazon.com lite” plus inventory Raises 150 exceptions over 3,900

requests Avg Response: 52.06ms (std dev 100ms)

34,608 lines of Java, 123 change sites Two hours of work Three simultaneous resources (DB)

Results: 168 lines shorter (~0.5%) 0 such exceptions over 3,900 requests Avg Response: 43.44ms (std dev 77ms)

Page 43: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Conclusion It is difficult to write error-handling code1) We have an analysis for finding mistakes

Dataflow analysis plus fault model We found 800 mistakes in 4M LOC (Java) We characterize these mistakes

• Programmers forget some paths

2) We propose a new feature Keep stacks of obligations at run-time Existing language features are insufficient

• Timing, bookkeeping, repeated logic … And back it up with case studies

Page 44: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Any Questions?

I encourage difficult questions.

Page 45: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Aspects

We could perhaps have used AoP to do the source-to-source transform

When we started this research, tools (e.g., AspectJ) weren’t well-suited for adding, removing and editing entire lexical scoping levels

Aspect tools also seemed like the wrong framework for a path-sensitive dataflow analysis

However, using the results of this analysis you could easily roll your own “compensation stack”-like mechanism with AoP

Page 46: Finding and Preventing Run-Time Error Handling Mistakes Westley Weimer George C. Necula University of California, Berkeley {weimer,necula}@cs.berkeley.edu.

Do Developers Care?

Beyond the scope of this work, but … ptolemy2 Developer Rating of Reported

Bugs: 11% “in tutorials or third-party code”44% 3/5 “little used or experimental

code”19% 4/5 “definitely a bug in code that is

used more often”26% 5/5 “definitely a bug in code that is

used often”