Separation Logic for a Higher-Order Typed Language

[Extended Abstract]

Neelakantan Krishnaswami John Reynolds Jonathan Aldrich Carnegie Mellon University Carnegie Mellon University Carnegie Mellon University 5000 Forbes Avenue 5000 Forbes Avenue 5000 Forbes Avenue Pittsburgh, PA 15213 Pittsburgh, PA 15213 Pittsburgh, PA 15213 [email protected] [email protected] [email protected]

ABSTRACT Separation logic, originally developed by John Reynolds Separation logic is an extension of Hoare logic which per- and Peter O’Hearn [18, 10, 8], and elaborated by many mits reasoning about low-level imperative programs that use others, is a powerful extension of Hoare logic for reasoning shared mutable heap structure. In this work, we create an about pointer programs. To handle the difficulties described extension of separation logic that permits effective, modu- above, separation logic extends the assertion language of lar reasoning about typed, higher-order functional programs Hoare logic with spatial connectives. They are spatial in that use aliased mutable heap data, including pointers to the sense that they permit formulas to range over just part code. of the heap: a spatial proposition p ∗ q, written using the “separating conjunction”, holds when p holds for one part of the heap, and q holds for the other part of it. Thus, aliasing Categories and Subject Descriptors between p and q is implicitly forbidden, removing the need D.3.0 [Programming Languages]: General; F.3.1 [Logic to write tedious and extensive noninterference conditions. and Meaning of Programs]: Specifying and Verifying Separation further enables local reasoning about the heap: and Reasoning About Programs If one command in a program does its job in a heap frag- ment described by a proposition p, and another does its job in a fragment described by q, then we can safely combine General Terms the commands to work together in a heap described by p ∗ q Separation Logic — the separating conjunction’s disjointness property means that the two subroutines cannot interfere with each other. However, most of the work on separation logic has fo- Keywords cused on low-level languages, which are strictly first-order Separation logic, specification logic, imperative, functional, and where features like the precise layout of data in memory aliasing, monads, ML, call-by-value and identity of pointers as integers are visible. In this work, we define a specification logic for a a high- level language: a monadic lambda calculus in which pointers 1. INTRODUCTION are a separate data type. Pointers may contain values of any Traditionally, pointer programs – programs which make type, including code (denoted by closures), such as functions use of aliased, mutable data values – have been difficult to and frozen monadic computations. Thus, our programming analyze, for two reasons. First, aliasing allows an assign- language resembles a subset of ML, except for the use of ment to a pointer to nonlocally affect other variables that monadic form to make effects and their order of execution contain the same pointer. This requires specifications to more explicit. Our program logic uses separation logic as the explicitly enumerate all the possible interference patterns essential mechanism for reasoning about imperative compu- between mutable variables and fields – and the number of tations, and simultaneously permits us to use the equational possible interference clauses can rise quadratically with the theory of the lambda calculus to reason about the functional number of such objects in a program. Second, the heap is a aspect of programs. global data structure, and changes to it are visible to every In Section 2, we give the static and dynamic semantics part of a program, greatly complicating efforts at modular of our language, and then in Section 3 define an assertion reasoning. language with the separating conjunction and implication in it and give its semantics. Finally, in Section 4 we define a notion of Hoare triple for our language, and then build a specification logic on top of that, which uses triples (contain- Permission to make digital or hard copies of all or part of this work for ing separation logic formulas) as its atomic formulas. This personal or classroom use is granted without fee provided that copies are gives us a two-level logic in which we can relatively easily 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 write program specifications. republish, to post on servers or to redistribute to lists, requires prior specific permission and/or a fee. 2. THE MONADIC LANGUAGE SPACE 2006 Charlestown, SC USA Copyright 200X ACM X-XXXXX-XX-X/XX/XX ...$5.00. The programming language we work with is a monadic call-by-value lambda calculus. Following Davies and Pfen- The decision to explicitly model what would happen with ning [7], we stratify the language into two syntactic cate- dangling pointers ends up substantially simplifying the se- gories, expressions and computations, which are described mantics of the new connectives of the assertion language in Figure 1. Expressions are the purely functional fragment of separation logic, as we will see in the next two sections. of the language, where evaluation always terminates and Informally, we use separation logic to reason about heap corresponds to the beta-rule of the lambda calculus. fragments, and the abort state lets the reduction relation We type expressions using the typing judgement Γ ` e : τ, “tell us” when a partial heap did not contain enough data described in Figure 2. Expressions include the usual in- for evaluation to proceed. troduction and elimination forms for sum, product, and Also, one standard choice still worth drawing attention types. Additionally, we have reference types and to is that dynamic allocation via newτ v is nondeterministic. monadic types. The evaluation rule for allocation promises to return a new The type ref τ classifies references that point to a value pointer not in the domain of the heap, but does not say what of type τ. Departing slightly from the usual presentation, value that pointer will take on. This is important, because it pointer values take on the form lτ – that is, a pointer is is necessary in order for the frame property discussed below tagged with the type of the value it points to. This simplifies to hold. the semantics of the separation logic assertions, which will The metatheory of this language is fairly standard. The be described in the next section. A computation that only wrinkle is that we have to prove soundness twice, one produces a value of type τ, can be suspended and turned for each of the two judgements for expressions and compu- into a first-class value [c] of the monadic type τ. A value of tations. We have the usual proof of type soundness for the monadic type is a frozen computation and does not evaluate expression language via the progress and type preservation any further, which keeps side-effects from infecting the pure lemmas. part of the language. Neither reference values nor frozen computations have any Proposition 1 (Expression Progress). If  ` e : τ, elimination rules in the expression language, which ensures then either e is a value or there exists an e0 such that e ; e0. that no expression can have a side-effect. We make this syn- tactically apparent in the dynamic semantics of expressions, Proposition 2 (Expression Subject Reduction). 0 0 given in Figure 5, by simply leaving out the store altogether If  ` e : τ and e ; e , then  ` e : τ. from its reduction relation (e ; e0). We have a judgement Γ ` c ÷ τ, given in Figure 3, which These are proved by structural induction on typing deriva- characterizes well-formed computations. A computation is tions and evaluation derivations, respectively. either an expression (which becomes a computation with- Additionally, we also show that expressions always reduce ∗ out side-effects); reading (!e), writing (e := e0), or creating to a value. We take e ; v to be the transitive closure of (newτ e) a reference; or sequencing two computations via the one-step evaluation relation. monadic sequencing with the form letv x = e in c.1 Se- quencing takes an expression of type τ, evaluates it to a Proposition 3 (Termination). If  ` e : τ, then there ∗ value [c0], and then executes c0 and passes the result (a value exists a v such that e ; v. plus side-effects) to c. As an example, consider the following program, which is We prove this using a straightforward logical relations ar- a computation of type nat. gument [17], though it also follows immediately from the fact that the simply typed lambda calculus is strongly nor- letv r = [new 5] in malizing. letv dummy = [r := 17] in Once we have soundness for our expression language, we letv n = [!r] in can use it to prove soundness for computation terms. (n - 5) Here, we have a computation which creates a new pointer, Proposition 4 (Partial Computation Progress). If ` c÷τ and σ ok, then either c is a value v, or there exists pointing to 5, and then updates it to point to 17, and then  a c0 and σ0 such that hc; σi ; hc0; σ0i, or hc; σi ; abort. dereferences the pointer and returns the dereferenced value minus 5, for a final result of 12. We freeze basic commands Proposition 5 (Computation Subject Reduction). and turn them into monadic values when we put them in If ` c ÷ τ and σ ok and hc; σi ; hc0; σ0i, then ` c0 ÷ τ brackets (e.g., [!r]), and then we can run them in the se-   and σ0ok. quential order using the monadic let-binding construct. We also have a judgement σ ok in Figure 4 to characterize The progress lemma includes the possibility of the compu- well-typed heaps. Unlike the usual presentation of adding tation aborting if it tries to access a dangling pointer. We references to the lambda calculus [13], this judgement ex- can restore the full safety of the conventional type-safety plicitly does not check whether or not there are dangling theorem if we introduce the notion of a closed state . We pointers in the heap – it permits dangling pointers as long say a state hc; σi is closed if all of the pointers in c and as the pointers are themselves well-typed. in each of the values in the range of σ are members of the The reduction relation for commands, hc; σi ; hc0; σi, is domain of σ. given in Figure 6 and takes a program state, i.e. a pair of a computation and a heap, into another program state. If Proposition 6 (Full Computation Progress). If  ` evaluation would read or write a pointer not in the heap, c ÷ τ, σ ok, and hc; σi is closed, then either c is a value v, then we transition into the abort state he; σi ; abort. or there exists a c0 and σ0 such that hc; σi ; hc0; σ0i and 1This is equivalent to the bind operation in Haskell. hc0; σ0i is closed. Types τ ::= 1 | τ × τ 0 | τ + τ 0 | τ → τ 0 | ref τ | τ

Γ ` e : τ Expressions e ::= () | (e1, e2) | π1e | π2e | inl e | inr e | case(e, x0. e0, x00. e00) x : τ ∈ Γ | λx : τ. e | x | e1 e2 | lτ | [c] Γ ` x : τ Γ ` () : 1 Computations c ::= e | letv x = e in c | !e | e := e0 Γ ` e : τ1 Γ ` e : τ2 | newτ e Γ ` inl e : τ1 + τ2 Γ ` inr e : τ1 + τ2 Values v ::= () | (v1, v2) | inl e | inr e Γ ` e1 : τ1 Γ ` e2 : τ2 Γ ` e : τ1 × τ2 | λx : τ. e | lτ | [c] Γ ` (e1, e2): τ1 × τ2 Γ ` πie : τi Contexts Γ ::= | Γ, x : τ  0 Γ, x : τ ` e : τ Γ ` e : τ 0 → τ Γ ` e0 : τ 0 Heaps σ ::=  | σ, lτ : v Γ ` λx : τ 0. e : τ 0 → τ Γ ` e e0 : τ

Γ ` c ÷ τ Figure 1: The Basic Syntactic Categories Γ ` lτ : ref τ Γ ` [c]: τ

Although we have no explicit operator for term-level re- Γ, x1 : τ1 ` e1 : τ Γ ` e : τ1 + τ2 cursion, nontermination is possible in the computation lan- Γ, x2 : τ2 ` e2 : τ guage, because we have higher-order state – that is, pointers Γ ` case(e, x1. e1, x2. e2): τ to functions. We can code an imperative fixpoint if we up- date a function pointer so that a function body contains a pointer to itself. (This is Landin’s technique of “tying a knot in the heap” to construct a recursive function.) As a Figure 2: Static Semantics of Expressions concrete example, consider the following computation: letv r = [ref (fun x:unit. [x])] in letv f = [fun y:unit. [letv recur = [!r] in recur ()]] in letv dummy = [r := f] in letv looper = f() in Γ ` c ÷ τ (unreached code) Γ ` e : τ 0 Γ, x : τ 0 ` c ÷ τ First, we create a function pointer r initially containing a Γ ` e : τ pointer to some dummy value of type 1 → 1. Next, we Γ ` e ÷ τ Γ ` letv x = e in c ÷ τ create a function f, whose body is a frozen computation that Γ ` e : ref τ Γ ` e : τ dereferences r and invokes that function. Third, we update Γ `!e ÷ τ Γ ` new e ÷ ref τ r to point to f. Finally, when we call f, r is dereferenced τ and binds its contents – f itself – to the variable recur, and Γ ` e1 : ref τ Γ ` e2 : τ finally calls f. This gives us an infinite loop, and shows Γ ` e1 := e2 ÷ 1 that we have introduced nontermination into our monadic language. Finally, we can devise a big step semantics for both the ex- pression and computation language, and prove their agree- Figure 3: Static Semantics of Computations ment with the small-step semantics. We will write e ⇓ v for expression evaluation, and he; σi ⇓ hv0; σ0i or he; σi ⇓ abort for the big-step computation evaluation. These judge- ments are primarily a technical convenience, and for space reasons we do not give them; the rules are the obvious ones. σ ok 3. THE ASSERTION LANGUAGE AND ITS

SEMANTICS σ ok  ` v : τ lτ 6∈ dom(σ) The assertion language in this paper, described in Figure  ok σ, lτ : v ok 8, is a multi-sorted first order logic with equality, extended with the additional spatial connectives ∗ and −∗. The sorts of the language are drawn form the types of the program- ming language, and we define a judgement Γ ` p : assert Figure 4: Heap Well-Typing which ensures that any programming language terms that 0 appear in an assertion are well-typed. The equality e =τ e e ; e0

0 0 e1 ; e1 e2 ; e2 0 0 e1 e2 ; e1 e2 v e2 ; v e2

0 0 e1 ; e1 e2 ; e2 0 0 (e1, e2) ; (e1, e2) (v, e2) ; (v, e2) hc; σi ; hc0; σ0i

0 0 e ; e e ; e hc; σi ; abort inl e ; inl e0 inr e ; inr e0 e ; e0 (λx : τ. e)v ; [v/x]e he; σi ; he0; σi

e ; e0 Figure 5: Small-step Dynamic Semantics of Expres- hletv x = e in c; σi ; hletv x = e0 in c; σi sions 0 0 hc1; σi ; hc1; σ i 0 0 hletv x = [c1] in c; σi ; hletv x = [c ] in c; σ i 0 1 and the points-to assertion e ,→τ e are both indexed by types, but we will normally elide this annotation. Finally, hletv x = [v] in c; σi ; h[v/x]c; σi we lift substitution of values for variables to assertions in the completely predictable way. hc1; σi ; abort The semantics of a well-formed assertion p (that is, Γ ` hletv x = [c ] in c; σi ; abort p : assert) is given with a forcing relation of the form 1 e ; e0 0 γ, σ ok |= p hnewτ e; σi ; hnewτ e ; σi

0 Here γ is an environment, a function mapping the free lτ 6∈ dom(σ) σ = σ, lτ : v variables in Γ to closed values of the appropriate type. We hnew v; σi ; hl ; σ0i will write γ(x) to apply the function to a variable, and we τ τ will abuse notation and write γ(e) to represent the appli- e ; e0 cation of an appropriately lifted function that substitutes h!e; σi ; h!e0; σi values for the free variables of an expression e, consistently with γ. Likewise, we will write γ(c), γ(p) and so on to for lτ : v ∈ σ liftings to computations, assertions, and so on. h!l ; σi ; hv; σi We write σ ok to denote a derivation that a heap σ is τ well-typed. Using a derivation differs from the traditional lτ 6∈ dom(σ) presentation of separation logic, where the heap itself models h!l ; σi ; abort a proposition. We make this choice in order to ensure that τ we only consider well-typed heaps. It also explains why our 0 e1 ; e1 heap well-typing judgement in the previous section does not 0 contain a closure condition that forbids dangling pointers: he1 := e2; σi ; he1 := e2; σi we want to be able to split and merge derivations in the e ; e0 same way that we can split and merge heaps.2 2 2 0 We use the following notation to represent this idea (taken hlτ := e2; σi ; hlτ := e2; σi from [8]): 0 lτ ∈ dom(σ) σ = [σ|lτ : v] 0 • σ#σ0 indicates that the domains of σ and σ0 are dis- hlτ := v; σi ; h(); σ i joint. lτ 6∈ dom(σ) 0 • σ·σ indicates the union of disjoint heaps, that is, when hlτ := v; σi ; abort σ#σ0 have disjoint domains, we take the concatenation of the two heaps. Figure 6: Dynamic Semantics of Computations • σ w σ0 indicates that σ is an extension of σ0; that is, σ contains all of the pointer/value pairs of σ0 and possibly some additional ones.

2The appropriate intuition is that the two rules for typing a heap give rise to a list datatype with a nil and a cons, and that lists form a monoid, which lets us use the monoidal resource semantics of BI [15]. 0 0 0 0 0 0 proach, and take only the monad laws as our equational p ::= e =τ e | e ,→τ e | p ∧ p | p ⊃ p | p ∗ p | p −∗p | > | ⊥ | p ∨ p0 | ∀x : τ. p | ∃x : τ. p theory of computations. These are the rules given for the judgement Γ ` c = c ÷ τ in Figure 9. (The monad laws are the natural transformations of a Kleisli triple in cat- egory theory [9], and are the commuting conversions in a Γ `: > : assert Γ `: ⊥ : assert proof-theoretic presentation of lax logic [1].) Verifying that the computation reduction rules for states agree with these 0 0 Γ ` e : τ Γ ` e : τ Γ ` e : ref τ Γ ` e : τ monad laws is again straightforward. It may be possible to 0 0 Γ ` e = e : assert Γ ` e ,→ e : assert give a richer notion of equality of computations employing more of the particular algebraic structure of heaps, e.g. [14], Γ ` p : assert Γ ` q : assert Op ∈ {∧, ⊃, ∨, ∗, −∗} but we have not yet investigated this possibility. 0 Γ ` p Op q : assert The connective e ,→τ e looks one deep into the heap. It is true exactly when the heap contains a pairing lτ : v, such Γ, x : τ ` p : assert Q ∈ ∀, ∃ 0 that e equals lτ and e = v. As noted above, our points-to Γ ` Qx : τ. p : assert connective is intuitionistic; it only asks whether there is at least a memory location e in the heap pointing to e0 – there Figure 7: Syntax of Separation Logic Assertions can be more cells. The separating conjunction p1 ∗ p2 holds whenever a heap typing σ ok can be split into two disjoint subheaps σ1 and Since every heap well-typing derivation σ ok identifies a σ2, in which p1 and p2 hold separately. For example, with 1 2 unique heap (up to permutation), we can overload our nota- this definition, the proposition lnat ,→ 0 ∗ lnat ,→ 5 holds of 1 2 tion and write (σ ok) # (σ0 ok) or (σ ok) · (σ0 ok) without any extension of the heap σ = lnat : 0, lnat : 5. confusion. We will also sometimes say that a proposition With this semantics, we can prove soundness for the logic. “holds in a heap”, with the understanding that we really We do this by defining the semantic consequence relation mean the derivation that proves the heap well-typed. p BΓ q to hold between well-formed formulas Γ ` p : assert We give the cases of the forcing relation in figure 7. This and Γ ` q : assert if and only if for all γ that are well- semantics satisfies the Kripke monotonicity condition, which typed environments under Γ, and for all heap typings σ ok, is that if γ, σ ok |= p and σ0 ok w σ ok, then γ, σ0 ok |= p. if γ, σ ok |= p holds then γ, σ ok |= q holds. This means that we have chosen to use the intuitionistic semantics of separation logic [8], in which if a proposition Proposition 7 (Assertion Soundness). The usual rules holds in a heap, it continues to hold in all extensions of of intuitionistic logic are sound for the semantic consequence that heap. There is no technical obstacle to using the classi- relation, along with the following rules: cal semantics; however, we choose this version of separation • ∗ is associative and commutative, with unit >. logic because our language does not contain a command for 3 0 de-allocating pointers. 0 0 0 • If p BΓ q, and Γ extends Γ, then p BΓ q. The equality connective e =τ e holds when e and e are equal. The notion of equality that we choose is beta-eta • ∗ supports weakening: p ∗ q BΓ p equality for the functional subset, and the monad laws for computations. For space reasons, we only give a subset of • The following inference rules hold: these rules in Figure 9. 0 0 p BΓ p q BΓ q Our choice raises a couple of interesting issues. First, 0 0 in the previous section, we gave an operational semantics, p ∗ q BΓ p ∗ q rather than a denotational semantics, for our language. This r p −∗q r0 p means that we have a relatively free choice for what we define r BΓ p −∗q BΓ BΓ 0 equality to mean, as long as we prove that evaluation of r ∗ p BΓ q r ∗ r BΓ q expressions preserve equality – that is, if Γ ` e1 = e2 : τ, 0 0 and e1 ; e1, then Γ ` e1 = e2 : τ. Verifying this is a straightforward induction on the reduction relation. 4. SPECIFICATION LOGIC Second, we have to consider what it means for two compu- With a semantics for the assertion language in hand, we 0 tations to be equal; that is, if we have the assertion [c] = [c ], now consider how to construct a specification language from 0 then we have to judge whether Γ ` [c] = [c ]: τ, and hence it. Our general approach closely mirrors specification logic 0 whether Γ ` c = c ÷ τ. To our knowledge, this question has [16] for Algol, in which Reynolds took a Hoare logic for not appeared in other presentations of separation logic, since commands and integrated it with a call-by-name functional for the most part they do not have heaps that contain code. programming language. Our language is call-by-value, but Obviously, we cannot give a full characterization of equality the critical property we retain is that the full beta rule is a of computations – it is because of the weakness of imperative valid notion of equality (intuitively, the monadic type dis- programs’ equational theory that we are trying to devise a cipline ensures that function application won’t change the separation logic at all. Instead, we take a conservative ap- side effects of an expression). To begin, we analyze Hoare triples and see what changes 3In a real implementation, memory will be collected using we will need to make. First, and most simply, a computation garbage collection. Giving a garbage-collection aware se- mantics for separation logic is quite subtle [6], and so we in our language will return a value in addition to having side ignore garbage collection in our operational semantics and effects. That is why the syntax for triples in our specification defer further consideration of this point for future work. language is of the form {p}c{x : τ. q} – the x is a binder Γ ` e = e0 : τ

Γ ` e : τ Refl Γ ` e = e : τ

0 0 γ, σ ok |= e = e iff  ` γ(e) = γ(e ): τ Γ ` e = e0 : τ Γ ` e0 = e00 : τ T rans Γ ` e = e00 : τ  ` γ(e) = lτ : ref τ and 0 0 γ, σ ok |= e ,→ e iff  ` γ(e ) = v : τ and Γ ` e0 = e : τ Sym lτ : v ∈ σ Γ ` e = e0 : τ

γ, σ ok |= p1 and 0 0 0 0 γ, σ ok |= p1 ∧ p2 iff Γ, x : τ ` e1 = e1 : τ Γ ` e2 = e2 : τ γ, σ ok |= p2 0 0 0 F unBeta Γ ` (λx : τ . e1)e2 = [e2/x]e1 : τ

γ, σ ok |= p or 0 0 γ, σ ok |= p ∨ p iff 1 Γ, x : τ ` ex = e x : τ 1 2 γ, σ ok |= p F unExt 2 Γ ` e = e0 : τ 0 → τ

for all σ0 ok w σ ok. 0 γ, σ ok |= p1 ⊃ p2 iff if γ, σ ok |= p1 0 0 Γ ` c = c ÷ τ then γ, σ ok |= p2 Γ ` c ÷ τ there exist σ1 ok, σ2 ok. Refl σ = σ1 · σ2 and σ1#σ2 and Γ ` c = c ÷ τ γ, σ ok |= p1 ∗ p2 iff γ, σ1 ok |= p1 and Γ ` c = c0 ÷ τ Γ ` c0 = c00 ÷ τ γ, σ2 ok |= p2 T rans Γ ` c = c00 ÷ τ

for all σ1 ok. Γ ` c0 = c ÷ τ γ, σ ok |= p1 −∗p2 iff if σ#σ1 and γ, σ1 ok |= p1 0 Sym then (γ, σ1 · σ) ok |= p2 Γ ` c = c ÷ τ

for all ` v : τ. Γ ` e = e0 : τ 0 γ, σ ok |= ∀x : τ. p iff  γ, σ ok |= p[v/x] Γ ` e = e0 ÷ τ

Γ ` c ÷ τ there exists ` v : τ. γ, σ ok |= ∃x : τ. p iff  γ, σ ok |= p[v/x] Γ ` c = letv x = [c] in x ÷ τ γ, σ ok |= > iff always y 6∈ FV(c00)Γ ` letv x = [letv y = e in c0] in c00 ÷ τ letv x = [letv y = e in c0] in c00 = γ, σ ok |= ⊥ iff never Γ ` letv y = e in letv x = c0 in c00 ÷ τ Γ ` letv x = [v] in c ÷ τ Figure 8: Semantics of Assertions Γ ` letv x = [v] in c = [v/x]c ÷ τ

Figure 9: Selected Rules of Typed Equality for Ex- pressions and Computations for the value the computation will return, and should not shadow any variables in p or c. [[S and S ]]γ = [[S ]]γ and [[S ]]γ Secondly, it’s not sufficient to give a semantics for triples 1 2 1 2 as a relation between states, because free variables in a [[S1 or S2]]γ = [[S1]]γ or [[S2]]γ higher-order program might be bound to functions or sus- pended computations, which both contain code. Consider [[S1 implies S2]]γ = if [[S1]]γ then [[S2]]γ the following small program: [[∀x : τ. S]]γ = ∀( ` v : τ). [[[v/x]S]]γ

[[∀x : τ. S]]γ = ∃( ` v : τ). [[[v/x]S]]γ {true} letv n = fact(k) in (k+1) * n Thus, we have turned triples into the atomic propositions {x:nat. x = (k+1)!} of yet another logic. This means that we have a two-level logic, in which we have propositions of separation logic ap- pearing in triples, and the triples themselves are proposi- tions in another logic. This permits us to characterize the Whether this triple is true for this program depends on behavior of free variables in a specification. For example, what value fact is bound to. So, we begin by giving the revisiting the factorial example, we might write: semantics of a triple as a function of its free variables. If Γ ` {p}c{x : τ. q} : spec, then we give meaning to the triple (forall m:nat. fact(m)<\x:nat. x = m!>) as a function of type-correct environments γ: implies ({true} letv n = fact(k) in (k+1) * n {x:nat. x = (k+1)!}) ∀σ ok. ∀σ0 ok. ∀v. if γ, σ ok |= p then This specification is substantially more satisfying than be- hγ(c); σi 6⇓ abort [[{p}c{x : τ. q}]]γ = fore, because we have a clear idea of what the fact function and is supposed to do. We can read this specification as saying, 0 (if hγ(c); σi ⇓ hv; σ i “If fact computes the factorial function, then the conse- 0 then γ, σ ok |= [v/x]q) quent will compute (k + 1)!.” However, we still have free variables in this spec, and we must ask under what circum- stances we can use such a specification – are there imple- The type of this semantic function is that it takes envi- mentations of fact or values of k for which the specification ronments to booleans; it is not a relation between heaps. will be falsified? Heap typings appear in the definition, but we universally The approach we will take towards answering this ques- quantify over all of them. Also, note that is a partial cor- tion is to come up with inference rules for deriving specifi- rectness criterion. Likewise, we give a semantics for triples cations which remain true in all type-correct environments. over suspended monadic computations as follows: Following Reynolds [16], we will call such specifications uni- versal. For a well-formed specification Γ ` S : spec, we say: ∀σ ok. ∀σ0 ok. ∀v.∀c. if γ, σ ok |= p S is universal iff ∀γ.[[S]]γ and  ` γ(e) = [c]: τ then In Figures 12 and 13, we give a collection of deduction [[hpiehx : τ. qi]]γ = hc; σi 6⇓ abort rules for inferring universal specifications. The rules are and written in a sequent style, but semantically a sequent of 0 (if hc; σi ⇓ hv; σ i the form Γ; ∆ ` S, where ∆ = S1,...Sn, is interpreted 0 then γ, σ ok |= [v/x]q) as the specification (S1 and ... and Sn) implies S with free variables in Γ.

This is essentially a duplicate of the previous semantic Proposition 8 (Soundness of Specification Logic). equation, but is needed for two reasons. First, a let-binding Every derivation Γ; ∆ ` S using the rules in Figures 12 and letv x = [c] in c0 in the monadic language will evaluate the 13 derives a universal specification. expression of monadic type [c] before substituting the value, so it is convenient to have a primitive triple that can be We prove this with an induction on the derivation. Most used directly with monadic expressions when giving an in- of the cases are routine, except for the base cases, the rule ference rule for sequencing. Secondly, all of the variables in Frame, and the Substitution rule. our monadic language are expression variables; there are no The base cases can all be proven with a straightforward variables that range over computations. appeal to the semantics, but are noteworthy because they Once we have these basic triples, we can compose the are all “small” or “tight”. In O’Hearn’s terminology [10], triples themselves with logical connectives to construct more they enable local reasoning because the preconditions and complex specifications, and inductively build up a meaning postconditions refer to no other pointers than the ones that for the composite formulas: are accessed. S ::= {p}c{x : τ. q} | hpiehx : τ. qi | S and S | S or S0 | S implies S0 | ∀x : τ. S | ∃x : τ. S Γ ` p : assert Γ ` c ÷ τ Γ, x : τ ` q : assert Γ ` {p}c{x : τ. q} : spec ∆ ::=  | ∆,S Γ ` p : assert Γ ` e : τ Γ, x : τ ` q : assert Figure 10: Syntax of Specifications Γ ` hpiehx : τ. qi : spec Γ ` S : spec Γ ` S0 : spec op ∈ {and, or, implies} To prove the Frame rule, we first show that the opera- Γ ` S op S0 : spec tional semantics validates the safety monotonicity and frame properties.[11] Informally, safety monotonicity is the prop- Γ, x : τ ` S : spec Q ∈ {∀, ∃} erty that if a particular program and heap do not evaluate Γ ` Qx : τ. S : spec to an abort, then that program will not abort with any ex- tension of the heap, and the frame property is the local Figure 11: Well-Formedness of Specifications reasoning property – a program will not modify any state outside of its footprint. The Substitution rule arises from the basic substitution principle that if Γ, x : τ 0 ` e : τ and Γ ` e0 : τ 0, then Γ ` [e0/x]e : τ, lifted first through the syntax of assertions and then lifted again to specifications, with a small extra bit of complexity arising from the use of environments in Γ; ∆ ` S the semantics. It is the combination of the frame rule and the substitution Γ ` newτ e ÷ ref τ New property that enables genuinely modular reasoning about Γ; ∆ ` {>}newτ e{x : ref τ. x ,→ e} programs. We can prove a client programs that use an imperative Γ `!e ÷ τ Γ ` e0 : τ 0 0 0 Deref module if we specify its interfaces in a hypothetical specifi- Γ; ∆ ` {e ,→τ e }!e{x : τ. e ,→τ e ∧ x = e } cation of the form Γ, x1 : τ1, . . . , xn : τn; ∆,Si ` Sc. Here, 00 we take Si to be the signature of the module, naming the Γ ` e := e ÷ 1 00 00 Assign data and operations in its interface with the variables. Si Γ; ∆ ` {e ,→ −}e := e {x : 1. e ,→ e } does not have to mention any of the client’s data – whenever Sc uses an operation from Si, it can use the Frame rule to Γ; ∆ ` hpiehx : τ. qi assert that its data is untouched. Γ, x : τ; ∆ ` {q}c{y : τ 0. r} x 6∈ FV(r) Then, we can derive a concrete implementation of that 0 Seq module, if we prove a program with a specification Γ; ∆ ` Γ; ∆ ` {p}letv x = e in c{y : τ . r} ∃x : τ ,..., ∃x : τ .S , using the local reasoning property 1 1 n n i Γ ` e : τ to consider only the module’s data. Then, we can easily P ure Γ; ∆ ` {>}e{x : τ. x = e} compose the pieces using the existential elimination rule. The existential elimination rule is only provable because Γ; ∆ ` {p}c{x : τ. q} the programming language is consistent with the beta-reduction Monad rule of the lambda calculus, and so permits us to freely sub- Γ; ∆ ` hpi[c]hx : τ. qi stitute expressions for variables without changing the mean- Γ; ∆ ` {p}c0{x : τ. q} Γ ` c = c0 ÷ τ ing of a program. CompEq A crucial part of the success of this methodology arises Γ; ∆ ` {p}c{x : τ. q} from the clear separation of the language into pure and Γ; ∆ ` hpie0hx : τ. qi Γ ` e = e0 : τ imperative parts via a monad. The first benefit is that it MonadEq greatly simplifies the assertion language: there is no need Γ; ∆ ` hpiehx : τ. qi for definedness predicates to assert that a term terminates, nor for nested specifications within assertions, to cope with Γ; ∆ ` {p}c{x : τ. q} Γ ` r : assert F rame1 possibly effectful expressions within an assertion. The sec- Γ; ∆ ` {p ∗ r}c{x : τ. q ∗ r} ond benefit is that it permits the use of an extremely gen- eral substitution principle, which allows a simple method of Γ; ∆ ` hpiehx : τ. qi Γ ` r : assert F rame2 combining specifications to work correctly. Γ; ∆ ` hp ∗ riehx : τ. q ∗ ri

0 0 0 0 p Γ p Γ; ∆ ` {p }c{x : τ. q } q Γ,x:τ q 5. RELATED AND FUTURE WORK B B Consequence Γ; ∆ ` {p}c{x : τ. q} In spirit, this work is a direct descendent of Reynolds’ work on specification logic for Idealized Algol [16]. It was the two observations that the full beta-rule is a valid rea- soning principle in Idealized Algol, and that Algol’s com- Figure 12: Universal Specification Inference Rules mand type completely separates the imperative and func- tional parts of the language [19], that spawned the hypoth- esis that the same idea could apply to a monadic language. This combination turned out to be especially pleasant to work with, because the decision to remove assignable vari- ables and put all aliasing into the heap, meant that we could simply dispense with the complex interference conditions of specification logic, which described whether variables in two expressions might interfere with one another. Instead, we could use separation logic to reason about aliasing. Γ; ∆ ` S Birkedal, Torp-Smith and Yang [5] have done work on a version of separation logic for a restricted variant of Al- Hyp gol: like us, they remove variable assignment and put all Γ; ∆,S ` S aliasing into the heap. The heap, as in Algol but in the Γ; ∆ ` S0 Γ; ∆,S0 ` S current work, is merely a first-order map of integers. This Cut system doesn’t distinguish the type system from the specifi- Γ; ∆ ` S cation language: command types can contain preconditions Γ, x : τ; ∆ ` S Γ ` e : τ and postconditions written in separation logic in a fashion Substitute similar to refinement types. However, they support a very Γ; [e/x]∆ ` [e/x]S powerful kind of hypothetical frame rule in their language. Γ; ∆ ` S Γ; ∆ ` S0 Parkinson [12] has built a version of separation logic for a 0 AndIntro programming language embodying a core subset of Java. As Γ; ∆ ` S and S in this work, he used an intuitionistic variant of separation logic. However, the the lack of pure higher-order functions Γ; ∆ ` S1 and S2 AndElim1 sharply limits the program expressions that can appear in Γ; ∆ ` S1 assertions. He also introduces the notion of an abstract pred- icate, in which a kind of assertion variable is used to conceal Γ; ∆ ` S1 and S2 AndElim2 the concrete predicate used to implement an object’s state. Γ; ∆ ` S 2 Our version of separation logic supports reasoning with procedures, but it does not support information hiding in Γ; ∆ ` S1 Γ ` S2 : spec OrIntro1 procedures, either in the sense of having a hypothetical Γ; ∆ ` S or S 1 2 frame rule in the sense of O’Hearn, Yang and Reynolds [11], or as with Parkinson’s abstract predicates. Instead of di- Γ; ∆ ` S2 Γ ` S1 : spec OrIntro2 rectly adding features to address this deficiency, we are in- Γ; ∆ ` S or S 1 2 stead considering moving to a higher-order variant of separa-

Γ; ∆ ` S1 or S2 Γ; ∆,S1 ` S Γ; ∆,S2 ` S tion logic, such as Biering, Birkedal and Torp-Smith propose OrElim Γ; ∆ ` S in [3]. Then, modules and their clients could communicate through existentially quantified assertions, as proposed in Γ; ∆,S0 ` S [4]. The latter paper also develops a specification logic using ImpIntro universal specifications (which they call valid) for a simple Γ; ∆ ` S0 implies S first-order programming language. Γ; ∆ ` S0 implies S Γ; ∆ ` S0 Additionally, it would be interesting to add polymorphism ImpElim and existential types to the underlying programming lan- Γ; ∆ ` S guage – the combination of existential types concealing the Γ, x : τ; ∆ ` S x 6∈ FV(∆) exact term representations of an ADT and existential sep- UnivIntro aration predicates concealing the exact heap layout could Γ; ∆ ` ∀x : τ. S be very illuminating about the nature of encapsulation. We Γ; ∆ ` ∀x : τ. S also plan on adding recursive types and term-level recursion UnivElim operators to the programming language, and to add recur- Γ, x : τ; ∆ ` S sively defined assertions to the assertion language. Γ; ∆ ` [e/x]S Γ ` e : τ Finally, Berger, Honda and Yoshida recently described a ExistIntro new logic for analysing aliasing in imperative functional pro- Γ; ∆ ` ∃x : τ. S grams [2]. Like separation logic, they added connectives to a first-order logic, but their new additions are modal operators Γ; ∆ ` ∃x : τ. S0 Γ, x : τ; ∆,S0 ` S ExistElim that can be interpreted as quantification over the possible Γ; ∆ ` S content of a pointer. Also, they work in a setting where effects are not confined to a monad, and their operators re- Figure 13: Universal Specifications, Continued quire explicitly require tracking the write set of a procedure. They noted that one of the difficulties that hindered com- parison with separation logic is that the languages the two approaches targetted were so different; we hope the current work will enable a better point of comparison.

6. ACKNOWLEDGMENTS I would like to thank John Reynolds and Jonathan Aldrich for their advice, encouragement, and patience. This work [15] D. J. Pym, P. W. O’Hearn, and H. Yang. Possible was supported in part by NASA cooperative agreements worlds and resources: the semantics of bi. Theoretical NCC-2-1298 and NNA05CS30A, and National Science Foun- , 315(1):257–305, 2004. dation Grants CCR-0204242 and CCR-0204047. [16] J. C. Reynolds. The Craft of Programming. Prentice-Hall International, London, 1981. [17] J. C. Reynolds. Types, abstraction and parametric 7. REFERENCES polymorphism. In R. E. A. Mason, editor, Information [1] P. Benton, G. Bierman, and V. D. Paiva. Processing 83, pages 513–523, Amsterdam, 1983. Computational types from a logical perspective. Elsevier Science Publishers B. V. (North-Holland). Journal of Functional Programming, 8(2):177–193, [18] J. C. Reynolds. Separation logic: A logic for shared March 1998. mutable data structures. In Proceedings Seventeenth [2] M. Berger, K. Honda, and N. Yoshida. A logical Annual IEEE Symposium on Logic in Computer analysis of aliasing in imperative higher-order Science, pages 55–74, Los Alamitos, California, 2002. functions. In Proceedings of the Tenth ACM SIGPLAN IEEE Computer Society. International Conference on Functional Programming, [19] S. Weeks and M. Felleisen. On the orthogonality of pages 280–293. ACM Press, September 2005. assignments and procedures in Algol. In Conference [3] B. Biering, L. Birkedal, and N. Torp-Smith. BI record of the Twentieth Annual ACM Hyperdoctrines and Higher-Order Separation Logic. In SIGPLAN-SIGACT Symposium on Principles of Programming Languages and Systems: 14th European Programming Languages, pages 57–70, 1993. Symposium on Programming, ESOP 2005, volume 3444/2005, pages 233–247, Edinburgh, UK, April 2005. Springer-Verlag GmbH. [4] B. Biering, L. Birkedal, and N. Torp-Smith. BI-hyperdoctrines, higher-order separation logic, and abstraction. Technical Report ITU-TR-2005-69, IT University of Copenhagen, July 2005. [5] L. Birkedal, N. Torp-Smith, and H. Yang. Semantics of separation-logic typing and higher-order frame rules. In P. Panangaden, editor, Proceedings of the Twentieth Annual IEEE Symp. on Logic in Computer Science, LICS 2005, pages 260–269. IEEE Computer Society Press, June 2005. [6] C. Calcagno, P. W. O’Hearn, and R. Bornat. Program logic and equivalence in the presence of garbage collection. Theoretical Computer Science, 298(3):557–581, April 2003. [7] R. Davies and F. Pfenning. A judgemental reconstruction of modal logic. Mathematical Structures in Computer Science, 11(4):511–540, 2001. [8] S. S. Ishtiaq and P. W. O’Hearn. BI as an Assertion Language for Mutable Data Structures. In POPL, pages 14–26, 2001. [9] E. Moggi. Notions of computation and monads. Information and Computation, 93(1):55–92, 1991. [10] P. W. O’Hearn, J. C. Reynolds, and H. Yang. Local reasoning about programs that alter data structures. In L. Fribourg, editor, Computer Science Logic, volume 2142 of Lecture Notes in Computer Science, pages 1–19, Berlin, 2001. Springer-Verlag. [11] P. W. O’Hearn, H. Yang, and J. C. Reynolds. Separation and information hiding. In Conference Record of POPL 2004: The 31st ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, pages 268–280, New York, 2004. ACM Press. [12] M. Parkinson. Local Reasoning for Java. PhD thesis, University of Cambridge, November 2005. [13] B. C. Pierce. Types and Programming Languages. MIT Press, Cambridge MA, 2002. [14] G. D. Plotkin and A. J. Power. Computational effects and operations: An overview. Electr. Notes Theor. Comput. Sci, 73:149–163, 2004.