Stacks, Heaps and Regions: One Logic to Bind Them David Walker Princeton University SPACE 2004 Stacks, Heaps and Regions: One Logic to Bind Them David Walker Princeton University With: Amal Ahmed & Limin Jia Certifying Compilers Source Program Certifying compilers produce: » machine code + » safety proof Certifying Compiler • type safety • thread safety • memory safety Uses: Machine Code + Safety Proof David Walker » trustworthy mobile code » safety-critical systems » compiler debugging Stacks, Heaps and Regions: One Logic to Bind Them 3 Certifying Compilers ML Java C# Low-level typing abstractions: Transform, Optimize Low-level Typing Abstractions Machine Code + » support diverse source languages » support diverse implementation & optimization strategies » clean interface between compiler and mechanical safety checkers Safety Proof (Typing Invariants Encoded) David Walker Stacks, Heaps and Regions: One Logic to Bind Them 4 TALx86 Lessons [Morrisett et al.] Checking control-flow safety is fairly easy State & memory management is the hard part » new typing algorithms for each new compiler trick • • • • machine register state heap memory (pointers, structs, ...) stack memory (stack pointers, stack structs, ...) user-managed memory (more pointers, aliasing info, ...) Results: » complex, ad hoc axioms (type checker less trust-worthy) » repeated work » abstractions not generally composable or reusable David Walker Stacks, Heaps and Regions: One Logic to Bind Them 5 A Goal for SPACE 20... What we are looking for: A new proof-carrying code system/typed assembly language for safe memory management » More uniform; more general » Easier to understand (simpler semantics) » Allows reuse and composition of abstractions A promising approach: Search for new logics that can capture common storage invariants » Following Ishtiaq, O’Hearn, Pym, Reynolds, and others insights on storage semantics & separation logic » And Pfenning, CMU crew and others logical design techniques & work on logical frameworks David Walker Stacks, Heaps and Regions: One Logic to Bind Them 6 This Talk… What recurring properties of memory do we need to reason about in a proof-carrying code system? Internalizing storage properties in a modal & substructural logic » Semantics of formulae Using the logic to describe state in a low-level type system (briefly) Related & Future work » This talk based on work at TLDI 03; LICS 03 David Walker Stacks, Heaps and Regions: One Logic to Bind Them 7 Property #1: Separation The memory for the heap is separate from the memory for the stack stack 7 8 9 14 15 7475 heap The register EAX is separate from register EBX (and ECX, etc...) EAX EBX In general, memory A is separate from memory B if the domain of A does not overlap with the domain of B David Walker Stacks, Heaps and Regions: One Logic to Bind Them 8 Property #1: Separation The importance of separation: » If memory A is separate from memory B then updates to A have no impact on B » Eg: updating the stack does not change values in the heap » Eg: updating EAX does not change the contents of EBX » Eg: deallocating region r1 has no impact on region r2 (if they are separate) Present in » Linear type systems » TALx86 » Ishtiaq, O’Hearn, Reynolds separation logic David Walker Stacks, Heaps and Regions: One Logic to Bind Them 9 Property #2: Adjacency A struct is a sequence of adjacent locations An activation record is a sequence of adjacent locations 7 8 9 A stack is a sequence of adjacent activation records a1 a2 rest... top In general, A is adjacent to B if the greatest location in A is next to the least location in B, and A is separate from B David Walker Stacks, Heaps and Regions: One Logic to Bind Them 10 Property #2: Adjacency The importance of adjacency: » If memory A is adjacent to memory B and we can access A then we can access B » Eg: using a pointer to the beginning of a struct, we can access all of its elements » Eg: using a pointer to the top of the stack, we can access the items in the current activation record Present in » TALx86 » Foundational PCC (Appel et al) » Ordered type systems (Petersen et al.) David Walker Stacks, Heaps and Regions: One Logic to Bind Them 11 Property #3: Containment Register EAX can contain an integer value (or a pointer value or other kinds of values) EAX 3 A memory location (say, 7) can contain a sequence of 32 bits 31: 0: 1: ... 7 on off on A user-managed memory region may contain a collection of memory locations. R7 David Walker 7 7 22 13 Stacks, Heaps and Regions: One Logic to Bind Them 12 Property #3: Containment The importance of containment: » If A is contained in memory region r and region r has property P then A has property P » Eg: EAX may contain an integer --- if so, we can add 3 to the contents of EAX » Eg: Memory region R1 may contain live data --- if so, we can dereference pointers into that region Present in » Tofte & Talpin’s region calculus » Cardelli, Gardner, Ghelli Gordon’s ambient, tree & graph logics » TALx86 (registers, static data segment, stack & heap) David Walker Stacks, Heaps and Regions: One Logic to Bind Them 13 Property #4: Aliasing Two pointers are aliases of one another if they are the same location. x y (x = y) 3 Aliasing information is important since changing memory at x changes memory at y Present in » every system!! » Talx86 reasoned about heap aliases and stack aliases David Walker Stacks, Heaps and Regions: One Logic to Bind Them 14 This Talk… What recurring properties of memory are convenient for reasoning in a proof-carrying code system? Internalizing storage properties in a modal & substructural logic » Semantics of formulae Using the logic to describe state in a low-level type system Related & Future work » This talk based on work at TLDI 03; LICS 03 David Walker Stacks, Heaps and Regions: One Logic to Bind Them 15 Preliminaries - Memories A memory is a mapping from locations to values. Each location may have a single successor. Successor relation gives rise to an ordering. m 5 6 7 3 a r1 9 16 17 1 r2 Locations may be composite » ::= ∗ | .n eg: *.R1.a7 David Walker *.R2.a14.b0 Stacks, Heaps and Regions: One Logic to Bind Them 16 Formulae Predicates q ::= t | … Formulae F ::= q | … Semantics of formulae given by: m F @ “F describes memory m, whose contents are located in place ” ( acts like a constraint on the memory) Simplest case: m t@ iff dom(m)={} and m() : t David Walker Stacks, Heaps and Regions: One Logic to Bind Them 17 Formulae Example m int @ 3 if m 3 5 David Walker (notice: m(3) : int ) Stacks, Heaps and Regions: One Logic to Bind Them 18 Formulae – Separation Predicates q ::= t | … Formulae F ::= q | F1 F2 | … m F1 F2 @ iff exists disjoint m1 and m2 such that m1 F1 @ and m2 F2 @ and m=m1 m2 David Walker Stacks, Heaps and Regions: One Logic to Bind Them 19 Formulae – Separation Example m1 F1 @ * m1 5 David Walker m2 3 7 m2 F2 @ * 16 17 7 8 9 3 16 Stacks, Heaps and Regions: One Logic to Bind Them r6 20 Formulae – Separation Example m1m2 F1 F2 @ * m1 m2 3 7 5 David Walker 16 17 7 8 9 3 16 Stacks, Heaps and Regions: One Logic to Bind Them r6 21 Formulae – Adjacency Predicates q ::= t | … Formulae F ::= q | F1 F2 | F1 ○ F2 | … m F1 ○ F2 @ iff there exist adjacent (and disjoint) m1 , m2 such that m1 F1 @ and m2 F2 @ and m=m1 m2 David Walker Stacks, Heaps and Regions: One Logic to Bind Them 22 Formulae – Adjacency Example m1 F1 @ * m1 3 7 David Walker m2 F2 @ * m2 5 7 8 9 b 10 c 16 17 Stacks, Heaps and Regions: One Logic to Bind Them 23 Formulae – Adjacency Example m1m2 F1 ○ F2 @ * m1 m2 3 7 David Walker 5 7 8 9 10 b c 16 17 Stacks, Heaps and Regions: One Logic to Bind Them 24 Formulae – Containment Predicates q ::= t | … Formulae F ::= q | F1 F2 | F1 ○ F2 | n[F] | … m n[F] @ iff m F @ .n David Walker Stacks, Heaps and Regions: One Logic to Bind Them 25 Formulae - Containment Example m eax[int] @ * m since m int @ *.eax since m(*.eax) : int eax 5 David Walker Stacks, Heaps and Regions: One Logic to Bind Them 26 Formulae - Containment Example m eax[int] ebx[char] @ * m eax 5 David Walker ebx ‘a’ Stacks, Heaps and Regions: One Logic to Bind Them 27 Formulae - Containment Example m eax[int] ebx[char] @ * since m1 eax[int] @ * m eax 5 David Walker m2 ebx[char] @ * and ebx ‘a’ Stacks, Heaps and Regions: One Logic to Bind Them 28 Formulae - Containment Example m eax[int] ebx[char] @ * since m1 eax[int] @ * and m2 ebx[char] @ * since m1 int @ *.eax and m2 char @ *.ebx m eax 5 David Walker ebx ‘a’ Stacks, Heaps and Regions: One Logic to Bind Them 29 Aliasing Types t ::=int | bool | S() | ... Predicates q ::= t | … Formulae F ::= q | F1 F2 | F1 ○ F2 | n[F] | … ⊢ v : S() iff v = David Walker (all values with type S() are aliases of one another) Stacks, Heaps and Regions: One Logic to Bind Them 30 Aliasing Example aliases m ⊨ eax[S(*.a2)] ⊗ ebx[S(*.a2)] ⊗ a2[int] @ * m eax ebx a2 7 David Walker Stacks, Heaps and Regions: One Logic to Bind Them 31 One More Useful Predicate Types t ::=int | bool | S() | ... Predicates q ::= t | more | more Formulae F ::= q | F1 F2 | F1 ○ F2 | n[F] | ... m morem more m m ... David Walker 4 5 6 7 8 9 14 15 16 1718 19 Stacks, Heaps and Regions: One Logic to Bind Them ... 32 Simple Machine Memory Layout ( more○ hd [t] ○ Ftail ○ Fheap ○ ap [t’] ○ more) r1 [t1] r2 [t2] ... sp [S(hd)] ap [S(ap)] ... hd ... moreFtail sp David Walker r1 ap ... r2 Fheap ... more ap Stacks, Heaps and Regions: One Logic to Bind Them 33 More logic Predicates q ::= t | more | more Formulae F ::= q | F1 F2 | F1 ○ F2 | n[F] | 1 | F1 -o F2 | F1 &F2 | ㄒ | F1 F2 | 0 | f | b. F | $b.F b ::= :L | n:N | a:T | f:F Bindings m 1 iff dom(m) is empty m F1 &F2 iff m F1 and m F2 m ㄒ (holds for any memory m) .... David Walker Stacks, Heaps and Regions: One Logic to Bind Them 34 Logical Deduction Judgments have the form q F @ q is a variable context – a list of free variables & their kinds is a bunched context – trees rather than lists (O’Hearn & Pym, 1999) ::=. | (F @ ) | , | ; object at a place separate storage (exchange prop) David Walker adjacent storage (no exchange prop) Stacks, Heaps and Regions: One Logic to Bind Them 35 Logical Deduction The natural deduction rules are sound with respect to the storage semantics Semantics of contexts : m Theorem (Soundness) If m and ‧ F @ then m F @ . David Walker Stacks, Heaps and Regions: One Logic to Bind Them 36 This Talk… What recurring properties of memory are convenient for reasoning in a proof-carrying code system? Internalizing storage properties in a modal & substructural logic » Semantics of formulae Using the logic to describe state in a low-level type system Related & Future work » This talk based on work at TLDI 03; LICS 03 David Walker Stacks, Heaps and Regions: One Logic to Bind Them 37 Mini-KAM – Simplified ML Kit Abstract Machine Registers r ::= acc1 | acc2 | sp Values v ::= .... Instructions i ::= immed1(v)| immed2(v)| add | sub | push | pop | selectStack(i)| storeStack(i)| select(i)| store(i)| letRgnInf | endRgnInf | alloc(i) register ops stack ops region ops David Walker Stacks, Heaps and Regions: One Logic to Bind Them 38 Mini-KAM Types Types t ::= int | S() | live | dead | (F @ ) 0 Integers 5 : int Places : S() Region status live : live dead : dead Code Locations c : (F @ ) 0 Means it is safe to jump to c with a memory m such that m F @ David Walker Stacks, Heaps and Regions: One Logic to Bind Them 39 Mini-KAM – Simplified ML Kit Abstract Machine Mini-KAM Store Hierarchy ∗ acc1 acc2 sp stack st[more○ ak[-] ○ . . ○ a1[-] ○ f] current activation record stack area David Walker stack tail R1 ... R1[live ⊗ F Rn ⊗ (a[-] ○ more description live region of data in region Stacks, Heaps and Regions: One Logic to Bind Them region allocation boundary 40 Using Formulae in Typing Rules Judgments of the form F @ can be used to describe the pre and postconditions of instructions Instruction typing judgment: q F @ David Walker Stacks, Heaps and Regions: One Logic to Bind Them i : F’ @ ’ 41 Using Formulae in Typing Rules Judgment : q F@ i : F’ @ ’ In J, look up the type of place .n: J(.n) = F if ‧J (ㄒ n[F] ) @ Rule for add instruction: (F @ )(∗.acc1) = int (F @ )(∗.acc2) = int q F @ add : F @ David Walker Stacks, Heaps and Regions: One Logic to Bind Them 42 Using Formulae in Typing Rules Judgment q J i : J’ (where J is of the form F @ p) J(∗.sp)=S(∗.stack.n0) J(∗.acc1)=t ( storeStack) q J storeStack(i) : J[∗.stack.no + i := t ] In J, update the type of place .no + i: J[.no+i := t] = (F1 ○ n0[-] ○ ‧‧‧ ○ ni[t] ○ F2) F3 @ if David Walker ‧u:J ((F1 ○ n0[-] ○ ‧‧‧ ○ ni[-] ○ F2) F3) @ Stacks, Heaps and Regions: One Logic to Bind Them 43 This Talk… What recurring properties of memory are convenient for reasoning in a proof-carrying code system? Internalizing storage properties in a modal & substructural logic » Semantics of formulae Using the logic to describe state in a low-level type system Related & Future work » This talk based on work at TLDI 03; LICS 03 David Walker Stacks, Heaps and Regions: One Logic to Bind Them 44 Related Work Reasoning about adjacency » Stack-based TAL (Morrisett et al., 1998) » Foundational PCC – reasoning about memory allocation (Appel et al.) » lord - calculus for reasoning about data layout at the frontier (Petersen et al., 2003) Reasoning about aliasing » Long history . . . singleton types for aliasing (Smith, Walker & Morrisett) continue to be useful Spatial logics : separation and/or containment » BI, separation logic (Ishtiaq, O’Hearn, Reynolds & others, 2000, 2001) » Ambient logic (Cardelli & Gordon, 2000) » Tree and graph logics (Cardelli, Gardner, Ghelli, 2002) David Walker Stacks, Heaps and Regions: One Logic to Bind Them 45 Lots More Work to Do Add inductive definitions & syntactic rules for reasoning about arrays, recursive data structures Investigate encodings for common invariants » stack-allocation algorithms » region-allocation algorithms » aliasing patterns Better understand the connection between modal (hybrid) logic & regions David Walker Stacks, Heaps and Regions: One Logic to Bind Them 46 Conclusion Described a unified framework for reasoning about » Separation » Adjacency » Containment » Aliasing Semantics are sound, simple and uniform Logic forms the basis for a sound and flexible lowlevel type system See TLDI 03; LICS 03 for details David Walker Stacks, Heaps and Regions: One Logic to Bind Them 47 David Walker Stacks, Heaps and Regions: One Logic to Bind Them 48 David Walker Stacks, Heaps and Regions: One Logic to Bind Them 49 May Alias Formula when two bits of storage (at a1 and a2) may alias: $a1. $a2. (a1[int] ⊗ ㄒ) & (a2[int] ⊗ ㄒ) both memories satisfy the formula: a1 5 David Walker a2 a 7 5 Stacks, Heaps and Regions: One Logic to Bind Them 50 Example: Saving Temporaries on the Stack Code Describing Formula Fpre (b-stackgrow)(x 2) (more○ [a ] ○ [a ] ○ [t] ○ F ) 1 1 2 2 1 (b-unpack)(x 2) sp[S()] r1[t1] r2[t2] sub sp,sp,2 st sp[0],r1 st sp[1],r2 < Code for A > ld r1,sp[0] ld r2,sp[1] add sp,sp,2 David Walker Fpost (more○ 1[a1] ○ 2[a2] ○ [t] ○ F1) sp[S(1)] r1[t1] r2[t2] Stacks, Heaps and Regions: One Logic to Bind Them 51 Formulae Wrapped in Types Types t ::= int | S(p) | (F @ p) 0 Informally, c : (F @ p) 0 means it is safe to jump to c with a memory m such that m F @ p David Walker Stacks, Heaps and Regions: One Logic to Bind Them 52 Motivation: Certifying Compilers Source Program Certifying Compiler Machine Code David Walker Safety Proof Stacks, Heaps and Regions: One Logic to Bind Them 53 Motivation: Certifying Compilers Source Program Parse, Typecheck High-level Typed IL Typepreserving Compiler Analysis, Optimization Medium-level Typed IL Code Generation Typed Assembly Language Assembler Hints Prover Machine Code David Walker Safety Proof Stacks, Heaps and Regions: One Logic to Bind Them 54 Motivation: Certifying Compilers Typepreserving Compiler ML Java Java High TIL High TIL High TIL Optimize Optimize Optimize Medium-level Typed IL Code Generation Typed Assembly Language Assembler Hints Prover Machine Code David Walker Safety Proof Stacks, Heaps and Regions: One Logic to Bind Them 55 Motivation: Proof-Carrying Code The Princeton foundational PCC system (Appel et al.) Scaling PCC to production compilers and realistic languages Some requirements: » Multiple source languages, single target language » Core proof system must be general and flexible • support for general language features • handle different implementation and optimization strategies » Trusted computing base should be small • to limit security bugs David Walker Stacks, Heaps and Regions: One Logic to Bind Them 56 PCC System – Layers of Abstraction Compiler High-level typing abstractions Low-level typing abstractions support for a range of language features David Walker Semantics of types general & flexible interface to compiler Machine spec Higher-order logic Stacks, Heaps and Regions: One Logic to Bind Them 57 A Hard Problem (Semantics) Semantics of memory updates and memory reuse Semantic model of ML-style mutable references (Ahmed, Appel, Virga, 2002) To handle ML function closures: » extended model with mutable references to (impredicative) polymorphic types (Ahmed, Appel, Virga, 2003) To allow memory reuse: » extended model to support region-based memory management David Walker Stacks, Heaps and Regions: One Logic to Bind Them 58 Motivation: Certifying Compilers ML Java C# High-level Typed IL Analysis, Optimization Medium-level Typed IL Typing abstractions (TAL) Prover Should be general & flexible; support many • language features • implementation + optimization strategies Machine Code + Safety Proof David Walker Stacks, Heaps and Regions: One Logic to Bind Them 59 Typing Abstractions for Memory Reasoning about memory is complicated » many different memory management strategies, aliasing patterns, data layout possibilities, etc. Systems for safe mobile code would benefit from » a unified framework for reasoning about a variety of invariants » convenient abstractions that help structure proofs of memory safety David Walker Stacks, Heaps and Regions: One Logic to Bind Them 60 Abstractions for Memory? Cornell Popcorn & Cyclone Cedilla Systems Special J Princeton Foundational PCC Source Source Source High TIL High TIL High TIL Medium TIL Medium TIL Medium TIL TALx86 Machine Code + Safety Proof David Walker LTAL VCGen + Prover Prover Machine Code + Safety Proof Machine Code + Safety Proof Stacks, Heaps and Regions: One Logic to Bind Them 61 Abstractions for Memory? Cornell Popcorn & Cyclone Cedilla Systems Special J Princeton Foundational PCC Source Source Source High TIL High TIL High TIL Medium TIL Medium TIL Medium TIL TALx86 Machine Code + Safety Proof David Walker LTAL VCGen + Prover Prover Machine Code + Safety Proof Machine Code + Safety Proof Stacks, Heaps and Regions: One Logic to Bind Them 62 Abstractions for Memory? Cornell Popcorn, Cyclone Cedilla Systems Special J Princeton Foundational PCC Source Source Source High TIL High TIL High TIL Medium TIL Medium TIL Medium TIL VCGen + Prover LTAL Prover Machine Code + Safety Proof Machine Code + Safety Proof TALx86 Machine Code + Safety Proof David Walker Reasoning about memory is complicated: many different memory management strategies, aliasing patterns, data layout possibilities, etc. Stacks, Heaps and Regions: One Logic to Bind Them 63 Typing Abstractions for Memory? Cornell Popcorn & Cyclone Cedilla Systems Special J Princeton Foundational PCC Source Source Source High TIL High TIL High TIL Medium TIL Medium TIL Medium TIL TALx86 VCGen + Prover LTAL Prover Machine Code + Safety Proof Machine Code + Safety Proof Machine Code + Safety Proof Reasoning about memory is complicated » many different memory management strategies, aliasing patterns, data layout possibilities, etc. David Walker Stacks, Heaps and Regions: One Logic to Bind Them 64 Formulae Wrapped in Types Types t ::= int | S(p) | (F @ p) 0 Informally, c : (F @ p) 0 means it is safe to jump to c with a memory m such that m F @ p David Walker Stacks, Heaps and Regions: One Logic to Bind Them 65 Lessons from Typed Assembly Language Lesson 1: » Much of the type theory designed for higher-level languages can be reused to help verify machine code. • TAL is “just” the closed, continuation-passing style polymorphic lambda calculus (++) Lesson 2: » The hard part is memory management & memory safety. David Walker Stacks, Heaps and Regions: One Logic to Bind Them 66 One Logic to Bind Them New goals for general-purpose safe memory management A unified & composable framework for reasoning about Proof that deduction in our logic is sound with respect to the memory model Use logic in a type system for an IL for region-based memory management (Mini-KAM) and prove that the language is sound » » » » » » » » composable abstractions reusable abstractions orthogonal abstractions comprehensible abstractions separation of objects (memory blocks) adjacency of objects aliasing of pointers containment of one place in another David Walker Stacks, Heaps and Regions: One Logic to Bind Them 67 This Talk… Logical formulae and the memory model » Flat memory » Hierarchical memory Type system for Mini-KAM (informally) David Walker Stacks, Heaps and Regions: One Logic to Bind Them 68 A Logical Approach to Memory Management One logic for reasoning about key storage properties: » » » » separation of objects (memory blocks) adjacency of objects containment of one place in another aliasing of pointers Logic comes with » orthogonal connectives to internalize key properties » syntactic proof rules » sound store semantics Logic is incorporated into a typed abstract machine » safe stack, heap and region-based memory management David Walker Stacks, Heaps and Regions: One Logic to Bind Them 69 Formulae – Multiplicative Unit Predicates q ::= [t] | … Formulae F ::= q | F1 F2 | F1 ○ F2 | 1 | … m 1 iff m David Walker Stacks, Heaps and Regions: One Logic to Bind Them 70 Hierarchical Memories m R1 David Walker 7 8 9 R2 14 15 Stacks, Heaps and Regions: One Logic to Bind Them 71 Hierarchical Memories, Paths m R1 7 8 9 Path/place *.R2.14 David Walker R2 p ::= ∗ | p.n R1 14 15 7 8 9 ∗ R2 14 15 eg: *.R1.7 Stacks, Heaps and Regions: One Logic to Bind Them 72 Hierarchical Memories, Paths m =A1 R1 7 8 9 R2 ∗ R1 14 15 7 8 R2 9 14 15 b0 b1 … b31 Path/place *.R2.14 p ::= ∗ | p.n eg: *.R1.7 A hierarchical memory is a mapping from paths to values. David Walker Stacks, Heaps and Regions: One Logic to Bind Them 73 Formulae – Containment Predicates q ::= t | more | more Formulae F ::= q | F1 F2 | F1 ○ F2 | 1 | F1 &F2 | ㄒ | F1 F2 | 0 | f | b. F | $b.F | n[F] Bindings b ::= p:P | n:N | a:T | f:F Semantics given by: m F @ p David Walker Stacks, Heaps and Regions: One Logic to Bind Them 74 Formula Semantics – Separation Formulae F ::= … | F1 F2 | … | n[F] m (F1 F2) @ p iff there exist disjoint m1 and m2 m1 F1 @ p and m2 F2 @ p and m=m1 m2 David Walker Stacks, Heaps and Regions: One Logic to Bind Them 75 Formula Semantics – Separation Example m1 F1 @ ∗ m1 R5 m2 3 R5 3 dom(m1)={∗.R5.3} David Walker m2 F2 @ ∗ 4 3 dom(m2)={∗.R5.4} Stacks, Heaps and Regions: One Logic to Bind Them 76 Formula Semantics – Separation Example m1 F1 @ ∗ m1m2 R5 3 m2 F2 @ ∗ R5 3 dom(m1)={∗.R5.3} 4 3 dom(m2)={∗.R5.4} m1 m2 (F1 F2) @ ∗ David Walker Stacks, Heaps and Regions: One Logic to Bind Them 77 Sample Deductive Rules q∥ F @ p ⊢ F @ p q∥ ⊢ F @ p.n q∥ ⊢ n[F] @ p (n[] I) (hypothesis) q∥ ⊢ n[F] @ p q∥ ⊢ F @ p.n (n[] E) Each connective is defined in terms of judgmental concepts only; no dependencies on other connectives Simpler to understand & manipulate David Walker Stacks, Heaps and Regions: One Logic to Bind Them 78