Upload
tallis
View
31
Download
1
Embed Size (px)
DESCRIPTION
User-defined type checkers for error detection and prevention in Java. Michael D. Ernst MIT Computer Science & AI Lab http://pag.csail.mit.edu/jsr308/. Code without type qualifiers. class DAG { Set edges; // ... List getNeighbors( Vertex v) { - PowerPoint PPT Presentation
Citation preview
User-defined type checkers for error detection and prevention
in JavaMichael D. Ernst
MIT Computer Science & AI Labhttp://pag.csail.mit.edu/jsr308/
Code without type qualifiers
class DAG { Set<Edge> edges;
// ...
List<Vertex> getNeighbors( Vertex v) { List<Vertex> neighbors = new LinkedList<Vertex>(); for (Edge e : edges) if (e.from() == v) neighbors.add(e.to()); return neighbors; }}
@NonNull type qualifier@NonNullDefaultclass DAG { Set<Edge> edges;
// ...
List<Vertex> getNeighbors( Vertex v) { List<Vertex> neighbors = new LinkedList<Vertex>(); for (Edge e : edges) if (e.from() == v) neighbors.add(e.to()); return neighbors; }}
@NonNull type qualifier@NonNullDefaultclass DAG { @NonNull Set<@NonNull Edge> edges;
// ...
@NonNull List<@NonNull Vertex> getNeighbors( @NonNull Vertex v) { List<Vertex> neighbors = new LinkedList<Vertex>(); for (Edge e : edges) if (e.from() == v) // OK neighbors.add(e.to()); // OK return neighbors; }}
@Interned type qualifier@NonNullDefaultclass DAG { Set<Edge> edges;
// ...
List<Vertex> getNeighbors(@Interned Vertex v) { List<Vertex> neighbors = new LinkedList<Vertex>(); for (Edge e : edges) if (e.from() == v) // OK neighbors.add(e.to()); return neighbors; }}
@ReadOnly type qualifier@NonNullDefaultclass DAG { Set<Edge> edges;
// ...
List<Vertex> getNeighbors(@ReadOnly Vertex v) @ReadOnly { List<Vertex> neighbors = new LinkedList<Vertex>(); for (Edge e : edges) if (e.from() == v) neighbors.add(e.to()); return neighbors; }}
Using a checker• Write annotations on the code
– Or use an inference tool• Compiler plugin for javac javac -processor NonnullChecker MyFile.java• Produces additional errors and warnings
– All existing Java checks are performed• Type-system-specific checks
– For NonNull: dereferences– For Interned: equality
• Error to assign supertype to subtype: myObject = myNonNullObject; // OK myInternedObject = myObject; // error myObject = myReadOnlyObject; // error
– Similarly for arguments, returns, overriding, …
Outline• NonNull checker• Interned checker• Javari checker• IGJ checker• Creating your own checker
NonNull checker• Problem: NullPointerExceptions• Example:
Object obj; // might be null@NonNull Object nnobj; // never nullnnobj.toString(); // OKobj.toString(); // possible NPEobj = ...; // OKnnobj = obj; // nnobj may become null
• Type system:
NonNull case study• Programs:
– Annotation file utilities (5 KLOC)– Lookup (4 KLOC, twice)– NonNull checker (1 KLOC)– Checkers framework (5 KLOC)
• Two different defaults: NonNull and Nullable
• Annotations with & without checker available
NonNull results• 1 annotation per 50 lines of code
– Inference tools exist (for NonNull and other qualifiers)• 44 errors
– if (x.y().z()) { somethingOptional(); }where no work need be done if x.y() is null
• 83 application invariants– @NonNull indicates whether a variable may be null– @NonNull cannot indicate conditions that hold when a
variable is null• entry_re == null iff exit_re == null
• 43 tool weaknesses (many already fixed)
Comparison with other toolsProgram to be checked: Lookup (4KLOC)
Other tools also find non-NPE bugsTo reduce false positives, they discard many
warnings
Our checker 7 errors (every error!) 7 false pos.
FindBugs 1 warning: dead code 1 false pos.
JLint 0 8PMD 0 0
Good defaults reduce user effort• Nullable default:
– Dictated by backward compatibility– Many instances of @NonNull – too verbose– Flow-sensitive analysis inferred many NonNull types
for local variables, reducing annotation burden• NonNull default
– Less verbose in signatures• Draws attention to exceptions rather than the rule
– More annotations in method bodies• Our system: Nullable only for local variables
– Not for generics on local variables– An alternative to type inference; effect may be similar
Interned checker• Interning (aka hash-consing, canonicalization)
chooses a canonical representative– Saves memory– Permits use of == for comparisons
• Problem: Equality errors• Example:
String s;@Interned String is, is2;... is = myString.intern() ... // OKif (is == is2) { ... } // OKif (s == is) { ... } // unsafe equalityis = s; // unsafe assignment
Interned case study• Program: Daikon (250 KLOC)
– Daikon’s key scalability problem is memory– 1170 lines of code/comment refer to interning
• 72% of files have none, 87% have 0, 1, or 2– 200 run-time assertions– Emacs plug-in for String equality checking
• 127 annotations in 11 files (12KLOC)
Interned results• 9 errors
– Missing calls to intern• 2 performance bugs
– Unnecessary interning in inner loop of file reading• 1 design flaw
– VarInfoName is not interned within its implementation, but all escaping objects are
– Too hard to understand complex interning• 14 false positives (used @SuppressWarnings)
Javari checker• Problem: Unintended side effects (mutations)• Example:
<E> List<E> sort(@ReadOnly List<E> arg) { ... // swap two elements E tmp = arg.get(i); arg.put(i, arg.get(j)); // illegal mutation arg.put(j, tmp); // illegal mutation}
• Type system:
Javari case study• Programs (8KLOC)
– JOlden benchmarks– Javari checker– Some JDK classes
Javari results• Mutability bug in Javari checker
– Global variable indicating checker state was set on entering an inner class, not reset on exiting
– The bug-fix allocates a new object instead• 3 false positives due to varargs
– void format(Object...) { … }
IGJ checker• Problem: Unintended side effects (mutations)• Type system:
– ReadOnly: Reference immutability (aliases may modify)– Immutable: Object immutability (object cannot change)
• Syntax uses annotations, not generics
IGJ case study• Programs (128KLOC)
– JOlden benchmarks– htmlparser library– tinySQL library– SVNKit subversion client– IGJ checker
• 4760 annotations (62133 possible locations)
IGJ results• Representation exposure errors• Constructors that left object in inconsistent state• 26 false positives (arrays, varargs, casting)• In SVNKit:
– some getters have side effects– some setters have no side effects
• Used both reference and object immutability• Preferred Annotation IGJ to original dialect: arrays, and
– List<ReadOnly, Date<Mutable>>– @ReadOnly List<@Mutable Date>
• More opportunities for immutability in new code than old
Writing your own checker• Base checker performs all standard
checks (assignment, method arguments)• Override only a couple methods, for
special rules– For NonNull: dereferences– For Interned: equality
• Check what you want:– General properties (tainting)– Project-specific (string formatting)
JSR 308: Annotation on Java types
• Permits annotations in new locationsList<@NonNull String> myList;class Properties extends @Immutable Map {…}
• Planned for inclusion in Java 7• Implementation is backwards compatible:
– Write annotations in comments: List</*@NonNull*/ String> myList; /*@NonNull*/ String s;– Compiles with any Java compiler
Pluggable type system benefits
• Easy to use• Scalable• Reveals errors• Prevents even more errors
• Download the checkers from http://pag.csail.mit.edu/jsr308/– Prerelease of annotation extensions in Java 7
• Backward-compatible implementation– Includes inference tools for some type checkers– Includes a framework for writing new checkers