Safe TypeScript Aseem Rastogi University of Maryland, College Park

Slides:



Advertisements
Similar presentations
Writing specifications for object-oriented programs K. Rustan M. Leino Microsoft Research, Redmond, WA, USA 21 Jan 2005 Invited talk, AIOOL 2005 Paris,
Advertisements

New features in JDK 1.5 Can these new and complex features simplify Java development?
Rigorous Software Development CSCI-GA Instructor: Thomas Wies Spring 2012 Lecture 8.
An Abstract Interpretation Framework for Refactoring P. Cousot, NYU, ENS, CNRS, INRIA R. Cousot, ENS, CNRS, INRIA F. Logozzo, M. Barnett, Microsoft Research.
Current Techniques in Language-based Security David Walker COS 597B With slides stolen from: Steve Zdancewic University of Pennsylvania.
Taming JavaScript with F* Nikhil Swamy Microsoft Research.
1 Mooly Sagiv and Greta Yorsh School of Computer Science Tel-Aviv University Modern Compiler Design.
Compiler Construction
Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.
Java Generics.
C. Varela1 Typing and Parameter Passing Dynamic and Static Typing (EPL 4.1-4, VRH 2.8.3) Parameter Passing Mechanisms (VRH 6.4.4) Carlos Varela RPI.
Alias Annotations for Program Understanding Jonathan Aldrich Valentin Kostadinov Craig Chambers University of Washington.
1 Chapter 4 Language Fundamentals. 2 Identifiers Program parts such as packages, classes, and class members have names, which are formally known as identifiers.
OOP #10: Correctness Fritz Henglein. Wrap-up: Types A type is a collection of objects with common behavior (operations and properties). (Abstract) types.
1 Inheritance and Polymorphism. 2 Motivations Suppose you will define classes to model circles, rectangles, and triangles. These classes have many common.
Inheritance and Polymorphism CS351 – Programming Paradigms.
Automatic Implementation of provable cryptography for confidentiality and integrity Presented by Tamara Rezk – INDES project - INRIA Joint work with: Cédric.
Major Sponsors Minor Sponsors. about John Liu Contents What is TypeScript Why do we need TypeScript How Demo Pinteresp Working with your existing JavaScript.
Modern Concurrency Abstractions for C# by Nick Benton, Luca Cardelli & C´EDRIC FOURNET Microsoft Research.
1 Inheritance and Polymorphism Chapter 9. 2 Polymorphism, Dynamic Binding and Generic Programming public class Test { public static void main(String[]
Polymorphism &Virtual Functions
GRADUAL TYPING EMBEDDED SECURELY IN JAVASCRIPT Aseem Rastogi University of Maryland, College Park Joint Work With: Nikhil Swamy, Cédric Fournet, Karthikeyan.
Software Engineering Prof. Dr. Bertrand Meyer March 2007 – June 2007 Chair of Software Engineering Static program checking and verification Slides: Based.
COP4020 Programming Languages
Types for Programs and Proofs Lecture 1. What are types? int, float, char, …, arrays types of procedures, functions, references, records, objects,...
Object Oriented Programming Elhanan Borenstein Lecture #4.
Java Implementation: Part 3 Software Construction Lecture 8.
Chapter 21 Generics 1. Generics - Overview Generic Methods specify a set of related methods Generic classes specify a set of related types Software reuse.
Effective Java: Generics Last Updated: Spring 2009.
CSC 243 – Java Programming, Spring 2013 March 12, 2013 Week 7, Generics.
Inheritance and Polymorphism Daniel Liang, Introduction to Java Programming.
Introduction to TypeScript Sergey Barskiy Architect Level: Introductory.
CS536 Semantic Analysis Introduction with Emphasis on Name Analysis 1.
C# C1 CSC 298 Elements of C# code (part 1). C# C2 Style for identifiers  Identifier: class, method, property (defined shortly) or variable names  class,
Modularly Typesafe Interface Dispatch in JPred Christopher Frost and Todd Millstein University of California, Los Angeles
Liang, Introduction to Java Programming, Sixth Edition, (c) 2007 Pearson Education, Inc. All rights reserved Chapter 9 Inheritance and.
Liang, Introduction to Java Programming, Seventh Edition, (c) 2009 Pearson Education, Inc. All rights reserved Chapter 10 Inheritance and.
CMSC 330: Organization of Programming Languages Java Generics.
©SoftMoore ConsultingSlide 1 Generics “Generics constitute the most significant change in the Java programming language since the 1.0 release.” – Cay Horstmann.
How to execute Program structure Variables name, keywords, binding, scope, lifetime Data types – type system – primitives, strings, arrays, hashes – pointers/references.
1 Lecture 17 Static Types type safety, static vs dynamic checks, subtyping Ras Bodik Ali and Mangpo Hack Your Language! CS164: Introduction to Programming.
Semantic Analysis II Type Checking EECS 483 – Lecture 12 University of Michigan Wednesday, October 18, 2006.
Quick Review of OOP Constructs Classes:  Data types for structured data and behavior  fields and methods Objects:  Variables whose data type is a class.
Support standard JavaScript code with static typing Encapsulation through classes and modules Support for constructors, properties and.
Zach Tatlock / Winter 2016 CSE 331 Software Design and Implementation Lecture 13 Generics 1.
John Liu. Senior Consultant for SharePoint Gurus Sydney User Groups, SharePoint Saturday, SharePoint Conferences,
CS412/413 Introduction to Compilers Radu Rugina Lecture 11: Symbol Tables 13 Feb 02.
The Ins and Outs of Gradual Type Inference Avik Chaudhuri Basil Hosmer Adobe Systems Aseem Rastogi Stony Brook University.
1 CSC 533: Programming Languages Spring 2014 Subprogram implementation  subprograms (procedures/functions/subroutines)  subprogram linkage  parameter.
Polymorphism & Virtual Functions 1. Objectives 2  Polymorphism in C++  Pointers to derived classes  Important point on inheritance  Introduction to.
CSC 520 – Advanced Object Oriented Programming, Fall, 2010 Thursday, September 30 Week 5, Generics and Inheritance Techniques, Meyer Ch. 10 & 16.
Dr. M. Al-Mulhem Introduction 1 Chapter 6 Type Systems.
Dart Omar Ansari, Kenneth Jones, Isaac Wilder. 1. Overview l Object Oriented Language l Developed By Google l Primarily used for building websites, servers,
Introduction to TypeScript
/* LIFE RUNS ON CODE*/ Konstantinos Pantos Microsoft MVP ASP.NET
Chapter 6 CS 3370 – C++ Functions.
Types for Programs and Proofs
Semantic Analysis Type Checking
Component Based Software Engineering
Typescript Programming Languages
TS*: Taming the Un-typed Adversary in JavaScript
CSC 533: Programming Languages Spring 2015
CS5220 Advanced Topics in Web Programming Angular – TypeScript
Java IDE Dwight Deugo Nesa Matic Portions of the notes for this lecture include excerpts from.
CS5220 Advanced Topics in Web Programming Angular – TypeScript
Introduction to TypeScript
CSC 533: Programming Languages Spring 2018
Binding 10: Binding Programming C# © 2003 DevelopMentor, Inc.
CSC 533: Programming Languages Spring 2019
Windows Azure Anders Hejlsberg Technical Fellow 3-012
Presentation transcript:

Safe TypeScript Aseem Rastogi University of Maryland, College Park End of Internship Talk Joint work with: Nikhil Swamy (RiSE, Internship mentor), Cédric Fournet (MSRC), Gavin Bierman (Oracle), Panagiotis Vekris (UCSD)

TypeScript Gradually typed superset of JavaScript (www. typescriptlang TypeScript Gradually typed superset of JavaScript (www.typescriptlang.org) "Strong tools for large applications" "Static checking, symbol-based navigation, statement completion, code refactoring" "TypeScript offers classes, modules, and interfaces to help you build robust components" "Compiled into simple JavaScript" Compared to JavaScript, this is a great leap forward!

But Typing JavaScript is Hard ! For all its dynamic idioms TypeScript (like Dart and Closure) gives up soundness, intentionally Types are uniformly erased when compiling to JavaScript E.g. casts are unchecked Unsound type erasure is beneficial Lightweight codegen (highly readable JavaScript output) Performance identical to plain JavaScript Types don’t get in the way of good programmers But it also has its disadvantages TypeScript components are not robust

(Un-)Robustness of TypeScript Components Type safety violation Client: Client: function client(Iterator<number> it) { it["index"] = true; } function client(it) { it["index"] = true; } Provider: Provider: interface Iterator<A> { next(): A } var x = { state:[..], index:0, next() { return state[index++]; } }; client(x); //client:Iterator<number> => void var x = { state:[..], index:0, next() { return state[index++]; } }; client(x); TypeScript JavaScript TypeScript compiler

(Un-)Robustness of TypeScript Components Abstraction violation Client: Client: function client(Iterator<number> it) { (<any> it).index = -1; } function client(it) { it.index = -1; } Provider: Provider: interface Iterator<A> { next(): A } var x = { state:[..], index:0, next() { return state[index++]; } }; client(x); //client:Iterator<number> => void var x = { state:[..], index:0, next() { return state[index++]; } }; client(x); TypeScript JavaScript TypeScript compiler

Safe TypeScript Sound and efficient gradual typing is possible for idiomatic TypeScript Sound typing is beneficial Finds type errors early Found and fixed 478 type errors in TypeScript compiler, 1 functional correctness bug in NavierStokes, a heavily tested Octane benchmark Provably robust components But it also has its cost A runtime performance penalty Ranging from 6% to 3x on 118,000 lines of code in 8 applications (details follow) Need to understand subtle corners of JS semantics and our type system

TypeScript type inference TypeScript Workflow function f(x:any):number { return x.f; } function f(x):number { app.ts tsc app.ts TypeScript type inference TypeScript parsing JavaScript emitting function f(x) { app.js Syntactic errors Static diagnostic basic type errors

Safe TypeScript Workflow Fully integrated into TypeScript v0. 9 Safe TypeScript Workflow Fully integrated into TypeScript v0.9.5 as an optional compiler flag function f(x:any):number { return x.f; } function f(x):number { app.ts tsc --safe app.ts TypeScript type inference TypeScript parsing Safe TypeScript type checking & instrumentation return RT.check(RT.Num, RT.read(x, "f")); JavaScript emitting function f(x) { app.js inconsistent subtyping implicit downcast from any variables not in scope unsafe use of this projecting methods as fields Static diagnostics Syntactic errors Static diagnostic basic type errors

Highlights of The Type System Object-oriented, with a mixture of structural and nominal types Nominal types provide a sound model of JavaScript's semantics of classes In contrast: TypeScript is purely structural Types are compiled to provide precise run-time type information (RTTI) Allows the runtime system to enforce invariants with dynamic checks In contrast: RTTI in TypeScript is only what is available in JavaScript Selective type-erasure for performance and robustness The type system ensures that erasure does not compromise safety In contrast: TypeScript uniformly erases all types By example …

Nominal Classes and Structural Interfaces interface PointI { x:number; y:number } class PointC { constructor(public x:number, public y:number) { } function f(p:PointC) { assert(p instanceof PointC); }

Nominal Classes and Structural Interfaces interface PointI { x:number; y:number } class PointC { constructor(public x:number, public y:number) { } TypeScript output: leads to runtime error in f function f(p:PointC) { assert(p instanceof PointC); } Safe TypeScript: Static Type Error {x:number;y:number} is not a subtype of PointC f({x:0, y:0});

Nominal Classes and Structural Interfaces interface PointI { x:number; y:number } class PointC { constructor(public x:number, public y:number) { } function f(p:PointC) { assert(p instanceof PointC); } f(new PointC(0, 0)); Safe TypeScript: OK

Nominal Classes and Structural Interfaces interface PointI { x:number; y:number } class PointC { constructor(public x:number, public y:number) { } function f(p:PointI) { return p.x + p.y; } Safe TypeScript: OK PointC is a subtype of PointI f(new PointC(0, 0));

Highlights of The Type System Object-oriented, with a mixture of structural and nominal types Nominal types provide a sound model of JavaScript's semantics of classes In contrast: TypeScript is purely structural Types are compiled to provide precise run-time type information (RTTI) Allows the runtime system to enforce invariants with dynamic checks In contrast: RTTI in TypeScript is only what is available in JavaScript Selective type-erasure for performance and robustness The type system ensures that erasure does not compromise safety In contrast: TypeScript uniformly erases all types

Tag Objects with RTTI to Lock Invariants function f(p:any) { p.x = "boom"; } TypeScript output: leads to runtime error in g function g(p:PointI) { f(p); assert(typeof p.x === "number"); }

Tag Objects with RTTI to Lock Invariants shallowTag for structural objects function f(p:any) { p.x = "boom"; } function f(p) { … } //coming up ! function g(p:PointI) { f(p); assert(typeof p.x === "number"); } function g(p) { f(shallowTag(p, PointI)); … } Safe TypeScript: Adds RTTI to objects to lock their type shallowTag(x,t) = x.tag := combine(x.tag,t); x

Instrumentation of any Code function f(p:any) { p.x = "boom"; } function f(p) { write(p, "x", "boom"); } // fails function g(p:PointI) { f(p); assert(typeof p.x === "number"); } function g(p) { f(shallowTag(p, PointI)); … } Safe TypeScript: Enforces type invariants in any code write(o,f,v) = let t = o.rtti; o[f] = check(v, t[f]);

Tag Objects with RTTI to Lock Invariants No tagging for class instances function f(p:any) { p.x = "boom"; } function g(p:PointC) { f(p); assert(typeof p.x === "number"); } function g(p) { f(p); // no tagging … } No tagging for class instances Class instances have primitive RTTI (prototype chain)

Runtime Checked Downcasts function f(p:PointI) { assert(typeof p.x === "number"); } TypeScript output: leads to runtime error in f function g(p:any) { f(<PointI> p); } g({x:"boom",y:0});

Runtime Checked Downcasts Check fields invariants for structural types function f(p:PointI) { assert(typeof p.x === "number"); } function f(p) { … } function g(p) { f(check(p, PointI)); } … function g(p:any) { f(<PointI> p); } g({x:"boom",y:0}); Safe TypeScript: Checks downcasts at runtime check(o, PointI) = if typeof o.x === “number” && typeof o.y === “number” then o.rtti := PointI; o else die

Runtime Checked Downcasts Simple instanceof check for class instances function f(p:PointC) { … } function f(p) { … } function g(p:any) { f(<PointC> p); } g({x:"boom",y:0}); function g(p) { f(check(p, PointC)); } … check(o, PointC) = if o instanceof PointC then o else die Fast instanceof check for class instances

Highlights of The Type System Object-oriented, with a mixture of structural and nominal types Nominal types provide a sound model of JavaScript's semantics of classes In contrast: TypeScript is purely structural Types are compiled to provide precise run-time type information (RTTI) Allows the runtime system to enforce invariants with dynamic checks In contrast: RTTI in TypeScript is only what is available in JavaScript Selective type-erasure for performance and robustness The type system ensures that erasure does not compromise safety In contrast: TypeScript uniformly erases all types

Safe TypeScript adds RTTI Tags On-demand interface 3dPointI extends PointI { z:number; } function f(r:any) { ... } function g(q:PointI) { f(q); function h(p:3dPointI) { g(p); function main(p:3dPointI) { h(p); function f(r) { … } function g(q) { f(shallowTag(q, PointI)); } function h(p) { g(shallowTag(p, {z:number}); // diff tagging } function main(p) { h(p); } // no tagging Safe TypeScript adds minimum RTTI to ensure safety shallowTag(x, t) = x.rtti := combine(x.rtti, t); x

Programmer-controlled Type Erasure A new operator on types: "Erased t" A value of type Erased t is known to be a t statically, and at runtime it may not have RTTI Erased types are erased from the JavaScript output

Programmer Controlled Type Erasure interface PointI extends Erased { x:number; y:number } function f(r) { ... } function g(q) { f(q); } function h(p) { g(p);  static type error Cannot pass erased types to any context interface 3dPointI extends PointI { z:number; } function f(r:any) { ... } function g(q:PointI) { f(q); function h(p:3dPointI) { g(p);  compiles as is No tagging despite loss in precision Recall that previously it was: g(shallowTag(p, {z:number})) Safe TypeScript: Erased types must only be used statically

Revisiting Robust Components Client: Robustness provided by Safe TypeScript type soundness theorem Several useful corollaries: -- RTTI tags are always consistent -- RTTI tags evolve in subtyping hierarchy function client(Iterator<number> it) { it["index"] = true; } //runtime error Provider: interface Iterator<A> { next(): A } var x = { state:[..], index:0, next() { return state[index++]; } }; client(x); //client:Iterator<number> => void Full formalization and proofs in technical report: http://research.microsoft.com/apps/pubs/default.aspx?id=224900

Revisiting Robust Components Provider’s perspective Client: function client(Iterator<number> it) { (<any> it).index = -1; } Provider: interface Iterator<A> { next(): A } var x = { state:[..], index:0, next() { return state[index++]; } }; client(x); //client:Iterator<number> => void

Revisiting Robust Components Provider’s perspective Client: function client(Iterator<number> it) { (<any> it).index = -1; } Stronger abstraction using erased types Safe TypeScript provides an abstraction theorem for erased types //static error Provider: interface Iterator<A> extends Erased { next(): A } var x = { state:[..], index:0, next() { return state[index++]; } }; client(x); //client:Iterator<number> => void Full formalization and proofs in technical report: http://research.microsoft.com/apps/pubs/default.aspx?id=224900

Much more … Arrays (with mutability controls) Dictionaries Inheritance Overloading Generics with bounded polymorphism Optional fields/arguments/variadic functions Auto-boxing Primitive prototype hierarchy Closed vs. open records Nominal interfaces Enums … All these features allow us to handle practical TypeScript developments …

Experience with SafeTypeScript Bootstrapping Safe TypeScript compiler (implemented in TypeScript v0.9.5) 90,000 lines of code (80,000 lines of TypeScript compiler) Heavily class based, most of the code is carefully type annotated Static errors 478 in total 98 uses of bi-variant array subtyping 130 uses of covariant method argument subtyping 128 cases of variable scoping issues 52 cases of projecting a method (leading to potential unsound use of this parameter) … Runtime errors 26 failed downcasts 5 in our own code ! 15% runtime overhead of type safety

Experience with SafeTypeScript Compiling TypeScript v1.1 18,000 lines of code Heavily interface based Static errors 81 in total Mainly variable scoping and array subtyping 3x runtime overhead of type safety High overhead because of more structural types Have not optimized Safe TypeScript runtime for structural types

Experience with SafeTypeScript Octane benchmarks 10,000 lines of code Static errors Found 1 variable scoping bug in heavily tested NavierStokes High runtime overhead when no annotations 2.4x (Splay) to 72x (Crypto), Average: 22x Performance recovers once we add type annotations Average overhead: 6.5%

Demo ( Examples on Online Playground: http://research.microsoft.com/en-us/um/people/nswamy/Playground/TSSafe/ )

Limitations and Work in Progress eval and friends Adversarial typing of unsafe constructs – Swamy et. al. POPL'14 Implementation limitations: Does not support external modules Current implementation is in TypeScript v0.9.5 that has evolved to v1.1 Ongoing discussion about integrating Safe TypeScript in TypeScript v1.1

Safe TypeScript Download: Sound and efficient gradual type system for TypeScript Download: http://research.microsoft.com/en-us/downloads/b250c887-2b79-4413-9d7a- 5a5a0c38cc57/ Submitted POPL'15 paper: http://www.cs.umd.edu/~aseem/safets.pdf Technical report (with full formalization and proofs): http://research.microsoft.com/apps/pubs/default.aspx?id=224900 Online playground: http://research.microsoft.com/en-us/um/people/nswamy/Playground/TSSafe/

Structural types distinguish fields from methods Handling this soundly class Line { constructor(public p1:Point, public p2:Point){} public moveUp() { this.p1.y++; this.p2.y++; } function g(l:{moveUp:() => void}) { var f = l.moveUp; f(); function h(p:Point) { g(new Line(p, p)); Compiles without warnings in TypeScript Classes are convertible with their structure Line <: {moveUp() :void; //method p1:Point; //field p2:Point} //field window.p1 is undefined, so p1.y crashes SafeTypeScript Line does not contain a field called moveUp Only a method called moveUp

Structural types distinguish fields from methods Handling this soundly class Line { constructor(public p1:Point, public p2:Point){} public moveUp() { this.p1.y++; this.p2.y++; } function g(l:{moveUp(): void}) { var f = l.moveUp; f(); function h(p:Point) { g(new Line(p, p)); Compiles without warnings in TypeScript Classes are convertible with their structure Line <: {moveUp() :void; //method p1:Point; //field p2:Point} //field SafeTypeScript Cannot project a method

Structural types distinguish fields from methods Handling this soundly class Line { constructor(public p1:Point, public p2:Point){} public moveUp() { this.p1.y++; this.p2.y++; } function g(l:{moveUp(): void}) { l.moveUp(); function h(p:Point) { g(new Line(p, p)); g({moveUp() { this.p1.y++; }, p1:p, p2:p}); Compiles without warnings in TypeScript Classes are convertible with their structure Line <: {moveUp() :void; //method p1:Point; //field p2:Point} //field SafeTypeScript: Ok! g({moveUp : () => {this.p1.y++;}, p1:p, p2:p}) SafeTypeScript: A function is not a method SafeTypeScript: Object literal with a method

Field Addition and Deletion Dynamically typed unless it becomes static function f(p:PointI) { p["z"] = 0; delete p.z; } function f(p: PointI) { write(p, "z", 0); delete(p, "z"); } SafeTypeScript: Both write and delete succeed at runtime

Field Addition and Deletion Dynamically typed unless it becomes static function g(p:3dPointI) { … } function f(p:PointI) { p["z"] = 0; g(<3dPointI> p); delete p.z; } function g(p:3dPointI) { … } function f(p:PointI) { write(p, "z", 0); g(check(p, 3dPointI)); delete(p, "z"); } SafeTypeScript: write succeeds at runtime SafeTypeScript: check succeeds at runtime SafeTypeScript: delete fails at runtime – violates invariant of g