70
Levels of Reasoning • propositional p 1 = q 1 p 2 = q 2 . . . p n = q n p = q • schematic (1 st order uninterpreted) x := s ; x := t = x := t[x/s] •1 st order interpreted i j j k i k

Levels of Reasoning propositional p 1 = q 1 p 2 = q 2 ... p n = q n p = q schematic (1 st order uninterpreted) x := s ; x := t = x := t[x/s] 1 st

  • View
    222

  • Download
    4

Embed Size (px)

Citation preview

Levels of Reasoning

• propositionalp1 = q1 p2 = q2 . . . pn = qn p = q

• schematic (1st order uninterpreted)x := s ; x := t = x := t[x/s]

• 1st order interpretedi j j k i k

Schematic KAT (SKAT)

x := s ; y := t = y := t[x/s] ; x := s y FV(s)

x := s ; y := t = x := s ; y := t[x/s] x FV(s)

x := s ; x := t = x := t[x/s]

b[x/t] ; x := t = x := t ; b

x := x = 1

Schematic KAT

x := s ; y := t = y := t ; x := s x FV(t), y FV(s)

b ; x := t = x := t ; b x FV(b)

Relation to Hoare Assignment Rule

b[x/t] ; x := t x := t ; b

is equivalent to

{b[x/t]} x := t {b}

b[x/t] ; x := t = x := t ; b

is equivalent to the conjunction of

{b[x/t]} x := t {b} {~b[x/t]} x := t {~b}

• universal Horn logic

p1 = q1 p2 = q2 . . . pn = qn p = q

• premises pi = qi

− self-evident assumptions about local behavior

− typically involve atomic instructions and tests

• conclusion p = q

− equivalence of original program and optimized or

annotated program

• use schematic and interpreted reasoning only to

establish validity of premises – most reasoning done

at the propositional level

Reasoning with KAT

Compiler Optimizations[Kozen & Patron 00]

• dead code elimination

• common subexpression elimination

• copy propagation

• loop hoisting

• loop unrolling

• reducing nesting depth

• induction variable elimination

• instruction scheduling

• algebraic simplification

• elimination of redundant instructions

• array bounds check elimination

• introduction of sentinels

Typical Premises

“two instructions that do not affect each other can be

done in either order”

load r1,x ; load r2,y = load r2,y ; load r1,x

“after loading a value in a register, that register

contains that value”

load r1,x = load r1,x ; r1=x p = pb

“no need to load a value if the register already

contains that value”

r1=x ; load r1,x = r1=x bp = b

Loop Hoisting

for (i = 0; i < n; i++) {

b[i] = x;

}

i := 0

: test i < n

jump if false

load r,x

store r,b[i]

i := i + 1

jump

:

Loop Hoisting

for (i = 0; i < n; i++) {

b[i] = x;

}

i := 0

: test i < n

jump if false

load r,x

store r,b[i]

i := i + 1

jump

:

This is of the form w(cupv)*c

p = load r,x b = r=x

load r,x = load r,x ; r=x p = pb

bpp

r=x ; load r,x = r=x bp = b

b p b

ub = bu

vb = bv

p = pb bp = b ub = bu vb = bv

w(cupv)*c = w(cupv(cubv)*c + c)

Suffices to show

p = pb bp = b ub = bu vb = bv

(cupv)* = cupv(cubv)* + 1

p = pb bp = b ub = bu vb = bv

(cupv)* = cupv(cubv)* + 1

(cupv)* = (cupv)*

p = pb bp = b ub = bu vb = bv

(cupv)* = cupv(cubv)* + 1

(cupv)* = cupv(cupv)* + 1

p = pb bp = b ub = bu vb = bv

(cupv)* = cupv(cubv)* + 1

(cupv)* = cupbv(cupv)* + 1

p = pb bp = b ub = bu vb = bv

(cupv)* = cupv(cubv)* + 1

(cupv)* = cupbv(cupbv)* + 1

p = pb bp = b ub = bu vb = bv

(cupv)* = cupv(cubv)* + 1

(cupv)* = cupb(vcupb)*v + 1

p = pb bp = b ub = bu vb = bv

(cupv)* = cupv(cubv)* + 1

(cupv)* = cup(bvcup)*bv + 1

p = pb bp = b ub = bu vb = bv

(cupv)* = cupv(cubv)* + 1

(cupv)* = cup(vbcup)*bv + 1

p = pb bp = b ub = bu vb = bv

(cupv)* = cupv(cubv)* + 1

(cupv)* = cup(vcbup)*bv + 1

p = pb bp = b ub = bu vb = bv

(cupv)* = cupv(cubv)* + 1

(cupv)* = cup(vcubp)*bv + 1

p = pb bp = b ub = bu vb = bv

(cupv)* = cupv(cubv)* + 1

(cupv)* = cup(vcub)*bv + 1

p = pb bp = b ub = bu vb = bv

(cupv)* = cupv(cubv)* + 1

(cupv)* = cup(vcbu)*bv + 1

p = pb bp = b ub = bu vb = bv

(cupv)* = cupv(cubv)* + 1

(cupv)* = cup(vbcu)*bv + 1

p = pb bp = b ub = bu vb = bv

(cupv)* = cupv(cubv)* + 1

(cupv)* = cup(bvcu)*bv + 1

p = pb bp = b ub = bu vb = bv

(cupv)* = cupv(cubv)* + 1

(cupv)* = cupb(vcub)*v + 1

p = pb bp = b ub = bu vb = bv

(cupv)* = cupv(cubv)* + 1

(cupv)* = cupbv(cubv)* + 1

p = pb bp = b ub = bu vb = bv

(cupv)* = cupv(cubv)* + 1

(cupv)* = cupv(cubv)* + 1

Loop Unrolling

while b do { while b do { p; p;} if b then p;

}

(bp)*b = (bp(bp + b))*b

Key lemma q* = (qn)*(1 + q)n-1

Array Bounds Check Elimination

for (i = 0; i < x.length; i++) { x[i] := e(i);

}

i := 0: test i < n

jump if falsecompute e(i) if i out of bounds then errorx[i] := e(i) i := i + 1jump

:

Array Bounds Check Elimination

for (i = 0; i < x.length; i++) { x[i] := e(i);

}

i := 0: test i < n

jump if falsecompute e(i) if i out of bounds then errorx[i] := e(i) i := i + 1jump

:

Array Bounds Check Elimination

a = 0 i b = i < x.length c = ab i is in bounds

We have to prove

u(bp(cq + cs)v)*b = u(bpqv)*b

Introduce a using u = ua, show a and b (and therefore c) hold where needed to eliminate the array bounds check

LU Decomposition with Pivoting[Mateev, Menon, Pingali 01]

• Restructuring of matrix operations to take advantage of locality

• Def/use analysis fails: transformations break def/use dependencies

• MMP develop a new technique, fractal symbolic analysis

y = x; x = 2*x;y = 2*y; y = 2*y;x = 2*x; y = x;

y = x; x = 2*x;y = 2*y; y = 2*y;x = 2*x; y = x;

y = 2*x;x = 2*x;

x := s ; x := t = x := t[x/s]

y = x; x = 2*x;y = 2*y; y = 2*y;x = 2*x; y = x;

y = 2*x; x = 2*x;x = 2*x; y = x;

x := s ; x := t = x := t[x/s]

y = x; x = 2*x;y = 2*y; y = 2*y;x = 2*x; y = x;

y = 2*x; x = 2*x;x = 2*x; y = x;

x := s ; y := t = y := t[x/s] ; x := s

y FV(s)

for (j = 0; j < n-1; j++) {tmp = a[j]; //swapa[j] = a[j+1];a[j+1] = tmp;for (i = j+1; i < n; i++) {

a[i] = a[i]/a[j]; //update}

}

for (j = 0; j < n-1; j++) {tmp = a[j]; //swapa[j] = a[j+1];a[j+1] = tmp;

}for (j = 0; j < n-1; j++) {

for (i = j+1; i < n; i++) {a[i] = a[i]/a[j]; //update

}}

for (j = 0; j < n-1; j++) {swap(j,j+1);

for (i = j+1; i < n; i++) {update(i,j);

}}

for (j = 0; j < n-1; j++) {swap(j,j+1);

}for (j = 0; j < n-1; j++) {

for (i = j+1; i < n; i++) {update(i,j);

}}

k < i < j

update(i,k); swap(i,j);update(j,k); = update(i,k);swap(i,j); update(j,k);

k > j

swap(k,k+1);for (i = j+1; i < n; i++) {

update(i,j);}

=

for (i = j+1; i < n; i++) {update(i,j);

}swap(k,k+1);

Key Lemma pq = qp pq* = q*p

for (j = 0; j < n-1; j++) {swap(j,j+1);for (i = j+1; i < n; i++) {

update(i,j);}

}

for (j = 0; j < n-1; j++) {swap(j,j+1);

}for (j = 0; j < n-1; j++) {

for (i = j+1; i < n; i++) {update(i,j);

}}

Key Lemma pq = qp p*q* = (pq)*(p* + q*)

start

y1 := x

y4 := f(y1)

y1 := f(y1)

y2 := g(y1,y4)

y3 := g(y1,y1)

P(y1)

y1 := f(y3)

P(y4)

P(y2)

y2 := f(y2) P(y3)

z := y2

halt

T

T

T

TF

F

F

F

start

y := f(x)

loop

P(y)

y := g(y,y)

P(y)

y2 := f(f(y)) z := y

halt

T

T

F

F

SchemeEquivalence

Example of Paterson

from [Manna 74]

x1p41p11q214q311(a1p11q214q311)*a1p13

((a4+a4(a2p22)*a2a3p41p11) q214q311(a1p11q214q311)*a1p13)*

a4(a2p22)*a2a3z2z

saq(araq)*az

x1 p41 p11 q214 q311 a1 p13 a4 a2 a3 z2

p22

a1

a4

a2

a3

s q a

r

z

a

a

Kleene’s Theorem

Static Analysis

• Derivation of information about the execution state at various points in a program at compile time or load time, prior to execution

• Approaches– type inference– dataflow analysis– abstract interpretation– set constraints

• Applications– code optimization– verification

Software Model Checking withSLAM

Thomas BallTesting, Verification and Measurement

Sriram K. RajamaniSoftware Productivity Tools

Microsoft Research

http://research.microsoft.com/slam/

State Machine for Locking

Unlocked Locked

Error

Rel Acq

Acq

Rel

state {

enum {Locked,Unlocked}

s = Unlocked;

}

KeAcquireSpinLock.entry {

if (s==Locked) abort;

else s = Locked;

}

KeReleaseSpinLock.entry {

if (s==Unlocked) abort;

else s = Unlocked;

}

Locking Rule in SLIC

do {KeAcquireSpinLock();

nPacketsOld = nPackets;

if(request){request = request->Next;KeReleaseSpinLock();nPackets++;

}} while (nPackets != nPacketsOld);

KeReleaseSpinLock();

ExampleDoes this code

obey the locking rule?

do {KeAcquireSpinLock();

if(*){

KeReleaseSpinLock();

}} while (*);

KeReleaseSpinLock();

ExampleModel checking boolean program

(bebop)

U

L

L

L

L

U

L

U

U

U

E

do {KeAcquireSpinLock();

nPacketsOld = nPackets;

if(request){request = request->Next;KeReleaseSpinLock();nPackets++;

}} while (nPackets != nPacketsOld);

KeReleaseSpinLock();

ExampleIs error path feasible

in C program?(newton)

U

L

L

L

L

U

L

U

U

U

E

do {KeAcquireSpinLock();

nPacketsOld = nPackets; b = true;

if(request){request = request->Next;KeReleaseSpinLock();nPackets++; b = b ? false : *;

}} while (nPackets != nPacketsOld); !b

KeReleaseSpinLock();

ExampleAdd new predicateto boolean program

(c2bp)b : (nPacketsOld == nPackets)

U

L

L

L

L

U

L

U

U

U

E

do {KeAcquireSpinLock();

b = true;

if(*){

KeReleaseSpinLock();b = b ? false : *;

}} while ( !b );

KeReleaseSpinLock();

b

b

b

b

ExampleModel checking

refined boolean program

(bebop)

b : (nPacketsOld == nPackets)

U

L

L

L

L

U

L

U

U

U

E

b

b

!b

Example

do {KeAcquireSpinLock();

b = true;

if(*){

KeReleaseSpinLock();b = b ? false : *;

}} while ( !b );

KeReleaseSpinLock();

b : (nPacketsOld == nPackets)

b

b

b

b

U

L

L

L

L

U

L

U

U

b

b

!b

Model checking refined

boolean program(bebop)

do { KeAcquireSpinLock(); nPacketsOld = nPackets; if (request) { request = request->Next; KeReleaseSpinLock(); nPackets++; } } while (nPackets != nPacketsOld); KeReleaseSpinLock();

do { kA; n; if (R) { u; kR; m; } } while (~B); kR;

do { kA; n; if (R) { do p while C u; = p;(C;p)*;~C kR; m; if C then p } = C;p + ~C } while (~B); kR;

do { kA; n; if (R) { do p while C u; = p;(C;p)*;~C kR; m; if C then p } = C;p + ~C } while (~B); kR;

kA;n;(R;u;kR;m + ~R); (~B;kA;n;(R;u;kR;m + ~R))*;B;kR

Preconditions for safe execution

operation preconditionkA (acquire) ~A (unlocked)kR (release) A (locked)Global precondition: initially unlocked

Original program

~A;kA;n;(R;u;kR;m + ~R);(~B;kA;n;(R;u;kR;m + ~R))*;B;kR

Annotated program

~A;~A;kA;n;(R;u;A;kR;m + ~R);(~B;~A;kA;n;(R;u;A;kR;m + ~R))*;B;A;kR

kA = kA;A - acquiring the lock acquires itkR = kR;~A - releasing the lock releases itB;m = B;m;~B - if two integer variables are

equal and we increment one, then they are no longer equal

n = n;B - setting one variable equal to another makes them equal

A;n = n;A - commutativity conditionsA;u = u;AA;m = m;AB;u = u;BB;kR = kR;B

kA = kA;A kR = kR;~A B;m = B;m;~B n = n;B A;n = n;A A;u = u;A A;m = m;A B;u = u;B B;kR = kR;B

~A;kA;n;(R;u;kR;m + ~R);(~B;kA;n;(R;u;kR;m + ~R))*;B;kR

=~A;~A;kA;n;(R;u;A;kR;m + ~R);(~B;~A;kA;n;(R;u;A;kR;m + ~R))*;B;A;kR

Security Automata [Schneider 98]

• general mechanism for specification and runtime enforcement of safety policies

• policy is specified by a finite automaton M• code is instrumented to call M before all

critical operations (ones that could change state of M )

• M aborts the computation if the operation causes a transition to an error state

• can handle all safety properties

read

send

send

read

errorstart

Example

no sendafter read

read

send

send

read

error

• code is instrumented to call M before each read and send instruction

• purely a runtime mechanism

start

Security Automata and KATUse KAT to do static analysis to eliminate unnecessary calls to M

• assertion U for each state of M

• premises AM :

• UV = 0 for U ≠ V

• Up pV for each atomic transition U V

• Up pU if p is noncritical

• start state S, error states E

p

Prefixes

Pre(r) = an expression representing prefixes of computations of r. Defined inductively:

Pre(p) = 1 + p p an atomic actionPre(b) = 1 b a testPre(pq) = Pre(p) + p;Pre(q)Pre(p + q) = Pre(p) + Pre(q)Pre(p*) = p*;Pre(p)

This is a closure operator in the sense thatPre(Pre(p)) = Pre(p) is a theorem of KAT

Eliminating Runtime Checks

Soundness Theorem Let D be any set of premises over P,B, and let r be any program over P,B. If

D AM S·Pre(r) (~E·ΣP)*·~E

is a theorem of KAT, then r is safe with respect to M in any Kripke frame whose trace algebra satisfies D.

Completeness Theorem The converse holds as well, provided D is finite and all elements of D are of the form p = 0.

2nd-Order Abstract Interpretation

Let L be an upper semilattice such that all ascending chains are finite (ACC). Elements are called types or abstract values.

Associated with each atomic action p is a strict, partial, finitely additive map fp : L L called its transfer function.

Take premises Xp p fp(X) and propagate information as before (ACC needed for *).

Types or Abstract Values

• Represent sets of values– statically derivable– conservative approximation

• Form a partial semilattice– higher = less specific– join does not exist = type error

Example: Java Bytecode

Object

Array [ ]

Integer Continuations

Array [ ][ ] …Interface

implements

Useless

Null

Java class

hierarchy

int, short, byte,

boolean, char

Example: Java Bytecode

local variable array

operand stack

this p0 p1 p2

parameters other locals

maxLocals

maxS

tack

= reference type= integer= continuation

StringHash-

tableObject

String-

Buffer

User-

Classint[ ]

= useless

Example of a Transfer Function

0 1 2 3 4 5 6 7

loca

lsst

ack

0 1 2 3 4 5 6 7

loca

lsst

ack

iload 3

Preconditions for safe execution:

• local 3 is an integer• stack is not full

Effect:• push integer in local 3 on stack

Work in Progress

• Second-order abstract interpretation [Kot]• Equational theory of arrays [Aboul-Hosn]• KAT-ML [Aboul-Hosn]