Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011.

Slides:



Advertisements
Similar presentations
Copyright © 2006 The McGraw-Hill Companies, Inc. Programming Languages 2nd edition Tucker and Noonan Chapter 18 Program Correctness To treat programming.
Advertisements

Technologies for finding errors in object-oriented software K. Rustan M. Leino Microsoft Research, Redmond, WA Lecture 1 Summer school on Formal Models.
Automated Theorem Proving Lecture 1. Program verification is undecidable! Given program P and specification S, does P satisfy S?
In this episode of The Verification Corner, Rustan Leino talks about Loop Invariants. He gives a brief summary of the theoretical foundations and shows.
Addressing the Challenges of Current Software. Questions to Address Why? What? Where? How?
Reasoning About Code; Hoare Logic, continued
Situation Calculus for Action Descriptions We talked about STRIPS representations for actions. Another common representation is called the Situation Calculus.
Time Bounds for General Function Pointers Robert Dockins and Aquinas Hobor (Princeton University) (NUS) TexPoint fonts used in EMF. Read the TexPoint manual.
Axiomatic Verification I Prepared by Stephen M. Thebaut, Ph.D. University of Florida Software Testing and Verification Lecture 17.
(c) 2007 Mauro Pezzè & Michal Young Ch 7, slide 1 Symbolic Execution and Proof of Properties.
ISBN Chapter 3 Describing Syntax and Semantics.
Program Proving Notes Ellen L. Walker.
1 Semantic Description of Programming languages. 2 Static versus Dynamic Semantics n Static Semantics represents legal forms of programs that cannot be.
CSE 331 Software Design & Implementation Dan Grossman Winter 2014 Lecture 2 – Reasoning About Code With Logic 1CSE 331 Winter 2014.
CS 355 – Programming Languages
1 Dynamic Software Updating Michael Hicks Jonathan T. Moore Scott Nettles Presented by: Ruchi Gupta Ritu Varma Rohan Puri.
Formal Methods of Systems Specification Logical Specification of Hard- and Software Prof. Dr. Holger Schlingloff Institut für Informatik der.
Comp 205: Comparative Programming Languages Semantics of Imperative Programming Languages denotational semantics operational semantics logical semantics.
1 Introduction to Computability Theory Lecture15: Reductions Prof. Amos Israeli.
1 Introduction to Computability Theory Lecture12: Reductions Prof. Amos Israeli.
ESC Java. Static Analysis Spectrum Power Cost Type checking Data-flow analysis Model checking Program verification AutomatedManual ESC.
Hoare-style program verification K. Rustan M. Leino Guest lecturer Rob DeLine’s CSE 503, Software Engineering University of Washington 26 Apr 2004.
JML and Class Specifications Class invariant JML definitions Queue example Running JML in Eclipse.
CS 330 Programming Languages 09 / 18 / 2007 Instructor: Michael Eckmann.
OOP #10: Correctness Fritz Henglein. Wrap-up: Types A type is a collection of objects with common behavior (operations and properties). (Abstract) types.
Copyright © 2006 The McGraw-Hill Companies, Inc. Programming Languages 2nd edition Tucker and Noonan Chapter 18 Program Correctness To treat programming.
ESC Java. Static Analysis Spectrum Power Cost Type checking Data-flow analysis Model checking Program verification AutomatedManual ESC.
Functional programming: LISP Originally developed for symbolic computing First interactive, interpreted language Dynamic typing: values have types, variables.
Describing Syntax and Semantics
State and Sequence Diagrams Modelling dynamic information So far we have seen: Use Case Diagrams – requirements capture, interface.
Computer Science School of Computing Clemson University Discrete Math and Reasoning about Software Correctness Murali Sitaraman
Crowfoot: a verifier for higher order store programs Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus University of Sussex VMCAI 2012.
Pre/Post Condition Logic 03/06/2013. Agenda Hoare’s Logic Overview Application to Pre/Post Conditions.
From Program Verification to Program Synthesis Saurabh Srivastava * Sumit Gulwani ♯ Jeffrey S. Foster * * University of Maryland, College Park ♯ Microsoft.
Hoare logic for higher order store using simple semantics Billiejoe (Nathaniel) Charlton University of Sussex WoLLIC 2011.
Reading and Writing Mathematical Proofs
1 Abstraction  Identify important aspects and ignore the details  Permeates software development programming languages are abstractions built on hardware.
1 Inference Rules and Proofs (Z); Program Specification and Verification Inference Rules and Proofs (Z); Program Specification and Verification.
ISBN Chapter 3 Describing Semantics -Attribute Grammars -Dynamic Semantics.
Course: Software Engineering ©Alessandra RussoUnit 2: States and Operations, slide number 1 States and Operations This unit aims to:  Define: State schemas.
Recursion. What is recursion? Rules of recursion Mathematical induction The Fibonacci sequence Summary Outline.
Reading and Writing Mathematical Proofs Spring 2015 Lecture 4: Beyond Basic Induction.
13-Nov-1513-Nov-1513-Nov-15 State Machines. What is a state machine? A state machine is a different way of thinking about computation A state machine.
C Functions Three major differences between C and Java functions: –Functions are stand-alone entities, not part of objects they can be defined in a file.
Runtime Organization (Chapter 6) 1 Course Overview PART I: overview material 1Introduction 2Language processors (tombstone diagrams, bootstrapping) 3Architecture.
Chapter 3 Part II Describing Syntax and Semantics.
Semantics In Text: Chapter 3.
ITCS 3181 Logic and Computer Systems 2015 B. Wilkinson Slides4-2.ppt Modification date: March 23, Procedures Essential ingredient of high level.
COP4020 Programming Languages Introduction to Axiomatic Semantics Prof. Robert van Engelen.
Naïve Set Theory. Basic Definitions Naïve set theory is the non-axiomatic treatment of set theory. In the axiomatic treatment, which we will only allude.
Software Engineering 2 -Prakash Shrestha.
From Hoare Logic to Matching Logic Reachability Grigore Rosu and Andrei Stefanescu University of Illinois, USA.
13 Aug 2013 Program Verification. Proofs about Programs Why make you study logic? Why make you do proofs? Because we want to prove properties of programs.
CSCI1600: Embedded and Real Time Software Lecture 28: Verification I Steven Reiss, Fall 2015.
CMSC 330: Organization of Programming Languages Operational Semantics.
SECTION 1: CODE REASONING + VERSION CONTROL slides borrowed and adapted from Alex Mariakis and CSE 390a Justin Bare & Deric Pang.
CSC3315 (Spring 2009)1 CSC 3315 Languages & Compilers Hamid Harroud School of Science and Engineering, Akhawayn University
Overview of the theory of computation Episode 3 0 Turing machines The traditional concepts of computability, decidability and recursive enumerability.
Amortized Analysis and Heaps Intro David Kauchak cs302 Spring 2013.
CORRECTNESS ISSUES AND LOOP INVARIANTS Lecture 8 CS2110 – Fall 2014.
Component-Based Software Engineering Components and Interfaces Paul Krause and Sotiris Moschoyiannis.
State your reasons or how to keep proofs while optimizing code
B (The language of B-Method )
Hoare-style program verification
Reasoning About Code; Hoare Logic
Programming Languages and Compilers (CS 421)
Programming Languages 2nd edition Tucker and Noonan
Formal Methods in software development
Programming Languages and Compilers (CS 421)
Programming Languages 2nd edition Tucker and Noonan
Presentation transcript:

Formal reasoning about runtime code update Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus HotSWUp 2011

Outline Discuss how to do formal proofs about safety of runtime code updates -Using a (relatively) new variant of Hoare logic -specifically, Hoare logic with nested Hoare triples

Outline Discuss how to do formal proofs about safety of runtime code updates -Using a (relatively) new variant of Hoare logic -specifically, Hoare logic with nested Hoare triples Example of formally specifying safety of a runtime update -for a model of an updateable web server from: “Formalizing Dynamic Software Updating” (Gavin Bierman, Michael Hicks, Peter Sewell, Gareth Stoyle)

Outline Discuss how to do formal proofs about safety of runtime code updates -Using a (relatively) new variant of Hoare logic -specifically, Hoare logic with nested Hoare triples Example of formally specifying safety of a runtime update -for a model of an updateable web server from: “Formalizing Dynamic Software Updating” (Gavin Bierman, Michael Hicks, Peter Sewell, Gareth Stoyle) -(time permitting) glimpse of this proof done in Crowfoot, our semi-automated verification tool

Hoare logic A formal logic for proving things - triples - about programs, e.g. Meaning: if we run the program in a state where the precondition holds -then the program doesn’t crash -and if it terminates, the postcondition will hold

Hoare logic A formal logic for proving things - triples - about programs, e.g. Meaning: if we run the program in a state where the precondition holds -then the program doesn’t crash -and if it terminates, the postcondition will hold [ ] = heap access (indirection)

Hoare logic A formal logic for proving things - triples - about programs, e.g. Meaning: if we run the program in a state where the precondition holds -then the program doesn’t crash -and if it terminates, the postcondition will hold BUT: Conventional Hoare logic assumes that program’s code is fixed -because pre- and post-condition talk only about data, not code -so how can one reason about dynamic software updates? 

Key idea: nested Hoare triples Writing code onto the heap:

Key idea: nested Hoare triples Writing code onto the heap:

Key idea: nested Hoare triples Writing code onto the heap:

Key idea: nested Hoare triples Writing code onto the heap: Invoking code stored on the heap:

Key idea: nested Hoare triples Writing code onto the heap: Invoking code stored on the heap:

Key idea: nested Hoare triples Writing code onto the heap: Invoking code stored on the heap:

Nested Hoare triples Only understood recently -because underlying mathematics is complicated -started with [Honda, Yoshida, Berger - LICS 05] -further developed by others since then

Nested Hoare triples Only understood recently -because underlying mathematics is complicated -started with [Honda, Yoshida, Berger - LICS 05] -further developed by others since then Now we have the theory, can we use it to reason about programs? -We thought: let’s give it a go

Nested Hoare triples Only understood recently -because underlying mathematics is complicated -started with [Honda, Yoshida, Berger - LICS 05] -further developed by others since then Now we have the theory, can we use it to reason about programs? -We thought: let’s give it a go We borrowed an example from the literature: a model of an updateable web server -One particular runtime update: adding logging to the web server -Code on slides is mercilessly pruned compared to our paper

heapcell loop_h; heapcell version; proc main() { locals q; [version] := 1; q := new 0; call mkQueue(q); [loop_h] := loop(_); eval [loop_h](q) } proc loop(q) { locals e; e := new 0; call getEvent(q,e); call handleEvent(e); call maybe_update(); eval [loop_h](q) } proc handleEvent(e) {...} proc getEvent(q,e) {...} proc mkQueue(q) {...} This slide: initial version of model web server

heapcell loop_h; heapcell version; proc main() { locals q; [version] := 1; q := new 0; call mkQueue(q); [loop_h] := loop(_); eval [loop_h](q) } proc loop(q) { locals e; e := new 0; call getEvent(q,e); call handleEvent(e); call maybe_update(); eval [loop_h](q) } proc handleEvent(e) {...} proc getEvent(q,e) {...} proc mkQueue(q) {...}

heapcell loop_h; heapcell version; proc main() { locals q; [version] := 1; q := new 0; call mkQueue(q); [loop_h] := loop(_); eval [loop_h](q) } proc loop(q) { locals e; e := new 0; call getEvent(q,e); call handleEvent(e); call maybe_update(); eval [loop_h](q) } proc handleEvent(e) {...} proc getEvent(q,e) {...} proc mkQueue(q) {...} Record that we start at version 1

heapcell loop_h; heapcell version; proc main() { locals q; [version] := 1; q := new 0; call mkQueue(q); [loop_h] := loop(_); eval [loop_h](q) } proc loop(q) { locals e; e := new 0; call getEvent(q,e); call handleEvent(e); call maybe_update(); eval [loop_h](q) } proc handleEvent(e) {...} proc getEvent(q,e) {...} proc mkQueue(q) {...} Create a queue for events

heapcell loop_h; heapcell version; proc main() { locals q; [version] := 1; q := new 0; call mkQueue(q); [loop_h] := loop(_); eval [loop_h](q) } proc loop(q) { locals e; e := new 0; call getEvent(q,e); call handleEvent(e); call maybe_update(); eval [loop_h](q) } proc handleEvent(e) {...} proc getEvent(q,e) {...} proc mkQueue(q) {...} ‘loop’ procedure kept on the heap, so we can update it later

heapcell loop_h; heapcell version; proc main() { locals q; [version] := 1; q := new 0; call mkQueue(q); [loop_h] := loop(_); eval [loop_h](q) } proc loop(q) { locals e; e := new 0; call getEvent(q,e); call handleEvent(e); call maybe_update(); eval [loop_h](q) } proc handleEvent(e) {...} proc getEvent(q,e) {...} proc mkQueue(q) {...}

heapcell loop_h; heapcell version; proc main() { locals q; [version] := 1; q := new 0; call mkQueue(q); [loop_h] := loop(_); eval [loop_h](q) } proc loop(q) { locals e; e := new 0; call getEvent(q,e); call handleEvent(e); call maybe_update(); eval [loop_h](q) } proc handleEvent(e) {...} proc getEvent(q,e) {...} proc mkQueue(q) {...}

heapcell loop_h; heapcell version; proc main() { locals q; [version] := 1; q := new 0; call mkQueue(q); [loop_h] := loop(_); eval [loop_h](q) } proc loop(q) { locals e; e := new 0; call getEvent(q,e); call handleEvent(e); call maybe_update(); eval [loop_h](q) } proc handleEvent(e) {...} proc getEvent(q,e) {...} proc mkQueue(q) {...}

heapcell loop_h; heapcell version; proc main() { locals q; [version] := 1; q := new 0; call mkQueue(q); [loop_h] := loop(_); eval [loop_h](q) } proc loop(q) { locals e; e := new 0; call getEvent(q,e); call handleEvent(e); call maybe_update(); eval [loop_h](q) } proc handleEvent(e) {...} proc getEvent(q,e) {...} proc mkQueue(q) {...}

heapcell loop_h; heapcell version; proc main() { locals q; [version] := 1; q := new 0; call mkQueue(q); [loop_h] := loop(_); eval [loop_h](q) } proc loop(q) { locals e; e := new 0; call getEvent(q,e); call handleEvent(e); call maybe_update(); eval [loop_h](q) } proc handleEvent(e) {...} proc getEvent(q,e) {...} proc mkQueue(q) {...}

What does our update do? Add logging to server – every event will be logged Overwrite ‘loop’ code with a new version Add three new procedures: -loopPrime – the new event-handling loop -logEvent – creates a log entry for a given event -mkEmptyLog – used during transition to create an empty log

heapcell loopPrime_h; heapcell logEvent_h; heapcell mkEmptyLog_h; proc mkEmptyLog_2(log) {...} proc logEvent_2(e,log) {...} proc loop_2(q) { locals log; log := new 0; eval [mkEmptyLog_h](log); eval [loopPrime_h](q,log) } proc loopPrime_2(q,log) { locals e; e := new 0; call getEvent(q,e); eval [logEvent_h](e,log); call handleEvent(e); call maybe_update(); eval [loopPrime_h](q,log) }

heapcell loopPrime_h; heapcell logEvent_h; heapcell mkEmptyLog_h; proc mkEmptyLog_2(log) {...} proc logEvent_2(e,log) {...} proc loop_2(q) { locals log; log := new 0; eval [mkEmptyLog_h](log); eval [loopPrime_h](q,log) } proc loopPrime_2(q,log) { locals e; e := new 0; call getEvent(q,e); eval [logEvent_h](e,log); call handleEvent(e); call maybe_update(); eval [loopPrime_h](q,log) } Replacement for ‘loop’: “transitional function” to take system into new version

heapcell loopPrime_h; heapcell logEvent_h; heapcell mkEmptyLog_h; proc mkEmptyLog_2(log) {...} proc logEvent_2(e,log) {...} proc loop_2(q) { locals log; log := new 0; eval [mkEmptyLog_h](log); eval [loopPrime_h](q,log) } proc loopPrime_2(q,log) { locals e; e := new 0; call getEvent(q,e); eval [logEvent_h](e,log); call handleEvent(e); call maybe_update(); eval [loopPrime_h](q,log) } Set up an empty Log structure

heapcell loopPrime_h; heapcell logEvent_h; heapcell mkEmptyLog_h; proc mkEmptyLog_2(log) {...} proc logEvent_2(e,log) {...} proc loop_2(q) { locals log; log := new 0; eval [mkEmptyLog_h](log); eval [loopPrime_h](q,log) } proc loopPrime_2(q,log) { locals e; e := new 0; call getEvent(q,e); eval [logEvent_h](e,log); call handleEvent(e); call maybe_update(); eval [loopPrime_h](q,log) } Pass control to the new event handling loop

heapcell loopPrime_h; heapcell logEvent_h; heapcell mkEmptyLog_h; proc mkEmptyLog_2(log) {...} proc logEvent_2(e,log) {...} proc loop_2(q) { locals log; log := new 0; eval [mkEmptyLog_h](log); eval [loopPrime_h](q,log) } proc loopPrime_2(q,log) { locals e; e := new 0; call getEvent(q,e); eval [logEvent_h](e,log); call handleEvent(e); call maybe_update(); eval [loopPrime_h](q,log) } new event handling loop The new behaviour: Log every event before processing

proc maybe_update() { if [version] = 1 then { if nondet then { skip } else { [version] := 2; [loop_h] := loop_2(_); [loopPrime_h] := loopPrime_2(_,_); [logEvent_h] := logEvent_2(_,_); [mkEmptyLog_h] := mkEmptyLog_2(_) } else { skip } } Non-deterministically decide whether to update or not

proc maybe_update() { if [version] = 1 then { if nondet then { skip } else { [version] := 2; [loop_h] := loop_2(_); [loopPrime_h] := loopPrime_2(_,_); [logEvent_h] := logEvent_2(_,_); [mkEmptyLog_h] := mkEmptyLog_2(_) } else { skip } } Increment version number

proc maybe_update() { if [version] = 1 then { if nondet then { skip } else { [version] := 2; [loop_h] := loop_2(_); [loopPrime_h] := loopPrime_2(_,_); [logEvent_h] := logEvent_2(_,_); [mkEmptyLog_h] := mkEmptyLog_2(_) } else { skip } } Overwrite ‘loop’ with new version

proc maybe_update() { if [version] = 1 then { if nondet then { skip } else { [version] := 2; [loop_h] := loop_2(_); [loopPrime_h] := loopPrime_2(_,_); [logEvent_h] := logEvent_2(_,_); [mkEmptyLog_h] := mkEmptyLog_2(_) } else { skip } } Load new procedures onto heap

What are we trying to prove? We need to say what we are trying to prove! -For each procedure we give a specification e.g. for ‘getEvent’: -Concentrate on memory safety -i.e. the right kind of data structures are present in the right place -We won’t go into details of Queue, Event, Log predicates...

To specify the effect of maybe_update(), we need this monster definition

Code(v) describes the kind of code present on the heap in version v

Code(v) is nested inside itself!

Specifications For ‘loop’:

Specifications For ‘loop’: For ‘logEvent_2’:

Specifications For ‘loop’: For ‘logEvent_2’: For ‘maybe_update’:

With these specifications we can prove the update safe Proof done semi-automatically by our verification tool

Summary Discussed how to do formal proofs about safety of runtime code updates -using Hoare logic with nested triples Talked through how to formally specify safety of an update -for a model of an updateable web server from: “Formalizing Dynamic Software Updating” (Bierman, Hicks, Sewell, Stoyle) (maybe) glimpsed Crowfoot, our semi-automated verification tool for such safety proofs

The End