Trust in programming tools: the formal verification of compilers and - - PowerPoint PPT Presentation

trust in programming tools the formal verification of
SMART_READER_LITE
LIVE PREVIEW

Trust in programming tools: the formal verification of compilers and - - PowerPoint PPT Presentation

Trust in programming tools: the formal verification of compilers and static analysers Xavier Leroy Inria Paris Verified trustworthy software systems, April 2016 X. Leroy (Inria) Trust in tools 2016-04-05 1 / 35 Tool-assisted formal


slide-1
SLIDE 1

Trust in programming tools: the formal verification of compilers and static analysers

Xavier Leroy

Inria Paris

Verified trustworthy software systems, April 2016

  • X. Leroy (Inria)

Trust in tools 2016-04-05 1 / 35

slide-2
SLIDE 2

Tool-assisted formal verification

Old, fundamental ideas. . .

(Hoare logic, 1960’s; model checking, abstract interpretation, 1970’s)

that remained theoretical for a long time. . . are now implemented and automated in verification tools. . . usable and sometimes used in the critical software industry.

  • X. Leroy (Inria)

Trust in tools 2016-04-05 2 / 35

slide-3
SLIDE 3

Examples of uses for avionics software

Simulink, Scade C code Executable AiT WCET (precise time bounds)

slide-4
SLIDE 4

Examples of uses for avionics software

Simulink, Scade C code Executable AiT WCET (precise time bounds) Astr´ ee (absence of run-time errors,

  • incl. floating-point)
slide-5
SLIDE 5

Examples of uses for avionics software

Simulink, Scade C code Executable AiT WCET (precise time bounds) Astr´ ee (absence of run-time errors,

  • incl. floating-point)

Caveat (program proof) (*)

(*) Motto: “unit proofs as a replacement for unit tests”

slide-6
SLIDE 6

Examples of uses for avionics software

Simulink, Scade C code Executable AiT WCET (precise time bounds) Astr´ ee (absence of run-time errors,

  • incl. floating-point)

Caveat (program proof) (*) Rockwell-Collins toolchain (model-checking + proof)

(*) Motto: “unit proofs as a replacement for unit tests”

  • X. Leroy (Inria)

Trust in tools 2016-04-05 3 / 35

slide-7
SLIDE 7

Trust in tools

that participate in the production and verification of critical software

  • X. Leroy (Inria)

Trust in tools 2016-04-05 4 / 35

slide-8
SLIDE 8

Trust in formal verification

Simulink, Scade Code generator C code Compiler Executable Simulation Model-checking Program proof Static analysis Testing

? ?

The unsoundness risk: Are verification tools semantically sound? The miscompilation risk: Are compilers semantics-preserving?

  • X. Leroy (Inria)

Trust in tools 2016-04-05 5 / 35

slide-9
SLIDE 9

Miscompilation happens

We tested thirteen production-quality C compilers and, for each, found situations in which the compiler generated incorrect code for accessing volatile variables.

  • E. Eide & J. Regehr, EMSOFT 2008

To improve the quality of C compilers, we created Csmith, a randomized test-case generation tool, and spent three years using it to find compiler bugs. During this period we reported more than 325 previously unknown bugs to compiler developers. Every compiler we tested was found to crash and also to silently generate wrong code when presented with valid input.

  • X. Yang, Y. Chen, E. Eide & J. Regehr, PLDI 2011
  • X. Leroy (Inria)

Trust in tools 2016-04-05 6 / 35

slide-10
SLIDE 10

An example of optimizing compilation

double dotproduct(int n, double * a, double * b) { double dp = 0.0; int i; for (i = 0; i < n; i++) dp += a[i] * b[i]; return dp; } Compiled with a good compiler, then manually decompiled back to C. . .

  • X. Leroy (Inria)

Trust in tools 2016-04-05 7 / 35

slide-11
SLIDE 11

double dotproduct(int n, double a[], double b[]) { dp = 0.0; if (n <= 0) goto L5; r2 = n - 3; f1 = 0.0; r1 = 0; f10 = 0.0; f11 = 0.0; if (r2 > n || r2 <= 0) goto L19; prefetch(a[16]); prefetch(b[16]); if (4 >= r2) goto L14; prefetch(a[20]); prefetch(b[20]); f12 = a[0]; f13 = b[0]; f14 = a[1]; f15 = b[1]; r1 = 8; if (8 >= r2) goto L16; L17: f16 = b[2]; f18 = a[2]; f17 = f12 * f13; f19 = b[3]; f20 = a[3]; f15 = f14 * f15; f12 = a[4]; f16 = f18 * f16; f19 = f29 * f19; f13 = b[4]; a += 4; f14 = a[1]; f11 += f17; r1 += 4; f10 += f15; f15 = b[5]; prefetch(a[20]); prefetch(b[24]); f1 += f16; dp += f19; b += 4; if (r1 < r2) goto L17; L16: f15 = f14 * f15; f21 = b[2]; f23 = a[2]; f22 = f12 * f13; f24 = b[3]; f25 = a[3]; f21 = f23 * f21; f12 = a[4]; f13 = b[4]; f24 = f25 * f24; f10 = f10 + f15; a += 4; b += 4; f14 = a[8]; f15 = b[8]; f11 += f22; f1 += f21; dp += f24; L18: f26 = b[2]; f27 = a[2]; f14 = f14 * f15; f28 = b[3]; f29 = a[3]; f12 = f12 * f13; f26 = f27 * f26; a += 4; f28 = f29 * f28; b += 4; f10 += f14; f11 += f12; f1 += f26; dp += f28; dp += f1; dp += f10; dp += f11; if (r1 >= n) goto L5; L19: f30 = a[0]; f18 = b[0]; r1 += 1; a += 8; f18 = f30 * f18; b += 8; dp += f18; if (r1 < n) goto L19; L5: return dp; L14: f12 = a[0]; f13 = b[0]; f14 = a[1]; f15 = b[1]; goto L18; }

  • X. Leroy (Inria)

Trust in tools 2016-04-05 8 / 35

slide-12
SLIDE 12

L17: f16 = b[2]; f18 = a[2]; f17 = f12 * f13; f19 = b[3]; f20 = a[3]; f15 = f14 * f15; f12 = a[4]; f16 = f18 * f16; f19 = f29 * f19; f13 = b[4]; a += 4; f14 = a[1]; f11 += f17; r1 += 4; f10 += f15; f15 = b[5]; prefetch(a[20]); prefetch(b[24]); f1 += f16; dp += f19; b += 4; if (r1 < r2) goto L17;

  • X. Leroy (Inria)

Trust in tools 2016-04-05 8 / 35

slide-13
SLIDE 13

double dotproduct(int n, double a[], double b[]) { dp = 0.0; if (n <= 0) goto L5; r2 = n - 3; f1 = 0.0; r1 = 0; f10 = 0.0; f11 = 0.0; if (r2 > n || r2 <= 0) goto L19; prefetch(a[16]); prefetch(b[16]); if (4 >= r2) goto L14; prefetch(a[20]); prefetch(b[20]); f12 = a[0]; f13 = b[0]; f14 = a[1]; f15 = b[1]; r1 = 8; if (8 >= r2) goto L16; L16: f15 = f14 * f15; f21 = b[2]; f23 = a[2]; f22 = f12 * f13; f24 = b[3]; f25 = a[3]; f21 = f23 * f21; f12 = a[4]; f13 = b[4]; f24 = f25 * f24; f10 = f10 + f15; a += 4; b += 4; f14 = a[8]; f15 = b[8]; f11 += f22; f1 += f21; dp += f24; L18: f26 = b[2]; f27 = a[2]; f14 = f14 * f15; f28 = b[3]; f29 = a[3]; f12 = f12 * f13; f26 = f27 * f26; a += 4; f28 = f29 * f28; b += 4; f10 += f14; f11 += f12; f1 += f26; dp += f28; dp += f1; dp += f10; dp += f11; if (r1 >= n) goto L5; L19: f30 = a[0]; f18 = b[0]; r1 += 1; a += 8; f18 = f30 * f18; b += 8; dp += f18; if (r1 < n) goto L19; L5: return dp; L14: f12 = a[0]; f13 = b[0]; f14 = a[1]; f15 = b[1]; goto L18; }

  • X. Leroy (Inria)

Trust in tools 2016-04-05 8 / 35

slide-14
SLIDE 14

Formal verification of tools

Why not formally verify the compiler and the verification tools themselves? (using program proof) After all, these tools have simple specifications: Correct compiler: if compilation succeeds, the generated code behaves as prescribed by the semantics of the source program. Sound verification tool: if the tool reports no alarms, all executions of the source program satisfy a given safety property. As a corollary, we obtain: The generated code satisfies the given safety property.

  • X. Leroy (Inria)

Trust in tools 2016-04-05 9 / 35

slide-15
SLIDE 15

An old idea. . .

Mathematical Aspects of Computer Science, 1967

  • X. Leroy (Inria)

Trust in tools 2016-04-05 10 / 35

slide-16
SLIDE 16

An old idea. . .

Machine Intelligence (7), 1972.

  • X. Leroy (Inria)

Trust in tools 2016-04-05 11 / 35

slide-17
SLIDE 17

CompCert: a formally-verified C compiler

  • X. Leroy (Inria)

Trust in tools 2016-04-05 12 / 35

slide-18
SLIDE 18

The CompCert project

(X.Leroy, S.Blazy, et al)

Develop and prove correct a realistic compiler, usable for critical embedded software. Source language: a very large subset of C99. Target language: PowerPC/ARM/x86 assembly. Generates reasonably compact and fast code ⇒ careful code generation; some optimizations. Note: compiler written from scratch, along with its proof; not trying to prove an existing compiler.

  • X. Leroy (Inria)

Trust in tools 2016-04-05 13 / 35

slide-19
SLIDE 19

The formally verified part of the compiler

CompCert C Clight C#minor Cminor CminorSel RTL LTL Linear Mach Asm PPC Asm ARM Asm x86

side-effects out

  • f expressions

type elimination loop simplifications stack allocation

  • f “&” variables

instruction selection CFG construction

  • expr. decomp.

register allocation (IRC) calling conventions linearization

  • f the CFG

layout of stack frames asm code generation Optimizations: constant prop., CSE, inlining, tail calls

  • X. Leroy (Inria)

Trust in tools 2016-04-05 14 / 35

slide-20
SLIDE 20

Formally verified using Coq

The correctness proof (semantic preservation) for the compiler is entirely machine-checked, using the Coq proof assistant. Proof pattern: simulation/refinement diagrams such as: State 1 (not stuck) State 1′ State 2′ invariant t Original program Transformed program Execution steps

slide-21
SLIDE 21

Formally verified using Coq

The correctness proof (semantic preservation) for the compiler is entirely machine-checked, using the Coq proof assistant. Proof pattern: simulation/refinement diagrams such as: State 1 (not stuck) State 1′ State 2′ invariant t Original program Transformed program Execution steps State 2 ∗ t invariant

  • X. Leroy (Inria)

Trust in tools 2016-04-05 15 / 35

slide-22
SLIDE 22

Formally verified using Coq

As a consequence, the observable behavior of the compiled code (trace of I/O operations) is identical to one of the possible behaviors of the source code, or improves over one: Source code: i1.o1.o2.i2.o3 i1.o1.† undefined behavior Compiled code: i1.o1.o2.i2.o3 i1.o1.o2 . . . (same behavior) (“improved” undefined behavior)

Theorem transf_c_program_preservation: forall p tp beh, transf_c_program p = OK tp -> program_behaves (Asm.semantics tp) beh -> exists beh’, program_behaves (Csem.semantics p) beh’ /\ behavior_improves beh’ beh.

  • X. Leroy (Inria)

Trust in tools 2016-04-05 16 / 35

slide-23
SLIDE 23

Compiler verification patterns (for each pass)

transformation transformation validator × transformation untrusted solver × checker Verified transformation Verified translation validation External solver with verified validation = formally verified = not verified

  • X. Leroy (Inria)

Trust in tools 2016-04-05 17 / 35

slide-24
SLIDE 24

Programmed (mostly) in Coq

All the verified parts of the compiler are programmed directly in Coq’s specification language, using pure functional style. Monads to handle errors and mutable state. Purely functional data structures. Coq’s extraction mechanism produces executable Caml code from these specifications. Claim: purely functional programming is the shortest path to writing and proving a program.

  • X. Leroy (Inria)

Trust in tools 2016-04-05 18 / 35

slide-25
SLIDE 25

The whole Compcert compiler

AST C AST Asm C source Assembly Executable

preprocessing, parsing, AST construction type-checking, de-sugaring Verified compiler printing of asm syntax assembling linking Register allocation Code linearization heuristics

Proved in Coq

(extracted to Caml)

Not proved

(hand-written in Caml) Part of the TCB Not part of the TCB

  • X. Leroy (Inria)

Trust in tools 2016-04-05 19 / 35

slide-26
SLIDE 26

Performance of generated code

(On a Power 7 processor) fib qsort fft sha1 aes almabench lists binarytrees fannkuch knucleotide mandelbrot nbody nsieve nsievebits spectral vmach bisect chomp perlin arcode lzw lzss raytracer Execution time gcc -O0 CompCert gcc -O1 gcc -O3

  • X. Leroy (Inria)

Trust in tools 2016-04-05 20 / 35

slide-27
SLIDE 27

A tangible increase in quality

The striking thing about our CompCert results is that the middleend bugs we found in all other compilers are absent. As of early 2011, the under-development version of CompCert is the

  • nly compiler we have tested for which Csmith cannot find

wrong-code errors. This is not for lack of trying: we have devoted about six CPU-years to the task. The apparent unbreakability of CompCert supports a strong argument that developing compiler optimizations within a proof framework, where safety checks are explicit and machine-checked, has tangible benefits for compiler users.

  • X. Yang, Y. Chen, E. Eide, J. Regehr, PLDI 2011
  • X. Leroy (Inria)

Trust in tools 2016-04-05 21 / 35

slide-28
SLIDE 28

Verasco: a formally-verified static analyzer based on abstract interpretation

  • X. Leroy (Inria)

Trust in tools 2016-04-05 22 / 35

slide-29
SLIDE 29

Trust in formal verification (again)

Simulink, Scade Code generator C code Compiler Executable Simulation Model-checking Program proof Static analysis Testing The unsoundness risk: Are verification tools semantically sound?

  • X. Leroy (Inria)

Trust in tools 2016-04-05 23 / 35

slide-30
SLIDE 30

The Verasco project

J.H. Jourdan, V. Laporte, et al

Goal: develop and verify in Coq a realistic static analyzer by abstract interpretation: Language analyzed: the CompCert subset of C. Property established: absence of run-time errors

(out-of-bound array accesses, null pointer dereferences, division by zero, etc).

Nontrivial abstract domains, including relational domains. Modular architecture inspired from Astr´ ee’s. Decent (but not great) alarm reporting. Slogan: if “CompCert = 1/10th of GCC but formally verified”, likewise “Verasco = 1/10th of Astr´ ee but formally verified”.

  • X. Leroy (Inria)

Trust in tools 2016-04-05 24 / 35

slide-31
SLIDE 31

Abstract interpretation for dummies

Execute (“interpret”) the program using a non-standard semantics that: Computes over an abstract domain of the desired properties (e.g. “x ∈ [n1, n2]” for interval analysis) instead of the concrete domain of values and states. Handles boolean conditions, even if they cannot be resolved statically. (THEN and ELSE branches of IF are considered both taken.) (Loops execute arbitrarily many times.) Always terminates.

  • X. Leroy (Inria)

Trust in tools 2016-04-05 25 / 35

slide-32
SLIDE 32

Example of abstract interpretation with intervals

x ∈ [−∞, ∞] IF x < 0 THEN x := 0; ELSE IF x > 1000 THEN x := 1000; ELSE SKIP; ENDIF

  • X. Leroy (Inria)

Trust in tools 2016-04-05 26 / 35

slide-33
SLIDE 33

Example of abstract interpretation with intervals

x ∈ [−∞, ∞] IF x < 0 THEN x := 0; x ∈ [0, 0] ELSE IF x > 1000 THEN x := 1000; ELSE SKIP; ENDIF

  • X. Leroy (Inria)

Trust in tools 2016-04-05 26 / 35

slide-34
SLIDE 34

Example of abstract interpretation with intervals

x ∈ [−∞, ∞] IF x < 0 THEN x := 0; x ∈ [0, 0] ELSE IF x > 1000 THEN x := 1000; x ∈ [1000, 1000] ELSE SKIP; ENDIF

  • X. Leroy (Inria)

Trust in tools 2016-04-05 26 / 35

slide-35
SLIDE 35

Example of abstract interpretation with intervals

x ∈ [−∞, ∞] IF x < 0 THEN x := 0; x ∈ [0, 0] ELSE IF x > 1000 THEN x := 1000; x ∈ [1000, 1000] ELSE SKIP; x ∈ [0, ∞] ∩ [−∞, 1000] = [0, 1000] ENDIF

  • X. Leroy (Inria)

Trust in tools 2016-04-05 26 / 35

slide-36
SLIDE 36

Example of abstract interpretation with intervals

x ∈ [−∞, ∞] IF x < 0 THEN x := 0; x ∈ [0, 0] ELSE IF x > 1000 THEN x := 1000; x ∈ [1000, 1000] ELSE SKIP; x ∈ [0, ∞] ∩ [−∞, 1000] = [0, 1000] ENDIF x ∈ [0, 0] ∪ [1000, 1000] ∪ [0, 1000] = [0, 1000]

  • X. Leroy (Inria)

Trust in tools 2016-04-05 26 / 35

slide-37
SLIDE 37

Example of abstract interpretation with intervals

x := 0; x ∈ [0, 0] WHILE x <= 1000 DO x := x + 1; DONE

  • X. Leroy (Inria)

Trust in tools 2016-04-05 27 / 35

slide-38
SLIDE 38

Example of abstract interpretation with intervals

x := 0; x ∈ [0, 0] WHILE x <= 1000 DO x ∈ [0, 0] ∩ [−∞, 1000] = [0, 0] x := x + 1; x ∈ [1, 1] DONE

  • X. Leroy (Inria)

Trust in tools 2016-04-05 27 / 35

slide-39
SLIDE 39

Example of abstract interpretation with intervals

x := 0; x ∈ [0, 0] WHILE x <= 1000 DO x ∈ ([0, 0] ∪ [1, 1]) ∩ [−∞, 1000] = [0, 1] x := x + 1; x ∈ [1, 2] DONE

  • X. Leroy (Inria)

Trust in tools 2016-04-05 27 / 35

slide-40
SLIDE 40

Example of abstract interpretation with intervals

x := 0; x ∈ [0, 0] WHILE x <= 1000 DO x ∈ ([0, 0] ∪ [1, 2]) ∩ [−∞, 1000] = [0, 2] x := x + 1; x ∈ [1, 3] DONE

  • X. Leroy (Inria)

Trust in tools 2016-04-05 27 / 35

slide-41
SLIDE 41

Example of abstract interpretation with intervals

x := 0; x ∈ [0, 0] WHILE x <= 1000 DO x ∈ [0, ∞] x := x + 1; x ∈ [1, ∞] DONE

Widening heuristic to accelerate convergence

  • X. Leroy (Inria)

Trust in tools 2016-04-05 27 / 35

slide-42
SLIDE 42

Example of abstract interpretation with intervals

x := 0; x ∈ [0, 0] WHILE x <= 1000 DO x ∈ ([0, 0] ∪ [1, ∞]) ∩ [−∞, 1000] = [0, 1000] x := x + 1; x ∈ [1, 1001] DONE

Narrowing iteration to improve the result

  • X. Leroy (Inria)

Trust in tools 2016-04-05 27 / 35

slide-43
SLIDE 43

Example of abstract interpretation with intervals

x := 0; x ∈ [0, 0] WHILE x <= 1000 DO x ∈ ([0, 0] ∪ [1, 1001]) ∩ [−∞, 1000] = [0, 1000] x := x + 1; x ∈ [1, 1001] DONE

Fixpoint reached!

  • X. Leroy (Inria)

Trust in tools 2016-04-05 27 / 35

slide-44
SLIDE 44

Example of abstract interpretation with intervals

x := 0; x ∈ [0, 0] WHILE x <= 1000 DO x ∈ ([0, 0] ∪ [1, 1001]) ∩ [−∞, 1000] = [0, 1000] x := x + 1; x ∈ [1, 1001] DONE x ∈ [1001, ∞] ∩ [1, 1001] = [1001, 1001]

Fixpoint reached!

  • X. Leroy (Inria)

Trust in tools 2016-04-05 27 / 35

slide-45
SLIDE 45

Properties inferred by Verasco

Properties of a single variable / memory cell: (value analysis) Variation intervals x ∈ [c1; c2] Integer congruences x mod c1 = c2 Points-to and nonaliasing p poinsTo {x1, . . . , xn} Relations between variables: (relational analysis) Polyhedra c1x1 + · · · + cnxn ≤ c Octagons ±x1 ± x2 ≤ c Symbolic equalities x = expr

  • X. Leroy (Inria)

Trust in tools 2016-04-05 28 / 35

slide-46
SLIDE 46

Architecture

source → C → Clight → C#minor → Cminor → · · · CompCert compiler Abstract interpreter Memory & pointers abstraction Z → int Channel-based combination of domains NR → R NR → R Integer & F.P. intervals Integer congruences Symbolic equalities Convex polyhedra Octagons OK / Alarms Control State Numbers

  • X. Leroy (Inria)

Trust in tools 2016-04-05 29 / 35

slide-47
SLIDE 47

Proof methodology

The abstract interpretation framework, with some simplifications: Only prove the soundness of the analyzer, using the γ half of Galois connections: γ : abstract object → ℘(concrete things) Don’t prove relative optimality of abstractions (the α half of Galois connections). Don’t prove termination of the analyzer.

  • X. Leroy (Inria)

Trust in tools 2016-04-05 30 / 35

slide-48
SLIDE 48

Status of Verasco

It works! Fully proved (46 000 lines of Coq) Executable analyzer obtained by extraction. Able to show absence of run-time errors in small but nontrivial C programs. It needs improving! Some loops need full unrolling (to show that an array is fully initialized at the end of a loop). Analysis is slow (e.g. 10 sec for 100 LOC).

  • X. Leroy (Inria)

Trust in tools 2016-04-05 31 / 35

slide-49
SLIDE 49

Conclusions and future work

  • X. Leroy (Inria)

Trust in tools 2016-04-05 32 / 35

slide-50
SLIDE 50

Conclusions

CompCert and especially Verasco are still ongoing projects. However, they demonstrate that the formal verification of compilers, static analyzers, and related tools is feasible. (Within the limitations of today’s proof assistants.)

  • X. Leroy (Inria)

Trust in tools 2016-04-05 33 / 35

slide-51
SLIDE 51

Future work

For verified compilers: Other source languages: functional, reactive. More optimizations, esp. loop optimizations. Increase confidence even further. For static analyzers based on abstract interpretation: Algorithmic efficiency. More advanced domains (e.g. shape analysis). For both: Separate compilation / modular static analysis. Support for shared-memory concurrency.

  • X. Leroy (Inria)

Trust in tools 2016-04-05 34 / 35

slide-52
SLIDE 52

In closing. . .

Critical software deserves the most trustworthy tools that computer science can produce. Let’s make this a reality!

  • X. Leroy (Inria)

Trust in tools 2016-04-05 35 / 35