210 likes | 397 Views
Static Analysis of Heap-manipulating Low-level software. Sumit Gulwani Ashish Tiwari MSR, Redmond SRI International. Related Work. Alias/Pointer Analysis [Work done in early 90s] Must/May equalities Considered not expressive enough Shape Analysis [Work that followed]
E N D
Static Analysis of Heap-manipulating Low-level software Sumit Gulwani Ashish Tiwari MSR, Redmond SRI International
Related Work • Alias/Pointer Analysis [Work done in early 90s] • Must/May equalities • Considered not expressive enough • Shape Analysis [Work that followed] • Fancy predicates • Need to provide transfer functions for each of them • This work • Must/May equalities extended with quantifiers (Provides expressiveness of an infinite class of predicates and avoids the need of providing transfer functions)
Example 1 struct List { int Len, *Data; List* Next; } ListOfPtrArray(struct List* x) { for (y := x; ynull; y := y!next) t := ?; y!len := t; y!data = malloc(4t); for (y := x; ynull; y := y!next) for (z :=0; z < y!len; z := z+1) y!data!(4z) := ….; Invariant required after first loop for proving memory safety 9i: List(x,i,next) Æ8j: (0·j<i) ) Array(x!nextj!data, 4*(x!nextj!len))
Example 2 struct List { int Data; List* Next; } List2Array(struct List* x) { n := 0; for (y := x; ynull; y := y!next) n := n+1; A := malloc(4n); y:= x; for (k := 0; k < n; k++) A!(4k) := y!data; y := y!next; return A; 1 2 3 4 5
Outline • Abstract Domain • Implies Algorithm • Join Algorithm • Meet Algorithm • PostAssignment Algorithm
Abstract Domain 9V: Cons Æ Must Æ May Must := true | Must Æ 8V: (Cons ) e1=e2) May := true | May Æ8V: (Cons ) e1» e2) e := y | c | e1§ e2 |ce | e1! e2e3 | valid | null Cons represent constraints over the base abstract domain, eg. Combination of linear arithmetic and uninterpreted functions
Expressiveness List(x,i,next)´ i ¸ 0 Æ x!nexti = null Æ 8 j: (0·j<i) ) Valid(x!nextj) Valid(e)´ e!w=valid Array(x,k)´8 j: (0·j<k) ) Valid(x+j)
Abstract Interpreter F’ F2 F1 F p Statement s False True F F F1 F2 Conditional Node Assignment Node Join Node F = Join(F1,F2) F = Post(F’,s) Where s may be: x := e *x := e x := malloc(e) free(x) F1 = Meet(F, p) F2 = Meet(F,:p)
Implies Algorithm Implies(F1, F2) returns 1 only if F1) F2 KeyIdea for checking F ) e1=e2 Check if e22 MustAliases(e1,F) KeyIdea for checking F ) e1 e2 Check if : (e22 MayAliases(e1,F))
MustAliases and MayAliases F1: x = x!nextj F2: 8i: (0·i·j) ) x!nexti = x!nexti+1!prev MustAliases KeyIdea: Apply k quantifier instantiations MustAliases(x,F1) = { x!nextj, x!next2j } MustAliases(x,F2) =
MustAliases and MayAliases F1: x = x!nextj F2: 8j: (0·i·j) ) x!nexti=x!nexti+1!prev MustAliases KeyIdea: Apply k quantifier instantiations MustAliases(x,F1) = { x!nextj, x!next2j } MustAliases(x,F2) = { x!next!prev, x!next!prev!next!prev }
MustAliases and MayAliases F1: x = x!nextj F2: 8j: (0·i·j) ) x!nexti=x!nexti+1!prev MustAliases KeyIdea: Apply k instantiations of each equality MustAliases(x,F1) = { x!nextj, x!next2j } MustAliases(x,F2) = { x!next!prev, x!next!prev!next!prev } MayAliases KeyIdea: Represent aliases by expressions of size k MayAliases(x,F1) = { x!nextt | t¸j } MayAliases(x,F2) =
MustAliases and MayAliases F1: x = x!nextj F2: 8j: (0·i·j) ) x!nexti=x!nexti+1!prev MustAliases KeyIdea: Apply k instantiations of each equality MustAliases(x,F1) = { x!nextj, x!next2j } MustAliases(x,F2) = { x!next!prev, x!next!prev!next!prev } MayAliases KeyIdea: Represent aliases by expressions of size k MayAliases(x,F1) = { x!nextt | t¸j } MayAliases(x,F2) = { x!(next|prev)t | t¸0 }
Join Algorithm Join(F1, F2) returns an overapproximation of F1Ç F2 Example 1 Input 1: i=1 Æ A[0]=0 Input 2: i=2 Æ A[0]=0 Æ A[1]=1 Output: 8 j: (0·j<i) ) A[j]=j Example 2 Let S(k) ´ Array(x!nextk!data, x!nextk!len) Input 1: y=x!next Æ S(0) Input 2: y=x!next2Æ S(0) Æ S(1) Output: 9i: 1·i·2 Æ y=x!nextiÆ8j: (0·j<i) ) S(j)
Join Algorithm: Key Idea Input 1: y=x!next Æ S(0) Input 2: y=x!next2Æ S(0) Æ S(1) After Normalization, we get: Input 1: 9i: i=1 Æ y=x!nextiÆ8j: (0·j<1) ) S(j) Input 2: 9i: i=2 Æ y=x!nextiÆ8j: (0·j<2) ) S(j) Now we use the following rule: Join (9V: E1Æ8U: C1)S, 9V: E2Æ8U: C2)S) = 9V: E3Æ8U: C3)S where E3 = Join(E1, E2) C3 = Underapproximation of C1ÆC2
Join Algorithm: Key Idea Input 1: y=x!next Æ S(0) Input 2: y=x!next2Æ S(0) Æ S(1) After Normalization, we get: Input 1: 9i: i=1 Æ y=x!nextiÆ8j: (0·j<1) ) S(j) Input 2: 9i: i=2 Æ y=x!nextiÆ8j: (0·j<2) ) S(j) Now we use the following rule: Join (9V: E1Æ8U: C1)S, 9V: E2Æ8U: C2)S) = 9V: E3Æ8U: C3)S where E3 = Join(E1, E2) C3 = Underapproximation of (E1)C1Æ E2)C2)
Meet Algorithm Meet(F,p) returns an overapproximation of F Æ p KeyIdea: Reason about interaction between equalities & disequalities Example 1 Input 1: 9 i: len·i Æ List(x,i,next) Æ y=x!nextlen Input 2: y=null Output: 9 i: len=i Æ List(x,i,next) Æ y=x!nextlen Example 2 Input 1: 9 i: len·i Æ List(x,i,next) Æ y=x!nextlen Input 2: ynull Output: 9 i: len<i Æ List(x,i,next) Æ y=x!nextlen
PostAssignment Algorithm Post(F, s) returns an overapproximation of the strongest postcondition of F w.r.t. s KeyIdea: Transitive Closure; Invalidate Must; Invalidate May; Add new fact Input 1: List(y,i,next) Æ List(result,j,next) Æ y+next=x Æ *x=tmp Input 2: *x := result Output: List(tmp,i-1,next) Æ List(result,j,next) Æ y+next=x Æ *x=result result y null null tmp
Related Work • Alias/Pointer Analysis [Work done in early 90s] • Must/May equalities • Considered not expressive enough • Shape Analysis [Work that followed] • Fancy predicates • Need to provide transfer functions for each of them • This work • Must/May equalities extended with quantifiers (Provides expressiveness of an infinite class of predicates and avoids the need of providing transfer functions)
Conclusion and Future Work • Quantified abstract domain for pointer analysis • Expressive enough to reason rich properties • Amenable to automated deduction • Extend analysis to inter-procedural setting • Add disjunction and richer quantification support in abstract domain