25.07.2013 Views

Deductive Verification of System Software in the Verisoft XT Project

Deductive Verification of System Software in the Verisoft XT Project

Deductive Verification of System Software in the Verisoft XT Project

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

step consists <strong>of</strong> two parts: (a) <strong>the</strong> BoogiePL code that results<br />

from compil<strong>in</strong>g <strong>the</strong> orig<strong>in</strong>al C source (<strong>in</strong>clud<strong>in</strong>g annotations) and<br />

(b) axiomatic descriptions (<strong>in</strong> BoogiePL syntax) <strong>of</strong> certa<strong>in</strong> aspects<br />

<strong>of</strong> <strong>the</strong> C programm<strong>in</strong>g language, called <strong>the</strong> BoogiePL prelude.<br />

The annotated BoogiePL program toge<strong>the</strong>r with <strong>the</strong> prelude<br />

is <strong>the</strong>n transformed <strong>in</strong>to first-order predicate logic formulas<br />

(verification conditions), which state that <strong>the</strong> program satisfies<br />

<strong>the</strong> annotated specification. (3) These verification conditions<br />

are given to <strong>the</strong> automatic <strong>the</strong>orem prover (SMT solver) Z3 [7]<br />

to check whe<strong>the</strong>r <strong>the</strong>y are valid, which <strong>the</strong>n implies that <strong>the</strong><br />

orig<strong>in</strong>al C program is correct w.r.t. <strong>the</strong> annotated specification.<br />

The possible results Z3 may return are: (1) The formulas are<br />

valid (Z3 has found a pro<strong>of</strong>). (2) At least one <strong>of</strong> <strong>the</strong> formulas<br />

is not valid (Z3 has found a counter-example). (3) Z3 runs out<br />

<strong>of</strong> resources (time or space). In Case (1) above, <strong>the</strong> program<br />

verification was successful. In Cases (2) and (3), <strong>the</strong> verification<br />

eng<strong>in</strong>eer has to analyse <strong>the</strong> problem and correct <strong>the</strong> error. In<br />

Case (2), <strong>the</strong> counter-example, which can be thought <strong>of</strong> as an<br />

execution trace, can be visualized us<strong>in</strong>g a VCC-specific tool with<br />

debugger-like <strong>in</strong>terface. In Case (3), one may also f<strong>in</strong>d that <strong>the</strong><br />

program <strong>in</strong>deed satisfies <strong>the</strong> annotations. Then new annotations<br />

(stronger <strong>in</strong>variants, helpful lemmas, etc.) have to be added.<br />

This process is repeated until a pro<strong>of</strong> is found.<br />

Annotation Language. The annotation language <strong>of</strong> VCC is<br />

guarded by C preprocessor macros. When verify<strong>in</strong>g, a flag is<br />

set so that <strong>the</strong>se macros evaluate to keywords specific to VCC,<br />

which <strong>in</strong> turn generates <strong>the</strong> correspond<strong>in</strong>g BoogiePL code out <strong>of</strong><br />

<strong>the</strong>m. If a normal C compiler is used (without this flag), all annotations<br />

evaluate to <strong>the</strong> empty str<strong>in</strong>g, so that <strong>the</strong> annotations<br />

are transparent for <strong>the</strong> compilation process.<br />

The VCC annotation language consists <strong>of</strong> side-effect-free C<br />

expressions, extended with first-order quantification, lambda expressions,<br />

and a number <strong>of</strong> constructs used to attach specifications<br />

to exist<strong>in</strong>g C constructs, e.g., to attach function contracts<br />

to function declarations, loop <strong>in</strong>variants to loops and so forth.<br />

Additionally one can also place explicit assertions <strong>in</strong> <strong>the</strong> runn<strong>in</strong>g<br />

code, e.g., to help <strong>in</strong> debugg<strong>in</strong>g specifications.<br />

Modularity. <strong>Verification</strong> <strong>in</strong> VCC is modular, both with respect<br />

to threads and functions. Functions are equipped with contracts<br />

<strong>in</strong> form <strong>of</strong> pre- and post-conditions, giv<strong>in</strong>g all necessary conditions<br />

to call <strong>the</strong> function and <strong>the</strong> guarantees on <strong>the</strong> state, when<br />

<strong>the</strong> function returns. Callers are <strong>the</strong>n verified with respect to<br />

<strong>the</strong> contracts, not bodies, <strong>of</strong> <strong>the</strong> called functions. The program<br />

is verified as if it were executed by a s<strong>in</strong>gle thread but, to handle<br />

concurrency, predicates describ<strong>in</strong>g knowledge about <strong>the</strong> state<br />

are weakened at possible po<strong>in</strong>ts <strong>of</strong> <strong>in</strong>terleav<strong>in</strong>gs to simulate <strong>the</strong><br />

effects <strong>of</strong> o<strong>the</strong>r threads.<br />

Ghost Fields and Ghost Code. <strong>Verification</strong> <strong>of</strong> complex, functional<br />

properties <strong>of</strong> programs has been, up to date, mostly done<br />

us<strong>in</strong>g <strong>in</strong>teractive, higher-order provers. VCC restricts <strong>the</strong> specification<br />

language not to use any higher order or specialized logics,<br />

and <strong>in</strong>stead relies on purely first-order specification for two reasons.<br />

The first one is automation: development <strong>of</strong> automatic<br />

first-order systems has received much more attention than ei<strong>the</strong>r<br />

specialized logics or higher-order logics. The second reason is<br />

<strong>the</strong> belief that first-order logic is better understood by “ord<strong>in</strong>ary”<br />

programmers.<br />

This restriction comes at a price. For example, <strong>the</strong> graph<br />

reachability relation, a crucial concept <strong>in</strong> specification <strong>of</strong> recursive<br />

data structures, is not expressible <strong>in</strong> first-order logic. In<br />

places where such relations are needed we <strong>in</strong>troduce ghost fields<br />

<strong>in</strong> data structures to keep track <strong>of</strong> <strong>the</strong> set <strong>of</strong> reachable objects<br />

and use ghost code to update <strong>the</strong>se fields whenever <strong>the</strong> data<br />

structure is updated. Ghost code is <strong>in</strong>troduced only to facilitate<br />

verification and is syntactically restricted not to alter execution<br />

<strong>of</strong> <strong>the</strong> physical code. We thus verify <strong>the</strong> program with ghost<br />

code, but <strong>the</strong> set <strong>of</strong> reachable physical states is <strong>the</strong> same with<br />

and without ghost code. VCC supports manipulation <strong>of</strong> a number<br />

<strong>of</strong> ghost-only types, <strong>in</strong>clud<strong>in</strong>g maps (from po<strong>in</strong>ters and <strong>in</strong>tegers<br />

<strong>in</strong>to arbitrary types) as well as entire states <strong>of</strong> execution,<br />

which can be captured and used to evaluate expressions <strong>in</strong> <strong>the</strong>m.<br />

Additionally, new user-def<strong>in</strong>ed ghost data types can be specified<br />

at <strong>the</strong> level <strong>of</strong> C, us<strong>in</strong>g function symbols and axioms.<br />

Ghost code and ghost state allow for <strong>in</strong>troduction <strong>of</strong> abstraction<br />

layers: for example a red-black tree, from <strong>the</strong> user’s po<strong>in</strong>t <strong>of</strong><br />

view, is represented as a ma<strong>the</strong>matical map, greatly simplify<strong>in</strong>g<br />

reason<strong>in</strong>g. Additionally ghost state is used to capture protocols<br />

us<strong>in</strong>g flags, ownership transfer, and two-state <strong>in</strong>variants. A significant<br />

advantage <strong>of</strong> ghost code is that it is well understood by<br />

“ord<strong>in</strong>ary” programmers, be<strong>in</strong>g much like code <strong>in</strong>troduced for<br />

debugg<strong>in</strong>g and runtime assertion check<strong>in</strong>g.<br />

We have been able to specify and verify multiple recursive<br />

data structures, as found <strong>in</strong> <strong>the</strong> Hyper-V code, some complex<br />

synchronisation primitives (sp<strong>in</strong> locks, reader-writer locks, rundowns,<br />

custom algorithms for message pass<strong>in</strong>g) and specify a<br />

good deal <strong>of</strong> data structure <strong>in</strong>variants. We currently do not face<br />

expressiveness problems with <strong>the</strong> restriction to first-order logic.<br />

Object Invariants and Ownership. One way to capture global<br />

properties <strong>of</strong> a s<strong>of</strong>tware system is to def<strong>in</strong>e <strong>in</strong>variants for data<br />

structures (i.e., structs <strong>in</strong> <strong>the</strong> case <strong>of</strong> C) used <strong>in</strong> <strong>the</strong> program.<br />

With VCC, such <strong>in</strong>variants can be given by annotat<strong>in</strong>g a<br />

struct with (arbitrarily many) <strong>in</strong>variant clauses. To enable<br />

modular reason<strong>in</strong>g about properties <strong>of</strong> complex data structures<br />

(e.g., po<strong>in</strong>ter structures or nested structs), and to capture relations<br />

between data structures, <strong>the</strong> concept <strong>of</strong> ownership between<br />

structured data is used (VCC’s ownership model is an extension<br />

<strong>of</strong> <strong>the</strong> one used <strong>in</strong> <strong>the</strong> Spec# methodology [13]). Every struct<br />

has exactly one “owner” and can itself own arbitrarily many<br />

structures. At <strong>the</strong> top <strong>of</strong> <strong>the</strong> ownership hierarchy, structs can<br />

be owned by execut<strong>in</strong>g threads. The ownership relation is provided<br />

explicitly <strong>in</strong> annotations by <strong>the</strong> verification eng<strong>in</strong>eer, and<br />

it reflects his/her abstract knowledge about <strong>the</strong> data structure<br />

and how it is used.<br />

3 The Deduction <strong>System</strong> Z3<br />

While <strong>the</strong>re are ongo<strong>in</strong>g efforts to accommodate different <strong>the</strong>orem<br />

provers <strong>in</strong>to <strong>the</strong> VCC tool cha<strong>in</strong> (<strong>in</strong>clud<strong>in</strong>g <strong>in</strong>teractive ones,<br />

like Isabelle/HOL [5]), <strong>the</strong> Veris<strong>of</strong>t <strong>XT</strong> sub-projects Hypervisor<br />

and Avionics mostly use <strong>the</strong> SMT solver called Z3 as <strong>the</strong> underly<strong>in</strong>g<br />

deduction eng<strong>in</strong>e. SMT stands for Satisfiability Modulo<br />

Theories. SMT solvers decide satisfiability <strong>of</strong> first-order formulas<br />

<strong>in</strong> presence <strong>of</strong> background <strong>the</strong>ories like <strong>in</strong>teger or bit-vector<br />

arithmetic, arrays, etc. Conjunctions <strong>of</strong> literals from <strong>the</strong> <strong>the</strong>ories<br />

are tested for satisfiability by decision procedures.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!