Regression Verification for Multi-Threaded Programs

Post on 22-Feb-2016

51 views 0 download

description

Regression Verification for Multi-Threaded Programs. Sagar Chaki, SEI-Pittsburgh Arie Gurfinkel, SEI-Pittsburgh Ofer Strichman , Technion-Haifa Originally presented at VMCAI 2012. VSSE 2012. Regression Verification. Formal equivalence checking of two similar programs - PowerPoint PPT Presentation

transcript

11

Regression Verification

for Multi-Threaded

ProgramsSagar Chaki, SEI-Pittsburgh

Arie Gurfinkel, SEI-PittsburghOfer Strichman, Technion-Haifa

Originally presented at VMCAI 2012

VSSE 2012

22

Regression Verification

Formal equivalence checking of two similar programs

Three selling points: Specification:

– not needed Complexity:

– dominated by the change, not by the size of the programs. Invariants:

– Easy to derive automatically high-quality loop/recursion invariants

Tool support: RVT (Technion) SymDiff (MSR)

33

Possible applications of regression verification Understand how changes propagate through the API

Validate refactoring

Semantic Impact Analysis

Generic Translation Validation

Proving Determinism P is equivalent to itself , P is deterministic

many more…

44

Definition: Partial Equivalence

Let f1 and f2 be functions with equivalent I/O signature

f1 and f2 are partially equivalent , executions of f1 and f2 on equal inputs

…which terminate, result in equal outputs.

Undecidable

55

Multi-Threaded Programs (MTPs)

Finite set of root functions :

P = f1 || … || fn

• Each executed in a separate thread• Communicate via shared variables

is P partially equivalent to itself?

…no!

int base = 1;

void f1(int n, int *r) { if (n < 1) *r = base; else { int t; f1(n-1, &t); *r = n * t; }}

void f2() { base = 2;}

P

shared variable

Computes n! or 2*n!

threadthread

66

Towards partial equivalence of MTPs

P is a multi-threaded program (P): the set of terminating computations of P R(P) = { (in, out) | ∃ ∈ (P). begins in in and ends

in out}

Example:R (P) = {(n, n!), (n, 2n!) | n ∈Z }

int base = 1;

void f1(int n, int *r) { if (n < 1) *r = base; else { int t; f1(n-1, &t); *r = n * t; }}

void f2() { base = 2;}

P

77

Partial equivalence of MTPs

MTPs P1, P2 are partially equivalent if R(P1) = R(P2).

Denoted p.e.n. (P1, P2) Partial Equivalence of Nondeterministic programs

Claim: 8P. ² p.e.n.(P,P)

88

Towards a sound proof rule for

partial equivalence of MTPs

- The sequential case

- Challenges in extending it to p.e.n.

- A proof rule

99

First: The sequential case [GS’08]

Loops/recursion are not a big problem in practice:

Recursive calls are replaced with calls to the same uninterpreted function:

Abstracts the callees By construction assumes the callees are partially equivalent

Sound by induction

f1 f2=f1 f2

UF

UF

=isolation

10

First: The sequential case [GS’08]

Now we have two isolated functions f1, f2 Checking partial equivalence is decidable:

in1 = in2 = *; o1 = f1(in); o2 = f2(in); assert (o1==o2)

The algorithm traverses up the call graphs while abstracting equal callees.

How can this method be extended to proving p.e.n(f1,f2) ?

1111

f2(int in) { x1 = in; x2 = in;}

What affects partial equivalence of MTPs?

Before: in = 1o1 = 1, o2 = 0;

(1, h1, 0i) 2 R(p)

f1() { o1 = x1; o2 = x2;}

||

x1 = x2 = 0

After:in = 1o1 = 1 ) o2 = 1

(1, h1, 0i) R(p)

Swap write order

x2 = in;x1 = in;

1212

f1(int in1) { x1 = in1; t1 = x2; o1 = t1;}

f2(int in2) { t2 = x1; x2 = in2; o2 = t2;}

After: in1 = 1, in2 = 2o2 = 1 ) x1 = 1 < t2 = x1 )t1 = 0 )o1 = 0(h1,2i, h2,1i) R(p)

||

x1 = x2 = 0

Before:in1 = 1, in2 = 2x1 = 1; t2 = x1 = 1; x2 = in2 = 2;t1 = x2 = 2; o1 = t1 = 2; o2 = t2 = 1;(h1,2i, h2,1i) 2 R(p)

Swap R/W order

t1 = x2; x1 = in1;

What affects partial equivalence of MTPs?

1313

f2(int in) { x1 = in; x2 = in;}

Before: in = 1o1 = 0, o2 = 1;

(1, h0, 1i) 2 R(p)

f1() { o1 = x1; o2 = x2;}

||

x1 = x2 = 0

After:in = 1o1 = 0 ) o2 = 0

(1, h0, 1i) R(p)

Swap read order

o2 = x2;o1 = x1;

What affects partial equivalence of MTPs?

1414

Preprocessing

1. Loops ) recursive functions2. Mutual recursion ) simple recursion3. Non-recursive functions ) inlined

4. Function’s return value ) parameter5. Each shared variable x only appears in

t = x or x = exp (add auxiliaries)6. Each auxiliary variable is read once

int base = 1;

void f1(int n, int *r) { if (n < 1) *r = base; else { int t; f1(n-1, &t); *r = n * t; }}

void f2() { base = 2;}

P

1515

Mapping

Assume each function is used in a single thread. Otherwise, duplicate it

Find a mapping between the non-basic types

Find a bijective map between: threads shared variables functions (same proto-type), in mapped functions: read globals, written-to globals

Without such a mapping: goto end-of-talk.

1616

The Observable Stream

Consider a function f and input in

The observable stream of f(in)’s run is its sequence of function calls read/write of shared variables

Example: let x be a shared variable:

The observable stream:

x = in; W(x,1)t1 = t;t = x; R(x,1)g(t+1); Call(g, <2>);

x

x

x

x

1717

Observable Equivalence of Functions

Denote by observe-equiv(f,f’)

Assume: outputs are defined via shared variables Hence: observable equivalence ) partial equivalence

f, f’ are observably equivalent , 8in. f(in), f’(in) have equal sets of finite observable streams

1818

We prove observe-equiv(f,f’) by isolating f,f’. proving observ. equivalence of all (isolated) pairs

Given f, we build an isolated version [f], in which: Function calls are replaced with calls to uninterpreted

functions Shared variables are read from an “input” stream The observable stream is recorded

Observable Equivalence of Functions

1919

Reading from an input stream…

For each shared variable x: R(x) Ã R(*) // read

R(x)W(x)g(…)W(x)R(x)R(x)

R(*)

R(*)R(*)

2020

R(x)localW(x)g(…)W(x)R(x)R(x)

R(x)W(x)W(x)localg(…)R(x)localR(x)

R(*1) R(*1)

R(*2) R(*2)R(*3)

R(*3)

Enforce: equal locations ) same ‘*’ value… if their streams up to that point were equal.

Reading from an input stream…

2121

Summary: from f to [f]

Transform function f and f’ to [f] and [f’] by:

Function calls are replaced with calls to UFs– t = g() ) t = UFg()– For (g,g’) 2 map, UFg = UFg’

Shared variables are read from an “input” stream: – t = x ) t = UFx(loc) // loc is the location in the stream– For (x,x’)2 map, Ufx = Ufx’

The Observable Stream is recorded.

2222

Example: from f to [f]

int base = 1;

void f (int n, int *r) { int t; if (n < 1) { t = base; *r = t;} else { f(n-1,&t); *r = n * t; }}

read

write

write

function call

list out;

void [f] (int n, int *r) { int t, loc = 0; if (n < 1) { t = UFbase(loc); out += (R,”base”); loc++; out += (W,”r”,t); loc++;} else { t = UFf,t(n-1); out += (C,f,n-1); out += (W,”r”, n * t); loc++; }}

Output treated as shared

Observable stream

f [f]

2323

Checking observable equivalence of [f], [f’] Generate sequential program S:

in1 = in2 = *;[f(in1)];[f’(in2)];rename ([f’].out); // according to mapassert([f].out == [f’].out);

Validity of S is decidable

ff’

[f][f’]

S CBMC

2424

A Proof Rule

Compositional: check one function pair at a time

Sequential: no thread composition

General: supports loops/recursion + arbitrary # of threads

8f, f’ 2 map. observe-equiv([f], [f’])p.e.n. (P1, P2)

2525

Summary and Future Thoughts

We suggested foundations of regression verification for MTPs

• Notion of partial equivalence of multi-threaded programs• A proof rule

Challenges ahead: Synchronization primitives: Locks, semaphores, atomic

blocks Dynamic thread creation Make more complete