Roman Manevich Ben-Gurion University Program Analysis and Verification Spring 2015 Program Analysis and Verification Lecture 16: Shape Analysis.

Slides:



Advertisements
Similar presentations
Automated Theorem Proving Lecture 1. Program verification is undecidable! Given program P and specification S, does P satisfy S?
Advertisements

Modular and Verified Automatic Program Repair Francesco Logozzo, Thomas Ball RiSE - Microsoft Research Redmond.
Abstract Interpretation Part II
Predicate Abstraction and Canonical Abstraction for Singly - linked Lists Roman Manevich Mooly Sagiv Tel Aviv University Eran Yahav G. Ramalingam IBM T.J.
Shape Analysis by Graph Decomposition R. Manevich M. Sagiv Tel Aviv University G. Ramalingam MSR India J. Berdine B. Cook MSR Cambridge.
Context-Sensitive Interprocedural Points-to Analysis in the Presence of Function Pointers Presentation by Patrick Kaleem Justin.
Automatic Verification Book: Chapter 6. What is verification? Traditionally, verification means proof of correctness automatic: model checking deductive:
Pointer Analysis – Part I Mayur Naik Intel Research, Berkeley CS294 Lecture March 17, 2009.
3-Valued Logic Analyzer (TVP) Tal Lev-Ami and Mooly Sagiv.
Rigorous Software Development CSCI-GA Instructor: Thomas Wies Spring 2012 Lecture 13.
A survey of techniques for precise program slicing Komondoor V. Raghavan Indian Institute of Science, Bangalore.
1 Lecture 08(a) – Shape Analysis – continued Lecture 08(b) – Typestate Verification Lecture 08(c) – Predicate Abstraction Eran Yahav.
1 Operational Semantics Mooly Sagiv Tel Aviv University Textbook: Semantics with Applications.
Establishing Local Temporal Heap Safety Properties with Applications to Compile-Time Memory Management Ran Shaham Eran Yahav Elliot Kolodner Mooly Sagiv.
Next Section: Pointer Analysis Outline: –What is pointer analysis –Intraprocedural pointer analysis –Interprocedural pointer analysis (Wilson & Lam) –Unification.
Program analysis Mooly Sagiv html://
Range Analysis. Intraprocedural Points-to Analysis Want to compute may-points-to information Lattice:
Abstract Interpretation Part I Mooly Sagiv Textbook: Chapter 4.
Intraprocedural Points-to Analysis Flow functions:
Overview of program analysis Mooly Sagiv html://
1 Program Analysis Systematic Domain Design Mooly Sagiv Tel Aviv University Textbook: Principles.
Comparison Caller precisionCallee precisionCode bloat Inlining context-insensitive interproc Context sensitive interproc Specialization.
Program Analysis Mooly Sagiv Tel Aviv University Sunday Scrieber 8 Monday Schrieber.
Pointer analysis. Pointer Analysis Outline: –What is pointer analysis –Intraprocedural pointer analysis –Interprocedural pointer analysis Andersen and.
1 Tentative Schedule u Today: Theory of abstract interpretation u May 5 Procedures u May 15, Orna Grumberg u May 12 Yom Hatzamaut u May.
272: Software Engineering Fall 2012 Instructor: Tevfik Bultan Lecture 4: SMT-based Bounded Model Checking of Concurrent Software.
Dagstuhl Seminar "Applied Deductive Verification" November Symbolically Computing Most-Precise Abstract Operations for Shape.
Program Analysis and Verification Noam Rinetzky Lecture 10: Shape Analysis 1 Slides credit: Roman Manevich, Mooly Sagiv, Eran Yahav.
Program Analysis and Verification Spring 2015 Program Analysis and Verification Lecture 2: Operational Semantics I Roman Manevich Ben-Gurion University.
June 27, 2002 HornstrupCentret1 Using Compile-time Techniques to Generate and Visualize Invariants for Algorithm Explanation Thursday, 27 June :00-13:30.
Program Analysis and Verification Spring 2014 Program Analysis and Verification Lecture 11: Abstract Interpretation III Roman Manevich Ben-Gurion University.
Program Analysis and Verification Spring 2015 Program Analysis and Verification Lecture 14: Numerical Abstractions Roman Manevich Ben-Gurion University.
Program Analysis and Verification Spring 2014 Program Analysis and Verification Lecture 14: Numerical Abstractions Roman Manevich Ben-Gurion University.
Program Analysis and Verification Spring 2015 Program Analysis and Verification Lecture 9: Abstract Interpretation I Roman Manevich Ben-Gurion University.
Introduction to Problem Solving. Steps in Programming A Very Simplified Picture –Problem Definition & Analysis – High Level Strategy for a solution –Arriving.
Compiler Principles Fall Compiler Principles Lecture 0: Local Optimizations Roman Manevich Ben-Gurion University.
Program Analysis and Verification Spring 2014 Program Analysis and Verification Lecture 4: Axiomatic Semantics I Roman Manevich Ben-Gurion University.
Convergence of Model Checking & Program Analysis Philippe Giabbanelli CMPT 894 – Spring 2008.
Symbolic Execution with Abstract Subsumption Checking Saswat Anand College of Computing, Georgia Institute of Technology Corina Păsăreanu QSS, NASA Ames.
Program Analysis and Verification Spring 2015 Program Analysis and Verification Lecture 12: Abstract Interpretation IV Roman Manevich Ben-Gurion University.
1 Shape Analysis via 3-Valued Logic Mooly Sagiv Tel Aviv University Shape analysis with applications Chapter 4.6
Program Analysis and Verification Spring 2015 Program Analysis and Verification Lecture 4: Axiomatic Semantics I Roman Manevich Ben-Gurion University.
Program Analysis and Verification Spring 2015 Program Analysis and Verification Lecture 13: Abstract Interpretation V Roman Manevich Ben-Gurion University.
CSE 311 Foundations of Computing I Lecture 28 Computability: Other Undecidable Problems Autumn 2011 CSE 3111.
Static Techniques for V&V. Hierarchy of V&V techniques Static Analysis V&V Dynamic Techniques Model Checking Simulation Symbolic Execution Testing Informal.
Program Analysis and Verification Spring 2014 Program Analysis and Verification Lecture 12: Abstract Interpretation IV Roman Manevich Ben-Gurion University.
Operational Semantics Mooly Sagiv Tel Aviv University Textbook: Semantics with Applications Chapter.
Quantified Data Automata on Skinny Trees: an Abstract Domain for Lists Pranav Garg 1, P. Madhusudan 1 and Gennaro Parlato 2 1 University of Illinois at.
1 Iterative Program Analysis Abstract Interpretation Mooly Sagiv Tel Aviv University Textbook:
1 Numeric Abstract Domains Mooly Sagiv Tel Aviv University Adapted from Antoine Mine.
Operational Semantics Mooly Sagiv Tel Aviv University Sunday Scrieber 8 Monday Schrieber.
Program Analysis and Verification Spring 2014 Program Analysis and Verification Lecture 8: Static Analysis II Roman Manevich Ben-Gurion University.
Operational Semantics Mooly Sagiv Reference: Semantics with Applications Chapter 2 H. Nielson and F. Nielson
Putting Static Analysis to Work for Verification A Case Study Tal Lev-Ami Thomas Reps Mooly Sagiv Reinhard Wilhelm.
Operational Semantics Mooly Sagiv Reference: Semantics with Applications Chapter 2 H. Nielson and F. Nielson
Abstraction and Abstract Interpretation. Abstraction (a simplified view) Abstraction is an effective tool in verification Given a transition system, we.
Program Analysis and Verification Spring 2015 Program Analysis and Verification Lecture 8: Static Analysis II Roman Manevich Ben-Gurion University.
Spring 2017 Program Analysis and Verification
Spring 2017 Program Analysis and Verification
Spring 2016 Program Analysis and Verification
Spring 2017 Program Analysis and Verification
Spring 2016 Program Analysis and Verification
Program Analysis and Verification
Symbolic Implementation of the Best Transformer
Spring 2017 Program Analysis and Verification Operational Semantics
Pointer analysis.
Predicate Transformers
Predicate Abstraction
Spring 2016 Program Analysis and Verification Operational Semantics
Presentation transcript:

Roman Manevich Ben-Gurion University Program Analysis and Verification Spring 2015 Program Analysis and Verification Lecture 16: Shape Analysis

Syllabus Semantics Natural Semantics Structural semantics Axiomatic Verification Static Analysis Automating Hoare Logic Control Flow Graphs Equation Systems Collecting Semantics Abstract Interpretation fundamentals LatticesFixed-Points Chaotic Iteration Galois Connections Domain constructors Widening/ Narrowing Analysis Techniques Numerical Domains Alias analysis Shape Analysis Interprocedural Analysis CEGAR Crafting your own Soot From proofs to abstractions Systematically developing transformers 2

Previously Points-to analysis and alias analysis 3

Agenda Going beyond pointer analysis Shape analysis – Property-based summarization – Materialization – Specialized analysis for singly-linked lists – (3-valued Shape Analysis Framework / TVLA) 4

Limitations of pointer analysis 5 // Singly-linked list // data type. class SLL { int data; public SLL n; // next cell SLL(Object data) { this.data = data; this.n = null; } } // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; }

Flow&Field-sensitive Analysis 6 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; }

Flow&Field-sensitive Analysis 7 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } null h t

Flow&Field-sensitive Analysis 8 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } null h t L1 n

Flow&Field-sensitive Analysis 9 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } tmp null h t L1 n

Flow&Field-sensitive Analysis 10 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } tmp null h t L1 n L2 n

Flow&Field-sensitive Analysis 11 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } tmp null h t L1 n L2 n n

Flow&Field-sensitive Analysis 12 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } tmp null h t L1 n L2 n n

Flow&Field-sensitive Analysis 13 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } tmp null h t L1 n L2 n tmp null h t L1 n  tmp != null tmp == null n

Flow&Field-sensitive Analysis 14 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } tmp null h t L1 n L2 n tmp null h t L1 n  n

Flow&Field-sensitive Analysis 15 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } tmp null h t L1 n L2 n tmp == null ? n

Flow&Field-sensitive Analysis 16 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } tmp null h t L1 n L2 n n

Flow&Field-sensitive Analysis 17 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } tmp null h t L1 n L2 n Possible null dereference! n

Flow&Field-sensitive Analysis 18 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } tmp null h t L1 n L2 n Fixed-point for first loop n

Flow&Field-sensitive Analysis 19 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } tmp null h t L1 n L2 n n

Flow&Field-sensitive Analysis 20 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } tmp null h t L1 n L2 n Possible null dereference! n

What was the problem? Pointer analysis abstract all objects allocated at same program location into one summary object. However, objects allocated at same memory location may behave very differently – E.g., object is first/last one in the list – Assign extra predicates to distinguish between objects with different roles Number of objects represented by summary object  1 – does not allow strong updates – Distinguish between concrete objects (#=1) and abstract objects (#  1) Join operator very coarse – abstracts away important distinctions (tmp=null/tmp!=null) – Apply disjunctive completion 21

Improved solution Pointer analysis abstract all objects allocated at same program location into one summary object. However, objects allocated at same memory location may behave very differently – E.g., object is first/last one in the list – Add extra instrumentation predicates to distinguish between objects with different roles Number of objects represented by summary object  1 – does not allow strong updates – Distinguish between concrete objects (#=1) and abstract objects (#  1) Join operator very coarse – abstracts away important distinctions (tmp=null/tmp!=null) – Apply disjunctive completion 22

Adding properties to objects Let’s first drop allocation site information and instead… Define a unary predicate x(v) for each pointer variable x meaning x points to x Predicate holds for at most one node Merge together nodes with same sets of predicates 23

Flow&Field-sensitive Analysis 24 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } null h t

Flow&Field-sensitive Analysis 25 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } null h t {h, t} n

Flow&Field-sensitive Analysis 26 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } null h t {h, t} tmp n

Flow&Field-sensitive Analysis 27 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } null h t {h, t} tmp n {tmp} n No null dereference

Flow&Field-sensitive Analysis 28 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } null h t {h, t} tmp n {tmp} n

Flow&Field-sensitive Analysis 29 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } null h t {t} tmp n {h, tmp} n

Flow&Field-sensitive Analysis 30 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } null h t {t} tmp n {h, tmp} n  null h t {h, t} tmp n

Flow&Field-sensitive Analysis 31 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } null h t {t} tmp n {h, tmp} n  null h t {h, t} tmp n Do we need to analyze this shape graph again?

Flow&Field-sensitive Analysis 32 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } null h t {t} tmp n {h, tmp} n  null h t {h, t} tmp n

Flow&Field-sensitive Analysis 33 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } null h t {t} tmp n { h} n { tmp} n No null dereference

Flow&Field-sensitive Analysis 34 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } null h t {t} tmp n { h} n { tmp} n

Flow&Field-sensitive Analysis 35 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } null h t {t} tmp n { } n { h, tmp} n

Flow&Field-sensitive Analysis 36 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } null h t {t} tmp n { } n { h, tmp} n

Flow&Field-sensitive Analysis 37 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } null h t {t} tmp n { } n { h} n { tmp} n No null dereference

Flow&Field-sensitive Analysis 38 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } null h t {t} tmp n { } n { h} n { tmp} n

Flow&Field-sensitive Analysis 39 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } null h t {t} tmp n { } n n {h, tmp} n

Flow&Field-sensitive Analysis 40 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } null h t {t} tmp n { } n {h, tmp} n n Summarization How many objects does it represent?

Flow&Field-sensitive Analysis 41 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } null h t {t} tmp n { } n {h} n n { tmp} No null dereference n

Flow&Field-sensitive Analysis 42 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } null h t {t} tmp n { } n {h} n n { tmp} n

Flow&Field-sensitive Analysis 43 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } null h t {t} tmp n { } n {h, tmp} n n Fixed-point for first loop

Flow&Field-sensitive Analysis 44 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } null h t {t} tmp n { } n {h, tmp} n n

Flow&Field-sensitive Analysis 45 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } null h t {t} tmp n { } n {h, tmp} n n

Flow&Field-sensitive Analysis 46 // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; } null h t {t} tmp n { tmp?} n { tmp} n n

Improving precision via partial concretization 47

Best (induced) transformer 48 CA 2 3 f f # (a)=  (f(  (a))) 1 f#f# 4 Problem:  incomputable directly

Best transformer for tmp=tmp.n 49 null h t {t} tmp n { } n {h, tmp} n n null h t {t} tmp n { } n {h, tmp} n null h t {t} tmp n { } n {h, tmp} n { } 

Best transformer for tmp=tmp.n:  50 null h t {t} tmp n { } n {h, tmp} n n null h t {t} tmp n { } n {h, tmp} n null h t {t} tmp n { } n {h, tmp} n { }  null h t {t} tmp n { } n {h, tmp} n { } …

Best transformer for  tmp=tmp.n  51 null h t {t} tmp n { } n {h, tmp} n n null h t {t} tmp n {tmp } n {h} n null h t {t} tmp n { } n {h} n { } {tmp } null h t {t} tmp n { } n {h} n { } {tmp } …

Best transformer for tmp=tmp.n:  52 null h t {t} tmp n { } n {h, tmp} n n null h t {t} tmp n {tmp } n {h} n null h t {t} tmp n { } n {h} n {tmp } null h t {t} tmp n { } n {h} n {tmp } …

Handling updates on summary nodes Transformers accessing only concrete nodes are easy Transformers accessing summary nodes are complicated Can’t concretize summary nodes – represents potentially unbounded number of concrete nodes We need to split into cases by “materializing” concrete nodes from summary node – Introduce a new temporary predicate tmp.n – Partial concretization 53

Transformer for tmp=tmp.n:  ’ 54 null h t {t} tmp n { } n {h, tmp} n n ’’ Case 1: Exactly 1 object. Case 2: >1 objects.

Transformer for tmp=tmp.n:  ’ 55 null h t {t} tmp n { } n {h, tmp} n n null h t {t} tmp n {tmp.n } n {h, tmp} n null h t {t} tmp n { } n {h, tmp} n {tmp.n } ’’ tmp.n is a concrete node Summary node spaghetti

Transformer  tmp=tmp.n  56 null h t {t} tmp n { } n {h, tmp} n n null h t {t} tmp n {t, tmp.n } n {h} n null h t {t} tmp n { } n {h} n {t, tmp.n }

Transformer for tmp=tmp.n:  57 null h t {t} tmp n {t} n {h} n null h t {t} tmp n { } n {h} n {t} // Build a list SLL h=null, t = null; L1: h=t= new SLL(-1); SLL tmp = null; while (…) { int data = getData(…); L2: tmp = new SLL(data); tmp.n = h; h = tmp; } // Process elements tmp = h; while (tmp != t) { assert tmp != null; tmp.data += 1; tmp = tmp.n; }

Transformer via partial-concretization 58 CA 2 3 f f # (a)=  ’(f # ’(  ’(a))) 1 f#f# 4 A’ 5 f #’ 6 ’’ ’’

Recap Adding more properties to nodes refines abstraction Can add temporary properties for partial concretization – Materialize concrete nodes from summary nodes – Allows turning weak updates into strong ones – Focus operation in shape-analysis lingo – Not trivial in general and requires more semantic reduction to clean up impossible edges – General algorithms available via 3-valued logic and implemented in TVLA system 59

Analyzing singly-linked lists 60

Specialized analysis for SLL Very simple shape analysis Assumes – SLL only data structure – Data fields cannot point to SLL nodes – No recursive procedures Simple algorithms, quick implementation – Implemented in Abstract Interpretation package 61

What is it good for? Supports assertions – assertReach(x,y) – assertDisjointLists(x,y) Enables parallelization – assertAcyclicList(x) – assertCyclicList(x) – assert(x==y)assert(x!=y) Check cleanness properties – Absence of NullPointerException ’s – Absence of memory leaks (in C) – No misuse of dangling pointers (in C) 62

Concrete store x y class SLL { int data; SLL n; } n nnnnnnnn nnn n 63

Interrupting nodes x y Interruption: node pointed-to by a variable or shared by n fields #interruptions ≤ 2 · #variables (bounded number of sharing patterns) n nnnnnnnn nnn n 64

List segments x y Maximal sub-list between two interruptions not containing interruptions in-between n nnnnnnn nnn n n 65

List segments x y segment 2segment 1 segment 3 segment 4 n nnnnnnn nnn n n 66

Abstraction idea Add following instrumentation predicates to each node – x(v) – node v is pointed-to by variable x – seg(v) – node v is properly contained in a list segment Merge nodes within the same end points of a segment 67

Instrumented store x y seg n nnnnnnn nnn n n 68

Abstract store x y n n nn n nn n n n seg 69

Store it represents x y seg n nnnnnnn nnn n n 70

Store it does not represent x y seg n nnnnnnn nnn n n 71

Simplified representation x y 1 >1 Make summary node implicit. Abstract length: how many links in segment {1, >1} 72

Intuitive meaning of abstraction Retains overall “shape” of the heap – Which important points exist – How they are connected via paths – Precisely captures disjointness/sharing/cycles Abstracts away – Lengths of simple paths – Many times not relevant for proving correctness of list-manipulating programs – But sometimes is Refinements with numerical abstractions of lengths is needed 73

Abstract transformers for singly-linked lists 74

Abstract transformers Need transformers for program statements – x = new List() – x = null – x = y – x = y.n – x.n = y – assume x!=y – assume x==y 75

Simplifying code transformations Code transformations that preserve semantics and simplify implementing transformers by eliminating annoying corner cases Precede all assignment to x by x=null E.g., replace x=new List() with x=null; x=new List() Replace x=x.n with t=x.n; x=t Replace x.n=x with t=x; x.n=t Replace x.n=t with x.n=null; x.n=t 76

 x = new List()  # Recall assumption that x==null before statement (simplifying transformation) Allocate new node and have x point to it – Just like concrete semantics 77 t y n >1 x null  x = new List()  # t y 1 >1 x null 1

 x = t  # Recall assumption that x==null before statement (simplifying transformation) t points to a concrete node Have x point to that node – Just like concrete semantics 78 t y 1 >1 x null  x = t  # t y 1 >1 x null

 x = null  # Case 1: x points to an interruption that remains an interruption even without x pointing to it Just have x point to null 79 t y 1 >1 x  x = null  # t y 1 >1 x null

 x = null  # Case 2: x points to an interruption that ceases to be an interruption Have x point to null 80 t 1 >1 x  x = null  # t 1 >1 x null

 x = null  # Case 2: x points to an interruption that ceases to be an interruption Step 1: Have x point to null Step 2: Abstract non-maximal list segments 81 t 1 >1 x  x = null  # t 1 >1 x null

 x = null  # Case 2: x points to an interruption that ceases to be an interruption Step 1: Have x point to null Step 2: Abstract non-maximal list segments 82 t 1 >1 x  x = null  # t >1 x null >1

 x = y.n  # Recall assumption that x==null before statement (simplifying transformation) Case 1: y.n is an interruption (edge with abstract length 1) Just have x point to the successor of y 83 t y 1 >1 1  x = y.n  # t y 1 >1 1 x x null

 x = y.n  # Recall assumption that x==null before statement (simplifying transformation) Case 2: y.n is not an interruption (edge with abstract length >1) Apply partial concretization and then do case 1 84 t y 1 >1  x = y.n  # x null What lengths does it represent?

 x = y.n  # Recall assumption that x==null before statement (simplifying transformation) Case 2: y.n is not an interruption (edge with abstract length >1) Apply partial concretization and then do case 1 85 t y 1 >1  x = y.n  # x null >1 = 2 or >2

 x = y.n  # Recall assumption that x==null before statement (simplifying transformation) Case 2: y.n is not an interruption (edge with abstract length >1) Apply partial concretization and then do case 1 86 t y null 1 >1 ’’ x t y null 1 >1 x 1 1 t y null 1 >1 x 1

 x = y.n  # Recall assumption that x==null before statement (simplifying transformation) Case 2: y.n is not an interruption (edge with abstract length >1) Apply partial concretization and then do case 1 87 t y null 1 >1  x = y.n   ’ x t y null 1 >1 x 1 1 t y null 1 >1 x 1

 x.n = null  # Can be used to detect memory leaks – (Also x=null) Again two cases: x.n is a concrete node / x.n is a summary node 88

 x.n = null  # Can be used to detect memory leaks Again two cases: x.n is a concrete node / x.n is a summary node Case 1: x.n is a concrete node Follow concrete semantics 89 t x null 1 >1 1  x.n = null  # t x null 1 >1 1 Need to merge non- maximal segment

 x.n = null  # Can be used to detect memory leaks Again two cases: x.n is a concrete node / x.n is a summary node Case 1: x.n is a concrete node Follow concrete semantics 90 t x null 1 >1 1  x.n = null  # t x null 1 >1

 x.n = null  # Can be used to detect memory leaks Again two cases: x.n is a concrete node / x.n is a summary node Case 2: x.n is a summary node Apply partial concretization and do case 1 91 t x null 1 >1  x.n = null  # … What can go wrong here in C?

 x.n = y  # Trivial after x.n=null 92 t x null 1 >1 1 y  x.n = y  # t x null 1 >1 1 y

 assume x==y  #  assume x!=y  # How do we check these? 93

Checking assertions How do we check these? – assertReach(x,y) – assertDisjointLists(x,y) – assertAcyclicList(x) – assertCyclicList(x) 94

Proving termination of heap-manipulating programs 95

The Goal Input: a program in a language with objects (Java, C++, C#...) Output: proof that program terminates or some information to suggest otherwise Why is it important? – When a device driver goes into an infinite loop your operating system hangs

The Challenge Proving termination is undecidable – Turing’s halting problem But the problem is really important What can we do? – Give up – Provide approximate algorithms with one-sided error (sound): if answer is yes program terminates but if answer is no we don’t really know – Focus on a subset of programs

[ x=y & list(x, null) ] L1: while (y != null) y := y.n; L2: skip; exit: [ y=null & list(x, null)] A Simple Example

[ x=y & list(x, null) ] t := 0; L1: while (y != null) ++t; assert t < |list(x,null)|; y := y.n; L2: skip; exit: [ y=null & list(x, null)] Idea: add counters and prove bound But how do we prove this?

Idea: Use Shape Abstraction Approximate memory layout by abstracting into a finite number of equivalence classes L1: xy nul l S4S4 xy 11 L1: 

xy a nul l b S1S1 xy m n S5S5 xy c d S2S2 xy o p S6S6 xy k l S4S4 i j xy g h S3S3 e f L1: L2: L3: Abstract Transition Relation Finite approximation of all program executions Where did the counter go?

xy d nul l 11 abc xy h 22 efg L1: L2: Idea: Encode Counter In Objects QFPA constraint for single transition Problem: infinite system of constraints for ALL transitions

Final Solution Generate constraints for abstract transition relation Finite system of constraints = quantifier-free formula in Presburger arithmetic Formula is satisfiable  program is Loop Polynomial – Polynomial in the maximum nesting depth – Each loop performs linear number iterations Satisfiability is decidable Works well in practice

Next lecture: Interprocedural analysis