RGSep action inference Viktor Vafeiadis Microsoft Research - - PowerPoint PPT Presentation

rgsep action inference
SMART_READER_LITE
LIVE PREVIEW

RGSep action inference Viktor Vafeiadis Microsoft Research - - PowerPoint PPT Presentation

RGSep action inference Viktor Vafeiadis Microsoft Research Cambridge/ University of Cambridge Michael & Scott non-blocking queue head tail null X 1 2 3 4 typedef struct Node_s *Node; struct Queue_s *Q; struct Node_s { init() { int


slide-1
SLIDE 1

RGSep action inference

Viktor Vafeiadis Microsoft Research Cambridge/ University of Cambridge

slide-2
SLIDE 2

Michael & Scott non-blocking queue

X 1 3 4

null

2 head tail

typedef struct Node_s *Node; struct Node_s { int val; Node next; } struct Queue_s { Node head; Node tail; } struct Queue_s *Q; init() { n = new Node(); n→next = null; Q = new Queue(); Q→head = node; Q→tail = node; }

slide-3
SLIDE 3

A slight complication...

The tail pointer can lag behind by one node: Except when the queue is empty:

Y X

null

head tail X 1 3

null

2 head tail

slide-4
SLIDE 4

Enqueue & dequeue

enqueue(v) { m = new Node(); m→val = v; m→next = null; while (true) { t = Q→tail; n = tail→next; if (Q→tail ≠ tail) continue; if (next == null) { if (CAS(&t→next,n,m)) break; } else { CAS(&Q→tail,t,n); } } CAS(&Q→tail,t,n); }

dequeue () { while (true) { h = Q→head; t = Q→tail; n = h→next; if (Q→tail ≠ t) continue; if (h == t) { if (n == null) return EMPTY; CAS(&Q→tail,t,n); } else { if (CAS(&Q→head,h,n)) return n→val; } } }

Don’t read the code!

slide-5
SLIDE 5

Verification challenge

Functional correctness: Every method executes ‘atomically’ and obeys a high-level specification Liveness properties, e.g. lock-freedom: At all times, some outstanding method call is guaranteed to terminate. But first, do shape analysis to: (1) Find data structure invariants (2) Prove memory safety

VMCAI ’09

work in progress

POPL ’09

this talk

slide-6
SLIDE 6

RGSep

Combining rely-guarantee and separation logic

slide-7
SLIDE 7

Whence RGSep?

Separation logic:

  • Good at describing dynamically allocated data

structures ∃h t. Q↦head:h,tail:t ∗ lseg(h,t) ∗ t↦next:null Rely-guarantee:

  • Good at reasoning about concurrency
  • Describes interference between threads:

how the state evolves null

head tail

slide-8
SLIDE 8

Local & shared assertions

Logically divide the state into:

  • Local: only one thread can access it
  • Shared: any thread can access it.

RGSep assertions: p, q ::= (Plocal ¦ PShared) | p1 ∨ p2 | ∃x. p

normal separation logic assertions (about the local & shared state respectively)

slide-9
SLIDE 9

Rely-guarantee specifications

R,G ⊢RGSep {p} cmd {q}

Rely: interference

caused by environment; Describes how the environment is allowed to change the shared state

Guarantee:

interference caused by the program. Describes how the program is allowed to change the shared state.

precondition postcondition

slide-10
SLIDE 10

RGSep actions (pre-/postcondition pairs)

  • Summarize the shared state updates

A B

null

head tail A B head tail A B head tail A

null

head tail A B head tail A B head tail Enqueue Dequeue Advance tail pointer

slide-11
SLIDE 11

RGSep actions (pre-/postcondition & context)

  • Summarize the shared state updates

A B

null

head tail A B head tail A B head tail A

null

head tail A B head tail A B head tail Enqueue Dequeue Advance tail pointer

slide-12
SLIDE 12

The actions of enqueue & dequeue

enqueue(v) { m = new Node(); m→val = v; m→next = null; while (true) { t = Q→tail; n = tail→next; if (Q→tail ≠ tail) continue; if (next == null) { if (CAS(&t→next,n,m)) break; } else { CAS(&Q→tail,t,n); } } CAS(&Q→tail,t,n); }

dequeue () { while (true) { h = Q→head; t = Q→tail; n = h→next; if (Q→tail ≠ t) continue; if (h == t) { if (n == null) return EMPTY; CAS(&Q→tail,t,n); } else { if (CAS(&Q→head,h,n)) return n→val; } } }

ENQUEUE DEQUEUE

  • ADV. TAIL
  • ADV. TAIL
  • ADV. TAIL

Local updates

slide-13
SLIDE 13

The semantics of actions

[[R|P↝Q]] ≝ {(s⊎sctx , s’⊎sctx) | ∃I. [[P]]I(s) ∧ [[Q]]I(s’) ∧ [[R∗true]]I(sctx) }

R & G are sets of such actions:

[[{a1,...an}]] ≝ ([[a1]] ∪ ... ∪ [[an]])*

precondition postcondition context

slide-14
SLIDE 14

Action Inference

slide-15
SLIDE 15

The action inference problem

  • Given cmd, R, p: find G, q s.t.

R, G ⊢RGSep {p} cmd {q}. Preferably, the strongest G and q

  • Top-level programs:

R = ∅ and p = true.

  • Libraries; the most general client:

init(); ‖? { if(?) enqueue(?) else if(?) dequeue() else length() }

slide-16
SLIDE 16

(Must)-Subtraction

a.k.a. entailment with frame inference SUBTRACT(P, Q, xs) returns R such that [[P]]I(s) ⇒ ∃s1s2vs. s=s1⊎s2 ∧ [[Q]]I[xs→vs](s1) ∧ [[R]]I[xs→vs](s2),

  • r fails if no such an R exists, or because if cannot find it.

Used to calculate postcondition of normal commands. Given precondition P & command with spec {Po} _ {Qo}, the postcondition is: SUBTRACT(P, Po) ∗ Qo

slide-17
SLIDE 17

May-Subtraction

MAY-SUBTRACT(P, Q, R) returns R’ such that [[P]]I(s1⊎s2) ∧ [[Q]]I(s1) ∧ [[R∗true]]I(s2) ⇒ [[R’]]I(s2)

  • Generalization of septraction (existential magic wand)
  • Used to calculate postcondition after interference.

Given precondition P and an action (Ro | Po↝ Qo), the postcondition is: MAY-SUBTRACT(P, Po, Ro) ∗ Qo

slide-18
SLIDE 18

Examples

SUBTRACT(a ↦ 3 ∗ b ↦ 4, a ↦ x, {}) = Error! SUBTRACT(a ↦ 3 ∗ b ↦ 4, a ↦ x, {x}) = b ↦ 4 ∗ (x = 3) MAY-SUBTRACT(a ↦ 3, a ↦ x, emp) = (x = 3) MAY-SUBTRACT(a ↦ 3, emp, a ↦ x) = a ↦ 3 ∗ (x = 3) MAY-SUBTRACT(a ↦ 3 ∗ b ↦ 4, x ↦ y, emp) = b ↦ 4 ∗ (x = a) ∗ (y = 3) ∨ a ↦ 3 ∗ (x = b) ∗ (y = 4)

slide-19
SLIDE 19

Stabilization

  • Calculate the efgect of interference on an assertion:
  • verapproximate P; Rely*

repeat Pold := P; for each Ri|Pi↝Qi in Rely do P := P ∨ MAY-SUBTRACT(Pold, Pi , Ri) ∗ Qi ; until (P = Pold)

slide-20
SLIDE 20

Symbolic execution of memory reads

SYMB-EXEC (Rely, p1 ∨ p2, x=*E) ≝

// Do the obvious case split...

(G1, q1) := SYMB-EXEC (Rely, p1, x=*E); (G2, q2) := SYMB-EXEC (Rely, p2, x=*E); return (G1 ∪ G2 , q1 ∨ q2) SYMB-EXEC (Rely, (PL ¦ PS), x=*E) ≝

// Is it a local read?

if SUBTRACT(PL , ∃α. E↦α) = RL then return (∅, (∃αβ. x=α ∗ E[β/x]↦α ∗ RL[β/x] ¦ PS[β/x]))

// Is it a shared read?

else if SUBTRACT(PS , ∃α. E↦α) = RS then return (∅, (∃αβ. x=α ∗ E[β/x]↦α ∗ PL[β/x] ¦ RS[β/x])) else Verification-Error

R, G1 ⊢ {p1} C {q1} R, G2 ⊢ {p2} C {q2} R, G1∪G2 ⊢ {p1∨p2} C {q1∨q2} {∃α. E↦α ∗ R} x=*E {∃αβ. E[β/x]↦α ∗ x=α ∗ R[β/x]}

slide-21
SLIDE 21

Symbolic execution of memory writes

SYMB-EXEC (Rely, (PL ¦ PS), *E=E’) ≝

// Is it a local write?

if SUBTRACT(PL , ∃α. E↦α) = RL then return (∅, (E↦E’ ∗ RL ¦ PS))

// Is it a shared write?

else if SUBTRACT(PS , ∃α. E↦α) = RS then

// Anything in the local state reachable from E’ becomes shared

(PL2S, PL) := REACHABLE-SPLIT (PL , E↦E’); act := (RS | E↦α ↝ E↦E’ ∗ PL2S); q := (PL ¦ E↦E’ ∗ PL2S ∗ RS);

// Abstract the action & return

return ({A-ABS(act)}, q) else Verification-Error

{∃α. E↦α ∗ R} *E=E’ {E↦E’ ∗ R} Transfer of ownership Local to shared

slide-22
SLIDE 22

Dealing with the parallel composition

Fixed point calculation:

  • Start with G = ∅.

Symbolically execute cmd and get new G’.

  • Extend G with G’ and repeat until G’=G.

R ∪ G , G ⊢ {p} cmd {q} R, G ⊢ {p} cmd∥cmd {q}

slide-23
SLIDE 23

Action abstraction

  • Abstraction. Given an action (C | P ↝ Q), return (C’ | P’ ↝ Q’)

such that [[C | P ↝ Q]] ⊆ [[C’ | P’ ↝ Q’]].

  • Replace local variables with fresh logical variables.
  • Abstract C, P, Q separately.
  • For locking and unlocking actions, let C’=emp.
slide-24
SLIDE 24

Initial experiments

Algorithm Iter Actions Time (s) Treiber stack 4 5 0.1 M&S two-lock queue 5 26 0.3 M&S non-blocking queue 5 10 1.7 DGLM non-blocking queue 5 12 2.2 Lock-coupling list 4 21 1.0 Optimistic list 5 30 109.1 Lazy list 5 48 60.0 Vechev’s CAS list 3 9 24.7 Vechev’s DCAS list 2 6 0.3

Too many actions

slide-25
SLIDE 25

Lossless join on action sets

  • Given action sets X & Y, return Z s.t. [[Z]] = [[X ∪ Y]].
  • Don’t do Z=X∪Y, but try to find a Z with fewer elements.

Approximation to inclusion. (C1|P1↝Q1) ⊑ (C2|P2↝Q2)

  • Exists substitution σ of the logical variables such that

P1 = σ(P2) and Q1 = σ(Q2) and C1 ⊢ σ(C2) ∗ true

  • If (C1|P1↝Q1) ⊑ (C2|P2↝Q2), then [[C1|P1↝Q1]] ⊆ [[C2|P2↝Q2]].

Lossless join. JOIN(A,{b}) ≝ if ∃a∊A. b ⊑ a then A else {b} ∪ {a∊A|a⋢b} JOIN(A,{b1,...,bn}) ≝ JOIN(...(JOIN(JOIN(A, {b1}),{b2})...),{bn})

slide-26
SLIDE 26

Experiments

Algorithm Iter Actions Time (s) Iter Actions Time (s) Treiber stack 4 5 0.1 4 2 0.1 M&S two-lock queue 5 26 0.3 5 12 0.3 M&S non-blocking queue 5 10 1.7 5 6 1.5 DGLM non-blocking queue 5 12 2.2 5 8 2.0 Lock-coupling list 4 21 1.0 3 10 0.8 Optimistic list 5 30 109.1 3 10 52.3 Lazy list 5 48 60.0 4 13 26.2 Vechev’s CAS list 3 9 24.7 3 5 8.8 Vechev’s DCAS list 2 6 0.3 3 4 0.3

Run action inference, finding data structure invariants & proving memory safety. Iter: number of iterations for finding the rely-guarantee specs of each thread. Actions: number of actions inferred.

No join With lossless join

slide-27
SLIDE 27

Future work

  • Other uses of action inference
  • Improve underlying abstract domains
  • More data structures / properties
  • Better performance
  • Less heuristic-based ownership transfer