CIS 890: Safety Critical Systems

Similar documents
CIS 890: Safety Critical Systems

Spark verification features

Lecture 1 Contracts. 1 A Mysterious Program : Principles of Imperative Computation (Spring 2018) Frank Pfenning

Lecture 1 Contracts : Principles of Imperative Computation (Fall 2018) Frank Pfenning

Part II. Hoare Logic and Program Verification. Why specify programs? Specification and Verification. Code Verification. Why verify programs?

CIS 890: Safety-Critical Systems

Softwaretechnik. Program verification. Software Engineering Albert-Ludwigs-University Freiburg. June 30, 2011

Hybrid Verification in SPARK 2014: Combining Formal Methods with Testing

Software Model Checking: Theory and Practice

Lecture Notes on Contracts

A3. Programming Languages for Writing Safety-Critical Software

AXIOMS OF AN IMPERATIVE LANGUAGE PARTIAL CORRECTNESS WEAK AND STRONG CONDITIONS. THE AXIOM FOR nop

Softwaretechnik. Program verification. Albert-Ludwigs-Universität Freiburg. June 28, Softwaretechnik June 28, / 24

Lectures 20, 21: Axiomatic Semantics

Hoare Logic: Proving Programs Correct

Testing! Prof. Leon Osterweil! CS 520/620! Spring 2013!

Formal Methods. CITS5501 Software Testing and Quality Assurance

The HOL-SPARK Program Verification Environment. Stefan Berghofer secunet Security Networks AG

Static program checking and verification

Lecture 18 Restoring Invariants

An Annotated Language

Program Verification. Aarti Gupta

Simulink 모델과 C/C++ 코드에대한매스웍스의정형검증툴소개 The MathWorks, Inc. 1

Semantics. There is no single widely acceptable notation or formalism for describing semantics Operational Semantics

Outline. Introduction. 2 Proof of Correctness. 3 Final Notes. Precondition P 1 : Inputs include

SPARK A state-of-the-practice approach to the Common Criteria implementation requirements

GNAT Pro Innovations for High-Integrity Development

Lecture Notes on Linear Search

Advances in Programming Languages

Introduction to Axiomatic Semantics

Bounded Model Checking Of C Programs: CBMC Tool Overview

Verification Condition Generation

UNIT 3

SPARK Examiner with Run-time Checker Generation of VCs for SPARK Programs

CSC313 High Integrity Systems/CSCM13 Critical Systems. CSC313/CSCM13 Chapter 2 1/ 221

Verification Overview Testing Theory and Principles Testing in Practice. Verification. Miaoqing Huang University of Arkansas 1 / 80

Lecture Notes: Hoare Logic

Verifying Safety Property of Lustre Programs: Temporal Induction

Software Model Checking: Theory and Practice

Symbolic Execution and Proof of Properties

Semantic Analysis. CSE 307 Principles of Programming Languages Stony Brook University

CIS 771: Software Specifications. Lecture: Alloy Whirlwind Tour (part A)

Lecture 4 Searching Arrays

Static Analysis Techniques

CIS 771: Software Specifications

Fachgebiet Softwaretechnik, Heinz Nixdorf Institut, Universität Paderborn. 4. Testing

Warm-Up Problem. Let be a set of well-formed Predicate logic formulas. Let be well-formed Predicate logic formulas. Prove or disprove the following.

Lecture 10 Design by Contract

Principles of Programming Languages

Global Optimization. Lecture Outline. Global flow analysis. Global constant propagation. Liveness analysis. Local Optimization. Global Optimization

Computer Security Course. Midterm Review

CMSC 330: Organization of Programming Languages. Formal Semantics of a Prog. Lang. Specifying Syntax, Semantics

Formal Methods for Java

Chapter 3. Describing Syntax and Semantics

CSC313 High Integrity Systems/CSCM13 Critical Systems. CSC313/CSCM13 Chapter 1 1/ 38

An Eclipse Plug-in for Model Checking

Fundamentals of Software Engineering

Reasoning About Imperative Programs. COS 441 Slides 10

Outline. software testing: search bugs black-box and white-box testing static and dynamic testing

AdaCore technologies

Introduction to Axiomatic Semantics (1/2)

CSE 331 Software Design and Implementation. Lecture 3 Loop Reasoning

Tool Support for Design Inspection: Automatic Generation of Questions

15-122: Principles of Imperative Computation (Section G)

Proof Carrying Code(PCC)

G Programming Languages - Fall 2012

Introduction to Axiomatic Semantics (1/2)

CS/ENGRD 2110 Object-Oriented Programming and Data Structures Spring 2012 Thorsten Joachims. Lecture 10: Asymptotic Complexity and

CS2 Algorithms and Data Structures Note 10. Depth-First Search and Topological Sorting

III. Check if the divisors add up to the number. Now we may consider each of these tasks separately, assuming the others will be taken care of

COS 320. Compiling Techniques

Checking Program Properties with ESC/Java

CS 161 Computer Security

Java Software Solutions for AP Computer Science 3rd Edition, Lewis et al. 2011

Warm-Up Problem. 1. What is the definition of a Hoare triple satisfying partial correctness? 2. Recall the rule for assignment: x (assignment)

Formal Verification! Prof. Leon Osterweil! Computer Science 520/620! Spring 2012!

CIS 890: Safety Critical Systems

Data Structures and Algorithms. Part 2

Review: Hoare Logic Rules

Program Verification. Program Verification 307/434

6. Hoare Logic and Weakest Preconditions

SEQUENCES, MATHEMATICAL INDUCTION, AND RECURSION

Objectives. Chapter 19. Verification vs. validation. Topics covered. Static and dynamic verification. The V&V process

Reasoning about programs

Algorithms and Data Structures. Algorithms and Data Structures. Algorithms and Data Structures. Algorithms and Data Structures

Last time. Reasoning about programs. Coming up. Project Final Presentations. This Thursday, Nov 30: 4 th in-class exercise

Lecture 5 - Axiomatic semantics

Sardar Vallabhbhai Patel Institute of Technology (SVIT), Vasad M.C.A. Department COSMOS LECTURE SERIES ( ) (ODD) Code Optimization

The Spark Approach. Regensburg

Data Structures and Algorithms Chapter 2

Algorithms and Data Structures

Violations of the contract are exceptions, and are usually handled by special language constructs. Design by contract

Research Collection. Formal background and algorithms. Other Conference Item. ETH Library. Author(s): Biere, Armin. Publication Date: 2001

Boca Raton Community High School AP Computer Science A - Syllabus 2009/10

Lecture Notes on Queues

Chapter 3 (part 3) Describing Syntax and Semantics

System Correctness. EEC 421/521: Software Engineering. System Correctness. The Problem at Hand. A system is correct when it meets its requirements

Coding and Unit Testing! The Coding Phase! Coding vs. Code! Coding! Overall Coding Language Trends!

CIS 771: Software Specifications. Lecture: Alloy Logic (part D)

Verification Condition Generation via Theorem Proving

Transcription:

CIS 890: Safety Critical Systems Lecture: SPARK -- Analysis Tools Copyright 2007, John Hatcliff. The syllabus and all lectures for this course are copyrighted materials and may not be used in other course settings outside of Kansas State University in their current form or modified form without the express written permission of one of the copyright holders. During this course, students are prohibited from selling notes to or being paid for taking notes by any person or commercial firm without the express written permission of one of the copyright holders.

Outline SPARK tool architecture overview Dataflow and information flow analysis Path functions Verification conditions Iterative processes (properties of loops) Nested processes

SPARK Tool Support The Examiner is the primary SPARK tool. From the perspective of the developer, it s the entry point into the SPARK tool chain.

Examiner Functionality The Examiner is a free-standing software tool to support the use of SPARK The Examiner always checks conformance of text file to the rules of SPARK checks consistency of executable code with its core annotations Optionally, the Examiner can be used to obtain verification conditions (VCs) for SPARK programs which can be fed to downstream tools facilitate demonstration that a SPARK program is free from run-time errors produce an obsolescent and less rigorous form of analysis called path functions.

SPARK Eliminates Errors Many run-time exceptions of full Ada cannot occur in SPARK Constraint_Error cannot arise if analysis shows that the program cannot violate ranges such as array bounds and does not cause arithmetic overflow or attempt to divide by zero. Storage_Error cannot arise since the storage requirements can be determined at compile time (recursion and dynamic arrays are forbidden in SPARK) and suitable hardware can therefore be provided. Program_Error cannot arise because the conditions leading to it such as running into the end of a function can never arise in SPARK. Tasking_Error cannot arise because SPARK does not support tasks and protected objects and the communication between them. (Note: this applies even when the Ravenscar profile is considered.)

Examiner Functionality The Examiner supports two specific forms of flow analysis Data Flow Analysis usage of parameters and global variables corresponds to their modes variables not read before assigned values are not overwritten without being used all imported variables used somewhere etc. Data & Information Flow Analysis checks derives annotations in addition to the above these different levels of checking can be combined within a single program

Derives Annotations Recall the basic properties of derives annotations procedure Exchange(X, Y : in out Float); --# derives X from Y & --# Y from X; is T : Float; begin T := X; X := Y; Y := T; end Exchange; +++ Flow analysis of subprogram Exchange performed: no errors found.

Derives Annotations Recall the basic properties of derives annotations procedure Exchange(X, Y : in out Float); --# derives X from Y & --# Y from X; is T : Float; begin T := X; X := Y; Y := X; end Exchange; What sort of output does the Examiner give?

Examiner Output Symbols used for classifying outputs +++???!!! OK, the examiner ran with no warnings or errors warning error

Information Flow Analysis Examiner outputs for the preceeding example!!! ( 2) Flow Error : 35: Importation of the initial value of variable X is ineffective.!!! ( 3) Flow Error : 33: The variable T is neither referenced nor exported.!!! ( 4) Flow Error : 50: The imported value of X is not used in the derivation of Y.??? ( 5) Warning :601: The imported value of Y may be used in the derivation of Y.

Full Slide Graphic SPARK Program Path functions The Examiner Verification conditions Messages regarding flow analysis Additional rules Proof tools The proofs Interactions with human user

Path Function Reveals what happens when a particular path is traced through a subprogram A subprogram with no loops has a finite number of paths through it and for each of these there is a corresponding path function Each path function has two parts traversal condition which is a formula defining the conditions under which the path is traversed action part which defines the final values of modified variables in terms of the initial values of the imported variables

Path Function Example Here s a very simple example of a path function procedure Exchange(X, Y : in out Float); --# derives X from Y & --# Y from X; is T : Float; begin T := X; X := Y; Y := T; end Exchange;} Path 1 Traversal condition: 1: true. Action: x' := y & y' := x & t' := x.

Path Function Example Example with simple branching function Max(I,J : Integer) return Integer is Result : Integer; begin if I > J then Result := I; else Result := J; end if; return Result; end Max; Path 1 Traversal condition: 1: i > j. Action: max' := i & result' := i. Path 2 Traversal condition: 1: not (i > j). Action: max' := j & result' := j.

Path Function Example Example with nested conditionals procedure Fault_Integrator(Fault_Found : in Boolean; Trip : in out Boolean; Counter : in out Integer); --# derives Trip from Fault_Found, Trip, Counter & --# Counter from Fault_Found, Counter; is begin if Fault_Found then Counter := Counter + Up_Rate; if Counter >= Upper_Limit then trip := True; Counter := Upper_Limit; end if; else Counter := Counter - Down_Rate; if Counter <= Lower_Limit then Trip := False; Counter := Lower_Limit; end if; end if; end Fault_Integrator;

Path Function Example Path function for examples with nested conditionals (part 1) Path 1 Traversal condition: 1: fault_found. 2: counter + up_rate >= upper_limit. Action: trip' := true & counter' := upper_limit. Path 2 Traversal condition: 1: fault_found. 2: not (counter + up_rate >= upper_limit). Action: counter' := counter + up_rate. Path condition is stated in terms of initial values of imported variables. Trip not modified in this branch, so not listed.

Path Function Example Path function for examples with nested conditionals (part 2) Path 3 Traversal condition: 1: not fault_found. 2: counter - down_rate <= lower_limit. Action: trip' := false & counter' := lower_limit. Path 4 Traversal condition: 1: not fault_found. 2: not (counter - down_rate <= lower_limit). Action: counter' := counter - down_rate.

Path Functions The path function mechanism can be used to detect infeasible paths (dead code) if X > Y then if X < Y then end if end if; It is impossible to have a path that reaches this point (assuming X, Y are not modified). Certification standards for development process often require each line of code to be traced back to some system requirement (each piece of code should be in the system for a reason) Also, these same standards often require testing to certain levels of coverage for a particular coverage criteria Thus, it is useful to have automated tools to indicate if a particular section of code is never executed otherwise, we might be working forever to try to generate a test that covers it

Path Functions Examiner output for example with infeasible path Path 2 Traversal condition: 1: x > y. 2: x < y. Running the SPARK Simplifier (SPADE) Path 2 Path eliminated. (Contradictory traversal condition)

Assessment Estimated that around 10% of paths in typical production programs can never be executed because the appropriate combination of path conditions never arises It is often easier to leave the code intact rather than make the conditions more elaborate However, this is not an option under certain certification regimes Due to combinatorial explosion in number of paths, it is often easier to develop a formal correctness proof using verification conditions that to manually analyze and document the correctness of each path Path functions can be used as the basis of automatically generating tests from implementations.

Tool Invocation Typical tool invocation $ spark -pfs <filename> Switch for option to generate path conditions. Output goes by default into a subdirectory named p within the current directory. $ spadesimp Automatically looks for various files (including p directory) within current directory to simplify

For You To Do (insert simple tool-based exercise for path conditions here)

Verification Conditions Pre-condition N(..) } Post-condition Path functions The Examiner Verification conditions Messages regarding flow analysis Additional rules Proof tools The proofs Interactions with human user Given some initial procedure contract information in the form of pre/post-conditions (or some other goal such as avoiding certain runtime errors), the Examiner DOES NOT try to directly prove that the code satisfies the contract instead, it processes the contract and the code and generates verification conditions -- conjectures which, if proved to be true, show that the postconditions to indeed always follow from the preconditions.

Verification Conditions Example with simple post-condition contract procedure Exchange(X, Y : in out Float); --# derives X from Y & --# Y from X; --# post X = Y~ and Y = X~; is T : Float; begin T := X; X := Y; Y := T; end Exchange; Essence of what the Examiner produces as verification condition generator for example above. H1: true. -> C1: y = y. C2: x = x. Simple post condition stating that parameter values have been swapped. H1 and H2 and -> C1 and C2 and

Steps for Simple Tool Chain Steps for generating verification conditions Pre-condition N(..) } Post-condition The Examiner $ spark -rtc <filename> Verification conditions (output in subdirectory p with file extension.vcg) SparkSimp $ sparksimp The proofs (output in subdirectory p with file extensions.siv and.slg)

Verification Conditions Can the tools detect a simple error? procedure Exchange(X, Y : in out Float); --# derives X from Y & --# Y from X; --# post X = Y~ and Y = X~; is T : Float; begin T := X; X := Y; Y := T + 1.0; end Exchange; Examiner output H1: true. -> C1: y = y. C2: x + 1 = x. Simplifier output H1: true. -> C1: false.

Verification Conditions Can the tools detect a simple error? procedure Exchange(X, Y : in out Float); --# derives X from Y & --# Y from X; --# post X = Y~ and Y = X~; is T : Float; begin T := X; X := Y; Y := X; end Exchange; Examiner output H1: true. -> C1: y = y. C2: y = x. Simplifier output In this case, the Examiner actually reports a number of information flow errors, but if we continue with VC generation, here s what we would get. H1: true. -> C1: y = x. Example File: ex0304c

Verification Conditions Verifying against possible run-time check errors type T is range -128.. 128; procedure Inc(X : in out T); --# derives X from X; is begin X := X + 1; end Inc; Examiner+Simplifier output H1: x >= - 128. H2: x <= 128. -> C1: x <= 127. Verification generated each time we have an assignment to a variable of range type (to establish that the assigned value is within range). Pre-conditions automatically generated based on knowledge of range type. Assessment: one cannot prove the conclusions from the given hypotheses -- so we have the potential for an error on some calls to the procedure. Example File: ex0304d

Verification Conditions Using contract pre-conditions to eliminate possibility of run-time violation (and allowing VCs to be proved) procedure Inc(X: in out T) --# derives X from X; --# pre X < T Last; is begin X := X + 1; end Inc; Max value of range type Examiner output H1: x < t last. H2: x >= t first. H3: x <= t last. -> C1: x + 1 >= t first. C2: x + 1 <= t last. which the Simplifier is able to prove. Example File: ex0304e

Verification Conditions Alternatively, use defensive programming procedure Inc(X: in out T) --# derives X from X; is begin if X < T Last then X := X + 1; end if; end Inc; Assessment: generally, not a good idea when one has an automated contract checking framework. We should instead let the contract checker do the work statically and avoid the run-time overhead. However, relying on contracts does mean that we have to establish that every client correctly satisfies the pre-condition.

For You To Do (insert exercise here for applying the Examiner/Simplifier for VC generation and simplification)

Dealing With Loops Loops introduce complexity in proving correctness a loop is traversed a number of times with different conditions (overwise it would never terminate) usually, automated verification techniques are not powerful enough to calculate the conditions (loop invariants) necessary to summarize the behavior of the loop on all paths Generally, with techniques based on Hoare Logic (such as SPARK), one seeks to reduce the problems given to the automated tool to reasoning about a collection single segments (paths) through the method use explicit assertions at crucial points to break up paths in the method to achieve this property each path should have its own pre/post condition when gluing the paths together, the post-condition of the preceding path has to be strong enough to establish the precondition of the successor path

Reasoning About Loops Consider the following simple iterative arithmetic calculation.. procedure Divide(M, N : in Integer; Q, R : out Integer); --# derives Q, R from M,N; is begin Q := 0; R := M; loop exit when R < N; Q := Q + 1; R := R - N; end loop; end Divide; Consider the behavior for M=5, N=2 Q=0, R=5 1st iteration Q=1, R=3 2nd iteration Q=2, R=1 3rd iteration when could things go wrong in the algorithm? Let s add pre-conditions to prevent that. Then add a post-condition to capture the correctness property. Example File: ex0305a

Reasoning About Loops Begin with appropriate pre/post-conditions procedure Divide(M, N : in Integer; Q, R : out Integer); --# derives Q, R from M,N; Simple pre-condtion --# pre (M >= 0) and (N > 0); --# post (M = Q * N + R) and (R < N) and (R >= 0); is begin Q := 0; R := M; loop exit when R < N; Q := Q + 1; R := R - N; end loop; end Divide; Correctness properties for output Q := Q + 1; R := R - M; false R < N? Need to cut this looping path into segments without cycles Example File: ex0305a

Reasoning About Loops Add loop invariant to summarize relationships between variables procedure Divide(M, N : in Integer; Q, R : out Integer); --# derives Q, R from M,N; --# pre (M >= 0) and (N > 0); --# post (M = Q * N + R) and (R < N) and (R >= 0); is begin Q := 0; R := M; loop --# assert (M = Q * N + R) and (R >= 0); exit when R < N; Q := Q + 1; R := R - N; Loop invariant end loop; end Divide; Example File: ex0305a

Path Segments Each path now has a pre/post-condition Note: the assert cuts a path and becomes the postcondition for the preceding segment and the precondition for the following section. Start pre M >= 0 and N > 0; (pre) Q := 0; R := M; (post) (pre/post) (pre) assert M = Q * N + R and R >= 0; false R < N? true Q := Q + 1; R := R - M; Halt post (M = Q * N + R) and R < N and R >= 0; (post)

Examiner VC Output Path 1 Start pre M >= 0 and N > 0; (pre) Q := 0; R := M; (post) assert M = Q * N + R and R >= 0; H1: m >= 0. H2: n > 0. -> C1: m = 0 * n + m. C2: m >= 0. the simplifier can reduce this (and subsequent VCs) to true

Examiner VC Output Path 2 Q := Q + 1; R := R - M; false R < N? (pre/post) assert M = Q * N + R and R >= 0; H1: m = q * n + r. H2: r >= 0. H3: not (r < n). -> C1: m = (q + 1) * n + (r - n). C2: r - n >= 0.

Examiner VC Output Path 3 H1: m = q * n + r. H2: r >= 0. H3: r < n. -> C1: m = q * n + r. C2: r < n. C3: r >= 0. (pre) assert M = Q * N + R and R >= 0; R < N? true Halt post (M = Q * N + R) and R < N and R >= 0; (post)

Check vs Assert assert causes the accumulated conditions to be dropped (starts a new path), whereas check causes the conditions to be maintained procedure P(... ) --# pre B1; --# post B3; is begin -- some code --# check B2; -- more code end p; path 1 path 2

Using Check Let s see the VCs generated when check is used procedure Exchange(X, Y : in out Float); --# derives X from Y & --# Y from X; --# post X = Y~ and Y = X~; is T : Float; begin T := X; X := Y; --# check X = Y~; Y := T; end Exchange; H1: true. -> C1: y = y. H1: true. H2: y = y. -> C1: y = y. C2: x = x. Example File: ex0306a

VCs for Procedure Calls H1: M-Pre. -> C1: N-Pre. H1: M-Pre. H2: N-Post. -> C1: M-Post. Pre-condition M(,, ) {. check N-Pre N(..) assume N-Post } Pre-condition N(..) } Post-condition Post-condition

VCs for Procedure Calls Building on our previous example procedure CAB(A, B, C : in out Float); --# derives A from C & --# B from A & --# C from B; --# post A = C~ and B = A~ and C = B~; is begin Exchange(A,B); Exchange(A,C); end CAB; Assumptions from postcondition of each call CAB post-condition procedure Exchange(X, Y : in out Float); --# derives X from Y & --# Y from X; --# post X = Y~ and Y = X~; end Exchange; CAB pre-condition H1: true. H2: a 1 = b. H3: b 1 = a. H4: a 2 = c. H5: c 2 = a 1. -> C1: a 2 = c. C2: b 1 = a. C3: c 2 = b. Note: Exchange has no preconditions so there are no intermediate check obligations. Thus, there is a single path (with a single VC) with hypotheses added for post-conditions of Exchange. Example File: ex0306b

GCD Verification GCD written as a recursive function function GCD(M, N: Integer) return Integer is begin if N = 0 then return M; else return GCD(N, M rem N); end if; end GCD 15, 9 9, 6 6, 3 3, 0

GCD Verification Iterative version of GCD procedure GCD(M, N : in Integer; G : out Integer); --# derives G from M,N; is C, D : Integer; R : Integer; begin C := M; D := N; while D /= 0 loop R := C rem D; C := D; D := R; end loop; G := C; end GCD; M,N are mode in, so we can t assign to them -- we need to introduce temporary variables.

GCD Verification Iterative version of GCD procedure GCD(M, N : in Integer; G : out Integer); --# derives G from M,N; is C, D : Integer; Q, R : Integer; begin C := M; D := N; while D /= 0 loop Divide(C, D, Q, R); C := R; Swap(C, D); end loop; G := C; end GCD; Utilized previously discussed procedures to illustrate treatment of procedure calls.

GCD Verification Adding a simple pre-condition and loop invariant procedure GCD(M, N : in Integer; G : out Integer); --# derives G from M,N; --# pre M >= 0 and N > 0; is C, D : Integer; Q, R : Integer; begin C := M; D := N; while D /= 0 loop --# assert C >= 0 and D > 0; Divide(C, D, Q, R); C := R; Swap(C, D); end loop; G := C; end GCD; We are not in a position to do full verification yet, but we at least need to prove enough to establish that the preconditions of Divide are satisfied. Example File: ex0306d

GCD Verification Summary of VC paths procedure GCD(M, N : in Integer; G : out Integer); --# derives G from M,N; --# pre M >= 0 and N > 0; is C, D : Integer; Q, R : Integer; begin C := M; D := N; while D /= 0 loop --# assert C >= 0 and D > 0; Divide(C, D, Q, R); C := R; Swap(C, D); end loop; G := C; end GCD; 1. From the start to the assertion, 2. From the assertion around the loop back to the assertion, 3. From the assertion to the check associated with the call of Divide, 4. From the start to the finish, 5. From the assertion to the finish. Example File: ex0306d

For You To Do (insert exercise here for applying the Examiner/Simplifier for VC generation and simplification for loop invariants and procedures)

Summary SPARK provides a powerful framework for verifying data/information flow partial & full functional correctness absence of run-time exceptions Framework is integrated directly via source code annotations

Acknowledgements The material in this lecture is based on Chapter 3 from High Integrity Software: The SPARK Approach to Safety and Security, John Barnes, Addison Wesley, 2003.