Javarifier: inference of reference immutability

Similar documents
David Glasser Michael D. Ernst CSAIL, MIT

Javarifier: Inferring Reference Immutability for Java

Combined Static and Dynamic Mutability Analysis 1/31

Javari: Adding Reference Immutability to Java. Matthew S. Tschantz

ReIm & ReImInfer: Checking and Inference of Reference Immutability and Method Purity

Javari: Adding Reference Immutability to Java. Matthew S. Matthew S. Tschantz, MMVI. All rights reserved. ARCHIVES

Object and Reference Immutability using Java Generics

Detecting and preventing null pointer errors with pluggable type-checking

Dataflow and Type-based Formulations for Reference Immutability

The Checker Framework: pluggable static analysis for Java

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

Detecting and preventing null pointer errors with pluggable type-checking

Javari: Adding Reference Immutability to Java

Using Type Annotations to Improve Your Code

Combined Static and Dynamic Mutability Analysis

CSE 331 Software Design and Implementation. Lecture 16 Checker Framework

Lecture 19 Checker Framework

OOPSLA 2004, Vancouver

CSE 331 Software Design and Implementation. Lecture 13 Generics 1

Refinement Types for TypeScript

A Practical Type System and Language for Reference Immutability

CSE 331 Software Design and Implementation. Lecture 14 Generics 2

Inference and Checking of Object Ownership

CSE 331 Software Design and Implementation. Lecture 14 Generics 2

Type Qualifier Inference for Java

Weiss Chapter 1 terminology (parenthesized numbers are page numbers)

Automatic Generation of Program Specifications

Static program checking and verification

Refactoring Java Generics by Inferring Wildcards, In Practice

Chapter 4 Defining Classes I

Java Generics -- an introduction. Based on

Cascade: A Universal Programmer-assisted Type Qualifier Inference Tool

CSE Lecture 7: Polymorphism and generics 16 September Nate Nystrom UTA

Code verification. CSE 331 University of Washington. Michael Ernst

C++ Inheritance and Encapsulation

Inference and Checking of Object Immutability

Class, Variable, Constructor, Object, Method Questions

Atelier Java - J1. Marwan Burelle. EPITA Première Année Cycle Ingénieur.

CSE 331 Software Design & Implementation

Exercise 10 Object Structures and Aliasing November 27, 2015

Exercise 8 Parametric polymorphism November 18, 2016

Exercise 3 Subtyping and Behavioral Subtyping October 13, 2017

For this section, we will implement a class with only non-static features, that represents a rectangle

Lecture Outline. Parametric Polymorphism and Java Generics. Polymorphism. Polymorphism

AP Computer Science Chapter 10 Implementing and Using Classes Study Guide

Programming Languages (PL)

Advanced Programming Generics Collections

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

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

Java 5 New Language Features

CS152: Programming Languages. Lecture 24 Bounded Polymorphism; Classless OOP. Dan Grossman Spring 2011

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

CSE 331 Software Design and Implementation. Lecture 15 Generics 2

Advances in Programming Languages

The Hack programming language:

A Short Summary of Javali

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

Java Fundamentals (II)

Graphical Interface and Application (I3305) Semester: 1 Academic Year: 2017/2018 Dr Antoun Yaacoub

generic programming alberto ferrari university of parma

CSE 331 Summer 2017 Final Exam. The exam is closed book and closed electronics. One page of notes is allowed.

The Checker Framework Manual

301AA - Advanced Programming [AP-2017]

Subtyping. Lecture 13 CS 565 3/27/06

301AA - Advanced Programming [AP-2017]

Exam 2. Topics. Preconditions vs. Exceptions. Exam 2 Review. Exam 2 on Thursday, March 29 th. Closed book, closed computer, closed phone

Generics method and class definitions which involve type parameters.

HAS-A Relationship. If A uses B, then it is an aggregation, stating that B exists independently from A.

Parametric polymorphism and Generics

CSE 331 Software Design & Implementation

objects

Applied Unified Ownership. Capabilities for Sharing Across Threads

Java: introduction to object-oriented features

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

Announcements. Written Assignment 2 Due Monday at 5:00PM. Midterm next Wednesday in class, 11:00 1:00. Midterm review session next Monday in class.

Field Analysis. Last time Exploit encapsulation to improve memory system performance

SHIFTLEFT OCULAR THE CODE PROPERTY GRAPH

Harvard School of Engineering and Applied Sciences CS 152: Programming Languages

Object Ownership in Program Verification

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

Method Resolution Approaches. Dynamic Dispatch

Array. Prepared By - Rifat Shahriyar

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

CS111: PROGRAMMING LANGUAGE II

The Java Programming Language

Index COPYRIGHTED MATERIAL

CS 251 Intermediate Programming Inheritance

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

Administrivia. Java Review. Objects and Variables. Demo. Example. Example: Assignments

The Case for Simple Object-Orientation in VDM++ Erik Ernst Aarhus University, Denmark

Stephen McLaughlin. From Uncertainty to Belief: Inferring the Specification Within

Java: advanced object-oriented features

Lecture 13: Subtyping

A Deep Dive into the Void

Agenda. Objects and classes Encapsulation and information hiding Documentation Packages

JFlow: Practical Mostly-Static Information Flow Control

Exercise 12 Initialization December 15, 2017

Big Bang. Designing a Statically Typed Scripting Language. Pottayil Harisanker Menon, Zachary Palmer, Scott F. Smith, Alexander Rozenshteyn

6.170 Lecture 7 Abstract Data Types MIT EECS

Transcription:

print(object x) { print(@readonly Object x) { Javarifier: inference of reference immutability Jaime Quinonez Matthew S. Tschantz Michael D. Ernst MIT

Security code in JDK 1.1 class Class { private Object[] signers; Object[] getsigners() { return signers;

Security code in JDK 1.1 class Class { private Object[] signers; Object[] getsigners() { return signers; myclass.getsigners()[0] = Sun ;

Immutability annotations prevent mutation errors class Class { private Object[] signers; // Prohibits client from mutating @Readonly Object[] getsigners() { return signers; myclass.getsigners()[0] = Sun ; // Error

Immutability annotations prevent mutation errors class Class { // Forces getsigners to return a copy private @Readonly Object[] signers; Object[] getsigners() { return signers; // Error myclass.getsigners()[0] = Sun ;

Reasoning about side effects Machine-checked formal documentation Error detection Verification Enables analyses Enables transformations and optimizations Case studies: expressive, natural, useful 300 KLOC of programmer-written code

Type-checking requires annotations Easy for new programs Tedious for legacy programs Worst for libraries: large, hard to understand Library annotations cannot be omitted // Assume user program is fully annotated @Readonly MyClass x = ; x.tostring(); // OK x.mutate(); // Error System.out.println(x); // False error! Library declares println as: void println(object) { But it should be: void println(@readonly Object) {

Immutability inference algorithm Sound Precise (complete) Linear time Rich, practical type system: Javari [Tschantz 2005] Context-sensitive Type polymorphism (Java generics and wildcards) Mutability polymorphism (type qualifier polymorphism) Containing-object context (deep immutability) Infers abstract state Handles partially-annotated code, unanalyzable code

Immutability inference implementation Implements the full algorithm Handles all of Java Works on bytecodes Inserts results in source or.class file Scales to >100 KLOC Verified by independent typechecker Verified by comparison to other tools Publicly available: http://pag.csail.mit.edu/javari/javarifier/

Javari type system A given reference cannot be used to modify its referent Other references to the object may modify it Deep: the transitively reachable state (the abstract state) is protected Generics: List<@Readonly Date> Mutability polymorphism: @Polyread Object id(@polyread arg) { return arg;

Algorithm: propagate mutability Syntax-directed constraint generation Unconditional constraint: x x is mutable Example code: x.field = 22; Conditional constraint: y z if y is mutable, then z is mutable Example code: y = z; Constraint solving: graph reachability Unmarked references remain readonly

Appointment class class Appt { private Date d; void setdate(appt this, Date newdate) { this.d = newdate; Date getdate(appt this) { Date result = this.d; return result; void reset(appt this) { Date thisdate = this.d; settime(thisdate, 0); Receivers are written explicitly class Date { private long time; void settime(date this, long newtime) { this.time = newtime;

Assignment class Appt { private Date d; void setdate(appt this, Date newdate) { this.d = newdate; Date getdate(appt this) { Date result = this.d; return result; void reset(appt this) { Date thisdate = this.d; settime(thisdate, 0); Sample code: x.f = y; Constraints: { x, f y class Date { private long time; void settime(date this, long newtime) { this.time = newtime;

Assignment class Appt { private Date d; void setdate(appt this, Date newdate) { this.d = newdate; Date getdate(appt this) { Date result = this.d; return result; void reset(appt this) { Date thisdate = this.d; settime(thisdate, 0); Sample code: x.f = y; Constraints: { x, f y class Date { private long time; void settime(date this, long newtime) { this.time = newtime;

Assignment class Appt { private Date d; void setdate(appt this, Date newdate) { this.d = newdate; Date getdate(appt this) { Date result = this.d; return result; void reset(appt this) { Date thisdate = this.d; settime(thisdate, 0); Sample code: x.f = y; Constraints: { x, f y class Date { private long time; void settime(date this, long newtime) { this.time = newtime;

Assignment class Appt { private Date d; void setdate(appt this, Date newdate) { this.d = newdate; Date getdate(appt this) { Date result = this.d; return result; void reset(appt this) { Date thisdate = this.d; settime(thisdate, 0); Sample code: x.f = y; Constraints: { x, f y class Date { private long time; void settime(date this, long newtime) { this.time = newtime;

Dereference class Appt { private Date d; void setdate(appt this, Date newdate) { this.d = newdate; Date getdate(appt this) { Date result = this.d; return result; void reset(appt this) { Date thisdate = this.d; settime(thisdate, 0); Sample code: x = y.f; Constraints: { x f, x y class Date { private long time; void settime(date this, long newtime) { this.time = newtime;

Dereference class Appt { private Date d; void setdate(appt this, Date newdate) { this.d = newdate; Date getdate(appt this) { Date result = this.d; return result; void reset(appt this) { Date thisdate = this.d; settime(thisdate, 0); Sample code: x = y.f; Constraints: { x f, x y class Date { private long time; void settime(date this, long newtime) { this.time = newtime;

Dereference class Appt { private Date d; void setdate(appt this, Date newdate) { this.d = newdate; Date getdate(appt this) { Date result = this.d; return result; void reset(appt this) { Date thisdate = this.d; settime(thisdate, 0); Sample code: x = y.f; Constraints: { x f, x y class Date { private long time; void settime(date this, long newtime) { this.time = newtime;

Dereference class Appt { private Date d; void setdate(appt this, Date newdate) { this.d = newdate; Date getdate(appt this) { Date result = this.d; return result; void reset(appt this) { Date thisdate = this.d; settime(thisdate, 0); Sample code: x = y.f; Constraints: { x f, x y class Date { private long time; void settime(date this, long newtime) { this.time = newtime;

Method invocation class Appt { private Date d; void setdate(appt this, Date newdate) { this.d = newdate; Date getdate(appt this) { Date result = this.d; return result; void reset(appt this) { Date thisdate = this.d; settime(thisdate, 0); Sample code: x = m(y1); Constraints: { param1 y1, x ret class Date { private long time; void settime(date this, long newtime) { this.time = newtime;

Method invocation class Appt { private Date d; void setdate(appt this, Date newdate) { this.d = newdate; Date getdate(appt this) { Date result = this.d; return result; void reset(appt this) { Date thisdate = this.d; settime(thisdate, 0); Sample code: x = m(y1); Constraints: { param1 y1, x ret class Date { private long time; void settime(date this, long newtime) { this.time = newtime;

Method invocation class Appt { private Date d; void setdate(appt this, Date newdate) { this.d = newdate; Date getdate(appt this) { Date result = this.d; return result; void reset(appt this) { Date thisdate = this.d; settime(thisdate, 0); Sample code: x = m(y1); Constraints: { param1 y1, x ret class Date { private long time; void settime(date this, long newtime) { this.time = newtime;

All constraints class Appt { private Date d; void setdate(appt this, Date newdate) { this.d = newdate; Date getdate(appt this) { Date result = this.d; return result; void reset(appt this) { Date thisdate = this.d; settime(thisdate, 0); class Date { private long time; void settime(date this, long newtime) { this.time = newtime;

Propagate mutability via graph reachability class Appt { private Date d; void setdate(appt this, Date newdate) { this.d = newdate; Date getdate(appt this) { Date result = this.d; return result; void reset(appt this) { Date thisdate = this.d; settime(thisdate, 0); class Date { private long time; void settime(date this, long newtime) { this.time = newtime;

Propagate mutability via graph reachability class Appt { private Date d; void setdate(appt this, Date newdate) { this.d = newdate; Date getdate(appt this) { Date result = this.d; return result; void reset(appt this) { Date thisdate = this.d; settime(thisdate, 0); class Date { private long time; void settime(date this, long newtime) { this.time = newtime;

Propagate mutability via graph reachability class Appt { private Date d; void setdate(appt this, Date newdate) { this.d = newdate; Date getdate(appt this) { Date result = this.d; return result; void reset(appt this) { Date thisdate = this.d; settime(thisdate, 0); class Date { private long time; void settime(date this, long newtime) { this.time = newtime;

Propagate mutability via graph reachability class Appt { private Date d; void setdate(appt this, Date newdate) { this.d = newdate; Date getdate(appt this) { Date result = this.d; return result; void reset(appt this) { Date thisdate = this.d; settime(thisdate, 0); class Date { private long time; void settime(date this, long newtime) { this.time = newtime;

Results inserted in source code class Appt { private Date d; void setdate(appt this, Date newdate) { this.d = newdate; @Readonly Date getdate( @Readonly Appt this) { @Readonly Date result = this.d; return result; void reset(appt this) { Date thisdate = this.d; settime(thisdate, 0); class Date { private long time; void settime(date this, long newtime) { this.time = newtime;

Subtyping Add new constraints for behavioral subtyping: Contravariant parameter mutability Covariant return mutability Preserves Java overriding and overloading Solve as usual

Annotations for un-analyzed code For native methods: Stub annotations Also useful for overriding inference results For libraries with unknown clients: Open-world assumption All public members are mutable (pessimistic) If whole program is available: Closed-world assumption Use existing clients (optimistic) Add constraints stemming from the annotations Solve as usual

Abstract state User annotations of fields not in the abstract state Caches, logging, beneficial side effects Change type rules to ignore permissible mutations Infer abstract state Inconsistencies with user or library annotations String tostring() @Readonly { if (cache == null) cache = computetostring(); return cache; Modifies receiver Does not modify receiver Heuristics for common programming patterns Requires user confirmation

Arrays and generic classes Each part of the type gets a type constraint variable 2 constraint variables for List<Date> Generated constraints may use subtyping Array assignment rule: x[z] = y : { x, type(y) <: type(x[z]) Dereference rule: x = y.f : { type(f) <: type(x), x y Simplify constraints via equivalences between Subtyping Type containment Mutability constraints When only mutability constraints remain, solve them

Wildcards let a method accept more arguments printlist(list lst) { for (int i=0; i<lst.size(); i++) { print(lst.get(i)); printlist(new List<Integer>()); printlist(new List<Long>());

Wildcards let a method accept more arguments printlist(list lst) { for (int i=0; i<lst.size(); i++) { print(lst.get(i)); printlist(new List<Integer>()); printlist(new List<Long>());

Wildcards let a method accept more arguments printlist(list<number > lst) { for (int i=0; i<lst.size(); i++) { print(lst.get(i)); printlist(new List<Integer>()); printlist(new List<Long>()); List<Number> is not a supertype of List<Integer>

Wildcards let a method accept more arguments printlist(list<? extends Number> lst) { for (int i=0; i<lst.size(); i++) { print(lst.get(i)); upper bound lst may be of any List type whose element extends Number printlist(new List<Integer>()); printlist(new List<Long>());

Mutability wildcards let a method accept more arguments printdates(list< Date> lst) { for (int i=0; i<lst.size(); i++) { print(lst.get(i)); printdates(new List<Date>()); List<@Readonly Date> is not a supertype of List<Date> printdates(new List<@Readonly Date>());

Mutability wildcards let a method accept more arguments printdates(list<?@readonly Date> lst) { for (int i=0; i<lst.size(); i++) { print(lst.get(i)); lst may be List<Date> or List<@Readonly Date> printdates(new List<Date>()); Can be expressed as a wildcard with upper and lower bounds: List<? extends @Readonly Date super Date> printdates(new List<@Readonly Date>());

Constraint variables for upper and lower bound A generic type List<Date> gives rise to 3 constraint variables: mutability of List mutability of upper bound of Date mutability of lower bound of Date Small increase in the number of constraints Solve as usual Translate to?@readonly: Lower bound Upper bound Javari type mutable mutable mutable readonly readonly readonly mutable readonly? readonly

Mutability (qualifier) polymorphism @Polyread Date getdate(@polyread Appt this) { return this.d; Orthogonal to type polymorphism (generics) Conceptually, duplicate the method: @Readonly Date getdate(@readonly Appt this){ Date getdate( Appt this){

Duplicate constraint variables: mutable and readonly context For each method, duplicate all its constraint variables Constant factor overhead (no need for >1 variable) Only the method invocation rule changes Solve as usual Translate to @Polyread: Mutable context Immutable context Javari type mutable mutable mutable readonly readonly readonly mutable readonly polyread

Experimental methodology Compare to Human-written Javari code Pidasa [Artzi 2007] JPPA [Salcianu 2005] JQual [Greenfieldboyce 2007] Javari type-checker [Correa 2007] Subject programs: JOlden (6 KLOC) tinysql (31 KLOC) htmlparser (64 KLOC) Eclipse compiler (111 KLOC) We inspected 8,694 references

Soundness Goal: No readonly reference can be modified Result obeys the Javari language specification Compared to: Human Other inference tools Javari type-checker Javarifier is sound Misidentified no references as readonly

Precision (completeness) Goal: Maximal qualifiers (readonly, etc ) Example imprecise algorithm: every reference is mutable Javarifier is precise Proof sketch that Javarifier is precise Javarifier identified every readonly reference That any other inference tool, or the human, did Javarifier identified all fields to exclude from the abstract state According to the human

Type-system-based inference Javarifier algorithm & initial experiments: [Tschantz 2006] JQual [Greenfieldboyce 2007]: Same basic rules as [Tschantz 2006] Polymorphism: multiple qualifiers, but no generics Generality: any qualifier, but less expressive Scalability: flow- and context-sensitive, unscalable Accuracy: less precise, not sound

Non type-system-based inference JPPA [Salcianu 2005] Whole-program static pointer and escape analysis Sophisticated method summaries Pidasa [Artzi 2007] Pipeline of static and dynamic stages Sound and unsound variants JDynPur [Dallmeier 2008] Lightweight dynamic analysis

Contributions Javarifier: inference of reference immutability Sound Precise (complete) Scalable Rich, practical type system: Javari Abstract state, type & mutability polymorphism, Download: http://pag.csail.mit.edu/javari/javarifier/ Handles all of Java Works on bytecodes, inserts in source or.class

Contributions Javarifier: inference of reference immutability Sound Precise (complete) Scalable Rich, practical type system: Javari Abstract state, type & mutability polymorphism, Download: http://pag.csail.mit.edu/javari/javarifier/ Handles all of Java Works on bytecodes, inserts in source or.class