• Keine Ergebnisse gefunden

Korrekte Software: Grundlagen und Methoden Vorlesung 1 vom 06.04.17: Einführung

N/A
N/A
Protected

Academic year: 2022

Aktie "Korrekte Software: Grundlagen und Methoden Vorlesung 1 vom 06.04.17: Einführung"

Copied!
307
0
0

Wird geladen.... (Jetzt Volltext ansehen)

Volltext

(1)

Korrekte Software: Grundlagen und Methoden Vorlesung 1 vom 06.04.17: Einführung

Serge Autexier, Christoph Lüth

Universität Bremen

Sommersemester 2017

(2)

Organisatorisches

I Veranstalter:

Christoph Lüth christoph.lueth@dfki.de

MZH 4186, Tel. 59830

Serge Autexier serge.autexier@dfki.de

Cartesium 2.11, Tel. 59834

I Termine:

I Montag, 14 – 16, MZH 6210

I Donnerstag, 14 – 16, MZH 1110

I Webseite:

http://www.informatik.uni-bremen.de/~cxl/lehre/ksgm.ss17

(3)

Prüfungsformen

I 10 Übungsblätter (geplant)

I Prüfungsform 1:

I Bearbeitung derÜbungsblätter,

I Fachgespräch,

I Noteaus den Übungsblättern.

I Prüfungsform 2:

I Mind. ausreichende Bearbeitung der Übungsblätter (50%),

I mündliche Prüfung,

I Noteaus der Prüfung.

(4)

Warum Korrekte Software?

(5)

Software-Disaster I: Therac-25

(6)

Bekannte Software-Disaster II: Ariane-5

(7)

Bekannte Software-Disaster III: Airbus A400M

(8)

Inhalt der Vorlesung

(9)

Themen

Korrekte Software im Lehrbuch:

I Spielzeugsprache

I Wenig Konstrukte

I Kleine Beispiele

Korrekte Software im Einsatz:

I Richtige Programmiersprache

I Mehr als nur ganze Zahlen

I Skalierbarkeit — wie können große Programme verifiziert werden?

(10)

Inhalt

I Grundlagen:

I DerHoare-Kalkül — Beweis der Korrektheit von Programmen

I Bedeutung von Programmen:Semantik

I Erweiterung der Programmkonstrukte und des Hoare-Kalküls:

1. Referenzen (Zeiger)

2. Funktion und Prozeduren (Modularität) 3. ReicheDatenstrukturen(Felder,struct)

I Übungsbetrieb:

I Betrachtete Programmiersprache: “C0” (erweiterte Untermenge von C)

I Entwicklung eines Verifikationswerkzeugs in Scala

I Beweise mit Princess (automatischerTheorembeweiser)

(11)

Einige Worte zu Scala

(12)

I Ascalable language

I Rein objektorientiert

I Funktional

I Eine “JVM-Sprache”

I Seit 2004 von Martin Odersky, EPFL Lausanne (http://www.scala-lang.org/).

I Seit 2011 kommerziell durch Lightbend Inc. (formerly Typesafe)

(13)

Scala am Beispiel: 01-GCD.scala

Was sehen wir hier?

d e f gcdLoop ( x : Long , y : Long ) : Long = {

v a r a = x v a r b = y w h i l e ( a 6= 0 ) {

v a l temp = a

a = b % a b = temp }

r e t u r n b }

d e f gcd ( x : Long , y : Long ) : Long = i f ( y == 0 ) x e l s e gcd ( y , x % y )

I Variablen, veränderlich ( var )

I Mit Vorsicht benutzen!

I Werte, unveränderlich ( val )

I while -Schleifen

I Unnötig!

I Rekursion

I Endrekursion wird optimiert

I Typinferenz

I Mehr als Java, weniger als Haskell

I Interaktive Auswertung

(14)

Scala am Beispiel: 01-GCD.scala

Was sehen wir hier?

d e f gcdLoop ( x : Long , y : Long ) : Long = {

v a r a = x v a r b = y w h i l e ( a 6= 0 ) {

v a l temp = a

a = b % a b = temp }

r e t u r n b }

d e f gcd ( x : Long , y : Long ) : Long = i f ( y == 0 ) x e l s e gcd ( y , x % y )

I Variablen, veränderlich ( var )

I Mit Vorsicht benutzen!

I Werte, unveränderlich ( val )

I while -Schleifen

I Unnötig!

I Rekursion

I Endrekursion wird optimiert

I Typinferenz

I Mehr als Java, weniger als Haskell

I Interaktive Auswertung

(15)

Scala am Beispiel: 01-GCD.scala

Was sehen wir hier?

d e f gcdLoop ( x : Long , y : Long ) : Long = {

v a r a = x v a r b = y w h i l e ( a 6= 0 ) {

v a l temp = a

a = b % a b = temp }

r e t u r n b }

d e f gcd ( x : Long , y : Long ) : Long = i f ( y == 0 ) x e l s e gcd ( y , x % y )

I Variablen, veränderlich ( var )

I Mit Vorsicht benutzen!

I Werte, unveränderlich ( val )

I while -Schleifen

I Unnötig!

I Rekursion

I Endrekursion wird optimiert

I Typinferenz

I Mehr als Java, weniger als Haskell

I Interaktive Auswertung

(16)

Scala am Beispiel: 01-GCD.scala

Was sehen wir hier?

d e f gcdLoop ( x : Long , y : Long ) : Long = {

v a r a = x v a r b = y w h i l e ( a 6= 0 ) {

v a l temp = a

a = b % a b = temp }

r e t u r n b }

d e f gcd ( x : Long , y : Long ) : Long = i f ( y == 0 ) x e l s e gcd ( y , x % y )

I Variablen, veränderlich ( var )

I Mit Vorsicht benutzen!

I Werte, unveränderlich ( val )

I while -Schleifen

I Unnötig!

I Rekursion

I Endrekursion wird optimiert

I Typinferenz

I Mehr als Java, weniger als Haskell

I Interaktive Auswertung

(17)

Scala am Beispiel: 02-Rational-1.scala

Was sehen wir hier?

c l a s s R a t i o n a l ( n : I n t , d : I n t ) { r e q u i r e ( d 6= 0 )

p r i v a t e v a l g = gcd ( n . abs , d . a b s )

v a l numer = n / g

v a l denom = d / g

d e f t h i s( n : I n t ) = t h i s( n , 1 ) d e f add ( t h a t : R a t i o n a l ) : R a t i o n a l =

new R a t i o n a l (

numer t h a t . denom + t h a t . numer

denom , denom t h a t . denom )

o v e r r i d e d e f t o S t r i n g = numer +" / "+

denom

p r i v a t e d e f gcd ( a : I n t , b : I n t ) : I n t =

i f ( b == 0 ) a e l s e gcd ( b , a % b ) }

I Klassenparameter

I Konstruktoren ( this )

I Klassenvorbedingungen ( require )

I private Werte und Methoden

I Methoden, Syntax für Methodenanwendung

I override (nicht optional)

I Overloading

I Operatoren

I Companion objects ( object )

(18)

Scala am Beispiel: 02-Rational-1.scala

Was sehen wir hier?

c l a s s R a t i o n a l ( n : I n t , d : I n t ) { r e q u i r e ( d 6= 0 )

p r i v a t e v a l g = gcd ( n . abs , d . a b s )

v a l numer = n / g

v a l denom = d / g

d e f t h i s( n : I n t ) = t h i s( n , 1 ) d e f add ( t h a t : R a t i o n a l ) : R a t i o n a l =

new R a t i o n a l (

numer t h a t . denom + t h a t . numer

denom , denom t h a t . denom )

o v e r r i d e d e f t o S t r i n g = numer +" / "+

denom

p r i v a t e d e f gcd ( a : I n t , b : I n t ) : I n t =

i f ( b == 0 ) a e l s e gcd ( b , a % b )

I Klassenparameter

I Konstruktoren ( this )

I Klassenvorbedingungen ( require )

I private Werte und Methoden

I Methoden, Syntax für Methodenanwendung

I override (nicht optional)

I Overloading

I Operatoren

I Companion objects ( object )

(19)

Algebraische Datentypen: 03-Expr.scala

Was sehen wir hier?

a b s t r a c t c l a s s E x p r

c a s e c l a s s Var ( name : S t r i n g ) e x t e n d s E x p r

c a s e c l a s s Number ( num : D o u b l e ) e x t e n d s E x p r

c a s e c l a s s UnOp ( o p e r a t o r : S t r i n g , a r g : E x p r ) e x t e n d s E x p r c a s e c l a s s BinOp ( o p e r a t o r : S t r i n g ,

l e f t : Expr , r i g h t : E x p r ) e x t e n d s E x p r

d e f e v a l ( e x p r : E x p r ) : D o u b l e = e x p r

match {

c a s e v : Var 0 // Variables evaluate to 0

c a s e Number ( x ) x

c a s e BinOp ("+", e1 , e2 ) e v a l ( e1 ) + e v a l ( e2 )

c a s e BinOp ("∗", e1 , e2 ) e v a l ( e1 )

e v a l ( e2 )

c a s e UnOp ("−", e ) ⇒ − e v a l ( e ) }

v a l e = BinOp ("∗", Number ( 1 2 ) , UnOp ("−", BinOp ("+",

Number ( 2 . 3 ) ,

Number ( 3 . 7 ) ) ) )

I case class erzeugt

I Factory-Methode für Konstruktoren

I Parameter als implizite val

I abgeleitete Implementierung für toString , equals

I . . . und pattern matching ( match )

I Pattern sind

I case 4 => Literale

I case C(4) => Konstruktoren

I case C(x) => Variablen

I case C(_) => Wildcards

I case x: C => getypte pattern

I case C(D(x: T, y), 4)

=> geschachtelt

Korrekte Software 15 [25]

(20)

Algebraische Datentypen: 03-Expr.scala

Was sehen wir hier?

a b s t r a c t c l a s s E x p r

c a s e c l a s s Var ( name : S t r i n g ) e x t e n d s E x p r

c a s e c l a s s Number ( num : D o u b l e ) e x t e n d s E x p r

c a s e c l a s s UnOp ( o p e r a t o r : S t r i n g , a r g : E x p r ) e x t e n d s E x p r c a s e c l a s s BinOp ( o p e r a t o r : S t r i n g ,

l e f t : Expr , r i g h t : E x p r ) e x t e n d s E x p r

d e f e v a l ( e x p r : E x p r ) : D o u b l e = e x p r

match {

c a s e v : Var 0 // Variables evaluate to 0

c a s e Number ( x ) x

c a s e BinOp ("+", e1 , e2 ) e v a l ( e1 ) + e v a l ( e2 )

c a s e BinOp ("∗", e1 , e2 ) e v a l ( e1 )

e v a l ( e2 )

c a s e UnOp ("−", e ) ⇒ − e v a l ( e ) }

v a l e = BinOp ("∗", Number ( 1 2 ) , UnOp ("−", BinOp ("+",

I case class erzeugt

I Factory-Methode für Konstruktoren

I Parameter als implizite val

I abgeleitete Implementierung für toString , equals

I . . . und pattern matching ( match )

I Pattern sind

I case 4 => Literale

I case C(4) => Konstruktoren

I case C(x) => Variablen

I case C(_) => Wildcards

I case x: C => getypte pattern

I case C(D(x: T, y), 4)

=> geschachtelt

(21)

Implementierung algebraischer Datentypen

Haskell:

data T = C1 | ... | Cn

I Ein Typ T

I Konstruktoren erzeugen Datentyp

Scala:

T

C1 . . . Cn

-

I Varianten als Subtypen

I Problem und Vorteil:

Erweiterbarkeit

I sealed verhindert Erweiterung

(22)

Implementierung algebraischer Datentypen

Haskell:

data T = C1 | ... | Cn

I Ein Typ T

I Konstruktoren erzeugen Datentyp

Scala:

T

C1 . . . Cn

-

I Varianten als Subtypen

I Problem und Vorteil:

Erweiterbarkeit

I sealed verhindert Erweiterung

(23)

Das Typsystem

Das Typsystem behebt mehrere Probleme von Java:

I Werte vs. Objekte

I Scala vs. Java

I NULL references

(24)

Vererbungshierarchie

Quelle: Odersky, Spoon, Venners:Programming in Scala

(25)

Parametrische Polymorphie

I Typparameter (wie in Haskell, Generics in Java), Bsp. List[T]

I Problem: Vererbung und Polymorphie

I Ziel: wenn S < T , dann List[S] < List[T]

I Does not work— 04-Ref.hs

I Warum?

I Funktionsraum nicht monoton im ersten Argument

I SeiX Y, dannZ −→X Z −→Y, aberX −→Z 6⊆Y −→Z

I SondernY −→Z X −→Z

(26)

Parametrische Polymorphie

I Typparameter (wie in Haskell, Generics in Java), Bsp. List[T]

I Problem: Vererbung und Polymorphie

I Ziel: wenn S < T , dann List[S] < List[T]

I Does not work— 04-Ref.hs

I Warum?

I Funktionsraum nicht monoton im ersten Argument

I SeiX Y, dann Z −→X Z −→Y, aberX −→Z 6⊆Y −→Z

I SondernY −→Z X −→Z

(27)

Typvarianz

class C[+T]

I Kovariant

I Wenn S < T , dann C[S] <

C[T]

I Parametertyp T nur im

Wertebereich von Methoden

class C[T]

I Rigide

I Kein Subtyping

I Parametertyp T kannbeliebig verwendet werden

class C[-T]

I Kontravariant

I Wenn S < T , dann C[T] <

C[S]

I Parametertyp T nur im

Definitionsbereich von Methoden Beispiel:

c l a s s F u n c t i o n [−S , +T ] { d e f a p p l y ( x : S ) : T }

(28)

Traits: 05-Funny.scala

Was sehen wir hier?

I Trait (Mix-ins): abstrakte Klassen, Interfaces; Haskell: Typklassen

I „Abstrakte Klasse ohne Oberklasse“

I Unterschied zu Klassen:

I Mehrfachvererbung möglich

I Keine feste Oberklasse ( super dynamisch gebunden)

I Nützlich zur Strukturierung (Aspektorientierung)

I Nützlich zur Strukturierung:

thin interface+trait=rich interface Beispiel:05-Ordered.scala,05-Rational.scala

(29)

Komprehension mit for : 06-For.scala

v a l l 1 =

L i s t ( 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ) f o r { x← l 1 ;

i f ( x % 2 == 0 ) } y i e l d 2∗x+1

v a l l 1= L i s t . r a n g e ( 1 , 9 ) d e f h a l f ( x : I n t ) :

O p t i o n [ I n t ] =

i f ( x%2 == 0 ) Some ( x / 2 ) e l s e None

f o r { x← l 1 ; y← h a l f ( x ) } y i e l d y

I For-Schleife iteriert über Liste:

I Generatoren, Filter, Result

I Für andere Datentypen: Option

I Für beliebige Datentypen T mit d e f map [ B ] ( f : ( A) ⇒

B) : T [ B ] = ? ? ? d e f f l a t M a p [ B ] ( f : ( A)⇒

T [ B ] ) : T [ B ] = ? ? ?

(30)

Komprehension mit for : 06-For.scala

v a l l 1 =

L i s t ( 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ) f o r { x← l 1 ;

i f ( x % 2 == 0 ) } y i e l d 2∗x+1

v a l l 1= L i s t . r a n g e ( 1 , 9 ) d e f h a l f ( x : I n t ) :

O p t i o n [ I n t ] =

i f ( x%2 == 0 ) Some ( x / 2 ) e l s e None

f o r { x← l 1 ; y← h a l f ( x ) } y i e l d y

I For-Schleife iteriert über Liste:

I Generatoren, Filter, Result

I Für andere Datentypen: Option

I Für beliebige Datentypen T mit d e f map [ B ] ( f : ( A) ⇒

B) : T [ B ] = ? ? ? d e f f l a t M a p [ B ] ( f : ( A)⇒

T [ B ] ) : T [ B ] = ? ? ?

(31)

Was wir ausgelassen haben. . .

I Gleichheit: == (final), equals (nicht final), eq (Referenzen)

I ImpliziteParameter und Typkonversionen

I Stringinterpolation, XML

I Nebenläufigkeit(Aktoren, Futures)

I TypsichereMetaprogrammierung

I Dassimple build tool sbt

I Scala-Plugin für IntelliJ

I Der JavaScript-Compiler scala.js

(32)

Zusammenfassung

I Objekt-orientiert:

I Veränderlicher, gekapselterZustand

I Subtypenund Vererbung

I KlassenundObjekte

I Funktional:

I UnveränderlicheWerte

I Parametrische und Ad-hocPolymorphie

I Funktionen höherer Ordnung

I Hindley-MilnerTypinferenz

(33)

Zusammenfassung

I Zum Lernen von Scala: 0. Übungsblatt

I Keine Punkte, aber Kurzbewertung wenn gewünscht.

I Nächste Woche:

I Reprise der Hoare-Logik

I Semantik

I Erste Gehversuche mit dem Analysewerkzeug

(34)

Korrekte Software: Grundlagen und Methoden Vorlesung 2 vom 10.04.17: Die Floyd-Hoare-Logik

Serge Autexier, Christoph Lüth

Universität Bremen

Sommersemester 2017

(35)

Organisatorisches

Die Übung am Donnerstag, 13.04.17, muss leider ausfallen!

(36)

Fahrplan

I Einführung

I Die Floyd-Hoare-Logik

I Operationale Semantik

I Denotationale Semantik

I Äquivalenz der Operationalen und Denotationalen Semantik

I Korrektheit des Hoare-Kalküls

I Vorwärts und Rückwärts mit Floyd und Hoare

I Funktionen und Prozeduren

I Referenzen und Speichermodelle

I Verifikationsbedingungen Revisited

I Vorwärtsrechnung Revisited

I Programmsicherheit und Frame Conditions

I Ausblick und Rückblick

(37)

Floyd-Hoare-Logik: Idee

I Was wird hier berechnet?

I Wie können wir dasbeweisen?

I Wir berechnen symbolisch, welche Werte Variablen über den

Programmverlauf annehmen.

p= 1 ; c= 1 ;

w h i l e ( c <= n ) { p := p c ; c := c + 1 ; }

I Um Aussagen über ein Program zu beweisen, benötigen wir einen Formalismus (eineLogik), die es erlaubt, Zusicherungen über Werte von Variablen zu bestimmten Ausführungszeitpunkten (im Programm) aufzuschreibenund zu beweisen.

I Dazu müssen wir auch dieBedeutung (Semantik) des Programmes definieren — die Frage “Was tut das Programm” mathematischexakt beantworten.

(38)

Floyd-Hoare-Logik: Idee

I Was wird hier berechnet?p =n!

I Wie können wir dasbeweisen?

I Wir berechnen symbolisch, welche Werte Variablen über den

Programmverlauf annehmen.

p= 1 ; c= 1 ;

w h i l e ( c <= n ) { p := p c ; c := c + 1 ; }

I Um Aussagen über ein Program zu beweisen, benötigen wir einen Formalismus (eineLogik), die es erlaubt, Zusicherungen über Werte von Variablen zu bestimmten Ausführungszeitpunkten (im Programm) aufzuschreibenund zu beweisen.

I Dazu müssen wir auch dieBedeutung (Semantik) des Programmes definieren — die Frage “Was tut das Programm” mathematischexakt beantworten.

(39)

Floyd-Hoare-Logik: Idee

I Was wird hier berechnet?p =n!

I Wie können wir dasbeweisen?

I Wir berechnen symbolisch, welche Werte Variablen über den

Programmverlauf annehmen.

{1n}

p= 1 ; c= 1 ;

w h i l e ( c <= n ) { p := p c ; c := c + 1 ; }

{p=n!}

I Um Aussagen über ein Program zu beweisen, benötigen wir einen Formalismus (eineLogik), die es erlaubt, Zusicherungen über Werte von Variablen zu bestimmten Ausführungszeitpunkten (im Programm) aufzuschreibenund zu beweisen.

I Dazu müssen wir auch dieBedeutung (Semantik) des Programmes definieren — die Frage “Was tut das Programm” mathematischexakt beantworten.

(40)

Floyd-Hoare-Logik: Idee

I Was wird hier berechnet?p =n!

I Wie können wir dasbeweisen?

I Wir berechnen symbolisch, welche Werte Variablen über den

Programmverlauf annehmen.

{1n}

p= 1 ; c= 1 ;

w h i l e ( c <= n ) { p := p c ; c := c + 1 ; }

{p=n!}

I Um Aussagen über ein Program zu beweisen, benötigen wir einen Formalismus (eineLogik), die es erlaubt, Zusicherungen über Werte von Variablen zu bestimmten Ausführungszeitpunkten (im Programm) aufzuschreibenund zu beweisen.

I Dazu müssen wir auch dieBedeutung (Semantik) des Programmes definieren — die Frage “Was tut das Programm” mathematischexakt beantworten.

(41)

Semantik von Programmiersprachen

Drei wesentliche Möglichkeiten:

I Operationale Semantikbeschreibt die Bedeutung eines Programmes, indem die Ausführung auf einer abstrakten Maschine beschrieben wird.

I Denotationale Semantikbildet jedes Programm auf ein mathematisches Objekt (meist ein partielle Funktion zwischen Systemzuständen) ab.

I Axiomatische Semantikbeschreibt die Bedeutung eines Programmes durch Beweisregeln, mit welchem sich gültige Eigenschaften herleiten lassen. Das prominenteste Beispiel hierzu ist die Floyd-Hoare-Logik.

(42)

Drei Semantiken — Eine Sicht

p = 1;

c := 1;

while (c <= n) { p= p * c;

c= c + 1;

}

Operational

Axiomatisch Denotational

Programm

I Jede Semantik ist eine Sichtauf das Program.

I Diese Semantiken sollten alleäquivalentsein. Wir müssen sie also in Beziehung setzen, und zeigen dass sie diegleiche Sichtergeben.

I Für die axiomatische Semantik (die

Floyd-Hoare-Logik) ist das die Frage derKorrektheit der Regeln.

(43)

Floyd-Hoare-Logik

I Grundbaustein der Floyd-Hoare-Logik sindZusicherungen der Form {P}c{Q}(Floyd-Hoare-Tripel), wobei P dieVorbedingung ist,c das Programm, undQ dieNachbedingung.

I Die Logik hat sowohllogische Variablen (zustandsfrei), und

Programmvariablen(deren Wert sich über die Programmausführung ändert).

I Die Floyd-Hoare-Logik hat eine wesentlichesPrinzipand einenTrick.

I DasPrinzipist die Abstraktion vom Programmzustand durch eine logische Sprache; insbesondere wird dieZuweisung durch Substitution modelliert.

I DerTrickbehandelt Schleifen: Iteration im Programm entspricht Rekursion in der Logik. Ein Beweis ist daher induktiv, und benötigt eine Induktionsannahme — eineInvariante.

(44)

Unsere Programmiersprache

Wir betrachten einen Ausschnitt der ProgrammierspracheC (C0).

Ausbaustufe 1 kennt folgende Konstrukte:

I Typen: int;

I Ausdrücke: Variablen, Literale (für ganze Zahlen), arithmetische Operatoren (für ganze Zahlen), Relationen (==,!=,<=, . . . ), boolsche Operatoren (&&, ||);

I Anweisungen:

I Fallunterscheidung (if. . .else. . . ), Iteration (while), Zuweisung, Blöcke;

I Sequenzierung und leere Anweisung sind implizit

(45)

C0: Ausdrücke und Anweisungen

Aexp a::=N|Loc |a1+a2 |a1a2 |a1a2 |a1/a2 Bexp b ::=0|1|a1 ==a2 |a1! =a2

|a1 <=a2 |!b |b1&&b2 |b1||b2

Exp e :=Aexp |Bexp Stmt c ::= Loc=Exp;

| if( b ) c1 else c2

| while ( b ) c

| {c}

(46)

Floyd-Hoare-Tripel

Partielle Korrektheit (|={P}c{Q})

c ist partiell korrekt, wenn für alle Zustände σ, dieP erfüllen:

wenn die Ausführung vonc mitσ in σ0 terminiert, dann erfülltσ0 Q

Totale Korrektheit (|= [P]c[Q])

c ist total korrekt, wenn für alle Zustandeσ, dieP erfüllen:

die Ausführung vonc mit σ in σ0 terminiert, und σ0 erfülltQ.

I Folgendesgilt:|={true} while(1){ } {true}

I Folgendes giltnicht:|= [true] while(1){ }[true]

(47)

Regeln der Floyd-Hoare-Logik

I Die Floyd-Hoare-Logik erlaubt es, Zusicherungen der Form

` {P}c{Q} syntaktischherzuleiten.

I DerKalkül der Logik besteht aus sechs Regeln der Form

` {P1}c1{Q1}. . .` {Pn}cn{Qn}

` {P}c{Q}

I Für jedes Konstrukt der Programmiersprache gibt es eine Regel.

(48)

Regeln der Floyd-Hoare-Logik: Zuweisung

` {P[e/x]}x =e{P}

I Eine Zuweisungx=e ändert den Zustand so dass an der Stellex jetzt der Wert vone steht. Damit nachher das PrädikatP gilt, muss also vorherdas Prädikat gelten, wenn wirx durch e ersetzen.

I Es ist völlig normal (aber dennoch falsch) zu denken, die Substitution gehöre eigentlich in die Nachbedingung.

I Beispiele:

x = 5 {x <10}

x = x+ 1

(49)

Regeln der Floyd-Hoare-Logik: Zuweisung

` {P[e/x]}x =e{P}

I Eine Zuweisungx=e ändert den Zustand so dass an der Stellex jetzt der Wert vone steht. Damit nachher das PrädikatP gilt, muss also vorherdas Prädikat gelten, wenn wirx durch e ersetzen.

I Es ist völlig normal (aber dennoch falsch) zu denken, die Substitution gehöre eigentlich in die Nachbedingung.

I Beispiele:

{5<10⇐⇒(x <10)[5/x]}

x = 5 {x <10}

x = x+ 1

(50)

Regeln der Floyd-Hoare-Logik: Zuweisung

` {P[e/x]}x =e{P}

I Eine Zuweisungx=e ändert den Zustand so dass an der Stellex jetzt der Wert vone steht. Damit nachher das PrädikatP gilt, muss also vorherdas Prädikat gelten, wenn wirx durch e ersetzen.

I Es ist völlig normal (aber dennoch falsch) zu denken, die Substitution gehöre eigentlich in die Nachbedingung.

I Beispiele:

{5<10⇐⇒(x <10)[5/x]}

x = 5 {x <10}

x = x+ 1 {x <10}

(51)

Regeln der Floyd-Hoare-Logik: Zuweisung

` {P[e/x]}x =e{P}

I Eine Zuweisungx=e ändert den Zustand so dass an der Stellex jetzt der Wert vone steht. Damit nachher das PrädikatP gilt, muss also vorherdas Prädikat gelten, wenn wirx durch e ersetzen.

I Es ist völlig normal (aber dennoch falsch) zu denken, die Substitution gehöre eigentlich in die Nachbedingung.

I Beispiele:

{5<10⇐⇒(x <10)[5/x]}

x = 5 {x <10}

{x <9⇐⇒x+ 1<10}

x = x+ 1 {x <10}

(52)

Regeln der Floyd-Hoare-Logik: Fallunterscheidung und Sequenzierung

` {A&&b}c0{B} ` {A&&¬b}c1{B}

` {A} if(b) c0 else c1{B}

I In der Vorbedingung desif-Zweiges gilt die Bedingung b, und im else-Zweig gilt die Negation ¬b.

I Beide Zweige müssem mit derselben Nachbedingung enden.

` {A}c{B} ` {B} {cs} {C}

` {A} {c cs} {C}

I Hier wird ein ZwischenzustandB benötigt.

(53)

Regeln der Floyd-Hoare-Logik: Iteration

` {A∧b}c{A}

` {A} while(b) c{A∧ ¬b}

I Iteration korrespondiert zuInduktion.

I Bei (natürlicher) Induktion zeigen wir, dass diegleicheEigenschaft P für 0 gilt, und dass wenn sie fürP(n) gilt, daraus folgt, dass sie für P(n+ 1) gilt.

I Analog dazu benötigen wir hier eineInvarianteA, die sowohl vorals auchnach dem Schleifenrumpf gilt.

I In derVorbedingungdes Schleifenrumpfeskönnen wir die Schleifenbedingungb annehmen.

I DieVorbedingungder Schleife ist die InvarianteA, und die Nachbedingungder Schleife istA und die Negation der Schleifenbedingungb.

(54)

Regeln der Floyd-Hoare-Logik: Weakening

A0 =⇒A ` {A}c{B} B=⇒B0

` {A0}c{B0}

c

All possible program states

A B

c

All possible program states B' A'

I |={A}c{B}: Ausführung von c startet in Zustand, in dem Agilt, und endet (ggf) in Zustand, in demB gilt.

I Zustandsprädikate beschreiben Mengen von Zuständen:PQ gdw.

P =⇒Q.

I Wir könnenAzuA0 einschränken (A0A oderA0 =⇒A), oderB zu B0 vergrößern (B ⊆B0 oderB=⇒B0), und erhalten |={A0}c{B0}.

(55)

Regeln der Floyd-Hoare-Logik: Weakening

A0 =⇒A ` {A}c{B} B=⇒B0

` {A0}c{B0}

c

All possible program states

A B

c

All possible program states A' B'

I |={A}c{B}: Ausführung von c startet in Zustand, in dem Agilt, und endet (ggf) in Zustand, in demB gilt.

I Zustandsprädikate beschreiben Mengen von Zuständen:PQ gdw.

P =⇒Q.

I Wir könnenAzuA0 einschränken (A0A oderA0 =⇒A), oder B zu B0 vergrößern (B ⊆B0 oderB=⇒B0), und erhalten |={A0}c{B0}.

(56)

Überblick: die Regeln des Floyd-Hoare-Kalküls

` {P[e/x]}x =e{P}

` {A} { } {A}

` {A}c{B} ` {B} {cs} {C}

` {A} {c cs} {C}

` {A∧b}c0{B} ` {A∧ ¬b}c1{B}

` {A} if(b) c0 else c1{B}

` {A∧b}c{A}

` {A}while(b) c{A∧ ¬b}

A0=⇒A ` {A}c{B} B=⇒B0

` {A0}c{B0}

(57)

Eigenschaften der Floyd-Hoare-Logik

Korrektheit

Wenn ` {P}c{Q}, dann |={P}c{Q}

I Wenn wir eine Korrektheitsaussage herleiten können, dann gilt sie auch.

I Wird gezeigt, indem wir|={P}c{Q} durch die anderen Semantiken definieren, und zeigen, dass alle Regeln diese Gültigkeit erhalten.

Relative Vollständigkeit

Wenn |={P}c{Q}, dann ` {P}c{Q} (bis auf Weakening)

I Wenn eine Korrektheitsaussage nicht beweisen werden kann (aber sie stimmt), dann liegt das immer daran, dass einelogische Aussage(in einer Anwendung der Weakening-Regelx) nicht bewiesen werden kann.

I Das ist zu erwarten: alle interessanten Logiken sind unvollständig.

(58)

Wie wir Floyd-Hoare-Beweise aufschreiben

// {P}

// {P1} x= e ; // {P2} // {P3}

w h i l e ( x< n ) { // {P3x<n}

// {P4} z= a ; // {P3} }

// {P3∧ ¬(x<n)}

// {Q}

I Beispiel zeigt: ` {P}c{Q}

I Programm wird mit gültigen Zusicherungen annotiert.

I Vor einer Zeile steht die Vorbedingung, danach die Nachbedingung.

I Implizite Anwendung der Sequenzenregel.

I Weakening wird notiert durch mehrere Zusicherungen, und mussbewiesenwerden.

I Im Beispiel:P=P1,

P2=P3,P3x<n=P4, P3∧ ¬(x <n) =Q.

(59)

Warum Verifikation?

Hier sind Varianten des Fakultätsbeispiels.

Welche sind korrekt?

// {1n}

p = 1 ; c = 1 ;

w h i l e ( c<=n ) { c = c +1;

p = p∗c ; }

// {p=n!}

// {1n}

p = 1 ; c = 1 ;

w h i l e ( c<n ) { c = c +1;

p = p∗c ; }

// {p=n!}

//{1Nn=N}

p = 1 ;

w h i l e (0<n ) { p = p∗n ; n = n−1;

}

//{p=N!}

(60)

Eine Handvoll Beispiele

// {y =Y} x= 1 ;

w h i l e ( y != 0 ) { y= y−1;

x= 2∗x ; }

// {x = 2Y}

// {a0b0}

r= a ; q= 0 ;

w h i l e ( b <= r ) { r= r−b ;

q= q +1;

}

// {a=bq+r0rr <b}

//{0a}

t= 1 ; s= 1 ; i = 0 ;

w h i l e ( s <= a ) { t= t+ 2 ;

s= s+ t ; i = i + 1 ; }

//{i2aa<(i+ 1)2}

(61)

Eine Handvoll Beispiele

// {y =Y y0}

x= 1 ;

w h i l e ( y != 0 ) { y= y−1;

x= 2∗x ; }

// {x = 2Y}

// {a0b0}

r= a ; q= 0 ;

w h i l e ( b <= r ) { r= r−b ;

q= q +1;

}

// {a=bq+r0rr <b}

//{0a}

t= 1 ; s= 1 ; i = 0 ;

w h i l e ( s <= a ) { t= t+ 2 ;

s= s+ t ; i = i + 1 ; }

//{i2aa<(i+ 1)2}

(62)

Zusammenfassung

I Floyd-Hoare-Logik zusammengefasst:

I Die Logik abstrahiert über konkrete Systemzustände durchZusicherungen (Hoare-Tripel|={P}c{Q}).

I Zusicherungen sind boolsche Ausdrücke, angereichert durch logische Variablen und Programmvariablen.

I Wir können partielle Korrektheitsaussgen der Form|={P}c{Q} herleiten (oder totale,|= [P]c[Q]).

I Zuweisungen werden durch Substitution modelliert, d.h. die Menge der gültigen Aussagen ändert sich.

I Für Iterationen wird eineInvariantebenötigt (dienichthergeleitet werden kann).

I Die Korrektheit hängt sehr davon ab, wieexaktwir die Semantik der Programmiersprache beschreiben können.

(63)

Korrekte Software: Grundlagen und Methoden Vorlesung 3 vom 20.04.17: Operationale Semantik

Serge Autexier, Christoph Lüth

Universität Bremen

Sommersemester 2017

(64)

Fahrplan

I Einführung

I Die Floyd-Hoare-Logik

I Operationale Semantik

I Denotationale Semantik

I Äquivalenz der Operationalen und Denotationalen Semantik

I Korrektheit des Hoare-Kalküls

I Vorwärts und Rückwärts mit Floyd und Hoare

I Funktionen und Prozeduren

I Referenzen und Speichermodelle

I Verifikationsbedingungen Revisited

I Vorwärtsrechnung Revisited

I Programmsicherheit und Frame Conditions

I Ausblick und Rückblick

(65)

Zutaten

// GGT(A,B)

i f ( a == 0 ) r = b ; e l s e {

w h i l e ( b != 0 ) { i f ( a <= b )

b = b a ; e l s e a = a b ; }

r = a ; }

I Programme berechnenWerte

I Basierend auf

I Werte sindVariablenzugewiesen

I Evaluation vonAusdrücken

I Folgt dem Programmablauf

(66)

Unsere Programmiersprache

Wir betrachten einen Ausschnitt der ProgrammierspracheC (C0).

Ausbaustufe 1 kennt folgende Konstrukte:

I Typen: int;

I Ausdrücke: Variablen, Literale (für ganze Zahlen), arithmetische Operatoren (für ganze Zahlen), Relationen (==,!=,<=, . . . ), boolsche Operatoren (&&, ||);

I Anweisungen:

I Fallunterscheidung (if. . .else. . . ), Iteration (while), Zuweisung, Blöcke;

I Sequenzierung und leere Anweisung sind implizit

(67)

Semantik von C0

I Die (operationale) Semantik einer imperativen Sprache wie C0 ist ein Zustandsübergang: das System hat einen impliziten Zustand, der durch Zuweisung vonWerten an Adressengeändert werden kann.

I Konkretes Beispiel:n= 3

p ? c ? n 3

p 1 c ? n 3

p 1 c 1 n 3

p 1 c 1 n 3

. . .

p 6 c 4 n 3

p = 1 ; c = 1 ;

w h i l e( c <= n ) { p = p c ; c = c + 1 ; }

Systemzustände

I Ausdrücke werten zuWerten V (hier ganze Zahlen) aus.

I AdressenLocsind hier Programmvariablen (Namen)

I EinSystemzustandbildet Adressen auf Werte ab: Σ =Loc*V

I Ein Programm bildet einen Anfangszustandmöglicherweiseauf einen Endzustand ab (wenn esterminiert).

I Zusicherungen sind Prädikate über dem Systemzustand.

(68)

C0: Ausdrücke und Anweisungen

Aexp a::=N|Loc |a1+a2 |a1a2 |a1a2 |a1/a2 Bexp b ::=0|1|a1 ==a2 |a1! =a2

|a1 <=a2 |!b |b1&&b2 |b1||b2

Exp e :=Aexp |Bexp Stmt c ::= Loc=Exp;

| if( b ) c1 else c2

| while ( b ) c

| {c}

(69)

Eine Handvoll Beispiele

// {y =Y y0}

x = 1 ;

w h i l e ( y != 0 ) { y = y−1;

x = 2∗x ; }

// {x = 2Y}

// {a0b0}

r = b ; q = 0 ;

w h i l e ( b <= r ) { r = r−y ;

q = q +1;

}

// {a=bq+rr <b}

p = 1 ; c = 1 ;

w h i l e ( c<=n ) { c = c +1;

p = p∗c ; }

//{p=n!}

//{0a}

t = 1 ; s = 1 ; i = 0 ;

w h i l e ( s <= a ) { t = t + 2 ; s = s + t ; i = i + 1 ; }

//{i2aa<(i+ 1)2}

(70)

Operationale Semantik: Arithmetische Ausdrücke

Ein arithmetischer Ausdruck a wertet unter gegebenen Zustandσ zu einer ganzen Zahl n (Wert) aus oder zu einem Fehler⊥.

I Aexpa::=N |Loc|a1+a2 |a1a2 |a1a2 |a1 / a2

I Zustände bilden Adressen/Programmvariablen auf Werte ab (σ)

ha, σi →Aexp n|⊥

Regeln:

hn, σi →Aexp n XLoc,XDom(σ), σ(X) =v

hX, σi →Aexp v

XLoc,X 6∈Dom(σ) hX, σi →Aexp

(71)

Operationale Semantik: Arithmetische Ausdrücke

Ein arithmetischer Ausdruck a wertet unter gegebenen Zustandσ zu einer ganzen Zahl n (Wert) aus oder zu einem Fehler⊥.

I Aexpa::=N |Loc|a1+a2 |a1a2 |a1a2 |a1 / a2

I Zustände bilden Adressen/Programmvariablen auf Werte ab (σ)

ha, σi →Aexp n|⊥

Regeln:

hn, σi →Aexp n

XLoc,XDom(σ), σ(X) =v hX, σi →Aexp v

XLoc,X 6∈Dom(σ) hX, σi →Aexp

(72)

Operationale Semantik: Arithmetische Ausdrücke

Ein arithmetischer Ausdruck a wertet unter gegebenen Zustandσ zu einer ganzen Zahl n (Wert) aus oder zu einem Fehler⊥.

I Aexpa::=N |Loc|a1+a2 |a1a2 |a1a2 |a1 / a2

I Zustände bilden Adressen/Programmvariablen auf Werte ab (σ)

ha, σi →Aexp n|⊥

Regeln:

hn, σi →Aexp n XLoc,XDom(σ), σ(X) =v

hX, σi →Aexp v

XLoc,X 6∈Dom(σ) hX, σi →Aexp

(73)

Operationale Semantik: Arithmetische Ausdrücke

I Aexpa::=N |Loc|a1+a2 |a1a2 |a1a2 |a1 / a2

ha, σi →Aexp n|⊥

ha1, σi →Aexp n1 ha2, σi →Aexp n2 niN,n Summe n1 undn2 ha1+a2, σi →Aexp n

ha1, σi →Aexp n1 ha2, σi →Aexp n2 falls n1 =⊥oder n2 =⊥ ha1+a2, σi →Aexp

ha1, σi →Aexp n1 ha2, σi →Aexp n2 niN,n Diff.n1 und n2 ha1a2, σi →Aexp n

ha1, σi →Aexp n1 ha2, σi →Aexp n2 fallsn1 =⊥oder n2 =⊥ ha1a2, σi →Aexp

(74)

Operationale Semantik: Arithmetische Ausdrücke

I Aexpa::=N |Loc|a1+a2 |a1a2 |a1a2 |a1 / a2

ha, σi →Aexp n|⊥

ha1, σi →Aexp n1 ha2, σi →Aexp n2 niN,n Summe n1 undn2 ha1+a2, σi →Aexp n

ha1, σi →Aexp n1 ha2, σi →Aexp n2 falls n1 =⊥oder n2 =⊥ ha1+a2, σi →Aexp

ha1, σi →Aexp n1 ha2, σi →Aexp n2 niN,n Diff.n1 und n2 ha1a2, σi →Aexp n

ha1, σi →Aexp n1 ha2, σi →Aexp n2 falls n1 =⊥oder n2 =⊥ ha1a2, σi →Aexp

Referenzen

ÄHNLICHE DOKUMENTE

I Wir annotieren daher die Invarianten an Schleifen, und können dann die schwächste Vorbedingung und Verifikationsbedingungen.

Partial cor- rectness means that if the programs starts in a state where the precondition P holds, and it terminates, then it does so in a state which satisfies the postcondition

I Die (operationale) Semantik einer imperativen Sprache wie C0 ist ein Zustandsübergang: das System hat einen impliziten Zustand, der durch Zuweisung von Werten an Adressen

I return ohne Argument darf nur bei einer Nachbedingung Q auftreten, die kein \result enthält. I Bei return mit Argument ersetzt der Rückgabewert den \result in

Partial cor- rectness means that if the programs starts in a state where the precondition P holds, and it terminates, then it does so in a state which satisfies the postcondition

I Trait (Mix-ins): abstrakte Klassen, Interfaces; Haskell: Typklassen. I „Abstrakte Klasse

I return ohne Argument darf nur bei einer Nachbedingung Q auftreten, die kein \result enthält. I Bei return mit Argument ersetzt der Rückgabewert den \result in

Korrekte Software: Grundlagen und Methoden Vorlesung 5 vom 2.05.16: Äquivalenz operationale und.