Hochschule Wismar Fakultät für Wirtschaftswissenschaften Semesterarbeit Software-Verifikation Fernstudiengang Master Wirtschaftsinformatik Modul: Formale Methoden Semester: WS 2011/2012 Dozent: Prof. Dr. Jürgen Cleve Eingereicht von: Robert Richter Matrikelnummer 117355 Steffen Weber Matrikelnummer 117517 Tim Strauss Matrikelnummer 115961 Leipzig / Stuttgart / Hermaringen, den 30. Oktober 2011 Eidesstattliche Erklärung Hiermit versichern wir die Seminararbeit mit dem Titel Software-Verifikation selbstständig verfasst und keine anderen als die angegebenen Quellen und Hilfsmittel benutzt wurden, alle Ausführungen, die anderen Schriften wörtlich oder sinngemäß entnommen wurden, kenntlich gemacht sind und die Arbeit in gleicher oder ähnlicher Fassung noch nicht Bestandteil einer Studien- oder Prüfungsleistung war. Leipzig / Stuttgart / Hermaringen, den 30. Oktober 2011 ___________________________________________________________ Robert Richter Steffen Weber Tim Strauss Inhaltsverzeichnis I Inhaltsverzeichnis Abkürzungsverzeichnis ....................................................................... III Abbildungsverzeichnis ......................................................................... IV Tabellenverzeichnis ............................................................................... V 1 Einleitung .......................................................................................... 1 2 Deduktion ......................................................................................... 5 2.1 Bedingungen............................................................................................. 5 Aussagenlogik .............................................................................................. 6 Prädikatenlogik .......................................................................................... 10 Temporallogik ............................................................................................ 12 Höherwertige Logik .................................................................................... 12 2.2 Verifikation nach Hoare............................................................................. 13 Das Hoare-Tripel ........................................................................................ 13 Partielle und Totale Korrektheit – Terminierung ........................................... 14 Hoare Regeln ............................................................................................. 15 Vorgehen der Verifikation ........................................................................... 23 Beispiel...................................................................................................... 24 2.3 Anwendung in der Praxis .......................................................................... 27 3 Modellprüfung ................................................................................ 29 3.1 Einleitung ................................................................................................ 29 3.2 Formale Softwaremodellierung .................................................................. 31 3.3 Formulierung der Softwareeigenschaften .................................................... 34 Linear Time Logic (LTL) .............................................................................. 35 Computation Tree Logic (CTL) .................................................................... 38 3.4 Verifikation der Software........................................................................... 41 Explizite Modellprüfung............................................................................... 42 Symbolische Modellprüfung ........................................................................ 47 Modellprüfung in der Praxis ........................................................................ 51 4 Abstrakte Interpretation ................................................................ 53 4.1 Fixpunktiteration ...................................................................................... 55 Fixpunkt .................................................................................................... 55 Direkte Fixpunktbestimmung ...................................................................... 56 Fixpunktiteration graphisch ......................................................................... 57 Fixpunkt-Berechnung durch Iteration .......................................................... 59 Fixpunktiteration nach Floyd, Clark und Park ................................................ 61 Fixpunktiteration zur Softwareverifikation .................................................... 64 Fehlermengen und Verifikation.................................................................... 70 4.2 Datenabstraktion ...................................................................................... 72 Inhaltsverzeichnis II 4.3 Abstraktion .............................................................................................. 72 Datenabstraktion........................................................................................ 73 4.4 Fixpunktiteration und Datenabstraktion im Rahmen der abstrakten Interpretation .......................................................................................... 75 4.5 Zusammenfassung Abstrakte Interpretation................................................ 77 5 Schlussbetrachtung ........................................................................ 79 5.1 Zusammenfassung ................................................................................... 79 5.2 Fazit ........................................................................................................ 79 6 Quellenverzeichnis ......................................................................... 81 Abkürzungsverzeichnis Abkürzungsverzeichnis AI Abstrakte Interpretation BDD Binary Decision Diagram CTL Computation Tree Logic DA Datenabstraktion FI Fixpunktiteration IT Informationstechnologie LTL Linear Time Logic OBDD Ordered Binary Decision Diagram PSL Property Specification Language RBDD Reduced Binary Decision Diagram ROBDD Reduced Ordered Binary Decision Diagram III Abbildungsverzeichnis IV Abbildungsverzeichnis Abbildung 1-1: Grundschema der Software-Verifikation [Hoffma08] ................ 2 Abbildung 1-2: Verifikationsverfahren im Vergleich [Hoffma08] ....................... 4 Abbildung 2-1: Beispiel Anwendung Zuweisungsregel (in Anl. an Gellne01) ........ Abbildung 2-2: Code Beispiel: Rest-Ermittlung einer ganzzahligen Division ..... 25 Abbildung 2-3: Darstellung der 4 Beweisabschnitte....................................... 25 Abbildung 3-1: Exemplarische Kripke-Struktur (in Anl. an iCMSCS83)............. 33 Abbildung 3-2: Teilgebiete der Logik ........................................................... 34 Abbildung 3-3: Temporaler Logiken (in Anl. an HauTei10) ............................ 35 Abbildung 3-4: Teilgebiete der Logik - erweiterter Zusammenhang................ 39 Abbildung 3-5: Syntaxbaum zur Formel ɸ .................................................... 43 Abbildung 3-6: Extensionsmenge T1 ............................................................ 44 Abbildung 3-7: Extensionsmenge C1 ............................................................ 44 Abbildung 3-8: Extensionsmenge A◊C1 ........................................................ 45 Abbildung 3-9: Extensionsmenge T1 → A◊C1, A□(T1 → A◊C1) ...................... 46 Abbildung 3-10: Reduced BDD .................................................................... 49 Abbildung 3-11: Ordered BDD ..................................................................... 50 Abbildung 4-1: grafische Fixpunktiteration ................................................... 58 Abbildung 4-2: Fixpunkt-Bestimmung in Abhängigkeit vom Startwert x0......... 58 Abbildung 4-3: vollständiger Verband (in Anlehnung an [MikN11]) ................ 63 Abbildung 4-4: Programmanalyse (in Anl. an iKönBar11) .............................. 72 Abbildung 4-5: Prinzip der Datenabstraktion (in Anl. an Hoffma08)................ 74 Abbildung 4-6: Schnittszenarien der Mengenapproximation [Hoffma08]. ........ 75 Tabellenverzeichnis V Tabellenverzeichnis Tabelle 2-1: Wahrheitstabelle - Negation ....................................................... 7 Tabelle 2-2: Wahrheitstabelle - Konjunktion ................................................... 7 Tabelle 2-3: Wahrheitstabelle - Disjunktion .................................................... 8 Tabelle 2-4: Wahrheitstabelle - Implikation .................................................... 8 Tabelle 2-5: Wahrheitstabelle - Äquivalenz ..................................................... 9 Tabelle 2-6: Beweisregeln des Hoare-Kalküls (in Anl. an Hoffma08)............... 23 Tabelle 3-1: Übersicht der temporalen Operatoren (LTL) .............................. 36 Tabelle 3-2: Semantik gültiger LTL-Formeln (in Anl. an HauTei10) ................ 38 Tabelle 3-3: Übersicht der temporalen Operatoren (CTL) .............................. 40 Tabelle 3-4: Semantik gültiger CTL-Formeln (in Anl. an Hoffma08) ................ 41 Tabelle 3-5: Berechnungsgrundlage für Extensionsmengen ........................... 47 Tabelle 4-1: Gleichungssystem des Programmfragments foo (Hoffma08) ....... 66 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 1 1 Einleitung Das tägliche Geschehen der Welt wird mehr und mehr durch Computersysteme gelenkt und beeinflusst. Seien es die Systeme an den Börsen, die in Sekundenschnelle über das wohl ganzer Nationen entscheiden oder die Telekommunikationssysteme die das Rückgrat der modernen Welt bilden. Wie empfindlich diese Systeme sind zeigte sich erst kürzlich als das Emailsystem der Firma Rim zusammenbrach und tausende Nutzer ohne mobile Email Anbindung den Tag überstehen mussten oder als ein sogenannter „Fat Finger“ für einen plötzlichen Kursrutsch an den Börsen der Welt sorgte. Häufig stecken hinter solchen Ereignissen Fehler in den zugrunde liegenden Programmen. Folglich ist es das Ziel der Hersteller als auch der Anwender möglichst fehlerfreie Software zu produzieren bzw. einzusetzen. Denn während eine fehlende Email ärgerlich ist, kann eine softwarebedingte Fehlfunktion in einem Fly-by-Wire-System Leben gefährden. Nun gibt es eine Vielzahl von Möglichkeiten Programme auf ihre Fehlerfreiheit zu untersuchen. Eine Möglichkeit stellen Softwaretests dar. Dabei gibt es verschieden Techniken wie Whitebox- oder Blackbox Verfahren. Das Testen von Software stellt dabei einen immensen Zeit und Kostenfaktor dar. Die meisten Techniken sind dabei nicht in der Lage die Fehlerfreiheit des Programms zu garantieren. Auch gilt es mittlerweile als anerkannt, dass der gelieferte Quellcode nicht vollständig korrekt ist. Ein konkretes Beispiel ist Windows NT, ein Programm mit ca. 27 Millionen Zeilen Quellcode. Bei dieser Größe wurde von ca. 6 Millionen enthaltenen Fehlern ausgegangen. Pro Fehlersuchlauf können dabei rund 30% der Fehler gefunden werden. Nach ca. 20 Durchläufen und einem Einsatz von ca. 200 Millionen $ [Luv 98] wurde ein akzeptabler Stand erreicht. Da wahrscheinlich jeder das ein oder andere Mal Windows Updates auf seinem PC installieren durfte oder sich selbiger mit Fehlermeldungen in das „PC-Nirvana“ verabschiedet hat wird die zuvor angesprochene Problematik der nicht erreichbaren Fehlerfreiheit deutlich. Selbst wenn kein Fehler mehr gefunden werden würde, hieße das im Falle von Softwaretest lediglich, dass “die gewählte Teststrategie keine Fehler mehr zutage för- Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 2 dert“, nicht aber „dass ein Programm von Fehlern bzw. das direkte Finden von Abweichungen zwischen Spezifikation und Implementation fehlerfrei ist“ [iGellne01]. Eine weitere Option zur Prüfung von Software stellen die Verfahren der Verifikation dar, diese beanspruchen für sich, „direkt zu beweisen, dass ein Programm fehlerfrei ist." Zu den Verfahren der Verifikation zählt man die Deduktion, die Modellprüfung und die abstrakte Interpretation. Dabei hängt die industrielle Anwendbarkeit bei allen Verfahren von drei wesentlichen Faktoren ab, der Ausdrucksstärke, der Skalierbarkeit und der Automatisierbarkeit des eingesetzten Verfahrens. Bei den Verifikationsverfahren hängt die Ausprägung dieser Merkmale von eigesetzten Modellen zu Beschreibung der Implementierung und der Spezifikation. Diese unterscheiden sich untereinander sehr stark voneinander, das Grundsätzliche Prinzip bleibt dabei jedoch gleich. Sowohl das Programm als auch seine Anforderungsbeschreibungen müssen vor der eigentlichen Beweisführung in formale Modelle übersetzt werden. Abbildung 1-1 stellt diese Prinzip nochmals grafisch dar. Programm Verhalten 1 2 3 reale Welt Formalisierung Spezifikation Implementierung ? Modellwelt Abbildung 1-1: Grundschema der Software-Verifikation [Hoffma08] Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 3 So entspricht das Deduktionsverfahren der mathematischen Beweisführung und verwendet zum Nachweis der Fehlerfreiheit eine präzise Semantik und das Logikkalkül. Die Modellprüfung hingegen übersetzt das Programm zunächst in die sogenannte Kripke-Struktur und untersucht dann, vor allem zeitliche Eigenschaften des Programms, mit Hilfe von Temporallogiken. Die abstrakte Interpretation formuliert den Quellcode als Gleichungssystem und versucht dann mit Hilfe von Schnittmengen von Zustandsmengen Fehler zu identifizieren. Abbildung 1-2 fasst die Verfahren nochmals zusammen. Auf die Details der einzelnen Verfahren wird im Verlauf der vorliegenden Arbeit eingegangen werden, dabei werden die Vor- und Nachteile der Verfahren anschaulich dargestellt und mit Hilfe von Beispielen gegebenenfalls näher erläutert. Der Leser wird dadurch in die Lage versetzt die potentiellen Einsatzmöglichkeiten der Verfahren zu erkennen und gegebenenfalls einen vorliegenden Quellcode auf seine Fehlerfreiheit zu prüfen. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Verfahren Deduktion Implementierung Spezifikation Formale Sprachsemantik Logikkalkül {P} S {Q} Kripke-Struktur Temporallogik Gleichungssystem Zustandsmengen Modellprüfung Abstrakte Interpretation Abbildung 1-2: Verifikationsverfahren im Vergleich [Hoffma08] 4 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 5 2 Deduktion Autor: Steffen Weber Ein Alternative zum Testen ist das Vermeiden von Fehlern bzw. das direkte Finden von Abweichungen zwischen Spezifikation und Implementation. Mit Testen lässt sich also immer nur ermitteln, wenn etwas nicht korrekt läuft, die bereits vorliegende Korrektheit lässt sich damit jedoch nicht zeigen. Wird beim Testen kein Fehler mehr gefunden, heißt dies auch keineswegs zwingend, dass ein Programm fehlerfrei ist, sondern nur, dass die gewählte Teststrategie keine Fehler mehr zutage fördert. Die Verifikation beansprucht für sich, direkt zu beweisen, dass ein Programm fehlerfrei ist. [iGellne01] Das Verfahren der Deduktion geht von einigen allgemeinen mathematischen Theorien und Prämissen aus, um mit Hilfe von Eliminierung und Verfeinerung zu einem Schluss (Lokalisieren des Fehlers) zu kommen. Basierend auf einer formal definierten Programmiersprache mit präziser Semantik verwendet die Deduktionsmethode ein Logikkalkül, das sich aus verschiedenen Beweisregeln zusammensetzt. Die Verifikationsaufgabe wird zunächst in Form von Vor- und Nachbedingungen formuliert, die anschließend durch sukzessive Anwendung der Beweisregeln ineinander überführt werden. [Hoffma08] 2.1 Bedingungen Deduktive Techniken spezifizieren die Eigenschaften eines Programms in Form von Vor- und Nachbedingungen. Analog zur klassischen mathematischen Beweisführung wird die Gültigkeit der Nachbedingungen durch die Anwendung spezieller Beweisregeln aus den Vorbedingungen hergeleitet. Sowohl die Vor- und Nachbedingungen, als auch alle geschlussfolgerten Aussagen, werden in einer formalisierten Sprache beschrieben – der sogenannten Logik. Durch die Hinzunahme der Beweisregeln wird eine Logik zu einem Logikkalkül erweitert. [Hoffma08] Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 6 Aussagenlogik Aussagenlogik beschäftigt sich mit Aussagen, Aussageformen und deren Verknüpfungen. Wichtig ist lediglich, dass sich eine Aussage formal als wahr oder falsch beantworten lässt, auch wenn, wie bei der dritten Aussage eine Bestätigung oder Verneinung von niemand wirklich gegeben werden kann. Die beiden möglichen Beurteilungen einer Aussage wahr oder falsch werden als Wahrheitswert bezeichnet. Die Aussagenlogik liefert nun Syntax und Semantik, um mit solchen Aussagenvariablen hantieren zu können. Hierfür gibt es logische Operatoren wie etwa Negation, Konjunktion und Disjunktion. Um zu sehen wie dies auf die Wahrheitswerte wirkt, berücksichtigt man alle Werte, die eine Aussagevariable annehmen kann und notiert das Ergebnis des Operators nach Anwendung auf die Aussagevariable. Mit der Aussagenlogik können also lediglich Aussagen gebildet und dann der Wahrheitswert bestimmt werden. [iGellne01] Mit Hilfe aussagenlogischer Ausdrücke können Beziehungen zwischen atomaren Aussagen formuliert werden, die ihrerseits einen der Wahrheitswerte Wahr (true) oder Falsch (false) annehmen können. Die klassische Aussagenlogik fällt damit in die große Gruppe der zweiwertigen Logiken. Wie die folgenden Beispiele zeigen, lassen sich atomare Aussagen mit Hilfe logischer Verknüpfungen rekursiv zu komplexeren Aussagen verbinden. Negation ¬A: A ist falsch Eine Verneinung bzw. Negation wendet den Sinn einer Aussage. Dies entspricht der Benutzung des Wortes nicht. Die Negation ist unär, d.h. sie hat nur einen Operanden. A A Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. wahr falsch falsch wahr 7 Tabelle 2-1: Wahrheitstabelle - Negation Konjunktion A ∧ B: A und B sind beide wahr Die Konjunktion verknüpft zwei Aussagen und liefert ein Ergebnis für beide Aussagen. Für die verknüpfte oder Gesamtaussage gilt hierbei, dass sie nur wahr sein, wenn beide Teile bereits wahr sind, in allen anderen Fällen resultiert für die Gesamtaussage ebenfalls der Wahrheitswert falsch. Die Konjunktion ist binär. A B A∧B wahr wahr wahr falsch wahr falsch wahr falsch falsch falsch falsch falsch Tabelle 2-2: Wahrheitstabelle - Konjunktion Disjunktion A ∨ B: A ist wahr oder B ist wahr Die ausschließende Veroderung bzw. Exklusion stellt eine Veroderung dar, bei nur eine Teilaussage wahr sein darf, damit die Gesamtaussage wahr liefert (entweder nur A oder nur B, nicht beides und auch nicht keines von beiden). In unserer Alltagssprache wird das Wort „oder“ sowohl für die Disjunktion als auch für die Exklusion verwendet. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. A B AvB wahr wahr falsch falsch wahr wahr wahr falsch wahr falsch falsch falsch 8 Tabelle 2-3: Wahrheitstabelle - Disjunktion Implikation A → B: Aus A folgt B Die Folgerung bzw. Implikation verknüpft wiederum zwei Aussagen zu einer. In diesem Fall so, dass die Gesamtaussage auch dann bereits als wahr gilt, wenn eine der beiden Aussagen A oder B bereits wahr ist. Die Implikation steht für die Beziehung, „wenn ... dann ...“ A B A→ B wahr wahr wahr falsch wahr wahr wahr falsch falsch falsch falsch wahr Tabelle 2-4: Wahrheitstabelle - Implikation Zu beachten sind die Festlegungen der Zeilen 2 und 4. Kann aus etwas Falschem etwas Wahres folgen? Aus logischer Sicht ja, aus falschen Daten kann zunächst immer alles folgen (das ist häufig das Verhängnisvolle). Wenn man falsch misst, rechnet oder eine Fehlerquelle in einem Versuchsaufbau hat, kann man zufällig immer auf ein (tatsäch- Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 9 lich) richtiges Ergebnis oder ein falsches Ergebnis kommen. Die Wahl von wahr ist im Fall falscher Vorderglieder von Implikationen per Definition gefunden worden. Äquivalenz A ↔ B: A und B sind beide wahr oder beide falsch Der Vergleich bzw. die Äquivalenz gleicht die Wahrheitswerte zweier Aussagen ab. Wenn beide Aussagen gleiche Wahrheitswerte haben (also auch wenn beide falsch sind) ist die Äquivalenz wahr. A B A↔B wahr wahr wahr falsch wahr falsch wahr falsch falsch falsch falsch wahr Tabelle 2-5: Wahrheitstabelle - Äquivalenz Die Ausdrucksstärke der Aussagenlogik reicht nicht an die Erfordernisse der SoftwareVerifikation heran, da ausschließlich Beziehungen zwischen den elementaren Wahrheitswerten True und False formuliert werden können. Die größte Bedeutung besitzt die Aussagenlogik im Bereich der Hardware-Verifikation. Auf der Logikebene lässt sich das Verhalten einer kombinatorischen Hardware-Schaltung eins zu eins auf eine aussagenlogische Formel abbilden. Trotzdem spielt sie auch im Bereich der SoftwareVerifikation eine indirekte Rolle, da sie als Teilmenge in allen anderen Logiken enthalten ist. Als eine der wenigen Logiken erfüllt die Aussagenlogik das Kriterium der Entscheidbarkeit. Eine Logik heißt entscheidbar, falls die Allgemeingültigkeit einer beliebigen aussagenlogischen Proposition auf algorithmischem Weg in endlicher Zeit entschieden werden kann. Im Falle der Aussagenlogik kann diese Eigenschaft durch das Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 10 erschöpfende Einsetzen aller möglichen Variablenkombinationen auf einfache Weise überprüft werden – wenngleich die Laufzeit eines solchen Algorithmus exponentiell mit der Formelgröße wächst. In der Literatur wird die Aussagenlogik auch als Prädikatenlogik nullter Stufe, kurz PL0, bezeichnet. [Hoffma08] Prädikatenlogik Die Prädikatenlogik erweitert die Ausdrucksmöglichkeiten der Aussagenlogik, dies wird ergänzt um Prädikate bzw. Prädikatsymbole und um Quantoren. Prädikate (Aussageformen) Prädikate sind Sätze, die Variablen enthalten und die beim Ersetzen dieser Variablen mit Elementen einer gegebenen Menge eine Aussage bilden (also auf die Menge {wahr, falsch} abbilden). a) Prädikatsymbole Führt man für Prädikate „Satzelement, Satzelement ... Satzelement“ eine abkürzende Schreibweise wie Folgende ein Bezeichner(Argument 1, Argument 2, ..., Argument n) so nennt man Bezeichner Prädikatsymbol und den ganzen Ausdruck atomare prädikatenlogische Formel. Beispiel: ist_prim(n) ggT(i, j, n) Falls für ein Element Argument i aus einer Menge G Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 11 Bezeichner(Argument 1 _ G, ..., Argument n _ G,) = wahr gilt, so sagt man, Bezeichner gilt für Argument. Beispiel: ist_prim(n) gilt für 7. ggT(i, j, n) gilt für 10, 25 und 5 Prädikatsymbole können als Abbildungen von beliebigen Grundmengen auf boolesche Mengen interpretiert werden. Damit fehlen als Ausdrucksmittel der Prädikatenlogik noch die Quantoren. [Gellne01] [Myers01] b) Quantoren Der Begriff Quantor hängt mit dem Begriff der Quantität zusammen. Quantitativ möchte man in der Mathematik in der Regel zwei Dinge ausdrücken: „Für alle n Elemente gilt“ und „es gibt (mindestens) ein Element n, für das gilt“. Den ersten Sachverhalt drückt man mit „∀n“ aus, den zweiten mit „Ǝ n“. Durch das Voranstellen des Allquantors ∀ vor einen Term entsteht eine Allaussage, durch das Voranstellen eines Existenzquantors Ǝ eine Existenzaussage, dieser Vorgang wird auch als Quantifizieren bezeichnet. Es lassen sich weitere Quantoren realisieren wie etwa ein Keinquantor, diese sind in der Regel jedoch durch die Kombination aus Allquantor oder Existenzquantor mit einem logischen Operator ebenso erzeugbar. Eine wichtige Unterscheidung besteht zwischen freien und gebundenen Variablen: eine gebundene Variable ist eine Variable die in Verbindung zu einem Quantor steht, eine freie Variable ist von einem Quantor unbeeinflusst. Ǝ x.P(x, x) beide x sind durch die Bindung des x an den Quantor gebunden ∀ x.P(x, y, z) x ist an den Quantor gebunden, y und z sind frei Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. ∀ (x, y, z).P(x, y, z) 12 sowohl x als auch y und z sind gebunden, keine Variable von P ist frei Besitzt eine Formel keine freien Variablen, nennt man sie geschlossen. Einer geschlossenen Formel kann man einen Wahrheitswert zuordnen. [Gellne01] [Myers01] Temporallogik Für die Modellierung zeitlicher Kausalzusammenhänge wurden in der Vergangenheit verschiedene Temporallogiken entwickelt, die auf der Aussagenlogik bzw. der Prädikatenlogik aufbauen und diese um spezielle temporale Operatoren ergänzen. Diese Logiken werden insbesondere im Bereich der Modellprüfung eingesetzt und später genauer beleuchtet. [Hoffma08] Höherwertige Logik Höherwertige Logiken unterscheiden sich von der Prädikatenlogik erster Stufe durch einen erweiterten Geltungsbereich der Quantoren ∀ und ∃. Im Gegensatz zur PL1, in der die Quantoren ausschließlich auf Variablen angewendet werden dürfen, erlauben höherwertige Logiken die Quantifizierung über Prädikate hinweg. Die Verallgemeinerung der Quantifizierungsregeln verleiht den höherwertigen Logiken eine ungeahnte Ausdrucksstärke, wie das Beispiel der natürlichen Zahlen eindrucksvoll unter Beweis stellt. Die natürlichen Zahlen lassen sich mit Hilfe der 5 Peano-Axiome formalisieren, die bereits seit dem Ende des neunzehnten Jahrhunderts bekannt sind und auf die Arbeiten des italienischen Mathematikers Giuseppe Peano zurückgehen. Mit Hilfe der Prädikatenlogik erster Stufe lassen sich die Axiome nicht beschreiben. Schuld daran ist das Induktionstheorem – Peanos fünftes Axiom: ∀P : ((P(0)∧∀n : P(n)→P(suc(n)))→∀n : P(n)) Das Induktionstheorem wendet den Allquantor auf Prädikate an und lässt sich daher nicht mit den Mitteln der Prädikatenlogik erster Stufe formulieren. Da die allermeisten Korrektheitseigenschaften Aussagen über natürliche Zahlen beinhalten, ist der Einsatz Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 13 höherwertiger Logiken im Bereich der Software-Verifikation nahezu unumgänglich. Auch die Vor- und die Nachbedingung unseres Beispielprogramms machen eine Aussage über die natürlichen Zahlen. Damit erfordert bereits der vergleichsweise einfache Korrektheitsbeweis der Funktion exp zwingend den Einsatz einer höherwertigen Logik. Auf der negativen Seite verfügen höherwertige Logikkalküle nur über ein geringes Automatisierungspotenzial, so dass große Teile eines Korrektheitsbeweises manuell durchgeführt werden müssen. Die Berechenbarkeitstheorie setzt ebenfalls klare Grenzen. Bereits in den frühen Dreißigerjahren konnte der Mathematiker Kurt Gödel formal beweisen, dass höherwertige Logiken die Eigenschaft der Semi-Entscheidbarkeit verlieren. Kurzum: Es lassen sich wahre Aussagen formulieren, die sich innerhalb des Logikkalküls nicht als solche beweisen lassen. [Hoffma08] [Myers01] 2.2 Verifikation nach Hoare Einer der wesentlichen Grundsteine der deduktiven Software-Verifikation wurde 1969 von dem britischen Mathematiker C. A. R. Hoare gelegt. Das Hoare-Kalkül ist ein axiomatisches System, dessen Vorgehensweise bis heute das Grundprinzip aller deduktiven Verfahren bildet. [Hoffma08] Das Hoare-Tripel Innerhalb des Kalküls werden alle Aussagen in Form von Hoare-Tripeln notiert, für die sowohl eine Spaltenschreibweise als auch eine Zeilenschreibweise existiert. [Hoffma08] Die Anwendung der Regeln des Hoare-Kalküls führt auf Hoare-Tripel, das heißt auf Gruppen von drei Elementen folgender Art: {P} S {Q} Hierbei werden P und Q Zusicherungen genannt, S steht für eine Anweisung (ein Statement) in einer Programmiersprache. Weiterhin wird zwischen Zusicherungen un- Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 14 terschieden, die vor einer Anweisung S und danach stehen, P ist eine Vorbedingung und Q ist eine Nachbedingung. Der Zusammenhang zwischen P, S und Q ist folgender: Wenn vor der Ausführung von S die Programmvariablen das Prädikat P erfüllen, so erfüllen sie nach der Ausführung (und Terminierung) von S das Prädikat Q. Weit verbreitet (weil im Quelltext realisierbar) ist die Notation der Hoare-Klauseln als Kommentar im Quelltext: {x+1>a} x := x + 1; {x>a} Partielle und Totale Korrektheit – Terminierung Man unterscheidet generell zwischen totaler Korrektheit und partieller Korrektheit, wobei der Unterschied in der Terminierung des Programmstückes liegt. Schließt P die sichere Terminierung mit ein, spricht man bei erfolgtem Beweis von einem total korrekten Programmteil, andernfalls nur von partieller Korrektheit. Kann zunächst lediglich der Beweis partieller Korrektheit erbracht werden, gibt es die Möglichkeit, Terminierungsbeweise separat zu führen. In beiden Fällen kann gezeigt werden, dass der Quelltext korrekte Ergebnisse liefert. Im Fall totaler Korrektheit ist auch sicher gestellt, daß das Programm terminiert, partielle Korrektheit besagt hingegen nur, dass die Ergebnisse korrekt sind, wenn das Programm terminiert, nicht jedoch, dass es terminiert. Die Grundlage für die Programmverifikation sind prädikatenlogische Ausdrücke, die auf den Zuständen eines Programms basieren, also mit den in den Variablen enthaltenen Werten an bestimmten Programmstellen. Diese Ausdrücke, Hoare-Klauseln genannt, basieren selbst wiederum auf sogenannten Beweisregeln. [BibelW91] Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 15 Hoare Regeln 2.2.3.1 Aufbau Beim Hoare-Kalkül handelt es sich um bis eine Menge von Regeln, die sich aus Prämissen und Schlussfolgerungen zusammensetzen. Prämisse 1 Prämisse 2 _ Prämisse n _______________ Konklusion Der Strich unter den Prämissen (Voraussetzungen) ist eine weitere Art neben den Symbolen _ und _ Folgerungen auszudrücken. Im Unterschied zu Formeln mit Folgerungen wie (A = B) und (B = C) (A = C) handelt es sich um Schlussfolgerungen (Konklusion, Conclusio). Dies ist anschaulich vergleichbar mit dem Strich unter dem Einkaufszettel: alle Elemente werden addiert, der Summenstrich trennt jedoch das Endergebnis von den anderen Summanden und Zwischenergebnissen, die man notieren könnte. Aus syntaktischer bzw. algebraischer Sicht unterscheidet sich die Schlussfolgerung nicht wirklich von den bisher betrachteten Implikationen, die Unterscheidung mit dem Schlussstrich ist eher inhaltlich begründet. In verschiedenen Quellen wird auch auf diese Darstellung verzichtet und ausschließlich mit Pfeilsymbolen gearbeitet, hier jedoch wird auf sie zurückgegriffen, da sie anschaulicher erscheint. [BibelW91] Der Prozess des Schlussfolgerns auf diese Art ist auch als deduktives Schließen bekannt. Grundsätzlich ist das nichts unbekanntes, wir denken ohnehin in vergleichbarer Art und Weise, lediglich auf die formale Schreibweise verzichten die meisten Menschen im Alltag. Bestimmte Konstellationen aus Prämissen und Konklusionen, die in der Praxis häufiger zitiert werden, haben eigene Bezeichnungen. Die folgende Konstellation wird als Modus tollens bezeichnet: Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 16 AB ¬B _______ ¬A Nach Änderung der zweiten Prämisse zu A folgt ein gegenteiliger Schluss, dies wird Modus ponens genannt: AB A _______ B Eine weitere bekannte Konstellation ist der Modus barbara, ein Syllogismus. Das heißt, es handelt sich um Aussagen, die von allen Elementen einer Menge auf einige bzw. mindestens eines schließen. Der Moduls barbara ist wie folgt aufgebaut: BC AB _______ AC [Gellne01] [Myers01] 2.2.3.2 Beweisregeln des Hoare-Kalkül Die Klauseln stehen zueinander in einem festen logischen Kontext – sie sind nicht einfach nur Notizen (dies ergäbe schließlich keinen Beweis im Sinne der Mathematik), sondern werden nach den bereits erwähnten Regeln von unten nach oben eingefügt1. Gelingt es, diese Klauseln in den Quelltext nach den Hoare-Regeln einzufügen ohne das sich widersprechende Terme auftreten und ohne, dass diese in ihrer Semantik vom Quelltext abweichen, ist bewiesen, dass das Programm formal korrekt arbeitet, also für die definierten Eingaben die erwarteten bzw. korrekten Ausgaben liefert. [Gellne01] Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 17 Das Hoare-Kalkül stellt verschiedene Beweisregeln zur Verfügung, die allesamt nach dem folgenden Schema aufgebaut sind: {P1} S1 {Q1}, . . . ,{Pn} Sn {Qn} {P} S {Q} Leere Anweisung _________________ { P } NOP { P } In einem Programm, das keine Zustände verändert bzw. in dem nichts ausgeführt wird, bleibt P gültig. [Gellne01] Zuweisungsregel __________________ { PEx } x := E { P } Hierbei bedeutet PEx, dass x durch E substituiert werden muss, damit die Nachbedingung P wahr wird. Da diese Regel keine Prämissen hat, wird sie auch als Axiom bezeichnet, also als Grundsatz, der nicht weiter zu begründen ist. [Gellne01] Die Regel wird herkömmlich auf Zuweisungen so angewendet, dass die rechte Seite der Zuweisung im Quelltext jedes Vorkommen der Variablen in der oberen Klausel ersetzt. Also: Von unten kommend liegt folgendes Stück Quelltext vor, die untere Klausel ist dadurch gegeben, woher sie kommt, spielt in diesem Kontext keine weitere Rolle. {?} x := x + 1; {x>a} Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 18 Jedes Vorkommen des Ausdrucks x in der unteren Klausel muss in der oberen Klausel nun durch den rechten Teil der Zuweisung substituiert werden. Term nach der Substitution Ausdruck, der nach ben hin zu substituieren ist (weil die Zuweisung genau dessen Zustand manipuliert hat) {x+1>a} x := x + 1; {x>a} Ausdruck, der in den zu substituierenden Ausdruck einzusetzen ist. Abbildung 2-1: Beispiel Anwendung Zuweisungsregel (in Anl. an Gellne01) Hierbei können weitere Überlegungen notwendig sein. Denkbar ist zum Beispiel die Veränderung einer Relation anstelle der direkten Substitution mit dem Ausdruck x + 1: {x≥a} x := x + 1; {x>a} Da der Hoare-Kalkül jedoch so weit wie möglich formal abgearbeitet werden soll, sind solche Umformungen nur hilfreich, wenn der vorliegende Term mit Termen in anderen Klauseln zur Übereinstimmung gebracht werden soll. Jede Vereinfachung oder Zusammenfassung vorzunehmen, weil man sie gerade erkennt, ist genau genommen nicht Sinn der Sache. Es soll letztendlich bewiesen werden, dass ein Quelltext korrekt arbeitet und nicht der Grad der Virtuosität, in dem Beweisende Terme umformen kann. [BibelW91] Kompositionsregel { P } S1 { Q }; { Q } S2 { R } { P } S1; S2 { R } Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 19 Für zwei Anweisungen S1 und S2, die nacheinander ausgeführt werden, können zu einem Programmstück S bestehend aus der Sequenz S1; S2 zusammengesetzt werden, wenn die Nachbedingung von S1 mit der Vorbedingung von S2 identisch ist. Mathematisch ausgedrückt: Wenn S1 Variablen von einem Zustand σ nach den Vorbedingungen P aus in einen Zustand σ' versetzt werden, in dem die Nachbedingungen Q gültig sind, und S2_von einem Q-Zustand σ' in einen R-Zustand σ'' führt, dann führt die Nacheinandderausführung von S1 und S2 auch von einem Zustand σ zu einem Folgezustand σ''. Die Verifikation funktioniert anhand von logischen Ausdrücken, sogenannten Zusicherungen, die um die Programmteile herum angebracht werden. Der Ansatz bei dieser Technik sind die Zustände eines Programms - also die jeweiligen Werte der enthaltenen Variablen. Die Folge einfacher Anweisungen r := r - y; q := q + 1; Hier kann gemäß der Regel für Anweisungsfolgen zeilenweise vorgegangen werden: { x = y · (q + 1) + r - y } r := r - y; { x = y · (q + 1) +r } q := q + 1; {x=y·q+r} Die Regel der sequentiellen Komposition wird nur an einer Stelle direkt angewandt, sie schafft die Grundlage dafür, dass Anweisungsfolgen in der gezeigten Art nacheinander überhaupt abverifiziert werden können: Geht man von der zweiten Spezifikation aus, die nur umfassend verifiziert ist, erlaubt die Regel in dieser Hinsicht betrachtet die im darüber stehenden Listing gezeigte Einbringung von Hoare-Klauseln zwischen den Quelltextzeilen. [Gellne01] [BibelW91] Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 20 Fallunterscheidungsregel { P ∧ B } S1 { R } { P ∧ ¬B } S2 { R } { P } if B then S1 else S2 { R } S1 führt unter der Bedingung B von einem Zustand P auf einen Zustand R, ebenso S2 unter der Bedingung ¬B. [iGellne01] Iterationsregel a) Präkonditionierte Schleifen {I∧B}S{I} { I } while B do S { I ∧ ¬B } Bei While-Schleifen wird der Rumpf S der Wiederholungsanweisung so lange wiederholt, bis die Wiederholungsbedingung B nicht mehr erfüllt ist (also bis ¬B gilt). Zur Verifikation von While-Schleifen ist es notwendig, eine sogenannte Invariante I zu finden. Invarianten gelten nach jedem Schleifendurchlauf und beschreiben innerhalb der Schleifendynamik das Gleichbleibende. Das Finden von Invarianten ist eine der Schwierigkeiten des Hoare-Kalküls, mit Erfahrung und Übung werden Invarianten einfacher und schneller gefunden, einen eindeutigen und sicheren Weg hierfür gibt es jedoch nicht. Allerdings gibt es schon einige Heuristiken, d.h. Faustregeln, die eine ganze Reihe von Fällen bereits abdecken. 1. Eine Konstante variabel machen 2. Den Bereich einer Variablen erweitern 3. Eine Disjunktion hinzufügen (A um B zu A v B ergänzen) Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 21 4. Eine Konjunktion aus einem Term weglassen, etwa wenn dieser Teil der Schleifenbedingung entspricht 5. Die im Verlauf der Schleife manipulierten Variablen in einer Tabelle mit einer ausreichenden Anzahl von Werten durchtracen um die Gesetzmäßigkeit leichter zu erkennen, die sich hinter dem Ablauf verbirgt. 6. In vielen Fällen (bei Berechnungen nach mathematischen Vorgaben) erfüllt die Rechenregel, die ohnehin Motivation für die Entwicklung der Schleife war, bereits die Anforderungen, die an eine Invariante gestellt werden (also eben invariant zu sein). Neben der Korrektheit von Schleifen muss in separaten Terminierungsbeweisen auch die Terminierung von Schleifen bewiesen werden, wenn die totale Korrektheit von Programmen gezeigt werden soll, andernfalls liegt nur eine partielle Korrektheit vor. [BibelW91] b) Postkonditionierte Schleifen Die Anwendung dieser Regel ist nur bedingt empfehlenswert. Generell sind Schleifen gleichmächtig, keine der drei Schleifen (in Pascal While-, For- und Repeat-Schleifen, allgemein Schleifen mit Eintrittsbedingung, Zählschleifen, Schleifen mit Austrittsbedingung) ermöglicht Implementierungen, die sich mit den jeweils anderen Konstrukten nicht erreichen lässt. Da die Verifikation der Schleife mit Eintrittsbedingung einfacher ist als die der anderen Schleifen, ist es üblich und wird empfohlen, für diesen Zweck die Schleife im Quelltext als Schleife mit Eintrittsbedingung zu formulieren. Die HoareRegel für Schleifen mit Austrittsbedingung: {I}S{R} { R ∧ ¬B} S { R } { I } repeat S until B { R ∧ B } [BibelW91] Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 22 Implikationsregel a) Verstärkung der Vorbedingung { P } S { Q }, Q R {P}S{R} Wenn über einen Quelltext S aus einem Zustand P ein Folgezustand Q resultiert und aus Q wiederum ein Zustand R, dann folgt R letzten Endes bereits aus den Zustandsmanipulationen die der Quelltext S im laufenden Programm verursacht. b) Abschwächung der Nachbedingung P R, { R } S { Q } {P}S{Q} Wenn aus einem Zustand P ein Zustand R folgt, aus dem über den Quelltext S ein Zustand Q angenommen wird, dann folgt Q bereits aus P. [Gellne01] Zuweisung Komposition Fallunterscheidung Iteration Verstärken der Vorbedingung {True} {P [x←c]}x = c;{P} {P} S1 {Q},{Q} S2 {R} {P} S1;S2 {R} {P∧B} S1 {Q},{P∧¬B} S2 {Q} {P} if B then S1 else S2 {Q} {I ∧B} S {I} {I} while B do S {I∧¬B} P⇒Q,{Q} S {R} {P} S {R} Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Abschwächen der Nachbedingung 23 {P} S {Q},Q⇒R {P} S {R} Tabelle 2-6: Beweisregeln des Hoare-Kalküls (in Anl. an Hoffma08) Vorgehen der Verifikation Der Beweis der Korrektheit eines Programmes oder Programmteiles wird nun in den folgenden Schritten vollzogen: 1. Die Nachbedingungen des gesamten Programmstückes werden notiert. Es wird also niedergeschrieben, zu was das Programmstück eigentlich dient. Hieran muss sich dann der Quelltext messen lassen: einzig an dem, was das Programm machen soll. Die letzte Anweisung, die ausführbaren Code enthält, wird ermittelt (also kein „end“ oder auch keine anschließende Rückgabe von Werten – obwohl diese auch einer Zuweisung entsprechen kann. Hier hinter wird die Nachbedingung eingetragen. Sofern eine algebraische Spezifikation oder eine andere formale Beschreibung vorliegt, kann die Nachbedingung auch hier entnommen werden. Sofern diese Beschreibung noch gültig ist, muss das Programm das ermitteln, was laut Spezifikation vorgegeben ist. 2. Die Vorbedingungen werden notiert. Diese folgen ähnlich den Nachbedingungen aus dem Kontext und können „schwach“ gehalten werden. Wenn einem hierbei nichts einfällt, kann theoretisch false als Vorbedingung eingetragen werden. Dies ist als Vorbedingung allerdings nicht nur schwach sondern auch trivial, da aus etwas Falschem immer alles gefolgert werden kann. 3. Von unten nach oben werden nun die passenden Hoare-Regeln für die jeweilige Anweisung auf den gesamten Quelltext angewendet. Schleifen werden zunächst von außen behandelt, dann folgt der Rumpf, wobei hier wieder von unten nach oben vorgegangen wird. Sind die inneren Anweisungen mit Klauseln versehen (und ist die Schleife auch innen mit Klauseln versehen, folgt die nächste Anweisung oberhalb der Schleife. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 24 4. Wenn alle Anweisungen mit Hoare-Klauseln versehen sind, liegt eine Beweisskizze oder Spezifikation (auch Tableau, z.B. in [Bac 89]) vor. Taucht hierbei kein Widerspruch auf, zeigt dies, dass ein Programmteil S unter der Vorbedingung P auf die Nachbedingung Q führt und der Beweis ist erbracht. Die Literatur äußert sich verschiedentlich zur „Richtung“ des Hoare-Kalküls und schreibt beispielsweise, dieser sei rückwärtsgewandt. Das ist in bestimmten Phasen richtig, in anderen jedoch absolut nicht. Beim Finden von Hoare-Klauseln (also beim Erstellen der Beweisskizze) ist es zutreffend, dass diese von unten nach oben ermittelt werden. Die Hoare-Regeln bieten diese Nutzung an (von oben nach unten zu nutzende Regeln können zwar aus den vorhandenen abgeleitet werden, sind aber wesentlich umständlicher und schwerer zu nutzen), ferner erscheint es sinnvoll nicht in der selben Richtung zu verifizieren, in die man bereits beim Implementieren falsch denkt. Die Wahrscheinlich Fehler zu finden und nicht in den Beweisen fortzupflanzen ist dabei größer. Die Verifikation ist abgeschlossen, wenn man von den letzten Anweisungen bzw. von den Zielvorgaben bis hin zum Anfang das Programm durchgegangen ist, ohne dass Widersprüche in den Klauseln aufgetreten sind. [Myers01] Beispiel Das folgende Stück Code ermittelt den Rest einer ganzzahligen Division mit Eingaben für x und y >= 0. Teilt man etwa 25 durch 4 mit dem Aufruf rest(25, 4) passt dies 6-mal (6 × 4 = 24), der Rest 1 bleibt übrig. Diese Reste ermittelt die Routine: function rest (x : integer; y : integer) : integer; var q, r : integer; begin ... q := 0; r := x; while r >= y do begin r := r - y; Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 25 q := q + 1; end; ... end; Abbildung 2-2: Code Beispiel: Rest-Ermittlung einer ganzzahligen Division Das Prinzip ist, solange von der größeren Zahl den Divisor abzuziehen, bis das Ergebnis kleiner als der Divisor ist, dies ist der Rest. Es ergibt sich ganz allgemein folgendes Hoare-Tripel: {P: x ³ 0 Ù y > 0} Routine rest {Q: x = q × y + r Ù r ³ 0 Ù r < y} Unter der Bedingung gültiger Eingaben, ergibt sich also eine Konstellation der Zahlen, in der x aus der Eingabe y und Anzahl der Divisionen q sowie dem Rest rekonstruierbar ist und in der 0 £ r < y gilt (r kann minmal 0 sein und maximal y – 1 sein, anderfalls wäre r kein richtiger Rest). Die Verifikation wird von hinten nach vorne durchgeführt, zielorientiert also. Zunächst bilden sich vier Abschnitte v1, v2, v3 und v4 heraus: Abbildung 2-3: Darstellung der 4 Beweisabschnitte Die Beweisdurchführung: Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 26 (I) Es gilt für den Abschnitt v1: {x=q×y+r} v1 {x=q×y+r} Begründung: Vor Ausführung gilt x=q×y+r Danach gilt = (q + 1) × y + r - y (Anweisungen in v1) also = (qy + y) + r - y (umformen) =q×y+r (II) Für den Abschnitt v2 gilt: {x=q×y+rÙr³0} v2 { x = q × y + r Ù r ³ 0 Ù r < y} Begründung: Vor Ausführung gilt x=q×y+rÙr³0 Danach gilt = q × y + r (folgt aus (I)) Da die Schleife nur ausgeführt wird, wenn r ³ y ist, kann r im Schritt r := r - y; nicht kleiner 0 werden, wenn am Anfang r ³ 0 erfüllt war, daher gilt r ³ 0 nach v2. Ist hingegen r > y kommt die Schleife nicht mehr zur Ausführung. Bis dieser Zustand eingetreten ist, wird die Schleife allerdings durchlaufen, daher gilt auch r < y nach v2. (III) Für Abschnitt v3 gilt: {x³0Ùy>0} v3 { x = q × y + r Ù r ³ 0} Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 27 Begründung: Vor Ausführung gilt: x³0Ùy>0 Danach gilt: x=0×y+x Dies folgt aus der Belegung von q mit 0 und von r mit x. (IV) und für v4 gilt: {x³0Ùy>0} v3 { x = q × y + r Ù r ³ 0 Ù r < y} Dies folgt direkt aus (II) und (III). Da das Beweisen von Programmen eine kompliziertere Angelegenheit ist, gebietet die Praxis nicht erst ein langes Programm einzugeben und dann 'durchzubeweisen', sondern Programm und Beweis Hand in Hand zu entwickeln und entsprechend gradlinig zum einfachen Beweisen zu implementieren. [Gellne01] 2.3 Anwendung in der Praxis Neben zahlreicher Kritik an der axiomatischen Semantik ‚von außen’ also an deren Anwendung schlechthin, an deren Kompliziertheit etc. – dies wird weiter hinten ausführlicher diskutiert – ist seit einer einschlägigen Publikation von Clarke 1979 auch ein schwerwiegender inhaltlicher Mangel bekannt: Sobald das Prozedurkonzept reichhaltig genutzt wird, ist es prinzipiell unmöglich, ein vollständiges Hoarsches Beweissystem zu finden [Clarke79]. Dies auch dann, wenn man sich auf logische Strukturen mit einem endlichen Datenbereich einschränkt. Damit kommt die Hoare’sche Logik in der Praxis relativ schnell an ihre Grenzen, denn kaum ein Softwaresystem, das heute realen Anfor- Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 28 derungen genügen muss, kann aus Gründen der Komplexität in monolithischer Form erstellt werden. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 29 3 Modellprüfung Autor: Tim Strauss 3.1 Einleitung Die fachspezifische Literatur verwendet für den Begriff Modellprüfung regelmäßig die englische Übersetzung Model Checking als gängiges Synonym [ClGrPe00, Holzma03, Busche04, et al.]. Trotz dieser weit verbreiteten Ersetzungslogik liegt keine einheitliche Definition der Begrifflichkeit vor. Folgend eine Zusammenstellung diverser Ansätze verschiedener Autoren: “Model checking is a technique for verifying finite state concurrent systems.” [ClGrPe00] “[…] method […] to check the correctness of software designs[…].” [Holzma03] “[…] model checking, a technique for automated verification of software and reactive systems.” [Berard01] “Die Technik der Modellprüfung […] übersetzt ein Programm zunächst in eine Kripke-Struktur. Die zu verifizierenden zeitlichen Eigenschaften werden in einer Temporallogik formuliert und mit Hilfe spezieller Traversierungsalgorithmen nachgewiesen oder widerlegt.” [Hoffma08] Die zuletzt genannte und am detailliertesten formulierte Definition von Hoffmann wird für den weiteren Verlauf dieses Kapitels als Arbeitsgrundlage festgelegt. Sie verdeutlicht die verschiedenen Bestandteile der Modellprüfung anschaulich und eignet daher in besonderem Maße für die weiteren Ausführungen. Der Definition folgend und in Bezugnahme auf das Grundschema der Software-Verifikation [Vgl. Abbildung 1-1] um- Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 30 fasst der Ansatz zur Überprüfung von Eigenschaften des modellierten Systems drei Stufen [Marwed07, S. 234f]: 1. Überführen des zu verifizierenden Systems oder der zu verifizierenden Software in ein geeignetes Modell [Vgl. 3.2] 2. Beschreiben der erwarteten Systemeigenschaften (Verhaltensgrundsätze, Funktionalität) [Vgl. 3.3] 3. Model Checking: Durchführen der eigentlichen Verifikation [Vgl. 3.4] Die Korrektheit eines Systems ist also genau dann gegeben, wenn die Systemeigenschaften E in dem durch endlich viele Zustände S beschriebenen Modell M(S) gelten – formal ausgedrückt: M ( S ) | E Abgrenzend zur Verifikation von nicht funktionalen Eigenschaften, wie beispielsweise die maximale Antwortzeit oder der minimale Datendurchsatz, beschränkt sich das Einsatzgebiet der Modellprüfung auf die Verifikation von funktionalen Systemeigenschaften. Charakteristische Vertreter dieser Art sind zum Beispiel Gefahrlosigkeits- und Lebendigkeitseigenschaften. [HauTei10] oder Sicherheitseigenschaften [Scholz05]. Die Gefahrlosigkeitseigenschaft besagt, dass ein System oder eine Software niemals in eine gefährliche Situation laufen wird (Absturz) bzw. in einer Situation verharren muss (Locks und Freezes). Dagegen beschreibt die Lebendigkeitseigenschaft die Tatsache, dass irgendwann in einem Programmablauf das gewünschte Ergebnis eintreten kann. Zu den Sicherheitseigenschaften wird beispielsweise die Transaktionssicherheit gezählt. Entgegen der zuvor beschriebenen Deduktionstechnik [Vgl. 2], welche ein System und dessen Eigenschaften vollständig beschreiben und validieren kann, ist der Methodeneinsatz der Modellprüfung auf die Verifikation von zeitlichen, funktionalen Eigenschaften limitiert, auch partielle Verifikation genannt. [Hoffma08]. Diese Einschränkung der Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 31 Ausdrucksstärke ist den zu verwendenden Formalisierungslogiken geschuldet, fördert ihrerseits dagegen die Möglichkeit der automatisierten Beweisführung Hinsichtlich der Anwendbarkeit des Model Checking Ansatzes auf komplexe Informationssystemen kann mittlerweile die gesamt Breite bedient werden, d.h. sowohl Hardware- als auch Softwarekomponenten können mit Hilfe der Modellprüfung auf deren Korrektheit geprüft werden. Historisch betrachtet hat die Hardwareverifikation den Anfang gemacht, wobei im Laufe der Entwicklung zunehmend auch der der Bereich der Softwareprüfung in den Fokus gerückt ist [Scholz05]. Im weiteren Verlauf dieser Arbeit wird die Hardwareverifikation vernachlässigt. 3.2 Formale Softwaremodellierung Die Modellprüfung beginnt in ihrem ersten Schritt [Vgl. 3.1] mit einer für die eigentliche Verifikation notwendigen Vorarbeit – der Formalisierung des zu prüfenden Programms durch ein Modell. Bereits in diesem Punkt unterscheidet sich die Modellprüfung grundlegend von der Deduktionstechnik [Vgl. 2]: deduktive Verfahren verifizieren die Software direkt basierend auf dem Programmquellcode und kommen daher ohne ein Modell aus. Unter einem Modell versteht man im Allgemeinen ein Abbild der Wirklichkeit. Dieses repräsentiert meist nur einen bestimmten Ausschnitt der Realität, welcher für die Analyse eines entsprechenden Anwendungsfalls von Bedeutung ist. Trotz dieser verkürzten Darstellung muss allerdings immer gewährleistet sein, dass die erstellte Abbildung in sich schlüssig und valide modelliert ist [Stacho73]. Eine Verifikation, die auf einem fehlerbehafteten Modell basiert, kann keine Gewissheit über die Korrektheit des Programms determinieren. Diese Tatsache stellt eine wichtige Randbedingung für und gleichzeitig Kritik gegen die Verwendung der Modellprüfung als Verifizierungsmethodik dar. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 32 Für das Model Checking hat sich die Kripke-Struktur als geeigneter Modelltyp bewiesen. Scholz definiert diese als „eine Art von endlichen Zustandsübergangssystemen“ [Scholz08], ähnlich formuliert es auch das Informatik-Spektrum durch die Worte „eine Form zustandsbasierter Transitionsgraphen“ [Busche04]. Beiden Definitionen folgend kann eine Kripke-Struktur M als ein Viertupel beschrieben und wie folgt charakterisiert werden: M (S , S 0 , R, L) Wobei S eine endliche Menge von Zuständen repräsentiert S0 die Menge der Anfangszustände darstellt ( S0 S ) R eine Zustandsübergangsrelation repräsentiert ( R S S ), d.h. für jeden Zustand s S existiert ein Folgezustand s' S mit R ( s, s ' ) L eine Markierungsfunktion darstellt ( L : S ), welche jeden Zustand auf A eine Menge von zugehörigen atomaren Aussagen A abbildet Anhand des in der Literatur häufig verwendeten Beispiels der konkurrierenden Ressourcen-Zugriffe zweier Prozesse [iCMSCS83, Hoffma08, et al.] wird im Folgenden exemplarisch ein Modell beschrieben: Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 33 N1N2 0 N2C1 N2T1 N1T2 1 2 3 4 T1T2 T1T1 5 6 7 8 T2C1 T1C2 N1C2 Abbildung 3-1: Exemplarische Kripke-Struktur (in Anl. an iCMSCS83) Die Kripke-Struktur beschreibt ein einfaches, überschaubares Programm, welches sich zu einem bestimmten Zeitpunkt in einem der 9 definierten Zustände S befindet. Der Initialzustand S0 stellt den Start der Programmausführung dar und wird in der Struktur optisch hervorgehoben. Die Zustandsübergangsrelationen R werden in Form der gerichteten Kanten innerhalb der Struktur abgebildet und verdeutlichen so die möglichen Folgezustände aus der aktuellen Situation. Für die Beschreibung der Software reichen des Weiteren drei atomare Aussagen aus, in denen sich die Prozesse i befinden können (mit i 1,2 ): Ni : Prozess i in unkritischer Region Ti : Prozess i in der Anmeldephase Ci : Prozess i in kritischer Region Eine Menge aussagenlogischer Variablen, bestehend aus zwei atomaren Aussagen, jeweils eine Aussage pro Prozess, wird in jedem Zustand der Kripke Struktur abgebildet. Aus der Summe der definierten Modelleigenschaften ergibt sich die Kripke-Struktur aus Abbildung 3-1. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 34 3.3 Formulierung der Softwareeigenschaften Die Definition der zu überprüfenden Systemeigenschaften stellt den zweiten Schritt des Model Checkings dar [Vgl. 3.1]. Für deren formale Spezifizierung muss auf eine Logik zurückgegriffen werden, welche die veränderliche Dynamik eines Softwaresystems beschreiben kann. Der Einsatz klassischer Logiken, wie der Aussagen- oder Prädikatenlogik, ist ausgeschlossen, da die Modellierung zeitlicher Eigenschaften und Abhängigkeiten mit den gegebenen Möglichkeiten nicht realisierbar ist. Durch die Erweiterung dieser Sprachkonstrukte um Zeitoperatoren [Vgl. 3.3.1] entstehen schließlich Temporallogiken [Vgl. Abbildung 3-2], welche ausreichende Formalismen für derartige Spezifikationen bereitstellen. [Busche04, Scholz08] Temporallogik temporale Operatoren Aussagenlogik Quantoren Prädikatenlogik Abbildung 3-2: Teilgebiete der Logik In der Theorie gibt es eine Vielzahl unterschiedlicher Temporallogiken, die sich jeweils in ihren Semantik und Ausdrucksmächtigkeit unterscheiden. Oftmals werden aus komplexen Logiken bestimmte Untermengen herausgelöst, um für einen konkreten Anwendungsfall ein passendes und angemessenes Werkzeug bereitstellen zu können. So hat sich für die Software-Verifikation der Einsatz zweier Untermengen der CTL* Logik [Vgl. Abbildung 3-3] als die wichtigsten Vertreter herauskristallisiert [Hoffma08]. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 35 μ–Kalkül CTL* Linear Time Logic (LTL) Computation Tree Logic (CTL) Abbildung 3-3: Temporaler Logiken (in Anl. an HauTei10) In der Linearzeit Temporallogik (Linear Time Logic (LTL)) wird die Zukunft als determiniert vorausgesetzt, d.h. zu jedem Zustand gibt es genau einen Folgezustand. Bei der Modellierung des zu verifizierenden Softwareverhaltens entsteht die für die Namensgebung charakteristische Linienstruktur. Dem entgegen steht der Ansatz der nicht deterministischen Zukunft, d.h. aus dem aktuellen Zustand können mehrere Folgezustände erreicht werden. Diese Variante ist unter dem Namen Zustandsbaum Temporallogik (Computation Tree Logic (CTL)) bekannt, wobei sich auch hier der Name aus der Modellstruktur ableitet [HofLan11]. Beide Logiken eignen sich für eine programmgestützte, vollautomatische Verifikation [HauTei10]. Neben den soeben genannten und in den folgenden Unterkapiteln detailliert dargestellten Temporallogiken CTL und LTL soll namentlich noch exemplarisch das μ–Kalkül, welches wiederrum die Obermenge der CTL* Logik ist [Vgl. Abbildung 3-3], und die Property Specification Language (PSL) als mögliche alternativen Logiken genannt werden, welche allerdings für die weitere Betrachtung dieser Arbeit vernachlässigt werden. Linear Time Logic (LTL) Für die Modellierung von komplexen kausalen Zusammenhängen in Form von relativ einfach verständlichen zeitlogischen Formeln müssen zunächst die temporalen Operatoren eingeführt werden, welche in der Literatur nicht durch eine einheitliche Symbolik repräsentiert werden [Vgl. Tabelle 3-1]. Die Operatoren sind als Aussage über die Gültigkeit einer LTL-Formel f in einem bestimmten Zustand zu verstehen. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Operator- Bedeutung beschreibung neXt time Im nächsten Zustand gilt f (temporaler Schrittoperator) in the Future In mind. einem Zustand auf dem Pfad (eventually) gilt f (temporaler Existenzquantor) Globally In allen Zuständen auf dem Pfad gilt f (always) (temporaler Allquantor) Until Release Bis zum Zustand, für den f gilt, ist g gültig (bedingte Allquantzifizierung) F gilt bis zu dem Zustand, bis g das erste Mal gültig wird Operator 36 Operator [Busche04] [Hoffma08] Xf ○f Ff ◊f Gf □f gUf gUf gRf n.n. Tabelle 3-1: Übersicht der temporalen Operatoren (LTL) Die Formulierung der LTL-Formeln kann durch eine kombinierte Verwendung atomarer Aussagen (aussagenlogische Variablen), temporaler Operatoren und logischer Operatoren, wie sie aus der klassischen Aussagenlogik bekannt sind (¬, ˄, ˅, →, ↔) [Vgl. 2.1.1], erfolgen. Des Weiteren lassen sie sich meist einer der folgenden Eigenschaftsklassen zuordnen [Hoffma08]: Sicherheitseigenschaften: □¬ ( f g ) Die Aussagen f und g gelten niemals gleichzeitig. Fairnesseigenschaften: □◊ f Aussage f ist unendlich oft gültig Lebendigkeitseigenschaften: □( f ◊ g ) Immer wenn f gilt, dann gilt irgendwann auch g Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 37 Wie bereits weiter oben erläutert, werden LTL-Formeln auf Linienstrukturen bzw. in anderen Worten auf unendliche Zustandspfade interpretiert. Die Pfade werden aus der bereits erstellten Kripke-Struktur [Vgl. 3.2] durch das Auflösen der gerichteten Kanten, startend vom Initialzustand, gebildet. Ausgehend von der aus endlich vielen Zuständen bestehenden Kripke-Struktur lassen sich so unendlich viele Pfade generieren. Die folgende Übersicht [Vgl. Tabelle 3-2] stellt exemplarisch gültige LTL-Formeln f im Zustand s einer Kripke-Struktur M dar, dargestellt als M, s |= f: LTL-Formel Zustand 0 Zustand 2 Zustand 3 f f M, 0 |= ◊ f f f f … … f f f f g M, 0 |= g R f f f f f M, 4 |= f … … M, 0 |= f U g M, 3 |= ¬ g Zustand 4 f M, 0 |= ○ f M, 0 |= □ f Zustand 1 ... f … … f f … Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. M, 0 |= ○(f ˄ g) fg 38 … Tabelle 3-2: Semantik gültiger LTL-Formeln (in Anl. an HauTei10) Until und Release unterscheidet sich darin, dass im Falle des Release-Operators die Möglichkeit gegeben ist, dass die atomare Aussage g niemals wahr werden muss und daher f für immer gültig sein kann. Die Gültigkeit und Erfüllbarkeit von LTL-Formeln ist nach Haubelt und Teich wie folgt definiert [HauTei10]: „Eine LTLFormel f heißt gültig, falls für alle linearen temporalen Strukturen M gilt, dass M, s |= f. Sie heißt erfüllbar, falls eine temporale Struktur M existiert, so dass M, s |= f.“ Computation Tree Logic (CTL) Die Grundannahme der LTL, dass es zu jedem Zustand nur exakt einen Folgezustand geben kann, wird für die Betrachtung der CTL verworfen. Die Auswirkung wird in der grafischen Modellierung deutlich, welche folglich von einem linearen Zustandspfad in einen verzweigten Zustandsbaum wechselt. Dessen Wurzel wird durch den Initialzustand der Kripke-Struktur abgebildet. Die weitere Baumstruktur entsteht durch das schrittweise Ausrollen der übrigen Strukturelemente. Die in der CTL verwendete Symbolik kann grundsätzlich nach verschiedenen Ansätzen definiert werden. Einerseits lässt sie sich als um temporale Operatoren erweiterte Prädikatenlogik definieren, andererseits als um Pfadquantoren erweiterte LTL [HauTei10, Busche04]. Der komplexe Zusammenhang der verschiedenen Logiken ist in Abbildung 3-4 grafisch veranschaulicht. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 39 Temporallogik - CTL* Linear Time Logic (LTL) Computation Tree Logic (CTL) temporale Operatoren Aussagenlogik Quantoren Prädikatenlogik Abbildung 3-4: Teilgebiete der Logik - erweiterter Zusammenhang Basierend auf letzterer Definition sind die Pfadquantoren E und A im Detail zu definieren. Nach dem Existenzquantor E ist eine Formel dann gültig, wenn es genau einen Pfad gibt, auf dem die entsprechende Aussage wahr ist (Möglichkeit). Der Allquantor A dagegen definiert eine Formel nur dann als gültig, wenn die Aussage auf allen Pfaden korrekt ist (Notwendigkeit). In Anlehnung an Tabelle 3-1werden die temporalen Operatoren der LTL für die CTL jeweils in zwei Varianten bereitgestellt [Vgl. Tabelle 3-3]. Operator- Operator mit Exis- Operator mit beschreibung tenzquantor Allquantor neXt time E○ f A○ f in the Future E◊ f A◊ f Globally E□ f E□ f Until g EU f g AU f Release g ER f g AR f Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 40 Tabelle 3-3: Übersicht der temporalen Operatoren (CTL) Die mit Hilfe der LTL definierten Formeln zur Beschreibung der Eigenschaftsklassen [Vgl. 3.3.1] können entsprechend der Symbolik der CTL umformuliert werden, so ergibt sich: Sicherheitseigenschaften: A□¬ ( f g ) Fairnesseigenschaften: A□A◊ f Lebendigkeitseigenschaften: A□( f A◊ g ) Die folgende Übersicht [Vgl. Tabelle 3-4] veranschaulicht sie Semantik von CTLFormeln grafisch: M, 0 |= E ○ f M, 0 |= A ○ f f f f M, 0 |= E □ f M, 0 |= A □ f f f f f f f M, 0 |= E ◊ f f f f M, 0 |= A ◊ f f Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 41 f f f f f M, 0 |= f EU g M, 0 |= f AU g f f g g f g g g Tabelle 3-4: Semantik gültiger CTL-Formeln (in Anl. an Hoffma08) Trotz zusätzlichen Operatoren ist die CTL der LTL Logik nicht überlegen, auch wenn dies auf den ersten Blick anzunehmen wäre. Für diese Tatsache spricht, dass es auf beiden Seiten Aussagen gibt, welche sich mit der Symbolik des jeweiligen Gegenübers nicht formulieren lassen können. Andererseits gibt es auch Formeln, die sich in keiner der beiden Logiken ausdrücken lassen. In diesem Fall würde man auf den Einsatz der CTL* zurückgreifen [HauTei10]. Da in der Praxis die CTL Logik durch essentielle Vorteile wie leichtere Modellierung oder effizientere Berechnung positiv auffällt, wird im Folgenden für die tatsächliche Verifikation auf diese Logik gesetzt [Hoffma08]. 3.4 Verifikation der Software Mit dem dritten und letzten Schritt im Rahmen der Modellprüfung wird die eigentliche Verifikation funktionaler Eigenschaften vorgenommen [Vgl. 3.1]. Hierbei kann im Wesentlichen zwischen zwei Arten unterschieden werden: Im Rahmen der expliziten Modellprüfung wird im Folgenden anhand eines Beispiels der mathematische Korrektheitsbeweis einer CTL-Formel erläutert. In einem weiteren Unterkapitel wird kurz die symbolische Modellprüfung eingeführt und dem expliziten Vorgehen gegenübergestellt. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 42 Abschließend wird ein Einblick in aktuell am Markt vorhandene Softwareprodukte für die automatisierte Modellprüfung gegeben. Explizite Modellprüfung Grundvoraussetzung für die explizite Modellprüfung ist das Vorhandensein einer vollständigen Struktur der zu verifizierenden Software - d.h. alle möglichen Zustände des Programms müssen explizit aufgeführt sein. Eine solche Struktur liegt bereits aus dem einführenden Beispiel des konkurrierende Ressourcenzugriffs vor [Vgl. Abbildung 3-1], auf welches in diesem Rahmen zurückgegriffen wird. Die in Kapitel 3.3.2 beschriebene Lebendigkeitseigenschaft A□( f A◊ g ) soll exemplarisch gegen die vorliegende Kripke-Struktur geprüft werden. Das Ersetzen der Platzhalter f und g durch die atomaren Aussagenvariablen T1 und C1 ergibt die in CTL beschrieben Formel ɸ = A□( T1 A◊C1), welche verbal formuliert so viel aussagt wie: „Es gilt immer (auf allen Pfaden), wenn sich Prozess 1 in der Anmeldephase befindet, dass er irgendwann (zu einem späteren Zeitpunkt) auch verarbeitet wird, d.h. in die kritische Region gelangen. Für die Verifikation der Formel ɸ gegen die Kripke-Struktur M müssen zwei Schritte durchlaufen werden. Zunächst werden alle Zustände der Struktur M identifiziert, für welche die Formel ɸ gültig ist. Alle ermittelten Zustände werden in einer Menge festgehalten, welche im Fachjargon auch als Extensionsmenge bezeichnet wird [Hoffma08]. Dieser erste Arbeitsschritt ist gemessen am Arbeitsumfang und –anspruch deutlich schwieriger einzustufen, als dessen Folgeaufgabe. Im zweiten Abschnitt wird lediglich noch geprüft, ob der Initialzustand in der zuvor ermittelten Extensionsmenge ||ɸ|| enthalten ist. Ist diese Bedingung erfüllt, konnte ɸ erfolgreich gegen M verprobt werden – im gegebenen Beispiel wäre die Lebendigkeitseigenschaft des ersten Prozesses positiv verifiziert. 3.4.1.1 Berechnung der Extensionsmenge Die Berechnung der Extensionsmenge ||ɸ|| basiert nicht direkt auf der Beschreibung der Formel ɸ, diese wird vielmehr zunächst in einen Syntaxbaum umgesetzt. Ein Syntax- Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 43 baum ist eine baumartige Darstellung einer syntaktischen Struktur einer Zeichenkette (Formel) [iIWiki11]. Für ɸ ergibt sich folgender Syntaxbaum [Vgl. Abbildung 3-5]: A□ T1 A◊ C1 Abbildung 3-5: Syntaxbaum zur Formel ɸ Den Wurzelknoten des Syntaxbaums bildet der, der Klammer vorangesetzte, temporale Pfadquantor A□. Diesem direkt untergeordnet ist die Implikation, welcher wiederrum zwei Aussagen nachgelagert sind: die aussagenlogische Variable T1 und die aus zwei Elementen bestehende allquantifizierte Variable C1. Die dem Wurzelkonten untergeordneten Bestandteile werden auch als Blätter bezeichnet. Ausgehend von den Blättern wird der Syntaxbaum zur Wurzel hin traversiert und dabei für jede Teilformel die Extensionsmenge bestimmt: Atomare Teilformeln T1 und C1 Für die Variablen T1 und C1 werden exakt die Zustände den Extensionsmengen hinzugefügt, in welchen die Variablen gültig sind. ||T1|| = {1,4,5,8} [Vgl. Abbildung 3-6] ||C1|| = {3,7} [Vgl. Abbildung 3-7] Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 44 N1N2 0 N2C1 N2T1 N1T2 1 2 3 4 T1T2 T1T2 5 7 8 T2C1 T1C2 6 N1C2 6 N1C2 Abbildung 3-6: Extensionsmenge T1 N1N2 0 N2C1 N2T1 N1T2 1 2 3 4 T1T2 T1T2 5 7 8 T2C1 T1C2 Abbildung 3-7: Extensionsmenge C1 Temporale Teilformel A◊C1 Bei temporalen Teilformeln des Future-Operators A◊ wird die Extensionsmenge mit ̅̅̅̅̅̅ Hilfe einer Fixpunktgleichung λmin Z. ||ɸ|| ∪ R ∙ Z̅ gelöst, wobei der kleinste Fixpunkt (λmin ) zu berechnen ist und ̅̅̅̅̅̅ R ∙ Z̅ die Menge der Vorgängerzustände beschreibt. Startend mit einer leeren Menge wird der Fixpunkt durch iteratives Vorgehen berechnet, indem die Gleichung so lange angewendet wird, bis sich die Extensionsmenge nicht mehr ändert. Der Ausdruck λZ. 𝜏(𝑍) beschreibt die Funktion 𝑓: 𝑍 → 𝜏(𝑍). 𝜏(𝑍) = ||C1|| ∪ ̅̅̅̅̅̅ R ∙ Z̅ = {3,7} ∪ {} 𝜏 1 (∅) = {3,7} Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 45 𝜏 2 (∅) = {3,4,7} 𝜏 3 (∅) = {1,3,4,7} 𝜏 4 (∅) = {1,3,4,7,8} 𝜏 5 (∅) = {1,3,4,5,7,8} 𝜏 6 (∅) = {1,3,4,5,7,8} = ||A◊C1|| [Vgl. Abbildung 3-8] N1N2 0 N2C1 N2T1 N1T2 1 2 3 4 T1T2 T1T2 5 6 7 8 T2C1 T1C2 N1C2 Abbildung 3-8: Extensionsmenge A◊C1 Nach der sechsten Iteration ist die Extensionsmenge abschließen berechnet. Die Zustände {0,2,6} sind nicht Teil der Menge, da für sie jeweils nicht gilt, dass auf allen möglichen Pfaden ein Zustand mit der Variablen C1 erreicht werden kann. Dies wird in diesem Beispiel besonders deutlich, da die drei Zustände in Form eines geschlossenen Kreises durchlaufen werden können, ohne daher Berührung zu anderen Zuständen haben zu müssen. Implikation T1 A◊C1 Die Extensionsmenge einer Implikation bestimmt sich aus der einfachen Mengen̅|| ∪ ||A◊C1|| operation Vereinigung: ||T1 A◊C1|| = ||T ||T1 A◊C1|| = ̅̅̅̅̅̅̅̅̅̅̅ {1,4,5,8} ∪ {1,3,4,5,7,8} ||T1 A◊C1|| = {0,2,3,6,7} ∪ {1,3,4,5,7,8} ||T1 A◊C1|| = {0,1,2,3,4,5,6,7,8] = S [Vgl. Abbildung 3-9]. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 46 N1N2 0 N2C1 N2T1 N1T2 1 2 3 4 T1T2 T1T2 5 6 7 8 T2C1 T1C2 N1C2 Abbildung 3-9: Extensionsmenge T1 → A◊C1, A□(T1 → A◊C1) Berechnung der endgültigen Extensionsmenge A□(T1 A◊C1) Die Berechnung der abschließenden Extensionsmenge erfolgt erneut über eine Fixpunktgleichung. Im Gegensatz zum Future-Operator ◊ ist beim Always-Operator A□ ̅̅̅̅̅̅ allerdings der maximale Fixpunkt über den Ausdruck λmax Z. ||ɸ|| ∩ R ∙ Z̅ zu bestimmen, weshalb als Ausgangspunkt die vollständige Zustandsmenge S verwendet wird. 𝜏(Z) = || T1 A◊C1|| ∩ ̅̅̅̅̅̅ R ∙ Z̅ Bereits nach der ersten Iteration ist der Fixpunkt erreicht: 𝜏 1 ({0,1,2,3,4,5,6,7,8}) = {0,1,2,3,4,5,6,7,8} [Vgl. Abbildung 3-9] Für die Berechnung der Extensionsmenge ||ɸ|| mussten nicht alle in der Symbolik verfügbaren Operatoren aufgelöst werden. Der Vollständigkeit wegen folgend eine Auflistung der fehlenden Operatoren und deren Gleichungen [Vgl. Tabelle 3-5]. || ¬ f || || 𝑓̅ || || f ˅ g || || f || ∪ || g || || f ˄ g || || f || ∩ || g || || E○f || R∙|| f || || A○f || ̅̅̅̅̅̅̅̅̅̅̅ R ∙ || 𝑓 ̅ || Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. || E◊f || λminZ.|| f || ∪ R∙Z || E□f || λmaxZ.|| f || ∩ R∙Z || E f Ug || λminZ.|| g || ∪ ( || f || ∩ R∙Z ) || A f Ug || λminZ.|| g || ∪ ( || f || ∩ ̅̅̅̅̅̅ R ∙ Z̅ ) 47 Tabelle 3-5: Berechnungsgrundlage für Extensionsmengen 3.4.1.2 Überprüfung der Gültigkeit Die final ermittelte Extensionsmenge || ɸ || umfasst alle Zustände S der Kripke-Struktur M, welche als formalisierte Softwarestruktur die Ausgangslage für die Verifikation bildet [Vgl. Abbildung 3-1]. Folglich ist die Formel ɸ = A□( T1 A◊C1) in allen Zuständen uneingeschränkt gültig und die zu prüfende Softwareeigenschaft Lebendigkeit von Prozess 1 des Ausgangsbeispiels kann als bewiesen angesehen werden. 3.4.1.3 Bewertung des Verfahrens Der große Nachteil der expliziten Modellprüfungsverfahren liegt in der sogenannten Zustandsexplosion. Das Schlagwort beschreibt treffend die eingeschränkte Skalierbarkeit dieses Ansatzes, welche auf der aufzählenden Repräsentation aller möglichen Programmzustände beruht [Busche08]. Für die in unserem Beispiel gewählte Kripke-Struktur mit neun Zuständen kann sowohl manuell als auch automatisiert ohne Probleme eine Verifikation durchgeführt werden. Mit steigender Komplexität der Software-Programme steigt die Zahl der erreichbaren Systemzustände hingegen exponentiell an, was die verwendeten Lösungsalgorithmen schnell an deren Grenzen bringt. In der Forschung wurden folglich zahlreiche Ansätze verfolgt, um dieses Problem wirkungsvoll zu umgehen. Eine Möglichkeit stellt die symbolische Modellprüfung dar. Symbolische Modellprüfung Entgegen der Verfahren der expliziten Modellprüfung basiert die symbolische Verifikation nicht auf einer vollumfänglichen Aufzählung aller Systemzustände, über die an- Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 48 schließend temporale Formeln interpretiert werden. Vielmehr sind unter dem Überbegriff verschiedene alternative Ansätze zusammengefasst, um eine Verifikation effizienter durchführen zu können. Hierzu werden unter anderem Verfahren eingesetzt, welche das Problem der Zustandsexplosion abschwächen, die sogenannten Binären Entscheidungsdiagramme (binary decision diagram (BDD)), oder eine vollkommen anderen Ansatz verfolgen, beispielsweise die SAT-basierte (von engl. satisfiability) Verifikation [HauTei10, Busche08]. In den folgenden Unterkapiteln werden die zwei Grundkonzepte kurz dargestellt. 3.4.2.1 BDD-basierte Modellprüfung Ein BDD ist als endlicher gerichteter azyklischer Graph mit genau einem Startknoten definiert [Vgl. Abbildung 3-10, weißer Kreis]. Diesem sind beliebig viele Knoten (innere Knote) untergeordnet [grüne Kreise], welche jeweils mit einer boolschen Variable beschriftet sind und über zwei ausgehende Kanten verfügen. Die Kanten sind mit den Werten 0 und 1 belegt. Am Ende des Graphen münden die Knotenkanten in sogenannten Terminalknoten [weiße Vierecke], welche mit 0 und 1 beschriftet sind [iSinz06]. Die Überführung einer gegebenen temporalen Struktur, wie z.B. einer Kripke-Struktur, in ein BDD erfolgt durch die binäre Codierung derer Zustände. Diese werden dann, wie bereits beschrieben, den Knoten zugeordnet. Durch zwei Verfahren können die modellierten BDDs für eine effizientere Verwendung im Rahmen der Modellprüfung optimiert werden [iBubeck06]. Ziel ist es jeweils, die Anzahl der modellierten Knoten zu reduzieren: Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. X 49 X 0 1 Y 0 Y 1 Y gleicher Teilbaum 1 0 1 0 1 1 0 1 0 1 X 0 1 Y Y gleicher Nachfolger 0 1 0 1 0 1 0 1 Abbildung 3-10: Reduced BDD Reduktion des Entscheidungsdiagramms (Reduced BDD – RBBD) Die Reduktion eines BDD kann durch zwei Methoden erreicht werden, welcher wiederrum parallel angewendet werden können: In der Gesamtstruktur werden gleichartige Teilbäume und/oder Knoten mit den gleichen Nachfolgern eliminiert [Vgl. Abbildung 3-10]. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 0 X1 1 X2 X1 X2 Y1 1 0 Y1 Y1 X2 Y2 Y2 0 50 1 0 1 Variablenordnung X1 > X 2 > Y 1 > Y 2 Variablenordnung X1 > Y1 > X2 > Y2 8 Knoten 6 Knoten Abbildung 3-11: Ordered BDD Totale Ordnung der Variablen (Ordered BDD – OBBD) Es wird festgelegt, dass die Variable des Elternknotens größer sein muss, als die der beiden untergeordneten Knoten. Dabei darf jede Variable auf einem Pfad höchstens einmal vorkommen [Vgl. Abbildung 3-11]. Beide Verfahren können gleichzeitig auf ein BDD angewendet werden, in diesem Fall spricht man von Reduced Ordered BDDs (ROBDDs). Zusammenfassend ist festzuhalten, dass durch die symbolisch, binäre Codierung der Zustände die zu verifizierende Struktur komprimiert werden kann, was den effizienten Einsatz von Model Checking Algorithmen fördert. 3.4.2.2 SAT- basierte Modellprüfung Durch den Einsatz von BDDs ist es möglich, große Softwaresysteme zu modellieren und effizient zu verifizieren. Die Qualität dieses Ansatzes hängt allerdings unter anderem entscheidend von der gewählten Variablenordnung ab [Vgl. 3.4.2.1] . Bei komplexen Systemen ist die Bestimmung einer „optimalen“ Ordnung eine ernstzunehmende Herausforderung. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 51 Ein SAT-basiertes Prüfungsverfahren verfolgt daher einen grundlegend anderen Ansatz: Anstelle der umfassenden Verifikation einer Formel wird vielmehr ein konkretes Gegenbeispiel gesucht - in anderen Worten ist das Ziel der Prüfung die Falsifikation der Formel. Hierfür ist eine Aussage zu definiere (beispielsweise in LTL), welche genau dann erfüllbar ist, wenn ein solches Gegenbeispiel existiert. Die maximale Länge des gesuchten Gegenbeispiels stellt die Grenze des Verifikationsverfahrens dar, aus diesem Grund wird die SAT-basierte Modellprüfung auch als partielle Modellprüfung bezeichnet [HauTei10]. Modellprüfung in der Praxis Aufgrund der Möglichkeit zur vollautomatisierten Verifikation (one-push-Verfahren) konnte die Modellprüfung den Sprung von der Forschung in den industriellen und wirtschaftlichen Sektor vollziehen. Der große Speicherbedarf und lange Verifizierungslaufzeiten verhindern allerdings noch heute, trotz stark gestiegener Rechen- und Speicherkapazitäten modernen IT (Informationstechnologie)-Architekturen den breiten Einsatz [Hoffma08]. Nichtsdestotrotz finden sich am Markt zahlreiche verschiedene Produkte, welche zum Teil auch von namenhaften Firmen eingesetzt werden [Busche08, Berard01] - folgend einige auserwählte Produkte im Detail: SPIN: Das wohl bekannteste Model Checking Werkzeug prüft endliche Zustandsautomaten gegen die LTL-Logik. SPIN wurde ursprünglich von Gerard J. Holzmann bei den Bell Labs entwickelt und ist heute frei über das Internet zugänglich. Die Beschreibung des zu prüfenden Systems erfolgt in der Sprache Promela. Kronos: Die von Verimag entwickelte Software ist ein Model Checker für Formeln der TCTL (Timed CTL) gegen endliche Zustandsautomaten, wobei die Software konsolenbasiert ist und kein grafisches Interface bietet. Uppaal: Kann nicht alle TCTL-Formeln verifizieren, hat aber im Gegensatz zu Kronos eine Benutzerschnittstelle mit Simulationsumgebung, Formeleditor und Verifzierer. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 52 Versys2: Ein von Motorola für den Eigenbedarf entwickeltes Model Checking Werkzeug für die Verifizierung von Schaltkreisen auf Computerchips. Eine interessante Übersicht der aktuell verfügbaren Werkzeuge liefert die englische Homepage von Wikipedia [iWIKIE11], wobei die Produkte nach verschiedenen Kriterien klassifiziert sind, wie z.B. den unterstützten temporalen Logiken. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 53 4 Abstrakte Interpretation Autor: Robert Richter Im dritten Teil der vorliegenden Arbeit soll das Verfahren der Abstrakten Interpretation (AI) näher beleuchtet und dem Leser möglichst anschaulich zu erörtert werden. Dazu wird im ersten Schritt das Verfahren in das Umfeld der Software-Prüfverfahren eingeordnet. Im zweiten Schritt wird die theoretische Basis der Fixpunktiteration (FI) als essentiellen Bestandteil der AI erläutert. Mit Hilfe von Beispielen soll dann die Verwendung in der praktischen Anwendung gezeigt werden. Im dritten Schritt wird dann näher auf Datenabstraktion (DA) und Ihren Beitrag zur AI eingegangen. Die abstrakte Interpretation findet man auch unter den Begriffen Abstraktionsverfeinerung [HauTei10], oder homomorphe Simulation [Franz07]. Sie wird wie die Deduktion als auch die Modellprüfung den Verfahren der statischen Codeanalyse zur Verifikation von Software zugeordnet. Im Gegensatz zu den beiden zuletzt genannten, konnte sie aufgrund ihrer besseren Skalierbarkeit bereits den Einzug in industrielle Anwendungen finden. Anwendungen wie Astree oder Polyspace werden heute zur Überprüfung von sicherheitsrelevanter Software, die ihren Einsatz im Automobilbereich, der Luftfahrt oder auch in Kernkraftwerken findet, eingesetzt [iAstree11,iMath11]. Die AI gilt als Kombination der Methode der statischen Programmanalyse und der Generalisierung der Datenbereiche, auch Datenabstraktion genannt [Hoffma08]. Merkmal der statischen Codeanalyse ist, dass sie am fertiggestellten Quellcode durchgeführt wird, ohne dabei den Quellcode in ein funktionsfähiges Programm zu übersetzen[Hoffma08]. Damit wird sie zu den sogenannten Whitebox-Verfahren gezählt, also Verfahren zu deren Durchführung Kenntnis über den inneren Aufbau von Programmen vorhanden sein muss [Franz07]. Die Datenabstraktion dient der Approximation der Datenbereiche, worauf später noch detailliert eingegangen wird. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 54 Die AI gehört zu den falsifizierenden Verfahren deren Ziel es ist, die Existenz von Fehlern nachzuweisen [Lamber10]. Das Gegenstück zu den falsifizierenden Verfahren stellen die Beweise dar [HauTei10], auf die hier aber nicht weiter eingegangen werden soll. Die ersten Beiträge, welche sich mit dem Verfahren der AI auseinandersetzten waren die Arbeiten von Robert W. Floyd 1967 [Floyd67], David Park 1969 [Park69] und E.M. Clarke 1979 [ClarkEM79]. Sie bilden das theoretische Fundament. Die grundlegende Überlegung besteht darin, jede Zeile des Quellcodes mit Hilfe einer Abstraktionsfunktion durch eine abstrakte Abbildung zu ersetzen. Diese Abstraktion kann sowohl durch Homomorphismen wie Abstraktions-Funktionen als auch durch andere Verfahren wie z.B. die Gallois-Verbindungen (in diesem Fall ist sowohl eine Abstraktions- als auch eine Konkretisierungsfunktion notwendig) geschehen [iPirMar11]. Die als Abbildung des konkreten Quellcode entstehenden Gleichungen spannen ein Gleichungssystem auf, welches auch als Lösungsmenge oder auch Zustandsmenge Zi bezeichnet wird. Aus dieser lässt sich mittels Fixpunktiteration „die Korrektheit der zu verifizierenden Eigenschaft ableiten oder im Fehlerfall ein Gegenbeispiel erzeugen.“[Hoffma08] Die konkrete Belegung aller im Programm vorhandenen Variablen wird als Zustand bezeichnet. Wobei die Anzahl n der Variablen einen n-dimensionalen Vektorraum aufspannen. Ein Programmzustand kann damit als Element dieses Vektorraumes aufgefasst werden. Die Menge Zi enthält somit alle Zustände in denen sich ein „Programm nach Ausführung der i-ten Zeile befinden kann“[Hoffma08]. Die aufgestellten Gleichungen ermöglichen damit Aussagen, darüber, welchen Zustand das zu prüfende Programm in welcher Zeile einnehmen kann. Für ein System mit i Quellcodezeilen ergibt sich damit folgendes Gleichungssystem: Z0 =f0 (Z0 , … Zi ) (1) Z1 =f1 (Z0 , … Zi ) (2) Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 55 ⋮ Zi =fi (Z0 , … Zi ) (3) 4.1 Fixpunktiteration Bevor weiter auf die AI als Verifikationsverfahren eingegangen wird, sollen zunächst die Bestandteile FI und DA weiteren Betrachtungen unterzogen werden, da es aus Verständnisgründen hilfreich erscheint, zunächst die aus der Mathematik stammenden Verfahren näher zu erläutern. Nachfolgend wird dazu auf direkte und auf die grafische Fixpunktbestimmung eingegangen bevor die FI nach Clark, Park und Floyd erläutert wird. Fixpunkt Um einen Fixpunkt zu bestimmen muss zunächst klar sein, was ein Fixpunkt ist, dies soll hier kurz geklärt werden. Ein Fixpunkt definiert sich mathematisch wie nachfolgend in Anlehnung an [iLevPau11] dargestellt Sei f: E → F, E, F⊆ℝ gegeben. Ein Punkt ξ→ F, E, F⊆ℝ heißt Fixpunkt von f, wenn gilt: f(ξ) = ξ (4) Ziel der Fixpunktbestimmung ist es also einen Punkt aus dem Definitionsbereich der Funktion zu finden, welcher von der Funktion wieder auf sich selbst abgebildet wird (ξ→ F). Hier ein kurzes aber einleuchtendes Beispiel: Sei F(x)=2x, dann wäre x=0 ein Fixpunkt, da F(0)=0 wäre. Hingegen ist x=1 kein Fixpunkt, da hier der F(1)=2 ist. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 56 Direkte Fixpunktbestimmung Da zur Fixpunktberechnung nicht zwangsläufig ein Iterationsverfahren eingesetzt werden muss, wird im nachfolgenden Beispiel in Anlehnung an [iLevPau11], kurz darauf eingegangen wie ein Fixpunkt direkt berechnet werden . Beispiel: Gegeben sei: 𝑓(𝑥) = 𝑥 2 +𝑐, c ℇ ℝ (5) Fixpunkte dieser Funktion lassen sich direkt berechnen, denn für sie muss gelten: (6) 𝑥2 + 𝑐 = 𝑥 Die rechte Seitze steht dabei für die Winkelhalbierende f(x)=x, welche alle Fixpunkte des Koordinatensystems beinhaltet. Die beiden Fixpunkte der Funktion ergeben sich aus den folgenden beiden Gleichungen: 1 2 (1 1 - 4c) (7) 1 2 (1 1 - 4c) (8) Wie man anhand des Terms unterhalb der Wurzel erkennt, sind die ermittelten Fixpunk1 te ξ+, ξ− nur für 𝑐 ≤ 4 reel, setzt man z.B. c=0, ergeben sich die Fixpunkte ξ+ = 1, ξ− = 0. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 57 Fixpunktiteration graphisch Wie Eingangs bereits erwähnt, ist auch eine grafische Lösungsfindung möglich, die im prinzipiellen Ablauf dem Banachschen Fixpunktsatz folgt [iManRog11]. Die grafische Lösungsfindung die hier gezeigt wird beschränkt sich jedoch auf den eindimensionalen Bereich. Im nachfolgenden Beispiel wird das grafische Verfahren veranschaulicht. Man geht dabei wie folgt vor [LevPau11] 1. Wähle Startpunkt xi = x0 2. Ziehe eine Senkrechte zum Graphen g(x) . Die x-Koordinate des Schnittpunktes der wird zum neuen Funktionswert von g(x). 3. Ziehe ausgehende vom Schnittpunkt eine Senkrechte zu Winkelhalbierenden y = x. Schnittpunkt wird zum neuen xi-Wert. 4. Wiederhole Schritt 2. und 3. bis der Schnittpunkt x = g(x) erreicht ist Abbildung 4-1verdeutlicht die Vorgehensweise. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 58 y y=x y=g(x) x0 x* x2 x3 x1 x Abbildung 4-1: grafische Fixpunktiteration y x** y=g(x) x* y=x x Abbildung 4-2: Fixpunkt-Bestimmung in Abhängigkeit vom Startwert x0 Anhand der grafischen Fixpunktbestimmung lässt sich sehr gut erkennen, dass es entscheidend vom Startwert x0 abhängt, welcher Fixpunkt gefunden wird. Betrachten wir Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 59 dazu das in Abbildung 4-2 dargestellte Beispiel. Wie man klar erkennt liegen zwei Fixpunkte vor, sowohl x** als auch x*. Durch die Wahl von x0 als Startpunkt der Iteration wurde x* als Fixpunkt bestimmt. Hätte man hier einen anderen Startpunkt x 0<x** gewählt , wäre das Ergebnis der Iteration x** gewesen. Dieses Problem lässt sich auch später auf die Fixpunktiteration von Clark, Park und Floyd übertragen. Worauf im Weiteren Verlauf noch eingegangen wird. Fixpunkt-Berechnung durch Iteration Vereinfacht kann man sich die FI in etwa so vorzustellen, man errichtet einen Käfig um einen Ausgangspunkt herum und beginnt dann dessen Wände immer weiter zusammenzuschieben. Treffen diese sich schließlich in einem Punkt, hat man den Fixpunkt erreicht. Treffen sich die Wände nicht, ist kein Fixpunkt vorhanden. Wenn die Fixpunkte einer Funktion nicht direkt berechnet oder grafisch bestimmt werden können, so versucht man, sie durch Iteration zu ermitteln. Man geht wie folgt vor: beginnend mit einem Startwert x0 nähert man sich einem Fixpunkt durch wiederholtes Anwenden der Funktion f auf sich selbst: Startwert: x0 (9) x0 = f(x0 ) (10) x2 = f(x1 ) = f(f(x0 )) = f ∘ f(x0 ) = f 2 (x0 ) (11) ... Xn = ⏟ f ∘ f ∘ … ∘ f(x0 ) = f n (x0 ) n−mal Allgemein gilt: (12) Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 60 (13) xi+1 = f(x𝑖 ) Da die Funktion f wiederholt angewendet wird, nennt man sie Iterationsfunktion. Mit der beschriebenen Vorgehensweise findet man immer höchstens einen Fixpunkt. Welcher das ist, hängt allerdings, wie auch bei der grafischen Bestimmung des Fixpunktes vom Startwert x0 ab. Beispiel Wir betrachten wieder die Funktion f ( x) x 2 c , durch Iteration dieser Funktion erhält man folgendes: f(x) = x 2 + c (14) f [2] = f(f(x)) = f(x 2 + c) = (x 2 + c 2 ) + c (15) f [3] (x) = ((x 2 + c 2 ) + c) + c (16) ⋮ (17) f [n] (x) = ⋯ Wenn es einen Fixpunkt ξ gibt, so gilt: lim xn = ξ, nℇℕ n→∞ (18) f n (ξ) = ξ, ∀nℇℕ (19) Als wichtige iterative Verfahren zur Bestimmung von Fixpunkten seien hier das Newtonsche Verfahren als auch, wie bereits oben, der Banachsche Fixpunktsatz erwähnt. Für den interessierten Leser in [HemThi96] weiterführend erörtert. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 61 Der vorhergehende Abschnitt hat die Fixpunktbestimmung an Hand verschiedener Verfahren erläutert um ein besseres Verständnis beim Leser aufzubauen. Dabei wurde auf die prinzipielle Vorgehensweise der direkten und der grafischen Fixpunktbestimmung eingegangen. Abschließend wurde das für den weiteren Verlauf relevante Verfahren der Fixpunktiteration erörtert. Fixpunktiteration nach Floyd, Clark und Park Nachdem zuvor die Bestimmung des Fixpunktes an einfachen Beispielen demonstriert wurde soll nun die Anwendung der FI auf Quellcode erörtert werden. Im ersten Abschnitt wird dazu das zugrunde liegende Prinzip erläutert. Im zweiten Abschnitt wird an einem Anwendungsbeispiel das zuvor beschriebene Verfahren durchgeführt 4.1.5.1 Fixpunkt-Theorie Um die Fixpunktberechnung zur Softwareverifikation anwenden zu können muss man diese auf Mengen anwenden. In Anlehnung an [iMikN11] wird darauf im Folgenden näher eingegangen. Zunächst sind einige Begriffe zu klären. 4.1.5.2 Vollständiger Verband Vollständiger Verband ist eine nicht leere Menge M mit einer kleinsten oberen (UpperBound oder auch Supremum) und einer größten unteren Schranke (Lower-Bound, oder auch Infimum) sowie zwei inneren binären Verknüpfungen und . Nur wenn diese Prämissen auch für jede Teilmenge T aus M gelten liegt ein vollständiger Verband vor. Die kleinste obere Menge T ist definiert als: ⊺= 𝑠𝑢b(𝑀) (20) Die größte untere Menge ist definiert als: ⊥= inf(M) (21) Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 62 Sei f: mM eine Funktion auf dem vollständigen Verband M so ergibt sich die Menge aller Fixpunkte als: (22) Fix (f ) = {m ∈ M | f (m) = m} Die Präfixpunkte ergeben sich aus: (23) Pre(f) = {m ∈ M|f(m) ⊑ m} Die Postfixpunkt ergeben sich aus (24) Post(f) = {m ∈ M|f(m) ⊒ m} Der kleinste Fixpunkt ist definiert als (25) lfp(f) = ⨅Fix(f) und der größte Fixpunkt als: (26) gfp(f) = ⨆Fix(f) vollständiger Verband M Pre(f) Fix(f) Post(f) gfp(f) lfp(f) Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 63 Abbildung 4-3: vollständiger Verband (in Anlehnung an [MikN11]) Aus dem Theorem von Knaster-Tarski geht hervor, dass wenn (M,⊑) ein vollständiger Verband und f : m→ M eine monotone Funktion ist, die Fixpunkte der Funktion f wieder einen Vollständigen Verband bilden. Daraus folgt, dass eine monotone Funktion mindestens einen Fixpunkt besitzt [MikN11;LoeSie84]. Laut dem Satz von Kleene ist der kleinste Fixpunkt einer Funktion f in n Iterationsschritten berechenbar. Da aber die Berechnung aufgrund des Berechenbarkeitsproblem unendlich lange dauern kann, werden Operatoren eingesetzt, deren Aufgabe es ist, die Zahl der Iterationsschritte zu reduzieren. Die wichtigsten sind der Widening- und der Narrowing Operator [iCorAgo11], auf die hier kurz eingegangen werden soll. 4.1.5.3 Widening- und Narrowing-Operator Ziel des Widening-Operators ist es eine Terminierung der Iteration zu erzwingen, indem er irgendeine anstelle der kleinsten oberen Schranke findet, um die Zahl der Iterationsläufe zu reduzieren. Dabei wählt der Widening Operator aus der Menge der zur Verfügung stehenden 1erte stets den Größeren aus und erhöht dadurch sowohl die den Wert untere Schranke als auch den der oberen Schranke. Von Nachteil ist hierbei, dass die mittels Widening Operator gefundene Lösung zu groß und ungenau sein kann. Aus diesem Grund werden im Anschluss an das Widening häufig Narrowing Operatoren eingesetzt deren Ziel es ist, die Lösung, welche im Rahmen es Widening erzielt wurde zu verfeinern und möglichst den kleinsten Fixpunkt zu bestimmen. Der Narrowing Operator verkleinert dabei iterativ sowohl die obere als auch die untere Schranke des vollständigen Verbandes. Aufgrund des zuvor durch das Widening eingeschränkten Bereiches treten dabei jedoch keine Terminierungsprobleme auf [SeWiHa10]. Beide Operatoren zusammen schaffen es die Zahl der Iterationsläufe erheblich zu reduzieren ohne die genaue Lösung aufgeben zu müssen. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 64 Fixpunktiteration zur Softwareverifikation Die theoretischen Grundlagen der Fixpunktiteration wurden soeben ausführlich erläutert, bevor aber die Fixpunktiteration auf einen Quellcode angewendet werden kann muss dieser zunächst in ein Gleichungssystem übersetzt werden. Auf die Art und Weise, wie der Quellcode in Gleichungen umgewandelt wird soll an hier im Detail nicht eingegangen werden. Wohl aber auf die darauf folgenden Schritte. Um den Fixpunkt zu bestimmen werden im ersten Schritt die zuvor aus den Quellcodezeilen bestimmten Gleichungen mit der leeren Menge gleichgesetzt. Das Ergebnis des ersten Iterationsschrittes wird im zweiten Schritt wieder in das vorhandene Gleichungssystem eingesetzt. Das daraus folgende Ergebnis im dritten schritt wird wieder in das Gleichungssystem eingesetzt und so weiter. Diese Vorgehensweise wird nun so lange wiederholt, bis sich die berechneten Ergebnis, in Falle von Gleichungen aus Quellcoden wird es sich um Mengen handeln, nicht mehr von dem zuvor berechneten Ergebnis unterscheidet. Ist dies der Fall, ist ein Fixpunkt erreicht. Mathematisch wurde also ein Punkt gefunden der das Gleichungssystem wieder auf sich selbst abbildet. Für den Quellcode gilt damit gleichzeitig, dass mit Bestimmung des Fixpunktes auch alle möglichen Programmzustände und folglich die Zustandsmenge Zi des Programmes ermittelt wurde [Hoffma08]. Die Fixpunktiteration erfolgt dabei in der folgenden allgemeingültigen Form [Hoffma08]: Gleichsetzen mit der leeren Menge Z0,0=⊘ (27) 𝑍1,0=⊘ (28) ⋯ 𝑍𝑘,0=⊘ (29) Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 𝑍0,𝑗+1 = 𝑓0 (𝑍0,𝑗 , ⋯ , 𝑍𝑘,𝑗 (30) 𝑍1,𝑗+1 = 𝑓1 (𝑍0,𝑗 , ⋯ , 𝑍𝑘,𝑗 ) (31) 65 ⋯ (32) 𝑍0,𝑗+1 = 𝑓0 (𝑍0,𝑗 , ⋯ , 𝑍𝑘,𝑗 ) Die FI soll im Folgenden an einem Programmfragment beispielhaft durchgeführt werden. Dieses wurde [Hoffma08] entnommen und um die Iterationsschritte 2 und drei erweitert. float foo(unsigned char x) { unsigned char i = 0; while(i < 6) { i + +; x / = 2;} return 1 / (x - i);} Abb. 4-1: Beispiel Programmfragment foo Zunächst muss das Programmfragment in ein Gleichungssystem übersetzt werden, wie nachfolgend in Tabelle 4-1 dargestellt. Quellcode Gleichung float foo(unsigned char x) Z0 = {(?, x) x Î [0, 255]} unsigned char i = 0; Z1 = {(0, x) x Î [0, 255]} while(i < 6) Z2 = Z1È Z2 i + +; Z3 = {(i +1, x) (i, x) Î Z2, i < 6} Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. x / = 2; x Z 4 = {(i, ) (i, x) Î Z3 } 2 return 1/ (x - i); x Z 5 = {(i, ) (i, x) Î Z 4 , i ³ 6} 2 66 Tabelle 4-1: Gleichungssystem des Programmfragments foo (Hoffma08) Für die Gleichungen gilt dabei: 𝐼𝑡𝑒𝑟𝑎𝑡𝑖𝑜𝑛𝑠𝑠𝑐ℎ𝑟𝑖𝑡𝑡 𝑚 𝑍𝐺𝑙𝑒𝑖𝑐ℎ𝑢𝑛𝑔 𝑗 Nachfolgend wird die FI anhand des in Tabelle 4-1: Gleichungssystem des Programmfragments foo (Hoffma08) dargestellten Gleichungssystems durchgeführt. 0. Iteration (einsetzen der leeren Menge) Z00 = ∅ (33) Z10 = ∅ (34) Z20 = ∅ (35) Z30 = ∅ (36) Z40 = ∅ (37) Z50 = ∅ (38) 1. Iteration Z01 = Z00 ∪ Z01 = ∅ ∪ {(? , x)|𝑥 ∈ [0,255]} = {(? , x)|𝑥 ∈ [0,255]} (39) Z11 = Z10 ∪ Z11 = ∅ ∪ {(0, x)|𝑥 ∈ [0,255]} = {(0, x)|𝑥 ∈ [0,255]} (40) Z21 = Z21 ∪ Z10 ∪ Z40 = {(0, x)|𝑥 ∈ [0,255]} ∪ ∅ ∪ ∅ = {(0, x)|𝑥 ∈ [0,255]} (41) Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Z31 = Z30 ∪ Z31 = ∅ ∪ {(i + 1, x)|(𝑖, 𝑥) ∈ Z20 , 𝑖 < 6} = ∅ ∪ ∅ = (42) = ∅, da Z20 = ∅ x Z41 = Z40 ∪ Z41 = ∅ ∪ {(i, ) |(𝑖, 𝑥) ∈ Z30 } = ∅ ∪ ∅ = ∅, da Z30 = ∅ 2 x Z51 = Z50 ∪ Z51 = ∅ ∪ {(i, 2) |(𝑖, 𝑥) ∈ Z40 , i ≥ 6} = ∅ ∪ ∅ = ∅, da Z40 = ∅ (43) (44) 2. Iteration Z02 = Z01 ∪ Z02 = {(? , x)|𝑥 ∈ [0,255]} ∪ {(? , x)|𝑥 ∈ [0,255]} = (45) = {(? , x)|𝑥 ∈ [0,255]} Z12 = Z11 ∪ Z12 = {(0, x)|𝑥 ∈ [0,255]} ∪ {(0, x)|𝑥 ∈ [0,255]} = (46) = {(0, x)|𝑥 ∈ [0,255]} Z22 = Z22 ∪ Z11 ∪ Z41 = Z12 ∪ Z42 ∪= {(0, x)|𝑥 ∈ [0,255]} ∪ ∅ = (47) = {(0, x)|𝑥 ∈ [0,255]} ∪ Z42 ∪ {(0, 𝑥)|𝑥 ∈ [0,255]} = = {(0, 𝑥)|𝑥 ∈ [0,255]}, 𝑑𝑎 𝑍42 = ∅ Z32 = Z31 ∪ Z32 = ∅ ∪ {(i + 1, x)|(i, x) ∈ Z21 ; i < 6} = (48) = {(1, x)|(i, x) ∈ Z21 }, i < 6}, da i = 0 x (49) x (50) Z42 = Z41 ∪ Z42 = ∅ ∪ {(i, 2) |(i, x) ∈ Z31 } = ∅ ∪ ∅ = ∅, da Z41 = ∅ Z52 = Z51 ∪ Z52 = ∅ ∪ {(i, 2) |(i, x) ∈ Z41 , i ≥ 6} = ∅ ∪ ∅ = ∅, da Z40 = ∅ 3. Iteration 67 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Z03 = Z02 ∪ Z03 = {(? , x)|x ∈ [0,255]} ∪ {(? , x)|x ∈ [0,255]} = 68 (51) = {(? , x)|x ∈ [0,255]} Z03 = Z02 ∪ Z03 = {(0, x)|x ∈ [0,255]} ∪ {(0, x)|x ∈ [0,255]} = (52) = {(0, x)|x ∈ [0,255]} 3 Z2= Z23 ∪ Z12 ∪ Z42 = Z23 ∪ {(0, x)|x ∈ [0,255]} ∪ ∅ = (53) = Z13 ∪ Z43 ∪ {(0, x)|x ∈ [0,255]} ∪ ∅ = = {(0, x)|x ∈ [0,255]} ∪ ∅ ∪ {(0, x)|x ∈ [0,255]} ∪ ∅ = = {(0, x)|x ∈ [0,255]} Z33 = Z32 ∪ Z33 = {(i + 1, x)|(i, x) ∈ Z21 , i < 6} ∪ (54) ∪ {(i + 1, x)|(i, x) ∈ Z21 , i < 6} = = {(1, 𝑥)|(𝑖, 𝑥) ∈ 𝑍21 , 𝑖 < 6}, 𝑑𝑎 𝑖 = 0 𝑎𝑢𝑠 𝑍21 x 3 3 Z4= Z42 ∪ Z4= ∅ ∪ {(i, 2)|(i, x) ∈ Z32 }= (55) x = ∅ ∪ {(1, )|(i, x) ∈Z32 }, da i = 1 aus Z32 2 x Z53 = Z52 ∪ Z53 = ∅ ∪ {(i, 2)|(i, x) ∈ Z42 , i ≥ 6} = ∅ ∪ ∅ = ∅, da i < 6 (56) Die nachfolgend Iterationen werden äquivalent, auf eines ausführliche Darstellung soll hier aber verzichtet werden, da der Leser mittlerweile in der Lage sein sollte die Ergebnisse dieser Schritte selber zu bestimmen. In dem aus [Hoffma08] entnommenen Beispiel wird der Fixpunkt in Iterationsschritt 11 gefunden. Die Iterationen 6 und 18 sollen die Überprüfung der eigenen Berechnungen durch den Leser ermöglichen. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 69 6. Iteration [Hoffma08] 𝑥 (57) 𝑥 (58) Z06 = {(? , 2) |𝑥 ∈ [0,255]} Z16 = {(0, 2) |𝑥 ∈ [0,255]} 𝑥 𝑥 (59) 𝑥 𝑥 (60) Z46 = {(1, 2) , (2, 2) |𝑥 ∈ [0,255]} 𝑥 𝑥 (61) Z56 = ∅ (62) Z26 = {(0, 2) , (1, 2) |𝑥 ∈ [0,255]} Z36 = {(1, 2) , (2, 2) |𝑥 ∈ [0,255]} 18. Iteration [Hoffma08] 𝑥 (63) 𝑥 (64) Z018 = {(? , 2) |𝑥 ∈ [0,255]} Z118 = {(0, 2) |𝑥 ∈ [0,255]} 𝑥 𝑥 𝑥 𝑥 𝑥 𝑥 2 4 8 𝑥 𝑥 𝑥 𝑥 (65) 𝑥 𝑥 16 32 (66) Z218 = {(0, 𝑥), (1, 2) , (2, 2) , (3, 8) , (4, 16) , (4, 32) |𝑥 ∈ [0,255]} Z318 = {(1, 𝑥), (2, ) , (3, ) , (4, ) , (5, ) , (6, ) |𝑥 ∈ [0,255]} 𝑥 𝑥 𝑥 𝑥 Z418 = {(1, 2) , (2, 4) , (3, 8) , (4, 16) , (5, 32) , (6, 64) |𝑥 ∈ [0,255]} 𝑥 Z518 = {(6, 64) |𝑥 ∈ [0,255]} (67) (68) Wie man erkennen kann, ist es bei Anwendung der Fixpunktiteration auf Mengen notwendig, die jeweils im Iterationsschritt zuvor bestimmten Menge rekursiv in den aktuellen Rechenschritt miteinzubinden um den Fixpunkt bestimmen zu können. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 70 Das Beispiel sollte es dem Leser ermöglichen die FI anhand eines aus einem Quellcode gewonnenen Gleichungssystem zu verstehen und erste Iterationsschritte selber durchzuführen. Fehlermengen und Verifikation Bisher wurde zwar durch die Bestimmung des Fixpunktes die Zustandsmenge des Programmes ermittelt. Eine Aussage über die Fehlerfreiheit des Programmes ist dadurch aber noch nicht möglich. Das soll nun geändert werden. Dazu wird die Funktion der Fehlermenge kurz beschrieben und schließlich zur Verifikation des Programmes eingesetzt. Mit Hilfe von Fehlermengen ZF (z.B. Division durch Null, arithmetischer Überlauf etc.), sogenannten bad states, werden die zu verifizierenden Programmeigenschaften beschrieben. Die Verifikation an sich wird durch das Schneiden der Fehlermenge mit der, im Rahmen der zuvor durchgeführten Iteration bestimmten, Zustandsmenge Zi durchgeführt. Fehlerfreiheit ist genau dann gegeben, wenn die Schnittmenge aus Fehlermenge und Zustandsmenge die leere Menge ist. Im Fall einer nicht leeren Menge kann eine konkrete Belegung der Eingangsvariablen (für das vorliegende Beispiel in Tabelle 4-1 x und i) bestimmt werden, welche das Fehlerszenario auslösen. Betrachten wir dazu das zuvor behandelte Beispiel aus Abbildung 4-3, ergibt sich die Fehlermenge ZF aus der letzten Quellcodezeile des Programmfragments: return 1/(x − i); (69) es gilt folglich zu prüfen, ob x oder i Werte annehmen können, die eine Division durch null erzeugen würden. Die zugehörige Fehlermenge lautet wie folgt: ZF = {(x, x)}|x ∈ [0,255] (70) Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 71 Im nächsten Schritt gilt es den Inhalt der Schnittmenge zu berechnen. Dazu werden die Mengen Z5 und ZF mit einander geschnitten. Z5 bildet die Zustandsmenge des Programmes nach Bestimmung des Fixpunktes ab. Die Fehlermenge ZF hingegen die potentiell vorhandenen Fehler im vorliegenden Quellcode : Z5 ∩ {(x, x)|x ∈ [0,255]} 𝑥 𝑥 64 64 = {(6, ) |( = 6) ∧ 𝑥 ∈ [0,255]} (71) (72) 𝑥 (73) = {(6, 64) |𝑥 ∈ ∅} 𝑥 (74) =∅ (75) = {(6, 64) |𝑥 ∈ [384,447] ∩[0,255]} Wie man sieht, muss der Term x/64 den Wert 6 annehmen, damit es zu einer Division durch Null kommen kann. Entsprechend muss x = 384 sein, folglich im Intervall {384,447} liegen. Da innerhalb von Z5 x nur im Intervall {0,255} definiert ist, ergibt sich aus der Schnittmenge mit ZF eine leere Menge. Die Variable x kann folglich im vorliegenden Quellcode den für einen Fehler erforderlichen Wert nicht annehmen. Damit ist für das Beispiel nachgewiesen, dass ein fehlerfreies Programm vorliegt. Nachdem mit der Fixpunktiteration die Zustandsmenge des Beispielprogrammfragmentes aus Abbildung 4-3 bestimmt wurde, konnte nun durch das Schneiden mit der Fehlermenge eine Aussage getroffen werden, ob das Programm fehlerfrei ist oder nicht. Für den Einsatz in industriellen Anwendungen ist diese Vorgehensweise jedoch immer noch zu speicher- und rechenintensiv. Im nächsten Abschnitt wird daher die Datenabstraktion als zweite Komponente der abstrakten Interpretation eingehenden Betrachtung unterzogen. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 72 4.2 Datenabstraktion Die abstrakte Interpretation stößt trotz ihrer Leistungsfähigkeit an Grenzen. Da dem Satz von Rice zufolge „ Jede nicht triviale Eigenschaft eines Programms, die sich auf die von der Turingmaschine berechnete Funktion bezieht“ algorithmisch „nicht entscheidbar ist“ (z.B. Halteproblem)[HemThi96], ist auch die exakte Zustandsmenge Zi nicht immer exakt durch die Iteration bestimmbar. Es liegt das sogenannte Berechenbarkeitsproblem vor. Daher bedient sich die Programmanalyse eines Tricks, indem sie kein exaktes Analyse-Ergebnis berechnet sondern eine alternative Zustandsmenge durch (über)-approximieren bestimmt. Abbildung 4-4zeigt dieses Prinzip grafisch. Diese Abstraktion der Zustandsmenge wird im weiteren Verlauf genauer beschrieben. Gesamtmenge Ergebnis der Analyse Exaktes Ergebnis Abbildung 4-4: Programmanalyse (in Anl. an iKönBar11) In einem kleinen Exkurs wird dafür die Abstraktion als Hilfsmittel von Verifikationsverfahren vorgestellt bevor die Datenabstraktion als Verfahren einer tieferen Betrachtung unterzogen wird. Abschließend wird erörtert wie das Verfahren im Rahmen der abstrakten Interpretation eingesetzt wird. 4.3 Abstraktion Mit Hilfe der Abstraktion ist es eher möglich die speicher- und rechenintensiven Methoden der Verifikationsverfahren auch in industriellen Anwendungen einzusetzen. Das Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 73 Ziel ist hierbei, die Abstraktion so zu gestalten, dass die interessierenden Eigenschaften des Originales, z.B. einer Menge im seinem Abbild erfasst sind. Nachfolgende werden die wichtigsten Abstraktions-Verfahren aufgeführt [HauTei10] -Strukturelle Abstraktion -Funktionale Abstraktion -Zeitabstraktion -Datenabstraktion Da die Datenabstraktion für das in diesem Beitrag beschriebene Verfahren allein von Interesse ist, sei der interessierte Leser für alle weiteren Abstraktionsarten auf [HauTei10] verwiesen. Datenabstraktion Die Datenabstraktion zielt wie die anderen Abstraktionsverfahren darauf ab den Bedarf an Speicher und Rechenkapazität zu senken. Um eine rechenintensive Überprüfung der originär im Quellcode vorhandenen Definitionsbereiche zu vermeiden, werden die Original Datentypen im Rahmen der Datenabstraktion durch abstrakte Datentypen ersetzt. So können z.B. ganze Zahlen anstelle von Vektoren oder Fließpunktzahlen verwendet werden. Hierzu wird jede Programmzeile auf den abstrahierten Datenbereich übertragen und die Original-Operatoren durch induzierte ersetzt. Die Elemente des originalen Datenbereichs werden dabei komprimiert, so dass ein Element des abstrahierten Datenbereichs stellvertretend für mehrere Original–Elemente stehen kann und diese damit approximiert werden. Die Approximation trägt einen entscheidenden Anteil zur Lösung des Berechenbarkeitsproblems bei. Nachteilig ist hierbei, das eventuell auftretende „Bereichsüber- oder Unterschreitungen nicht mehr erkannt“ [Hoffma08] werden. [Hoffma08,HauTei10] Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 74 Verfahren der Datenabstraktion sind z.B. die Gallois-Verbindungen nach Patrick Cousot und Radhia Cousot. Hier wird neben einer Abstraktionsfunktion zusätzlich eine Konkretisierungsfunktion verwendet um die konkreten Werte auf einen abstrakten Wert (Abstraktionsfunktion) und den abstrakten Werte alle konkreten Werte für die er stellvertretend steht zu zuweisen [iMikN11]. Vertiefend dazu sei dem interessierten Leser das Werk von P. und R. Cousot empfohlen [Cousot77]. Abstraktionfunktion α: α:L→M Konkretisierungsfunktion: γ: γ:M→L Trotz Bereichsüber- oder Unterschreitungen, die Vorteile der DA überwiegen, so bietet ein durch DA bestimmtes Abstraktionsgerüst nicht nur die Reduktion des Datenbereiches, es ist zudem, mit Hilfe der DA möglich, wichtige Eigenschaften der OriginalDomäne auf die abstrahierte Domäne zu übertragen. Dadurch kann eine gewisse Rückübertragbarkeit von Eigenschaften der abstrahierten Domäne auf die Originaldomäne gewährleistet werden. Anhand eines Beispiels soll dies veranschaulicht werden. Prinzip der Datenabstraktion Originaldomäne Beispiel: Restklassenarithmetik Originaldomäne x Original Operator α α α x Induzierter Operator Abstraktionsdomäne α {0,1,2,3} {0,1,2,3} Abstraktionsdomäne Abbildung 4-5: Prinzip der Datenabstraktion (in Anl. an Hoffma08) Abbildung 4-5 zeigt Beispiel auf der linken Seite das Prinzip der Abstraktion, die rechte Seite bildet ein Beispiel der Restklassenarithmetik ab. Wie zu sehen ist, liegen der Original-Domäne des rechten Darstellung die natürlichen Zahlen zugrunde. Der abstrahier- Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 75 te Datenbereich hingegen liegt im Intervall {0,3}. Mit Hilfe der Abstraktionsfunktion α wird nun jedem Element des Original-Bereichs der Wert x mod 4 zugewiesen. Es wird dadurch möglich jede Operation des Originalbereichs auf den abstrahierten Bereich zu übertragen, indem das Ergebnis mod 4 gerechnet wird [Hoffma08]. Neben der Reduktion des Datenbereichs von der Menge der natürlichen Zahlen auf das Intervall {0,3}, werden auch die Original-Funktionen auf den abstrahierten Datenbereich übertragen. Die Datenabstraktion bildet damit den zweiten Baustein der abstrakten Interpretation, sie trägt zwar keinen Anteil an der Verifikation selbst, durch die Reduktion des Datenbereiches wird aber eine Bestimmung des Fixpunktes mit einem vertretbaren Ressourcenaufwandes möglich. Die Übertragbarkeit und Rückübertragbarkeit der Eigenschaften von originären auf abstrahierten Datenbereich und umgekehrt spielt dabei eine entscheidende Rolle. 4.4 Fixpunktiteration und Datenabstraktion im Rahmen der abstrakten Interpretation In den bisherigen Ausführungen wurden die Bestandteile abstrakten Interpretation, die FI sowie die DA erläutert. Nichts desto trotz fehlt bisher die Kombination der beiden Verfahren. Darauf soll jetzt ausführlich eingegangen werden. Szenario 1 Szenario 2 ZF ZF Z ∧C(Z ) = Exakte Zustandsmenge C(ZF) Z Z F ZF C(ZF) C(ZF) F Szenario 3 F F Z ∧C(Z ) = Zustandsaproxima on Z F F Z ∧C(Z ) = Fehlerzustände Abbildung 4-6: Schnittszenarien der Mengenapproximation [Hoffma08]. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 76 Um das Prinzip von Floyd, Park und Park Clarke auch in der Praxis anwenden zu können wird als abstrahierter Datenbereich die Menge der konvexen Polygone im n Dimensionalen Raum gewählt, welche die Basis der Fixpunktiteration bilden. [Hoffma08] Dies macht es möglich, jede Zustandsmenge Z eines Programmes mit n Variablen durch eine konvexe Hülle C(Z) anzunähern (welche ebenfalls durch ein Gleichungssystem dargestellt wird). Im Verlauf der Fixpunktbestimmung kann bei Kombination der konvexen Polygone bzw. Zustände ein nicht konvexes Polygon entstehen. Das heißt die Fixpunktiteration würde nicht in der gewünschten Zeit terminieren. Es würde schlicht zu lange dauern, bis der Fixpunkt bestimmt wäre, da das Polygon entweder unendlich oder sehr sehr groß wäre. Um den Datenbereich wieder einzugrenzen wird durch Kombination mit weiteren Zuständen erneut eine konvexes Polygon erzeugt. Durch diese Vorgehensweise kommt es zu einer Überapproximation, die sicherstellt, dass jeder Zustand der nicht berechenbaren Menge Z vollständig in C(Z) enthalten ist [HofDi08]. Die Mengenapproximation bezieht schließlich auch die Fehlermenge ZF mit ein, was schließlich zu drei Schnittszenarien führen kann. Einen Einfluss auf die Schnittszenarien nehmen dabei auch die Elemente die zwar in C(Z) nicht aber in Z enthalten sind. Bedingt wird dies dadurch, dass neben den Elementen aus Z auch weitere Elemente in C(Z) enthalten sein können, die Datenabstraktion zollt damit der sogenannte Bereichsüberschreitung und Bereichsunterschreitung ihren Tribut. Die sich ergebenden Schnittszenarien sind nachfolgend in Abbildung 4-6 dargestellt. Szenario 1 Wie der Abbildung 4-6 zu entnehmen ist, haben die approximierte Menge C(Z) und die Fehlermenge ZF keine Schnittmenge, sie sind disjunkt. Daraus kann geschlussfolgert werden, dass keiner der in ZE enthaltenen fehlerhaften Zustände erreicht werden kann. Das Programm erfüllt damit die zu verifizierende Eigenschaft ohne Einschränkungen. Szenario 2 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 77 Die Fehlermenge ZF umschließt sowohl die approximierte Menge C(Z) und damit auch die auch die originäre Zustandsmenge Z. Entsprechend liegen sind im Programm Zustände der Fehlermenge ZF enthalten und die zu verifizierende Eigenschaft wird verletzt. Das Programm wäre folglich nicht fehlerfrei. Szenario 3 Hier kommt es zu einer Schnittmenge zwischen der Fehlermenge ZF und der approximierten Menge C(Z). Es kann folglich keine Aussage über die zu verifizierende Eigenschaft getroffen werden, da nicht klar ist, ob die Schnittmenge Elemente der originären Zustandsmenge Z enthält. Wäre dies der Fall, wäre auch die zu verifizierende Eigenschaft verletzt. Sind jedoch lediglich Elemente der überapproximierten Menge C(Z) aufgrund einer Bereichsüber- oder Bereichsunterschreitung, enthalten so lässt sich das Fehlerszenario nicht herbeiführen. Das Verfahren würde dann einen sogenannten False negative erzeugen. Das heißt, trotz eines korrekt arbeitenden Programmes ist es nicht möglich die zu verifizierende Eigenschaft zu beweisen. Dies ist auch notwendig, zwar ist es das Ziel ein exaktes Ergebnis zu erzeugen, dennoch macht es vor allem im Rahmen sicherheitskritischer Systeme wie. z.B. Fly-By-Wire-Systemen durchaus Sinn einen Fehler anzeigen zu lassen und damit behebbar zu machen, der sich eventuell als Finte herausstellt, als diesen Fehler gar nicht zu untersuchen. 4.5 Zusammenfassung Abstrakte Interpretation Die Fixpunktiteration als exaktes, aber ressourcenintensives Verfahren ist wie anhand von Beispielen erläutert wurde in der Praxis ebenso schwierig einzusetzen wie andere Verifikationsverfahren. Erst die Datenabstraktion sowie die Widening- und NarrowingOperatoren ermöglichen durch die Reduktion des Prüfraums eine praxisnahe Anwendung. Das dabei in einigen Fällen, wie Szenario 3 zeigt, lediglich eine partielle anstatt der vollständigen Korrektheit eines Programmes nachgewiesen werden kann stellt einen Nachteil dar, der durch eine erheblich bessere Skalierbarkeit des Verfahrens aufgewogen wird. Zudem ist es allemal besser eine False-Negative-Meldung mehr zu erzeugen Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 78 als einen verstecken False-Positive Fehler nicht zu entdecken, was mit der AI ausgeschlossen ist. Der Vorteil der besseren Skalierbarkeit führte schließlich dazu, dass die abstrakte Interpretation in der Praxis bereits breite Anwendung findet, was der Modellprüfung und der Deduktion bis auf wenige Ausnahmen bisher verwehrt blieb. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 79 5 Schlussbetrachtung 5.1 Zusammenfassung Wie in Kapitel 1 dieses Dokuments beschrieben, hängt die industrielle Anwendbarkeit bei allen Verifikationsverfahren von drei wesentlichen Faktoren ab, der Ausdrucksstärke, der Skalierbarkeit und der Automatisierbarkeit des eingesetzten Verfahrens. Bewertet man die drei vorgestellten Verfahren: Deduktion, Modellprüfung und abstrakte Interpretation anhand dieser Faktoren, so ist die Deduktion das Verfahren mit der höchsten Ausdruckstärke, mit ihrer Hilfe können komplexe Programme und Algorithmen mit Hilfe höherwertiger Logiken vollständig abgebildet werden. Ihre Skalierbarkeit ist jedoch stark eingeschränkt, da eine Anwendung auf große Programme meist nur mit erheblichem Aufwand realisierbar ist. Auch eine Automatisierung des Verfahrens ist kaum möglich. Die Modellprüfung und die Abstrakte Interpretation sind beide weniger Ausdrucksstark als die Deduktion, dafür aber leichter automatisierbar und vor allem besser skalierbar. Besonders die abstrakte Interpretation hat hier große Vorteile und konnte bereits den Weg in industrielle Anwendungen finden. 5.2 Fazit Ein nicht durchführbarer Beweis nach den vorgestellten Verfahren deutet darauf hin, dass der geprüfte Code eine bestimmte Unschlüssigkeit aufweist. Möglicherweise liegt aber auch das Gegenteil vor, es ist ein tatsächlich ein fehlerfreies Programm entstanden, der Autor ist aber nicht in der Lage zur Durchführung der Codeprüfung. Mit wachsender Größe und Komplexität des Programms nimmt auch die Komplexität der Beweisführung deutlich zu, die zwangsläufig auch eine erhöhte Fehlerrate bei deren Durchführung mit sich bringt. Ein sehr komplexes Programm mit längeren Stücken Code setzt einen wesentlich aufwändigeren Beweis voraus, bei dessen Durchführung mit ähnlich vielen Fehlern zu rechnen ist, wie bereits im Programm selber enthalten sind. Auf Grund der Tatsache, dass Menschen Fehler machen - umso mehr, desto komplexer die Angelegenheit wird – stellt sich die Frage, ob so einem Beweis mehr Vertrauen zu Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 80 schenken ist, als dem Programm, dessen Korrektheit möglichweise bezweifelt wird. Kein Prüfsystem, das auf den Programmcode eines zu untersuchenden Programms aufsetzt, wie etwa das Hoare-Kalkül, kann einen Fehler aufdecken, der auf der Spezifikation beruht. Maximal wird gezeigt, dass die Spezifikation korrekt umgesetzt worden ist, ob diese an sich korrekt oder fehlerhaft ist, wird nicht berücksichtigt. Programme mit zwar korrekt umgesetzten Routinen, die allerdings auf einer nicht ausgereiften Spezifikation beruhen, haben das gleiche Gefahrenpotential, wie eine fehlerhafte Implementierung einer an sich korrekten Spezifikation. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 81 6 Quellenverzeichnis Literaturquellen [Berard01] Bérard, B. et al.: Systems and Software Verification. Springer Verlag, Berlin, Heidelberg, 2001 [BibelW91] Bibel, W.: Deduktion, Automatisierung der Logik. Oldenbourg Verlag, München, Wien, 1991/92 [Busche04] Buschermöhle, R. et al.: Model Checking. In: Informatik-Spektrum. Hrsg. von Bode, Arndt. Springer Verlag, Berlin, Heidelberg, 2004 [Clarke79] Clarke, E.M.: Programming language constructs for which it is impossible to obtain good Hoare axiom systems. Journal of the ACM, 26(1), 1979 [ClGrPe00] Clarke, E. M.; Grumberg, O.; Peled, D. A.: Model Checking. MIT Press, Cambridge (MA), 2000 [Cousot77] Cousot, P.; Cousot, R.: Abstract interpretation: a unified lattice model for static analysis of programs by construction or approximation of fixpoints. In Conference Record of the Sixth Annual ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, Los Angeles, California, 1977. [Floyd67] Floyd, R.W.: Assigning meaning to programms. In: Proceedings of symposia on Applied Mathematics; American Mathematical Society, Providence, 1967. [Franz07] Franz, K.: Handbuch zum Testen von Web-Applikationen. Springer Verlag, Berlin, Heidelberg, New York, 2007. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. [HauTei10] Haubelt, C.; Teich, J.: Digitale Hardware/Software-Systeme. Springer Verlag, Berlin, Heidelberg, 2010 [Hempel96] Hempel, T.: Darstellung von Iterationsverfahren zur Nullstellenbestimmung von Funktionen und visualisierende Computerexperimente, Chemnitz, 1996. [Hoffma08] Hoffmann, Dirk W.: Software-Qualität. Springer Verlag, Berlin, Heidelberg, 2008 [HofLan11] Hofmann, M.; Lange, M.: Automatentheorie und Logik. Springer Verlag, Berlin, Heidelberg, 2011 [Holzma03] Holzmann, G. J.: The Spin Model Checker – Primer and Reference Manual. Addison-Wesley, Boston (MA), 2003 [Lamber10] Lambert, M.; Tipleton, M.T.; Marseken, S.F.: Abstrakte Interpretation, Betascript Publishing, Mauritius, 2010. [LoeSie84] Loeckx, J.; Sieber, K.: The Foundations of Programm Verification; Stuttgart, 1984. [Lovisc98] Loviscach, J.: Absturzgefahr, die Bug-Story. In: c’t, Magazin für Computertechnik, Nr. 18/1998. [Marwed07] Marwedel, P.: Eingebettet Systeme. Springer Verlag, Berlin, Heidelberg, 2007 [Myers01] Myers, G. J.: Methodisches Testen von Programmen. Oldenbourg Verlag, München, Wien, 2001 82 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. [Park69] Park; D.: Fixpoint induction and proofs of programm properties. Machine Intelligence 5, 1969 [Scholz05] Scholz, P.: Softwarequalität eingebetteter Systeme. Springer Verlag, Berlin, Heidelberg, 2005 [SeWiHa10] Seidl, H.; Wilhelm, R.; Hack, S.: Übersetzerbau 3: Analyse und Transformation; Springer Verlag, Berlin, Heidelberg, 2010 [Stacho73] Stachowiak, H.: Allgemeine Modelltheorie. Springer Verlag, Wien, New York, 1973 83 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. 84 Internetquellen [iAstree11] Homepage der Firma Astree: The Astrée Static Analyser. URL: http://www.astree.ens.fr Abfrage: 2011-09-12 [iBubeck06] Bubeck, U.: Binary Decision Diagrams, 2006. URL: http://www2.cs.uni-paderborn.de/cs/agklbue/de/courses/ws05/logik/bdd.pdf Abfrage: 2011-10-13 [iCMSCS83] Homepage der Carnegie Mellon School of Computer Science: Automatic Verification of Finite-StateConcurrent Systems Using Temporal LogicSpecifications, 1983. URL: http://www.cs.cmu.edu/~emc/papers/Conference%20Papers/Automati c%20verification%20of%20finite%20state%20concurrent%20system %20using%20temporal%20logic%20specifications%20a%20practical %20approach.pdf Abfrage: 2011-10-02 [iCorAgo11] Cortesi, Agostino; Homepage der Universität Venedig: Widening Operators for Abstract Interpretation. URL: http://www.dsi.unive.it/~cortesi/paperi/sefm08.pdf Abfrage: 2011-09-12 [iGellne01] Gellner, M.: Einführung in die Verifikation, 2001. URL: http://www.inf.fu-berlin.de/lehre/SS09/PI03/docs/Hoare.pdf Abfrage: 2011-10-10 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. [iKönBar11] 85 König, Barbara; Homepage der Universität Duisburg: Programmanalyse-Modellierung, Analyse, Verifikation. URL: http://www.ti.inf.unidue.de/fileadmin/public/teaching/mav/slides /ws201112/einfuehrung-2x2.pdf. Abfrage: 2011-09-15 [iLevPau11] Levi, Paul; Homepage der Universität Stuttgart: Fixpunktiteration und Nullstellenbestimmung. URL: http://www.ipvs.uni-stuttgart.de/abteilungen/bv/lehre/lehrveranstaltungen/vorlesungen/WS091 0/NSG_termine/dateien/Fixpunktiteration.pdf Abfrage: 2011-09-29 [iManRog11] Manz, Roger; Homepage von Prof. Roger Manz: Fixpunktiteration. URL: http://www.ipvs.uni-stuttgart.de/abteilungen/bv/lehre/lehrveranstaltungen/vorlesungen/WS091 0/NSG_termine/dateien/Fixpunktiteration.pdf Abfrage: 2011-09-26 [iMath11] Homepage der Firma Mathworks: Fixpunktiteration. URL: http:// www.mathworks.de/products/polyspace/index.html Abfrage: 2011-09-29 [iMikN11] Mikhaylova, N; Homepage der Ludwig-Maximilians-Universität München; Abstrakte Interpretation I. URL: http://www2.tcs.ifi.lmu.de/lehre/SS09/ProSem/Folien/ Mikhaylova.pdf Abfrage: 2011-10-02 [iPirMar11] Pirrainen, Martti; Homepage der TU-Berlin: Abstrakte Interpretation. URL: http://swt.cs.tu-berlin.de/lehre/atswt/ss02/AbsInt.pdf Abfrage: 2011-10-05 Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. Error! Use the Home tab to apply Überschrift 1 to the text that you want to appear here. [iSinz06] Sinz, C.: Binäre Entscheidungsdiagramme, 2006. URL: http://www-sr.informatik.unituebingen.de/~sinz/SAT_0607/pdf/V7.pdf Abfrage: 2011-10-13 [iIWiki11] Online-Lexikon der Fakultät Informatik/Wirtschaftsinformatik der Fachhochschule Würzburg: Syntaxbaum, 2011. URL: http://www.iwiki.de/wiki/index.php/Syntaxbaum Abfrage: 2011-10-11 [iWikiE11] Homepage der englischsprachigen Wikipedia Foundation: List of model checking tools, 2011. URL: http://en.wikipedia.org/wiki/List_of_model_checking_tools Abfrage: 2011-10-14 86