Runtime Checking and Test Case Generation for Python

Similar documents
Automatic Verification of Closures and Lambda-Functions in Python Master s Thesis Project Description

Static program checking and verification

Generalized Verification Support for Magic Wands

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

MASTER THESIS. Petr Hudeček. Soothsharp: A C#-to-Viper translator. Department of Distributed and Dependable Systems. Software and Data Engineering

Verified Secure Routing

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

Towards Customizability of a Symbolic-Execution-Based Program Verifier

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

Program Verification using Templates over Predicate Abstraction. Saurabh Srivastava and Sumit Gulwani

6. Hoare Logic and Weakest Preconditions

Symbolic Execution and Proof of Properties

Viper A Verification Infrastructure for Permission-Based Reasoning

Basic Verification Strategy

Lecture Notes on Contracts

Cover Page. The handle holds various files of this Leiden University dissertation

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

Combining Static and Dynamic Contract Checking for Curry

References: internet notes; Bertrand Meyer, Object-Oriented Software Construction; 10/14/2004 1

Lecture 10 Design by Contract

CSC Advanced Object Oriented Programming, Spring Specification

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

Assertions. Assertions - Example

Introduction to Axiomatic Semantics

Hoare Logic: Proving Programs Correct

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

Lecture Notes: Hoare Logic

n Specifying what each method does q Specify it in a comment before method's header n Precondition q Caller obligation n Postcondition

Testing, Debugging, and Verification

Goal. Overflow Checking in Firefox. Sixgill. Sixgill (cont) Verifier Design Questions. Sixgill: Properties 4/8/2010

Lecture Notes on Memory Layout

Chapter 3 (part 3) Describing Syntax and Semantics

Assertions & Design-by-Contract using JML Erik Poll University of Nijmegen

Spark verification features

Lectures 20, 21: Axiomatic Semantics

Verification Condition Generation for Magic Wands

Program Verification (6EC version only)

Chapter 3. Describing Syntax and Semantics ISBN

Software Development. Modular Design and Algorithm Analysis

Assertions, pre/postconditions

Generalised Verification for Quantified Permissions

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

Lecture Notes on Linear Search

Lecture 18 Restoring Invariants

Chapter 3. Describing Syntax and Semantics

Hardware versus software

Software Engineering Testing and Debugging Testing

Research Collection. Overapproximating the Cost of Loops. Master Thesis. ETH Library. Author(s): Schweizer, Daniel. Publication Date: 2013

VS 3 : SMT Solvers for Program Verification

Translating Scala to SIL

Hoare Logic and Model Checking

JML tool-supported specification for Java Erik Poll Radboud University Nijmegen

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

Advances in Programming Languages

The Boogie Intermediate Language

Main Goal. Language-independent program verification framework. Derive program properties from operational semantics

Hoare Logic and Model Checking. A proof system for Separation logic. Introduction. Separation Logic

An Annotated Language

Incremental Proof Development in Dafny

An Introduction to Heap Analysis. Pietro Ferrara. Chair of Programming Methodology ETH Zurich, Switzerland

Avoiding undefined behavior in contracts

Static verification of program running time

Chapter 3. Describing Syntax and Semantics ISBN

Chapter 3. Describing Syntax and Semantics

The JML Tool. Faculty of Engineering Pontificia Universidad Javeriana. The JML Tool p.1/23

Tool Support for Design Inspection: Automatic Generation of Questions

Deductive Verification in Frama-C and SPARK2014: Past, Present and Future

Program Verification. Aarti Gupta

Formal Specification and Verification

Counterexample-Driven Genetic Programming

Integrating dynamic test generation with sound verification. Patrick Emmisberger

Proving well-formedness of interface specifications. Geraldine von Roten

Hoare Logic. COMP2600 Formal Methods for Software Engineering. Rajeev Goré

Automatic Generation of Program Specifications

CS 220: Discrete Structures and their Applications. Loop Invariants Chapter 3 in zybooks

Invariant Based Programming

Object Ownership in Program Verification

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

Repetition Through Recursion

The Contract Pattern. Design by contract

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

Software Engineering

Verifying JML specifications with model fields

Avoiding undefined behavior in contracts

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

Midterm I Exam Principles of Imperative Computation André Platzer Ananda Gunawardena. February 23, 2012

Implementation of frozen objects into Spec#

GNATprove a Spark2014 verifying compiler Florian Schanda, Altran UK

Specifications. Prof. Clarkson Fall Today s music: Nice to know you by Incubus

DM502 Programming A. Peter Schneider-Kamp.

Checking Program Properties with ESC/Java

ESC/Java2 vs. JMLForge. Juan Pablo Galeotti, Alessandra Gorla, Andreas Rau Saarland University, Germany

FreePascal changes: user documentation

Proof Carrying Code(PCC)

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

Introduction to Axiomatic Semantics (1/2)

ESC/Java 2. Checker for Java 2. Extended. Static. B y K ats man Andrey S oftware E ngineering S em inar

Language Techniques for Provably Safe Mobile Code

Chapter 1: Principles of Programming and Software Engineering

Verification Condition Generation

Transcription:

Runtime Checking and Test Case Generation for Python Anna Durrer Master Thesis Chair of Programming Methodology D-INFK ETH Supervisor: Marco Eilers, Prof. Peter Müller 24. Mai 2017 1 Introduction This thesis is part of a software verification project of the Chair of Programming Methodology. The goal of program verification is to prove mathematically that the given program fulfils a given formal specification. The consequence is that for every input that fulfils the precondition the postcondition and all loop invariants have to hold. This is more powerful than testing in that the results are guaranteed for any inputs. Writing all the necessary conditions, also called contracts, can be tedious and error-prone, therefore it is desirable to write them incrementally and check whether they are sufficient. One of the problems that occurs when writing contracts is that whenever the program cannot be verified by an automatic verifier, the cause could lie in three different reasons. The different kinds of errors are: The program code contains one or more errors that disallows the correct contracts to be proven. A specification is too weak. This means that a precondition or loop invariant within the method or a postcondition of a called method is not strong enough and has to be amended. The contracts are of a form that is not provable by the verifier. For example, the SMT solver cannot prove some non-linear arithmetic expressions. For a programmer, it is important to distinguish these errors, because then they know whether to change the code or specification. 1

In this thesis, we aim to develop an automated mechanism that uses a counterexample and the symbolic heap that we get from the verifier to decide whether the detected error is more likely in the specification or the code. 1.1 Example # Example for different kinds of error in Python def m (self, my_boolean): #Method with one argument, a boolean Ensures (self.x == 3) #Postcondition if my_boolean: #Branching self.x = 2 #Setting x to the wrong value => CODE ERROR else: calculate_x(self) #Calling a method => SPECIFICATION ERROR def calculate_x(self): Ensures (self.x > 0) self.x = 3 #Too weak postcondition #Correct code Here is an example of Python code with different kinds of verification errors. In the method m there are two errors: In Line 4, the program sets x to 2 but the specification states that x has to be 3 at the end of the execution. This is a program code error because the code does not comply with the required result. (Of course, it could be possible that the postcondition is wrong, but we assume that the postcondition of a method is always correct but maybe too weak for calling methods.) The postcondition of calculate x is not strong enough to actually prove that x is 3 at the end of the second branch. Here, it is a specification error, because the code guarantees our postcondition but calculate x does not guarantee it in its specification. 1.2 SCION As mentioned above, this thesis is part of a project of the Chair of Programming Methodology. The project is the verification of the Python implementation of the SCION internet architecture developed at ETH. The verification is done automatically by a newly developed static verifier called Nagini that has its own specification language. One speciality of Viper, which is used by Nagini, are the access permissions for each heap or field access. Each heap location has a total permission of 1, this means the sum of all permissions given is at most 1. To read or write a heap location a method needs to acquire a fraction of the total permission. Namely, to read an object, a positive fraction of a permission is needed (for example 0.5). To write to a heap location, we need the full permission of 1. 2

1.3 Counterexample The verifier represents a possible code or specification error by a counterexample. The counterexample given by the Symbolic Execution verifier of Viper consists of two different kinds of information. The counterexample of the Z3 prover - an SMT solver - with values assigned to variables and the symbolic state at every point in the execution. The symbolic state is - slightly simplified - structured in the following way: store #Local variables x Int x 0 y Ref y 0 z Ref z 0 heap #Known heap structure with permissions y 0.f 0.5 v 2 path_condition #Path conditions established at program point is_instance(x 0, list) v 2 > 0 Here, it is important to note that the symbolic state has incomplete information. Only fields that have permissions are visible in the state but there is no information about fields without permission. 1.4 Approach To solve the problem of distinguishing the different errors mentioned above, the goal is to use the counterexample as specified in the previous section. The steps that we will use are the following: 1. Run the static verifier and obtain a counterexample. 2. Generate test inputs that fulfil the conditions of the counterexample. 3. Run the test cases on the program and check all assertions and contracts at runtime. 2 Core Goals 2.1 Runtime Checking One part of this Master thesis deals with the problem of translating a Python method with specifications that are only checked in the verifier to a Python method that checks the properties also at runtime. 2.1.1 Determining strategy As the first step, it is necessary to determine which Viper pre-, postconditions and loop invariants can be translated where and how to Python assertions. Especially, the translation of the above described permissions seems to be challenging 3

because each heap access has to be checked for the correct permission. Another important part here is to decide which data structures are used for representing permissions, as those are just concepts within the verification language. 2.1.2 Implementation After determining how to translate the Viper contracts into Python assertions, the next step is the implementation of a code instrumentation that transforms any method into a method with the according assertions. Methodically, it is interesting how to transform Python programs that use methods of standard libraries. The interesting thing about standard libraries is that contracts have been written for their methods but the contracts are unchecked. It would be desirable to check at least some of the contracts also in standard libraries when doing runtime checking. One idea is to rewrite the method getattribute - that is called whenever a field is accessed in any Python method - for any type of Python to check whether the access is allowed according to the method s permissions, whether or not this approach is useful has to be determined at this step. 2.2 Test Case Generation Another important step in this thesis is to actually produce test cases that check which of the above mentioned error categories the error reported by the SMT solver actually belongs to. 2.2.1 Parsing counterexample The counterexample given by the SMT solver is quite difficult to read and understand. The first step for producing test cases is to parse the counterexample and map it to Python - directly or via an intermediate step through Viper. Here, one expected difficulty is that the symbolic heap is not complete as shown above. 2.2.2 Generate input As the next step, several - if possible - objects that fulfil the conditions of the counterexample are to be produced automatically. And with those objects, different inputs for the method have to be constructed. It is notable that some input objects could not occur in the symbolic heap and have to be guessed. Here, different approaches on how to initialize unspecified values have to be tested or decided on (choose randomly, establish corner cases,...) 2.3 Combination The first two parts of the thesis, runtime checking and test case generation, have to be combined in the end. The generated test cases should be run on the translated methods accordingly and the results are to be returned in a useful way. For example, one could output all test inputs with the results (no assertion 4

broken or the assertion that does not hold). One part of the thesis is to apply the process to some of the examples in SCION and determine whether the output is useful for the programmer or not. 3 Extension Goals There are some extensions to the thesis that could improve the project further. Some of the proposed extensions are: Including information from predicates and functions in the test case generation step: Without including information from predicates and functions, we have two options: either we disallow programs that contain those or we ignore the information given by them and therefore can have false positives. In the first case, this extension allows a wider application and in the second one we can avoid false positives. Extending runtime checking by obligations: Nagini contains obligations, namely for I/O contracts, loop termination and other conditions. By including those in the runtime checking the project could have a wider application by including also programs with obligations or be more precise by checking obligations as well. Determining the statement where the contracts are too weak: If the project determines that the error is due to insufficient contracts, it would be quite helpful for the programmer to know at which instruction the contracts are insufficient. To that end, the runtime checking might be adapted to run a method from a certain point in the method and check when the input produced in the earlier steps in not sufficient. To illustrate how this could be accomplished, we should consider the following example: # Example for finding position of specification error in Python def m (self, my_boolean) #Method with one argumnt, a boolean Ensures(x == 3) #Postcondition calculate_y(self) #other function of no consequence calculate_x(self) #Place of SPECIFICATION ERROR calculate_z(self) #other function of no consequence In this example, the specification error is in the second function call but we do not know that in advance. So, the goal is that we can generate test inputs from the symbolic state at the end of some instruction (for example after the first method call) and then check whether the assertion holds or whether there are allowed inputs in the symbolic state that lead to an assertion failure (in this example we could start after the second function call with a value x = 1 and get an assertion failure). One difficulty here is that we have to generate additional values for local variables. 5