13
Abstractions from Proofs * Thomas A. Henzinger Ranjit Jhala Rupak Majumdar EECS Department, University of California Berkeley, CA 94720-1770, U.S.A. {tah,jhala,rupak}@eecs.berkeley.edu Kenneth L. McMillan Cadence Berkeley Labs. Berkeley, CA, U.S.A. [email protected] Abstract The success of model checking for large programs depends cru- cially on the ability to efficiently construct parsimonious abstrac- tions. A predicate abstraction is parsimonious if at each control location, it specifies only relationships between current values of variables, and only those which are required for proving correct- ness. Previous methods for automatically refining predicate ab- stractions until sufficient precision is obtained do not systemati- cally construct parsimonious abstractions: predicates usually con- tain symbolic variables, and are added heuristically and often uni- formly to many or all control locations at once. We use Craig inter- polation to efficiently construct, from a given abstract error trace which cannot be concretized, a parsominous abstraction that re- moves the trace. At each location of the trace, we infer the relevant predicates as an interpolant between the two formulas that define the past and the future segment of the trace. Each interpolant is a relationship between current values of program variables, and is relevant only at that particular program location. It can be found by a linear scan of the proof of infeasibility of the trace. We develop our method for programs with arithmetic and pointer expressions, and call-by-value function calls. For function calls, Craig interpolation offers a systematic way of generating relevant predicates that contain only the local variables of the function and the values of the formal parameters when the function was called. We have extended our model checker BLAST with predicate dis- covery by Craig interpolation, and applied it successfully to C pro- grams with more than 130,000 lines of code, which was not possible with approaches that build less parsimonious abstractions. Categories and Subject Descriptors: D.2.4 [Software Engineer- ing]: Software/Program Verification; F.3.1 [Logics and Meanings * This research was supported in part by the NSF grants CCR- 0085949, CCR-0234690, and ITR-0326577, by the AFOSR grant F49620-00-1-0327, by the DARPA grant F33615-00-C-1693, and by the ONR grant N00014-02-1-0671. Permission to make digital or hard copies of all or part of this work for personal or classroom use is granted without fee provided that copies are not made or distributed for profit or commercial advantage and that copies bear this notice and the full citation on the first page. To copy otherwise, to republish, to post on servers or to redistribute to lists, requires prior specific permission and/or a fee. POPL’04: 31st ACM Symp. Principles of Programming Languages, January 14–16, 2004, Venice, Italy. Copyright 2004 ACM 1-58113-729-X/04/0001 ...$5.00 of Programs]: Specifying and Verifying and Reasoning about Pro- grams. General Terms: Languages, Verification, Reliability. Keywords: Software model checking, predicate abstraction, coun- terexample analysis. 1 Introduction Increasing dependency on software systems amplifies the need for techniques that can analyze such systems for errors and prove them safe. The two most desirable features of such analyses is that they be precise and scalable. Precision is required so that the analy- sis does not report errors where none exist, nor assert correctness when there are bugs. Scalability is necessary so that the method works for large software systems, where the need for analysis is most acute. These two features are often mutually exclusive: flow based interprocedural analyses [11, 15] achieve scalability by fixing a small domain of dataflow facts to be tracked, and compute flow functions over the abstract semantics of the program on this fixed set. For complicated properties, if the set of facts that are tracked is too small, many false positives are reported. Model checking based approaches [25] on the other hand offer the promise of precision as they are path-sensitive, but they often track too many facts, so state explosion comes in the way of scalability. To avoid the pitfalls arising from using a fixed set of facts, much re- cent interest has focused on interprocedural analyses that automati- cally tune the precision of the analysis using false positives, i.e., in a counterexample-guided manner. These start with some coarse ab- stract domain and successively refine the domain by adding facts that make the abstraction sufficiently precise to refute spurious counterexamples [4, 5, 8, 12, 19]. The “facts” are predicates that relate values of programs variables. While this approach holds the promise of precision, there are several obstacles that must be over- come before it can be scaled to very large programs. The first chal- lenge is how to efficiently analyze a false positive and learn from it a small set of predicates such that the refined abstraction does not contain the spurious error trace. The second, closely related prob- lem is how to use the discovered predicates parsimoniously. The number of facts that one needs to track grows with the size of the program being analyzed. However, most predicates are only locally useful, i.e., only useful when analyzing certain parts of the program, and irrelevant in others. If locality is not exploited, then the sheer number of facts may render the abstract system too detailed to be amenable to analysis, as the size of the abstract system grows ex- ponentially with the number of predicates.

Abstractions From Proofs (HENZINGER, T. a. Et Al., 2004)

Embed Size (px)

Citation preview

Page 1: Abstractions From Proofs (HENZINGER, T. a. Et Al., 2004)

Abstractions from Proofs ∗

Thomas A. Henzinger Ranjit Jhala Rupak MajumdarEECS Department, University of California

Berkeley, CA 94720-1770, U.S.A.

{tah,jhala,rupak}@eecs.berkeley.edu

Kenneth L. McMillanCadence Berkeley Labs.

Berkeley, CA, U.S.A.

[email protected]

Abstract

The success of model checking for large programs depends cru-cially on the ability to efficiently construct parsimonious abstrac-tions. A predicate abstraction is parsimonious if at each controllocation, it specifies only relationships betweencurrent values ofvariables, and only those which are required for proving correct-ness. Previous methods for automatically refining predicate ab-stractions until sufficient precision is obtained do not systemati-cally construct parsimonious abstractions: predicates usually con-tain symbolic variables, and are added heuristically and often uni-formly to many or all control locations at once. We use Craig inter-polation to efficiently construct, from a given abstract error tracewhich cannot be concretized, a parsominous abstraction that re-moves the trace. At each location of the trace, we infer the relevantpredicates as an interpolant between the two formulas that definethe past and the future segment of the trace. Each interpolant isa relationship between current values of program variables, and isrelevant only at that particular program location. It can be found bya linear scan of the proof of infeasibility of the trace.

We develop our method for programs with arithmetic and pointerexpressions, and call-by-value function calls. For function calls,Craig interpolation offers a systematic way of generating relevantpredicates that contain only the local variables of the function andthe values of the formal parameters when the function was called.We have extended our model checker BLAST with predicate dis-covery by Craig interpolation, and applied it successfully to C pro-grams with more than 130,000 lines of code, which was not possiblewith approaches that build less parsimonious abstractions.

Categories and Subject Descriptors:D.2.4 [Software Engineer-ing]: Software/Program Verification; F.3.1 [Logics and Meanings

∗This research was supported in part by the NSF grants CCR-0085949, CCR-0234690, and ITR-0326577, by the AFOSR grantF49620-00-1-0327, by the DARPA grant F33615-00-C-1693, andby the ONR grant N00014-02-1-0671.

Permission to make digital or hard copies of all or part of this work for personal orclassroom use is granted without fee provided that copies are not made or distributedfor profit or commercial advantage and that copies bear this notice and the full citationon the first page. To copy otherwise, to republish, to post on servers or to redistributeto lists, requires prior specific permission and/or a fee.POPL’04: 31st ACM Symp. Principles of Programming Languages,

January 14–16, 2004, Venice, Italy.Copyright 2004 ACM 1-58113-729-X/04/0001 ...$5.00

of Programs]: Specifying and Verifying and Reasoning about Pro-grams.

General Terms: Languages, Verification, Reliability.

Keywords: Software model checking, predicate abstraction, coun-terexample analysis.

1 Introduction

Increasing dependency on software systems amplifies the need fortechniques that can analyze such systems for errors and prove themsafe. The two most desirable features of such analyses is that theybe preciseand scalable. Precision is required so that the analy-sis does not report errors where none exist, nor assert correctnesswhen there are bugs. Scalability is necessary so that the methodworks for large software systems, where the need for analysis ismost acute. These two features are often mutually exclusive: flowbased interprocedural analyses [11, 15] achieve scalability by fixinga small domain of dataflow facts to be tracked, and compute flowfunctions over the abstract semantics of the program on this fixedset. For complicated properties, if the set of facts that are tracked istoo small, many false positives are reported. Model checking basedapproaches [25] on the other hand offer the promise of precision asthey are path-sensitive, but they often track too many facts, so stateexplosion comes in the way of scalability.

To avoid the pitfalls arising from using a fixed set of facts, much re-cent interest has focused on interprocedural analyses that automati-cally tune the precision of the analysis using false positives,i.e., inacounterexample-guidedmanner. These start with some coarse ab-stract domain and successively refine the domain by adding factsthat make the abstraction sufficiently precise to refute spuriouscounterexamples [4, 5, 8, 12, 19]. The “facts” are predicates thatrelate values of programs variables. While this approach holds thepromise of precision, there are several obstacles that must be over-come before it can be scaled to very large programs. The first chal-lenge is how to efficiently analyze a false positive and learn from ita smallset of predicates such that the refined abstraction does notcontain the spurious error trace. The second, closely related prob-lem is how to use the discovered predicates parsimoniously. Thenumber of facts that one needs to track grows with the size of theprogram being analyzed. However, most predicates are only locallyuseful,i.e.,only useful when analyzing certain parts of the program,and irrelevant in others. If locality is not exploited, then the sheernumber of facts may render the abstract system too detailed to beamenable to analysis, as the size of the abstract system grows ex-ponentially with the number of predicates.

Page 2: Abstractions From Proofs (HENZINGER, T. a. Et Al., 2004)

We solve both problems using the following observation: therea-sonwhy an abstract trace is infeasible is succinctly encoded in aproof that the trace is infeasible, and so the appropriate abstractioncan be culled from the proof. The difficulty in extracting the rele-vant facts from the proof is that the proof uses the entire history ofthe trace, while our analysis, and hence our facts, should refer at allpoints of the trace only to relationships between the “current” val-ues of program variables. Inspired by the use of Craig Interpolationfor image-computation in [22], we introduce a method by which theproof can be sliced to yield the relevant facts at each point of thetrace. Given an abstract trace, we construct atrace formula(TF),which is the conjunction of several constraints, one per instruction,such that the TF is satisfiable iff the trace is feasible. If the traceis infeasible, then we use Craig’s interpolation theorem [9] to ex-tract, for each point of the trace, the relevant facts from the proof ofunsatisfiability of the TF. Given two formulasϕ− andϕ+, whoseconjunction is unsatisfiable, theCraig interpolantof (ϕ−,ϕ+) is aformula ψ such that (i)ϕ− implies ψ, (ii) ψ∧ϕ+ is unsatisfiable,and (iii) ψ contains only symbols common toϕ− andϕ+. If ϕ− isthe part of the TF that represents a prefix of an infeasible trace, andϕ+ encodes the remainder of the trace, then the Craig interpolantψ consists of precisely the facts, as relations between current val-ues of the variables, which need to be known at the cut-point of thetrace in order to prove infeasibility.

In this paper, we make the following contributions. First, we showhow a proof of unsatisfiability ofϕ− ∧ϕ+ can be mined to buildthe interpolantψ. The method is efficient in that it uses the sametheorem proving effort as is needed to produce a proof of unsatisfia-bility: the interpolant is generated by a linear scan of the proof. Sec-ond, we show how to infer from the interpolants, at each cut-pointof an infeasible abstract trace, enough facts to rule out the trace.Moreover, the cut-points provide precise information at which pro-gram locations the inferred facts are useful, thus enabling a parsi-monious use of predicates. The method can be combined with on-the-fly lazy abstraction [19], and presents an improvement: whilein pure lazy abstraction, the set of predicates increases monotoni-cally along a trace, the interpolant predicates may change from onecontrol location to the next,i.e., interpolation provides a procedurefor deciding when a predicate becomes irrelevant, and therefore ob-solete. We show that the method is both sound and complete, in thesense that if an abstract trace is infeasible, then the interpolants al-ways provide sufficient information for proving infeasibility. More-over, when abstractions are used as certificates for program cor-rectness following the proof-carrying code paradigm [17], then ourparsimonious use of predicates yields more compact proofs.

We illustrate the method on an imperative language of arithmeticand pointer expressions with call-by-value function calls. There aretwo orthogonal sources of complexity in generating interpolants.The first is function calls and scoping. We want the analysis of afunction to be polymorphic in all callers,i.e.,the inferred predicatesshould involve only lvalues that are local to the scope of the func-tion. Here, interpolation provides a procedure for systematicallydiscovering predicates that refer only to (i) the local variables ofthe function and (ii) the values of the formal parameters at the timeof the function call. This allows us to keep the subsequent anal-ysis interprocedural [1, 29]. The second issue is the presence ofpointers and aliasing. We want to generate predicates that soundlyand completely capture the semantics of programs with pointersand memory allocation. As McCarthy’s theory of arrays [21] doesnot offer suitable interpolants, we need to model memory locationsindividually.

Finally we report on our experiences with this new kind of abstrac-

tion refinement. We have implemented the method in BLAST [19].Owing to the fact that we only track a few predicates at every pro-gram location, we have been able to precisely model check pro-grams considerably larger than have been reported before [7, 17],including a driver that consists of 138,000 lines of C code (we foundseveral behaviors that violate the specification). Even though 382predicates are required in total to show correctness, the reason theanalysis scales is that the average number of relevant predicates ateach program location is about 8.

2 Overview

Consider the program fragment shown in Figure 1. The property wewish to check is that locking and unlocking alternate,i.e.,betweenany two calls oflock there must be a call ofunlock, and betweenany two calls ofunlock there must be a call oflock. Suppose thatthe code not shown does not contain any calls oflock or unlock.

while(*){1: if (p1) lock (); assume p1;

if (p1) unlock (); lock ();· · · assume ¬ p1;

2: if (p2) lock (); assume p2;if (p2) unlock (); lock ();· · ·

n: if (pn) lock ();if (pn) unlock ();

}Figure 1. Program; spurious counterexample.

A static analysis that tracks whether or not the lock is held returnsfalse positives,i.e., error traces that arise from the imprecision ofthe analysis. One such spurious error trace is shown on the rightin Figure 1. The analysis is fooled because it does not track thepredicatep1 which correlates the first twoif statements; eitherboth happen or neither happens, and either way the error cannot bereached. We would like to make the analysis more precise so thatthis spurious counterexample is eliminated, and we would like tokeep refining the analysis until we either have a real counterexam-ple, or, as in this case, the program is proved safe.

Various methods can analyze this particular counterexample andlearn that the analysis should track the value ofp1. Similar coun-terexamples show that all of the predicatesp1, . . . , pn must betracked, but as a result, the analysis blows up, because it is not clearwhen we can “merge” states with different predicate values, andwithout merging there are an exponential number of states.1 Noticehowever that in this program, each predicate is only locally useful,i.e., eachpi is “live” only at the statements between labelsi and(not including)i + 1. Hence, to make apreciseanalysisscalablewe need a method that infers both the predicates andwherethey areuseful. In our experience, many large software systems have theproperty that, while the number of relevant predicates grows withthe size of the system, each predicate is useful only in a small partof the state space,i.e., the number of predicates that are relevant atany particular program location is small. By exploiting this prop-erty one can make a precise analysis scale to large programs. Inparticular, our algorithm infers the predicatespi and also thatpiis useful only between the labelsi and i + 1; outside these labels,we can forget the value ofpi. Thus our analysis considers, in thisexample, only a linear number of distinct states.

1For this particular example certain state representation methodssuch as BDDs would implicitly merge the states.

Page 3: Abstractions From Proofs (HENZINGER, T. a. Et Al., 2004)

1: x := ctr; 〈x,1〉= 〈ctr,0〉 x = ctr2: ctr := ctr +1; 〈ctr,1〉= 〈ctr,0〉+1 x = ctr−13: y := ctr; 〈y,2〉= 〈ctr,1〉 x = y−14: assume(x = m); 〈x,1〉= 〈m,0〉 y = m+15: assume(y 6= m+1); 〈y,2〉= 〈m,0〉+1

Figure 2. Infeasible trace; constraints; predicates.

The problem, then, is (i) to prove that an abstract trace is infeasible,i.e., it does not correspond to a concrete program trace, and (ii) toextract predicates from the proof, together with (iii) informationwhere to use each predicate, such that the refined abstraction nolonger contains the infeasible trace. This is not always as simpleas in the locking example; consider the infeasible trace shown inFigure 2, wherex, y, ctr, andi are program variables, := denotes anassignment, andassume represents anif statement.

Preliminary definitions. Suppose that the formulaϕ (over the pro-gram variables) describes a set of program states, namely, the statesin which the values of the variables satisfyϕ. Thestrongest post-condition[16] of ϕ w.r.t. an operationop is a formula that describesthe set of states reachable from some state inϕ by performing theoperationop. For an assignment,SP.ϕ.(x := e) is (∃x′.ϕ[x′/x]∧x=e[x′/x]), and for anassume we have,SP.ϕ.(assume p) = (ϕ∧ p).For example,(x= ctr) describes the set of states where the value ofx equals that ofctr, andSP.(x = ctr).(ctr := ctr +1) = (∃ctr′.x =ctr′ ∧ ctr = ctr′ + 1). The operatorSP is extended to sequencesof operations bySP.ϕ.(t1; t2) = SP.(SP.ϕ.t1).t2. A trace t isfeasible if SP.true.t is satisfiable. Given a setP of predicatesand a formulaϕ, the predicate abstractionof ϕ w.r.t. P, writ-ten α.P.ϕ is the strongest formulaϕ (in the implication order-ing) such that (i)ϕ is a boolean combination of predicates inP,and (ii) ϕ implies ϕ. For example, ifP = {a = 0,b > 0}, thenα.P.(a = b+ c∧ b = 2∧ c > 0) is ¬(a = 0)∧ (b > 0). The ab-stract strongest postconditionof ϕ w.r.t. the operationop and pred-icatesP is SPP.ϕ.op = α.P.(SP.ϕ.op). This is extended to tracesby SPP.ϕ.(t1; t2) = SPP.(SPP.ϕ.t1).t2. A tracet is abstractly fea-siblew.r.t. P if SPP.true.t is satisfiable. The problem is, given aninfeasible tracet, find a setP of predicates such thatt is abstractlyinfeasible w.r.t.P.

Symbolic simulation. One way to solve this problem is to symbol-ically simulate the trace until an inconsistent state is reached; suchinconsistencies can be detected by decision procedures [6]. A de-pendency analysis can be used to compute which events in the tracecause the inconsistency, and this set of events can then be heuristi-cally minimized to obtain a suitable set of predicates [3, 7]. Thereare two problems with this approach. First, the inconsistency maydepend upon “old” values of program variables,e.g., in the traceshown, such an analysis would use facts likex equals “the value ofctr at line 1,” and that the “current” value ofctr is one more thanthe “value at line 1.” In general there may be many such old val-ues, and not only must one use heuristics to deduce which ones tokeep, a problem complicated by the presence of pointers and proce-dures, but one must also modify the program appropriately in orderto explicitly name these old values. Intuitively, however, since theprogram itself does not remember “old” values of variables, and yetcannot follow the path, it must be possible to track relationships be-tween “live” values of variables only, and still show infeasibility.Second, this approach yields no information aboutwherea predi-cate is useful.

Example. We now demonstrate our technique on the trace of Fig-ure 2. First, we build atrace formula(TF) which is satisfiable iffthe trace is feasible. The TFϕ is a conjunction of constraints, one

per instruction in the trace. In Figure 2, the constraint for each in-struction is shown on the right of the instruction. Each term〈·, ·〉denotes a special constant which represents the value of some vari-able at some point in the trace,e.g.,〈ctr,1〉 represents the value ofctr after the first two instructions. The constraints are essentiallythe strongest postconditions, where we give new names to variablesupon assignment [10, 14]. Thus, for the assignment in line 1, wegenerate the constraint〈x,1〉= 〈ctr,0〉, where〈x,1〉 is a new namefor the value ofx after the assignment, and〈ctr,0〉 is the name forctr at that point. Notice that the “latest” name of a variable is usedwhen the variable appears in an expression on the right. Also notethat the conjunctionϕ of all constraints is unsatisfiable.

To compute the setP of relevant predicates, we could simplytake all atomic predicates that occur in the constraints, rename theconstants to corresponding program variables, create new names(“symbolic variables”) for “old” values of a variablee.g., for〈ctr,1〉 = 〈ctr,0〉+ 1 create a new name that denotes the value ofctr at the previous instruction, and add these names as new vari-ables to the program. However, such a setP is often too large, andin practice [3, 19] one must use heuristics to minimize the sets ofpredicates and symbolic variables by using a minimally infeasiblesubset of the constraints.

Craig interpolation. Given a pair(ϕ−,ϕ+) of formulas, anin-terpolant for (ϕ−,ϕ+) is a formulaψ such that (i)ϕ− implies ψ,(ii) ψ∧ϕ+ is unsatisfiable, and (iii) the variables ofψ are commonto bothϕ− andϕ+. If ϕ−∧ϕ+ is unsatisfiable, then an interpolantalways exists [9], and can be computed from a proof of unsatisfia-bility of ϕ− ∧ϕ+. We present an algorithm for extracting an inter-polant from an unsatisfiability proof in Section 3; ifP is a proof ofunsatisfiability ofϕ−∧ϕ+, then we write ITP.(ϕ−,ϕ+).(P ) for theextracted interpolant for(ϕ−,ϕ+).

In our example, suppose thatP is a proof of unsatisfiability for theTF ϕ. Now consider the partition ofϕ into ϕ−2 , the conjunction ofthe first two constraints (〈x,1〉 = 〈ctr,0〉 ∧ 〈ctr,1〉 = 〈ctr,0〉+ 1),and ϕ+

2 , the conjunction of the last three constraints (〈y,2〉 =〈ctr,1〉 ∧ 〈x,1〉 = 〈m,0〉 ∧ 〈y,2〉 = 〈m,0〉+ 1). The symbols com-mon toϕ−2 andϕ+

2 are〈x,1〉 and〈ctr,1〉; they denote, respectively,the values ofx andctr after the first two operations of the trace.The interpolant ITP.(ϕ−2 ,ϕ+

2 ).(P ) is ψ2 = (〈x,1〉 = 〈ctr,1〉 − 1).Let ψ2 be the formula obtained fromψ2 by replacing each constantwith the corresponding program variable,i.e., ψ2 = (x = ctr−1).Sinceψ2 is an interpolant,ϕ−2 implies ψ2, and sox = ctr− 1 isan overapproximation of the set of states that are reachable afterthe first two instructions (as the common constants denote the val-ues of the variables after the first two instructions). Moreover, byvirtue of being an interpolant,ψ2∧ϕ+

2 is unsatisfiable, meaning thatfrom no state satisfyingψ2 can one execute the remaining threeinstructions,i.e., the suffix of the trace is infeasible for all stateswith x = ctr−1. If we partition the TFϕ in this way at each pointi = 1, . . . ,4 of the trace, then we obtain fromP four interpolantsψi = ITP.(ϕ−i ,ϕ+

i ).(P ), whereϕ−i is the conjunction of the firsti constraints ofφ, andϕ+

i is the conjunction of the remaining con-straints. Upon renaming the constants, we arrive at the formulasψi ,which are shown in the rightmost column of Figure 2. We collectthe atomic predicates that occur in the formulasψi , for i = 1, . . . ,4,in the setP of predicates.

We can prove that the trace is abstractly infeasible w.r.t.P. In-tuitively, for each pointi = 1, . . . ,4 of the trace, the formulaψirepresents an overapproximation of the statesssuch thats is reach-able after the firsti instructions of the trace, and the remaining in-

Page 4: Abstractions From Proofs (HENZINGER, T. a. Et Al., 2004)

structions are infeasible froms. From Equation 1 of Section 3, itfollows thatSP.(ψi).opi+1 implies ψi+1, for eachi. For example,SP.(x = ctr−1).(y := ctr) impliesx = y−1. Therefore, by addingall predicates from allψi to P, we haveSPP.true.(op1; . . . ;opi)impliesψi . Note that, as the trace is infeasible,ψ5 = ψ5 = false.Thus,SPP.true.(op1; . . . ;op5) impliesfalse, i.e., the trace is ab-stractly infeasible w.r.t.P.

Locality. The interpolants give us even more information. Con-sider the naive method of looking at just the TF. The predicates weget from it are such that we must track all of them all the time.If, for example, after the third instruction, we forget thatx equalsthe “old” value of ctr, then the subsequentassume does not tellus thaty = m+ 1 (dropping the fact aboutx breaks a long chainof reasoning), thus making the trace abstractly feasible. In thisexample, heuristic minimization cannot rule out any predicates,so all predicates that occur in the proof of unsatisfiability of theTF must be used at all points in the trace. Using the interpolantmethod, we show that for infeasible traces of lengthn, the for-mula SPψn

.(. . .(SPψ1.true.op1)).opn is unsatisfiable (see Theo-

rem 1 for a precise statement of this). Thus, at each pointi in thetrace, we need only to track the predicates inψi . For example, afterexecuting the first instruction, all we need to know isx = ctr, afterthe second, all we need to know isx= ctr−1, after the third, all weneed to know isx= y−1, and so on. This gives us a way to localizepredicate usage. Thus, instead of a monolithic set of predicates allof which are relevant at all points of a trace, we can deduce a smallset of predicates for each point of the trace.

Function calls. The method described above can be generalized tosystematically infer well-scoped predicates for an interproceduralanalysis [29]. To obtain predicates that contain only locally visi-ble variables, we cut the TF at each pointi in a different way. Thefirst partϕ− of a formula pair consists of the constraints from theinstructions between and includingiL andi, whereiL is the first in-struction of the call body to whichi belongs. The second partϕ+

contains all remaining constraints. It can be shown that interpolantsfor such pairs(ϕ−,ϕ+) contain only variables that are in scope atthe pointi, and are sufficient to rule out the false positive when thesubsequent static analysis is done in an interprocedural, polymor-phic way [1].

Paper outline. Next, we describe how to extract interpolants fromproofs. In Section 4 we describe the syntax and semantics of ourlanguage. In Section 5 we show how the predicate inference al-gorithm works for programs without pointers, and in Section 6 wediscuss how pointers can be handled. Finally, in Section 7 we reporton our experimental results.

3 Interpolants from Proofs

We now present rules that, given a refutation of a formulaϕ−∧ϕ+

in cnf, derives an interpolantψ for the pair(ϕ−,ϕ+). Let FOLbe the set of formulas in the first-order logic of linear equality.A term in the logic is a linear combinationc0 + c1x1 + · · ·cnxn,wherex1, . . . ,xn are individual variables andc0, . . . ,cn are integerconstants. An atomic predicate is either a propositional variable oran inequality of the form 0≤ x, wherex is a term. A literal is ei-ther an atomic predicate or its negation. A clause is a disjunction ofliterals. Here we consider formulas in the quantifier-free fragmentof FOL. A sequent is of the formΓ ` ∆, whereΓ and∆ are sets offormulas. The interpretation ofΓ ` ∆ is that the conjunction of theformulas inΓ entails the disjunction of the formulas in∆.

HYP Γ ` φ φ ∈ Γ

COMBΓ ` 0≤ x Γ ` 0≤ y

Γ ` 0≤ c1x+c2yc1,2 > 0

CONTRA{φ1, . . . ,φn} ` 0≤ c

Γ ` ¬φ1, . . . ,¬φnc < 0

RESΓ ` {φ}∪Θ Γ ` {¬φ}∪Θ′

Γ `Θ∪Θ′

Figure 3. Proof system.

We use a theorem prover that generates refutations for sets ofclauses using the sequent proof system of Figure 3. In particular, allboolean reasoning is done by resolution. This system is completefor refutation of clause systems over the rationals. We obtain anincomplete system for the integers by systematically translating theliteral¬(0≤ x) to 0≤−1−x, which is valid for the integers.

We will use the notationφ � ρ to indicate that all variables occur-ring in φ also occur inρ. An interpolated sequentis of the form(ϕ−,ϕ+) ` ∆ [ψ], whereϕ− andϕ+ are sets of clauses,∆ is a setof formulas, andψ is a formula. This encodes the following threefacts:

(1) ϕ− ` ψ, (2) ψ,ϕ+ ` ∆, and (3)ψ� ϕ+∪∆.

Note that if(ϕ−,ϕ+) `⊥ [ψ], thenψ is an interpolant for(ϕ−,ϕ+).We now give a system of derivation rules for interpolated sequentscorresponding to the rules of our proof system. These rules are adistillation of methods found in [20, 28]. They are sound, in thesense that they derive only valid interpolated sequents, and alsocomplete relative to our proof system, in the sense that we can trans-late the derivation of any sequentϕ− ∪ϕ+ ` ∆ into the derivationof an interpolated sequent(ϕ−,ϕ+) ` ∆[ψ].

We begin with the rule for introduction of hypotheses. Here, we dis-tinguish two cases, depending on whether the hypothesis is fromϕ−or ϕ+:

HYP-A (ϕ−,ϕ+) ` φ [φ] φ ∈ ϕ−

HYP-B (ϕ−,ϕ+) ` φ [>] φ 6∈ ϕ−

We take> here to be an abbreviation for 0≤ 0. The rule for in-equalities is as follows:

COMB

(ϕ−,ϕ+) ` 0≤ x [0≤ x′](ϕ−,ϕ+) ` 0≤ y [0≤ y′]

(ϕ−,ϕ+) ` 0≤ c1x+c2y [0≤ c1x′+c2y′]c1,2 > 0

In effect, to obtain the interpolant for a linear combination of in-equalities fromϕ− andϕ+ we just replace the inequalities fromϕ+

with 0≤ 0. Interpolated sequents derived using these rules satisfythe following invariant.

INVARIANT 1. For any interpolated sequent of the form(ϕ−,ϕ+) ` 0≤ x [0≤ x′], we haveϕ+ ` 0≤ y′ such that x= x′+y′.Further, for all individual variables v such that v6� ϕ+, the coeffi-cients of v in x and x′ are equal.

Page 5: Abstractions From Proofs (HENZINGER, T. a. Et Al., 2004)

From this, we can show that the above rules are sound.

As an example, Figure 4 shows the derivation of an interpolant forthe case whereϕ− is (0≤ y−x)(0≤ z−y) andϕ+ is (0≤ x−z−1).In the figure, we abbreviate(ϕ−,ϕ+) ` φ [ψ] to ` φ [ψ]. Using theabove rules, we derive the sequent` 0 ≤ −1 [0 ≤ z− x]. Since0≤−1 is equivalent to⊥, it follows that 0≤ z−x is an interpolantfor (ϕ−,ϕ+) (which the reader may wish to confirm).

Inequality reasoning is connected to Boolean reasoning in our sys-tem via the CONTRA rule. The corresponding interpolation rule isas follows:

CONTRA({a1, . . . ,ak},{b1, . . . ,bm}) `⊥ [ψ]

(ϕ−,ϕ+) ` ¬a1, . . . ,¬ak,¬b1, . . . ,¬bm[(¬a1∨·· ·∨¬ak)∨ψ]

This rule is sound because both the consequent and the interpolantit generates are tautologies. Moreover, we apply the side conditionthat all thebi are literals occurring inϕ+, while all theai are literalsnot occurring inϕ+. This establishes the following invariant.

INVARIANT 2. For any interpolated sequent(ϕ−,ϕ+) ` Θ [ψ],the setΘ is a collection of literals, andψ is of the formφ∨ρ, whereφ is the disjunction of those literals inΘ not occurring inϕ+.

Notice that, providedϕ− is in clause form, our two hypothesis in-troduction rules HYP-A and HYP-B also establish this invariant(any clause fromϕ− can be rewritten into the formφ∨ρ requiredby the invariant).

Now, we introduce two interpolation rules for resolution: one forresolution on a literal occurring inϕ+, and the other for resolutionon a literal not occurring inϕ+:

RES-A

(ϕ−,ϕ+) ` φ,Θ [(φ∨ρ)∨ψ](ϕ−,ϕ+) ` ¬φ,Θ′ [(¬φ∨ρ′)∨ψ′]

(ϕ−,ϕ+) `Θ,Θ′ [(ρ∨ρ′)∨ (ψ∨ψ′)]

RES-B(ϕ−,ϕ+) ` φ,Θ [ρ∨ψ] (ϕ−,ϕ+) ` ¬φ,Θ′ [ρ′∨ψ′]

(ϕ−,ϕ+) `Θ,Θ′ [(ρ∨ρ′)∨ (ψ∧ψ′)]

In effect, when resolving a literal on theϕ− side (not occurring inϕ+) we take the disjunction of the interpolants, and when resolvinga literal on theϕ+ side (occurring inϕ+) we take the conjunctionof the interpolants. Using Invariant 2 we can show that these rulesare sound.

As an example, Figure 5 shows a derivation of an interpolant for(ϕ−,ϕ+), whereϕ− is (b)(¬b∨c) andϕ+ is (¬c). Using the res-olution rule, we derive the sequent(ϕ−,ϕ+) `⊥ [c]. Thusc is aninterpolant for(ϕ−,ϕ+).

Using the invariants given above, we can also show that for everyderivationP of a sequent(ϕ−,ϕ+) ` φ in our original proof system,there is a corresponding derivationP ′ of an interpolated sequent ofthe form(ϕ−,ϕ+) ` φ [ψ]. We will refer to the interpolantψ thusderived as ITP.(ϕ−,ϕ+).(P ). Using the same proof but partitioningthe antecedent differently, we can obtain related interpolants. Forexample, we can show the following fact:

ITP.(ϕ−,φ∪ϕ+).(P )∧φ =⇒ ITP.(ϕ−∪φ,ϕ+).(P ) (1)

This fact will be useful later in showing that a set of interpolantsderived from an infeasible program trace provides a sufficient set ofpredicates to rule out that trace.

We can also give interpolation rules for treating equalities and un-interpreted functions. This is omitted here due to space considera-tions. We also note that some useful theories do not have the Craiginterpolation property. For example, interpolants do not always ex-ist in the quantifier-free theory of arrays (withsel andupd opera-tors) [21]. For this reason, we avoid arrays in this work, althoughthe use of array operators would simplify the theory somewhat.

4 Languages and Abstractions

We illustrate our algorithm on a small imperative language withinteger variables, references, and functions with call-by-value pa-rameter passing.

Syntax. We consider a language with integer variables and point-ers. Lvalues (memory locations) in the language are declared vari-ables or dereferences of pointer-typed expressions. We assumefor simplicity that at the beginning of a function, memory is allo-cated for each reference variable. Arithmetic comparison or pointerequality constitute boolean expressions. For any lvaluel , let typ.lbe the type ofl ; typ.x is the declared type of the variablex in thecurrent scope, andtyp.∗ l1 is τ if typ.l1 is ref τ (and there is a typeerror otherwise). The operationl := ewrites the value of the expres-sione in the memory locationl ; the operationassume(p) succeedsif the boolean expressionp evaluates totrue, the program haltsotherwise. An operationf (x1, . . . ,xn) corresponds to a call to func-tion f with actual parametersx1 to xn, andreturn corresponds toa return to the caller. We assume that all operations are type safe.

We represent each functionf as acontrol flow automaton (CFA)Cf = (L f ,Ef , l0f ,Opf ,Vf ). The CFACf is a rooted, directed graphwith a set of verticesL f ⊆ PC which correspond to program loca-tions, a set of edgesEf ⊆ L f ×L f , a special start locationl0f ∈ L f ,a labeling functionOpf : Ef →Opsthat yields the operation label-ing each edge, and a set of typed local variablesVf ⊆ Lvals. ThesetVf of local variables has a subsetXf ⊆Vf of formal parameterspassed tof on a call, and a variabler f ∈ Vf that stores the returnvalue. Aprogramis a set of CFAsP = {Cf0, . . . ,Cfk}, where eachCfi is the CFA for a functionfi . There is a special functionmainand corresponding CFACmain, and the program execution beginsthere.

Let PC= ∪{L f |Cf ∈ P} be the set of program locations. Acom-mandis a pair(op,pc) ∈ Ops×PC. A traceof P is a sequence ofcommands(op1 : pc1); . . . ;(opn : pcn), where (1) there is an edge(l0main,pc1) in Cmain such thatOp(l0main,pc1) = op1, (2) if opi isa function call f (· · ·), thenpci is l0f , the initial location of func-tion f , (3) the function calls and returns are properly matched, soif opi is areturn, thenpci is the control location immediately af-ter the call in the appropriate caller, (4) otherwise (ifopi is nota function call or return), there is an edge(pci−1,pci) ∈ Ef suchthatOp(pci−1,pci) = opi (where f is the CFA such thatpci ∈ L f ).For a tracet = (op1 : pc1); . . . ;(opn : pcn), let Cl.t be a functionsuch that ifopi is a function call, thenopCl.t.i is the matching re-turn, andCl.t.i = n otherwise. For each 1≤ i ≤ n, defineL.t.i tobe max{ j | j ≤ i, andop j is a function call, andCl.t. j ≥ i}, and 0if this set is empty, andR.t.i = Cl.t.(L.t.i). For a tracet = (op1 :pc1); . . . ;(opn : pcn), and 1≤ i ≤ n, the positionL.t.i has the callthat begins the scope to whichopi belongs, andR.t.i has the returnthat ends that scope. For simplicity of notation, we assume thatevery function call returns.

We fix the following notation for the sequel. We uset for the trace

Page 6: Abstractions From Proofs (HENZINGER, T. a. Et Al., 2004)

COMB

COMB

HYP-A` 0≤ y−x [0≤ y−x]

HYP-A` 0≤ z−y [0≤ z−y]

` 0≤ z−x [0≤ z−x]HYP-B

` 0≤ x−z−1 [0≤ 0]` 0≤−1 [0≤ z−x]

Figure 4. Deriving an interpolant.

RES

RES

HYP-A` b [b∨ ⊥]

HYP-A` ¬b,c [¬b∨c]

` c [⊥ ∨(⊥ ∨c)]HYP-B

` ¬c [⊥ ∨>]`⊥ [⊥ ∨((⊥ ∨c)∧>)]

Figure 5. Deriving an interpolant using resolution.

(op1 : pc1); . . . ;(opn : pcn). For formulasφ,φ1,φ2 ∈ FOL, we writeite.φ.φ1.φ2 to abbreviate(φ∧φ1)∨ (¬φ∧φ2).

Semantics.The semantics of a program is defined over the setv ofstates. The state of a program contains valuations to all lvalues, thevalue of the program counter, as well as the call stack. For our pur-poses, we only consider thedata state, which is a type-preservingfunction from all lvalues to values. Aregion is a set of data states.We represent regions using first-order formulas with free variablesfrom the set of program variables. Each operationop ∈ Opsde-fines a state transition relation

op−→⊆ v× v in a standard way [23].The semantics of a trace can also be given in terms of thestrongestpostconditionoperator [16]. Letϕ be a formula inFOL represent-ing a region. The strongest postcondition ofϕ w.r.t. an operationop, written SP.ϕ.op is the set of states reachable from states inϕafter executingop. The strongest postcondition operator for ourlanguage can be computed syntactically as a predicate transformer.

The strongest postcondition operator gives the concrete semanticsof the program. Our analyses will consider abstract semantics ofprograms. The abstract domain will be defined by a set of predicatesover the program variables. As we use decision procedures to com-pute predicate abstractions, we require quantifier-free predicates.For a formulaϕ∈ FOL and a set of atomic predicatesP⊆ FOL, thepredicate abstractionof ϕ w.r.t. the setP is the strongest formulaψ (in the implication order) with atomic predicates fromP suchthatϕ impliesψ. Let Π: PC→ 2FOL be a mapping from programlocations to sets of atomic predicates. The operatorSPΠ is the ab-straction of the operatorSP w.r.t. Π. Formally, letϕ denote a set ofstates, and let(op : pc) be a command. ThenSPΠ.ϕ.(op : pc) is thepredicate abstraction ofSP.ϕ.op w.r.t. Π.pc.

Let SP be a syntactic strongest postcondition operation, andSPΠits abstraction w.r.t. the mappingΠ. For any tracet, the tracet is(1) feasibleif there exist statess0,s1, . . . ,sn∈ v such thatsj

op j−−→sj+1for j = 0, . . . ,n− 1, and infeasible otherwise; (2)SP-feasible ifSP.true.t is satisfiable, andSP-infeasibleotherwise; and (3)Π-feasibleif SPΠ.true.t is satisfiable, andΠ-infeasibleotherwise.The two notions (1) and (2) coincide [23].

Subclasses of programs. A program is flat if it is a single-ton {Cmain}, and there is no edge(pc,pc′) in Cmain such thatOp(pc,pc′) is a function call or a return. A program ispointer-free if all lvalues and expressions have typeint. Specifically, apointer-free program does not have any references. In the follow-ing, we shall consider four classes of programs: (ClassPI) flat andpointer-free, (ClassPII) pointer-free (but not flat), (ClassPIII) flat

(but not pointer-free), and (ClassPIV) the class of all programs.For each class, we define a syntactic predicate transformerSP thattakes a formulaϕ∈ FOL and an operationop∈Opsand returns thestrongest postconditionSP.ϕ.op. We also define the predicate ab-stractionSPΠ of SP. Finally, we present an algorithmExtract thattakes a tracet and returns a mappingΠ from PC to sets of atomicpredicates inFOL. The following theorem relates the different no-tions of feasibility.

THEOREM 1. Let t be a trace of a program P of classPI, PII, PIII,or PIV. The following are equivalent:

1. t is infeasible (or equivalently, t isSP-infeasible).

2. t isSPΠ-infeasible forΠ = Extract.t.

In particular, Theorem 1 states that our predicate discovery proce-dureExtract is completefor each class: for an infeasible tracet, thepredicate mapExtract.t is precise enough to make the traceSPΠ-infeasible (i.e.,the infeasible tracet is not a trace of the abstraction).If all integer variables are initialized to some default integer value,say 0, then all satisfying assignments of theSP of a trace will beintegral even if theSP is interpreted over the rationals. Thus, if thetrace is infeasible, our proof system can derive the unsatisfiabilityof the strongest postcondition.

In the next two sections, we describe in detail how we mine pred-icates from proofs of unsatisfiability of spurious error traces. Firstwe consider programs in the classesPI andPII. We then generalizeour results to the classesPIII andPIV. For a given tracet of eachclass of program, we define the following operators. First, we de-fine the concrete and abstract strongest postcondition operatorsSPandSPΠ, which take a formula and an operation and return a for-mula, and we extend them to the entire tracet. Next, we define anoperatorCon, which returns aconstraint map. This is a functionthat maps each pointi of the tracet to aconstraintthat correspondsto theith operation of the trace. The conjunction of the constraintsthat are generated at all points oft is the trace formula (TF) fort,which is satisfiable iff the trace is feasible. Finally, we define theprocedureExtract, which uses a proof of unsatisfiability of the TFto compute a functionΠ that maps each program location to a setof atomic predicates such that the tracet is Π-infeasible.

Page 7: Abstractions From Proofs (HENZINGER, T. a. Et Al., 2004)

t SP.ϕ.t SPΠ.ϕ.t Con.(θ,Γ).t

(x := e : pci) ∃x′. (ϕ[x′/x]∧ x = e[x′/x]) α.(Π.pc).(SP.ϕ.t) (θ′,Γ[i 7→ (Sub.θ′.x = Sub.θ.e)])wherex′ is a fresh variable whereθ′ = Upd.θ.{x}

(assume(p) : pci) ϕ∧ p ” (θ,Γ[i 7→ Sub.θ.p])

t1; t2 SP.(SP.ϕ.t1).t2 SPΠ.(SPΠ.ϕ.t1).t2 Con.(Con.(θ,Γ).t1).t2

(y := f (~e) : pci); ∃y′,~φ. ϕ[y′/y] α.(Π.pcj ). (θ′,Γ′)t1; ∧ ∃r.~φ =~e[y′/y] (∃y′,~φ. ϕ[y′/y] where

(return : pcj ) ∧ ∃V−f . SP.true.t1 ∧ ∃r.~φ =~e[y′/y] θ′ = Upd.θ.{y}

∧ y = r ∧ ∃V−f . SPΠ.true.t1 θI = Upd.θ′.Vf

wherey′ is fresh ∧ y = r) ΓI = Γ[i 7→ Sub.θI .~φ = Sub.θ.~e]~x are the formals off (θO,ΓO) = Con.(θI ,ΓI ).t1r is the return variable off Γ′ = ΓO[ j 7→ Sub.θ′.y = Sub.θO.r]V−

f = Vf \ (symf ∪{r}) r is the return variable off

Figure 6. Postconditions and constraints forPI and PII traces.

5 Programs without Pointers

5.1 Flat Pointer-free Programs:PI

Strongest postconditions and constraints. We first define thesemantics of flat pointer-free programs in terms of a syntacticstrongest postcondition operatorSP and its predicate abstractionSPΠ (w.r.t. a predicate mapΠ). In Figure 6 the first three rows de-fine the operatorsSP andSPΠ for traces ofPI. Each operator takesa formula inFOL and returns a formula inFOL. The operatorSPΠis parameterized by a mapΠ from PC to sets of atomic predicates.With this definition ofSP, we can show that Theorem 1 holds.

An lvalue mapis a functionθ from Lvals to N. The operatorUpd:(Lvals→ N) → 2Lvals→ (Lvals→ N) takes a mapθ and a set oflvaluesL, and returns a mapθ′ such thatθ′.l = θ.l if l 6∈ L, andθ′.l = i l for a fresh integeri l if l ∈ L. The functionSub takes anlvalue mapθ and an lvaluel and returns〈l ,θ.l〉. The functionSub.θis extended naturally to expressions and formulas. Anew lvaluemap is one whose range is disjoint from all other maps. We uselvalue maps to generate trace formulas (TF); at a point in the trace,if the map isθ, then the the pair〈l ,θ.l〉 is a special constant thatequals the value ofl at that point in the trace. Whenever somelvalue l is updated, we update the map so that a fresh constant isused to denote the new value ofl . For every such constantc= 〈l , i〉,let Clean.c = l . The operatorClean can be naturally extended toexpressions and formulas ofFOL.

The constraints are generated by the functionCon, which takesa pair (θ,Γ) consisting of an lvalue mapθ and a constraint mapΓ: N → FOL, and a command(pc : op) ∈ Cmd, and returns apair (θ′,Γ′) consisting of a new lvalue map and constraint map.We generate one constraint per command. For a tracet = (op1 :pc1); . . . ;(opn : pcn), if (θ′,Γ′) = Con.(θ,Γ).t for some initialΓ,θ,thenΓ.i is the constraint foropi , and it can be shown by inductionon the length of the trace, that the TF

∧1≤i≤n Γ.i is satisfiable iff

SP.true.t is satisfiable. The generated constraints are a skolem-ized version of the strongest postcondition. The functionCon isdefined in the first three rows of Figure 6. If theith operation in thetrace is the assignmentx := e, we first update the map so that a newconstant denotes the value ofx, and then we have theith constraintspecify that the new constant forx has the same value as the ex-pressione (with appropriate constants plugged in). For an assumeoperationassume(p), the constraint stipulates that the constants atthat point satisfy the formulap. The constants enable us to encode

Algorithm 1 Extract

Input: an infeasible tracet = (op1 : pc1); . . . ;(opn : pcn).Output: a mapΠ from the locations oft to sets of atomic predicates.Π.pci := /0 for 1≤ i ≤ n(·,Γ) := Con.(θ0,Γ0)P := derivation of

∧1≤i≤n Γ.i ` false

for i := 1 ton doϕ− :=

∧1≤ j≤i Γ. j

ϕ+ :=∧

i+1≤ j≤n Γ. jψ := ITP.(ϕ−,ϕ+).(P )Π.pci := Π.pci ∪Atoms.(Clean.ψ)

return Π.

(assume(b > 0) : pc1); 〈b,0〉> 0(c := 2∗b : pc2); 〈c,1〉= 2∗ 〈b,0〉

(a := b : pc3); 〈a,2〉= 〈b,0〉(a := a−1 : pc4); 〈a,3〉= 〈a,2〉−1 ϕ−

(assume(a < b) : pc5); 〈a,3〉< 〈b,0〉 ϕ+

(assume(a = c) : pc6) 〈a,3〉= 〈c,1〉Figure 7. Cutting a PI trace.

the entire history of the trace in the constraint map.

PROPOSITION 1. [Equisatisfiability] For a trace t let (θ,Γ) =Con.(θ0,Γ0).t and let ϕ =

∧1≤i≤n Γ.i. The trace t is feasible iff

theϕ is satisfiable. Moreover, the size ofϕ is linear in the size of t.

Predicates from cuts.Given an infeasible tracet, we want to learna set of predicates that exhibit the infeasibility of the trace. Ourmethod has been described in Section 2 and is made precise in Al-gorithm 1. Algorithm 1 first sets the mapΠ to be the empty map.It then generates the constraint mapΓ for the entire trace and con-structs the TF by conjoining all constraints in the range ofΓ. LetP be a proof of unsatisfiability of the TF. Then for each pointiin the trace, wecut the constraints into those from the firsti com-mands (ϕ−) and those from the remaining commands (ϕ+). Usingthe proofP we compute the interpolantψ for (ϕ−,ϕ+) and add theatomic predicates that occur inψ after cleaning to the predicate mapfor pci . The correctness of this procedure is stated in Theorem 1.

EXAMPLE 1: Consider the infeasible trace from [3] shown onthe left in Figure 7. On the right, the figure shows the result ofCon.(θ0,Γ0).t, where the initial lvalue mapθ0 mapsa, b, andcto 0. To the right of each command is the corresponding con-straint. When we cut the trace at the fourth location, the result-

Page 8: Abstractions From Proofs (HENZINGER, T. a. Et Al., 2004)

(a := 0 : pc1); 〈a,1〉= 0(b := inc(a) : pc2); 〈φx,2〉= 〈a,1〉

(assume (x = φx) : pc2); 〈x,3〉= 〈φx,2〉(x := x+1 : pc3); 〈x,4〉= 〈x,3〉+1(r := x : pc4); 〈r,5〉= 〈x,4〉

(return r : pc5); 〈b,6〉= 〈r,5〉(assume(a 6= b−1) : pc6) 〈a,1〉 6= 〈b,6〉−1

i

ϕ+

ϕ−

ϕ−C

ϕ+C

Figure 8. Cutting a PII trace.

ing pair (ϕ−,ϕ+) consists of the conjunctions of the constraintsfrom above and below the line, respectively. The interpolant in thiscase is〈a,3〉 ≤ 〈c,1〉−2, which upon cleaning yields the predicatea≤ c−2. Notice that the constants common to both sides of thecut denote the values of the respective variables after the first fouroperations, andϕ− implies the interpolant. 2

5.2 Pointer-free Programs:PII

We now move on to programs with function calls, but no pointers.We assume that there are no global variables, and that each func-tion returns a single integer. When dealing with such programs, theanalysis of the previous section may learn predicates that are notwell-scoped,i.e., for some location, we may extract predicates thatcontain variables which are out-of-scope at that location, and suchan analysis is not modular. For a modular interprocedural analy-sis, we need to compute the effect of a function in terms of thearguments passed to it,i.e., we wish to relate the “output” of thefunction to its “input.” The way to do this is to introduce symbolicvariables that denote the values the function is called with, performthe analysis using the symbolic variables, and then, at the call site,plug in the actual values for the constants to see the result of thefunction. This method is known as polymorphic predicate abstrac-tion [1]. We assume that the program has been preprocessed sothat (1) for every function and every formal parameterx, the func-tion has a new local, so-calledsymbolicvariableφx, which holdsthe value of the argument when the function is called and is neverwritten to (the set of symbolic variables off is symf ), and (2) thefirst statement of every function isassume(∧ixi = φxi ), where theconjunction ranges over the setXf of formal parameters. Finally, toavoid clutter in the definitions due to renaming, we assume that dif-ferent functions have different names for their variables, and that nofunction calls itself directly (a functionf can of course call anotherfunction which, in turn, callsf ).

Strongest postconditions and constraints.Figure 6 shows thesyntactic strongest postcondition operatorSP and its predicate ab-stractionSPΠ for PII traces. The fourth row shows the case of callsand returns (we process the entire call-return subtrace at once). Thestrongest postcondition for this case is computed as follows: we re-placey as for an assignment, we set the symbolic variablesφ’s to thearguments~e[y′/y], we then computeSP for the body of the functiont1 w.r.t. true (the first operation in the function will equate the for-mal parameters~x with the φ’s), and we subsequently quantify outall locals except theφ’s, which leaves us with a formula that relatesthe return variabler to theφ’s. We then sety to r and quantify outtheφ’s andr. The abstract postcondition does the same, only it usesthe the abstract postconditionSPΠ of the function body instead ofSP, and then abstracts the resulting formulas using the predicatesof pcj , the location of the caller after the function returns. The gen-erated constraints are again a skolemized version of the strongestpostcondition. The constraint for the call command is the formulathat equates theφ’s with the corresponding actual parameters, andthe constraint for the return is the formula that equatesy with the

return valuer of the function. To deal with possibly recursive func-tions, we use a different lvalue map for the constraints of the func-tion body, because we do not want assignments to local variables ofthe called function to change the values of variables in the callingcontext. With these definitions, the analogue of Proposition 1 holdsfor PII programs.

EXAMPLE 2: Consider the trace in Figure 8. The functioninc hasthe formal parameterx and return variabler, and returns a value onegreater than its input. Assume that we start with an lvalue mapθ0,which mapsa, b, x, andφx to 0. The constraintsCon.(θ0,true).tare shown on the right in Figure 8. 2

Predicates from cuts.To get well-scoped predicates, we need onlyto generalize the notion of cuts. For each locationi of a trace, in-stead of partitioning the constraints into those due to commandsbeforei and those originating from commands afteri, we use thepartition shown in Figure 8. LetiL (resp.,iR) be the first (resp., last)command in the call body to which theith command belongs. SoiL is the first command after a function call, and the operation afteriR is a return. We consider four sets of constraints: (1)ϕ− corre-sponds to the commands between (and including)iL and i, whichmay include commands that call into and return from other func-tions, (2)ϕ+ corresponds to the commands fromi +1 to iR, whichmay include commands that call into and return from other func-tions betweeni + 1 and iR, (3) ϕ−C corresponds to the commandsin the calling context of commandi which occur before the callof the function to whichi belongs, and which include the call ofthe function, and (4)ϕ+

C corresponds to the commands in the call-ing context which occur after the return of the function to whichibelongs, and which include the return. We then construct the in-terpolant of(ϕ−,ϕ+∧ϕ−C ∧ϕ+

C ). One can check that the constantscommon toϕ− andϕ+∧ϕ+

C are denote the values of locals (includ-ing the return variable) at locationi, and that the constants commonto ϕ− andϕ−C are denote the values of symbolic variables upon en-try to the function, which are never changed by the function, andhence also the values of the symbolic variables at locationi; (theseare also locals of the called function). Hence the interpolant, andthus the predicates we compute, are in terms of variables that arein scope at locationi, and they refer only to current values of thosevariables at locationi.

To see why such an interpolant suffices, consider first the parti-tion (ϕ− ∧ ϕ+,ϕ−C ∧ ϕ+

C ), namely, into constraints that belong tothe function body and constraints that belong to the calling con-text. The resulting interpolantψ contains the symbolic variablesof the function to which the cut-point belongs, as well as the re-turn variabler, i.e., the inputs and output of the called function.Moreover,ψ abstractly summarizes the information about the func-tion call which renders the trace infeasible, becauseψ∧ (ϕ−C ∧ϕ+)is unsatisfiable. Now, at each point inside the function, we needto know what information is required to show thatψ holds at theend. To get this information, we could compute the interpolant of(ϕ−,ϕ+∧¬ψ), but since¬ψ is implied byϕ−C ∧ϕ+

C , we can insteaddirectly compute the interpolant of(ϕ−,ϕ+ ∧ (ϕ−C ∧ϕ+

C )). The re-sulting predicate discovery algorithmExtract for traces ofPII pro-grams is shown in Figure 2. The correctness of this procedure isstated in Theorem 1.

EXAMPLE 3: Recall the trace and constraints from Figure 8. Theformulas that result from cutting the trace at the fourth locationareϕ− = (Γ.3∧Γ.4) = (〈x,3〉 = 〈φx,2〉 ∧ 〈x,4〉 = 〈x,3〉+ 1) andϕ+ = Γ.5 = (〈r,5〉 = 〈x,4〉). Furthermore,ϕ−C = (Γ.1∧ Γ.2) =

Page 9: Abstractions From Proofs (HENZINGER, T. a. Et Al., 2004)

Algorithm 2 Extract

Input: an infeasible tracet = (op1 : pc1); . . . ;(opn : pcn).Output: a mapΠ from the locations oft to sets of atomic predicates.Π.pci := /0 for 1≤ i ≤ n(·,Γ) := Con.(θ0,Γ0)P := derivation of

∧1≤i≤n Γ.i ` false

for i := 1 ton do(iL, iR) := (L.t.i,R.t.i)ϕ− :=

∧iL+1≤ j≤i Γ. j

ϕ+ :=∧

i+1≤ j≤iR−1 Γ. jϕC := (

∧1≤ j≤iL Γ. j)∧ (

∧iR≤ j≤n Γ. j)

ψ := ITP.(ϕ−,ϕ+ ∧ϕC).(P )Π.pci := Π.pci ∪Atoms.(Clean.ψ)

return Π.

(assume (x 6= y) : pc1); 〈x,0〉 6= 〈y,0〉(∗x := 0 : pc2); 〈∗〈x,0〉,3〉= 0(y := x : pc3); 〈y,4〉= 〈x,0〉∧ 〈∗〈y,4〉,5〉= 〈∗〈x,0〉,3〉

(assume(y = x) : pc4); 〈y,4〉= 〈x,0〉∧ 〈∗〈y,4〉,5〉= 〈∗〈x,0〉,3〉(∗y := ∗y+1 : pc5); 〈∗〈y,4〉,6〉= 〈∗〈y,4〉,5〉+1∧

ite.(〈x,0〉= 〈y,4〉).(〈∗〈x,0〉,7〉= 〈∗〈y,4〉,5〉+1).(〈∗〈x,0〉,7〉= (〈∗〈x,0〉,3〉))

(assume(∗x = 0) : pc6) 〈∗〈x,0〉,7〉= 0Figure 9. Cutting a PIII trace.

(〈a,1〉 = 0∧ 〈φx,2〉 = 〈a,1〉) and ϕ+C = (Γ.6∧ Γ.7) = (〈b,6〉 =

〈r,5〉 ∧ (〈a,1〉 6= 〈b,6〉 − 1). The symbols common toϕ− andϕ+ ∧ (ϕ−C ∧ ϕ+

C ) are 〈x,4〉 and 〈φx,2〉, which are the values ofxandφx at that point. The interpolant is〈x,4〉 = 〈φx,2〉+ 1, whichyields the predicatex = φx +1. Similarly, when we cut the trace atthe fifth location, the common variables are〈r,5〉 and〈φx,2〉, andthe cleaned interpolant which summarizes the function’s behaviorfor all calling contexts isr = φx+1. Notice that at this point, whichis the last location of the function body, the interpolant is guaran-teed to only use the “input” and “output” variables of the function.When cutting the trace at the sixth location, we get the predicateb = a−1, which is again well-scoped forpc6, where the variablesx, φx, andr are not in scope. It is easy to check that these predicatesmake the trace abstractly infeasible. 2

6 Programs with Pointers

We now consider programs that deal with pointers. As before, wefirst consider “flat” programs, and then move on to programs withprocedures. The only difference with the previous section is in theconstraint generation; the algorithmExtract is exactly the sameas before, only it uses a different functionCon. In this somewhattechnical section we show how the constraint generation must beextended to handle pointers in a sound and complete way.

Stores. The classical way to model the store is to use memoryexpressions and the theory of arrays [13, 26, 27], which comesequipped with two special functions,sel andupd. The functionsel takes a memoryM and an addressa and returns the contentsof the addressa; the functionupd takes a memoryM, an addressa, and a valuev, and returns a new memory that agrees withMexcept that the addressa now has valuev. The relationship be-tweensel andupd is succinctly stated by McCarthy’s axiom [21]:sel(upd(M,a,v),b) = ite.(a= b).v.sel(M,b). For a memory vari-ableM and a variablex, defineM.x = sel(M,x), and for an lvalue∗l , defineM.(∗l) = sel(M,M.l). With some slight abuse of nota-tion, we useM in this way to denote a map from lvalues to memoryexpressions overM. We naturally extend the mapM to expressions

and formulas ofFOL. Expressions and formulas appearing in theprogram do not contain memory variables,sel, or upd.

Symbolic variables. We must generalize the notion of symbolicvariables, which freeze the formal parameters of a function, be-cause now a pointer may be passed to a function and the func-tion may change the value of some cell that is reachable usingthe pointer. Hence, we have to relate the values of cells at thereturn of a function with the values the cells had upon the corre-sponding function call. For a setX of variables, letReach.X ={∗kx | x∈ X andk≥ 0} be the set of cells that are reachable fromXby dereferences. As we do not have recursive types, this set is finiteand syntactically computable (k is bounded by the type ofx). Theset ofsymbolic variablesof f is nowsymf = {φl | l ∈ Reach.Xf },whereXf is the set of formal parameters off . As before, (1) thesymbolic variables are local variables of the function which arenever written to, and (2) the program is changed, by a syntacticpreprocessing pass, so that each lvalue that is reachable from theformal parameters reads its value from the corresponding symbolicvariable (i.e., x from φx, ∗x from φ∗x and so on) in the very firststatement of the function (usingassume(

∧l∈Reach.Xf

l = φl )). Asbefore, for modularity we analyze the function using the symbolicvariables, and replace their values with the actual parameters at thecall sites [1, 29]. For a symbolic variableφl , define(φl ↓) = l .

Constraints for modeling allocation. Suppose there are two vari-ablesx andy, each of typeref int. When the program begins,and the pointers are allocated, the standard semantics is that theirvalues are not equal. For completeness, this must be explicitly mod-eled by constraints. We modify the transformation, described ear-lier, which inserts into every function as first statement anassumethat copies the symbolic variables into the formal parameters, toinclude another clause that states that every two distinct lvaluesl1, l2 ∈ Reach.(Vf \ (Xf ∪ symf )) of reference type are not equal.Again, as the types are nonrecursive, this clause is quadratic in thesize of the function. An example is the firstassume in the trace ofFigure 9.

Constraints for modeling the store with lvalue maps. Usingsel andupd it is straightforward to generate the strongest post-conditions for programs with pointers; see Figure 10. Unfortu-nately, the theory of arrays does not have the interpolant prop-erty, thus we cannot get interpolants from TFs that use this the-ory. For example, the conjunction ofM′ = upd(M,x,y) and(a 6=b)∧ (sel(M,a) 6= sel(M′,a))∧ (sel(M,b) 6= sel(M′,b)) is un-satisfiable, but there is no quantifier-free interpolant in the commonset of variables, namely{M,M′}. We surmount this hurdle by mod-eling the memory axioms using (generalized) lvalue maps, and byinstantiating the array axioms on demand. Recall the definitions oflvalue maps andUpd from Section 5. The setChLval consists ofelementscl generated by the grammarcl ::= 〈x, i〉 | 〈cl, i〉, wherei ∈ N. The functionClean of the previous section is extended byClean.〈x, i〉 = x andClean.〈cl, i〉 = ∗(Clean.cl). Eachcl ∈ ChLvalis a special constant that denotes the value ofClean.cl at some pointin the trace. The functionSub of the previous section is extended toall lvalues bySub.θ.(∗kx) = 〈x,θ.x〉 if k = 0, andSub.θ.(∗kx) =〈Sub.θ.∗k−1 x,θ.(∗kx)〉 otherwise, and extended naturally to ex-pressions, atomic predicates, and formulas.

Constraints for assume operations.Modeling the memory withsel and upd gives us some relations for free,e.g., from x = y(modeled assel(M,x) = sel(M,y)) the equality∗x = ∗y (mod-eled assel(M,sel(M,x)) = sel(M,sel(M,y))) follows by con-

Page 10: Abstractions From Proofs (HENZINGER, T. a. Et Al., 2004)

gruence. We explicitly state these implied equalities when generat-ing constraints, by closing a predicate with the operatorclos∗.true:FOL→ FOL, where

clos∗.b.p =

(clos∗.b.p1) op (clos∗.b.p2) if p≡ (p1 op p2),¬(clos∗.(¬b).p1) if p≡ (¬p1),p∧

∧0≤k≤N((∗kl1) = (∗kl2)) if p≡ (l1 = l2) and

b = true,p otherwise,

providedtyp.l1 = typ.l2 = refNint. The formulaclos∗.true.pexplicates all equalities inferred by the memory axioms from theformulap. When generating the constraints forassume(p), we first“close” p usingclos∗, and then generate constraints for the result.Consider, for example, the constraint for the fourth command inFigure 9. For any formulap that can appear in anassume, wehaveM.p⇔ M.(clos∗.true.p) in the theory of arrays. Using thisequivalence, we can show the following lemma, which tells us thatthe constraints have been modeled adequately. For a programP, anlvalue∗kx is well-typed inP if typ.x = ref Nint for someN ≥ k,i.e., if x has typeref int, then∗x is well-typed but not∗ ∗ ∗x. Aformula p is well-typed w.r.t.P if (1) it does nor contain memoryvariables,sel, or upd, and (2) each lvalue that occurs inp is well-typed inP.

LEMMA 1. For a programP, two formulas p, p′ ∈ FOL that arewell-typed w.r.t.P, and an lvalue mapθ, the condition M.p impliesM.p′ iff Sub.θ.(clos∗.true.p) impliesSub.θ.p′.

Constraints for assignments.When assigning to∗l1 we must ex-plicate that for all lvalues∗l2 such thatl1 = l2, the value of∗l2 isupdated as well. LetEquate be a function that takes a pair of lvaluemaps(θ1,θ2) and a pair of expressions(l1, l2), and generates equal-ities between the names ofl1 and its transitive dereferences underθ1, and the names ofl2 and its transitive dereferences underθ2.Formally,

Equate.(θ1,θ2).(l1, l2) =∧

0≤k≤N

(Sub.θ1.(∗kl1) = Sub.θ2.(∗kl2)),

wheretyp.l1 = typ.l2 = refNint. Define the functionEqAddr,which takes a pair of lvalues and returns a formula that is true whenthe lvalues have the same address, byEqAddr.(∗k1x1,∗k2x2) =false if k1 = 0 ork2 = 0, andEqAddr.(∗k1x1,∗k2x2) = (∗k1−1x1 =∗k2−1x2) otherwise. For a functionf (which ismain for flat pro-grams), letLvals. f = Reach.Vf . For an lvaluel and a functionf , let Alias. f .l = {l ′ | l ′ ∈ Lvals. f andl ′ may be aliased tol}. Weonly require thatAlias. f .l overapproximates the set of lvalues thatcan actually aliasl .

Finally, we define the functionAsgn, which generates appropriateconstraints for an assignmentl := e. The functionAsgn takes afunction namef , an lvalue mapθ, and a pair(l ,e), wherel is anlvalue ande the expression that is being written intol , and returnsa pair(θ′,ϕ′) of an updated lvalue mapθ′ and a formulaϕ′. Defineθ′ = Upd.θ.S, whereS= {∗kl ′ | l ′ ∈ (Alias.l)∪{l} andk≥ 0}, anddefine

ϕ′ = Equate.(θ′,θ).(l ,e)∧

∧l ′∈Alias. f .l

ite. (Sub.θ.(EqAddr.(l , l ′))).(Equate.(θ′,θ).(l ′,e)).(Equate.(θ′,θ).(l ′, l ′))

.

The first conjunct ofϕ′ states thatl gets a new valuee, and alltransitive dereferences ofl andeare “equated” (i.e.,∗l gets the new

value ∗e, and so on). The big second conjunct ofϕ′ states howthe potential aliasesl ′ of l are updated: ifl and l ′ have the sameaddress, then the new value ofl ′ (given bySub.θ′.l ′) is equatedwith e; otherwise the new value ofl ′ is equated with the old valueof l ′ (given bySub.θ.l ′). This generalizes Morris’ definition for thestrongest postcondition in the presence of pointers [24].

LEMMA 2. Let l := e be an assignment in a programP, letϕ = SP.true.(l := e), and let(θ′,ϕ′) = Con.(θ0,true).t for somelvalue mapθ0. For every formula p∈FOL that is well typed w.r.t.P,the formulaϕ implies M.p in the theory of arrays iffϕ′ impliesSub.θ′.p.

6.1 Flat Programs: PIII

The first three rows of Figure 10 give the definition of the operatorSP using the theory of arrays, as well as the generated constraints.The definition ofSPΠ is the same as before, except that the newSPoperator is used. Notice that the “current” memory is always rep-resented byM. For assignments,SP states that the current memoryM is now an updated version of the old memory, which is renamedM′. We useAsgn to generate the appropriate constraints for deal-ing with the possible alias scenarios. For assume operations,SPis defined as before, except that the constraint generated is on the“closure” of the predicate usingclos∗. Constraints for sequences areobtained by composition. The size of the constraints is quadratic inthe size of the trace. By induction over the length of the trace, split-ting cases on the kind of the last operation, and using Lemmas 1and 2, we can prove the following theorem.

THEOREM 2. Given a trace t of a programP, let (θ′,Γ) =Con.(θ0,Γ0).t, let ϕr = SP.true.t, and letϕ =

∧1≤i≤n Γ.i. For

every formula p∈ FOL that is well-typed w.r.t.P, the formulaϕrimplies M.p in the theory of arrays iffϕ impliesSub.θ′.p. Hence,the trace t is feasible iff the formulaϕ is satisfiable.

Given the new definition ofCon, the algorithm for predicate dis-covery is the same asExtract (Algorithm 1), and Theorem 1 holds.

EXAMPLE 4: The right column in Figure 9 shows the constraintsfor the trace on the left. For readability, we omit unsatisfiable anduninteresting disjuncts (for the second and third commands). At thefourth cut-point of this trace, the common variables are〈∗〈y,4〉,3〉,〈y,4〉, 〈x,0〉, and 〈∗〈x,0〉,3〉, which denote the values of∗y, y,x, and∗x at that point in the trace. The interpolant for this cutis 〈∗〈y,2〉,3〉 = 0, which gives the predicate∗y = 0 for the loca-tion pc4. 2

6.2 General Programs:PIV

The main difficulty when dealing with functions and pointers is inhandling the semantics of calls and returns, because the callee maybe passed pointers into the local space of the caller. The complex-ity arises when we wish to abstract functions polymorphically [1],because then we have to summarize all effects that the callee mayhave had on the caller’s store at the point of return. One way to dothis is to imagine the callee starting with acopyof the caller’s storeand, upon return, the caller refreshing his store appropriately usingthe callee’s store. As we shall see, the difficulty is only in modelingthis appropriately with strongest postconditions. Following that, itis straightforward to generate the constraints, and the method forlearning predicates is again Algorithm 2, only now using the newdefinition ofCon.

Page 11: Abstractions From Proofs (HENZINGER, T. a. Et Al., 2004)

t SP.ϕ.t Con.(θ,Γ).t

(l := e : pci) ∃M′.(ϕ[M′/M]∧M = upd(M′,M′.l ,M′.e)) (θ′,Γ[i 7→ ϕ])whereM′ is a fresh store where(θ′,ϕ) = Asgn. f .θ.(l ,e)

f is the function in whichpci belongs

(assume(p) : pci) ϕ∧M.p (θ,Γ[i 7→ Sub.θ.(clos∗.true.p)])

t1; t2 SP.(SP.ϕ.t1).t2 Con.(Con.(θ,Γ).t1).t2

( f (~y) : pci); ∃M′,MI ,MO.symf . (θ′,Γ′)t1; ϕ[M′/M] where θI = Upd.θ.(Reach.Vf )

(return : pcj ) ∧M′ = MI ∧ϕld ϕld =∧

φ∈symfEquate.(θI ,θ).(φ,(φ ↓)[y/x])

∧ ϕ′[MO/M] ΓI = Γ[i 7→ ϕld ]∧ New.(L,P,R′).(MO,MI ) (θO,ΓO) = Con.(θI ,ΓI ).t1∧ M = copy(M′,MO,R) L,P,R,R′ as forSP

whereM′,MI ,M0 are fresh stores Γ′ = ΓO[ j 7→New.(L,P,R′).(θ,θO)∧copy.(θ,θ′,θO).(L,R)]ϕld =

∧φ∈symf

φ = MI .(φ ↓)[y/x] θ′ = Upd.θ.L~x are the formals offR= {∗φ | φ ∈ symf }ϕ′ = ∃V−

f .SP.true.t1V−

f = Vf \symf ,L = lvalues in scope atpc2P = symf andR′ = Reach.PFigure 10. Postconditions and constraints forPIII and PIV traces.

(∗y := 0 : pc1); 〈∗〈y,0〉,1〉= 0(inc(y) : pc2); 〈φx,1〉= 〈y,0〉∧ 〈φ∗x,2〉= 〈∗〈y,0〉,1〉

(assume (x = φx 〈x,4〉= 〈φx,1〉∧∗x = φ∗x) : pc3); ∧〈∗〈x,4〉,5〉= 〈∗〈φx,1〉,7〉

∧〈∗〈x,4〉,5〉= 〈φ∗x,2〉(∗x := ∗x+1 : pc4); 〈∗〈x,4〉,6〉= 〈∗〈x,4〉,5〉+1

ite.(〈x,4〉= 〈φx,1〉).(〈∗〈φx,1〉,8〉= 〈∗〈x,4〉,5〉+1).(〈∗〈φx,1〉,8〉= 〈∗〈φx,1〉,7〉

(return : pc5); ite.(〈y,0〉= 〈φx,1〉).(〈∗〈y,0〉,9〉= 〈∗〈φx,1〉,8〉).(〈∗〈y,0〉,9〉= 〈∗〈y,0〉,1〉).

(assume(∗y 6= 1) : pc6) 〈∗〈y,0〉,9〉 6= 1Figure 11. Cutting a PIV trace.

As we allow functions to pass pointers into the local store as argu-ments, to keep the exposition simple, we can assume w.l.o.g. that(1) there are no global variables (these can be modeled by passingreferences), and (2) there is no explicit “return” variable; instead,return values are passed by updating the contents of some cell thatis passed in as a parameter.

EXAMPLE 5: Consider the trace on the left in Figure 11. The caller(main) passes a pointery to the store to the calleeinc. The calleeupdates the memory address∗y (which is called∗x in inc). Thereare two symbolic variablesφx andφ∗x in inc, corresponding to theformal parameterx and its dereference. Theassume at locationpc3loads the symbolic variables into the formal parameters. 2

Soundness.Every cell in the caller’s store which is modified bythe callee must be reachable from a parameter passed to the callee,e.g., the cell pointed to byy in the caller is the same as the cellpointed to byx when the functioninc is called, hence upon re-turn the value of∗y should be the value of∗(φx) (as in the interim,the callee may have changedx). Every cell of the caller which isunreachable from the parameters passed to the callee remains un-changed as a result of the call. This is modeled in theSP seman-tics by copying the contents of the callee’s store, at the locationsreachable from the passed parameters, into the caller’s store. Thelocations that are reachable from the passed parameters are frozen

in the symbolic variables of the callee. It can be shown that this issound for our language. To express the copying inSP, we use theoperatorcopy: for a destination memoryMd, a source memoryMs,and a dereferenced lvalue∗l , the expressioncopy(Md,Ms,∗l) is theresult of updatingMd such that all cells reachable froml have thesame value as inMs. Formally, we definecopy(Md,Ms,∗l) as{

upd(Md,Md.l ,Ms.(∗l)) if typ.∗ l = int,copy(upd(Md,Md.l ,Ms.(∗l)),Ms,∗∗ l) otherwise.

We never need to copy into a variablex. The functioncopy is ex-tended to a sequence of lvalues~l = (∗l ::~l ′) by copy(Md,Ms,~l) =copy(copy(Md,Ms,∗l),Ms,~l ′). It can be shown that the result isindependent of the order of lvalues. Hence, we can consider theoperatorcopy to be defined oversetsof lvalues. We can mimic“copying” by lvalue maps as follows. Given three lvalue mapsθd, θ′d, andθs, an lvalue∗l , and a sequenceR of lvalues, definecopy.(θd,θ′d,θs).(∗l ,R) =

Sub.θ′d.∗ l = Sub.θd.∗ l if R≡ ·,ite.(Sub.θ′d.l = Sub.θd.φ).

(Equate.(θ′d,θs).(∗l ,∗φ)).copy.(θd,θ′d,θs).(∗l ,R′) if R≡ φ :: R′.

Finally, for a setL of lvalues, definecopy.(θd,θ′d,θs).(L,R) =∧∗l∈L copy.(θd,θ′d,θs).(∗l ,R).

When a function returns, we update all local variables of the caller.We setθd to the lvalue map of the callerbeforethe call, andθ′d =Upd.θd.L is the lvalue map of the callerafter the call, whereL =Reach.{∗x | x is a local variable of the caller} is the set of lvaluesof the caller that can change (no local variablex can change as theresult of a call; only dereferences can change). We setθs to thelvalue map of the callee upon return, andR = symf is the set ofcells that were passed to the callee, and hence must be copied backinto the caller. It can be checked that the formulas resulting fromdifferent permutations ofRare equivalent.

Completeness.For completeness, we must ensure that we prop-erly model the semantics of allocation. It can be shown that

Page 12: Abstractions From Proofs (HENZINGER, T. a. Et Al., 2004)

it suffices to ensure that every cell that is being “returned” bythe callee (i.e., reachable from a symbolic variable of the callee)is either a cell passed to it (i.e., equal to some symbolic vari-able) or is brand new (i.e., different from Reach.Vf , the set ofcells known to the caller). If a cell is different from those ofthe caller, then transitivity of equality and the same check on allsubsequent returns ensures that the cell is different from all pre-viously allocated ones. The check is encoded with the op-erator New. For an lvaluel of reference type, a setL oflvalues, and two storesMl and ML, definediff.(l ,L).(Ml ,ML) =∧l ′∈L¬(Ml .l = ML.l ′). Given three setsL, P, and R of lvalues,and a pairMO andMI of stores, defineNew.(L,P,R).(MO,MI ) =(∧r∈R(diff.(r,P).(MO,MI ) ⇒ diff.(r,L).(MO,MI )). Here L =Reach.Vf ′ is the set of local variables of the callerf ′, andP= symfis the set of cells passed to the calleef , and R = Reach.symfis the set of cells returned by the callee. The storeMO isthe store upon return fromf , and MI was the store upon en-try to f . The formula says that for every cellr that is returned,if r is different from all cells passed tof , then r is differentfrom all local cells L of the caller f ′. This is generalized tolvalue maps as follows:diff.(l ,L).(θl ,θL) = ∧l ′∈L¬(Sub.θl .l =Sub.θL.l ′) andNew.(L,P,R).(θ,θ′) = (∧r∈R(diff.(r,P).(θ,θ′)) ⇒diff(r,L).(θ,θ′)).

Strongest postconditions and constraints.Using these functions,we can generate the strongest postconditions and the constraints asshown in Figure 10. Assignments, assume operations, and sequenc-ing is handled as before; we describe here only function calls. ForSP, we rename the caller’s store toM′ as it will change as a resultof the call. We pass a memoryMI equal toM′ to the callee, equatethe actual parameters with the symbolic variables, and computeSPof the callee. Then we rename the memory returned by the calleeto MO, and copy back the local store modified by the call intoM′

to get the current memoryM. Additionally, we add distinctnessconstraints to model allocation. The definition ofSPΠ is similar tothe one before: before it was the predicate abstraction ofSP, usingSPΠ to analyze the call body; now it is the predicate abstraction(using the predicates at the return location) of the newSP, usingSPΠ recursively for the call body. The correctness of the constraintgeneration is stated in Theorem 2. The size of the constraints iscubic in the size of the trace. Given the new definition ofCon,the method for predicate discovery is Algorithm 2, and Theorem 1holds.

EXAMPLE 6: Consider the trace in Figure 11. The right columnshows the constraints that correspond to each command. The con-straint from the assignment∗y= 0 is〈∗〈y,1〉,1〉= 0. First, the con-straint for the call command is the clauseϕld , which loads the actualparameters into to the symbolic constants forinc. The first com-mand in the body loads the values from the symbolic constants intothe formal parameters; notice that we take the “closure”. We thenbuild the constraints for the increment operation. NowL = {y,∗y},P = {φx,φ∗x}, R= {∗φx}, andR′ = {φx,∗φx,φ∗x}. The constraintNew.(L,P,R).(θ,θO) simplifies totrue, because∗φx is not a ref-erence type, and〈φx,1〉 = 〈y,0〉, i.e., it is a cell that was passed tof . Let θ′ be the map updatingθ so that∗y is mapped to 9. Fi-nally, the copy-back constraintcopy.(θ,θ′,θO).(L,R) is shown tothe right of the return. At the end, the assume operation generatesthe constraint〈∗〈y,1〉,3〉 6= 1. The set of generated constraints isunsatisfiable. Consider the fourth cut-point of this trace,i.e., upto and including the increment operation. The common variablesare〈φx,1〉, 〈∗〈φx,1〉,8〉, and〈φ∗x,2〉; they denote the current val-ues ofφx, ∗φx, andφ∗x, respectively. The interpolant for this cut is〈∗〈φx,1〉,8〉= 〈φ∗x,2〉+1, which upon cleaning gives the predicate

∗φx = φ∗x+1. This predicate asserts that the present cell pointed toby φx has a value 1 greater than the cell∗x had upon entry tof . 2

7 Experiments

We have implemented the interpolation based abstraction refine-ment scheme in the software model checker BLAST [19]. Thealgorithm for generating interpolants uses the VAMPYRE proof-generating theorem prover.2 For efficiency, we have implementedseveral optimizations of the basic procedure described in this paper.First, we treat sequences of assignments atomically. Second, we donot cut at every point of a spurious error trace. Instead, we performa preliminary analysis which identifies a subset of the constraintsthat imply the infeasibility of the trace, and only consider the in-structions that generate these constraints as cut-points. It is easy tocheck that the optimized procedure is still complete. For pointers,we only generate constraints between expressions of the same type.With these optimizations, we find, for example, that the two pred-icatesa≤ c−2 andb > 0 suffice to prove the trace in Example 1infeasible. These are fewer predicates than those generated by theheuristically optimized predicate discovery scheme of [3].

We ran interpolation based BLAST on several Windows NT de-vice drivers, checking a property related to the handling of I/ORequest packets. The property is a finite-state automaton with 22states [2]. The results, obtained on an IBM ThinkPad T30 laptopwith a 2.4 GHz Pentium processor and 512MB RAM, are sum-marized in Table 1. We present three sets of numbers: ‘Previ-ous’ gives the times for running the previous version of BLAST,without interpolants; ‘Craig’ uses interpolants to discover pred-icates, and drops predicates that are out of scope, but it doesnot track different sets of predicates at individual program loca-tions; ‘Craig+Locality’ uses interpolants and tracks only the rel-evant predicates at each program location. The previous versionof BLAST timed out after several hours on the driversparportand parclass. We found several violations of the specificationin parclass. The numbers in the table refer to a version ofparclass where the cases that contain errors are commented out.Both ‘Craig’ and ‘Craig+Locality’ perform better than the previ-ous version of BLAST. When started with the empty set of ini-tial predicates, ‘Craig’ is faster than ‘Craig+Locality’, because‘Craig+Locality’ may rediscover the same predicate at several dif-ferent program locations. However, since the predicates are trackedextremely precisely (the average number of predicates at a programlocation is much smaller than the total number of predicates re-quired), ‘Craig+Locality’ uses considerably less memory, and sub-sequent runs (for example, for verifying a modified version of theprogram [18], or for generating PCC-style proofs [17]) are faster,and the proof trees smaller.

8 References

[1] T. Ball, T. Millstein, and S.K. Rajamani. Polymorphic predicate ab-straction. ACM Transactions on Programming Languages and Sys-tems, 2003.

[2] T. Ball and S.K. Rajamani. Personal communication.

[3] T. Ball and S.K. Rajamani. Generating abstract explanations of spu-rious counterexamples in C programs. Technical Report MSR-TR-2002-09, Microsoft Research, 2002.

2VAMPYRE is available fromhttp://www.eecs.berkeley.edu/∼rupak/Vampyre.

Page 13: Abstractions From Proofs (HENZINGER, T. a. Et Al., 2004)

Program LOC Previous Craig Craig+LocalityDisc Reach Disc Reach Preds Disc Reach Preds Avg/Max

kbfiltr 12301 1m12s 0m30s 0m52s 0m22s 49 3m48s 0m10s 72 6.5/16floppy 17707 7m10s 3m59s 7m56s 3m21s 156 25m20s 0m46s 240 7.7/37diskperf 14286 5m36s 3m3s 3m13s 1m18s 86 13m32s 0m27s 140 10/31cdaudio 18209 20m18s 4m55s 17m47s 4m12s 196 23m51s 0m52s 256 7.8/27parport 61777 - - - - - 74m58s 2m23s 753 8.1/32parclass 138373 - - 42m24s 9m1s 251 77m40s 1m6s 382 7.2/28

Table 1. Experimental results usingBLAST: ‘m’ stands for minutes, ‘s’ for seconds; ‘LOC’ is the number of lines of preprocessed code; ‘Disc’ is thetotal running time of the verification starting with the empty set of predicates; ‘Reach’ is the time to perform the reachability analysis only, given allnecessary predicates; ‘Preds’ is the total number of predicates required, and Avg (Max) is the average (maximum) number of predicates tracked at aprogram location; the symbol ‘-’ indicates that the tool does not finish in 6 hours.

[4] T. Ball and S.K. Rajamani. The SLAM project: debugging systemsoftware via static analysis. InPOPL 02: Principles of ProgrammingLanguages, pages 1–3. ACM, 2002.

[5] R. Bodik, R. Gupta, and M.L. Soffa. Refining dataflow informationusing infeasible paths. InFSE 97: Foundations of Software Engineer-ing, LNCS 1301, pages 361–377. Springer, 1997.

[6] W.R. Bush, J.D. Pincus, and D.J. Sielaff. A static analyzer for find-ing dynamic programming errors.Software Practice and Experience,30:775–802, 2000.

[7] S. Chaki, E.M. Clarke, A. Groce, and O. Strichman. Predicate abstrac-tion with minimum predicates. InCHARME 03: Correct HardwareDesign and Verification, LNCS 2860, pages 19–34. Springer, 2003.

[8] E.M. Clarke, O. Grumberg, S. Jha, Y. Lu, and H. Veith.Counterexample-guided abstraction refinement. InCAV 00:Computer-Aided Verification, LNCS 1855, pages 154–169. Springer,2000.

[9] W. Craig. Linear reasoning.J. Symbolic Logic, 22:250–268, 1957.

[10] R. Cytron, J. Ferrante, B.K. Rosen, M.N. Wegman, and F.K. Zadek.Efficiently computing static single assignment form and the programdependence graph.ACM Transactions on Programming Languagesand Systems, 13:451–490, 1991.

[11] M. Das, S. Lerner, and M. Seigle. ESP: path-sensitive program ver-ification in polynomial time. InPLDI 02: Programming LanguageDesign and Implementation, pages 57–68. ACM, 2002.

[12] C. Flanagan. Automatic software model checking using CLP. InESOP 03: European Symposium on Programming, LNCS 2618, pages189–203. Springer, 2003.

[13] C. Flanagan, K.R.M. Leino, M. Lillibridge, G. Nelson, J.B. Saxe, andR. Stata. Extended static checking for Java. InPLDI 02: ProgrammingLanguage Design and Implementation, pages 234–245. ACM, 2002.

[14] C. Flanagan and J.B. Saxe. Avoiding exponential explosion: gen-erating compact verification conditions. InPOPL 01: Principles ofProgramming Languages, pages 193–205. ACM, 2001.

[15] J.S. Foster, T. Terauchi, and A. Aiken. Flow-sensitive type qualifiers.In PLDI 02: Programming Language Design and Implementation,pages 1–12. ACM, 2002.

[16] D. Gries.The Science of Programming. Springer, 1981.

[17] T.A. Henzinger, R. Jhala, R. Majumdar, G.C. Necula, G. Sutre, andW. Weimer. Temporal-safety proofs for systems code. InCAV 02:Computer-Aided Verification, LNCS 2404, pages 526–538. Springer,2002.

[18] T.A. Henzinger, R. Jhala, R. Majumdar, and M.A.A. Sanvido. Ex-treme model checking. InInternational Symposium on Verification,LNCS. Springer, 2003.

[19] T.A. Henzinger, R. Jhala, R. Majumdar, and G. Sutre. Lazy abstrac-tion. In POPL 02: Principles of Programming Languages, pages 58–70. ACM, 2002.

[20] J. Krajicek. Interpolation theorems, lower bounds for proof systems,and independence results for bounded arithmetic.J. Symbolic Logic,

62:457–486, 1997.

[21] J. McCarthy and J. Painter. Correctness of a compiler for arithmeticexpressions. InProc. Symposia in Applied Mathematics. AmericanMathematical Society, 1967.

[22] K.L. McMillan. Interpolation and SAT-based model checking. InCAV03: Computer-Aided Verification, LNCS 2725, pages 1–13. Springer,2003.

[23] J.C. Mitchell. Foundations for Programming Languages. MIT Press,1996.

[24] J. M. Morris. A general axiom of assignment. InTheoretical Founda-tions of Programming Methodology, Lecture Notes of an InternationalSummer School, pages 25–34. D. Reidel Publishing Company, 1982.

[25] M. Musuvathi, D.Y.W. Park, A. Chou, D.R. Engler, and D.L. Dill.CMC: A pragmatic approach to model checking real code. InOSDI02: Operating Systems Design and Implementation. ACM, 2002.

[26] G.C. Necula. Proof carrying code. InPOPL 97: Principles of Pro-gramming Languages, pages 106–119. ACM, 1997.

[27] G. Nelson. Techniques for program verification. Technical ReportCSL81-10, Xerox Palo Alto Research Center, 1981.

[28] P. Pudlak. Lower bounds for resolution and cutting plane proofs andmonotone computations.J. Symbolic Logic, 62:981–998, 1997.

[29] T. Reps, S. Horwitz, and M. Sagiv. Precise interprocedural dataflowanalysis via graph reachability. InPOPL 95: Principles of Program-ming Languages, pages 49–61. ACM, 1995.