verifying concurrent go code in coq with goose
play

Verifying concurrent Go code in Coq with Goose Tej Chajed , Joseph - PowerPoint PPT Presentation

Verifying concurrent Go code in Coq with Goose Tej Chajed , Joseph Tassarotti*, Frans Kaashoek, Nickolai Zeldovich MIT and *Boston College Systems verification, broadly impl proof specification 2 Systems verification requires connecting


  1. Verifying concurrent Go code in Coq with Goose Tej Chajed , Joseph Tassarotti*, Frans Kaashoek, Nickolai Zeldovich MIT and *Boston College

  2. Systems verification, broadly impl proof specification 2

  3. Systems verification requires connecting implementation to proof model of impl impl proof specification 3

  4. Systems verification requires connecting implementation to proof this talk model of impl impl previous [SOSP 2019] proof and current work specification 3

  5. We aim to verify realistic systems PDOS (the part that does verification) Systems: running code, interacts with outside world Realistic: reasonably e ffi cient, concurrency Verification: functional correctness, focus on crash safety 4

  6. Goal: implement in a systems language (1) write ordinary imperative code (2) import into Coq model of impl impl (3) prove something about the model 5

  7. Goose: write code in Go and prove with Iris Why Go (vs. C or Rust) ? Simple, good tooling Why Iris (vs. VST) ? Concurrency, extensibility 6

  8. Implementing in Go helps build the software (1a) write ordinary imperative code (2) import into Coq model of impl impl (1b) test (3) prove something (1c) debug about the model (1d) profile (1e) benchmark 7

  9. Goose: import subset of Go into a Coq model Go Goose ✓ locks ✓ fork ✓ structs ✓ pointers ✗ interfaces 8

  10. Goose: import subset of Go into a Coq model Coq Go goose translator Goose ✓ locks ✓ fork ✓ structs ✓ pointers ✗ interfaces 8

  11. Goose: import subset of Go into a Coq model Coq Go GooseLang goose translator λ ref,conc with 
 Goose ✓ locks external ops ✓ fork ✓ structs ✓ pointers ✗ interfaces 8

  12. Goose: import subset of Go into a Coq model Coq Go GooseLang goose translator λ ref,conc with 
 Goose ✓ locks external ops ✓ fork ✓ structs carry out ✓ pointers proofs in Iris ✗ interfaces 8

  13. Our systems verification research using Goose Persistent key-value store using file system (unverified) Mail server using file system (appeared in SOSP ’19) Concurrent file system using disk (in progress) 9

  14. Go is a systems language C-like: functions, structs, pointers Exposes system calls E ffi cient runtime (garbage collection, threads) 10

  15. Goose code Looks like standard Go, but avoids most of the standard library Use narrow interfaces for file system or disk More of Go is supported frequently 11

  16. Challenges in implementing Goose Defining GooseLang, a semantic model of Go Translating Go to GooseLang 12

  17. GooseLang, a semantic model of Go e ::= x | λ x. e | e 1 e 2 // λ -calculus 
 | ref e | !e | e 1 ← e 2 // heap operations 
 | fork e | cmpxchg // concurrency | call op e // external operations 13

  18. GooseLang, a semantic model of Go e ::= x | λ x. e | e 1 e 2 // λ -calculus 
 | ref e | !e | e 1 ← e 2 // heap operations 
 | fork e | cmpxchg // concurrency | call op e // external operations 13

  19. GooseLang, a semantic model of Go e ::= x | λ x. e | e 1 e 2 // λ -calculus 
 | ref e | !e | e 1 ← e 2 // heap operations 
 | fork e | cmpxchg // concurrency | call op e // external operations v ::= U64 x | Loc z | … // literals | Pair | InjL | InjR // sums, products 13

  20. Excerpt from GooseLang: 
 slices x = (ptr, len) Definition sliceAppend := … λ s, x. ptr let s’ := alloc (s.len + #1) () in len … (* fill s’ *) (s’, s.len + #1). Coq 14

  21. Excerpt from GooseLang: 
 slices x = (ptr, len) Definition sliceAppend := … λ s, x. ptr let s’ := alloc (s.len + #1) () in len … (* fill s’ *) (s’, s.len + #1). Coq Go Definition example := func example(x []uint64) { x1 := x[1] λ x. goose append(x, 5) let x1 := !(x.ptr + ₗ #1) in } sliceAppend x #5;; #(). 14

  22. Excerpt from GooseLang: 
 modeling concurrency and locking func coin() bool { m := new(sync.Mutex) x := new(bool) go func() { m.Lock() *x = true m.Unlock() }() m.Lock() v := *x m.Unlock() return v 15

  23. Excerpt from GooseLang: 
 modeling concurrency and locking Definition coin: val := func coin() bool { λ <>. m := new(sync.Mutex) let: “m” := lock.new #() in x := new(bool) let: “x” := ref #(zero_val boolT) in go func() { goose fork (lock.acquire “m”;; m.Lock() “x” ← #true;; *x = true m.Unlock() lock.release “m”);; }() lock.acquire “m”;; m.Lock() let: “v” := !”x” in v := *x lock.release “m”;; m.Unlock() “v”. return v 15

  24. Excerpt from GooseLang: 
 modeling concurrency and locking Definition coin: val := func coin() bool { λ <>. m := new(sync.Mutex) let: “m” := lock.new #() in x := new(bool) let: “x” := ref #(zero_val boolT) in go func() { goose fork (lock.acquire “m”;; m.Lock() “x” ← #true;; *x = true m.Unlock() lock.release “m”);; }() lock.acquire “m”;; m.Lock() let: “v” := !”x” in v := *x lock.release “m”;; m.Unlock() “v”. return v 16

  25. Excerpt from GooseLang: 
 modeling concurrency and locking Definition coin: val := func coin() bool { λ <>. m := new(sync.Mutex) let: “m” := lock.new #() in x := new(bool) let: “x” := ref #(zero_val boolT) in go func() { goose fork (lock.acquire “m”;; m.Lock() “x” ← #true;; *x = true m.Unlock() lock.release “m”);; }() lock.acquire “m”;; m.Lock() let: “v” := !”x” in v := *x lock.release “m”;; m.Unlock() “v”. return v 17

  26. Excerpt from GooseLang: 
 modeling concurrency and locking Definition coin: val := func coin() bool { λ <>. m := new(sync.Mutex) let: “m” := lock.new #() in x := new(bool) let: “x” := ref #(zero_val boolT) in go func() { goose fork (lock.acquire “m”;; m.Lock() “x” ← #true;; *x = true m.Unlock() lock.release “m”);; }() lock.acquire “m”;; m.Lock() let: “v” := !”x” in v := *x lock.release “m”;; m.Unlock() “v”. return v 18

  27. Challenge in modeling Go: weak memory func uhOh(x *uint64) { Definition uhOh: val := go func() { λ x. goose *x = 1 fork (x ← #1 print(“set x”) print “set x” !x);; }() print “x=” !x. print(“x=”, *x) Sequential consistency } x86-TSO If we first see “set x”, then 19

  28. Challenge in modeling Go: weak memory func uhOh(x *uint64) { Definition uhOh: val := go func() { λ x. goose *x = 1 fork (x ← #1 ✓ print(“set x”) print “set x” !x);; }() print “x=” !x. print(“x=”, *x) Sequential consistency } x86-TSO If we first see “set x”, then sequential consistency means x=1 19

  29. Challenge in modeling Go: weak memory func uhOh(x *uint64) { Definition uhOh: val := go func() { λ x. goose *x = 1 ✗ fork (x ← #1 ✓ print(“set x”) print “set x” !x);; }() print “x=” !x. print(“x=”, *x) Sequential consistency } x86-TSO If we first see “set x”, then sequential consistency means x=1 but TSO allows x=0 19

  30. Challenge in modeling Go: weak memory func uhOh(x *uint64) { Definition uhOh: val := go func() { λ x. goose *x = 1 ✗ fork (x ← #1 ✓ print(“set x”) print “set x” !x);; }() print “x=” !x. print(“x=”, *x) Sequential consistency } x86-TSO If we first see “set x”, then sequential consistency means x=1 but TSO allows x=0 19

  31. Disallow racy loads and stores Definition Store: val := λ p, v. BeginStore p;; FinishStore p v. Notation “p ← v” := (Store p v). Track in-progress stores Concurrent store/store and load/store are undefined 20

  32. Compatibility with Iris gives us amazing verification technology Concurrent separation logic with higher-order ghost state Iris Proof Mode (IPM) for interactive proofs 21

  33. Compatibility with Iris gives us amazing verification technology Concurrent separation logic with higher-order ghost state Iris Proof Mode (IPM) for interactive proofs Connect to our unwritten POPL 2021 paper for crash safety 21

  34. Proofs using non-atomic memory Load (non-atomic) Store { p ↦ v } { p ↦ v 0 } ! p p ← v { p ↦ v } { λ v . p ↦ v } These triples are sound because is exclusive access to p ↦ v p 22

  35. Proofs using non-atomic memory Load (non-atomic) Store { p ↦ v } { p ↦ v 0 } ! p p ← v { p ↦ v } { λ v . p ↦ v } These triples are sound because exclude using locks is exclusive access to p ↦ v p exclude by using local variables 22

  36. GooseLang programs can make system calls Import disk. import “github.com/tchajed/goose/ machine/disk" goose Definition Copy: val := func Copy() { b := disk.Read(0) λ _. disk.Write(1, b) let b := call ReadOp #0 in } call WriteOp (#1, b). Language is parameterized by external calls Currently implementing GooseLang + file-system ops in terms of GooseLang + disk ops 23

  37. Semantics of GooseLang Small-step operational semantics, mostly standard and following design of HeapLang For testing, have executable semantics (interpreter + soundness proof) 24

  38. Previous approach: shallow embedding as semantic model GooseLang was a free monad instead of a λ -calculus Go code had to explicitly sequence e ff ectful operations Pure operations were expressed directly in Gallina 25

  39. GooseLang is a mix of shallow and deep embedding Heap operations, concurrency are deeply represented Data structures are shallowly built out of sums 26

Recommend


More recommend