Detecting and preventing null pointer errors with pluggable type-checking

Similar documents
Detecting and preventing null pointer errors with pluggable type-checking

CSE 331 Software Design and Implementation. Lecture 16 Checker Framework

Lecture 19 Checker Framework

Using Type Annotations to Improve Your Code

Code verification. CSE 331 University of Washington. Michael Ernst

The Checker Framework: pluggable static analysis for Java

Preventing Errors Before They Happen The Checker Framework

Preventing Errors Before They Happen The Checker Framework

Javarifier: inference of reference immutability

JSR-305: Annotations for Software Defect Detection

Status Report. JSR-305: Annotations for Software Defect Detection. William Pugh Professor

Outline. Java Models for variables Types and type checking, type safety Interpretation vs. compilation. Reasoning about code. CSCI 2600 Spring

Cascade: A Universal Programmer-assisted Type Qualifier Inference Tool

The Checker Framework Manual

Data abstractions: ADTs Invariants, Abstraction function. Lecture 4: OOP, autumn 2003

Java: advanced object-oriented features

Program Verification (6EC version only)

5) Attacker causes damage Different to gaining control. For example, the attacker might quit after gaining control.

CSE341: Programming Languages Lecture 11 Type Inference. Dan Grossman Spring 2016

Topic 9: Type Checking

Topic 9: Type Checking

Semantic Analysis. Outline. The role of semantic analysis in a compiler. Scope. Types. Where we are. The Compiler Front-End

University of Washington CSE 331 Software Design & Implementation Spring Final exam. Monday, June 10, 2013

CSE 331 Software Design and Implementation. Lecture 14 Generics 2

Advances in Programming Languages

A Type System for Regular Expressions

Topics Covered Thus Far CMSC 330: Organization of Programming Languages

Functional Programming in Java. CSE 219 Department of Computer Science, Stony Brook University

JML tool-supported specification for Java Erik Poll Radboud University Nijmegen

Equality. Michael Ernst. CSE 331 University of Washington

The role of semantic analysis in a compiler

Announcements. Lecture 14 Generics 1. Announcements. CSE 331 Software Design and Implementation. Leah Perlmutter / Summer 2018

CSE 331 Software Design and Implementation. Lecture 14 Generics 1

CSE331 Winter 2014, Midterm Examination February 12, 2014

CSE 331 Software Design and Implementation. Lecture 14 Generics 2

Exercise 10 Object Structures and Aliasing November 27, 2015

CS6202: Advanced Topics in Programming Languages and Systems Lecture 0 : Overview

Outline. Introduction Concepts and terminology The case for static typing. Implementing a static type system Basic typing relations Adding context

Principles of Software Construction: Objects, Design and Concurrency. Static Analysis. toad Spring 2013

ESC/Java2 Use and Features David Cok, Joe Kiniry, Erik Poll Eastman Kodak Company, University College Dublin, and Radboud University Nijmegen

ESC/Java2 Warnings David Cok, Joe Kiniry, and Erik Poll Eastman Kodak Company, University College Dublin, and Radboud University Nijmegen

CSE 331 Final Exam 6/5/17. Name UW ID#

CSE 331 Software Design & Implementation

Announcements. Lecture 15 Generics 2. Announcements. Big picture. CSE 331 Software Design and Implementation

CSE 331 Software Design and Implementation. Lecture 15 Generics 2

ESC/Java2 Use and Features

Lecture 5 Representation Invariants

Pierce Ch. 3, 8, 11, 15. Type Systems

ESC/Java2 Use and Features

CSE 331 Software Design & Implementation

CSE 331 Midterm Exam Sample Solution 2/18/15

Expected properties of equality

Type Checking and Type Inference

Semantic Analysis. How to Ensure Type-Safety. What Are Types? Static vs. Dynamic Typing. Type Checking. Last time: CS412/CS413

CS558 Programming Languages

1. true / false By a compiler we mean a program that translates to code that will run natively on some machine.

'Safe' programming languages

Static program checking and verification

CS-XXX: Graduate Programming Languages. Lecture 9 Simply Typed Lambda Calculus. Dan Grossman 2012

Metadata Features in Java SE 8

Discussion. Type 08/12/2016. Language and Type. Type Checking Subtypes Type and Polymorphism Inheritance and Polymorphism

CSE 331 Final Exam 3/16/15 Sample Solution

Finding User/Kernel Pointer Bugs with Type Inference p.1

Top Down Design vs. Modularization

CMSC 330: Organization of Programming Languages

CSE 331 Software Design & Implementation

CSCI-GA Scripting Languages

Types and Type Inference

A Short Summary of Javali

Inheritance (Part 5) Odds and ends

The JML Tool. Faculty of Engineering Pontificia Universidad Javeriana. The JML Tool p.1/23

CSE 331 Software Design and Implementation. Lecture 13 Generics 1

CS 565: Programming Languages. Spring 2008 Tu, Th: 16:30-17:45 Room LWSN 1106

Types and Type Inference

CSE wi Midterm Exam 2/8/18. Name UW ID #

Simply-Typed Lambda Calculus

Polymorphism. CMSC 330: Organization of Programming Languages. Two Kinds of Polymorphism. Polymorphism Overview. Polymorphism

CS412/CS413. Introduction to Compilers Tim Teitelbaum. Lecture 17: Types and Type-Checking 25 Feb 08

CS263: Runtime Systems Lecture: High-level language virtual machines

Array. Prepared By - Rifat Shahriyar

Javarifier: Inferring Reference Immutability for Java

CS 430 Spring Mike Lam, Professor. Data Types and Type Checking

Topics Covered Thus Far. CMSC 330: Organization of Programming Languages. Language Features Covered Thus Far. Programming Languages Revisited

CSE 431S Type Checking. Washington University Spring 2013

Programming Languages and Techniques (CIS120)

CS 11 java track: lecture 1

Computer Components. Software{ User Programs. Operating System. Hardware

A Practical Optional Type System for Clojure. Ambrose Bonnaire-Sergeant

Assertions & Design-by-Contract using JML Erik Poll University of Nijmegen

The Compiler So Far. CSC 4181 Compiler Construction. Semantic Analysis. Beyond Syntax. Goals of a Semantic Analyzer.

Java Modelling Language (JML) References

Equality. Michael Ernst. CSE 331 University of Washington

G Programming Languages Spring 2010 Lecture 6. Robert Grimm, New York University

Solutions to Quiz 1 (March 22, 2019)

An introduction to formal specifications and JML. Invariant properties

CSE 331 Final Exam 6/10/14

6.005 Elements of Software Construction Fall 2008

Computer Components. Software{ User Programs. Operating System. Hardware

Type Checking and Type Equality

INF 212/CS 253 Type Systems. Instructors: Harry Xu Crista Lopes

Transcription:

print(@readonly Object x) { List<@NonNull String> lst; Detecting and preventing null pointer errors with pluggable type-checking CSE 331 University of Washington

Motivation java.lang.nullpointerexception

Java s type checking is too weak Type checking prevents many bugs int i = hello ; // type error Type checking doesn t prevent enough bugs System.console().readLine(); NullPointerException Collections.emptyList().add( One ); UnsupportedOperationException 3

Some errors are silent Date date = new Date(0); mymap.put(date, Java epoch ); date.setyear(70); mymap.put(date, Linux epoch ); Corrupted map dbstatement.executequery(userinput); SQL injection attack Initialization, data formatting, equality tests, 4

Problem: Your code has bugs Who discovers the problems? If you are very lucky, testingdiscovers (some of) them If you are unlucky, your customer discovers them If you are very unlucky, hackersdiscover them If you are smart, the compilerdiscovers them It s better to be smartthan lucky 5

Solution: Pluggable type systems Design a type system to solve a specific problem Write type qualifiers in code (or, use type inference) @Immutable Date date = new Date(0); date.settime(70); // compile-time error Type checker warns about violations (bugs) % javac -processor NullnessChecker MyFile.java MyFile.java:149: dereference of possibly-null reference bb2 allvars = bb2.vars; ^ 6

Type qualifiers Java 8: annotations on types @Untainted String query; List<@NonNull String> strings; mygraph = (@Immutable Graph) tmpgraph; class UnmodifiableList<T> implements @Readonly List<@Readonly T> { Backward-compatible: compile with any Java compiler List</*@NonNull*/ String> strings; 7

Benefits of type qualifiers Find bugs in programs Guarantee the absence of errors Improve documentation Improve code structure & maintainability Aid compilers, optimizers, and analysis tools Reduce number of assertions and run-time checks Possible negatives: Must write the types (or use type inference) False positives are possible (can be suppressed) 8

NullnessChecker demo Detect errors Guarantee the absence of errors Verify the correctness of optimizations 9

What bugs can you find & prevent? Null dereferences Mutation and side-effects Concurrency: locking Security: encryption, tainting Aliasing Equality tests Strings: localization, regular expression syntax Typestate(e.g., open/closed files You can write your own checker! The annotation you write: @NonNull @Immutable @GuardedBy @Encrypted @Untainted @Linear @Interned @Localized @Regex @State 10

Using a checker Run in IDE or on command line Works as a compiler plug-in (annotation processor) Uses familiar error messages % javac processor NullnessChecker MyFile.java MyFile.java:9: incompatible types. nonnullvar = nullablevalue; ^ found : @Nullable String required: @NonNull String 11

What is checked Proper use of the type hierarchy assignments method calls and returns overriding Proper use of methods and operations No dereferences of possibly-null values

What the checker guarantees Program satisfies type property no bugs (of particular varieties) no wrong annotations Caveat 1: only for code that is checked Native methods Reflection Code compiled without the pluggable type checker Suppressed warnings Indicates what code a human should analyze Checking part of a programis still useful Caveat 2: The checker itself might contain an error

Static and dynamic typing Static typing Compiler guarantees that some errors cannot happen The set of errors depends on the language Other errors are still possible! Examples: C, C++, Objective C, Java, C#, ML, Haskell Dynamic typing The run-time system keeps track of types, and throws errors Examples: Lisp, Scheme, Perl, PHP, Python, Ruby, JavaScript No type system Example: Assembly

Why we static typing Documentation Correctness/reliability Refactoring Speed

Why we dynamic typing (= Why we static typing) More concise code Type inference is possible No false positive warnings Every static type system rejects some correct programs @NonNull String linesep = System.getProperty("line.separator"); More flexible code Add fields at run time Change class of an object Ability to run tests at any time Feedback is important for quality code Programmer knows whether static or dynamic feedback is best

Nullnesssubtypingrelationship Which type hierarchy is best? @NonNull Date @Nullable Date @?? Date @Nullable Date @NonNull Date @Nullable Date @NonNull Date A subtype has fewer values A subtype has more operations A subtype is substitutable A subtype preserves supertype properties

Mutability subtypingrelationship Which type hierarchy is best? @Immutable Date @Mutable Date @ReadOnly @?? Date Date @Mutable Date @Immutable Date @Immutable Date @Mutable Date @Immutable: no one can do mutation @Mutable: anyone can do mutation @ReadOnly I can t do mutation No guarantee about mutation from elsewhere

Flow sensitivity Which callsare legal? Object name; name = new Object(); name.tolowercase(); name = HELLO ; name.tolowercase(); name = new Object(); name.tolowercase(); @Nullable String name; name = null; name.tolowercase(); name = HELLO ; name.tolowercase(); name = null; name.tolowercase();

Flow sensitivity: name and legality Control flow determines the type if (x==null) {... // treat as nullable else {... // treat as non-null What changes to the type are legal? String name; name = new Object();... // treat nameas Object @NonNull String name; name = null;... // treat nameas nullable Not these! It s only legal to change to a subtype.

Flow sensitivity and type inference Default for nullness checker: Non-null except locals Locals default to nullable(top of hierarchy) Flow-sensitivity changes this as needed @Nullable String name; name = hello ;... // treat nameas non-null @Nullable String name; name = othernullable;... // treat nameas nullable Rarely write annotations on local variables

The receiver is just another parameter How many arguments does Object.equals take? class MyClass { @Override public boolean equals(object other) { Two! Their names are thisand other Neither one is mutated by the method public boolean Annotation on type of other Annotation on type of this equals(@readonly Object other) @ReadOnly {

Find the potential null pointer error class C { @Nullable Object currentobj; // If currentobj is non-null, // prints it and a timestamp void printcurrent() { if (currentobj!= null) { System.out.println(this.getTimeStamp()); System.out.println(currentObj.toString()); Object gettimestamp() {

Lack of side effects class C { @Nullable Object currentobj; // If currentobj is non-null, // prints it and a timestamp void printcurrent() { if (currentobj!= null) { System.out.println(this.getTimeStamp()); System.out.println(currentObj.toString()); @Pure Object gettimestamp() {

Lazy initialization class C { @LazyNonNull Object currentobj; // If currentobj is non-null, // prints it and a timestamp void printcurrent() { if (currentobj!= null) { System.out.println(this.getTimeStamp()); System.out.println(currentObj.toString()); Object gettimestamp() {

Why doesn t this typecheck? class C { @Nullable Object f; void m1() { setf(); f.hashcode(); @AssertNonNullAfter( this.f ) void setf() { this.f = new Object(); Type-checking is modular Libraries you call must be annotated (much of the JDK is provided)

Why doesn t this typecheck? class C { Map<String, Date> m; String getdatestring(string key) { return m.get(k).tostring();

Map keys class C { Map<String, Date> m, String getdatestring(@keyfor( m ) String key) { return m.get(k).tostring();

Another map key example class C { Date getdate(map<string, Date> m, String key) { return m.get(k); void usedate(map<string, Date> m) { String s = now, Date d = new Date(); m.put(s, d); getdate(s);

Naming a formal parameter Use number, not name, for formal class C { parameters. Date getdate(map<string, Date> m, @KeyFor( #0 ) String key) { return m.get(k); void usedate(map<string, Date> m) { String s = now, Date d = new Date(); m.put(s, d); getdate(s);

class C { Map<String, Date> m; String getdatestring(string key) { return m.get(k).tostring(); void usedate(map<string, Date> m) { String s = now, Date d = new Date(); m.put(s, d); getdate(s);

How should identity be annotated? String identity(string arg) { return arg; void client() { // desired result: identity( hello ).hashcode(); // OK; no warning identity(null).hashcode(); // compiler warning

How should identity be written? These types are too specific: String identity(string arg) { return arg; We want to say: ThatSameType identity(anytype arg) { return arg; In Java, this is expressed as: <T> T identity(t arg) { return arg; identity has many types: String String Integer Integer List<Date> List<Date> Java automatically chooses the best type at each call site We also write this as: T. T T Java calls this a generic method The standard term is polymorphism We will learn about this soon

Polymorphism over nullness @PolyNull String identity(@polynull String arg) { return arg; void client() { identity( hello ).hashcode(); // OK; no warning identity(null).hashcode(); // compiler warning @PolyNull is a hack that is necessary for non-generic methods It is not necessary for generic methods: // No annotations, but type-checks just like identity(). <T> T identity2(t arg) { return arg;

Safe but un-annotatable code class Point { // rep invariant: either rep1 or rep2 is non-null XAndY rep1; RhoAndTheta rep2; float magnitude() { if (rep1!= null) { return Math.sqrt(rep1.x * rep1.x + rep1.y * rep1.y); else { // We know rep2 is non-null at this point. return rep2.rho;

Summary of nullnessannotations @Nullable @NonNull (rarely used) @LazyNonNull Preconditions: @NonNullOnEntry Postconditions: @Pure @AssertNonNullAfter @AssertNonNullIfTrue @AssertNonNullIfFalse Initialization: @Raw (rarely used) Maps: @KeyFor Polymorphism: @PolyNull (rarely used)