Prophecy Variables in Separation Logic (Extending Iris with Prophecy - - PowerPoint PPT Presentation

prophecy variables in separation logic
SMART_READER_LITE
LIVE PREVIEW

Prophecy Variables in Separation Logic (Extending Iris with Prophecy - - PowerPoint PPT Presentation

Prophecy Variables in Separation Logic (Extending Iris with Prophecy Variables) Ralf Jung, Rodolphe Lepigre, Gaurav Parthasarathy, Marianna Rapoport, Amin Timany, Derek Dreyer, Bart Jacobs MPI-SWS, KU Leuven, ETH Zrich, University of Waterloo


slide-1
SLIDE 1

Prophecy Variables in Separation Logic

(Extending Iris with Prophecy Variables)

Ralf Jung, Rodolphe Lepigre, Gaurav Parthasarathy, Marianna Rapoport, Amin Timany, Derek Dreyer, Bart Jacobs

MPI-SWS, KU Leuven, ETH Zürich, University of Waterloo

Iris Workshop – Aarhus, October 2019

slide-2
SLIDE 2

Reasoning about the correctness of a program

Forward reasoning is ofen easier and more natural:

  • Start at the beginning of a program’s execution
  • Reason about how it behaves as it executes

1

slide-3
SLIDE 3

Reasoning about the correctness of a program

Forward reasoning is ofen easier and more natural:

  • Start at the beginning of a program’s execution
  • Reason about how it behaves as it executes

Strictly forward reasoning is not always good enough!

1

slide-4
SLIDE 4

Reasoning about the correctness of a program

Forward reasoning is ofen easier and more natural:

  • Start at the beginning of a program’s execution
  • Reason about how it behaves as it executes

Strictly forward reasoning is not always good enough! Reasoning about the current execution step may require:

  • Information about past events (this is usual)
  • Knowledge of what will happen later in the execution

1

slide-5
SLIDE 5

Remember the past, know the future

Auxiliary/ghost variables store information not present in the program’s physical state History variables [Owicki & Gries 1976] (past):

  • Record what happened in the execution so far
  • Introduced in the context of Hoare logic
  • Widely used (modern form: user-defined ghost state)

2

slide-6
SLIDE 6

Remember the past, know the future

Auxiliary/ghost variables store information not present in the program’s physical state History variables [Owicki & Gries 1976] (past):

  • Record what happened in the execution so far
  • Introduced in the context of Hoare logic
  • Widely used (modern form: user-defined ghost state)

Prophecy variables [Abadi & Lamport 1991] (future):

  • Predict what will happen later in the execution
  • Introduced in the context of state machine refinement
  • Fairly exotic, (almost) never used for Hoare logic

2

slide-7
SLIDE 7

Motivating example: eager specification

Let us look at a simple coin implementation: new_coin() {val = ref(nondet_bool())} read_coin(c) !c.val

3

slide-8
SLIDE 8

Motivating example: eager specification

Let us look at a simple coin implementation: new_coin() {val = ref(nondet_bool())} read_coin(c) !c.val Used for the sake of presentation

3

slide-9
SLIDE 9

Motivating example: eager specification

Let us look at a simple coin implementation: new_coin() {val = ref(nondet_bool())} read_coin(c) !c.val Used for the sake of presentation We consider an “eager” coin specification:

  • A coin is only ever tossed once
  • Reading its value always gives the same result

3

slide-10
SLIDE 10

Motivating example: eager specification

Let us look at a simple coin implementation: new_coin() {val = ref(nondet_bool())} read_coin(c) !c.val Used for the sake of presentation We consider an “eager” coin specification:

  • A coin is only ever tossed once
  • Reading its value always gives the same result

{True} new_coin() {c. ∃b. Coin(c, b)} {Coin(c, b)} read_coin(c) {x. x = b ∧ Coin(c, b)}

3

slide-11
SLIDE 11

Motivating example: eager specification

Let us look at a simple coin implementation: new_coin() {val = ref(nondet_bool())} read_coin(c) !c.val Used for the sake of presentation We consider an “eager” coin specification:

  • A coin is only ever tossed once
  • Reading its value always gives the same result

{True} new_coin() {c. ∃b. Coin(c, b)} {Coin(c, b)} read_coin(c) {x. x = b ∧ Coin(c, b)} Coin(c, b) c.val → b

3

slide-12
SLIDE 12

Motivating example: lazy implementation

What if we want to flip the coin as late as possible?

4

slide-13
SLIDE 13

Motivating example: lazy implementation

What if we want to flip the coin as late as possible? “Lazy” coin implementation: new_coin() {val = ref(None)} read_coin(c) match ! c.val with Some(b) ⇒ b | None ⇒ let b = nondet_bool(); c.val ← Some(b); b end

4

slide-14
SLIDE 14

Motivating example: lazy implementation

What if we want to flip the coin as late as possible? “Lazy” coin implementation: new_coin() {val = ref(None)} read_coin(c) match ! c.val with Some(b) ⇒ b | None ⇒ let b = nondet_bool(); c.val ← Some(b); b end To keep the same spec we need prophecy variables!!!

4

slide-15
SLIDE 15

Prior work on prophecy variables

Prophecy variables have been used in:

  • Verification tools based on reduction [Sezgin et al. 2010]
  • Temporal logic [Cook & Koskinen 2011, Lamport & Merz 2017]

5

slide-16
SLIDE 16

Prior work on prophecy variables

Prophecy variables have been used in:

  • Verification tools based on reduction [Sezgin et al. 2010]
  • Temporal logic [Cook & Koskinen 2011, Lamport & Merz 2017]

But never formally integrated into Hoare logic before!!!

5

slide-17
SLIDE 17

Prior work on prophecy variables

Prophecy variables have been used in:

  • Verification tools based on reduction [Sezgin et al. 2010]
  • Temporal logic [Cook & Koskinen 2011, Lamport & Merz 2017]

But never formally integrated into Hoare logic before!!! Only two previous attempts:

  • Vafeiadis’s thesis [Vafeiadis 2007] (informal and flawed)
  • Structural approach [Zhang et al. 2012] (too limited)

5

slide-18
SLIDE 18

Our contribution: prophecy variables in Hoare logic

We are the first to give a formal account of prophecy variables in Hoare logic!

  • Our results are all formalized in the Iris framework
  • We also extended VeriFast with prophecy variables
  • Useful to prove logical atomicity (RDCSS, HW Queue)

6

slide-19
SLIDE 19

Our contribution: prophecy variables in Hoare logic

We are the first to give a formal account of prophecy variables in Hoare logic!

  • Our results are all formalized in the Iris framework
  • We also extended VeriFast with prophecy variables
  • Useful to prove logical atomicity (RDCSS, HW Queue)

Presented this morning by Ralf Prophecies help in case of “future-dependent” LP

6

slide-20
SLIDE 20

Key idea of our approach

We leverage separation logic to easily ensure soundness!!!

7

slide-21
SLIDE 21

Key idea of our approach

We leverage separation logic to easily ensure soundness!!! The high-level idea is to use new instruction for:

  • Predicting a future observation (let p = NewProph)
  • Realizing such an observation (Resolve p to v)

7

slide-22
SLIDE 22

Key idea of our approach

We leverage separation logic to easily ensure soundness!!! Principles of prophecy variables in separation logic:

  • 1. The future is ours
  • We model the right to resolve a prophecy as a resource
  • ProphB

1 (p, b) gives exclusive right to resolve p

7

slide-23
SLIDE 23

Key idea of our approach

We leverage separation logic to easily ensure soundness!!! Principles of prophecy variables in separation logic:

  • 1. The future is ours
  • We model the right to resolve a prophecy as a resource
  • ProphB

1 (p, b) gives exclusive right to resolve p

“Assign a value to”

7

slide-24
SLIDE 24

Key idea of our approach

We leverage separation logic to easily ensure soundness!!! Principles of prophecy variables in separation logic:

  • 1. The future is ours
  • We model the right to resolve a prophecy as a resource
  • ProphB

1 (p, b) gives exclusive right to resolve p

  • 2. We must fulfill our destiny
  • A prophecy can only be resolved to the predicted value
  • A contradiction can be derived if that is not the case

“Assign a value to”

7

slide-25
SLIDE 25

“One-shot” prophecy variable specification

Prophecy variables are manipulated using ghost code

8

slide-26
SLIDE 26

“One-shot” prophecy variable specification

Prophecy variables are manipulated using ghost code {True} NewProph

{p. ∃b. ProphB

1 (p, b)}

(Creates a one-shot prophecy variable p)

8

slide-27
SLIDE 27

“One-shot” prophecy variable specification

Prophecy variables are manipulated using ghost code {True} NewProph

{p. ∃b. ProphB

1 (p, b)}

(Creates a one-shot prophecy variable p) Provides an exclusive resolution token

8

slide-28
SLIDE 28

“One-shot” prophecy variable specification

Prophecy variables are manipulated using ghost code {True} NewProph

{p. ∃b. ProphB

1 (p, b)}

(Creates a one-shot prophecy variable p) Provides an exclusive resolution token

{ProphB

1 (p, b)}

Resolve p to v {v = b} (Resolves the prophecy p to value v)

8

slide-29
SLIDE 29

“One-shot” prophecy variable specification

Prophecy variables are manipulated using ghost code {True} NewProph

{p. ∃b. ProphB

1 (p, b)}

(Creates a one-shot prophecy variable p) Provides an exclusive resolution token

{ProphB

1 (p, b)}

Resolve p to v {v = b} (Resolves the prophecy p to value v) Consumes the resolution token

8

slide-30
SLIDE 30

“One-shot” prophecy variable specification

Prophecy variables are manipulated using ghost code {True} NewProph

{p. ∃b. ProphB

1 (p, b)}

(Creates a one-shot prophecy variable p) Provides an exclusive resolution token

{ProphB

1 (p, b)}

Resolve p to v {v = b} (Resolves the prophecy p to value v) Consumes the resolution token But we learn that the prophesied and resolved values are equal

8

slide-31
SLIDE 31

Back to the lazy coin example

With the required ghost code the example becomes: new_coin() {val = ref(None), p = NewProph} read_coin(c) match ! c.val with Some(b) ⇒ b | None ⇒ let b = nondet_bool(); Resolve c.p to b; c.val ← Some(b); b end

9

slide-32
SLIDE 32

Back to the lazy coin example

With the required ghost code the example becomes: new_coin() {val = ref(None), p = NewProph} read_coin(c) match ! c.val with Some(b) ⇒ b | None ⇒ let b = nondet_bool(); Resolve c.p to b; c.val ← Some(b); b end The specification can be proved using: Coin(c, b) (c.val → Some b) ∨ (c.val → None ∗ ProphB

1 (c.p, b)) 9

slide-33
SLIDE 33

Is the one-shot prophecy mechanism general enough?

Consider the following coin implementation: new_coin() {val = ref(nondet_bool())} read_coin(c) ! c.val toss_coin(c) c.val ← nondet_bool();

10

slide-34
SLIDE 34

Is the one-shot prophecy mechanism general enough?

Consider the following coin implementation: new_coin() {val = ref(nondet_bool())} read_coin(c) ! c.val toss_coin(c) c.val ← nondet_bool(); What if we want a “clairvoyant” specification? {True} new_coin() {c. ∃bs. Coin(c, bs)} {Coin(c, bs)} read_coin(c) {b. ∃bs′. bs = b :: bs′ ∧ Coin(c, bs)} {Coin(c, bs)} toss_coin(c) {∃b, bs′. bs = b :: bs′ ∧ Coin(c, bs′)}

10

slide-35
SLIDE 35

One shot is not enough

Generalization: prophecy a sequence of resolutions! {True} NewProph

{p. ∃bs. ProphB(p, bs)}

11

slide-36
SLIDE 36

One shot is not enough

Generalization: prophecy a sequence of resolutions! {True} NewProph

{p. ∃bs. ProphB(p, bs)}

Prophecy assertion now holds a list

11

slide-37
SLIDE 37

One shot is not enough

Generalization: prophecy a sequence of resolutions! {True} NewProph

{p. ∃bs. ProphB(p, bs)}

Prophecy assertion now holds a list

{ProphB(p, bs)}

Resolve p to v

{∃bs′. bs = v :: bs′ ∧ ProphB(p, bs′)}

11

slide-38
SLIDE 38

One shot is not enough

Generalization: prophecy a sequence of resolutions! {True} NewProph

{p. ∃bs. ProphB(p, bs)}

Prophecy assertion now holds a list

{ProphB(p, bs)}

Resolve p to v

{∃bs′. bs = v :: bs′ ∧ ProphB(p, bs′)}

Resolving just pops one element

11

slide-39
SLIDE 39

One shot is not enough

Generalization: prophecy a sequence of resolutions! {True} NewProph

{p. ∃bs. ProphB(p, bs)}

Prophecy assertion now holds a list

{ProphB(p, bs)}

Resolve p to v

{∃bs′. bs = v :: bs′ ∧ ProphB(p, bs′)}

Resolving just pops one element One-shot prophecies can be encoded easily

11

slide-40
SLIDE 40

Back to the clairvoyant coin example

Clairvoyant coin implementation: new_coin() let v = ref(nondet_bool()); {val = v, p = NewProph} read_coin(c) ! c.val toss_coin(c) let r = nondet_bool(); Resolve c.p to r; c.val ← r

12

slide-41
SLIDE 41

Back to the clairvoyant coin example

Clairvoyant coin implementation: new_coin() let v = ref(nondet_bool()); {val = v, p = NewProph} read_coin(c) ! c.val toss_coin(c) let r = nondet_bool(); Resolve c.p to r; c.val ← r The specification can be proved using: Coin(c, bs) ∃b, bs′. c.val → b ∧ ProphB(p, bs′) ∧ bs = b :: bs′

12

slide-42
SLIDE 42

A glimpse at the model of weakest pre

Modified model of weakest preconditions (simplified):

wp e1 {Φ} if e1 ∈ Val then Φ(e1) else (return value) ∀σ1, κ1, κ2. S(σ1, κ1 + + κ2) reducible(e1, σ1) ∧ (progress) ∀e2, σ2, ef.

  • (e1, σ1) → (e2, σ2,

ef, κ1)

  • S(σ2,

κ2) ∗ wp e2 {Φ} ∗∗e∈

ef wp e {True}

  (preservation) S(σ, κ) • σ.1

γheap ∗ ∃Π. • Π γproph ∧ dom(Π) = σ.2 ∧

∀{p ← vs} ∈ Π. vs = filter(p, κ) (state interp.)

13

slide-43
SLIDE 43

A glimpse at the model of weakest pre

Modified model of weakest preconditions (simplified):

wp e1 {Φ} if e1 ∈ Val then Φ(e1) else (return value) ∀σ1, κ1, κ2. S(σ1, κ1 + + κ2) reducible(e1, σ1) ∧ (progress) ∀e2, σ2, ef.

  • (e1, σ1) → (e2, σ2,

ef, κ1)

  • S(σ2,

κ2) ∗ wp e2 {Φ} ∗∗e∈

ef wp e {True}

  (preservation) S(σ, κ) • σ.1

γheap ∗ ∃Π. • Π γproph ∧ dom(Π) = σ.2 ∧

∀{p ← vs} ∈ Π. vs = filter(p, κ) (state interp.) Reduction now collects “observations”

13

slide-44
SLIDE 44

A glimpse at the model of weakest pre

Modified model of weakest preconditions (simplified):

wp e1 {Φ} if e1 ∈ Val then Φ(e1) else (return value) ∀σ1, κ1, κ2. S(σ1, κ1 + + κ2) reducible(e1, σ1) ∧ (progress) ∀e2, σ2, ef.

  • (e1, σ1) → (e2, σ2,

ef, κ1)

  • S(σ2,

κ2) ∗ wp e2 {Φ} ∗∗e∈

ef wp e {True}

  (preservation) S(σ, κ) • σ.1

γheap ∗ ∃Π. • Π γproph ∧ dom(Π) = σ.2 ∧

∀{p ← vs} ∈ Π. vs = filter(p, κ) (state interp.) Reduction now collects “observations” Observations yet to be made

13

slide-45
SLIDE 45

Wrapping up!

Iris now has support for prophecy variables:

  • First formal integration into a program logic
  • Useful for logically atomic specifications (Ralf’s talk)
  • But that’s not the only application (see François’s talk)

14

slide-46
SLIDE 46

Wrapping up!

Iris now has support for prophecy variables:

  • First formal integration into a program logic
  • Useful for logically atomic specifications (Ralf’s talk)
  • But that’s not the only application (see François’s talk)

Things there was no time for:

  • Atomic resolution of prophecy variables
  • Logically atomic spec for RDCSS and Herlihy-Wing queue
  • Erasure theorem (elimination of ghost code)

14

slide-47
SLIDE 47

Wrapping up!

Iris now has support for prophecy variables:

  • First formal integration into a program logic
  • Useful for logically atomic specifications (Ralf’s talk)
  • But that’s not the only application (see François’s talk)

Things there was no time for:

  • Atomic resolution of prophecy variables
  • Logically atomic spec for RDCSS and Herlihy-Wing queue
  • Erasure theorem (elimination of ghost code)

14

slide-48
SLIDE 48

Thanks! Questions?

(For more details: https://iris-project.org)

slide-49
SLIDE 49

Model of weakest preconditions in Iris

Encoding of weakest preconditions (simplified):

wp e1 {Φ} if e1 ∈ Val then Φ(e1) else (return value) ∀σ1. S(σ1) reducible(e1, σ1) ∧ (progress) ∀e2, σ2, ef.

  • (e1, σ1) → (e2, σ2,

ef)

  • S(σ2) ∗ wp e2 {Φ} ∗∗e∈

ef wp e {True}

  (preservation) S(σ) • σ

γheap

(state interp.) Some intuitions about the involved components:

  • The state interpretation holds the state of the physical heap
  • View shifs P

Q allow updates to owned resources

  • The actual definition uses the ⊲ P modality to avoid circularity

15

slide-50
SLIDE 50

Operational semantics: head reduction and observations

We extend reduction rules with observations: (n + m, σ) →h (n + m, σ, ǫ, ǫ) (ref(v), σ) →h (ℓ, σ ⊎ {ℓ ← v}, ǫ, ǫ) (ℓ ← w, σ ⊎ {ℓ ← v}) →h (ℓ, σ ⊎ {ℓ ← w}, ǫ, ǫ) (fork {e} , σ) →h ((), σ, e :: ǫ, ǫ) (Resolve p to v, σ) →h ((), σ, ǫ, (p, v) :: ǫ) (NewProph, σ) →h (p, σ ⊎ {p}, ǫ, ǫ) A couple of remarks:

  • Observations are only recorded on resolutions
  • State σ now records the prophecy variables in scope

16

slide-51
SLIDE 51

Extension for prophecy variables

Encoding of weakest preconditions (simplified):

wp e1 {Φ} if e1 ∈ Val then Φ(e1) else (return value) ∀σ1, κ1, κ2. S(σ1, κ1 + + κ2) reducible(e1, σ1) ∧ (progress) ∀e2, σ2, ef.

  • (e1, σ1) → (e2, σ2,

ef, κ1)

  • S(σ2,

κ2) ∗ wp e2 {Φ} ∗∗e∈

ef wp e {True}

  (preservation) S(σ, κ) • σ.1

γheap ∗ ∃Π. • Π γproph ∧ dom(Π) = σ.2 ∧

∀{p ← vs} ∈ Π. vs = filter(p, κ) (state interp.) Some more intuitions about the involved components:

  • State interpretation: holds observations yet to be made
  • Observations are removed from the list when taking steps

17

slide-52
SLIDE 52

Statement of safety and adequacy

Safety with respect to a (pure) predicate: Safeφ(e1) ∀ es, σ, κ. ([e1], ∅) →∗

tp (e2 ::

es, σ, κ) ⇒ properφ(e2, σ) ∧ ∀e ∈

  • es. properTrue(e, σ)

properψ(e, σ) (e ∈ Val ∧ ψ(e)) ∨ reducible(e, σ) Theorem (adequacy). Let e be an expression and φ be a (pure)

  • predicate. If wp e {φ} is provable then Safeφ(e).

18