370 likes | 468 Vues
This paper presents a method for static verification of Object-Based Programs by using size analysis and alias controls to specify and verify safety policies. It addresses challenges such as object mutation and aliasing, employing annotated types to capture size properties. The text explores the application of size invariants to AVL tree objects and discusses alias controls like Immutability and Uniqueness annotations. Examples of content include size-defining annotations and lending annotations for unique references. Furthermore, a system for classification of size variables is proposed, categorizing them into Size-Immutable, Trackable, and Non-Trackable groups. The paper outlines the background on size analysis, showcases size tracking with alias controls, introduces a Kernel Language for specification, explains the type system for verification, and hints at implementation details.
E N D
Verifying Safety Policies with Size Properties and Alias Controls Wei Ngan Chin1,2, Siau-Cheng Khoo1, Shengchao Qin3, Corneliu Popeea1, Huu Hai Nguyen2 1 National University of Singapore 2 Singapore-MIT Alliance 3 University of Durham
analyseand verify Background • Uses of Size Analysis : • array bound check elimin. [Xi-Pfenning'98] • data structure invariance [Xi-Pfenning'99] • termination analysis [Lee-Jones'01] • space complexity [Hofman-Jost'03] • Current Status : • mostly for declarative languages (functional + logic) • restricted imperative language (e.g. Xanadu)
Our Goal • Static Verification for Object-Based Programs • Main Challenges : • objects may mutate • objects may be aliased • Our ApproachUse size analysis and alias controls to specify and verify safety policies
value True --> b=1 value False --> b=0 value 3 --> n=3 Type System for Size Analysis • Uses annotated types ::= c<s1,…,sm> • Types are annotated with size properties that capture: Values : bool<b>, int<n> Lengths : Array<s>, List<n>, Tree<s,h>
Methods with Size Annotation mn (1 v1, … , n vn) where pre ; post{ body } • Examples int<r>add (int<a> x, int<b>y) where true ; (r=a+b) { x+y } int<r> sub (Array<s> A, int<i> i) where (0is) ; true { A[i] }
def - size definition element value left sub-tree right sub-tree inv - AVL Tree is height-balanced AVL’s invariant is preserved after node insertion Object with Size Invariant • AVL Tree: s – number of nodes in tree h – height of tree adt AVL<s,h> where s=1+s1+s2Æ h=1+max(h1,h2) ; s¸0 Æ h¸0 Æ -1·h1-h2·1 { int<v> val ; AVL<s1,h1> left ; AVL<s2,h2> right; … } void insert (AVL<s,h> t, int<n> n) where true ; s’=s+1 Æ h·h’·h+1 { ... }
tail of the list Mutability & Aliasing • Problem with aliasing and mutability : List<x> a = new List(5,new List(6,null)); // x’=2 List<y> b = a; // y’=x Æ x’=x setNext(b,null); // y’=1 Æ x’=x Unsound conclusion: x’=2 Æ y’=1 adt List<n> where n=m+1 ; n0 { int<v> val ; List<m> next; void setNext (List<n> x, List<l> y) where n>0 ; n’=l+1 { x.next = y } …}
Alias Controls Adopted annotations : Immutability + Uniqueness Each reference (field/param/local var) is marked: • Read-Only (R) : always refers to the same object. • Unique (U) : sole reference to an object. • Shared (S) : maybe globally aliased. • Lent-Once (L) : unique parameter temporarily lent. Goal: precisely and soundly capture size-properties.
List<a>@S x; List<b>@S y; x=y; y.val=4; y.next=x; freely shared and trackable Size Property for List (1) List with Read-Only (R) tail. adt List<n> where n=m+1 ; n¸0 { int<v>@S val ; List<m>@R next ; : } read-only
MList<a>@U x; MList<b>@U y; x=y; x.next=.. …y… y loses its uniqueness Size Property for List (2) List with Unique (U) tail. adt MList<n> where n=m+1 ; n¸0 { int<v>@S val ; MList<m>@U next ; : } mutable but unique
lent & unique Lending Annotation Properties of a Lent-once reference : • value does not escape the method • has exclusive/unique access to the object void append (MList<m>@L xs, MList<n>@U ys) where m>0 ; m'=m+n { if xs.next==null then xs.next=ys else append(xs.next,ys) }
MList<a>@U x; MList<b>@U y; append(x,y); …x.next… …y.next… uniqueness of x is lent uniqueness of y is consumed Lending Annotation void append (MList<m>@L xs, MList<n>@U ys) where m>0 ; m'=m+n { … }
Classification of Size-Variables Three possible groups Vobj(hs*i) = (SI,ST,SN) • Size-Immutable (freely shared) (ii) Trackable (mutable and unique) (iii) Non-Trackable (mutable and globally aliased)
Outline • Background on Size Analysis • Size Tracking with Alias Controls • Kernel Language and Protocol Specification • Type System for Verification • Implementation and Conclusion.
source program pre/post states define size size invariant Presburger size constraint annotated types expression oriented language Kernel Language
How are Safety Policies Specified? • Popular approach - finite state machine. • Our approach : ADT with (i) Object’s Size Invariant. (ii) Methods’ Preconditions. • Benefits: Relational Properties Infinite-State Policies
File Protocol Safety policy : Read/Write after Successful Open. read new close open 1 2 3 open File state 1 - uninitialized 2 - opened 3 - closed write
successful file open must be opened closed state File Protocol • Specified using sized typing.
n,c 2,c 1,c 0,c Bounded Buffer Protocol Safety policy : Buffer does not Under/Overflow. s<c ; s’=s+1 Æ c’=c add n>0 ; s’=0 Æ c’=n s,c new get Buffer state s - no of elements c - capacity s>0 ; s’=s-1 Æ c’=c
Outline • Background on Size Analysis • Size Tracking with Alias Controls • Kernel Language and Protocol Specification • Type System for Verification • Implementation and Conclusion.
expression to type-check pre/post states type environment Type System for Verification Type judgement
size of b corresponds to what branch is taken type of v path-sensitivity for size information using disjunction Rule for IF: path-sensitivity
substitution from formal to actual parameters types for actual parameters method declaration precondition checked poststate effect Rule for Call
Correctness of Type System • Type Preservation – size type property is correctly preserved during reduction. • Progress – a well-typed program never goes wrong. Safety policies are guaranteed for well-typed programs.
Implementation • Prototype built using • Haskell language (GHC) • Omega Presburger solver • Accepts a Java-like language (without concurrency and exceptions). • Is this method viable? • Verification is fast because of modular type-checking. • Annotation is less than 5% of source code.
Related Work Size analysis for immutable data structures [Hughes et.al'96, Xi-Pfenning'98,'99, Jost-Hofman'03] Alias controls for program reasoning [Chan-Boyland'98, Aldrich-Kostadinov-Chambers'02] Other approaches to verification: • Finite type-state: Vault, Fugue [Fahndrich-DeLine'02,'04] • Theorem proving: ESC (may be unsound) [Flanagan-Leino-Lillibridge-Nelson et.al'02] • Model checking: Bogor (requires test harness) [Robby-Dwyer-Hatcliff-Rodriguez'03,'04]
Conclusion • Formulate a precise relational size analysis for object-based programs. • Use alias controls to track mutable size properties. • Automatic verification for: Safety policies - files, bounded-buffers. Data invariants - lists, AVL trees. • Working towards inference of alias and size annotations (for methods).
Experiments JOlden benchmarks
fields can only be accessed via methods size definition Object Declaration adt Cell<n> where n=v ; true { int<v> val ; void incr(Cell<n> x) where true ; n’=n+1 {x.val =x.val + 1} …} Development: a client is based on ADT’s interface (the implementation details are hidden). Modular analysis: correct usage of ADT verified against ADT’s interface. Why use ADTs ?
new value old value Mutable Size Properties • Example with aliasing and mutability : Cell<x> a = new Cell(5); // x’=5 Cell<y> b = a; // y’=x Æ x’=x incr(b); // y’=y+1 Æ x’=x // x’=5 Æ y’=6 unsound! adt Cell<n> where n=v ; true { int<v> val ; void incr(Cell<n> x) where true ; n’=n+1 {x.val =x.val + 1} …}
where true ; p1’=xÆp2’=p2 size definition r@U (,{r1,r2},) Pair ({p2},{p1},) fst@S snd@R ({s2},,) (,{s1},) int int ({s1},,) ({s2},,) Pair Example adt Pair<p1,p2> where p1=s1Æp2=s2 ; true { int<s1>@S fst; int<s2>@R snd; void setFst(Pair<p1,p2>@L p, int<x>@S x) { p.fst=x } } Pair<r1,r2>@U r = new Pair(…); r.setFst(…);
where true ; p2’=p2 m@S n@S (,{n2},{n1}) (,{m2},{m1}) Pair Example adt Pair<p1,p2> where p1=s1Æp2=s2 ; true { int<s1>@S fst; int<s2>@R snd; void setFst(Pair<p1,p2>@ p, int<x>@S x) { p.fst=x } } Pair<m1,m2>@S m = new Pair(…); Pair<n1,n2>@S n = m; m.setFst(…); n.setFst(…); S Pair ({p2},{p1},) fst@S snd@R ({s2},,) (,{s1},) int int ({s1},,) ({s2},,)
no bounds violation size never change Array Protocol Safety policy : No Array Bounds Violation. • Implementation: array primitive operations (that need no runtime tests). sub(A,i) … A[i] update(A,i,v) … A[i] = v
safety preconditions Buffer Protocol Safety policy : Buffer does not Under/Overflow. • Implemented using a cyclic array. • Implementation checked to comply with Array protocol.
Lock Protocol Safety policy : No double lock/unlock operations.
AVL Tree adt AVL<s,h> where s=1+s1+s2Æ h=1+max(h1,h2) ; s¸0 Æ h¸0 Æ -1·h1-h2·1 { int<v>@S val ; AVL<s1,h1>@U left ; AVL<s2,h2>@U right; void insert (AVL<ts,th>@L t, int<n>@S n) where true ; ts’=ts+1 Æ th·th’·th+1 { ... } }