Lazy Abstraction Lecture 2: Modular Analyses Ranjit Jhala UC San Diego With: Tom Henzinger, Rupak Majumdar, Ken McMillan, Gregoire Sutre.

Slides:



Advertisements
Similar presentations
Greta YorshEran YahavMartin Vechev IBM Research. { ……………… …… …………………. ……………………. ………………………… } T1() Challenge: Correct and Efficient Synchronization { ……………………………
Advertisements

1 Chao Wang, Yu Yang*, Aarti Gupta, and Ganesh Gopalakrishnan* NEC Laboratories America, Princeton, NJ * University of Utah, Salt Lake City, UT Dynamic.
A Program Transformation For Faster Goal-Directed Search Akash Lal, Shaz Qadeer Microsoft Research.
Verification of Evolving Software Natasha Sharygina Joint work with Sagar Chaki and Nishant Sinha Carnegie Mellon University.
Automatic Verification Book: Chapter 6. What is verification? Traditionally, verification means proof of correctness automatic: model checking deductive:
50.530: Software Engineering Sun Jun SUTD. Week 10: Invariant Generation.
Abstraction and Modular Reasoning for the Verification of Software Corina Pasareanu NASA Ames Research Center.
Lecture 8: Three-Level Architectures CS 344R: Robotics Benjamin Kuipers.
Rigorous Software Development CSCI-GA Instructor: Thomas Wies Spring 2012 Lecture 13.
Introducing BLAST Software Verification John Gallagher CS4117.
Software Verification with BLAST Tom Henzinger Ranjit Jhala Rupak Majumdar.
A survey of techniques for precise program slicing Komondoor V. Raghavan Indian Institute of Science, Bangalore.
Proofs and Counterexamples Rupak Majumdar. In the good old days… Decision Procedure  yes no.
BLAST-A Model Checker for C Developed by Thomas A. Henzinger (EPFL) Rupak Majumdar (UC Los Angeles) Ranjit Jhala (UC San Diego) Dirk Beyer (Simon Fraser.
The Software Model Checker BLAST by Dirk Beyer, Thomas A. Henzinger, Ranjit Jhala and Rupak Majumdar Presented by Yunho Kim Provable Software Lab, KAIST.
Thread-modular Abstraction Refinement Tom Henzinger Ranjit Jhala Rupak Majumdar Shaz Qadeer.
Permissive Interfaces Tom Henzinger Ranjit Jhala Rupak Majumdar.
Software Verification with Blast Thomas A. Henzinger, Ranjit Jhala, Rupak Majumdar, George Necula, Grégoire Sutre, Wes Weimer UC Berkeley.
Static Analysis of Embedded C Code John Regehr University of Utah Joint work with Nathan Cooprider.
Scalable Program Verification by Lazy Abstraction Ranjit Jhala U.C. Berkeley.
Lazy Abstraction Thomas A. Henzinger Ranjit Jhala Rupak Majumdar Grégoire Sutre UC Berkeley.
Program Verification by Lazy Abstraction Ranjit Jhala UC San Diego Lecture 1 With: Tom Henzinger, Rupak Majumdar, Ken McMillan, Gregoire Sutre.
Thread-modular Abstraction Refinement Tom Henzinger Ranjit Jhala Rupak Majumdar [UC Berkeley] Shaz Qadeer [Microsoft Research]
Lazy Predicate Abstraction in BLAST John Gallagher CS4117.
Speeding Up Dataflow Analysis Using Flow- Insensitive Pointer Analysis Stephen Adams, Tom Ball, Manuvir Das Sorin Lerner, Mark Seigle Westley Weimer Microsoft.
Modular Verification of Multithreaded Software Shaz Qadeer Compaq Systems Research Center Shaz Qadeer Compaq Systems Research Center Joint work with Cormac.
Counter Example Guided Refinement CEGAR Mooly Sagiv.
Race Checking by Context Inference Tom Henzinger Ranjit Jhala Rupak Majumdar UC Berkeley.
Software Reliability Methods Sorin Lerner. Software reliability methods: issues What are the issues?
Predicate Abstraction for Software and Hardware Verification Himanshu Jain Model checking seminar April 22, 2005.
Temporal-Safety Proofs for Systems Code Thomas A. Henzinger Ranjit Jhala Rupak Majumdar George Necula Westley Weimer Grégoire Sutre UC Berkeley.
1 RELAY: Static Race Detection on Millions of Lines of Code Jan Voung, Ranjit Jhala, and Sorin Lerner UC San Diego speaker.
Software Verification with BLAST Tom Henzinger Ranjit Jhala Rupak Majumdar.
A. Frank - P. Weisberg Operating Systems Introduction to Cooperating Processes.
1 Formal Engineering of Reliable Software LASER 2004 school Tutorial, Lecture1 Natasha Sharygina Carnegie Mellon University.
Lazy Abstraction Tom Henzinger Ranjit Jhala Rupak Majumdar Grégoire Sutre.
Ranjit Jhala Rupak Majumdar Interprocedural Analysis of Asynchronous Programs.
Cormac Flanagan UC Santa Cruz Velodrome: A Sound and Complete Dynamic Atomicity Checker for Multithreaded Programs Jaeheon Yi UC Santa Cruz Stephen Freund.
Lazy Abstraction Lecture 3 : Partial Analysis Ranjit Jhala UC San Diego With: Tom Henzinger, Rupak Majumdar, Ken McMillan, Gregoire Sutre.
Program Verification by Lazy Abstraction Ranjit Jhala UC San Diego Lecture 1 With: Tom Henzinger, Rupak Majumdar, Ken McMillan, Gregoire Sutre, Adam Chlipala.
272: Software Engineering Fall 2012 Instructor: Tevfik Bultan Lecture 4: SMT-based Bounded Model Checking of Concurrent Software.
Maria-Cristina Marinescu Martin Rinard Laboratory for Computer Science Massachusetts Institute of Technology A Synthesis Algorithm for Modular Design of.
Thread-modular Abstraction Refinement Thomas A. Henzinger, et al. CAV 2003 Seonggun Kim KAIST CS750b.
Program Analysis with Dynamic Change of Precision Dirk Beyer Tom Henzinger Grégory Théoduloz Presented by: Pashootan Vaezipoor Directed Reading ASE 2008.
Exercise Solutions 2014 Fall Term. Week 2: Exercise 1 public static Boolean repOK(Stack mystack) { if (mystack.capacity() < 0) { return false;
Survey on Trace Analyzer (2) Hong, Shin /34Survey on Trace Analyzer (2) KAIST.
Race Checking by Context Inference Tom Henzinger Ranjit Jhala Rupak Majumdar UC Berkeley.
Lazy Abstraction Jinseong Jeon ARCS, KAIST CS750b, KAIST2/26 References Lazy Abstraction –Thomas A. Henzinger et al., POPL ’02 Software verification.
Operating Systems ECE344 Ashvin Goel ECE University of Toronto Mutual Exclusion.
Localization and Register Sharing for Predicate Abstraction Himanshu Jain Franjo Ivančić Aarti Gupta Malay Ganai.
CSCI1600: Embedded and Real Time Software Lecture 11: Modeling IV: Concurrency Steven Reiss, Fall 2015.
Ranjit Jhala Rupak Majumdar Interprocedural Analysis of Asynchronous Programs.
/ PSWLAB Thread Modular Model Checking by Cormac Flanagan and Shaz Qadeer (published in Spin’03) Hong,Shin Thread Modular Model.
Counter Example Guided Refinement CEGAR Mooly Sagiv.
#1 Having a BLAST with SLAM. #2 Software Model Checking via Counter-Example Guided Abstraction Refinement Topic: Software Model Checking via Counter-Example.
Lecture 5 Page 1 CS 111 Summer 2013 Bounded Buffers A higher level abstraction than shared domains or simple messages But not quite as high level as RPC.
The software model checker BLAST Dirk Beyer, Thomas A. Henzinger, Ranjit Jhala, Rupak Majumdar Presented by Yunho Kim TexPoint fonts used in EMF. Read.
Having a BLAST with SLAM
Sequentializing Parameterized Programs
Amir Kamil and Katherine Yelick
CSCI1600: Embedded and Real Time Software
CSCI1600: Embedded and Real Time Software
Amir Kamil and Katherine Yelick
Abstractions from Proofs
Program Verification by Lazy Abstraction
Abstraction, Verification & Refinement
Software Verification with BLAST
Predicate Abstraction
BLAST: A Software Verification Tool for C programs
Presentation transcript:

Lazy Abstraction Lecture 2: Modular Analyses Ranjit Jhala UC San Diego With: Tom Henzinger, Rupak Majumdar, Ken McMillan, Gregoire Sutre

Program Verification by Lazy Abstraction Ranjit Jhala UC San Diego Lecture 1 With: Tom Henzinger, Rupak Majumdar, Ken McMillan, Gregoire Sutre

Last lecture … Lazy Abstraction for Sequential Programs Predicates: –Abstract infinite program states Counterexample-guided Refinement: –Find predicates tailored to prog, property 1.Abstraction : Expensive Reachability Tree 2.Refinement : Find predicates, use locations Proof of unsat of TF + Interpolation

This Lecture: Modular Analyses Procedures - Summaries Concurrency - Thread-Context Reasoning

An example main(){  1: if (flag){ 2: y = inc(x,flag); 3: if (y<=x) ERROR; } else { 4: y = inc(z,flag); 5: if (y>=z) ERROR; }  return; } main(){  1: if (flag){ 2: y = inc(x,flag); 3: if (y<=x) ERROR; } else { 4: y = inc(z,flag); 5: if (y>=z) ERROR; }  return; } inc(int a, int sign){ 1: if (sign){ 2: rv = a+1; } else { 3: rv = a-1; } 4: return rv; } inc(int a, int sign){ 1: if (sign){ 2: rv = a+1; } else { 3: rv = a-1; } 4: return rv; }

Inline Calls in Reach Tree main(){  1: if (flag){ 2: y = inc(x,flag); 3: if (y<=x) ERROR; } else { 4: y = inc(z,flag); 5: if (y>=z) ERROR; }  return; } main(){  1: if (flag){ 2: y = inc(x,flag); 3: if (y<=x) ERROR; } else { 4: y = inc(z,flag); 5: if (y>=z) ERROR; }  return; } inc(int a, int sign){ 1: if (sign){ 2: rv = a+1; } else { 3: rv = a-1; } 4: return rv; } inc(int a, int sign){ 1: if (sign){ 2: rv = a+1; } else { 3: rv = a-1; } 4: return rv; } 1 2 1,2 Initial 2,2 4,2 3,2 4, ,4 2,4 4,4 3,4 4,4 5 5

Inline Calls in Reach Tree 1 2 1,2 Initial 2,2 4,2 3,2 4, ,4 2,4 4,4 3,4 4,4 5 5 Problem -Repeated analysis for “inc” -Exploding call contexts int x; //global f1(){ 1: x = 0; 2: if(*) f2(); 3: else f2(); 4: if (x<0) ERROR; return; } int x; //global f1(){ 1: x = 0; 2: if(*) f2(); 3: else f2(); 4: if (x<0) ERROR; return; } f2(){ 1: if(*) f3(); 2: else f3(); return; } f2(){ 1: if(*) f3(); 2: else f3(); return; } f3(){ 1: if(*) f4(); 2: else f4(); return; } f3(){ 1: if(*) f4(); 2: else f4(); return; } f4(){ 1: if(*) f5(); 2: else f5(); return; } f4(){ 1: if(*) f5(); 2: else f5(); return; } fn(){ 1: x ++; return; } fn(){ 1: x ++; return; } 2 n nodes in Reach Tree

Inline Calls in Reach Tree 1 2 1,2 Initial 2,2 4,2 3,2 4, ,4 2,4 4,4 3,4 4,4 5 5 Problem -Repeated analysis for “inc” -Exploding call contexts -Cyclic call graph (Recursion) -Infinite Tree!

Solution : Procedure Summaries Summaries: Input/Output behavior Plug summaries in at each callsite … instead of inlining entire procedure [Sharir-Pnueli 81, Reps-Horwitz-Sagiv 95] Summary = set of (F  F’) –F : Precondition formula describing input state –F’ : Postcondition formula describing output state

Solution : Procedure Summaries Summaries: Input/Output behavior Plug summaries in at each callsite … instead of inlining entire procedure [Sharir-Pnueli 81, Reps-Horwitz-Sagiv 95, Ball-Rajamani 01] Summary = set of (F  F’) –F : Precondition formula describing input state –F’ : Postcondition formula describing output state inc(int a, int sign){ 1: if (sign){ 2: rv = a+1; } else { 3: rv = a-1; } 4: return rv; } inc(int a, int sign){ 1: if (sign){ 2: rv = a+1; } else { 3: rv = a-1; } 4: return rv; } ( : sign=0  rv > a) (sign = 0  rv < a) Q. How to compute, use summaries ?

Lazy Abstraction + Procedure Summaries Abstract Refine C Program Safe Trace Yes No Property Q. How to compute, use summaries ?

Abstraction with Summaries main(){  1: if (flag){ 2: y = inc(x,flag); 3: if (y<=x) ERROR; } else { 4: y = inc(z,flag); 5: if (y>=z) ERROR; }  return; } main(){  1: if (flag){ 2: y = inc(x,flag); 3: if (y<=x) ERROR; } else { 4: y = inc(z,flag); 5: if (y>=z) ERROR; }  return; } inc(int a, int sign){ 1: if (sign){ 2: rv = a+1; } else { 3: rv = a-1; } 4: return rv; } inc(int a, int sign){ 1: if (sign){ 2: rv = a+1; } else { 3: rv = a-1; } 4: return rv; } 1 2 main Predicates: flag=0, y>x, y<z sign=0, rv>a, rv<a : flag=0 a=x sign=flag : sign=0 [flag!=0]

Abstraction with Summaries main(){  1: if (flag){ 2: y = inc(x,flag); 3: if (y<=x) ERROR; } else { 4: y = inc(z,flag); 5: if (y>=z) ERROR; }  return; } main(){  1: if (flag){ 2: y = inc(x,flag); 3: if (y<=x) ERROR; } else { 4: y = inc(z,flag); 5: if (y>=z) ERROR; }  return; } inc(int a, int sign){ 1: if (sign){ 2: rv = a+1; } else { 3: rv = a-1; } 4: return rv; } inc(int a, int sign){ 1: if (sign){ 2: rv = a+1; } else { 3: rv = a-1; } 4: return rv; } main 2 4 Predicates: flag=0, y>x, y<z sign=0, rv>a, rv<a inc : flag=0 : sign=0 a=x sign=flag : sign=0 [sign!=0] : sign=0 rv=a+1 rv>a Summary: ( : sign=0  rv>a),

Summary Successor main(){  1: if (flag){ 2: y = inc(x,flag); 3: if (y<=x) ERROR; } else { 4: y = inc(z,flag); 5: if (y>=z) ERROR; }  return; } main(){  1: if (flag){ 2: y = inc(x,flag); 3: if (y<=x) ERROR; } else { 4: y = inc(z,flag); 5: if (y>=z) ERROR; }  return; } inc(int a, int sign){ 1: if (sign){ 2: rv = a+1; } else { 3: rv = a-1; } 4: return rv; } inc(int a, int sign){ 1: if (sign){ 2: rv = a+1; } else { 3: rv = a-1; } 4: return rv; } main 2 4 Predicates: flag=0, y>x, y<z sign=0, rv>a, rv<a inc : flag=0 : sign=0 rv>a Summary: ( : sign=0  rv>a), 3 a=x sign=flag y>x assume rv>a y=rv

Abstraction with Summaries main(){  1: if (flag){ 2: y = inc(x,flag); 3: if (y<=x) ERROR; } else { 4: y = inc(z,flag); 5: if (y>=z) ERROR; }  return; } main(){  1: if (flag){ 2: y = inc(x,flag); 3: if (y<=x) ERROR; } else { 4: y = inc(z,flag); 5: if (y>=z) ERROR; }  return; } inc(int a, int sign){ 1: if (sign){ 2: rv = a+1; } else { 3: rv = a-1; } 4: return rv; } inc(int a, int sign){ 1: if (sign){ 2: rv = a+1; } else { 3: rv = a-1; } 4: return rv; } main 2 4 Predicates: flag=0, y>x, y<z sign=0, rv>a, rv<a inc : flag=0 : sign=0 rv>a Summary: ( : sign=0  rv>a), 3 y>x [y<=x] 3 4 flag=0 a=x sign=flag sign=0 [sign=0] [flag==0]

Abstraction with Summaries main(){  1: if (flag){ 2: y = inc(x,flag); 3: if (y<=x) ERROR; } else { 4: y = inc(z,flag); 5: if (y>=z) ERROR; }  return; } main(){  1: if (flag){ 2: y = inc(x,flag); 3: if (y<=x) ERROR; } else { 4: y = inc(z,flag); 5: if (y>=z) ERROR; }  return; } inc(int a, int sign){ 1: if (sign){ 2: rv = a+1; } else { 3: rv = a-1; } 4: return rv; } inc(int a, int sign){ 1: if (sign){ 2: rv = a+1; } else { 3: rv = a-1; } 4: return rv; } main 2 4 Predicates: flag=0, y>x, y<z sign=0, rv>a, rv<a inc : flag=0 : sign=0 rv>a Summary: ( : sign=0  rv>a), (sign=0  rv<a) 3 y>x 3 4 flag=0 a=x sign=flag sign= rv<a

Summary Successor main(){  1: if (flag){ 2: y = inc(x,flag); 3: if (y<=x) ERROR; } else { 4: y = inc(z,flag); 5: if (y>=z) ERROR; }  return; } main(){  1: if (flag){ 2: y = inc(x,flag); 3: if (y<=x) ERROR; } else { 4: y = inc(z,flag); 5: if (y>=z) ERROR; }  return; } inc(int a, int sign){ 1: if (sign){ 2: rv = a+1; } else { 3: rv = a-1; } 4: return rv; } inc(int a, int sign){ 1: if (sign){ 2: rv = a+1; } else { 3: rv = a-1; } 4: return rv; } main 2 4 Predicates: flag=0, y>x, y<z sign=0, rv>a, rv<a inc : flag=0 : sign=0 rv>a Summary: ( : sign=0  rv>a), (sign=0  rv<a) 3 y>x 3 4 flag=0 1 sign= rv<a a=x sign=flag assume rv<a y=rv 3 y<z

Abstraction with Summaries main(){  1: if (flag){ 2: y = inc(x,flag); 3: if (y<=x) ERROR; } else { 4: y = inc(z,flag); 5: if (y>=z) ERROR; }  return; } main(){  1: if (flag){ 2: y = inc(x,flag); 3: if (y<=x) ERROR; } else { 4: y = inc(z,flag); 5: if (y>=z) ERROR; }  return; } inc(int a, int sign){ 1: if (sign){ 2: rv = a+1; } else { 3: rv = a-1; } 4: return rv; } inc(int a, int sign){ 1: if (sign){ 2: rv = a+1; } else { 3: rv = a-1; } 4: return rv; } main 2 4 Predicates: flag=0, y>x, y<z sign=0, rv>a, rv<a inc : flag=0 : sign=0 rv>a Summary: ( : sign=0  rv>a), (sign=0  rv<a) 3 y>x 3 4 flag=0 1 sign= rv<a 3 y<z [y>=z]

Another Call … main(){  1: if (flag){ 2: y = inc(x,flag); 3: if (y<=x) ERROR; } else { 4: y = inc(z,flag); 5: if (y>=z) ERROR; } 6: y1 = inc(z1,1); 7: if (y1<=z1) ERROR; return; } main(){  1: if (flag){ 2: y = inc(x,flag); 3: if (y<=x) ERROR; } else { 4: y = inc(z,flag); 5: if (y>=z) ERROR; } 6: y1 = inc(z1,1); 7: if (y1<=z1) ERROR; return; } inc(int a, int sign){ 1: if (sign){ 2: rv = a+1; } else { 3: rv = a-1; } 4: return rv; } inc(int a, int sign){ 1: if (sign){ 2: rv = a+1; } else { 3: rv = a-1; } 4: return rv; } main 2 4 inc : flag=0 : sign=0 rv>a Summary: ( : sign=0  rv>a), (sign=0  rv<a) 3 6 y>x 3 4 flag=0 1 sign= rv<a 3 y<z a=z1 sign=1 : sign=0 6 Predicates: flag=0,y>x,y z1 sign=0, rv>a, rv<a

Another Call … main(){  1: if (flag){ 2: y = inc(x,flag); 3: if (y<=x) ERROR; } else { 4: y = inc(z,flag); 5: if (y>=z) ERROR; } 6: y1 = inc(z1,1); 7: if (y1<=z1) ERROR; return; } main(){  1: if (flag){ 2: y = inc(x,flag); 3: if (y<=x) ERROR; } else { 4: y = inc(z,flag); 5: if (y>=z) ERROR; } 6: y1 = inc(z1,1); 7: if (y1<=z1) ERROR; return; } inc(int a, int sign){ 1: if (sign){ 2: rv = a+1; } else { 3: rv = a-1; } 4: return rv; } inc(int a, int sign){ 1: if (sign){ 2: rv = a+1; } else { 3: rv = a-1; } 4: return rv; } main 2 4 Predicates: flag=0,y>x,y z1 sign=0, rv>a, rv<a inc : flag=0 : sign=0 rv>a Summary: ( : sign=0  rv>a), (sign=0  rv<a) 3 6 y>x 3 4 flag=0 1 sign= rv<a 3 y<z 7 a=z1 sign=1 assume rv>a y1=rv 6 y1>z1 SAFE Note: Predicates are well-scoped …

Lazy Abstraction + Procedure Summaries Abstract Refine C Program Safe Trace Yes No Property Q. How to find scoped predicates ?

pc 1 : x 1 = 3 pc 2 : assume (x 1 >0) pc 3 : x 3 = f 1 (x 1 ) pc 4 : y 2 = y 1 pc 5 : y 3 = f 2 (y 2 ) pc 6 : z 2 = z 1 +1 pc 7 : z 3 = 2*z 2 pc 8 : return z 3 pc 9 : return y 3 pc 10 : x 4 = x 3 +1 pc 11 : x 5 = f 3 (x 4 ) pc 12 : assume(w 1 <5) pc 13 : return w 1 pc 14 : assume x 4 >5 pc 15 : assume (x 1 =x 3 +2) Traces with Procedure Calls Trace Formula i Trace i Find predicate needed at point i pc 1 : x 1 = 3 pc 2 : assume (x 1 >0) pc 3 : x 3 = f 1 (x 1 ) pc 4 : y 2 = y 1 pc 5 : y 3 = f 2 (y 2 ) pc 6 : z 2 = z 1 +1 pc 7 : z 3 = 2*z 2 pc 8 : return z 3 pc 9 : return y 3 pc 10 : x 4 = x 3 +1 pc 11 : x 5 = f 3 (x 4 ) pc 12 : assume(w 1 <5) pc 13 : return w 1 pc 14 : assume x 4 >5 pc 15 : assume(x 1 =x 3 +2)

Interprocedural Analysis Trace Formula i Trace i Require at each point i : Scoped predicates YES: Variables visible at i NO: Caller’s local variables Find predicate needed at point i YES NO

Problems with Cutting Trace Formula i Trace i -- ++ Caller variables common to  - and  + Unsuitable interpolant: not well-scoped

Scoped Cuts Trace Formula i Call begins Trace i

Scoped Cuts -- ++ Trace Formula i Call begins Trace i Predicate at pc i = Interpolant from cut i

Common Variables Formals Current locals Trace Formula Predicate at pc i = Interpolant from i-cut i Trace i -- ++ Common Variables Formals Well-scoped

Example Trace m1: assume(flag!=0) m2: y=inc(x,flag) i1: assume(sign!=0) i2: rv = a+1 i4: return rv m3: assume(y<=x) ERROR: main(){  1: if (flag){ 2: y = inc(x,flag); 3: if (y<=x) ERROR; } else { 4: y = inc(z,flag); 5: if (y>=z) ERROR; }  return; } main(){  1: if (flag){ 2: y = inc(x,flag); 3: if (y<=x) ERROR; } else { 4: y = inc(z,flag); 5: if (y>=z) ERROR; }  return; } inc(int a, int sign){ 1: if (sign){ 2: rv = a+1; } else { 3: rv = a-1; } 4: return rv; } inc(int a, int sign){ 1: if (sign){ 2: rv = a+1; } else { 3: rv = a-1; } 4: return rv; }

Trace Formula Trace SSA Trace m1: assume(flag!=0) m2: y=inc(x,flag) i1: assume(sign!=0) i2: rv = a+1 i4: return rv m3: assume(y<=x) m1: assume(flag 0 !=0) m2: a 0 =x 0, sign 0 =flag 0 i1: assume(sign 0 !=0) i2: rv 0 =a 0 +1 i4: y 0 =rv 0 m3: assume(y 0 <= x 0 )

Trace Formula TraceTrace Formula m1: assume(flag!=0) m2: y=inc(x,flag) i1: assume(sign!=0) i2: rv = a+1 i4: return rv m3: assume(y<=x) Æ flag 0  0 Æ a 0 =x 0 Æ sign 0 = flag 0 Æ sign 0  0 Æ rv 0 =a 0 +1 Æ y 0 =rv 0 Æ y 0 <= x 0 ii Call begins

Trace Formula TraceTrace Formula m1: assume(flag!=0) m2: y=inc(x,flag) i1: assume(sign!=0) i2: rv = a+1 i4: return rv m3: assume(y<=x) Æ flag 0  0 Æ a 0 =x 0 Æ sign 0 = flag 0 Æ sign 0  0 Æ rv 0 =a 0 +1 Æ y 0 =rv 0 Æ y 0 <= x 0 -- ++ ii

Trace Formula TraceTrace Formula m1: assume(flag!=0) m2: y=inc(x,flag) i1: assume(sign!=0) i2: rv = a+1 i4: return rv m3: assume(y<=x) Æ flag 0  0 Æ a 0 =x 0 Æ sign 0 = flag 0 Æ sign 0  0 Æ rv 0 =a 0 +1 Æ y 0 =rv 0 Æ y 0 <= x 0 i -- ++ i rv 0 a0a0 a0a0 rv 0 > a 0 Interpolate

Lazy Abstraction + Procedure Summaries Abstract Refine C Program Safe Trace Yes No Property Q. How to find scoped predicates ? Solution: Scoped Cuts + Interpolation

Review : Procedures Modular Analysis via Summaries –Summary = (In,Out) vertices’ formulas Requires scoped predicates –Scoped cuts + Interpolation

This Lecture: Modular Analyses Procedures - Summaries Concurrency - Thread-Context Reasoning

This Lecture: Modular Analyses Procedures - Summaries Concurrency - Thread-Context Reasoning

Multithreaded Programs OS, WebServers, Databases, Embedded Systems Curse of Interleaving Non-deterministic scheduling Exponentially many behaviors: hard to detect, reproduce errors Testing exercises a fraction of possible behaviors Thread Shared Memory x Thread Thread

Data Races  x:= x+1   x:= x+1   x:= x-5   x:= x-5  x A data race on x is a state where: Two threads can access x One of the accesses is a write Unpredictable, undesirable Synchronization: Must hold lock when accessing x lock(l) unlock(l) lock(l) unlock(l)

Previous Work : Locks  x:= x+1  x:= x+1  lock(l) unlock(l) 1.Infer some lock(s) that protect x 2.Check lock(s) held when accessing x 3.Report error if lock(s) not held Static LockSet [Sterling 93], [Engler-Ashcraft 03] [Flanagan-Freund 00] [Bacon et al. 00] [Boyapati et al. 02] [Dinning-Schonberg 90] [Savage et al. 97] [Cheng et al. 98] [Choi et al. 02] Type-based Dynamic LockSet Object Usage Graph [von Praun-Gross 03] Scalable Restricted to locking

Other Synchronization Idioms Producer-Consumer atomic{ old:= state; if(state==0){ state:=1; }  if(old==0){ x++; state:=0; } atomic{ old:= state; if(state==0){ state:=1; }  if(old==0){ x++; state:=0; } State-basedInterrupt-toggling x

Previous Work : Model Checking Producer-Consumer atomic{ old:= state; if(state==0){ state:=1; }  if(old==0){ x++; state:=0; } atomic{ old:= state; if(state==0){ state:=1; }  if(old==0){ x++; state:=0; } State-basedInterrupt-toggling x Model Checking (State Exploration) [Godefroid 97] [Holzmann][Havelund-Visser] [Dwyer-Hatcliff][Avrunin-Clarke] [Musuvathi-Dill-Engler 02] [Yahav 01] Any Synch. Idiom Fixed #threads Manual Abstraction State Explosion

Data Race Shared Memory Initial Race Checking by State Exploration Is there a path from Initial to Race ?

Problem: State Explosion Shared Memory Data Race Initial Is there a path from Initial to Race ?

Problem: State Explosion 2. Control k threads, m locations = m k - k=4,m=100, states = 1 billion Unbounded threads ? 1. Data Infinitely many valuations for program variables Data Race Initial

LA for Multithreaded Programs 1.Data Races –Previous Work –State Explosion 2.Abstractions 3.Context Inference

1.Data Races –Previous Work –State Explosion 2.Abstractions 3.Context Inference LA for Multithreaded Programs

Problem: State Explosion 2. Control k threads, m locations = m k - k=4,m=100, states = 1 billion Unbounded threads ? 1. Data Infinitely many valuations for program variables Data Race Initial

Solution: Abstract Irrelevant Detail 1. Data Infinitely many valuations for program variables 2. Control k threads, m locations = m k - k=4,m=100, states = 1 billion Unbounded threads ? Observe - Analyze system as Thread + Context - Context: Summary of all other threads (w.r.t. property) 2. Thread-Context Analysis Observe - Few relevant variables, relationships - Track predicates (relationships) instead of values 1. Predicate Abstraction

Example Check for races on x: Initially: s is 0 1 st thread into atomic : - sets old to 0 (value of s ) - sets s to 1 - passes test before access Later threads: - set old to 1 (value set by 1 st thread) - fail test before access (until the 1 st thread is done) 1: while(1){ atomic{ 2: old := s; 3: if(s==0){ 4: s := 1; } // do_work()  5: if(old==0){ 6: x++; 7: s:=0;} } 1: while(1){ atomic{ 2: old := s; 3: if(s==0){ 4: s := 1; } // do_work()  5: if(old==0){ 6: x++; 7: s:=0;} }

1.Data Races –Previous Work –State Explosion 2.Abstractions –Data: Predicate Abstraction –Control: Thread-Context Reasoning 3.Verifying Multithreaded Programs LA for Multithreaded Programs

Predicate Abstraction 1: while(1){ atomic{ 2: old := s; 3: if(s==0){ 4: s := 1; } // do_work()  5: if(old==0){ 6: x++; 7: s:=0;} } 1: while(1){ atomic{ 2: old := s; 3: if(s==0){ 4: s := 1; } // do_work()  5: if(old==0){ 6: x++; 7: s:=0;} } Predicates on Variables s=0, old=0 s= Reachability Graph s=0 s=0, old=0 5 6 : s=0, old=0 : s=0 old=0 s=0 old=0 Q: What about other threads ? x++

1.Data Races –Previous Work –State Explosion 2.Abstractions –Data: Predicate Abstraction –Control: Contexts Thread-Context Reasoning 3.Context Inference LA for Multithreaded Programs

Threads, Contexts Q: What about other threads ? Shared Memory Assume threads run same code Context: Summary of all other threads - Precise enough to check property System = Thread + Context Q: What does a Context look like ? Context

Thread, Contexts Context: Summary of all other threads 1. Summarize a single thread 2. Multiple threads by counting Q: What does a Context look like ? Shared Memory Context 1: while(1){ atomic{ 2: old := s; 3: if(s==0){ 4: s := 1; } // do_work()  5: if(old==0){ 6: x++; 7: s:=0;} } 1: while(1){ atomic{ 2: old := s; 3: if(s==0){ 4: s := 1; } // do_work()  5: if(old==0){ 6: x++; 7: s:=0;} } s=0 s s,x s0s0 s0s0 ThreadSummary Context

Many Threads by Counting s=0 s s,x s0s0 s0s0 Context True s=0 State s 0s 0 s  0 Æ s=0 Initial loc = 1, other = 0 Operations 1. Pick edge w/ source counter > 0, 2. Source counter -1 Target counter +1 Havoc variables on edge, Assume predicate on target Unbounded threads k-Counter Abstraction: Value > k abstracted to 1 for k=1, values: 0,1, 1 Q: What does a Context look like ? 1 Contra! 1 2 1

1.Data Races –Previous Work –State Explosion 2.Abstractions –Data: Predicate Abstraction –Control: Contexts Thread-Context Reasoning 3.Context Inference LA for Multithreaded Programs

Thread-Context Reasoning Q: How to check race-freedom ? Given an Abstraction: 1. Data:Predicates 2. Control: Summary, k 1 Use Context Build finite Reach Graph Check Race unreachable 2 Verify Context Sound Check Summary Overapproximates single Thread’s behavior k k Shared Memory No Race µ Reach Graph Summarize Computed Summary Given Summary

Q: How to check race-freedom ? Given an Abstraction: 1. Data:Predicates 2. Control: Summary, k 1 2 Shared Memory Assume-Guarantee (Use) (Verify) No Race k Shared Memory No Race µ Reach Graph Summarize Thread-Context Reasoning Computed Summary Given Summary

1.Data Races –Previous Work –State Explosion 2.Abstractions –Data: Predicate Abstraction –Control: Thread-Context Reasoning 3.Context Inference LA for Multithreaded Programs

1.Data Races –Previous Work –State Explosion 2.Abstractions –Data: Predicate Abstraction –Control: Thread-Context Reasoning 3.Context Inference LA for Multithreaded Programs

Inference: Build Summary 1 Reach Grap h 2 ; µ ; Summarize 1 Reach Grap h No Race Race Trace Abstraction Preds: P 0 Ctr: k 0

Inference: Trace Analysis Trace FeasibleInfeasible Refine using Trace Either: 1.Add new predicates 2.Increase k Abstraction Preds: P 0 Ctr: k 0 Report Trace Interleaved sequence of threads’ ops Abstraction Preds: P 1 Ctr: k 1

Inference: Build Summary 1 Reach Graph 2 µ ; Summarize Abstraction Preds: P 0 Ctr: k 0 Abstraction Preds: P 1 Ctr: k 1 1 Reach Graph 2 µ Summarize 1 Reach Graph 2 µ Summarize ;

Context Inferred 1 Reach Graph 2 µ Summarize Shared Memory Assume-Guarantee No Race

NO (trace) Context Inference Init. Abstraction Preds: P 0 Ctr: k 0 Init. Summary Summary: ; 1 Reach Graph YES Summarize Safe? 2 µ ? YES NO Update Summary Refine using Trace Feasible? YES NO Output SAFE No Data Races Output Data Race TRACE ANALYSIS BUILD SUMMARY

Plan 1.Data Races –Previous Work –State Explosion 2.Abstractions –Data: Predicate Abstraction –Control: Thread-Context Reasoning 3.Context Inference –Example

Ex: Races on x 1: while(1){ atomic{ 2: old := s; 3: if(s==0){ 4: s := 1; } // do_work()  5: if(old==0){ 6: x++; 7: s:=0;} } 1: while(1){ atomic{ 2: old := s; 3: if(s==0){ 4: s := 1; } // do_work()  5: if(old==0){ 6: x++; 7: s:=0;} } ; Abstraction Preds = ; k= Reach Graph T 7 x++; Summarize 2 µ ; 1 x Build Summary x Control-Flow Graph

Ex: Races on x 1: while(1){ atomic{ 2: old := s; 3: if(s==0){ 4: s := 1; } // do_work()  5: if(old==0){ 6: x++; 7: s:=0;} } 1: while(1){ atomic{ 2: old := s; 3: if(s==0){ 4: s := 1; } // do_work()  5: if(old==0){ 6: x++; 7: s:=0;} } Abstraction Preds = ; k=1 Reach Graph 1 Build Summary x x++ 6 Race x

Thread 1 Ex: Races on x 1: while(1){ atomic{ 2: old := s; 3: if(s==0){ 4: s := 1; } // do_work()  5: if(old==0){ 6: x++; 7: s:=0;} } 1: while(1){ atomic{ 2: old := s; 3: if(s==0){ 4: s := 1; } // do_work()  5: if(old==0){ 6: x++; 7: s:=0;} } Abstraction Preds = ; k=1 Reach Graph 1 Trace Analysis x x++ 6 Trace x Thread 0 1: while(1){ atomic{ 2: old := s; 3: if(s==0){ 4: s := 1; } // do_work()  5: if(old==0){ 6: x++; 7: s:=0;} } 1: while(1){ atomic{ 2: old := s; 3: if(s==0){ 4: s := 1; } // do_work()  5: if(old==0){ 6: x++; 7: s:=0;} } x assume (True) old := s assume (s==0) s:= 1 // do_work() assume (old==0) //write x enabled T 7 x++; assume (True) old := s assume (s==0) s:= 1 // do_work() assume (old==0) //write x enabled

Thread 1 Ex: Races on x Trace Analysis Trace Thread 0 assume (True) old := s assume (s==0) s:= 1 // do_work() assume (old==0) //write x enabled assume (True) old := s assume (s==0) s:= 1 // do_work() assume (old==0) //write x enabled Time s is set to 1 Infeasible branch New Predicate s = 0 Infeasible Trace

Ex: Races on x 1: while(1){ atomic{ 2: old := s; 3: if(s==0){ 4: s := 1; } // do_work()  5: if(old==0){ 6: x++; 7: s:=0;} } 1: while(1){ atomic{ 2: old := s; 3: if(s==0){ 4: s := 1; } // do_work()  5: if(old==0){ 6: x++; 7: s:=0;} } ; Abstraction Preds: s=0 k=1 Reach Graph Summarize 2 µ ; 1 Build Summary, old=0 s= s=0 old=0 5 6 : s=0 old=0 7 x++ s:=0 : s=0 old=0 Local Pred. old=0 - Prunes infeasible paths - Invisible to other threads - Quantified away s:=1 s=0 x s0s0 s s s0s0 x s0s0 s s s0s0

Ex: Races on x 1:while(1){ atomic{ 2: old := s; 3: if(s==0){ 4: s := 1; } // do_work()  5: if(old==0){ 6: x++; 7: s:=0;} } 1:while(1){ atomic{ 2: old := s; 3: if(s==0){ 4: s := 1; } // do_work()  5: if(old==0){ 6: x++; 7: s:=0;} } Abstraction Preds: s=0 k=1 Reach Graph Summarize 2 µ 1 Build Summary, old= s=0 Ç s  s=0 old=0 s  0 old=0 x++ s:=0 s:=1 T T 5 Context changes s s  0 old  0 s=0 s s,x s0s0 s0s0 s=0 x s0s0 s s s0s0 Local Pred. old=0 - Cuts locally infeasible paths - Invisible to other threads - Quantified away s=0 x s0s0 s s s0s0 s s,x s0s0 s0s0 s=0 Ç s  0

Ex: Races on x 1:while(1){ atomic{ 2: old := s; 3: if(s==0){ 4: s := 1; } // do_work()  5: if(old==0){ 6: x++; 7: s:=0;} } 1:while(1){ atomic{ 2: old := s; 3: if(s==0){ 4: s := 1; } // do_work()  5: if(old==0){ 6: x++; 7: s:=0;} } Abstraction Preds: s=0 k=1 Reach Graph Sumz 2 µ 1 Build Summary, old= s=0 old=0 s  0 old=0 x++ s:=0 s:=1 T T T 5 s  0 old  0 s=0 s s,x s0s0 s0s0 s=0 s s,x s0s0 s0s0 s=0 s s,x s0s0 s0s0 SAFE No Races on x

Plan 1.Data Races –Previous Work –State Explosion 2.Abstractions –Data: Predicate Abstraction –Control: Thread-Context Reasoning 3.Context Inference –Example 4. Experiments

Data Races in NesC Programs PL for Networked Embedded Systems [Gay et al. 03] Interrupts fire events, which fire other events or post tasks which run asynchronously Race-freedom important –Non-trivial synchronization idioms –Flow-based analysis Compiled to C

Case Study: sense.nc atomic{ old:= state; if(state==0){ state:=1; }  if(old==0){ x++;  atomic{ old:= state; if(state==0){ state:=1; }  if(old==0){ x++;  Interrupt 1 fires  old := state if (state ==0){ state := 1  assume (old == 0){ about to write x Interrupt 2 fires  state := 0 Interrupt 1 fires  old := state assume (state ==0){ state := 1  If (old == 0){ about to write x Interrupt 1 handler disables interrupt 2 BLAST finds information proves no races

Review : Multithreaded 1.Multithreaded Verification is hard –Data, Control Explosion –Abstract Irrelevant details 2.Combine Abstractions 1.Data: Predicates 2.Control: Contexts (Summary + Counter) 3.Iterative Context Inference

Next lecture … Partial-program analysis: From verification to interfaces