VPERM: Variable Permissions for Concurrency Verification Duy-Khanh Le, Wei-Ngan Chin, Yong-Meng Teo ICFEM, Kyoto, Japan, Nov 2012 Outline Motivation & Example Formalism Programming & Specification Language Verification by Entailment Checking Inferring Variable Permissions Eliminating Variable Aliasing Applicability Experiment Conclusion VPERM: Variable Permissions for Concurrency Verification 2 Motivation Access permissions attracted much attention for reasoning about shared heap data structures State-of-the-art verification tools ignore program variables or apply the same permission system, designed for heap memory, to variables However, variables are simpler than heap data structures: each variable is distinct Need a simpler reasoning scheme for variables VPERM: Variable Permissions for Concurrency Verification 3 Related Work Variables as Resource [Bornat et al. 2006] Logic + complex permissions Syntactic Control of Inference [Reddy et al. 2012] Syntactic + complex permissions Our Variable Permissions (VPERM) Logic + simple Smallfoot [Berdine et al. 2006] Syntactic + simple Expressiveness Complexity VPERM: Variable Permissions for Concurrency Verification 4 Related Work Permission systems for variables Variables as resources [1] & syntactic control of inference [2] • User fractional/counting permissions to allow sharing • Though flexible, this places higher burden on programmers to figure out the fraction used Verification systems for concurrency Smallfoot [3] uses side conditions to outlaw conflicting accesses Chalice [4] does not support permission of variables in method’s bodies Verifast [5] treats variables as heap locations VPERM: Variable Permissions for Concurrency Verification 5 Objective Propose a simple permission system to ensure data-race freedom when accessing variables VPERM: Variable Permissions for Concurrency Verification 6 A Motivating Example void inc(ref int i, int j) { i=i+j; } pass-by-ref pass-by-value int creator(ref int x,ref int y) { int tid; tid=fork(inc,x,1); inc(y,2); return tid; } void main() { int id; int x,y; x=0;y=0; id = creator(x,y); … join(id); assert (x+y=3); } 1. Any accesses to x after fork and before join are unsafe (racy) 2. How to propagate the above fact across procedure boundaries VPERM: Variable Permissions for Concurrency Verification 7 A Motivating Example with Specifications void inc(ref int i, int j) requires true ensures i'=i+j; { main thread i=i+j; } child thread void main() requires true ensures true; { int id; int x,y; x=0;y=0; id = creator(x,y); … join(id); assert (x+y=3); } int creator(ref int x, ref int y) requires true implicit ensures y’=y+2 & res=tid & thread=main and x'=x+1 & thread=tid; { int id; id=fork(inc,x,1); inc(y,2); return id; } VPERM: Variable Permissions for Concurrency Verification 8 A Motivating Example with Specifications void inc(ref int i, int j) requires true ensures i'=i+j; { main thread i=i+j; } child thread void main() requires true ensures true; { int id; int x,y; x=0;y=0; id = creator(x,y); … join(id); assert (x+y=3); } int creator(ref int x, ref int y) requires true ensures y’=y+2 & res=tid and x'=x+1 & thread=tid; { int id; id=fork(inc,x,1); inc(y,2); return id; } VPERM: Variable Permissions for Concurrency Verification 9 A Motivating Example with VPERM void inc(ref int i, int j) requires @full[i] & @value[j] ensures i'=i+j & @full[i]; { main thread i=i+j; } child thread void main() requires true ensures true; { int id; int x,y; x=0;y=0; id = creator(x,y); … join(id); assert (x+y=3); } int creator(ref int x, ref int y) requires @full[x,y] ensures @full[y] & y’=y+2 & res=tid and @full[x] & x'=x+1 & thread=tid; { int id; id=fork(inc,x,1); inc(y,2); return id; } VPERM: Variable Permissions for Concurrency Verification 10 A Motivating Example with VPERM void inc(ref int i, int j) requires @full[i] & @value[j] ensures i'=i+j & @full[i]; { i=i+j; } int creator(ref int x, ref int y) requires @full[x,y] ensures @full[y] & y’=y+2 & res=tid and @full[x] & x'=x+1 & thread=tid; { int id; // @full[x,y] & x’=x & y’=y & id’=0 } id=fork(inc,x,1); // @full[y] & y’=y & id’=tid // and @full[x] & x'=x+1 & thread=tid; inc(y,2); // @full[y] & y’=y+2 & id’=tid // and @full[x] & x'=x+1 & thread=tid; return id; // @full[y] & y’=y+2 & id’=tid & res=tid // and @full[x] & x'=x+1 & thread=tid; VPERM: Variable Permissions for Concurrency Verification main thread main thread and child thread 11 A Motivating Example with VPERM void inc(ref int i, int j) requires @full[i] & @value[j] ensures i'=i+j & @full[i]; { i=i+j; } void main() requires true ensures true; { int id; int x,y; x=0;y=0; id = creator(x,y); … join(id); assert (x+y=3); } int creator(ref int x, ref int y) requires @full[x,y] ensures @full[y] & y’=y+2 & res=tid and @full[x] & x'=x+1 & thread=tid; { int id; id=fork(inc,x,1); inc(y,2); return id; } // @full[id] // @full[id,x,y] // @full[id,x,y] // @full[id,y] and @full[x] // @full[id,y] and @full[x] // @full[id,x,y] // @full[id,x,y] VPERM: Variable Permissions for Concurrency Verification 12 Programming Language VPERM: Variable Permissions for Concurrency Verification 13 Specification Language VPERM: Variable Permissions for Concurrency Verification 14 Variable Permissions Two key annotations for variable permissions @full[w*] In a pre-condition • w* is a list of pass-by-ref variables • variable permissions are passed from caller to callee In a post-condition • variable permissions are returned from callee to caller @value[w*] In a pre-condition • w* is a list of pass-by-value variables Not exist in post-conditions VPERM: Variable Permissions for Concurrency Verification 15 Verification by Entailment Checking VPERM: Variable Permissions for Concurrency Verification 16 Entailment Rules for VPERM VPERM: Variable Permissions for Concurrency Verification 17 Soundness Proofs are in the paper VPERM: Variable Permissions for Concurrency Verification 18 Inferring Variable Permissions int creator(ref int x, ref int y) requires true ensures y’=y+2 & res=tid and x'=x+1 & thread=tid; { int id; id=fork(inc,x,1); inc(y,2); return id; } Vpost = {x,y} @full[y] , Vpost = {x} VPERM: Variable Permissions for Concurrency Verification 19 Inferring Variable Permissions int creator(ref int x, ref int y) requires true ensures y’=y+2 & res=tid and x'=x+1 & thread=tid; { int id; id=fork(inc,x,1); inc(y,2); return id; } @full[y] , Vpost = {x} @full[x] , Vpost = {} VPERM: Variable Permissions for Concurrency Verification 20 Inferring Variable Permissions int creator(ref int x, ref int y) requires true ensures y’=y+2 & res=tid and x'=x+1 & thread=tid; { int id; id=fork(inc,x,1); inc(y,2); return id; } Vpre = {x,y} @full[x,y] @full[y] @full[x] VPERM: Variable Permissions for Concurrency Verification 21 Inferring Variable Permissions int creator(ref int x, ref int y) requires true ensures y’=y+2 & res=tid and x'=x+1 & thread=tid; { int id; id=fork(inc,x,1); inc(y,2); return id; } @full[x,y] @full[y] @full[x] (*) Algorithm and Soundness in the paper VPERM: Variable Permissions for Concurrency Verification 22 Eliminating Variable Aliasing void inc(ref int i, int j) requires @full [i] ∧ @value[j] ensures @full [i] ∧ i’=i+j; { i = i + j; } void main() { int x = 0; int ∗ p = &x; int id; id = fork(inc, x, 1); ... //accesses to *p are racy join(id); } VPERM: Variable Permissions for Concurrency Verification 23 Eliminating Variable Aliasing void inc(ref int i, int j) requires @full [i] ∧ @value[j] ensures @full [i] ∧ i’=i+j; { i = i + j; } void main() { int x = 0; int ∗ p = &x; int id; id = fork(inc, x, 1); ... join(id); } // @full[x] // @full[x,p] // @full[x,p,id] // @full[p,id] // @full[p,id] // @full[x,p,id] Solution: a translation to eliminate * and & still have permission to access p and indirectly x VPERM: Variable Permissions for Concurrency Verification 24 Translation Scheme void inc(ref int i, int j) requires @full [i] ∧ @value[j] ensures @full [i] ∧ i’=i+j; { i = i + j; } void inc(int_ptr i, int j) requires i::int_ptr<old_i>& @value[i,j] ensures i::int_ptr<new_i> & new_i=old_i+j; { i.val = i.val + j; } void main() { promote int x = 0; int ∗ p = &x; int id; id = fork(inc, x, 1); ... join(id); void main() { int_ptr x = new int_ptr(0); int_ptr p = x; int id; id = fork(inc, x, 1); ... join(id); delete(x); (*) details are in the paper } } VPERM: Variable Permissions for Concurrency Verification 25 Applicability Pthread Vperm pthread_create requires a single pointer to heap memory Passing the pointer by value when fork Cilk More flexible, either pass-by-ref or pass-byvalue Pass-by-ref and passby-value VPERM: Variable Permissions for Concurrency Verification 26 Applicability: Cilk cilk int fib (int n) { if (n<=1) return n; else{ int x, y; x = spawn fib (n-1); y = spawn fib (n-2); … // not safe to access x and y sync; return (x+y); } } VPERM: Variable Permissions for Concurrency Verification 27 Applicability: Cilk cilk int fib (int n) void fib(int n, ref int result) requires @value[n] & @full [result] & n>=0 ensures @full [result] & fiba(n, result ); { { if (n<=1) return n; if (n<=1){ result = n; } else{ else{ int x, y; int x, y; x = spawn fib (n-1); int id1 = fork(fib,n−1, x); y = spawn fib (n-2); int id2 = fork(fib,n−2, y); … // not safe to access x and y … // cannot access x and y sync; join(id1); join(id2); return (x+y); result=x+y; } } } } VPERM: Variable Permissions for Concurrency Verification 28 Experiments Trade-off: higher verification time (machine effort) BUT less manual annotation (human effort). Download or try VPERM online at http://loris-7.ddns.comp.nus.edu.sg/~project/vperm/ VPERM: Variable Permissions for Concurrency Verification 29 Conclusion A simple permission system for variables Simple to understand Simple to reason about Simple to infer Expressive enough to capture real-world programming languages such as Pthreads, Cilk Feasible to incorporate into a tool VPERM Experiments show less annotation overheads compared to state-of-the-art VPERM: Variable Permissions for Concurrency Verification 30 Q&A THANK YOU leduykha@comp.nus.edu.sg Download or try VPERM online at http://loris-7.ddns.comp.nus.edu.sg/~project/vperm/ END VPERM: Variable Permissions for Concurrency Verification 31 Limitations Phased Accesses to Shared Variables Read outside a critical region but write inside a critical region This requires partial permissions BUT we could use pseudo-heap locations for this type of complex reasoning VPERM: Variable Permissions for Concurrency Verification 32 Phased Accesses inv<x,a,b> := @full[x] & @half[a,b] & x=a+b; int x=0; int a = 0; int b = 0; lock l; //@full[x,a,b,l] init(l); //@full[l] & half[a,b] // l is passed by value to child thread //full[l] & half[a] acquire(l); //full[l,x,a] & half[b] x = x +1; a = 1; //full[l,x,a] & half[b] release(l); //full[l] & half[a] //full[l] & half[b] acquire(l); //full[l,x,b] & half[a] x = x +1; b = 1; //full[l,x,b] & half[a] release(l); //full[l] & half[b] //@full[l] & half[a,b] assert(x’=2); For this complex reasoning, convert two integer auxiliary variables a,b to int_ptr and use the complex reasoning over heap Phased Accesses inv<x,a,b> := @full[x] & x=a.val+b.val; int x=0; int_ptr a = new int_ptr(0); int_ptr b = new int_ptr(0); lock l; //@full[x,a,b,l] init(l); //@full[l] & half[a,b] // l,a,b is passed by value to child thread //a::int_ptr(1/2)<> & full[l,a] acquire(l); //full[l,x,a] & half[b] x = x +1; a.val = 1; //full[l,x,a] & half[b] release(l); //full[l] & half[a] //full[l] & half[b] acquire(l); //full[l,x,b] & half[a] x = x +1; b.val = 1; //full[l,x,b] & half[a] release(l); //full[l] & half[b] //@full[l] & half[a,b] assert(x’=2); For this complex reasoning, convert two integer auxiliary variables a,b to int_ptr and use the complex reasoning over heap Verification by Entailment Checking (Full) VPERM: Variable Permissions for Concurrency Verification 35 Background Heap vs stack x1 A stack variable x pointing to A heap location containing an integer E.g. int_ptr x = new int_ptr(1); Separation logic {x2 * y2} [x]=3 {x3 * y2} Fractional permissions 0.5 0.5 1.0 {x2 * x2} {x2} How about program (stack) variables? VPERM: Variable Permissions for Concurrency Verification 36 Background Heap vs stack x1 A stack variable x pointing to A heap location containing an integer 1 E.g. int_ptr x = new int_ptr(1); Hoare’s logic {x1 /\ y2} x=3 {x3 /\ y2} {x2 /\ y2} x=3 {x3 /\ y2} ok what if x and y aliased ??? Separation logic {x2 * y2} x=3 {x3 * y2} no alias Fractional permissions {x2 * x2} {x2} VPERM: Variable Permissions for Concurrency Verification 37