ebook img

Compositional Shape Analysis by means of Bi-Abduction PDF

73 Pages·2011·1.08 MB·English
by  
Save to my drive
Quick download
Download
Most books are stored in the elastic cloud where traffic is expensive. For this reason, we have a limit on daily download.

Preview Compositional Shape Analysis by means of Bi-Abduction

Accepted for publication in Journal of the ACM Compositional Shape Analysis by means of Bi-Abduction CRISTIANO CALCAGNO Monoidics Ltd and Imperial College London DINO DISTEFANO Queen Mary University of London PETER W. O’HEARN Queen Mary University of London HONGSEOK YANG University of Oxford Theaccurateandefficienttreatmentofmutabledatastructuresisoneoftheoutstandingproblem areasinautomaticprogramverificationandanalysis. Shapeanalysisisaformofprogramanalysis that attempts to infer descriptions of the data structures in a program, and to prove that these structures are not misused or corrupted. It is one of the more challenging and expensive forms of program analysis, due to the complexity of aliasing and the need to look arbitrarily deeply into the program heap. This paper describes a method of boosting shape analyses by defining a compositionalmethod,whereeachprocedureisanalyzedindependentlyofitscallers. Theanalysis algorithmusesarestrictedfragmentofseparationlogic,andassignsacollectionofHoaretriples toeachprocedure;thetriplesprovideanover-approximationofdatastructureusage. Ourmethod brings the usual benefits of compositionality – increased potential to scale, ability to deal with incompleteprograms,gracefulwaytodealwithimprecision–toshapeanalysis,forthefirsttime. The analysis rests on a generalized form of abduction (inference of explanatory hypotheses) which we call bi-abduction. Bi-abduction displays abduction as a kind of inverse to the frame problem: itjointlyinfersanti-frames(missingportionsofstate)andframes(portionsofstatenot touched by an operation), and is the basis of a new analysis algorithm. We have implemented ouranalysisandwereportcasestudiesonsmallerprogramstoevaluatethequalityofdiscovered specifications, and larger code bases (e.g. sendmail, an imap server, a Linux distribution) to illustratethelevelofautomationandscalabilitythatweobtainfromourcompositionalmethod. The paper makes number of specific technical contributions on proof procedures and analy- sis algorithms, but in a sense its more important contribution is holistic: the explanation and demonstrationofhowamassiveincreaseinautomationispossibleusingabductiveinference. Categories and Subject Descriptors: F.3.2 [Logics and Meanings of Programs]: Seman- ticsofProgrammingLanguages—DenotationalSemantics;ProgramAnalysis;F.3.2[Logics and Meanings of Programs]: SpecifyingandVerifyingandReasoningaboutPrograms—Mechan- ical verification; Pre- and post-conditions; D.2.4 [Software Engineering]: Software/Program Verification—Correctness proofs GeneralTerms: Languages,Reliability,Theory,Verification Additional Key Words and Phrases: abstract interpretation, compositionality, static analysis, programproving,separationlogic JournaloftheACM,Vol.V,No.N,May2011,Pages1–0??. 2 Compositional Shape Analysis by means of Bi-Abduction · Contents 1 Introduction 2 1.1 Context and Motivating Question . . . . . . . . . . . . . . . . . . . . 3 1.2 Compositionality, Overapproximation, Footprints . . . . . . . . . . . 5 1.3 Approach and Contributions . . . . . . . . . . . . . . . . . . . . . . 6 2 Preliminary Concepts and Examples 7 2.1 Abductive Inference . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 2.2 Generating Preconditions using Abduction . . . . . . . . . . . . . . . 8 2.3 Bi-Abduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 2.4 Abstraction and Loops . . . . . . . . . . . . . . . . . . . . . . . . . . 10 3 Abduction and Bi-Abduction for Separated Heap Abstractions 12 3.1 Symbolic Heaps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 3.2 An Heuristic Algorithm for Abduction . . . . . . . . . . . . . . . . . 16 3.3 On the Quality of Solutions . . . . . . . . . . . . . . . . . . . . . . . 22 3.4 A Systematic Algorithm for a Restricted Fragment . . . . . . . . . . 25 3.5 Bi-Abduction and Framing: Execution-oriented Program-Proof Rules 34 3.6 Discussion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 4 Algorithms for Automatic Program Analysis 38 4.1 Procedures, Summaries and Control-flow Graphs . . . . . . . . . . . 38 4.2 Precondition Generation . . . . . . . . . . . . . . . . . . . . . . . . . 39 4.3 Pre/PostSynthesis: RevisingourWorkafterInductionandAbduction 50 4.4 The Soundness Property . . . . . . . . . . . . . . . . . . . . . . . . . 54 5 Case Studies 56 5.1 Small Examples: Simple Linked-List Programs . . . . . . . . . . . . 56 5.2 Medium Example: IEEE (1394) Firewire Device Driver. . . . . . . . 59 5.3 Large Programs and Complete Open Source Projects. . . . . . . . . 60 5.4 Discussion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 6 Related Work 66 7 Conclusions 68 1. INTRODUCTION Abductive inference – inference of explanatory hypotheses – was introduced by Charles Peirce in his writings on the scientific process [Peirce 1958]. Abduction was formulated to distinguish the creation of new hypotheses from deductive and inductive (generalization) inference patterns. Abductive inference has been widely studied in philosophy, and it has been used in a number of ways in artificial intelli- gence,suchasindiagnosisandinplanning. (Thesurveyarticles[Kakasetal.1992; Paul 1993] point to many formalizations and applications in the AI literature.) This paper is about the use of abductive inference in reasoning about computer programs. Just as abduction considered philosophically is thought of as a mecha- nism to create hypotheses, we propose that in reasoning about computer programs JournaloftheACM,Vol.V,No.N,May2011. Compositional Shape Analysis by means of Bi-Abduction 3 · it can be used to generate preconditions, in the sense of pre/post specifications of program components. We state right away that the goal of abduction used in this way is not necessarily to supplant the human in the writing of specifications, but rather to complement him or her: we suggest that generated preconditions could be useful in program understanding or as a helpful guide during interactive proof efforts, and we demonstrate that they can be used to raise the scalability and level of automation in mechanized tools for program verification and analysis. 1.1 Context and Motivating Question Thecontextinwhichthisresearcharoseisverificationofprogramsthataccessand mutatedatastructuresincomputermemory. Weareinterestedinparticularinthe use of techniques from static program analysis to perform automatic verification. Program analyses can relieve the user of the burden of stating loop invariants and otherannotations,andcaninprinciplebeappliedmoreeasilytoexistingcodebases than can more manual techniques. The last decade has seen a surge of interest in verification-by-static-analysis, with prominent success stories such as SLAM’s application of proof technology to Microsoft device drivers [Ball et al. 2006] and ASTRE´E’s proof of the absence of run-time errors in Airbus code [Cousot et al. 2005]. But, most practical tools for verification-oriented static analysis ignore pointer-based data structures, or use coarse models that are insufficient to prove basic properties of them; for example, SLAM assumes memory safety and ASTRE´E works only on input programs that do not use dynamic allocation. Data structures present one of the most pressing open problems in verification-oriented program analysis, progress on which would extend the reach of automatic program verification tools. Althoughthegeneralproblemisnotsolved,therehasbeensubstantialpriorwork under the heading ‘shape analysis’1, a kind of pointer analysis which looks deeply intotheheapinanattempttodiscoverinvariantsthatdescribethedatastructures in a program (e.g., [Sagiv et al. 1998; Balaban et al. 2005; Podelski and Wies 2005; Guo et al. 2007; Berdine et al. 2007]). A shape analysis can in principle prove that programs do not commit pointer-safety errors (dereferencing a null or dangling pointer, or leaking memory), without the user having to write loop invariants or even pre/post specifications for procedures; these are inferred during analysis. To do this the analysis typically has to accurately identify (or distinguish) cyclic and acyclic linked structures, nested lists, and so on. There are, though, some fundamental problems holding back the wider use of shape analyses in verification-by-static-analysis tools. First of all, shape analyses are notoriously expensive, and had mostly been applied to verification of codes in the tens or hundreds of LOC and, only recently, after much effort, to a restricted family of similar programs up to 10k LOC [Yang et al. 2008]. Second, in our prior work on SpaceInvader attempting to apply shape analysis techniques to verification [Calcagno et al. 2006; Berdine et al. 2007; Yang et al. 2008], we were frustrated not only by the issue of scaling in terms of LOC, but even more by the 1Thedatastructureverificationproblemisbroaderandcanconcernmorethanshape,butwewill persistwiththeterm‘shapeanalysis’inthispaperforbackwardscompatibility. JournaloftheACM,Vol.V,No.N,May2011. 4 Compositional Shape Analysis by means of Bi-Abduction · amount of effort we had to put in before our analysis was run. We would have to write preconditions, or the verification analogue of a test harness, and this meant studyingaprogramfordaysorweeksbefore‘pushingthebutton’. Wespeakofour personal experience with SpaceInvader here, but believe that the same issue of ‘human time spent before pushing button’ arises as well when attempting to apply any other existing shape analysis tools to verification problems. The final problem is that shape analyses have been formulated as whole-program analyses, meaning that it is difficult to apply them to a program as it is being written, before there is a complete program to analyze; this limits their potential to be used during the program-development process. These‘problems’allmotivatethecentralquestionofthispaper,whichiswhether a compositional shape analysis can be formulated, which will help existing tech- niques be more easily applied to a greater variety of code.2 The term ‘compositionality’ is used in different ways by different people, so we should be precise about our usage. We first recall Frege’s original notion for lan- guagesemantics: asemanticdefinitionofalanguageiscompositionalifthemeaning of a composite expression is defined in terms of the meanings of its parts. So, we say that a program analysis is compositional if the analysis result of a composite program (or program fragment) is computed from the analysis results of its parts. Wecanunderstandthisdefinitionatthelevelofgranularityofproceduresorgroups of recursive procedures. The most important feature of this definition of compositionality is that it pre- supposes that you can do the analysis of a part of a program without knowing the complete program.3 If we can achieve compositionality, we are immediately in a position of being able to analyze incomplete programs. Further, compositional analysis, by its nature, easily yields an incremental algorithm. When an analysis is first run its results can be stored to disk. Then, if a procedure (or recursive procedure group) is changed, only it has to be re-analyzed; the old analysis results for independent procedures remain unchanged. Asecondfeatureofcompositionalityiswhatwetermgracefulimprecision. There is no single existing shape domain that has yet been proposed which is appropriate to all of the kinds of data structures found in a large program (such as Linux): any known shape domain will deliver uselessly imprecise results at some point, after which (in a whole program analysis) meaningful results cease to be obtained even for portions of code which could be well treated, were a suitable precondition known. However, if a compositional analysis is unable to get precise results for one procedure, due to limitations of its abstract domain, it can still obtain precise results for other procedures. So one could apply a compositional analysis partially, without waiting for the discoveryofthe‘magicalabstractdomain’thatcoversallstructuresinallthelarge 2Note that we are not claiming that compositionality will ‘solve’ the data structure verification problem. It can boost existing techniques, but is still limited by the limitations of the abstract domains in these techniques; e.g., it remains difficult to precisely and efficiently analyze graph structureswithsignificantinternalsharing. 3Thus, in contrast to the usage in some papers that have appeared in the literature, a whole- programanalysiswhich(say)usesproceduresummariestoreduceworkisnotnecessarilycompo- sitionalinthesenseweareusing(orinFrege’soriginalsense). JournaloftheACM,Vol.V,No.N,May2011. Compositional Shape Analysis by means of Bi-Abduction 5 · programs one might ever encounter. The human might then be brought into the loop by changing the domain, by supplying manual proofs for difficult parts of the code, etc. But, with compositionality, we are not prevented from getting started just because the magical domain doesn’t yet exist. Finally, compositional analyses are interesting for their potential to scale. With a compositional analysis it becomes relatively easy to get meaningful (if partial) results for large code bases, as long as the analyses of the program parts are not prohibitive. It is all well and good to wish for a compositional analysis with very many remarkableproperties,buthowmightwegoaboutobtainingone? Beforewesuggest our own approach, we must clarify what such an analysis should be aiming to do. 1.2 Compositionality, Overapproximation, Footprints In formulating the compositional analysis we take our lead from denotational se- mantics. For sequential programs, denotational semantics established that the meaning of a procedure can be taken to be a mathematical function from states to states which abstracts away from intermediate states of the code: e.g., a function of type ConcreteProcs =def States (States) →P where the states can include input parameters as well as return values. What we would like to do in a compositional analysis is to over-approximate such a function space (what the Cousots call a ‘relational’ analysis [Cousot and Cousot 2002]). If we have a set of abstract states AbstractStates which overapproximate the concrete states (so that one abstract state may correspond to several concrete), then a naive way of overapproximating ConcreteProcs would be to use the function type BadAbstractProcs =def AbstractStates (AbstractStates). →P This would be impractical because BadAbstractProcs is far too large, especially in the case of shape analysis when there are very many abstract states. Something similarlyunrealisticisobtainedifoneattemptstousethe‘mostgeneralclient’fora procedureasawaytogenerate‘proceduresummaries’,asthatinvolvesenumerating a great many abstract states. To be practical we need to abstract the procedures moredirectly,withoutusinga(total)functionontheentiretyoftheabstractstates, to get a more parsimonious abstraction. Insteadofanentirefunctiontable,wewilluseacollectionofHoaretriplesasour abstract domain. Although at first glance it looks like this choice could be as bad as BadAbstractProcs, it is actually possible to get very compact representations of procedure meanings. The key to this is the ‘principle of local reasoning [O’Hearn et al. 2001]’, which allows program specifications to concentrate on the footprint, the cells accessed by a procedure, and this allows for compact representations of procedure meanings . For example, a single Hoare triple the heap is an acyclic list rooted at x disposelist(x) the heap is empty { } { } is enough to specify a procedure to free all the elements in a linked list; a consid- erably smaller representation of the meaning than an element of BadAbstractProcs. JournaloftheACM,Vol.V,No.N,May2011. 6 Compositional Shape Analysis by means of Bi-Abduction · (It might seem at first that this spec is not enough, because it does not talk heaps bigger than the one containing only the list x, but an inference rule of separation logic, the frame rule, allows such specifications to be applied in wider contexts.) Inthisexamplespec, thepreconditiondescribesexactlythecellsaccessedbythe procedure (the footprint). This will be the aim of our compositional analysis: fol- lowing on from the local reasoning idea, the analysis will aim to discover pre/post specs that talk about the footprint of a procedure only. Because of computability reasons, we know that we cannot make an algorithm that computes static descrip- tionsoffootprintsperfectly,butwewillusethefootprintideaasaguide,toattempt to obtain compact over-approximations of procedure meanings. Is this wishful thinking again? It is all well and good to wish for the footprint, but (quite apart from computability considerations) what might be an algorithmic technique to attempt to approximate it? Our answer is abduction, or rather a variant on the notion of abduction, and a program analysis algorithm which uses it in a new way. 1.3 Approach and Contributions The basic idea of how our method works is this. We begin by trying to prove a program (either manually or automatically). During the proof attempt we might find that we do not have a strong enough precondition to perform an operation – a procedure call, or a dereferencing. For example: we might need to know that a pointerisallocated,notdangling,beforeweattempttofreeit;or,wemightneedto know that a variable points to an acyclic linked list, before we attempt to traverse it. We then perform abductive inference to infer what is missing, and hypothesize thatthisispartofthepreconditionthatyouneedtodescribethememorythatthe program uses. We abduce preconditions describing allocatedness of cells, or even entire linked lists, from the free operation or the code in a traversal procedure. Infact,totreatprocedurecallsproperlywewilldealwithamoregeneralproblem, which we call bi-abduction, that infers ‘frames’ describing extra, unneeded portions of state (those cells that automatically remain unchanged) as well as the needed, missing portions (the ‘anti-frames’). Wemaketwospecifictechnicalcontributionswhichgiveusawaytoleveragethe above ideas in an automated tool: (i) we define an abductive proof procedure for separatedheapabstractions,certainrestrictedseparationlogicformulaewhichhave been used previously in automatic program analysis [Berdine et al. 2005b; Diste- fano et al. 2006]; (ii) we present a new heuristic algorithm, PreGen, which uses bi-abduction to guide search for preconditions. After precondition generation, we use an existing forwards program analysis algorithm, PostGen, to generate post- conditions (and to remove preconditions erroneously hypothesized by our heuristic search). The overall result is a compositional algorithm which finds pre/post specs approximating a procedure’s memory usage, without knowledge or even existence of the procedure’s calling context within a larger program. Although these are new specific technical contributions of the paper, the more significant contribution concerns how these ideas can be used together to increase automation in program verification. We have implemented our analysis algorithm in prototype tool, abductor. We have done a case study on a number of small programs to examine the quality of synthesized specifications. To probe implica- JournaloftheACM,Vol.V,No.N,May2011. Compositional Shape Analysis by means of Bi-Abduction 7 · tions for scalability of automatic program verification techniques we have also run abductor on larger code-bases and open-source projects. The results we obtain therearepartial(weareunabletoproveanythingaboutsomeprocedures),butthe significant point is that we are able to apply the analysis immediately, and get the partial information in the form of specs of some procedures without going through the weeks or months of prep work that was necessary previously. The larger code bases include a number of open-source projects in the hundreds of thousands of LOC, and one of over three million LOC. 2. PRELIMINARY CONCEPTS AND EXAMPLES Thepresentationinthepaperwillconsistofagradualmovementfromlogictowards program analysis. As we go along we will use particular programs, and speak aboutprogramproofsoranalysisinasemi-formalway,asameanstomotivateand illustrate our techniques. 2.1 Abductive Inference In standard logic, abduction can be set up as follows. Given: assumption A and goal G. To find: ‘missing’ assumptions M making the entailment A M G ∧ ￿ true. Constraints are often placed on what counts as a solution: that it be consistent, thatitbeexpressedusingarestrictedcollectionof‘abducible’facts,andsometimes that it be minimal in some sense. For example, in artificial intelligence it is often required that M be a conjunction of literals, rather than a general logical formula, thus ruling out the trivial M =A G solution. Minimality requirements rule out ⇒ another trivial solution, M = G. In any case, the intuition of abduction is that, ideally, M should contain ‘just enough’ information to conclude G, and even when thisidealcannotbereachedperfectlythebasicintuitioncanserveasaguideinthe search for solutions. In this paper we will be solving a similar problem, but for separation logic [Reynolds ; Ishtiaq and O’Hearn 2001] rather than classical logic. Given: assumption A and goal G. To find: ‘missing’ assumptions M making the entailment A M G ∗ ￿ true. Here,formulaedescribesetsofstates,andtheseparatingconjunctionA M istrue ∗ of a memory state just if A and M are true for disjoint partitions of the state: in words, A ‘and separately’ M. (The formal semantics of our separation logic formulae will be given in Section 3.1.2.) In separation logic, the abduction question takes on a spatial connotation: In A M G we think of M as describing a missing portion of memory, which is in ∗ ￿ JournaloftheACM,Vol.V,No.N,May2011. 8 Compositional Shape Analysis by means of Bi-Abduction · G but not in A. As in classical logic, there are immediate solutions to the question if expressive-enough logical machinery is present, such as by taking M to be the separatingimplicationformulaA G. Motivatedbyprogramanalysis,wewilllater −∗ constrain our solutions to be selected from certain special formulae called symbolic heaps, which will have the effect of ruling out such immediate solutions. 2.2 Generating Preconditions using Abduction Suppose that during an attempted program verification we have an assertion A at a call site for a procedure, and the procedure has a precondition G. For example, Procedure precondition: G =def list(x) list(y), ∗ Assertion at call site: A =def x nil ￿→ Here the precondition says that x and y point to acyclic linked lists occupying separate memory, while the assertion A says that x is a pointer variable containing nil (so a list of length 1). The difficulty we face in our attempted program proof is that the assertion A does not imply G; the call site and given precondition do not match up. One thing we can do is to give up on our verification, or our program analysis, at this point. But we might also realize ifonlywehadtheassertionlist(y)aswell,separatelyconjoined,thenwe would be able to meet the precondition. The informal inference step expressed here is abductive in nature: it is about inferring an hypothesis concerning what is missing. Formally, it involves solving a question of the form A ?? G. ∗ ￿ We can see the relevance of this question more clearly using a specific program. Suppose we are given a pre/post spec of a procedure foo(x,y). This spec might havebeencomputedpreviouslyinanautomaticprogramanalysis(wherethejargon ‘proceduresummary’issometimesusedforthespec),oritmighthavebeensupplied manually by a user. The list() predicate describes acyclic, nil-terminated singly- · linked lists. We have an enclosing procedure p(y) which calls foo as follows. 0 struct node {struct node* tl; }; 1 struct node* p(struct node *y) { // Inferred Pre: list(y) 2 struct node *x; 3 x=malloc(sizeof(struct node)); x->tail = 0; 4 foo(x,y); // Obtained Post: list(x) 5 return(x); 6 } // Inferred Post: list(ret) 7 8 void foo(struct node *x,struct node *y){//SUMMARY ONLY 9 // Given Pre: list(x) * list(y) 10 } // Given Post: list(x) JournaloftheACM,Vol.V,No.N,May2011. Compositional Shape Analysis by means of Bi-Abduction 9 · Here is how we can synthesize the pre and post described at lines 1 and 6. We begin by executing p() with starting symbolic heap emp, an assertion describing the empty memory. Just after line 3 we obtain the assertion A = x nil which ￿→ saysthatxisanallocatedcellpointingtonil4,andforthefollowingprocedurecall foo(x,y) we ask the abduction question x nil ?? list(x) list(y). ￿→ ∗ ￿ ∗ Asensibleansweris?? = list(y), soweinferthatweshouldhavestartedexecution with list(y) rather than emp, and record list(y) as a missing precondition. We pretend that the analysis of the call at line 4 was successful, and continue the analysisofp()withthepostconditionlist(x)offoo(x,y). Attheendofprocedure p() we obtain list(ret) as the computed post, where ret is the value returned by the procedure. Notice that the specification synthesized for p() is not at all random: the pre- condition describes the set of states on which the procedure can be safely run, presuming the given spec of foo(). 2.3 Bi-Abduction Abduction gives us a way to synthesize missing portions of state. We also have to synthesize additional, leftover portions of state (the frame) by solving a more general problem which we term bi-abduction: A ?anti-frame G ?frame. ∗ ￿ ∗ Weillustratetheuseofbi-abductionwiththefollowingvariationontheexample above, using the same procedure summary as before for foo(). 1 struct node* q(struct node *y) { // Inferred Pre: list(y) 2 struct node *x, *z; 3 x=malloc(sizeof(struct node)); x->tail=0; 4 z=malloc(sizeof(struct node)); z->tail=0; 5 // Abduced: list(y), Framed: z|->0 6 foo(x,y); // Obtained Post: list(x)*z|->0 7 // Abduced:emp, Framed: emp 8 foo(x,z); // Obtained Post: list(x) 9 return(x); 10 } // Inferred Post: list(ret) This time we infer anti-frame list(y) as before, but using bi-abduction we also infer z nil as the frame axiom that won’t be needed by procedure call at line 6. That ￿→ is, we obtain a solution to the bi-abduction question x nil z nil ?anti-frame list(x) list(y) ?frame ￿→ ∗ ￿→ ∗ ￿ ∗ ∗ where ?anti-frame = list(y), ?frame = z nil. We tack the frame on to the post- ￿→ condition list(x) obtained from the procedure summary, continue execution at line 7, and this eventually gives us the indicated pre/post pair at lines 1 and 10. 4Forsimplicity,inthisexamplewehaveignoredthepossibilitythatmalloc()mightfail(returning 0);wewilltreatthefailurecaselater(seeSection4.1). JournaloftheACM,Vol.V,No.N,May2011. 10 Compositional Shape Analysis by means of Bi-Abduction · Again, the inferred pre/post spec talks about only those cells that the procedure accesses. Such ‘small specifications’ are useful to aim for when synthesizing pre- and postconditions, because (1) shape domains usually have an enormous number of states that might be used and (2) ‘small specifications’ describe more general factsaboutproceduresthan‘bigspecifications’, sothattheyleadtoamoreprecise analysis of callers of those procedures. Themoregeneralpointwewishtomakeisthatbi-abductiongivesusaninference technique to realize the principle of local reasoning stated earlier. Synthesis of frames allows us to use small specifications of memory portions by slotting them into larger states found at call sites, whereas abduction of anti-frames helps us to find the small specs. 2.4 Abstraction and Loops Consider the simple program for freeing the elements of an acyclic linked list. // start state: x=X /\ emp // Inferred pre: list(x) 1 void free_list(struct node *x) { 2 while (x!=0) { 3 t=x; 4 x=x->tl; 5 free(t); 6 } If we start symbolically executing the program from a starting state x=X emp ∧ then we will discover at line 4 that we cannot proceed without the assertion x X ￿ ￿→ that x is allocated, for some X . It is convenient to express this fact using the ￿ additional variable X instead of x: the variable X does not appear in the program andwillnotbealtered,wherexwilleventuallybealtered,soitiseasiertouseX to talkaboutpre-states. Sowecouldupdateourpreconditionsothatitchangesfrom x=X emp to become to be x=X X X , and this gives us enough information ￿ ∧ ∧ ￿→ to avoid memory faulting on the first iteration of the loop. Then,ontheseconditerationwerunintothesameproblemagain. Letusassume thatourprogramanalysistechniqueissmartenoughtoguessthatx=X (X X ￿ ∧ ￿→ ∗ X X ), for another new variable X , rules out the memory faulting in either of ￿ ￿￿ ￿￿ ￿→ the first or the second iteration of the loop. If we continue in this way, we get ever longer formulae to cover successive iterates x=X X X ￿ ∧ ￿→ x=X (X X X X ) ￿ ￿ ￿￿ ∧ ￿→ ∗ ￿→ x=X (X X X X X X ) ￿ ￿ ￿￿ ￿￿ ￿￿￿ ∧ ￿→ ∗ ￿→ ∗ ￿→ . . . and if we do not do something we will obtain an infinite regress. We can interrupt this regress using abstraction. At the second step we can simplify our assertion by using the operation replace x=X X X X X with x=X ls(X,X ) ￿ ￿ ￿￿ ￿￿ ∧ ￿→ ∗ ￿→ ∧ JournaloftheACM,Vol.V,No.N,May2011.

Description:
tics of Programming Languages—Denotational Semantics; Program . be useful in program understanding or as a helpful guide during interactive proof Compositionality gives a easy and natural way to exploit parallelism in . sees this idiom, for example in the relation between the Linux kernel and.
See more

The list of books you might like

Most books are stored in the elastic cloud where traffic is expensive. For this reason, we have a limit on daily download.