Sichtgraphen: Ein Konzept zur gezielten Untersuchung von Kontrollflussstrukturen

Der technischen Fakultät der Universität Erlangen-Nürnberg

zur Erlangung des Grades

D O K T O – I N G E N I E U R

vorgelegt von

Stefan Goßens

Erlangen, 2004

Als Dissertation genehmigt von der Technischen Fakultät der Universität Erlangen-Nürnberg

Tag der Einreichung: 14. Mai 2004 Tag der Promotion: 15. Juli 2004 Dekan: Prof. Dr. Albrecht Winnacker Berichterstatter: Prof. Dr. Dr. h.. Mario Dal Cin Prof. Dr.-Ing. habil. Fevzi Belli

Kurzfassung

Die vorliegende Arbeit beschreibt ein Konzept zur Abstraktion von Kontrollflussstrukturen, die Sichtgraphen, und mögliche Anwendungen. Viele Aufgabenstellungen der Informatik, speziell im Validierungs– und Verifikationsbereich, basieren direkt oder indirekt auf der Analyse von Kontrollflüssen. Oft interessieren dabei beson- ders bestimmte Aktionen im Kontrollfluss des Systems – beispielsweise Ein– und Ausgaben. Diese Aktionsmengen definieren eine Sicht auf den Graphen. Die möglichen Abfolgen der Ak- tionen werden im vorgestellten Ansatz kompakt als Sichtgraph repräsentiert, der so eine gezielte Abstraktion des Kontrollflussgraphen darstellt. Es gibt viele denkbare Anwendungen für Sichtgraphen. Die Arbeit stellt neben den Grundla- gen exemplarisch zwei spezielle Sichten vor, die Verhaltenssicht und die Zuverlässigkeitssicht. Dies sind die Sichten bezüglich der Ein– und Ausgabeanweisungen bzw. der Anweisungen, die zur Realisierung expliziter Fehlertoleranz dienen. Die entsprechenden Sichtgraphen sind Verhaltensgraphen und Zuverlässigkeitsgraphen. Verhaltensgraphbasierte Metriken können zur Bewertung von Testfallmengen dienen. In der Arbeit wird eine solche Kenngrösse, die Verhaltensdiversität, vorgestellt. Ein Ansatz zur Mo- dellierung der Fehleraufdeckungsfähigkeiten von Programmen wird entwickelt und in einer experimentellen Untersuchung der Verhaltensdiversität benutzt. Anhand der Zuverlässigkeitssicht lässt sich die Fehlertoleranzarchitektur eines Systems prüfen. Die Arbeit betrachtet ein entsprechendes Verfahren. Zusätzlich wird ein an Sichtgraphen angelehntes Konzept zum Entwurf von Tests aus automa- tenbasierten Spezifikationen beschrieben.

Abstract

The thesis describes a concept for the abstraction of control flow graphs, view graphs, and some of its possible applications. Many computer science applications, especially in validation and verification, are directly or indirectly based on control flow analysis. Often, certain actions in the control flow are of special interest – e.g. input and output actions. These actions define a view of the graph. Their possible sequences are represented as view graphs in the presented approach, which are view–focused abstractions of the control flow graph. There are many imaginable applications for view graphs. The thesis introduces the basic con- cepts as well as two special views, behavioural view and reliability view. These are the views with respect to input and output statements resp. the statements that constitute explicit fault tolerance mechanisms. The corresponding view graphs are behavioural graphs and reliability graphs. Metrics based on behavioural graphs can serve as a basis of test case evaluations. This thesis in- troduces such a metric, behavioural diversity. An approach for modeling fault detection abilities of programs is developed and used in an experimental evaluation of the metric. Using reliability graphs, the fault tolerance architecture of a system can be examined and veri- fied. The thesis describes a corresponding approach. Additionally, a concept similar to the view–graph approach to generate test designs is presented.

Dank

Für Betreuung, gute Zusammenarbeit und Begutachtung danke ich Prof. Dr. Dr. h.c. Dal Cin. Bei Prof. Dr.–Ing. habil. Fevzi Belli bedanke ich mich für die Übernahme des Zweitgutachtens und die besonders freundliche Unterstützung. Neben den genannten haben auch andere Menschen durch fachliche Diskussion, konstruktive Kritik und/oder Ermutigung zur Entstehung der Arbeit beigetragen. Für diese oft nur kurzen, aber manchmal entscheidenden, Gespräche danke ich: Dipl.–Math. Martin Becker–Wennecker, Dr. Yunja Choi, Prof. Dr. Jürgen Ebert, Prof. Dr. Klaus Echtle, Prof. Dr.–Ing. Wolfram Glauert, Dipl.–Ing. Werner Haas, Dr.–Ing. Ulrich Heinkel, Prof. Dr.–Ing. Ulrich Herzog, Dr. Markus Jochim, Dr.–Ing. Roman König, Dr.–Ing. David Kreische, Dr. Raymond Paul, Prof. Dr. Francesca Saglietti, Dr.–Ing. Volkmar Sieh, Dr.–Ing. habil. Bernd Straube und Dr. Andreas Winter. Mein besonderer Dank gilt M.Sc. (mult.) Fangfang Wang für die umfassendste Unterstützung, die denkbar ist.

Inhaltsverzeichnis

1 Einführung 1 1.1 Black-Box und White-Box-Perspektiven ...... 1 1.2 Umfang und Beitrag dieser Arbeit ...... 2 1.3 Kapitelübersicht ...... 3

2 Verhaltensgraphen und Sichtgraphen 5 2.1 Abstraktion von Verhaltensstrukturen ...... 7 2.1.1 Berechnung von Verhaltensgraphen ...... 8 2.1.2 Sichtgraphen ...... 10

3 Verhaltensgraphen und Testfallmengenbewertung 11 3.1 Strukturbasierte Kontrollflussmetriken ...... 12 3.2 Verhaltensdiversität ...... 14 3.3 Fehleraufdeckungsmodellierung ...... 15 3.3.1 Fehlerentstehung und Fehleraufdeckung ...... 16 3.3.2 Fehleraufdeckungshäufigkeiten und -wahrscheinlichkeiten ...... 19 3.4 Validierungsexperiment ...... 23 3.4.1 Das Werkzeug proggen ...... 23 3.4.2 Das Experiment ...... 28 3.4.3 Parameterauswahl ...... 34 3.4.4 Ergebnisse ...... 36 3.5 Diskussion ...... 40

4 Sichtgraphen und Architekturuntersuchung 47 4.1 Fehlertoleranzstrukturen ...... 47 4.2 Zuverlässigkeitssicht ...... 50 4.3 Pfade als Suchmuster ...... 51 4.4 Strukturanalyse mit mcana und SMV ...... 52 4.4.1 Das Werkzeug mcana ...... 53 4.4.2 Pfadsuche ...... 53 4.4.3 Fallbeispiel ...... 54 4.5 Diskussion ...... 61

5 Unterstützung beim Testentwurf 63 5.1 Rechnergestütztes Testen ...... 63

i Inhaltsverzeichnis

5.2 Generierung von Testentwürfen aus Spezifikationsautomaten ...... 64 5.2.1 ADeVA ...... 65 5.2.2 Generierung von Testentwürfen ...... 67 5.3 Testpfadgenerierung mit Guwen ...... 69 5.3.1 Umformung von ADeVA–Tabellen in SMV–Modelle ...... 69 5.3.2 CTL–Formeln und Pfadbestimmung ...... 72 5.3.3 Interpretation der SMV–Ergebnisse ...... 72 5.4 Diskussion ...... 74

6 Perspektiven 77 6.1 Sichtgraphen als Automaten: Sichttypen ...... 77 6.2 Numerische Analyse ...... 81 6.2.1 Zeitbehaftete Verhaltensgraphen ...... 81 6.2.2 Zuverlässigkeitsparameter ...... 81 6.3 Erweiterte Architekturuntersuchung ...... 82 6.4 Verwandte Techniken ...... 82

Literaturverzeichnis 85

Schriftenverzeichnis 90

A Programme der Voruntersuchung 93

B Listen der Sprungbefehle und E/A–Routinen 97

C SMV-Lauf 101

ii Abbildungsverzeichnis

2.1 Beispiel eines Kontrollflussgraphen ...... 6 2.2 Black-Box-Sicht eines Systems ...... 6 2.3 Verhaltensgrapherzeugung ...... 8

3.1 Strukturelemente in proggen-Kontrollflussgraphen ...... 24 3.2 Von proggen erzeugter Kontrollflussgraph ...... 26 3.3 Von proggen generiertes Pseudoprogramm ...... 27 3.4 Von proggen erzeugter Verhaltensgraph ...... 28 3.5 Von proggen erzeugter Pfad im Kontrollflussgraph und Verhaltensgraph . . . . 29 3.6 Programmgrösse gegen E/A-Prozentanteile ...... 33 3.7 Programmgrösse gegen E/A-Prozentanteile (Ausschnitt) ...... 34 3.8 Programmgrösse gegen Verzweigungs-Prozentanteile ...... 35 3.9 Programmgrösse gegen Verzweigungs-Prozentanteile (Ausschnitt) ...... 35

¢¡ min 3.10 f £ nach Verteilung nichtaufdeckende/aufdeckende Ausgabeanweisungen und Häufigkeitsobergrenzen (1) ...... 42

¢¡ min 3.11 f £ nach Verteilung nichtaufdeckende/aufdeckende Ausgabeanweisungen und Häufigkeitsobergrenzen (2) ...... 43 min 3.12 Verzweigungsabdeckung/f £ nach Verteilung nichtaufdeckende/aufdeckende Ausgabeanweisungen und Häufigkeitsobergrenzen (3) ...... 44 min 3.13 Verzweigungsabdeckung/f £ nach Verteilung nichtaufdeckende/aufdeckende Ausgabeanweisungen und Häufigkeitsobergrenzen (4) ...... 45

4.1 Recovery Block–Modul ...... 49 4.2 MVP–Modul ...... 49 4.3 Gemischte Fehlertoleranzarchitektur ...... 50 4.4 Kontrollflüsse Recovery Block und Multiversion Programming ...... 51 4.5 Geschachtelte Zuverlässigkeitsmuster ...... 52 4.6 Untersuchtes Programm ...... 55 4.7 Kontrollflussgraph des untersuchten Programms ...... 56 4.8 Zuverlässigkeitsgraph ...... 58 4.9 SMV–Eingabe ...... 58 4.10 Entwurfsfehler (1) ...... 59 4.11 Zuverlässigkeitsgraph nach Änderung (1) ...... 59 4.12 Entwurfsfehler (2) ...... 60 4.13 Zuverlässigkeitsgraph nach Änderung (2) ...... 61

iii Abbildungsverzeichnis

5.1 Mode Transition Table für Signal current mode ...... 66 5.2 Data Transformation Table für Signal byteMON ...... 66 5.3 SMV–Modell für ADeVA–Tabelle aus Abbildung 5.1 ...... 71 5.4 Testentwürfe ...... 73

6.1 Erzeugung von Kontrollflussautomaten aus Kontrollflussgraphen ...... 79 6.2 Automat und Typ zum Verhaltensgraph aus Kapitel 2 ...... 79

iv Tabellenverzeichnis

3.1 Pakete der Vorstudie ...... 32 3.2 Ergebnisse nach Häufigkeitsobergrenzen ...... 36 3.3 Ergebnisse nach Anteil potenziell fehlerhafter E/A-Anweisungen (1) ...... 38 3.4 Ergebnisse nach Anteil potenziell fehlerhafter E/A-Anweisungen (2) ...... 39

v Tabellenverzeichnis

vi 1 Einführung

Der Verhaltensbegriff wird zum Beginn des 20. Jahrhunderts durch den Behaviorismus wis- senschaftlich konkretisiert. Dessen Gegenstand ist die Analyse des manifesten, beobachtbaren (menschlichen) Verhaltens, basierend auf Reiz-Reaktions-Schemata. Im Rahmen dieser Inter- pretation des Verhaltensbegriffs werden die Termini Stimulus-Response-Modell (S-R-Modell) und Black-Box-Modell geprägt. In späteren Entwicklungen konkretisieren sich die Begriffe „Sti- mulus“ und „Response“ auf physiologische (und damit letztlich physikalische) Begrifflichkei- ten, was sich auch terminologisch im neueren Begriff Rezeptor-Effektor-System niederschlägt.1 Betrachtung und Bewertung von Ingenieurskonstruktionen basieren üblicherweise auf diesem Modell. Dessen Übernahme in die Ingenieurwissenschaften und speziell die Elektrotechnik lässt sich mindestens bis in die vierziger Jahre des 20. Jahrhunderts zurückverfolgen. In der Infor- matik wird „Verhalten“ besonders im Rahmen der Validierung und Verifikation von Systemen betrachtet. Bei der Funktionsprüfung wird davon ausgegangen, dass Programme und andere de- terministische Systeme durch ihre nach aussen (d.h. an ihren Schnittstellen) sichtbare Aktivität charakterisiert werden. Dies ist der Standpunkt eines Betrachters, den im wesentlichen nicht in- teressiert, wie ein System eine Aufgabe löst, sondern nur, dass es sie zufriedenstellend löst. Das Lösen einer Aufgabe (das Berechnen einer Funktion) ist dadurch charakterisiert, dass zu jedem möglichen Wert an den Eingabeschnittstellen ein gewünschter Wert an den Ausgabeschnittstel- len geliefert wird. Die „korrekte“ Lösung kann neben der eigentlichen Wertebestimmung noch durch weitere, etwa zeitliche, Bedingungen charakterisiert sein.

1.1 Black-Box und White-Box-Perspektiven

Bei Validation und Verifikation bringt diese Definition von Systemverhalten Probleme mit sich. Zwar wird durch die im allgemeinen endlichen Ein- und Ausgabemengen digitaler Syste- me auch die Menge der möglichen „Verhaltensweisen“ auf eine endliche Menge beschränkt, was gegenüber den unendlichen oder sogar unbekannten Ein- und Ausgabemengen natürli- cher Systeme einen Vorteil darstellt. Eine expermientelle vollständige Verhaltensuntersuchung kann aber überaus aufwändig und de facto unmöglich werden, wenn es sehr viele mögliche

1In der Psychologie wurde diese Entwicklung nicht unkritisch betrachtet, da soziale Eigenschaften – und damit grössere Verhaltensstrukturen – in diesem Modell nicht berücksichtigt werden. Besonders die frühen Phasen werden heute gerne als fachlich „naiv“ qualifiziert. Die Entwicklung des Verhaltensbegriffs in den Sozialwis- senschaften soll aber an dieser Stelle nicht weiter betrachtet werden.

1 1 Einführung

Ein-/Ausgabepaare gibt. Beispielsweise erzeugt ein System mit 32 binären Eingängen und Aus- gängen bereits 264 mögliche Paare, von denen jeweils zu entscheiden ist, ob sie eine korrekte Berechnung darstellen oder nicht. Mindestens müssten 232 einzelne Beobachtungen durchge- führt werden. In der Informatik werden im Themenkreis „Black-Box-Testen“ Methoden untersucht, die ver- suchen, unter bestimmten Annahmen aus den gewünschten Ein-/Ausgabepaaren geeignete Ver- treter zu bestimmen, ohne die technische Realisierung des Systems (als Programm, Schaltung oder ähnliches) zu betrachten. Dazu gehören die Partitionierung der Ein- und Ausgabemengen in bestimmte Äquivalenzklassen, Zufallstests, Auswahl spezieller Testwerte, Vergleich diver- sitärer Implementationen und vieles mehr. Komplementär dazu wird beim White-Box-Testen ausgenutzt, dass in den allermeisten Fällen neben einer funktionsfähigen Implementation auch das Konstruktionsmuster (in Form von Quellprogramm oder Schaltplan) zur Verfügung steht. White-Box-Verfahren nutzen in der Regel aus der Konstruktionsstruktur abgeleitete Kriterien oder Kenngrössen, beispielsweise die Abdeckung der Anweisungen oder Verzweigungen ei- nes Programms (Statement/Branch Coverage), um die Qualität von Testvorgängen zu bewerten oder daraufhin optimierte Testdaten zu konstruieren. Ein anderer Weg, den die White-Box- Perspektive eröffnet, ist die Untersuchung der Implementation auf verifikationsrelevante Struk- turinformation, beispielsweise die Möglichkeit unerwünschter Programmabläufe. So kann man unter Umständen bereits verifikationsrelevante Aussagen gewinnen, bevor mit dem eigentlichen Test begonnen wird. In der Systemanalyse nach Black-Box- und White-Box-Verfahren bleiben spezifische Aspek- te des einzelnen untersuchten Systems weitgehend unberücksichtigt. Beispielsweise wird die Qualität funktionaler Tests anhand struktureller Kriterien beurteilt, die für alle möglichen un- tersuchten Systeme gleich sind. Dabei wird keine Aussage über die Relevanz der ausgewählten Testdaten getroffen, sondern nur eine rein quantitative Abdeckung angegeben. Mit einer hohen Abdeckungsquote wird die Hoffnung auf eine hohe Fehleraufdeckungsrate verbunden.

1.2 Umfang und Beitrag dieser Arbeit

Die White-Box-Perspektive erlaubt die Untersuchung der Kontrollflussstruktur des betrachteten Systems aus gezielt gewählten Blickwinkeln. In der vorliegenden Arbeit wird ein Konzept zur Abstraktion des Kontrollflusses vorgestellt. Dabei werden speziell interessierende Aktionen im Kontrollfluss des Systems identifiziert und deren Abfolgestruktur ermittelt. Basierend auf den möglichen Variationen des Kontrollflusses werden alle möglichen Abfolgen dieser Anweisun- gen ermittelt und in einem Graphen repräsentiert, der auf diese Weise eine gezielte Abstraktion oder Sicht des Kontrollflusses darstellt. Der entstehende Graph heisse der Sichtgraph des Sys- tems bezüglich der gewählten Anweisungsmenge. Wählt man die Sicht der Ein-/Ausgabeanweisungen, erhält man den Verhaltensgraph, der die möglichen Aktivitätsabfolgen des Systems beschreibt. Verhaltensgraphen können als Grundla- ge für Bewertungskriterien von Testläufen dienen. Statt allgemeiner struktureller Abdeckung erfassen solche Kriterien die Abdeckung der als besonders testrelevant eingestuften Quellco-

2 1.3 Kapitelübersicht deelemente und -strukturen. Die Arbeit zeigt, dass eine verhaltensgraphbasierte Kenngrösse übliche Abdeckungskriterien sinnvoll ergänzen kann. Die White-Box-Perspektive kann auch in anderen Anwendungsbereichen als dem Testen ausge- nutzt werden, Sichtgraphen können ausser der Verhaltensstruktur auch beliebige andere Struk- turen fokussieren. Wählt man die Sicht der Anweisungen, die zur Realisierung expliziter Fehler- toleranz dienen, erhält man Zuverlässigkeitsgraphen. Durch Analyse von Zuverlässigkeitsgra- phen kann man bei Programmen die Anwesenheit oder das Fehlen gewünschter Fehlertoleranz- strukturen, wie etwa die richtige Abfolge von Berechnungs- und Prüfvorgängen, feststellen. Der Vorgang lässt sich durch Einbeziehung von Model Checkern weitgehend automatisieren und wird an Programmen für den Microcontroller Motorola 68HC705J1A demonstriert. Bei der automatischen Generierung von Testdaten aus automatenähnlichen Spezifikationen wer- den aus den vielen möglichen Automatenabläufen einige ausgewählt, die später als Grundla- ge von Tests dienen. Soll diese Auswahl gezielt erfolgen, bietet sich eine an das Sichtgraph- Konzept angelehnte Vorgehensweise an. Hierbei werden bestimmte, für das Testen wichtige Knoten (Zustände) der Spezifikation ausgewählt und die Testvorschläge so bestimmt, dass mög- lichst viele dieser Zustände durch sie abgedeckt werden. Der Ansatz wird anhand der Generie- rung von Testvorschlägen aus Spezifikationen der ASIC-Spezifikationssprache ADeVA illus- triert.

1.3 Kapitelübersicht

Im zweiten Kapitel wird der Begriff des Verhaltens genauer betrachtet. Darauf aufbauend wird der Begriff des Verhaltensgraphs definiert, der dann zum Sichtgraph verallgemeinert wird. In den darauf folgenden drei Kapiteln werden einige Anwendungsmöglichkeiten von Sichtgraphen vorgestellt und diskutiert. Kapitel 3 beschreibt zunächst ein Modellierungskonzept der Fehleraufdeckungsfähigkeiten von Programmen. Dieses Konzept wird in einer Fallstudie benutzt, in der die verhaltensgraphbasier- te Kenngrösse Verhaltensdiversität auf ihre Fehleraufdeckungseigenschaften untersucht wird. Basis dieser Studie ist die Untersuchung eines grossen Satzes künstlicher Kontrollflussgraphen. Das zu Erstellung und Analyse der Graphen verwendete Werkzeugs proggen wird vorgestellt und die durchgeführten Experimente besprochen und ausgewertet. In Kapitel 4 wird die strukturelle Untersuchung von Zuverlässigkeitsgraphen unter Verwen- dung von Model Checking-Technologie beschrieben. Konkret wird dies an der Prüfung struk- tureller Fehlertoleranzeigenschaften an Assemblerprogrammen des Microcontrollers Motorola 68HC705J1A vorgeführt. Als letztes Anwendungsbeispiel behandelt Kapitel 5 das Werkzeug Guwen, das unter Aus- wahl spezieller Zustände Testvorschläge aus automatenbasierten Spezifikationen in der Sprache ADeVA erstellt. Kapitel 6 schliesslich diskutiert weitere Anwendungsperspektiven von Sichtgraphen.

3 1 Einführung

4 2 Verhaltensgraphen und Sichtgraphen

Untersucht man berechnende Systeme, kann man bestimmte allgemein vorhandene Charakte- ristika feststellen. Solche Systeme folgen dem Eingabe-Verarbeitung-Ausgabe-Schema, mögli- cherweise in endloser Wiederholung. Die Abfolge sichtbarer wie unsichtbarer Systemaktivitä- ten (Eingaben und Ausgaben bzw. Berechnungen und innere Kommunikation) hat eine Struktur, die unmittelbar durch die Systemdefinition, etwa Programm oder Schaltung, festgelegt ist. Die möglichen Variationen dieser Abfolgen sind im Kontrollflussgraphen des Systems beschrieben. Abbildung 2.1 zeigt als Beispiel ein Programmfragment und den zugehörigen Kontrollfluss- graph. Jedes System hat dabei bestimmte, normalerweise unveränderliche, Ein- und Ausgabeschnitt- stellen. Diese Schnittstellen erwarten im Verlauf der Zeit Werte oder halten bestimmte Werte zur Abholung bereit. Diese Ein-/Ausgabeaktivitäten zu bestimmten Zeitpunkten nennt man ge- wöhnlich das beobachtbare Verhalten oder einfach nur Verhalten des Systems. Ein korrektes Verhalten hinsichtlich einer Vorgabe oder Spezifikation ist wichtigstes Ziel jeder Implementati- on. Beobachtbares Verhalten zeigt sich durch Werteveränderung oder -erwartung an Schnittstellen. Daher sollen zunächst die damit in Zusammenhang stehenden Grundbegriffe in der Interpreta- tion der vorliegenden Arbeit geklärt werden. Es wird die Black-Box-Sicht von Systemen angenommen:

Definition (System, Schnittstelle, Port, Systemdefinition) Ein System ist eine Recheneinheit, die über Schnittstellen mit der Aussenwelt kommuniziert. Eine Schnittstelle ist die Menge der Variablen oder Signale eines Systems, die von ausser- halb der Systemgrenze (z.B. Programm, Funktionskonstrukt, physische Grenze) eingesehen und/oder beschrieben werden können. Die Elemente einer Schnittstelle werden in dieser Arbeit als Port bezeichnet. Der Quellcode oder die Systemdefinition, kurz Definition, eines Systems ist eine strukturelle Beschreibung eines Systems, die hinreichend für das Implementieren des Systems ist. Abbidlung 2.2 zeigt schematisch ein System, dessen Schnittstelle aus den Ports a, b und c besteht.

5 2 Verhaltensgraphen und Sichtgraphen

read(a); mult; if( x ) { read(a); div; write(b); } else { write(b); write(c); } add; sub; write(b);

read(a) div write(b) read(a) mult if add sub write(b) write(b) write(c)

Abbildung 2.1: Beispiel eines Kontrollflussgraphen

b a c

Abbildung 2.2: Black-Box-Sicht eines Systems

6 2.1 Abstraktion von Verhaltensstrukturen

Es seien Systeme betrachtet, deren Definiton unabänderlich festgelegt, oder mindestens zu al- len beobachteten Zeitpunkten identisch ist1. Hier sind die möglichen Aktivitätsabfolgen fest durch die Struktur des Quellcodes festgelegt. Um die Betrachtung begrifflich zu erleichtern, soll die Definition zudem als Computerprogramm vorliegen. Die nachfolgenden Betrachtun- gen sind jedoch nicht auf Software beschränkt. In der Regel liegt heute auch die Beschrei- bung von Hardware, zumindest im digitalen Fall, in programmähnlicher Form vor, etwa als VHDL-Spezifikation, Tabelle oder Zustandsübergangsdiagramm. Definitionen in allen diesen Darstellungsformen ist gemeinsam, dass man sie zu sequentiell ausführbaren Algorithmenbe- schreibungen umformen kann, in denen mit einer deterministischen Abfolge von Anweisungen (Befehlen, Tabellenzeilen, Guard/Action-Kombinationen etc.) ein Algorithmus implementiert wird. In der vorliegenden Arbeit wird von einer solchen programmartigen Darstellung ausge- gangen, ohne die Art betrachteten Systeme beschränken zu wollen.

2.1 Abstraktion von Verhaltensstrukturen

Das mögliche Spektrum des Verhaltens eines Systems ist in seiner Definition (Quellcode) fest- gelegt. Jedoch löst nicht jede Anweisung der Definition auch nach aussen sichtbares Verhalten aus. Beispielsweise sind in den meisten Programmen nur ein Bruchteil der Anweisungen Ein- oder Ausgabeanweisungen. Diese Operationen auf Ports haben jedoch fundamentale Bedeutung für die Funktion des Systems, denn nur durch deren Aktivität wird die gewünschte Funktion, die innerhalb der Systemgrenze vorbereitet wird, auch nach aussen manifestiert. Ist es in einem Programm möglich, jedem Programmelement eindeutig zuzuordnen, ob es Portaktivität auslöst oder nicht, und wenn ja, an welchem Port, so können die möglichen Reihenfolgen von Portaktivitäten durch statische Analyse des Kontrollflussgraphen ermittelt werden. Die Reduktion des Kontrollflussgraphen auf die Nachbarschaftsstruktur dieser E/A- Anweisungen erlaubt eine kompakte Repräsentation der potenziell unendlich vielen Reihenfol- gemöglichkeiten in einer Graphstruktur. Diese Struktur heisse der Verhaltensgraph des Systems. Abbildung 2.3 zeigt den Kontrollflussgraphen aus Abbildung 2.1, in dem die E/A-Anweisungen markiert sind und darunter den entsprechenden Verhaltensgraph.

Definition (Verhaltensgraph)

¡

£

Sei G VG ¢ EG ein Kontrollflussgraph, mit einer Knotenmenge VG und einer Kantenmenge ¥ EG ¤ VG VG. Jedem Knoten aus VG entspreche eine Anweisung des zugrundeliegenden Pro- 2 B gramms. Sei V ¤ VG die Menge der Knoten, die Ein-/Ausgabeanweisungen entspricht. Der

G ¡

B

£ Verhaltensgraph zu G sei GB VG ¢ EGB mit

1Damit fallen selbstmodifizierende oder dynamisch rekonfigurierbare Systeme aus dem Skopus dieser Arbeit. 2Gegebenenfalls ist bei gleichen Anweisungen an verschiedenen Stellen durch Annotierung, Indizes o.ä. eine eineindeutige Zuordnung zwischen Graphknoten und Anweisungen herzustellen. In den grafisch dargestellten Beispielen dieser Arbeit wird darauf verzichtet, da die Zuordnung jeweils aus dem Kontext klar ist.

7 2 Verhaltensgraphen und Sichtgraphen

read(a) div write(b) read(a) mult if add sub write(b)

write(b) write(c)

read(a) write(b) read(a) write(b) write(b) write(c)

Abbildung 2.3: Verhaltensgrapherzeugung

¡ B B

¢¡

¢ £¤£ E v v V ¥ V GB 1 2 G G ¥

Es gibt einen Pfad v1 ¦¨§ v2 in G und ©

B

¢ ¢ ¦¨§ ¦¨§ ¦¨§ v3 £ VG v3 v1 v3 v2 : v1 v2 v1 v3 v2}

Ein Pfad in einem Verhaltensgraph abstrahiert einen Pfad im zugrundeliegenden Kontrollfluss- graphen durch „Streichung“ aller Knoten, die nicht zur Knoten-Auswahlmenge der Sicht gehö- ren:

Definition (Abstraktion von Pfaden) ¡

¡ B

£ ¢ £

Sei G VG ¢ EG ein Kontrollflussgraph, GB VG EGB der entsprechende Verhaltensgraph

¢ ¢ und p v1 ¦  ¦ vn ein Pfad in G. Seien vs1 vsm die nach Indizes geordneten Knoten von

B

  

¢  ¦ ¦

p aus VG mit 1 si  si 1 n 1 i m. Dann heisse vs1 vsm der p abstrahierende

Pfad im Verhaltensgraphen.§

B

¡ ¨

 ¢  Ist v1 ¢ vn VG , gibt es keinen Pfad, der p abstrahiert. Verhaltensgraphen beschreiben kompakt die möglichen Reihenfolgen von Ein- und Ausgabe- aktivität des zugrundeliegenden Systems. Pfade in Verhaltensgraphen werden daher in dieser Arbeit auch als Interaktionsmuster des ursprünglichen Kontrollflussgraphen bezeichnet.

2.1.1 Berechnung von Verhaltensgraphen

Verhaltensgraphen lassen sich durch eine leichte Modifikation des klassischen Algorithmus von Warshall zur Berechnung der Erreichbarkeitsmatrix eines Graphen berechnen:

8 2.1 Abstraktion von Verhaltensstrukturen

Algorithmus (Berechnung von Verhaltensgraphen) ¡

¡ B

¡

£ ¢ £ ¢ ¢  Seien G VG ¢ EG und GB VG EGB definiert wie oben, VG v1 v VG .

Sei A eine V ¥ V –Matrix. E wird schematisch wie folgt berechnet:

¥ ¥ ¥ ¥ G G GB

1. A := „Adjazenzmatrix von G“

2. EGB := 

B £

for „vi ¢ vj VG“ do £

if „vi ¦ vj EG“ do

¡ ¢

A i ¢ j := 0

¡  E : E v ¦ v

GB GB £ i j

¡ ¢

3. for i := 1 to V do A i ¢ i := 1 ¥

¥ G

4. for j := 1 to V do ¥

¥ G

for i := 1 to V do ¥

¥ G if A[i,j] = 1 then

for k := 1 to V ¥

¥ G if A[j,k] = 1 then

B

£

if „vi ¢ vk VG und j k“ then

¡  E : E v ¦ v GB GB £ i k else

A[i,k] := 1

Durch die Abfrage im Körper der Schleife über k werden die Kanten zwischen zwei Knoten der Auswahlmenge bestimmt. Gleichzeitig wird sichergestellt, dass die triviale Erreichbarkeit eines Knotens von sich selbst aus nicht zu einer Schlinge zu ihm selbst führt.

¡ 3

Das zugrundeliegende Warshallverfahren hat einen Aufwand von O V £ , dazu kommt noch ¥

¥ G ¡

die Initialisierung von E mit O E £ . Insgesamt ergibt sich also – bei effizienter Men- ¥

GB ¥ G ¡

3 ¤

genverwaltung – ein Aufwand von O V E £ . Aufgrund der üblicherweise lichten

¥ ¥ ¥

G ¥ G Kontrollflussgraphen fällt der zusätzliche Aufwand allerdings in der Praxis kaum ins Gewicht.

9 2 Verhaltensgraphen und Sichtgraphen

2.1.2 Sichtgraphen

Verhaltensgraphen fokussieren auf die Muster der Ein- und Ausgabeaktivitäten bzw. der ent- B sprechenden Anweisungen in einem gegebenen Kontrollflussgraph. Wählt man die Menge VG nicht anhand der E/A-Anweisungen, sondern als eine beliebige andere Teilmenge von VG, erhält man eine analoge Abstraktion der entsprechenden Aktivitätsstruktur. Sie definiert so eine be- stimmte Sicht auf den Kontrollflussgraphen. Allgemein sei daher von Sichtgraphen gesprochen. Die Berechnung von Sichtgraphen erfolgt analog der Berechnung von Verhaltensgraphen. In dieser Arbeit werden zwei spezielle Sichten als Anwendungsbeispiele betrachtet. Die Verhal- tenssicht wurde bereits mit den Verhaltensgraphen vorgestellt. Im nächsten Kapitel wird gezeigt, wie diese Sicht als Bewertungsbasis für Mengen von Testläufe dienen kann, die herkömmliche strukturbasierte Bewertungen sinnvoll ergänzt. Weiterhin wird die Zuverlässigkeitssicht betrachtet werden, die Analysen hinsichtlich verwen- deter Zuverlässigkeitsarchitekturen ermöglicht und helfen kann, Fehler in deren Entwurf bereits durch statische Analyse zu erkennen und zu beheben.

10 3 Verhaltensgraphen und Testfallmengenbewertung

Die im letzten Kapitel vorgestellte Verhaltenssicht wird implizit in vielen Szenarien eingenom- men. Insbesondere testet man die korrekte Funktion von Systemen oft aus dieser Perspektive: Es interessiert das korrekte Verhalten an den Schnittstellen, nicht die Verfahren, die das Verhal- ten realisieren (insofern sie unter Berücksichtigung aller Rahmenbedingungen geeignet sind, die gewünschte Funktion zu realisieren, was möglicherweise auch das Verhalten bezüglich Zeit und anderer „knapper“ Ressourcen betrifft). In der Regel ist es unmöglich, das korrekte Verhalten von Systemen (ab einer gewissen Kom- plexität) zu garantieren. Techniken wie Beweise mittels Hoare-Logik, symbolischer Programm- ausführung [29] oder Verfeinerungskalkül [6] bieten zwar formale Ansätze zur Sicherstellung der Korrektheit. Üblicherweise wird der mit diesen Ansätzen verbundene Aufwand aber bereits für Systeme mittlerer Grösse – wenigstens beim aktuellen Stand von Theorie und Werkzeug- unterstützung – sehr gross. Dazu kommen relativ hohe methodenspezifische Anforderungen an Wissen und Fähigkeiten des Korrektheitsprüfers, die deren Anwendung fehleranfällig machen. Ein unverzichtbarer Teil der Prüfung eines Systems bleibt daher auf absehbare Zeit das Testen: Mehr oder weniger systematische Probeläufe des Systems mit verschiedenen Eingabedaten, de- ren Resultate beobachtet und bewertet werden. Ein vollständiger Test mit Programmläufen zu allen möglichen Eingabevariationen könnte Gewissheit über die Korrektheit eines untersuchten Systems geben. Vollständige Tests sind jedoch in der Praxis nicht durchführbar, weil die Einga- bewerte üblicherweise riesige Räume aufspannen. Bereits eine einfache int-Eingabevariable führt mit ihrer Breite von 32 Bit zu 232 möglichen Eingaben und damit 232 notwendigen Pro- grammläufen. Durch praktische Gegebenheiten wie Zeit, Geld, verfügbare Arbeitskraft und Re- chenressourcen ist man auf die Auswahl weniger Programmläufe (bezogen auf die Gesamtzahl der möglichen Läufe) beschränkt. Damit durch diese wenigen Läufe Vertrauen zur Korrektheit aufgebaut werden kann, sollen diese möglich gut ausgewählt werden. Was aber ist ein „guter“ Programmlauf ?

11 3 Verhaltensgraphen und Testfallmengenbewertung

Aus Forschung und Praxis der Informatik sind viele Auswahlmethoden bekannt. Methoden der Black-Box-Sicht beruhen in der Regel auf Heuristiken wie Zufallsauswahl, Partitionierung der Eingabemengen, Auswahl von Extremwerten (0/1/min/max), bestimmten Eingabewertkombi- nationen usw. [8]. In der White-Box-Perspektive ist auch die Definition des Systems bekannt. In ihr können Programmläufe anhand der systematischen Abdeckung interner Details, etwa Pro- grammzeilen oder Verzweigungen, ausgewählt oder bewertet werden. Solche rein strukturba- sierten Bewertungen von Programmläufen liefern nicht immer erwartungskonforme Ergebnis- se, d.h., ein hohe Bewertung entspricht nicht immer einem guten, möglichst fehleraufdeckenden Satz von Programmläufen. In diesem Kapitel wird die Bewertungsgrösse Verhaltensdiversität vorgestellt, die auf Verhaltensgraphen basiert und auf diese Weise neben struktureller auch pro- grammspezifische Information einbezieht. Das Kapitel beschreibt weiterhin einen Ansatz zur Modellierung von Fehleraufdeckungswahr- scheinlichkeiten in Programmen, der anschliessend in einer Fallstudie benutzt wird, um den Nutzen der Verhaltensdiversität zu untersuchen.

3.1 Strukturbasierte Kontrollflussmetriken

Um die Qualität von Testdaten (Sammlungen von Testfällen) zu beurteilen, wird die dabei be- nutzte Menge an Testfällen bzw. der zugehörigen Programmläufe oft auf die Erfüllung von Kriterien untersucht, die auf der Quellcodestruktur basieren. Häufig genutzte Bezugsgrössen sind dabei Kontrollflussgraphen und Datenflussstruktur des Systems. Hier sollen einige Bewer- tungsmethoden betrachtet werden, die Bezug auf den Kontrollfluss nehmen. Seien Programme in Form von Modulen betrachtet. Ein Modul ist eine Prozedur oder eine

Funktion mit genau einem Einstiegspunkt. Die Implementation eines Moduls M kann als Kon-

¡

£

trollflussgraph GM VGM ¢ EGM notiert werden, wobei jeder Knoten in VGM eine Anweisung ¥ repräsentiert und EGM ¤ VGM VGM die Möglichkeiten des Kontrolltransfers, d.h. die mög- lichen Nachfolgeanweisungen einer Anweisung während des Programmlaufs beschreibt. Ein Programmlauf lässt sich einem Pfad des Kontrollflussgraphen eindeutig (aber im Allgemeinen nicht eineindeutig) zuordnen. Ein Testvorgang umfasst eine Reihe von Programmläufen (die Testfällen entsprechen). Abdeckungskriterien bestimmen gewünschte Eigenschaften von Pfadmengen in Kontrollfluss- graphen. Einige Beispiele sind

Anweisungsabdeckung (Statement Coverage): Die Pfadmenge enthält jede Anweisung des Programms (jeden Knoten des Kontrollfluss- graphen) in mindestens einem Pfad.

Verzweigungsabdeckung (Branch Coverage): Die Pfadmenge enthält jede Kante des Kontrollflussgraphen in mindestens einem Pfad.

Pfadabdeckung (Path Coverage): Die Pfadmenge entspricht der Menge der möglichen Pfade.

12 3.1 Strukturbasierte Kontrollflussmetriken

n-Längenabdeckung (Length-n-Path Coverage): Die Pfadmenge enthält alle vom Startknoten ausgehenden Pfade mit bis zu n Knoten.

k-Schleifendurchlaufabdeckung (Loop-Count-k-Coverage): Die Pfadmenge enthält alle Pfade durch das Programm mit bis zu k Durchläufen der Schleifen des Programms

Abdeckung linear unabhängiger Pfade (Cyclomatic Number Coverage Criterion): ¤ κ

Die Pfadmenge enthält eine Teilmenge von ν E V Pfaden, die sich

¥ ¥ ¥

G ¥ G G G in genau einer Kante unterscheiden (νG ist die zyklomatische Zahl des Graphen, κG die Anzahl der starken Zusammenhangskomponenten).

Erfüllt eine Pfadmenge die gewünschten Eigenschaften, so sagt man, sie erfüllt das entspre- chende Kriterium. Eine gute Übersicht über Abdeckungskriterien bietet [67]. Möchte man bestimmen, ob eine Pfadmenge ein Kriterium erfüllt oder nicht, müssen verschie- dene Voraussetzungen beachtet werden. Beispielsweise ist die obige Definition der Pfadabde- ckung im Allgemeinen weder erfüll– noch prüfbar, da Programme mit Schleifen Kontrollfluss- graphen mit Kreisen erzeugen. In solchen Graphen gibt es unendlich viele Pfade. Weiterhin gibt es in real existierenden Programmen die Möglichkeit, dass sie nicht ausführbare Anteile (dead code) enthalten. In diesem Fall kann im Allgemeinen keines der o.g. Kriterien erfüllt werden. Daher sind die betrachteten Kriterien stets durch bestimmte einschränkende Annah- men erfüllbar (feasible) zu machen [67]. Speziell die Endlichkeit der untersuchten Bezugsgrös- sen (Pfadmengen etc.) ist herzustellen (finite applicability). Die oben skizzierten Abdeckungen nach n-Länge und k-Schleifendurchlaufzahl sind beispielsweise solche Spezialisierungen der allgemeinen Pfadabdeckung. Abdeckungskriterien stehen in hierarchischer Beziehung, d.h., ein Kriterium kann ein anderes implizieren. So impliziert Pfadabdeckung Verzweigungsabdeckung, letztere wiederum impli- ziert Anweisungsabdeckung. Eine umfassende Betrachtung findet sich in [67]. Viele erfüllbare Abdeckungskriterien erlauben die Definition einer aus ihnen abgeleiteten Metrik. 1 In der Regel ist dies ein Verhältnis zwischen einem von der untersuchten Pfadmenge erreichten Wert einer Zielgrösse zum maximal erreichbaren Wert. Beispielsweise lässt sich ein Grad der Anweisungsabdeckung einer Pfadmenge angeben, indem das Verhältnis der Zahl der in ihren Pfaden enthaltenen Knoten zur Gesamtzahl der Knoten gebildet wird. Metriken für die Abdeckung von Pfaden mit bestimmten Kriterien werden auf ähnliche Weise berechnet, nur ist die Bezugsgrösse hier die Grösse der Pfadmengen. Für manche Kriterien ist die Definiti- on jedoch schwierig, wie etwa bei der Abdeckung linear unabhängiger Pfade, wo es an einer konstanten Bezugsgrösse mangelt.

1Der Begriff „Metrik“ ist hier nicht im streng mathematischen Sinne zu verstehen, sondern als „eine standar- disierte Messgrösse“. Dieser informale Metrikbegriff bzw. dessen englische Entsprechung metric hat sich für Masszahlen in der Softwaretechnik etabliert.

13 3 Verhaltensgraphen und Testfallmengenbewertung

Abdeckungskriterien und -metriken sollen helfen, die Güte einer Menge von Testfällen zu be- werten. Es ist jedoch kaum ein formaler Nachweis möglich, dass sie diese auch gewährleisten. Strukturelle Kriterien sollten daher – trotz ihrer relativ grossen Beliebtheit in Testwerkzeugen – nicht als einziges Qualitätsmerkmal der Testbewertung verwendet werden (eine ausführliche Diskussion zur Stärke struktureller Abdeckungskriterien findet sich in [54]). Als ein Schwachpunkt ist die zu allgemeine Definition der Kriterien zu sehen, die unabhängig von speziellen Eigenschaften, Anweisungsarten etc. ist, sondern sich lediglich auf Strukturele- mente bezieht. Daher soll der Versuch unternommen werden, mit der im nächsten Abschnitt vorgestellten Verhaltensdiversität programmspezifische Elemente in strukturelle Bewertungs- kriterien einfliessen zu lassen und damit eine Verbesserung der Aussagekraft zu erreichen.

3.2 Verhaltensdiversität

Vehaltensgraphen fokussieren auf Ein-/Ausgabeanweisungen, denen beim Black-Box-Testen eine wichtige Rolle zukommt: Sie machen Fehler sichtbar.2 Der Verhaltensgraph eines Systems stellt eine kompakte Sicht der Struktur der Ein- und Aus- gabeanweisungen eines Programms dar. Die Pfade dieses Graphen entsprechen den möglichen Interaktionsmustern des Programms. Eine Menge von Programmläufen entspricht der Abde- ckung eines Teils dieser Interaktionsmuster. Die Zahl dieser Pfade ist, wie die Zahl der mög- lichen Kontrollflusspfade, im Allgemeinen sehr gross. Selbst wenn Schleifenfreiheit angenom- men wird, gibt es bei n Verzweigungen im Programm bis zu 2n mögliche Kontrollflusspfade. Man kann daher davon ausgehen, dass zum Test eines Programms immer nur ein kleiner Teil der möglichen Kontrollflusspfade und damit auch Pfade des Verhaltensgraphen abgedeckt werden kann. Die Verhaltensdiversität gibt das Anzahlverhältnis der durch die Testfälle abgedeckten Interak- tionsmuster (Pfade des Verhaltensgraphen) zu den abgedeckten Kontrollflusspfaden an:

Definition (Verhaltensdiversität)

Sei G ein Kontrollflussgraph und GB der G abstrahierende Verhaltensgraph. Seien G eine

Menge von Pfaden in G und B die Menge der Pfade von GB, die die Pfade aus G abstrahieren.

£

Dann sei die Verhaltensdiversität von G ¢ G , definiert als

¥

B ¥

£

G ¥

¥ G

Wenn eine Menge von Kontrollflusspfaden eine Verhaltensdiversität von 1 aufweist, deckt jeder Pfad ein anderes Interaktionsmuster des Programms ab. Je geringer die Verhaltensdiversität ist, umso kleiner wird die Breite der abgedeckten Interaktionsmuster.

2In diesem Kapitel wird davon ausgegangen, dass die Auswahlmenge der Verhaltensgraphen im Beobachtungs- zeitraum unveränderlich ist und alle Ein-/Ausgabeanweisungen enthält, an denen Fehler sichtbar werden kön- nen.

14 3.3 Fehleraufdeckungsmodellierung

Mit der Verhaltensdiversität gewinnt man Information, inwieweit eine Pfadmenge unterschied- liche Interaktionsmuster abdeckt. Dies lässt einen Zusammenhang der Verhaltensdiversität mit den Fehleraufdeckungsfähigkeiten der untersuchten Pfade vermuten. Wie dieser Zusammen- hang ausgeprägt ist, soll in den folgenden Abschnitten untersucht werden.

3.3 Fehleraufdeckungsmodellierung

Die Verhaltensdiversität gibt einen Hinweis auf die Variation der Interaktionsmuster inner- halb einer Pfadmenge. Allerdings ist damit noch nichts über den Zusammenhang mit der Fehleraufdeckungsfähigkeit gesagt. Das primäre Ziel eines Testvorgangs ist die Aufdeckung von Fehlern, nicht der Besuch möglichst vieler potenziell fehleraufdeckender Stellen (Ausga- beanweisungen) in möglichst vielen Varianten. Nicht jede potenziell fehleraufdeckende Stelle wird unter den gleichen Bedingungen auch tatsächlich fehleraufdeckend, und es liegt nahe, dass manche Stellen „weniger fehleraufdeckend“ oder „fehleraufdeckender“ als andere sind. Daher ist der Wert des neuen Kriteriums a priori nicht klar, da z.B. eine Menge von Testfällen auch bei maximaler Verhaltensdiversität (von 1) die fehlerträchtigen Interaktionsmuster nicht zwingend abdecken muss. Im Rahmen dieser Arbeit wurde daher der Nutzen der Verhaltensdiversität experimentell unter- sucht. Im Experiment wurde anhand einer Auswahl von Kontrollflussgraphen und der Analyse von Pfadmengen in ihnen untersucht, ob man bei einer hohen Verhaltensdiversität auch eine gute Fehleraufdeckungsfähigkeit erwarten kann. Zur Vorbereitung eines solchen Experimentes sind folgende Fragestellungen zu klären:

1. Welche Programme bzw. Kontrollflussgraphen werden für das Experiment herangezo- gen ?

2. Welche Pfade durch die Kontrollflussgraphen werden benutzt und wie werden sie er- zeugt ?

3. Wie modelliert man die Fehleraufdeckungsfähigkeiten ?

Die skizzierten Fragestellungen lassen sich mit Sammlungen existierender Programme aus verschiedenen Gründen nur unbefriedigend behandeln [67]. Gegebene Programmsammlungen können zu klein oder zu speziell sein, die Testfälle nicht adäquat, die realisierten Fehler entwe- der unbekannt oder nicht repräsentativ: “It is not unfair to say that a typical testing experiment uses a small set of toy programs, with uncontrolled human generation of the test data“. (D. Hamlet, zitiert nach [67])

15 3 Verhaltensgraphen und Testfallmengenbewertung

Es stellt sich, wie bei vielen Leistungsbewertungen, die Frage nach einer Menge möglichst „guter“ Referenzdaten (Benchmark-Problem). Zusätzlich ist für die Durchführung der Experi- mente mit echten Programmen ein grosser Aufwand zu betreiben. Die zu prüfenden Programme müssen in einer kontrollierten Umgebung ausgeführt werden, es sind die zu den Berechnungs- pfaden gehörigen Stimuli und erwarteten Reaktionen des Systems zu bestimmen. Daher ist die Benutzung von einfacher zu standardisierenden und leichter handhabbaren Programmmodellen wünschenswert, die die für eine spezielle Untersuchung interessanten Aspekte von Programmen realitätsnah abbilden. Bei der durchgeführten Untersuchung sollten Kenngrössen von Programmen ermittelt werden, die im wesentlichen durch Analyse derer Kontrollflussgraphen zu erschliessen sind. Kontroll- flussgraphen, die denen echter Programme strukturell nachempfunden sind, lassen sich leicht und in grosser Variation künstlich erzeugen. Dabei können gewünschte strukturelle Eigenschaf- ten, wie etwa die Verteilung verschiedener Anweisungstypen, exakt realisiert werden. Daher wurde statt mit echten Programmen mit künstlich erzeugten Kontrollflussgraphen gearbeitet. Auf diese Weise konnte eine grosse Variation von Kontrollflussstrukturen der Analyse zuge- führt werden. Die untersuchten Pfadmengen wurden zufällig ausgewählt. Möchte man in Kontrollflussgraphen auch Fehleraufdeckungsfähigkeiten der zugrundeliegen- den Programme modellieren, sind einige Betrachtungen über den Entstehensprozess von Feh- lern und dessen Auswirkungen auf die Fehleraufdeckungsfähigkeiten von Anweisungen und Pfaden notwendig. Ein entsprechender Ansatz zur Modellierung von Fehleraufdeckungsfähig- keiten in Kontrollflussgraphen wird im Folgenden vorgestellt.

3.3.1 Fehlerentstehung und Fehleraufdeckung

Im Validierungsexperiment war nicht die Natur von Fehlern zu betrachten, sondern deren Aufdeckung. Daher wurde von konkreten Fehlern abstrahiert und von Fehlern beliebiger Art ausgegangen. Die einzige Eigenschaft, die von einem Fehler angenommen wurde, ist, dass er sich letztlich gegenüber einem Beobachter manifestiert. Nicht die Fehler wurden modelliert, sondern die Fehleraufdeckung. Ausgehend vom Black-Box-Modell lässt sich feststellen, dass es zwar viele mögliche Ursachen der Fehlerentstehung gibt und diese ihren Ursprung daher bei der Abarbeitung der unterschied- lichsten Anweisungen haben können. Die Manifestation, das Sichtbarwerden von Fehlern, fin- det jedoch stets an den Schnittstellen des Systems statt. Ein Fehler bleibt so lange unerkannt, bis er sich – in Form eines falschen Ausgabewertes, des Verzögerns oder Ausbleibens einer Systemreaktion (Systemabsturz, Blockierung) etc. – an einer Schnittstelle manifestiert. Es sind also letztlich die entsprechenden Zugriffsanweisungen, die den Fehler aufdecken, auch wenn er an einer anderen Stelle des Programms entstanden ist. Daran angelehnt wird in dieser Un- tersuchung statt eines Fehlermodells ein Fehleraufdeckungsmodell angenommen, in dem jeder Anweisung eines Programms, die auf eine Schnittstelle zugreift (Ausgabestelle), eine individu- elle Fehleraufdeckungshäufigkeit zugeordnet wird.

16 3.3 Fehleraufdeckungsmodellierung

Im Bereich der Softwaretechnik sind Fehlerentstehungsmodelle entwickelt worden. Der Be- griff der Fehleraufdeckungshäufigkeit wird im folgenden aus solchen Modellen abgeleitet. Die verwendeten Konzepte und Terminologie basieren im wesentlichen auf dem RELAY-Modell (Staffellauf-Modell) [60]. Eine Grundannahme vieler Fehlerenstehungsmodelle, von der auch hier ausgegangen wird, ist, dass bereits eine „beinahe korrekte“ Implementation mit wenigen Restfehlern vorliegt („competent programmer hypothesis“). Das auf Fehler zu untersuchende potenziell fehlerhaf-

te Programm P soll also einem gedachten fehlerfreien Programm P bereits sehr ähnlich sein (dies ist durch nicht weiter betrachtete Massnahmen abzusichern). Insbesondere wird, wie im

RELAY-Modell, angenommen, dass P und P einen strukturell identischen Kontrollfluss ha- 3 ben. Das heisst, die Kontrollflussgraphen von P und P unterscheiden sich höchstens durch die Knotenbeschriftungen, also durch einzelne Anweisungen innerhalb der gleichen Kontrollfluss- struktur. Ein Fehler könnte beispielsweise durch einen falsch gewählten Befehl, eine falsche Variable in einem Ausdruck oder einen falschen Operator zum Ausdruck kommen. Die Kno-

ten in P, deren Beschriftung sich vom entsprechenden Knoten in P unterscheidet, heissen die Fehlerstellen (faults) von P. In den obigen Ausführungen werden nur Entwurfsfehler berücksichtigt. Eine Ausdehnung auf andere (permanente) Fehlerarten ist denkbar, wird aber hier nicht weiter betrachtet. Programmzustände beschreiben die Belegungen aller Programmvariablen zu einem gegebenen Zeitpunkt. Ein Programmlauf ist eine Folge von Kontrollflussgraph– Knoten/Programmzustand–Paaren, die das Ablaufen eines (Teil-)Programms beschreiben. Die Abdeckung von Pfaden in Kontrollflussgraphen kann in der Regel durch verschiedene Programmläufe erfolgen. Die Menge der Kontrollflusspfade partitioniert so die Menge der möglichen Programmläufe in Äquivalenzklassen. Eine Eingabefolge ist eine Folge von Werten, die einem Programm eingegeben werden. Feh- lerzustände sind generell als Programmzustände von P definiert, die von den entsprechenden

Programmzuständen von P bei gleicher Eingabefolge abweichen.

Schema der Fehleraufdeckung

Der Lebenszyklus von Fehlerzuständen kann in vier Phasen eingeteilt werden:

Zunächst entsteht ein initialer Fehler (initial potential failure), wenn innerhalb einer Feh- lerstelle zum ersten Mal eine Abweichung vom Verhalten des korrekten Programms ent- steht. Dies kann z.B. die Ausführung eines falschen Befehls oder die Auswertung eines Ausdrucks sein, der eine falsche Variable enthält.

3Dies geschieht im wesentlichen, um die Definition von Fehlerstellen zu fundieren. Wählt man eine andere Defi- nition von Fehlerstellen, etwa anhand eines Fehlermodells, gelten die nachfolgenden Ausführungen und Defi- nitionen weiterhin.

17 3 Verhaltensgraphen und Testfallmengenbewertung

Ein initialer Fehler führt nicht unbedingt zu einem Fehlerzustand, weil beispielsweise die Auswertung eines Ausdrucks ohne Zuweisung des Ergebnisses an eine Variable den Pro- grammzustand nicht beeinflusst oder Teile des falschen Ausdrucks den Fehler maskieren können.

Ein initialer Fehler wird zum Fehlerzustand oder potenziellen Fehler (state [potential] failure, error), wenn innerhalb der Fehlerstelle die Variablen des Programms beeinflusst werden, wenn also beispielsweise die Auswertung eines fehler- haften Ausdrucks zu einem fehlerhaften Wert führt und dieser einer Variablen zugewiesen wird.

Der Fehlerzustand wird dann durch das Programm propagiert , indem die falsch beleg- ten Variablen zu weiteren Berechnungen von Variablen oder Verzweigungsbedingungen benutzt werden.

Der Fehlerzustand wird letztlich an eine Ausgabestelle propagiert. Diese kann den Feh- lerzustand aufdecken ([external] failure).

Ein initialer Fehler oder ein Fehlerzustand muss nicht unbedingt aufgedeckt werden. Auf dem Propagierungspfad können Fehlerzustände maskiert werden. Dies kann viele denkbare Ursa- chen haben. Beispielsweise könnte der Unterschied der korrekten und falschen Variablenbe- legungen so gering sein, dass er die Ergebnisse weiterer Berechnungen nur unterhalb die Ge- nauigkeitsgrenze der Zahlendarstellung beeinflusst oder eine andere Fehlerstelle könnte den Fehlerzustand per Zufall aufheben. 4 Das „Leben“ eines Fehlerzustands ist mit dem Erreichen einer Ausgabestelle nicht notwendi- gerweise beendet, er kann auch weiterhin durch die nachfolgenden Anweisungen propagiert werden (insofern er nicht eine Termination des Programms verursacht). Wie schon angespro- chen, können ausserdem mehrere initiale Fehler interagieren und Fehlerzustände entsprechend verändern oder sogar in korrekte Programmzustände zurückverwandeln. Dies stört beim Testen häufig die Fehlerauffindung: “Coincidental correctness [...] is the bane of testing“ [60]. Bei der Propagierung eines Fehlerzustandes von der Fehlerstelle bis zu einer Ausgabestelle ist er also modifizierenden Einflüssen ausgesetzt, die neben seiner Ausprägung auch die Umstände seiner Aufdeckung beeinflussen. Ob ein Fehlerzustand aufgedeckt wird, hängt wesentlich von vier Einflussgrössen ab: Den Anweisungen des Programms, Art und Ort der Fehlerstelle und den Eingabedaten.

4Fehlertoleranzstrategien [58] versuchen, diese Beeinflussungsmöglichkeit aktiv zu nutzen.

18 3.3 Fehleraufdeckungsmodellierung

3.3.2 Fehleraufdeckungshäufigkeiten und -wahrscheinlichkeiten

Nicht alle Programmläufe zwischen einer Fehlerstelle und einer Ausgabestelle führen zur Auf- deckung von Fehlern. Sei f eine Fehlerstelle, a eine Ausgabestelle in einem Programm P. Die möglichen Programmläufe vom Programmbeginn über f und a werden durch die möglichen Programmzustände vor der Ausführung von f und die möglichen Anweisungsfolgen zwischen f und a bestimmt. Ein Teil der möglichen Programmzustände vor f führt - je nach Art der Feh- lerstelle - zu initialen Fehlern und eventuell zu Fehlerzuständen. Entsteht ein Fehlerzustand, besteht auf jedem der möglichen Programmläufe bis zu a die Möglichkeit, dass er bei seiner Propagierung beeinflusst und möglicherweise in einen korrekten Zustand überführt oder bei der Ausgabe ausmaskiert wird. Die Art der Beeinflussung hängt von der konkreten Anweisungsfol- ge ab. Man kann im Allgemeinen erwarten, dass ein Teil der möglichen Programmläufe über f und a bei der Ausführung von f einen Fehlerzustand erzeugt, ihn bis zu a propagiert und dort aufdeckt (fehleraufdeckender Programmlauf). „Aufdecken“ bedeutet, dass ein Beobachter den Fehler – auf irgendeine, hier nicht weiter betrachtete Art – bemerken kann. Der andere Teil der möglichen Programmläufe erzeugt entweder keinen Fehlerzustand in f oder behebt ihn auf dem Weg zu a wieder (nichtfehleraufdeckender Programmlauf). So lässt sich zwischen allen möglichen Fehlerstelle/Ausgabestelle-Paaren ein Verhältnis der Zahl der möglichen fehleraufdeckenden Programmläufe zur Zahl der möglichen Programmläu- fe angeben. Bemerkung zu den nachfolgenden Definitionen Will man das beschriebene Verhältnis mathematisch definieren, muss beachtet werden, dass in Programmen mit Endlosschleifen potenziell unendlich viele unterschiedliche Programmläufe über f und a möglich sind. Bei einer allgemeinen Beschreibung wäre daher eine Grenzwert- bildung mit einzubeziehen und alle Aussagen unter dem Vorbehalt der Konvergenz der gebil- deten Verhältnisse zu sehen. Hier sollen daher nur Szenarien betrachtet werden, in denen die Programmlaufmengen endlich sind. Von den Programmen soll entweder angenommen werden, dass sie sicher für jede Eingabe terminieren oder die Menge der betrachteten Läufe ist, z.B. über eine maximale Schleifendurchlaufzahl, geeignet einzugrenzen. Exakterweise müsste also bei den nachfolgenden Definitionen stets von Fehleraufdeckungshäufigkeiten unter Beschrän- kung auf eine endliche Zahl von Programmläufen gesprochen werden, wobei die Beschränkung auf einem „beliebig, aber für die Dauer der Betrachtung fest“ ausgewählten Kriterium beruht. Programme mit beabsichtigen Endlosschleifen – beispielsweise reaktive Systeme – werden hier nicht betrachtet, genausowenig wie Systeme mit veränderlichen Kontrollflussgraphen, wie etwa selbstmodifizierende Programme. Intuitiv ist die Fehleraufdeckungshäufigkeit einer Anweisung mit dem Anteil der sie berüh- renden möglichen Programmläufe gleichzusetzen, auf dem sie selbst (mindestens) einen Fehler aufdeckt. Sie gibt die relativen Häufigkeiten von fehleraufdeckenden Programmläufen über eine Anweisung wieder und kann so als die Wahrscheinlichkeit aufgefasst werden, mit der ein be- liebig ausgewählter Programmlauf, der die Anweisung berührt, fehleraufdeckend ist. Zunächst soll die spezielle Fehleraufdeckungshäufigkeit einer Ausgabestelle bezüglich einer Fehlerstelle betrachtet werden:

19 3 Verhaltensgraphen und Testfallmengenbewertung

Definition (Spezielle Fehleraufdeckungshäufigkeit)

Sei f eine Fehlerstelle, a eine Ausgabestelle eines fehlerhaften Programs P und a ¡ f die Menge

der möglichen Programmläufe vom Start über zunächst f und dann a bis zum Programmende.

£¢

¡ Sei weiterhin ¤ a f die Menge der Programmläufe, die bei Ausführung von a einen durch a ¡ f

f induzierten Fehler aufdecken. ¤

Die (spezielle) Fehleraufdeckungshäufigkeit a ¡ f von a bezüglich f sei der Anteil der mögli-

chen Programmläufe über f und a, auf dem a einen durch f erzeugten Fehlerzustand aufdeckt:

¥¢

¥ ¥

a ¡ f

¤

a ¡ f

¡ ¥

¥ a f

Zur Berechnung der allgemeinen Fehleraufdeckungshäufigkeit einer Ausgabestelle ist die Men- ge der in sie eingehenden fehleraufdeckenden Programmläufe der Menge der in sie eingehenden möglichen Programmläufe gegenüberzustellen:

Definition (Allgemeine Fehleraufdeckungshäufigkeit)

¡

¢  Seien a eine Ausgabestelle des fehlerhaften Programms P, und FP f1 ¢ fn die Menge der Fehlerstellen von P.

Die (allgemeine) Fehleraufdeckungshäufigkeit ¤ a von a ist der Anteil der möglichen Pro-

grammläufe über a, auf dem a einen durch eine beliebige Teilmenge von FP induzierten Fehler-

¢ zustand aufdeckt. Sei a die Menge der möglichen Programmläufe über a und a , die Menge

der fehleraufdeckenden Programmläufe von P über a, definiert als

¢

£¢

§¦

a a ¡ f

f ¨ F

Dann berechnet sich ¤ a folgendermassen:

¢ ¥

¥ a

¤ a ¥

¥ a

Bei den nachfolgenden Untersuchungen werden die im Programm vorhandenen Fehler nicht bestimmt. Weder Anzahl, Fehlerstellen noch Fehlerarten sind bekannt. Es wird lediglich ihr Vorhandensein angenommen, so dass es zu allgemeinen Fehleraufdeckungshäufigkeiten grös- ser als 0 für die Ausgabeanweisungen des Programms kommt. Dies wird durch ein Fehlerauf- deckungsmodell modelliert:

20 3.3 Fehleraufdeckungsmodellierung

Definition (Fehleraufdeckungsmodell)

¡

£

Ein Fehleraufdeckungsmodell zu einem Kontrollflussgraphen G VG ¢ EG ist eine totale

¢ ϕ ¡ ¢ Funktion G : VG ¦ 0 1 , die jeder Anweisung des Kontrollflussgraphen eine allgemeine Fehleraufdeckungshäufigkeit zuordnet.

ϕ ¡ ¡ Eine Anweisung v mit G v £ 0 wird potenziell fehleraufdeckend genannt. In der (in den vor- liegenden Ausführungen angenommenen) Sichtweise des Black-Box-Modells können nur Aus- gabeanweisungen potenziell fehleraufdeckend sein. Ein Fehleraufdeckungsmodell modelliert nur Eigenschaften von Fehlern hinsichtlich ihrer Aufdeckung an bestimmten Punkten des Pro- gramms; Fehlerarten beschreibt es jedoch weder explizit noch implizit. Die Definition der Fehleraufdeckungshäufigkeit lässt sich auch auf Pfade erweitern. Die Fehler- aufdeckungshäufigkeit von Pfaden wird als Verhältnis der entsprechenden fehleraufdeckenden Programmläufe zu den möglichen Programmläufen, die der Pfad repräsentiert, angegeben:

Definition (Fehleraufdeckungshäufigkeit von Pfaden)

Die Fehleraufdeckungshäufigkeit ¤ p eines Pfades p vom Initialknoten bis zu einem Endknoten in einem Kontrollflussgraphen G ist die Häufigkeit, mit der ein Programmlauf, der in G dem

Pfad p entspricht, mindestens einen Fehler aufdeckt.

¢ ¡ ¢  ¢ ¡

Seien a1 ¢ an die Ausgabestellen, die in p enthalten sind sowie p a1 p an und

¢ ¢

¡ ¢ ¢ ¡ ¤

¤ die Mengen der möglichen bzw. fehleraufdeckenden Pro- ¡

p ¡ a1 p a1 p an p an

¢ grammläufe durch a1 ¢ an, die p abdecken.

Dann berechnet sich ¤ p wie folgt:

¢

n ¢

¡

£ ¥

¥ i 1 p ai

¢

¤ p n

¡

£ ¥

¥ i 1 p ai

Fehleraufdeckungshäufigkeiten sind schwierig zu bestimmen, obwohl sie für jedes potenziell fehlerhafte Programm bereits zum Zeitpunkt des Laufs unveränderlich feststehen. Eine explizite Berechnung entspricht einem Test des untersuchten Programms unter konstanten Fehlerbedin- gungen über den Raum aller möglichen Eingabewerte und ist aus praktischen Gründen in der Regel nicht durchführbar. Andere Möglichkeiten ergeben sich aus formalen Ansätzen wie der symbolischen Programmausführung [29] unter Annahme eines Fehlermodells. Diese Gedan- ken sollen aber hier nicht vertieft werden, da im Rahmen des Validierungsexperiments keine Fehleraufdeckungshäufigkeiten aus konkreten Programmen berechnet werden müssen. Auch bei gegebenem Fehleraufdeckungsmodell lassen sich zu Pfaden ohne Betrachtung des

konkreten Programms keine Fehleraufdeckungshäufigkeiten bestimmen. Die Grössen der zur

¢ ¢ n n ¢

Berechnung zu bestimmenden Mengen ¡ und hängen unmittelbar von der

¡ £ i £ 1 p ai i 1 p ai Programmsemantik sowie den möglichen Ausführungskontexten und Fehlern ab.

21 3 Verhaltensgraphen und Testfallmengenbewertung

Sind die Fehleraufdeckungshäufigkeiten der Ausgabestellen eines Programms bekannt, lässt sich jedoch die untere Schranke der Wahrscheinlichkeit dafür angeben, dass ein Pfad einen Fehler an einem der potenziell fehleraufdeckenden Knoten entdeckt. Es sei ein Programmlauf betrachtet, der potenziell fehleraufdeckende Knoten berührt. In jedem dieser Knoten deckt der Programmlauf mit der als Wahrscheinlichkeit interpretierten allgemei- nen Fehleraufdeckungshäufigkeit des Knotens einen Fehler auf. Diese Fehleraufdeckungshäu- figkeiten sind unabhängig vom Verlauf des Programmlaufs. Ihr Maximum kann daher durch den Pfad nicht unterschritten werden.

Definition (Untere Schranke der Fehleraufdeckungswahrscheinlichkeiten von Pfaden) Die untere Schranke der Wahrscheinlichkeit eines Programmlaufs, der einen Pfad p in einem Kontrollflussgraphen G mit Fehleraufdeckungsmodell ϕG abdeckt, einen Fehler aufzudecken min (kurz: die untere Schranke der Fehleraufdeckungswahrscheinlichkeit von p), ¤ p , ist die

maximale Fehleraufdeckungshäufigkeit, die einem Knoten aus p zugeordnet ist.5

¢ Formal: Seien a1 ¢ an die potenziell fehleraufdeckenden Knoten auf p. Dann gilt

min ¡

¡ ¡ ¤ ϕ

£ ¢ ¢   max a £ a a a

p ¥ 1 n

Die untere Schranke der Fehleraufdeckungswahrscheinlichkeit eines Programmlaufs, der einen Pfad aus einer bestimmten Pfadmenge abdeckt, lässt sich aus den unteren Schranken der Feh- leraufdeckungswahrscheinlichkeiten der einzelnen Pfade bestimmen:

Definition

(Untere Schranke der Fehleraufdeckungswahrscheinlichkeit von Pfadmengen)

¡

 ¢  Sei p1 ¢ pn eine Menge von Pfaden eines Kontrollflussgraphen G mit den jeweiligen

min min

¤ ¤

 ¢

unteren Schranken der Fehleraufdeckungswahrscheinlichkeit p1 ¢ pn .

¢ ¢  ¢ Die Pfade p1 ¢ pn repräsentieren n Mengen von Programmläufen 1 n. Diese Mengen

sind paarweise disjunkt.

 ¢

Szenario: Ein Tester wähle zufällig Programmläufe aus den Mengen 1 ¢ n aus. Dabei sei angenommen, dass er alle i in gleichem Masse berücksichtigt, d.h. die Auswahl auf der Ebene

der Pfade gleichverteilt erfolgt.

¡

£ ¢ 

Wi ¢ i 1 n seien die (disjunkten) Ereignisse, dass der Tester einen Programmlauf aus Pfad

¡

£ ¢ 

i auswählt und Ei ¢ i 1 n die (ebenfalls disjunkten) Ereignisse, dass durch einen Pro- grammlauf aus i ein Fehler aufgedeckt wird. Das Ereignis der Fehleraufdeckung F durch einen Programmlauf entspricht der oder–Verknüpfung der Ei:

5Vgl. Urnenmodell der Stochastik, z.B. in [49].

22

3.4 Validierungsexperiment

F E1 En

Nach dem Satz der vollständigen Wahrscheinlichkeit berechnet sich die untere Schranke der Fehleraufdeckungswahrscheinlichkeit eines Programmlaufs, der einen Pfad aus abdeckt

min £ (kurz: die untere Schranke der Fehleraufdeckungswahrscheinlichkeit von ), ¤ , folgen- dermassen:

n n n

¡ ¡

min ¡ min 1 1 min

£

¤ ¤ ¤

£ ∑ P F Wi £ P Wi ∑ ∑

pi ¡ n n pi

£ £

i £ 1 i 1 i 1

3.4 Validierungsexperiment

Das vorgestellte Konzept der Fehleraufdeckungsmodellierung wurde in einem Validierungsex- periment zur Untersuchung der Verhaltensdiversität benutzt. Dort wurden die unteren Schran- ken der Fehleraufdeckungswahrscheinlichkeit ausgewählter Pfadmengen den für sie berechne- ten Werten der Verhaltensdiversität gegenübergestellt. Zur Generierung einer breit variierenden Menge von Kontrollflussgraphen wurde dabei das Werkzeug proggen benutzt. Die Ergebnisse solcher Untersuchungen lassen nur dann einen Rückschluss auf die Realität zu, wenn die künstlichen Kontrollflussgraphen denen echter Programme ähneln. Um die von proggen erzeugten Graphen entsprechend zu gestalten, mussten daher realistische Generie- rungsparameter bestimmt werden. Diese wurden in einer Vorstudie zum Validierungsexperi- ment gewonnen, in der 101 Programme unterschiedlichster Anwendungsbereiche auf struktu- relle Kenngrössen untersucht wurden. Im Folgenden werden proggen, die Vorstudie und das Experiment besprochen. Eine Präsentati- on der Ergebnisse schliesst den Abschnitt ab.

3.4.1 Das Werkzeug proggen

Mit proggen wurde ein Werkzeug entwickelt, das die Generierung beliebig grosser Kontroll- flussgraphen ermöglicht und gleichzeitig eine Umgebung für die Auswahl und Untersuchung von Pfaden in den erzeugten Graphen bietet. Die Generierung kann mittels diverser Parame- ter exakt gesteuert werden, wobei neben der Gesamtzahl der zu erzeugenden Anweisungen die genaue Aufteilung auf verschiedene (Pseudo–)Anweisungstypen einstellbar ist.

23 3 Verhaltensgraphen und Testfallmengenbewertung

if

B1 B1 B2 while

B2 B

Sequenz Alternative Iteration

Abbildung 3.1: Strukturelemente in proggen-Kontrollflussgraphen proggen versieht die Graphen mit zufallsbasiert generierten Fehleraufdeckungsmodellen, wählt zufallsgesteuert eine beliebig grosse Menge von Pfaden durch die Graphen und ermittelt um- fangreiche strukturelle Kenndaten für die Pfadmenge. Die erzeugten Kontrollflussgraphen, Mo- delle und Pfade sind anhand der Parameter reproduzierbar, so dass alle Untersuchungen und Ergebnisse beliebig oft nachvollzogen werden können.

Programmmodell

Das Programmmodell, das den Kontrollflussgraphen von proggen zugrundeliegt, entspricht Pro- zeduren oder Funktionen einer goto-freien Programmiersprache. Die zur Generierung verwen- deten Kontrollflusselemente werden schematisch in Abbildung 3.1 wiedergegeben. Zunächst gibt es die grundlegende Struktur des Aneinanderfügens (Sequenz), in der die Anweisungsblö- cke B1 und B2 zu aufeinanderfolgenden Codeteilen geordnet werden. Bei if-Verzweigungen wird der Kontrollfluss in zwei alternative Blöcke B1 und B2 geteilt. In while-Schleifen schliesslich erhält der Kontrollfluss eine optionale Schleife durch den Block B. Zusätzlich zu if und while können proggen-Kontrollflussgraphen Anweisungen enthalten, die keine unmittelbare Auswirkung auf den Kontrollfluss haben. Es gibt folgende Anweisungstypen:

if

while

berechnende Anweisungen ohne direkte Effekte auf den Kontrollfluss

nichtfehleraufdeckende Ein-/Ausgabeanweisungen

potenziell fehleraufdeckende Ein-/Ausgabeanweisungen

24 3.4 Validierungsexperiment

Die berechnenden Anweisungen haben keine Semantik und dienen lediglich dazu, die Kontroll- flussstruktur existierender Programme nachzubilden, die ebenfalls nichtverzweigende Elemente enthält. Die drei Konstruktionsprinzipien Konkatenation, Alternative und Wiederholung entsprechen denen Turing-mächtiger Programmiersprachen (siehe Programmiersprachen WHILE bzw. GO- TO der theoretischen Informatik [62]). Daher kann angenommen werden, dass beliebige Be- rechnungen mit einem auf diesen Prinzipien basierenden Kontrollfluss realisierbar sind. Natür- lich enthalten Programme in Programmiersprachen wie C gelegentlich auch goto–Befehle und Mehrfachverzweigungen wie case–Anweisungen. Während die künstliche Erzeugung auch solcher Konstrukte in Kontrollflussgraphen unproblematisch ist, ist die Pfadzählung (eine Funk- tion von proggen) in den entsprechenden Kontrollflussgraphen wesentlich aufwändiger.6 Um den Simulationsaufwand zu reduzieren, wurde daher das „goto– und case–freie“ Modell gewählt, welches effektiv von sehr vielen Programmen eingehalten wird (wenn man case- Anweisungen als if-Kaskaden auffasst). Jeder proggen-Lauf wird mit den gewünschten Anzahlen der jeweiligen Anweisungstypen para- metrisiert. Das Werkzeug erzeugt einen Kontrollflussgraph, der in der Verteilung der Anweisun- gen exakt den Parametern entspricht. Die Abfolge der Anweisungen wird dabei zufallsbasiert festgelegt. Zum Kontrollflussgraph wird der Verhaltensgraph bestimmt. Abbildung 3.2 zeigt einen von proggen generierten Kontrollflussgraphen. Abbildung 3.3 gibt das entsprechende Pseudoprogramm wieder und Abbildung 3.4 den Verhaltensgraphen. 7 Zu jedem generierten Kontrollflussgraph wird ein Fehleraufdeckungsmodell erzeugt. Jeder po- tenziell fehleraufdeckenden E/A-Anweisung wird dabei eine Fehleraufdeckungshäufigkeit zu- geordnet, wobei diese zufällig aus einem Intervall zwischen 0 und einer Obergrenze bestimmt wird. Die Obergrenze ist ein zwischen 0 und 1 frei wählbarer Parameter der Generierung, die Auswahl erfolgt gleichverteilt. Im Beispiel sind zwei potenziell fehleraufdeckende Anweisun- gen enthalten (O58 und O59). Sie sind im Listing in Abbildung 3.3 mit ihren Fehleraufde- ckungshäufigkeiten kommentiert.

Erzeugung von Pfaden proggen bietet die Möglichkeit, aus den generierten Programmen eine beliebig grosse Menge von Pfaden zu bestimmen (bis zur vollständigen Pfadmenge). Die Auswahl erfolgt dabei zufalls- gesteuert und erzeugt stets einen Pfad der vom Anfangs- zum Endknoten des entsprechenden Kontrollflussgraphen verläuft. Abbildung 3.5 zeigt einen aus dem Beispielgraphen ausgewähl- ten Pfad (fett markiert).

6Die proggen–Strukturelemente entsprechen den Konstruktionsprinzipien (einer eingeschränkten Klasse) regulä- rer Ausdrücke. Die durch einen regulären Ausdruck erzeugte Zahl von Worten lässt sich leicht anhand seines Syntaxbaumes ermitteln (wenn man die Kleene-Sterne im Ausdruck durch eine maximale Wiederholungszahl ersetzt). Dagegen müsste ein unbeschränkter Graph zunächst als Automat aufgefasst und der entsprechende reguläre Ausdruck gebildet werden, was aber für die Pfadzählung einen zusätzlichen Aufwandsfaktor von n3 (bei n Knoten im Graphen) bedeutet. 7Die Knoten der Graphen sind in den Abbildungen mit ihren internen proggen–internen Bezeichnern markiert. Diese Bezeichner spielen in der vorliegenden Betrachtung keine Rolle.

25 3 Verhaltensgraphen und Testfallmengenbewertung

x1

x3

x5

x7

o9

x11

w14

x15 x17

x19

w20

x21 x33

x23 x35

i25 x37

x27 x39

x29 x41

x31 x43

i45

x47

x49

x51

x53

b55

x56

O58 O59

x61

Abbildung 3.2: Von proggen erzeugter Kontrollflussgraph

26 3.4 Validierungsexperiment

operation; operation; operation; operation; output; operation; while () { operation; } operation; operation; while () { operation; operation; input; operation; operation; operation; } operation; operation; operation; operation; operation; operation; input; operation; operation; operation; operation; if () { operation; output; // revealing error with prob 0.000482; } else { output; // revealing error with prob 0.000216; } operation;

Parameter der Programmgenerierung: 1 if-Anweisung 2 while-Anweisungen 25 berechnende Anweisungen 3 nicht potenziell fehleraufdeckende E/A-Anweisungen 2 potenziell fehleraufdeckende E/A-Anweisungen Maximale Schachtelungstiefe 1 Obergrenze der Fehleraufdeckungshäufigkeit 0,001

Abbildung 3.3: Von proggen generiertes Pseudoprogramm

27 3 Verhaltensgraphen und Testfallmengenbewertung

o9

i25

i45

O58 O59

Abbildung 3.4: Von proggen erzeugter Verhaltensgraph

Dabei wird sichergestellt, dass sich die Pfade stets unterscheiden, d.h., es gibt keine Duplikate in der Pfadmenge. Zu jedem Pfad wird zusätzlich der ihn abstrahierende Pfad im Verhaltensgraph bestimmt (siehe ebenfalls Abbildung 3.5).

Ermittelte Kenndaten

Die generierten Kontrollflussgraphen und Pfadmengen können hinsichtlich verschiedener struk- tureller Kenngrössen analysiert werden. Zu jedem Kontrollflussgraphen wird die Anzahl der möglichen Pfade bestimmt. 8 Zu jeder generierten Pfadmenge können spezifische Kenngrös- sen wie Zustands-, Verzweigungs- und Pfadabdeckung im Kontrollflussgraph, Abdeckung der min potenziell fehleraufdeckenden Zustände sowie Verhaltensdiversität und ¤ bestimmt werden. In der folgend beschriebenen Untersuchung wurde proggen benutzt, um Werte für Verzwei- min gungsabdeckung, Verhaltensdiversität und ¤ zu berechnen.

3.4.2 Das Experiment

Im Experiment wurde anhand von 76.800 durch proggen generierten Kontrollflussgraph/Fehleraufdeckungsmodell-Kombinationen die Korrelation zwischen Ver- haltensdiversität und unterer Schranke der Fehleraufdeckungswahrscheinlichkeit untersucht. Zusätzlich wurde – zu Vergleichszwecken – die Korrelation zwischen Verzweigungsabdeckung und unterer Schranke der Fehleraufdeckungswahrscheinlichkeit betrachtet.

Zunächst wurden mit Hilfe von fünf Merkmalen 1.920 Parameterkombinationen für die Grapherzeugung ausgewählt. Diese Parametersätze wurden u.a. anhand einer Vorstudie an 101 Programmen ausgewählt. Die Strukturparameter wurden um einen sechsten Pa- rameter ergänzt, in dem die Häufigkeitsobergrenze für die Generierung des Fehleraufde- ckungsmodells vierfach variiert wurden. Insgesamt entstanden so 7.680 Parametersätze.

8Da es durch jedes Programm, das Schleifen enthält, unendlich viele Pfade gibt, muss man die Pfadauswahl geeignet einschränken. In proggen wird die Pfadzahl nach dem Prinzip „Loop-count-1“ („C2-Pfade“) bestimmt, d.h. es werden nur Pfade berücksichtigt, die die im Programm vorhandenen while-Körper null- oder einmal durchlaufen. Die Pfadzählfunktion von proggen wird in der vorliegenden Arbeit nicht verwendet.

28 3.4 Validierungsexperiment

x1

1

x3

2

x5

3

x7

4

o9

5

x11

6

w14

7

x15 x17

8

x19

9

w20

10

x21 x33

11

x23 x35

12

i25 x37

13

x27 x39

14

x29 x41

15

x31 x43

16

i45

17

x47

18

x49 o9 19

x51

20

x53 i25 1

21

b55

22 i45 x56

23 O59 2 O58

24 O58 O59 x61

Abbildung 3.5: Von proggen erzeugter Pfad im Kontrollflussgraph und Verhaltensgraph

29 3 Verhaltensgraphen und Testfallmengenbewertung

Zu jedem der 7.680 Parametersätze wurden zufallsbasiert 10 unterschiedliche Kontrollflussgraph/Fehleraufdeckungsmodell–Kombinationen generiert.

Aus jeder Kontrollflussgraph/Fehleraufdeckungsmodell-Kombination wurde eine Menge von 200 Pfaden zufallsbasiert ausgewählt und für diese Menge die Werte

min £

Verhaltensdiversität, Verzweigungsabdeckung und ¤ berechnet. ¡

¢¡ min min

£ £ ¤ Insgesamt wurden so 76.800 Messwertpaare ¤ und Verzweigungsabdeckung ermit- telt. Diese Messreihen wurden – nach Häufigkeitsobergrenzen getrennt – auf ihre Korrelation untersucht. Ziel des Experiments war der statistische Nachweis eines Zusammenhangs zwi-

min £ schen Verhaltensdiversität und ¤ . Über die Arten der modellierten Fehler werden im Feh- leraufdeckungsmodell – wie bereits erwähnt – keine Annahmen gemacht, lediglich über ihre Auswirkungen hinsichtlich der Aufdeckung. Die Experimente fanden auf drei Linux–Servern statt, die mit je zwei Intel 3,06 GHz Xeon–Prozessoren sowie 2 GB Hauptspeicher ausgestattet waren und nahmen etwa drei Tage Rechenzeit in Anspruch.

Verwendete statistische Kenngrössen

Zur Charakterisierung zentraler Tendenzen von Messwerten werden in dieser Arbeit die Grös-

sen Median und arithmetisches Mittel (Durchschnitt) benutzt. Der Median charakterisiert den

¡

 ¢  Wert einer geordneten Messreihe X x1 ¢ xn , über und unter dem gleich viele Messwerte

liegen. Er wird wie folgt bestimmt:

Für ungerade n: Median x n 1 2

x n ¤ x n 1

2 2 § Für gerade n: Median 2

Das arithmetische Mittel X ist die Summe aller Messwerte geteilt durch deren Anzahl: ∑n x i £ 1 i

X n

Unterschiede zwischen Median und arithmetischem Mittel geben Hinweise auf die Verteilung der Messwerte. Bei der Auswertung der ermittelten Daten kommt eine statistische Standardmethode der Korrelationsanalyse zum Einsatz, um den Zusammenhang verschiedener Messparameter nach- zuweisen. Hier soll das benutzte Verfahren kurz skizziert werden. Möchte man in der Statistik den Zusammenhang zwischen zwei Messreihen nachweisen, deren Werte zu bestimmten Beobachtungszeitpunkten paarweise ermittelt wurden, bestimmt man in

der Regel einen Korrelationskoeffizienten nach einem für das spezielle Experiment geeigneten

¡ ¢

Verfahren. Ein Korrelationskoeffizient r ist ein Wert im Intervall 1 ¢ 1 , der aussagt, ob die

 beiden Werte unkorreliert (r 0), positiv korreliert (r 0) oder negativ korreliert (r 0) sind.

30 3.4 Validierungsexperiment

Weiterhin ist durch einen Test abzusichern, dass die ermittelte Korrelation einen gewissen kri- tischen Wert überschreitet (bzw. unterschreitet bei negativer Korrelation). Dieser Wert ist ab- hängig von der Stichprobengrösse und der gewünschten Wahrscheinlichkeit, dass die ermittelte Korrelation nicht doch zufallsbedingt ist (Signifikanzniveau). Der kritische Wert wird in spezi- ellen Tabellenwerken, wie etwa [32], nachgeschlagen. In der Auswertung des vorgestellten Versuchs kommt das Verfahren von Spearman zum Einsatz, bei dem die Korrelation der relativen Positionen in den Messreihen berechnet wird (Rangkorre- lation). Dieses Verfahren hat den Vorteil, dass es – im Gegensatz zu anderen Verfahren – keine

bestimmte Verteilung der Messreihen voraussetzt. 9

¡

£ ¢ £ ¢  ¢ Seien n Messwertpaare xi ¢ yi i 1 n gegeben, von denen die erste Komponente aus der ersten gemessenen Grösse und die zweite Komponente aus der zweiten gemessenen Grösse stammt. Der Spearman-Korrelationskoeffizient rs der beiden Messreihen berechnet sich nach folgendem Schema [32]:

1. Bestimmung der relativen Ränge der Messwerte innerhalb der jeweiligen Messreihe (Ord-

¡ £

nung nach aufsteigender Grösse beginnend mit Rang 1). Zu jedem Paar xi ¢ yi wird so

¡ £

ein Rangpaar ki ¢ li berechnet. Sind die nach aufsteigender Grösse geordneten Werte Nr. ¤ i bis i ¤ c gleich, spricht man von einer Bindung vom Ausmass c 1 und ordnet jedem

¤ c der Werte die Rangzahl i 2 zu.

2. Der Spearman-Korrelationskoeffizient rs der Messreihen ergibt sich wie folgt. Die Anzahl

 ¢

der Bindungen in den ki sei mit a, die Ausmasse der Bindungen mit t1 ¢ ta bezeichnet,

¢

die Anzahl der Bindungen in den li mit b, die Ausmasse der Bindungen mit w1 ¢ wb. ¡

∑n 2

6 k l £

£ i i

i 1 ¡

rs 1 ¤

3

n n Ts Ws £ mit

a b ¡

1 ¡ 1

2 2

¢ £ T ∑ t t 1 £ W ∑ w w 1

s 2 j j s 2 j j £ j £ 1 j 1

In der grafischen Darstellung der untersuchten Paare als Punkte (Scatterplot) ist eine Korrelation oft an kohärenten Punktwolken erkennbar. Die Berechnungen wurden mithilfe des Statistikpakets GNU–pspp durchgeführt.

Vorstudie: Ermittlung der Generierungsparameter

Mit proggen können, wie beschrieben, Kontrollflussgraphen erzeugt werden, die innerhalb ge- wisser struktureller Parameter zufällig variieren. Aber wie wählt man diese Parameter, um eine Ähnlichkeit zu Kontrollflussgraphen aus der Realität zu erzielen ?

9Beispielsweise kann der sehr häufig verwendete Produkt-Moment-Koeffizient (Verfahren nach Pearson) im vor- liegenden Experiment nicht angewendet werden, weil er eine Normalverteilung der Messreihen voraussetzt, die hier nicht angenommen werden kann.

31 3 Verhaltensgraphen und Testfallmengenbewertung

Paketname Paketbeschreibung aolserver AOL Web Server The GNU Bourne Again SHell bwbasic Bywater BASIC Interpreter catdoc MS-Word to TeX or plain text converter dc The GNU dc arbitrary precision reverse-polish calculator emacs20 The GNU Emacs editor fdutils Linux floppy utilities fileutils GNU file management utilities flex A fast lexical analyzer generator gcc-30 The GNU C compiler gnucap GNU Circuit Analysis package gzip The GNU compression utility lifelines Text-based genealogy software lynx Text-mode WWW Browser make The GNU version of the „make“ utility mt-st Linux SCSI tape driver aware magnetic tape control (aka mt) mtools Tools for manipulating MSDOS files nap Napster console client patch Apply a diff file to an original postgresql Object-relational SQL database descended from POSTGRES procmail Versatile e-mail processor rcs The GNU Revision Control System tar GNU tar workbone A simple text-based CD player

Tabelle 3.1: Pakete der Vorstudie

In der Vorbereitung des vorliegenden Experiments wurde dazu eine Untersuchung eines Korpus von textmodusbasierten Programmpaketen des Betriebssystems Linux (Debian-Distribution, Stand März 2004) durchgeführt. Die Werte zweier wichtiger Parameter, die Anteile von E/A- Anweisungen und Verzweigungsanweisungen, wurden anhand der Ergebnisse dieser Studie be- stimmt. Die Paketauswahl bietet einen umfangreichen Querschnitt durch unterschiedlichste Anwen- dungsbereiche. Die entsprechenden Paketnamen und deren Kurzbeschreibungen sind in Tabel- le 3.1 aufgeführt. Es finden sich sowohl einfache Systemprogramme, wie der Unix–Befehl ls zum Auflisten von Verzeichnissen, als auch Editoren, Programmiersprachen, WWW–Browser und WWW–Server, Datenbank–Tools, CD–Player, Kopierprogramme etc. Insgesamt enthalten die Pakete 101 ausführbare Programmdateien (eine vollständige Liste findet sich in Anhang A). Eine quellcodebasierte Analyse auf E/A–Anweisungsanteile fällt schwer, da vorher für jedes einzelne Programm die entsprechenden Routinen, Programmteile etc. separat bestimmt wer- den müssten. Einfacher ist die Untersuchung der übersetzten Programme im Objektcode, da Ein- und Ausgaben über eine standardisierte Schnittstelle (spezielle Funktionen der libc- Bibliothek) abgewickelt werden. Jedes der Programme wurde daher zunächst mit statischer

32 3.4 Validierungsexperiment

7

6

5

4

3

Anteil E/A-Anweisungen in % 2

1

0 0 100000 200000 300000 400000 500000 600000 Anweisungen Abbildung 3.6: Programmgrösse gegen E/A-Prozentanteile

Bindung an die C–Bibliothek libc (in der Version 2.2.5) übersetzt. Anschliessend wurde das .text-Segment (welches des Programmcode enthält) mit dem Linux-Werkzeug objdump zu einem Assemblerlisting in mnemonischer Form disassembliert. Das Assemblerlisting wurde auf die Gesamtzahl der Anweisungen (Assembler–Instruktionen), Aufrufe von E/A–Routinen und verzweigende Anweisungen untersucht. Die E/A–Routinen der C–Bibliothek, über die normalerweise alle Ein- und Ausgaben eines textmodusbasierten Programms ablaufen (Bildschirmausgaben, Tastatureingaben, Dateizugrif- fe etc.), sind mit eindeutigen Namen bezeichnet. Aufrufe dieser Routinen wurden als E/A– Anweisungen eingestuft und gezählt. Zusätzlich wurde die Zahl der Verzweigungsanweisungen bestimmt. Für beide Anweisungstypen wurde der prozentuale Anteil an den Anweisungen des Programms berechnet. Die Namen der betreffenden E/A–Routinen sowie die Mnemonics der Verzweigungsanweisungen sind in Anhang B dokumentiert. Da die statisch zugebundene Bibliothek selbst einen gewissen Umfang hat und sowohl Ver- zweigungen als auch Aufrufe der E/A–Routinen enthält, mussten die ermittelten Zahlen um die entsprechenden Werte korrigiert werden. Die Gesamtanweisungszahl wurde daher um 88.650 vermindert. Bei den Zahlen für E/A– und Verzweigungsanweisungen wurde ein Korrekturwert von 236 (E/A) bzw. 13.328 (Verzweigungen) abgezogen. Die Korrekturwerte wurden durch Übersetzung und Analyse eines C–Programms ermittelt, welches nur eine leere main–Funktion enthält. Die Programmgrösse variierte von 65 Anweisungen bis zu 546.365 Anweisungen mit einem

Schwerpunkt unter 12.000 Anweisungen (Median 12.020 Anweisungen, arithmetisches Mit-

tel 54 033 Anweisungen). E/A–Anweisungen traten in einem Anteil von etwa 0,023% bis 6,15% mit Schwerpunkt zwischen 0,1% und 0,5% auf (Median 0,457%, arithmetisches Mittel

0 ¢ 681%). Abbildung 3.6 gibt die Messwerte grafisch wieder, Abbildung 3.7 im dichter besetz- ten Ausschnitt.

33 3 Verhaltensgraphen und Testfallmengenbewertung

5

4

3

2 Anteil E/A-Anweisungen in %

1

0 0 5000 10000 15000 20000 25000 30000 35000 40000 Anweisungen Abbildung 3.7: Programmgrösse gegen E/A-Prozentanteile (Ausschnitt)

Der Bereich der Verzweigungsprozentzahlen lief von etwa 4,62% bis 18,38% (Medi-

an 12,517%, arithmetisches Mittel 12 ¢ 553%). Abbildung 3.6 zeigt die Messwerte grafisch und Abbildung 3.7 einen Ausschnitt. Die gemessenen Rohdaten finden sich in der Liste der Programmdateien im Anhang A.

3.4.3 Parameterauswahl

Für die Experimente wurden sechs Merkmale gewählt, nach denen die Parametersätze variiert wurden:

1. Anweisungszahl (Knotenanzahl des Kontrollflussgraphen) 2. Anteil E/A–Anweisungen 3. Relativer Anteil potenziell fehleraufdeckender E/A-Anweisungen an 2. 4. Anteil verzweigende Anweisungen (if/while) 5. Relative Anteile if/while-Anweisungen an 4. 6. Obergrenze der Fehleraufdeckungshäufigkeit im Fehleraufdeckungsmodell

Die Anweisungszahl wurde in drei Stufen gewählt: 5.000 – 12.000 – 25.000. Die Merk- male 2 und 4 wurden in Anlehnung an die Ergebnisse der Vorstudie belegt. Die An- teile der E/A–Anweisungen und verzweigender Anweisungen variierten in je vier Stu- fen: 0,1% – 0,5% – 3,3% – 6,15% bzw. 4,6% – 12,5% – 15,5% – 18,4%. Der rela- tive Anteil der E/A-Anweisungen, die potenziell Fehler aufdecken, wurde achtfach vari- iert (wobei jedoch unabhängig von der Prozentzahl mindestens eine Anweisung potenziell fehleraufdeckend war): 1% – 3% – 5% – 10% – 25% – 50% – 75% – 100%. Bei der Auftei-

34 3.4 Validierungsexperiment

20

18

16

14

12

10 Anteil Verzweigungsanweisungen 8

6

4 0 100000 200000 300000 400000 500000 600000 Anweisungen Abbildung 3.8: Programmgrösse gegen Verzweigungs-Prozentanteile

20

18

16

14

12

10

8 Anteil Verzweigungsanweisungen in %

6

4 0 20000 40000 60000 80000 100000 Anweisungen Abbildung 3.9: Programmgrösse gegen Verzweigungs-Prozentanteile (Ausschnitt)

35

3 Verhaltensgraphen und Testfallmengenbewertung

¡ ¡

min min min

£ £ £

 ¤  ¤  ¤

¢ £ £ pmax va rs va rs ¢ 0,001 0,000356 0,810 0,129 0,576 0,645 0,01 0,003585 0,813 0,106 0,583 0,644 0,1 0,035824 0,813 0,124 0,578 0,634 1 0,360649 0,812 0,128 0,582 0,641

va = Verzweigungsabdeckung, = Verhaltensdiversität, rs = Spearman-Korrelationskoeffizient, pmax = Häufigkeitsobergrenze im Fehleraufdeckungsmodell Tabelle 3.2: Ergebnisse nach Häufigkeitsobergrenzen lung der Verzweigungen auf if/while wurde zwischen fünf Verhältnissen unterschieden: 1/0 – 0,75/0,25 – 0,5/0,5 – 0,25/0,75 – 0/1. Die Obergrenze der Fehleraufdeckungshäufigkeit im Fehleraufdeckungsmodell wurde in vier Stufen variiert: 0,001 – 0,01 – 0,1 – 1.

Insgesamt ergeben sich aus den möglichen Merkmalskombinationen

3 4 4 8 5 4 7 680 Parametersätze.

¡ ¡ ¡ ¡ ¡

3.4.4 Ergebnisse

min £ Die in den Einzelexperimenten gemessenen Werte für ¤ wurden den Werten von und Ver- zweigungsabdeckung gegenübergestellt und einer Korrelationsanalyse unterzogen.

min £ Die Werte von ¤ liegen im Experiment in vier unterschiedlichen Intervallen vor, die durch

die Häufigkeitsobergrenzen bei der Fehleraufdeckungsmodellgenerierung definiert werden

¡ ¢ ¡ ¢ ¡ ¢ ¡ ¢

¢ ¢ ¢ ¢ ¢ ¢ ¢ ¢ ¢ ( 0 ¢ 0 001 0 0 01 0 0 1 0 1 ). Die Ergebnisse wurden daher in vier entsprechende Grup- pen unterteilt und getrennt auf Korrelation untersucht. Um die Ergebnisse möglichst gut abzusichern, sollte für die Korrelationsanalyse ein hohes Signifikanzniveau von 0,01 angenommen werden, also der gefundene Zusammenhang mit

99% Wahrscheinlichkeit überzufällig sein. Der entsprechende kritische Wert des Spearman-

¢ Korrelationskoeffizienten bei n 19 200 beträgt 0 019 [32]. Tabelle 3.2 zeigt die Ergebnisse der vier Gruppen. Zusätzlich zu den Korrelationskoeffizienten

min £ sind – zur Charakterisierung der generierten Pfadmengen – noch die Durchschnitte von ¤ , Verhaltensabdeckung und der Pfadmengen angegeben. 10

10 min¢

Es fällt auf, dass sich die Durchschnitte von ¡ im Wesentlichen durch einen Faktor nahe der entsprechenden

min¢

Häufigkeitsobergrenze unterscheiden. Die Werte sind als empirischer Erwartungswert von ¡ in der jeweiligen Graphklasse zu interpretieren, der durch den Erwartungswert der Fehleraufdeckungshäufigkeiten im Modell

(0,5 £ Obergrenze wg. gleichverteilter Auswahl) skaliert wird.

36 3.4 Validierungsexperiment

Die generierten Pfadmengen erreichen im Schnitt bereits ein hohes Mass an Verzweigungs- abdeckung, während der Durchschnitt der Verhaltensdiversität im mittleren Bereich liegt. Die

min £ Korrelation zwischen Verhaltensdiversität und ¤ bewegt sich in in allen Gruppen auf einem mittleren Niveau mit Koeffizienten um 0,64. Der kritische Wert wird immer weit überschritten.

min £ Verzweigungsabdeckung und ¤ korrelieren dagegen auf sehr niedrigem Niveau (Koeffizien- ten um 0,12). Zwar übertreffen auch diese Korrelationskoeffizienten den kritischen Wert (der bei grossen n generell sehr niedrig ist), trotzdem ist bei Koeffizienten dieser Grösse von einer äusserst marginalen Korrelation auszugehen. Bei dieser Betrachtung der Versuchsergebnisse ist also zunächst davon auszugehen, dass die Verhaltensdiversität einer Pfadmenge ein mittelguter Indikator für die untere Schranke der Feh- leraufdeckungswahrscheinlichkeit einer Pfadmenge ist, während die Verzweigungsabdeckung diese Eigenschaft nicht aufweist. Um das Ergebnis zu präzisieren, wurde zusätzlich zur be- schriebenen Auswertung der Einfluss der relativen Häufigkeit von potenziell fehleraufdecken- den Anweisungen auf die Messwerte untersucht. Dazu wurden aus den Ergebnissen 32 entspre- chende Gruppen (erzeugt durch acht verschiedene Häufigkeiten, vier Häufigkeitsobergrenzen bzgl. Programmstellen) gebildet und getrennt analysiert. Die Messwerte für jede Gruppe sind in den Abbildungen 3.10 bis 3.13 am Ende des Kapitels als Scatterplots wiedergegeben. Die

Ergebnisse der Analyse sind in den Tabellen 3.3 und 3.4 zusammengefasst. Der kritische Wert

¢ für die Korrelation (bei der resultierenden Gruppengrösse von n 2 400) ist 0 053. In den 16 Gruppen mit kleinem Anteil potenziell fehleraufdeckender Anweisungen (1%, 3%, 5% und 10%, Abbildung 3.10) sieht man einen deutlichen Trend zu grösseren Korrelationen mit steigendem Anteil potenziell fehleraufdeckender Anweisungen (etwa 0,6, 0,78, 0,84 und 0,88). Bei den höheren Anteilen (25%, 50%, 75%, 100%, Abbildung 3.11) pendelt sich der Wert auf einem hohen Niveau von etwa 0,9 ein. Bemerkenswert ist, dass selbst bei den sehr niedrigen An- teilen von 1% und 3%, die oft nur aus einer einzigen potenziell fehleraufdeckenden Anweisung bestehen, bereits eine mittlere bis gute Korrelation zu beobachten ist. Die Verzweigungsabdeckung zeigt dagegen in keiner der untersuchten Gruppen eine mittlere oder gute Korrelation (Abbildungen 3.12 und 3.13). Der höchste erreichte Wert ist 0,332. Im Licht dieser zusätzlichen Auswertung ist das vorläufige Ergebnis von oben zu relativieren, welches auf der undifferenzierten Betrachtung der Gesamtdatenmenge (bzw. Gruppierung nur

min nach Häufigkeitsobergrenze) basierte. Die Korrelation zwischen und f £ wächst sehr schnell mit dem Anteil potenziell fehleraufdeckender Anweisungen unter den E/A-Anweisungen. Die Korrelation ist bei kleinen Prozentzahlen bereits im mittleren bis guten Bereich und erreicht ab etwa 10% Werte um 0,9. Zusammenfassend können daher die gefundenen Messwerte so interpretiert werden, dass im Experiment die Verhaltensdiversität in den meisten untersuchten Bereichen gut bis sehr gut mit der unteren Schranke der Fehleraufdeckungsfähigkeit von Pfadmengen korreliert. Wenn man die Ergebnisse des Experiments auf echte Programme überträgt, heisst dass, das die Aussage- kraft der Verhaltensdiversität zwar von Programm und Fehlerart abhängt, man jedoch in sehr vielen Fällen eine hohe Relevanz erwarten kann.

37 3 Verhaltensgraphen und Testfallmengenbewertung

E/A–Anweisungen: 1% potenziell aufdeckend, 99% nicht aufdeckend

¡ ¡

min min min

£ £ £

 ¤  ¤  ¤

¢ £ £ pmax va rs va rs ¢ 0,001 0,000058 0,817 0,329 0,585 0,581 0,01 0,000613 0,822 0,260 0,595 0,604 0,1 0,007119 0,822 0,332 0,592 0,578 1 0,064765 0,819 0,281 0,593 0,526

E/A–Anweisungen: 3% potenziell aufdeckend, 97% nicht aufdeckend

¡ ¡

min min min

£ £ £

 ¤   ¤ ¤

£ ¢ £ pmax va rs va ¢ rs 0,001 0,000138 0,815 0,269 0,580 0,781 0,01 0,001407 0,823 0,214 0,592 0,793 0,1 0,014003 0,824 0,262 0,595 0,780 1 0,138222 0,814 0,261 0,585 0,765

E/A–Anweisungen: 5% potenziell aufdeckend, 95% nicht aufdeckend

¡ ¡

min min min

£ £ £

¤  ¤   ¤

¢ £ £ pmax va rs va rs ¢ 0,001 0,000196 0,816 0,209 0,586 0,843 0,01 0,001990 0,824 0,208 0,595 0,849 0,1 0,019678 0,825 0,236 0,590 0,846 1 0,203669 0,820 0,196 0,592 0,836

E/A–Anweisungen: 10% potenziell aufdeckend, 90% nicht aufdeckend

¡ ¡

min min min

£ £ £

 ¤  ¤  ¤

£ ¢ £ pmax va rs va ¢ rs 0,001 0,000287 0,813 0,215 0,583 0,889 0,01 0,002898 0,823 0,189 0,595 0,899 0,1 0,029113 0,826 0,198 0,589 0,887 1 0,296700 0,817 0,220 0,591 0,885

va = Verzweigungsabdeckung, = Verhaltensdiversität, rs = Spearman-Korrelationskoeffizient, pmax = Häufigkeitsobergrenze im Fehleraufdeckungsmodell Tabelle 3.3: Ergebnisse nach Anteil potenziell fehlerhafter E/A-Anweisungen (1)

38 3.4 Validierungsexperiment

E/A–Anweisungen: 25% potenziell aufdeckend, 75% nicht aufdeckend

¡ ¡

min min min

£ £ £

 ¤  ¤  ¤

¢ £ £ pmax va rs va rs ¢ 0,001 0,000439 0,823 0,175 0,592 0,910 0,01 0,004376 0,823 0,178 0,597 0,914 0,1 0,042935 0,820 0,184 0,583 0,909 1 0,436122 0,829 0,200 0,596 0,927

E/A–Anweisungen: 50% potenziell aufdeckend, 50% nicht aufdeckend

¡ ¡

min min min

£ £ £

 ¤   ¤ ¤

£ ¢ £ pmax va rs va ¢ rs 0,001 0,000542 0,824 0,199 0,591 0,917 0,01 0,005428 0,822 0,192 0,592 0,912 0,1 0,054027 0,821 0,194 0,583 0,903 1 0,544702 0,827 0,204 0,596 0,921

E/A–Anweisungen: 25% potenziell aufdeckend, 75% nicht aufdeckend

¡ ¡

min min min

£ £ £

¤  ¤   ¤

¢ £ £ pmax va rs va rs ¢ 0,001 0,000602 0,826 0,223 0,591 0,924 0,01 0,006016 0,824 0,183 0,595 0,920 0,1 0,059861 0,820 0,201 0,583 0,906 1 0,599667 0,825 0,205 0,594 0,921

E/A–Anweisungen: 100% potenziell aufdeckend, 0% nicht aufdeckend

¡ ¡

min min min

£ £ £

 ¤  ¤  ¤

£ ¢ £ pmax va rs va ¢ rs 0,001 0,000588 0,745 0,235 0,497 0,911 0,01 0,005949 0,742 0,233 0,502 0,907 0,1 0,059854 0,746 0,243 0,512 0,901 1 0,601342 0,746 0,213 0,507 0,905

va = Verzweigungsabdeckung, = Verhaltensdiversität, rs = Spearman-Korrelationskoeffizient, pmax = Häufigkeitsobergrenze im Fehleraufdeckungsmodell Tabelle 3.4: Ergebnisse nach Anteil potenziell fehlerhafter E/A-Anweisungen (2)

39 3 Verhaltensgraphen und Testfallmengenbewertung

3.5 Diskussion

Das vorgestellte Experiment ist statistischer Natur; ausserdem werden nur untere Grenzen der Fehleraufdeckungswahrscheinlichkeit betrachtet. Zusätzlich ist es keine Untersuchung an „na- türlichen“ Programmen, sondern an Kontrollflussmodellen. Das Ergebnis des Experiments ist daher keine absolute, beweisartige Aussage, liefert aber einen Anhalt für die Güte des un- tersuchten Masses. Im Experiment korrelierte die Verhaltensdiversität einer Menge von Pro- grammläufen bzw. der von ihnen abgedeckten Kontrollflusspfade mit der Fähigkeit zur Fehler- auffindung in Form der unteren Schranke der Fehleraufdeckungswahrscheinlichkeit von Pfad- mengen. Die guten Korrelationswerte müssen aber durch Betrachtung der absoluten Werte für untere Schranken der Fehleraufdeckungswahrscheinlichkeit relativiert werden; insgesamt kann kein Programmlauf hier einen Wert erreichen, der grösser ist als die maximale Fehleraufde- ckungshäufigkeit unter den Knoten der Pfadmenge. Zusätzlich ist zumindest ein Grund der guten Korrelation darin zu sehen, dass eine hohe Verhaltensdiversität auch anzeigt, dass in der Pfadmenge viele Pfade mit potenziell fehleraufdeckenden Knoten enthalten sind (hat z.B. eine Pfadmenge die Verhaltensdiversität 0, kann kein entsprechender Pfad einen Fehler aufdecken). Dies ist eine wünschenswerte Charakteristik, konnte jedoch als Hauptgrund der Korrelation durch eine weitere Kontrollauswertung der Daten ausgeschlossen werden. In ihr wurde keine nennenswerte Korrelation für die Abdeckung von E/A-Anweisungen bzw. fehleraufdeckenden

min £

E/A-Anweisungen mit f festgestellt (Koeffizienten um 0,07 bzw. 0 ¢ 1). Die Verhaltensdiversität ist kein absolutes Mass, sondern gibt einen Anhalt bezüglich der Re- levanz der gewählten Pfadmenge an. Man kann zwar von einem Programmlauf, der einen Pfad aus einer Menge mit einer hohen Verhaltensdiversität abdeckt, eine gewisse Eignung zur Fehler- aufdeckung erwarten. Jedoch sagt die Verhaltensdiversität nichts über die Fähigkeit von Test- fällen aus, einen möglichst grossen Teil der möglichen unterschiedlichen Fehlverhalten eines Programms aufzudecken. Daher kann sie die Testfallmengenbewertung durch andere Kriterien nur komplementieren, aber keineswegs ersetzen. Ein hoher Wert an Verhaltensdiversität garan- tiert keine Fehleraufdeckung in jedem Fall – wenn sich beispielsweise die Fehler nur auf einem einzigen Interaktionsmuster von vielen möglichen manifestieren und dieses Muster in der Pfad- menge nicht vorhanden ist. Das Ergebnis des Experimentes legt jedoch die Erwartung nahe, dass man der Einschätzung in vielen Fällen mit einem höheren Niveau vertrauen kann als einfachen Metriken wie der Anweisungs- oder Verzweigungsabdeckung. Die Verhaltensdiversität kann daher ein zusätzliches Entscheidungskriterium für die Auswahl zwischen verschiedenen Test- fallmengen sein, die unter einer anderen Metrik gleiche Werte zeigen oder ein anderes Kriterium erfüllen. Auf diese Weise kann sie die Aussagen anderer Bewertungskriterien präzisieren. In der Literatur finden sich verwandte Ansätze der Fehleraufdeckungsmodellierung, beispiels- weise in [20, 23, 24, 36], in denen Fehleraufdeckungsfähigkeiten ebenfalls über Häufigkeiten bzw. Wahrscheinlichkeiten beschrieben werden. Diese Ansätze charakterisieren die Fehlerauf- deckungswahrscheinlichkeiten ausschliesslich über angenommene Fehlerraten. Im hier vorge- stellten Modell werden die Wahrscheinlichkeiten (bzw. Häufigkeiten) dagegen anhand des Pro- zesses der Fehlerentstehung und –aufdeckung im Programm definiert. Es berücksichtigt so des-

40 3.5 Diskussion sen Einfluss auf die Fehleraufdeckungshäufigkeiten individueller Kontrollflusspfade. In der Ter- minologie der zititerten Arbeiten ist das Modell ein Domain-Test-Modell. Das quantitative Fehleraufdeckungsmodell dieses Kapitels bietet sich in der gezeigten Kombi- nation mit künstlich erzeugten Programmen als offener Testbed-Ansatz an, in dem auch andere Metriken, Kriterien, kontrollflussbasierte Techniken etc. untersucht werden können. Statt we- nige vorgegebene Programme zu benutzen, die erst auf ihre Eigenschaften, Eignung etc. un- tersucht werden müssen, kann man automatisch eine exakt spezifizierte und beliebig grosse Untersuchungsbasis erzeugen. Bevorzugt man die Untersuchung von Metriken und Kriterien an echten Programmen, könnte das in diesem Kapitel definierte System der Fehleraufdeckungshäufigkeiten und – wahrscheinlichkeiten auch bei der Bereitstellung von Programmkorpora für Benchmark– Zwecke helfen. Findet man einen Weg, für konkrete Programme und Fehler ein Fehleraufde- ckungsmodell zu bestimmen, können an ihnen ähnliche Untersuchungen durchgeführt werden. Dies erscheint für manche Programme durch Anwendung von Techniken möglich, die ad-hoc- Testentwurfsstrategien (Partitionierung von Eingabemengen etc.) ähneln. Der Themenkreis be- darf aber weiterer grundlegender Untersuchung und wird in dieser Arbeit nicht vertieft.

41 3 Verhaltensgraphen und Testfallmengenbewertung 1 1 1 1 0.9 0.9 0.9 0.9 0.8 0.8 0.8 0.8 0.7 0.7 0.7 0.7 0.6 0.6 0.6 0.6 0.5 0.5 0.5 0.5 0.4 0.4 0.4 0.4 0.3 0.3 0.3 0.3 0.2 0.2 0.2 0.2 0.1 Verhaltensdiversitaet (Pmax=1, Verteilung nichtaufdeckend/aufdeckend 90/10) Verhaltensdiversitaet (Pmax=0.001, Verteilung nichtaufdeckend/aufdeckend 90/10) Verhaltensdiversitaet (Pmax=0.01, Verteilung nichtaufdeckend/aufdeckend 90/10) Verhaltensdiversitaet (Pmax=0.1, Verteilung nichtaufdeckend/aufdeckend 90/10) 0.1 0.1 0.1 rs=0,889 rs=0,899 rs=0,887 rs=0,885 0 0 0 0 0 0 0 1 0 0.001

0.01 0.1

0.0009 0.0008 0.0007 0.0006 0.0005 0.0004 0.0003 0.0002 0.0001 0.009 0.008 0.007 0.006 0.005 0.004 0.003 0.002 0.001 0.09 0.08 0.07 0.06 0.05 0.04 0.03 0.02 0.01 0.9 0.8 0.7 0.6 0.5 0.4 0.3 0.2 0.1

Untere Schranke Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere 1 1 1 1 0.9 0.9 0.9 0.9 0.8 0.8 0.8 0.8 0.7 0.7 0.7 0.7 0.6 0.6 0.6 0.6 0.5 0.5 0.5 0.5 0.4 0.4 0.4 0.4 0.3 0.3 0.3 0.3 0.2 0.2 0.2 0.2 0.1 Verhaltensdiversitaet (Pmax=1, Verteilung nichtaufdeckend/aufdeckend 95/5) Verhaltensdiversitaet (Pmax=0.001, Verteilung nichtaufdeckend/aufdeckend 95/5) Verhaltensdiversitaet (Pmax=0.01, Verteilung nichtaufdeckend/aufdeckend 95/5) Verhaltensdiversitaet (Pmax=0.1, Verteilung nichtaufdeckend/aufdeckend 95/5) 0.1 0.1 0.1 rs=0,843 rs=0,849 rs=0,846 rs=0,836 0 0 0 0 0 0 0 1 0 0.001

0.01 0.1

0.0009 0.0008 0.0007 0.0006 0.0005 0.0004 0.0003 0.0002 0.0001 0.009 0.008 0.007 0.006 0.005 0.004 0.003 0.002 0.001 0.09 0.08 0.07 0.06 0.05 0.04 0.03 0.02 0.01 0.9 0.8 0.7 0.6 0.5 0.4 0.3 0.2 0.1

Untere Schranke Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere 1 1 1 1 0.9 0.9 0.9 0.9 0.8 0.8 0.8 0.8 0.7 0.7 0.7 0.7 0.6 0.6 0.6 0.6 0.5 0.5 0.5 0.5 0.4 0.4 0.4 0.4 0.3 0.3 0.3 0.3 0.2 0.2 0.2 0.2 0.1 Verhaltensdiversitaet (Pmax=1, Verteilung nichtaufdeckend/aufdeckend 97/3) Verhaltensdiversitaet (Pmax=0.001, Verteilung nichtaufdeckend/aufdeckend 97/3) Verhaltensdiversitaet (Pmax=0.01, Verteilung nichtaufdeckend/aufdeckend 97/3) Verhaltensdiversitaet (Pmax=0.1, Verteilung nichtaufdeckend/aufdeckend 97/3) 0.1 0.1 0.1 rs=0,781 rs=0,793 rs=0,780 rs=0,765 0 0 0 0 0 0 0 1 0 0.001

0.01 0.1

0.0009 0.0008 0.0007 0.0006 0.0005 0.0004 0.0003 0.0002 0.0001 0.009 0.008 0.007 0.006 0.005 0.004 0.003 0.002 0.001 0.09 0.08 0.07 0.06 0.05 0.04 0.03 0.02 0.01 0.9 0.8 0.7 0.6 0.5 0.4 0.3 0.2 0.1

Untere Schranke Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere 1 1 1 1 0.9 0.9 0.9 0.9 0.8 0.8 0.8 0.8 0.7 0.7 0.7 0.7 0.6 0.6 0.6 0.6 0.5 0.5 0.5 0.5 0.4 0.4 0.4 0.4 0.3 0.3 0.3 0.3 0.2 0.2 0.2 0.2 0.1 Verhaltensdiversitaet (Pmax=1, Verteilung nichtaufdeckend/aufdeckend 99/1) Verhaltensdiversitaet (Pmax=0.001, Verteilung nichtaufdeckend/aufdeckend 99/1) Verhaltensdiversitaet (Pmax=0.01, Verteilung nichtaufdeckend/aufdeckend 99/1) Verhaltensdiversitaet (Pmax=0.1, Verteilung nichtaufdeckend/aufdeckend 99/1) 0.1 0.1 0.1 rs=0,581 rs=0,604 rs=0,578 rs=0,526 0 0 0 0 0 0 0 0

0.1

0.0007 0.0006 0.0005 0.0004 0.0003 0.0002 0.0001 0.009 0.008 0.007 0.006 0.005 0.004 0.003 0.002 0.001 0.09 0.08 0.07 0.06 0.05 0.04 0.03 0.02 0.01 0.9 0.8 0.7 0.6 0.5 0.4 0.3 0.2 0.1

Untere Schranke Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere

¢¡ min Abbildung 3.10: f £ nach Verteilung nichtaufdeckende/aufdeckende Ausgabeanweisungen und Häufigkeitsobergrenzen (1)

42 3.5 Diskussion 1 1 1 1 0.9 0.9 0.9 0.9 0.8 0.8 0.8 0.8 0.7 0.7 0.7 0.7 0.6 0.6 0.6 0.6 0.5 0.5 0.5 0.5 0.4 0.4 0.4 0.4 0.3 0.3 0.3 0.3 0.2 0.2 0.2 0.2 0.1 Verhaltensdiversitaet (Pmax=1, Verteilung nichtaufdeckend/aufdeckend 0/100) Verhaltensdiversitaet (Pmax=0.001, Verteilung nichtaufdeckend/aufdeckend 0/100) Verhaltensdiversitaet (Pmax=0.01, Verteilung nichtaufdeckend/aufdeckend 0/100) Verhaltensdiversitaet (Pmax=0.1, Verteilung nichtaufdeckend/aufdeckend 0/100) 0.1 0.1 0.1 rs=0,911 rs=0,907 rs=0,901 rs=0,905 0 0 0 0 0 0 0 1 0 0.001

0.01 0.1

0.0009 0.0008 0.0007 0.0006 0.0005 0.0004 0.0003 0.0002 0.0001 0.009 0.008 0.007 0.006 0.005 0.004 0.003 0.002 0.001 0.09 0.08 0.07 0.06 0.05 0.04 0.03 0.02 0.01 0.9 0.8 0.7 0.6 0.5 0.4 0.3 0.2 0.1

Untere Schranke Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere 1 1 1 1 0.9 0.9 0.9 0.9 0.8 0.8 0.8 0.8 0.7 0.7 0.7 0.7 0.6 0.6 0.6 0.6 0.5 0.5 0.5 0.5 0.4 0.4 0.4 0.4 0.3 0.3 0.3 0.3 0.2 0.2 0.2 0.2 0.1 Verhaltensdiversitaet (Pmax=1, Verteilung nichtaufdeckend/aufdeckend 25/75) Verhaltensdiversitaet (Pmax=0.001, Verteilung nichtaufdeckend/aufdeckend 25/75) Verhaltensdiversitaet (Pmax=0.01, Verteilung nichtaufdeckend/aufdeckend 25/75) Verhaltensdiversitaet (Pmax=0.1, Verteilung nichtaufdeckend/aufdeckend 25/75) 0.1 0.1 0.1 rs=0,924 rs=0,920 rs=0,906 rs=0,921 0 0 0 0 0 0 0 1 0 0.001

0.01 0.1

0.0009 0.0008 0.0007 0.0006 0.0005 0.0004 0.0003 0.0002 0.0001 0.009 0.008 0.007 0.006 0.005 0.004 0.003 0.002 0.001 0.09 0.08 0.07 0.06 0.05 0.04 0.03 0.02 0.01 0.9 0.8 0.7 0.6 0.5 0.4 0.3 0.2 0.1

Untere Schranke Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere 1 1 1 1 0.9 0.9 0.9 0.9 0.8 0.8 0.8 0.8 0.7 0.7 0.7 0.7 0.6 0.6 0.6 0.6 0.5 0.5 0.5 0.5 0.4 0.4 0.4 0.4 0.3 0.3 0.3 0.3 0.2 0.2 0.2 0.2 0.1 Verhaltensdiversitaet (Pmax=1, Verteilung nichtaufdeckend/aufdeckend 50/50) Verhaltensdiversitaet (Pmax=0.001, Verteilung nichtaufdeckend/aufdeckend 50/50) Verhaltensdiversitaet (Pmax=0.01, Verteilung nichtaufdeckend/aufdeckend 50/50) Verhaltensdiversitaet (Pmax=0.1, Verteilung nichtaufdeckend/aufdeckend 50/50) 0.1 0.1 0.1 rs=0,917 rs=0,912 rs=0,903 rs=0,921 0 0 0 0 0 0 0 1 0 0.001

0.01 0.1

0.0009 0.0008 0.0007 0.0006 0.0005 0.0004 0.0003 0.0002 0.0001 0.009 0.008 0.007 0.006 0.005 0.004 0.003 0.002 0.001 0.09 0.08 0.07 0.06 0.05 0.04 0.03 0.02 0.01 0.9 0.8 0.7 0.6 0.5 0.4 0.3 0.2 0.1

Untere Schranke Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere 1 1 1 1 0.9 0.9 0.9 0.9 0.8 0.8 0.8 0.8 0.7 0.7 0.7 0.7 0.6 0.6 0.6 0.6 0.5 0.5 0.5 0.5 0.4 0.4 0.4 0.4 0.3 0.3 0.3 0.3 0.2 0.2 0.2 0.2 0.1 Verhaltensdiversitaet (Pmax=1, Verteilung nichtaufdeckend/aufdeckend 75/25) Verhaltensdiversitaet (Pmax=0.001, Verteilung nichtaufdeckend/aufdeckend 75/25) Verhaltensdiversitaet (Pmax=0.01, Verteilung nichtaufdeckend/aufdeckend 75/25) Verhaltensdiversitaet (Pmax=0.1, Verteilung nichtaufdeckend/aufdeckend 75/25) 0.1 0.1 0.1 rs=0,910 rs=0,914 rs=0,909 rs=0,927 0 0 0 0 0 0 0 1 0 0.001

0.01 0.1

0.0009 0.0008 0.0007 0.0006 0.0005 0.0004 0.0003 0.0002 0.0001 0.009 0.008 0.007 0.006 0.005 0.004 0.003 0.002 0.001 0.09 0.08 0.07 0.06 0.05 0.04 0.03 0.02 0.01 0.9 0.8 0.7 0.6 0.5 0.4 0.3 0.2 0.1

Untere Schranke Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere

¢¡ min Abbildung 3.11: f £ nach Verteilung nichtaufdeckende/aufdeckende Ausgabeanweisungen und Häufigkeitsobergrenzen (2)

43 3 Verhaltensgraphen und Testfallmengenbewertung 1 1 1 1 0.9 0.9 0.9 0.9 0.8 0.8 0.8 0.8 0.7 0.7 0.7 0.7 0.6 0.6 0.6 0.6 0.5 0.5 0.5 0.5 0.4 0.4 0.4 0.4 0.3 0.3 0.3 0.3 Verzweigungsabdeckung (Pmax=1, Verteilung nichtaufdeckend/aufdeckend 90/10) Verzweigungsabdeckung (Pmax=0.001, Verteilung nichtaufdeckend/aufdeckend 90/10) Verzweigungsabdeckung (Pmax=0.01, Verteilung nichtaufdeckend/aufdeckend 90/10) Verzweigungsabdeckung (Pmax=0.1, Verteilung nichtaufdeckend/aufdeckend 90/10) rs=0,215 rs=0,189 rs=0,198 rs=0,220 0.2 0 0.2 0 0.2 0 0.2 1 0 0.001

0.01 0.1

0.0009 0.0008 0.0007 0.0006 0.0005 0.0004 0.0003 0.0002 0.0001 0.009 0.008 0.007 0.006 0.005 0.004 0.003 0.002 0.001 0.09 0.08 0.07 0.06 0.05 0.04 0.03 0.02 0.01 0.9 0.8 0.7 0.6 0.5 0.4 0.3 0.2 0.1

Untere Schranke Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere 1 1 1 1 0.9 0.9 0.9 0.9 0.8 0.8 0.8 0.8 0.7 0.7 0.7 0.7 0.6 0.6 0.6 0.6 0.5 0.5 0.5 0.5 0.4 0.4 0.4 0.4 0.3 0.3 0.3 0.3 Verzweigungsabdeckung (Pmax=1, Verteilung nichtaufdeckend/aufdeckend 95/5) Verzweigungsabdeckung (Pmax=0.001, Verteilung nichtaufdeckend/aufdeckend 95/5) Verzweigungsabdeckung (Pmax=0.01, Verteilung nichtaufdeckend/aufdeckend 95/5) Verzweigungsabdeckung (Pmax=0.1, Verteilung nichtaufdeckend/aufdeckend 95/5) rs=0,209 rs=0,208 rs=0,236 rs=0,196 0.2 0 0.2 0 0.2 0 0.2 1 0 0.001

0.01 0.1

0.0009 0.0008 0.0007 0.0006 0.0005 0.0004 0.0003 0.0002 0.0001 0.009 0.008 0.007 0.006 0.005 0.004 0.003 0.002 0.001 0.09 0.08 0.07 0.06 0.05 0.04 0.03 0.02 0.01 0.9 0.8 0.7 0.6 0.5 0.4 0.3 0.2 0.1

Untere Schranke Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere 1 1 1 1 0.9 0.9 0.9 0.9 0.8 0.8 0.8 0.8 0.7 0.7 0.7 0.7 0.6 0.6 0.6 0.6 0.5 0.5 0.5 0.5 0.4 0.4 0.4 0.3 0.4 0.3 0.2 0.3 0.3 Verzweigungsabdeckung (Pmax=1, Verteilung nichtaufdeckend/aufdeckend 97/3) Verzweigungsabdeckung (Pmax=0.001, Verteilung nichtaufdeckend/aufdeckend 97/3) Verzweigungsabdeckung (Pmax=0.01, Verteilung nichtaufdeckend/aufdeckend 97/3) Verzweigungsabdeckung (Pmax=0.1, Verteilung nichtaufdeckend/aufdeckend 97/3) rs=0,269 rs=0,214 rs=0,262 rs=0,261 0.1 0 0.2 0 0.2 0 0.2 1 0 0.001

0.01 0.1

0.0009 0.0008 0.0007 0.0006 0.0005 0.0004 0.0003 0.0002 0.0001 0.009 0.008 0.007 0.006 0.005 0.004 0.003 0.002 0.001 0.09 0.08 0.07 0.06 0.05 0.04 0.03 0.02 0.01 0.9 0.8 0.7 0.6 0.5 0.4 0.3 0.2 0.1

Untere Schranke Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere 1 1 1 1 0.9 0.9 0.9 0.9 0.8 0.8 0.8 0.8 0.7 0.7 0.7 0.7 0.6 0.6 0.6 0.6 0.5 0.5 0.5 0.5 0.4 0.4 0.4 0.3 0.4 0.3 0.2 0.3 0.3 Verzweigungsabdeckung (Pmax=1, Verteilung nichtaufdeckend/aufdeckend 99/1) Verzweigungsabdeckung (Pmax=0.001, Verteilung nichtaufdeckend/aufdeckend 99/1) Verzweigungsabdeckung (Pmax=0.01, Verteilung nichtaufdeckend/aufdeckend 99/1) Verzweigungsabdeckung (Pmax=0.1, Verteilung nichtaufdeckend/aufdeckend 99/1) rs=0,329 rs=0,260 rs=0,332 rs=0,281 0.1 0 0.2 0 0.2 0 0.2 0

0.1

0.0007 0.0006 0.0005 0.0004 0.0003 0.0002 0.0001 0.009 0.008 0.007 0.006 0.005 0.004 0.003 0.002 0.001 0.09 0.08 0.07 0.06 0.05 0.04 0.03 0.02 0.01 0.9 0.8 0.7 0.6 0.5 0.4 0.3 0.2 0.1

Untere Schranke Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere

min Abbildung 3.12: Verzweigungsabdeckung/f £ nach Verteilung nichtaufdeckende/aufdeckende Ausgabeanweisungen und Häufigkeitsobergrenzen (3)

44 3.5 Diskussion 1 1 1 1 0.9 0.9 0.9 0.9 0.8 0.8 0.8 0.8 0.7 0.7 0.7 0.7 0.6 0.6 0.6 0.6 0.5 0.5 0.5 0.4 0.5 0.4 0.4 0.3 0.4 0.3 0.3 0.2 0.3 0.2 0.2 Verzweigungsabdeckung (Pmax=1, Verteilung nichtaufdeckend/aufdeckend 0/100) Verzweigungsabdeckung (Pmax=0.001, Verteilung nichtaufdeckend/aufdeckend 0/100) Verzweigungsabdeckung (Pmax=0.01, Verteilung nichtaufdeckend/aufdeckend 0/100) Verzweigungsabdeckung (Pmax=0.1, Verteilung nichtaufdeckend/aufdeckend 0/100) 0.1 rs=0,235 rs=0,233 rs=0,243 rs=0,213 0.1 0 0.2 0 0.1 0 0 1 0 0.001

0.01 0.1

0.0009 0.0008 0.0007 0.0006 0.0005 0.0004 0.0003 0.0002 0.0001 0.009 0.008 0.007 0.006 0.005 0.004 0.003 0.002 0.001 0.09 0.08 0.07 0.06 0.05 0.04 0.03 0.02 0.01 0.9 0.8 0.7 0.6 0.5 0.4 0.3 0.2 0.1

Untere Schranke Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere 1 1 1 1 0.9 0.9 0.9 0.9 0.8 0.8 0.8 0.8 0.7 0.7 0.7 0.7 0.6 0.6 0.6 0.6 0.5 0.5 0.5 0.5 0.4 0.4 0.4 0.3 0.4 0.3 0.3 0.2 0.3 0.2 Verzweigungsabdeckung (Pmax=1, Verteilung nichtaufdeckend/aufdeckend 25/75) Verzweigungsabdeckung (Pmax=0.001, Verteilung nichtaufdeckend/aufdeckend 25/75) Verzweigungsabdeckung (Pmax=0.01, Verteilung nichtaufdeckend/aufdeckend 25/75) Verzweigungsabdeckung (Pmax=0.1, Verteilung nichtaufdeckend/aufdeckend 25/75) rs=0,223 rs=0,183 rs=0,201 rs=0,205 0.1 0 0.2 0 0.1 0 0.2 1 0 0.001

0.01 0.1

0.0009 0.0008 0.0007 0.0006 0.0005 0.0004 0.0003 0.0002 0.0001 0.009 0.008 0.007 0.006 0.005 0.004 0.003 0.002 0.001 0.09 0.08 0.07 0.06 0.05 0.04 0.03 0.02 0.01 0.9 0.8 0.7 0.6 0.5 0.4 0.3 0.2 0.1

Untere Schranke Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere 1 1 1 1 0.9 0.9 0.9 0.9 0.8 0.8 0.8 0.8 0.7 0.7 0.7 0.7 0.6 0.6 0.6 0.6 0.5 0.5 0.5 0.5 0.4 0.4 0.4 0.4 0.3 0.3 0.3 0.3 Verzweigungsabdeckung (Pmax=1, Verteilung nichtaufdeckend/aufdeckend 50/50) Verzweigungsabdeckung (Pmax=0.001, Verteilung nichtaufdeckend/aufdeckend 50/50) Verzweigungsabdeckung (Pmax=0.01, Verteilung nichtaufdeckend/aufdeckend 50/50) Verzweigungsabdeckung (Pmax=0.1, Verteilung nichtaufdeckend/aufdeckend 50/50) rs=0,199 rs=0,192 rs=0,194 rs=0,204 0.2 0 0.2 0 0.2 0 0.2 1 0 0.001

0.01 0.1

0.0009 0.0008 0.0007 0.0006 0.0005 0.0004 0.0003 0.0002 0.0001 0.009 0.008 0.007 0.006 0.005 0.004 0.003 0.002 0.001 0.09 0.08 0.07 0.06 0.05 0.04 0.03 0.02 0.01 0.9 0.8 0.7 0.6 0.5 0.4 0.3 0.2 0.1

Untere Schranke Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere 1 1 1 1 0.9 0.9 0.9 0.9 0.8 0.8 0.8 0.8 0.7 0.7 0.7 0.7 0.6 0.6 0.6 0.6 0.5 0.5 0.5 0.5 0.4 0.4 0.4 0.4 0.3 0.3 0.3 0.3 Verzweigungsabdeckung (Pmax=1, Verteilung nichtaufdeckend/aufdeckend 75/25) Verzweigungsabdeckung (Pmax=0.001, Verteilung nichtaufdeckend/aufdeckend 75/25) Verzweigungsabdeckung (Pmax=0.01, Verteilung nichtaufdeckend/aufdeckend 75/25) Verzweigungsabdeckung (Pmax=0.1, Verteilung nichtaufdeckend/aufdeckend 75/25) rs=0,175 rs=0,178 rs=0,184 rs=0,200 0.2 0 0.2 0 0.2 0 0.2 1 0 0.001

0.01 0.1

0.0009 0.0008 0.0007 0.0006 0.0005 0.0004 0.0003 0.0002 0.0001 0.009 0.008 0.007 0.006 0.005 0.004 0.003 0.002 0.001 0.09 0.08 0.07 0.06 0.05 0.04 0.03 0.02 0.01 0.9 0.8 0.7 0.6 0.5 0.4 0.3 0.2 0.1

Untere Schranke Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere Fehleraufdeckungswahrscheinlichkeit Schranke Untere

min Abbildung 3.13: Verzweigungsabdeckung/f £ nach Verteilung nichtaufdeckende/aufdeckende Ausgabeanweisungen und Häufigkeitsobergrenzen (4)

45 3 Verhaltensgraphen und Testfallmengenbewertung

46 4 Sichtgraphen und Architekturuntersuchung

Bestimmte Berechnungsverfahren und Architekturen schlagen sich in charakteristischen Struk- turmustern des Kontrollflusses nieder. Möchte man wissen, ob ein unbekanntes Programm ein solches Verfahren oder eine solche Architektur realisiert, bietet sich die Analyse eines archi- tekturspezifischen Sichtgraphen an. Das Vorhandensein solcher Muster ist daher ein (u.U. hin- reichender) Hinweis darauf, dass das Programm die entsprechende Architektur implementiert. Findet man die gesuchten Strukturen im Sichtgraph nicht wieder, realisiert das Programm die Architektur dagegen sicher nicht. Der Ansatz kann Reengineeringmassnahmen durch die Bewertung von Altprogrammen unter- stützen. Zusätzlich kann er bei der Softwareerstellung helfen, Entwurfsfehler zu entdecken, indem geprüft wird, ob eine beabsichtigte Struktur auch tatsächlich implementiert wurde. Dieses Kapitel illustriert das Konzept anhand eines Anwendungsbeispiels. Es zeigt, wie mit Hilfe des Werkzeugs mcana Sichtgraphen aus Microcontrollerprogrammen extrahiert und mit dem Modelchecker SMV auf charakteristische Strukturen explizit fehlertoleranter Architektu- ren untersucht werden können.

4.1 Fehlertoleranzstrukturen

Entwurf und Implementierung komplexerer Softwaresysteme sind in der Regel nicht fehler- frei. Im Gegensatz dazu stehen Anforderungen an Robustheit (Fähigkeit zur Erkennung von Betriebsfehlern) und Fehlertoleranz (Fähigkeit, erkannte Fehler zu beheben oder maskieren), speziell bei Systemen, die in sicherheitskritischen Bereichen eingesetzt werden. Dabei müssen neben Hardwarefehlern auch Entwurfsfehler betrachtet werden. Glücklicherweise kann ein gewisses Mass an Robustheit und Toleranz gegenüber Entwurfsfeh- lern durch Vervielfältigung wichtiger Komponenten erreicht werden. Die voneinander unab- hängig berechneten Ergebnisse dieser redundanten Komponenten werden dabei in Prüf– und Fehlerbeseitigungsfunktionen oder –einheiten genutzt. Man unterscheidet explizite Fehlerto- leranz von transparenter (verdeckter) Fehlertoleranz. Bei expliziter Fehlertoleranz sorgt die Anwendungssoftware für die Fehlertoleranz, während die entsprechenden Eigenschaften bei der transparenten Fehlertoleranz von der Infrastruktur (etwa Middleware oder Betriebssystem) ohne Mitwirkung der Anwendungssoftware realisiert werden [18, 48, 64].

47 4 Sichtgraphen und Architekturuntersuchung

Bei transparenter Fehlertoleranz bleiben die fehlertolerierenden Komponenten dem Anwen- dungsprogrammierer gegenüber unsichtbar, während diese bei der expliziten Fehlertoleranz im Anwendungscode verankert sind und daher (in der While-Box-Perspektive) zur Analyse offen- liegen. Die Fehlertoleranzeigenschaften eines Programms spiegeln sich dabei in charakteristi- schen Mustern (Abläufen) im Kontrollfluss. Ein System, das einen Einzelfehler entdeckt, kann man beispielsweise dadurch realisieren, dass die kritischen Werte zweifach von diversitärer Software berechnet und danach verglichen wer- den. Je nach Ausgang des Vergleiches wird die Berechnung akzeptiert oder verworfen und eine entsprechende Fehlerbehandlung eingeleitet. Dabei ist wichtig, dass dieser Prozess (Voting) vor jeder Ausgabe oder anderen Verwendung eines aktualisierten oder neu berechneten kritischen Wertes stattfindet. Ist ein Pfad im Kontrollfluss vorhanden, der es ermöglicht, den Voting–Schritt auszulassen, so ist die gewünschte Architektur effektiv nicht realisiert. Die Prüfung des Kon- trollflusses auf Strukturen dieser Art ermöglicht daher Aussagen, ob in einem Programm ge- wünschte Fehlertoleranzarchitekturen implementiert sind oder nicht.

Recovery Blocks und Multiversion Programming In der Literatur werden verschiedene Techniken der expliziten Fehlertoleranz vorgeschlagen. Ziel aller dieser Techniken ist die Behebung der Effekte von Fehlerstellen (Fehlerzuständen), die nach der endgültigen Implementation noch im Programm vorhanden sind. Die Fehlertoleranz- techniken sollen also die korrekte Funktion des Systems trotz des Vorhandenseins von Ent- wurfsfehlern garantieren. Man kann drei grundsätzliche Ansätze unterscheiden: Benutzung einer Berechnungsvariante (single version techniques), Benutzung mehrerer Berechnungsvarianten (multiple version tech- niques) sowie diversitäre Datenrepräsentation (multiple data representation techniques). Bei nur einer Berechnungsvariante können nur relativ einfache und aus der Programmierung bekannte Techniken wie die Überprüfung von Zusicherungen oder Ausnahmebehandlungen zur Anwendung kommen. Bei mehreren Berechnungsvarianten ergeben sich verschiedene Möglich- keiten, die Berechnungsreihenfolgen der Varianten zu gestalten und die dadurch gewonnenen unterschiedlichen Ergebnisse zu bewerten und unter ihnen auszuwählen. Zwei häufig beschrie- bene Strukturen sind Multiversion Programming (MVP) (auch als N–Version Programming (NVP) bezeichnet) [3, 4, 7, 14, 44, 56] und Recovery Blocks (RB) [48, 59]. Die Fehlertoleranz- eigenschaften werden bei diesen Ansätzen durch systematischen Einsatz von Berechnungs- redundanz erreicht. Bei der diversitären Datenrepräsentation wird versucht, die Berechnung beim Auftreten von Fehlern mit „ähnlichen“ Daten zu wiederholen, bis ein Akzeptanztest ein korrektes Ergebnis anzeigt oder eine spezielle Fehlerbedingung (z.B. durch einen Watchdog ausgelöst) eingetreten ist. Diese ähnlichen Daten werden durch eine spezielle Datenvariations- funktion (data re–expression function) erzeugt, die Daten aus sog. Fehlerregionen des Eingabe- raums in Nichtfehlerregionen abbilden soll. Diese Technik eignet sich nur für Anwendungsbe- reiche, in denen Berechnungen auch auf ähnlichen Werten wie den originalen Eingabewerten ausgeführt dürfen (z.B. in bestimmten Anwendungen bei Sensordaten). Einen guten Überblick über den Themenkreis bietet [58].

48 4.1 Fehlertoleranzstrukturen module x { RECOVERY BLOCK ensure AT by B1 else by B2 ... else by Bn else error handler }

Abbildung 4.1: Recovery Block–Modul

module x { MVP BLOCK B1, B2, ... Bn VOTER voteproc error handler }

Abbildung 4.2: MVP–Modul

Hier sollen die Strukturen von Recovery Blocks und Multiversion Programming betrachtet wer- den. Recovery Blocks enthalten sequenziell angeordnete Codeblöcke, die jeweils die gleiche Funktion berechnen, dies aber möglichst auf unterschiedliche Weisen. Diese Blöcke werden nacheinander ausgeführt, bis ein Akzeptanztest ein gültiges Ergebnis anzeigt. In diesem Fall wird die Bearbeitung abgebrochen und nach dem Recovery Block fortgesetzt. Verläuft der Ak- zeptanztest dagegen negativ, werden die Auswirkungen des gerade ausgeführten Blocks zu- rückgenommen und der nächste Block ausgeführt. Kann kein Block mit korrektem Ergebnis ausgeführt werden, kommt eine Fehlerbehandlung zum Zug. Recovery Blocks werden schematisch wie in Abbildung 4.1 notiert. AT bezeichnet den Akzeptanztest, B1 bis Bn entsprechen den alternativen Programmblöcken und error handler der Fehlerbehandlungsroutine. Recovery Blocks dürfen verschachtelt sein, d.h. die alternativen Programmblöcke können selbst wieder Recovery Blocks sein. Beim Multiversion Programming werden die verschiedene Blockvarianten (parallel oder se- quenziell) ausgeführt und die gesammelten Ergebnisse einem Voting unterzogen.

49 4 Sichtgraphen und Architekturuntersuchung module nvsort{ MVP BLOCK quicksort(in A, out C) shellsort(in A, out D) insertionsort(in A, out E) VOTER majority(in C, D,E , out B) module rbsort{ RECOVERY BLOCK ensure B[j+1]>=B[j] for j = 1 to n-1 by quicksort(in A, out B) else by shellsort(in A, out B) else by insertionsort(in A, out B) else printError( no sort ) } }

Abbildung 4.3: Gemischte Fehlertoleranzarchitektur

Abbildung 4.2 zeigt die schematische Notation eines MVP–Moduls. Hier sind wieder B1 bis Bn die alternativen Berechnungsblöcke, voteproc steht für die Funktion, die das Voting über die Ergebnisse durchführt und error handler ist eine Fehlerbehandlungsroutine, die greift, wenn kein gültiges Votingergebnis erzielt werden konnte. Auch MVP–Blöcke dürfen geschach- telt sein. Bei beiden vorgestellte Techniken sollen die alternativen Blöcke zwar die gleiche Funktion berechnen, dies jedoch auf (möglichst) unterschiedliche Weise tun. Diesen Ansatz nennt man diversitär. Diversität führt nur dann zum gewünschten Ergebnis, wenn die unterschiedlichen Blockvarianten in Bezug auf Fehlererzeugung voneinander unabhängig sind. Verteilt man die Blöcke jedoch auf mehrere Hardwarekomponenten, kann man die Techniken zur Erkennung und Behebung von hardwareinduzierten Fehlern nutzen und auf die Diversität verzichten. Architekturen fehlertoleranter Programme dürfen beliebig geschachtelt werden und können da- bei entsprechend komplexere Formen annehmen. Abbildung 4.3 gibt mit dem Schema einer fehlertoleranten Sortierung ein einfaches Beispiel einer Architektur wieder, in der Recovery Block und Multiversion Programming geschachtelt vorkommen. Liefert das Voting des MVP ein Ergebnis, wird der Recovery Block nicht ausge- führt, ansonsten dient er als dessen Fehlerbehandlungsstrategie.

4.2 Zuverlässigkeitssicht

Die vorgestellten Fehlertoleranzarchitekturen spiegeln sich im Kontrollfluss ihrer Implementa- tionen. Abbildung 4.4 zeigt schematisch den Kontrollfluss von RB– und MVP–Systemen.

50 4.3 Pfade als Suchmuster

B1

Akzeptanztest

/* Akzeptanztest fehlgeschlagen */

B1

/* Akzeptanztest fehlgeschlagen */ /* Akzeptanztest erfolgreich */

Bn Bn /* Akzeptanztest erfolgreich */

Akzeptanztest voteproc

/* Akzeptanztest fehlgeschlagen */ /* Akzeptanztest erfolgreich */ /* Votieren ok */ /* Votierfehler */

Fehlerbehandlung Fehlerbehandlung

Abbildung 4.4: Kontrollflüsse Recovery Block und Multiversion Programming

Charakteristische Strukturen wie diese sind implizit in jedem Kontrollfluss eines Programms enthalten, das die entsprechende Fehlertoleranztechnik benutzt. Allerdings sind die Kontroll- flussgraphen von Anwendungsprogrammen normalerweise für eine direkte Analyse wenig ge- eignet, denn die gesuchten Kontrollflussmuster liegen in der Regel nicht in reiner Form vor, sondern sind in andere Strukturen eingebettet und von Anweisungen durchsetzt, die für die Fehlertoleranz irrelevant sind. Wenn man allerdings die Kontrollflusselemente (Anweisungen, Funktionen, Funktionsaufrufe, Unterroutinen usw.) kennt, die die Fehlertoleranz ermöglichen, kann man sie als Knoten–Auswahlmenge eines Sichtgraphs benutzen und die Zuverlässigkeits- sicht des Softwaresystems berechnen, in der die irrelevanten Teile nicht mehr enthalten sind. Zumindest in der Implementationsphase sollten die fehlertoleranzrelevanten Elemente bekannt sein. Zuverlässigkeitsgraphen selbst können – entsprechend den Schachtelungsmöglichkeiten der Ar- chitekturen – Schachtelungen mehrerer Zuverlässigkeitsmuster sein. Abbildung 4.5 zeigt den Zuverlässigkeitsgraph eines Programms mit der geschachtelten Architektur von Abbildung 4.3.

4.3 Pfade als Suchmuster

Aus der Zuverlässigkeitssicht kann man durch Prüfung auf die entsprechenden Muster die Fehlertoleranzarchitektur einer gegebenen Software bestimmen. Für die Analyse müssen Ein- bettungsprobleme gelöst und Obergraph–Teilgraph–Relationen zwischen Teilsuchmustern und Zuverlässigkeitsgraph geprüft werden. Bereits das Vorhandensein eines Teilgraphs in einem anderen Graph ist im Allgemeinen nur teuer zu berechnen, das Problem fällt in die Zeitkom- plexitätsklasse NP. Wenn es allerdings gelingt, die gesuchten Teilgraphen auf Pfade von einem ausgezeichneten Initialknoten des Graphen zu beschränken, die bestimmte Anforderungen hin- sichtlich ihrer Knotenreihenfolgen erfüllen müssen, ist das Teilgraphmatching schon durch die kostengünstigere Pfadsuche realisierbar.

51 4 Sichtgraphen und Architekturuntersuchung

quicksort

shellsort

insertionsort

voter

quicksort

ensure

shellsort

ensure

insertionsort

ensure

printError print

Abbildung 4.5: Geschachtelte Zuverlässigkeitsmuster

Neben einer Handimplementation der Pfadsuche kommt dabei auch die Benutzung von Werk- zeugen des Model Checking in Betracht. Spezifiziert man die entsprechenden Pfade mit der Temporallogik CTL, ist diese Berechnung mit (maximal) quadratischem Aufwand im Bezug zur Knotenzahl des Graphen implementierbar [42]. Dieser Weg wird im folgenden Anwen- dungsbeispiel beschritten.

4.4 Strukturanalyse mit mcana und SMV

In diesem Abschnitt wird an einem Beispiel gezeigt, wie man die oben beschriebene Ana- lysemethode auf Programme des Microcontrollers MC68HC705J1A von Motorola anwenden kann. Dabei kommen das Analysewerkzeug mcana [30] und der Computation Tree Logic– Modelchecker (CTL–Modelchecker) SMV [52] zum Einsatz. Mit mcana werden aus den Pro- grammen Zuverlässigkeitsgraphen berechnet, die dann durch SMV auf charakteristische Pfade der MVP–Architektur geprüft werden.

52 4.4 Strukturanalyse mit mcana und SMV

Zunächst wird im Folgenden das Werkzeug mcana vorgestellt, danach die Strukturanalyse an einem praktischen Beispiel demonstriert.

4.4.1 Das Werkzeug mcana

Um die Arbeit mit Sichtgraphen in der Praxis zu erproben, wurde das Werkzeug mcana ge- schaffen, das beliebige Sichtgraphen aus Assemblerprogrammen für den Microcontroller Mo- torola MC68HC705J1A berechnet, der einen Acht–Bit–CPU–Kern, einige Peripherie wie Ti- mer und E/A–Bausteine sowie kleine EPROM– und RAM–Speicher auf einem Chip verei- nigt [53]. Das Werkzeug wurde als Zusatzmodul zum (ebenfalls am Lehrstuhl 3 implemen- tierten) vollständigen Simulator dieses Microcontrollers, mcsim, realisiert. mcana berechnet die gewünschten Sichtgraphen direkt aus dem Maschinencode des Programms im simulierten Speicher. Daher wird kein Quellcode benötigt. Zur Bestimmung der gewünschten Sicht können beliebige Opcodes, Aufrufe von Unterroutinen sowie Zugriffe auf bestimmte Speicherbereiche als Elemente der Sichtgraph–Auswahlmenge bestimmt werden. Neben Sichtgraphen kann mcana auch Kontrollflussgraphen bestimmen und besitzt Zusatz- funktionen zur präsentationsgerechten Aufbereitung der berechneten Graphen. Für die Zu- verlässigkeitsanalyse wurde das Werkzeug zur Generierung spezieller Zuverlässigkeitsgraphen konfiguriert.

4.4.2 Pfadsuche

Man kann durch Graphtraversierung, beispielsweise mittels Breitensuche, leicht feststellen, ob ein Zuverlässigkeitsgraph einen bestimmten Pfad enthält oder nicht. Allerdings ist das Verfah- ren nicht sehr flexibel, weil für jeden Pfad ein spezielles Programm formuliert werden muss. Es gibt einige Ansätze, Pfade mit formalen Sprachen zu beschreiben und solche Pfadspezifika- tionen als Eingabe eines Suchalgorithmus zu benutzen. Neben Werkzeugen, die grafische oder SQL–ähnliche Pfadspezifikationen als Basis der Suche in explizit gespeicherten Graphen benut- zen [15, 17, 25], gibt es mit Temporallogiken und dem damit verbundenen Berechnungsparadig- ma Model Checking einen Ansatz, Pfade implizit und unvollständig über Struktureigenschaften (Abfolgen bestimmter Knoten, ohne konkret Pfadexemplare anzugeben) zu beschreiben und in Graphen suchen zu lassen. Bei der Speicherung der Graphen werden dabei in der Regel kompri- mierende Verfahren, beispielsweise Binary Decision Diagrams (BDD) benutzt. Im unten vorge- stellten Beispiel kommt mit dem CTL–Modelchecker SMV ein entsprechendes Werkzeug zum Einsatz.

Model Checking Jeder gerichtete Graph kann als Kripke–Struktur interpretiert werden, die Basis des CTL–Model Checking.

53

4 Sichtgraphen und Architekturuntersuchung

¡

¢ £ Eine Kripke–Struktur ist ein Tripel M S ¢ R Label mit einer nichtleeren Zustandsmenge S, ei- ner totalen Relation R über S, die den Elemente von S mögliche Nachfolger zuordnet, und einer Funktion Label, die jedem Zustand atomare Propositionen (Wahrheitswerte von Eigenschafts- variablen) zuordnet. Sichtgraphen bildet man in Kripke–Strukturen ab, indem man jeden Kno- ten als einen Zustand aus S interpretiert und mittels R jeder Anweisung ihre möglichen Nach- folger im Sichtgraph zuordnet. Label soll für die Analyseanwendung jeder Anweisung einen Anweisungstyp–Bezeichner, wie etwa PRINT, IF oder quicksort (letzteres ein Funktions- aufruf) zuordnen. Ein Sichtgraph enthält nur noch Knoten, die durch Anweisungen aus seiner Auswahlmenge markiert sind. Eine aus einem Zuverlässigkeitsgraph gebildete Kripke–Struktur markiert daher die Zustände durch Label ausschliesslich mit Bezeichnern von Anweisungsty- pen, die die Fehlertoleranz realisieren. Man kann charakteristische Pfade für spezielle Fehlertoleranzarchitekturen mit CTL–Formeln beschreiben. Eine wichtige Anforderung an eine MVP–Architektur ist beispielsweise, dass kri- tische Werte nie vor der Freigabe durch ein Voting verwendet werden dürfen. Diese Eigenschaft ist durch eine einfache CTL–Formel charakterisierbar, die die gültigen Reihenfolgen der Vor- gänge „Votieren“ und „Benutzen“ beschreibt. Wird diese Formel von SMV in einem Zuverläs- sigkeitsgraph als gültig angesehen, liegt die gewünschte Eigenschaft vor und der Zuverlässig- keitsgraph (und damit das untersuchte Programm) genügt der spezifizierten MVP–Anforderung. Gibt SMV dagegen ein Gegenbeispiel aus, existiert mindestens ein Pfad (und damit ein Be- rechnungsweg), der die MVP–Anforderung verletzt. Damit kann sicher ausgeschlossen werden, dass das Programm der MVP–Architektur entspricht. Seien Anweisungen des Typs USE diejenigen, die kritische Werte benutzen, VOTER die Vo- tieranweisung. Die genannte MVP–Eigenschaft wird dann abstrakt mit der einfachen CTL–

Formel

E[ VOTER U USE ] beschrieben. Dieses CTL–Formelmuster wird im nächsten Abschnitt benutzt, um das Auffinden von MVP–Strukturen an einem konkreten Programmbeispiel zu demonstrieren.

4.4.3 Fallbeispiel

Das kleine Programm in Abbildung 4.6 soll Messergebnisse von einer externen Quelle anneh- men, sie mit 2 multiplizieren und dieses Ergebnis (und ggfs. eine Fehlermeldung) ausgeben. Die Multiplikation soll dabei durch eine MVP–Architektur (2–aus–3–Voting) geschützt sein. Der Code der Ein– und Ausgaberoutinen spielt bei der Analyse keine Rolle und wurde daher nicht wiedergegeben. Bereits dieses kleine Programm hat einen Kontrollfluss einiger Komplexität. Abbildung 4.7 zeigt den entsprechenden Kontrollflussgraph (inklusive Aufrufkanten von Unterroutinenaufru- fen zu Unterroutineneinsprüngen; aus Gründen der Übersichtlichkeit wurden einige Teilgraphen für Unterroutinen entfernt).

54 4.4 Strukturanalyse mit mcana und SMV

ORG RAM ;Declaration of Variables voteValueA RMB 1 ;address of sort result voteValueB RMB 1 ;address of sort result voteValueC RMB 1 ;address of sort result Temp RMB 1 ;temporary variable measurementResult RMB 1 ;result of measurement

ORG ROM ;Program (and const) Start: JSR getMeasurement STA measurementResult ; store measured value in RAM JSR multiplyByTwo1 STA voteValueA LDA measurementResult JSR multiplyByTwo2 STA voteValueB LDA measurementResult JSR multiplyByTwo3 STA voteValueC ; set cursor to pos 7 row 2 LDA #$80+$47 JSR sendcom JSR voter finish: JSR display ; check whether voting failed BEQ failure JMP STArt failure: JSR failureDisplay RTS multiplyByTwo1: ; use cpu multiplier for arithmetic LDX #2 MUL RTS multiplyByTwo2: ; use cpu shifter for arithmetic ASLA RTS multiplyByTwo3: ; use cpu adder for arithmetic STX Temp ADD Temp RTS voter: LDA voteValueA CMP voteValueB BEQ finishVoting CMP voteValueC BEQ finishVoting LDA voteValueB CMP voteValueC BEQ finishVoting LDA #0 ; indicate error finishVoting: RTS

Abbildung 4.6: Untersuchtes Programm

55 4 Sichtgraphen und Architekturuntersuchung

0300 cd JSR $034c

0303 b7 STA $00c4

0305 cd JSR $032e

0308 b7 STA $00c0

030a b6 LDA $00c4

030c cd JSR $0332

030f b7 STA $00c1

0311 b6 LDA $00c4

0313 cd JSR $0334

0316 b7 STA $00c2

0318 a6 LDA #$0

031a cd JSR $034d

031d cd JSR $0339

0320 cd JSR $034e

0323 27 BEQ $0328

0328 cd JSR $034f 0325 cc JMP $0300

032e ae LDX #$0 0332 48 ASLA 0334 bf STX $00c3 034d 81 RTS 0339 b6 LDA $00c0 034f 81 RTS 032b 81 RTS 034e 81 RTS 034c 81 RTS

0330 42 MUL 0333 81 RTS 0336 bb ADD $00c3 033b b1 CMP $00c1

0331 81 RTS 0338 81 RTS 033d 27 BEQ $034b

033f b1 CMP $00c2

0341 27 BEQ $034b

0343 b6 LDA $00c1

0345 b1 CMP $00c2

0347 27 BEQ $034b

0349 a6 LDA #$0

034b 81 RTS

Abbildung 4.7: Kontrollflussgraph des untersuchten Programms

56 4.4 Strukturanalyse mit mcana und SMV

Die Auswahlmenge des Zuverlässigkeitsgraphen bestand aus den für die vorliegende Un- tersuchung relevanten Routinenaufrufen von getMeasurement, vote, display und failureDisplay. Wie man sieht, liest das Programm Messwerte, gibt etwas aus und wie- derholt diese Abfolge oder beendet sich nach zusätzlicher Ausgabe eines Fehlers. Es ergibt sich der Zuverlässigkeitsgraph in Abbildung 4.8 (zur besseren Lesbarkeit wurden die aufrufenden JSR–Anweisungen durch die Namen der Routinen ersetzt). Für die Pfadprüfung entspricht der Aufruf von display der Benutzung des geschützten Wertes (dem Multiplika- tionsergebnis), der Aufruf von vote entspricht dem Votierschritt. Zusammen mit der entspre- chend angepassten CTL–Formel aus Abschnitt 4.4.2 entsteht das SMV–Eingabeprogram aus Abbildung 4.9. Bei der Erstellung des SMV–Programms ist zu beachten, dass Endzustände mit einem Nachfolgeübergang zu sich selbst ausgestattet werden müssen, um die Nachfolgerelation der Kripke–Struktur total zu halten, wie hier bei failureDisplay geschehen. Es ist nicht schwierig, dem SMV–Modell anzusehen, dass die MVP–Anforderung „kein display vor vote“ erfüllt ist. Entsprechend liefert SMV die Ausgabe

-- specification !E[ cfg != vote U cfg = display ] is true

Bestimmte Entwurfsfehler werden im Zuverlässigkeitsgraph unmittelbar abgebildet. Die Än- derung der Hauptroutine in Abbildung 4.10 fällt dagegen im Code kaum auf: Die aufeinan- derfolgenden Aufrufe von display und voter wurden vertauscht. Fehler dieser Art sind – besonders bei „cut–and–paste“–Programmiervorgehen – nicht selten. Das Programm wird nur minimal verändert, der Fehler kann leicht übersehen werden. Allerdings verändert er bereits

den Zuverlässigkeitsgraph, wie in Abbildung 4.11 zu sehen ist.

Im Zuverlässigkeitsgraph existiert der Pfad getMeasurement ¦ display, durch den die MVP–Eigenschaft verletzt ist. SMV findet den Fehler und gibt ihn mit folgender Ausgabe wieder:

-- specification !E(cfg != vote U cfg = display) is false -- as demonstrated by the following execution sequence state 1.1: cfg = getMeasurement state 1.2: cfg = display

Eine weitere fehlerbehaftete Version der Hauptroutine in Abbildung 4.12 enthält einen über- flüssigen Sprungbefehl. Dieser könnte z.B. in einer Testphase eingefügt und später „vergessen“ worden sein.

Der Zuverlässigkeitsgraph weist wieder den verletzenden Pfad

getMeasurement ¦ display auf, der durch den fehlerhaften Sprung erzeugt wird, wie am SMV–Modell in Abbildung 4.13 zu sehen ist.

57 4 Sichtgraphen und Architekturuntersuchung

getMeasurement

vote

display

failureDisplay

Abbildung 4.8: Zuverlässigkeitsgraph

MODULE main

VAR cfg: { getMeasurement, vote, display, failureDisplay };

ASSIGN init( cfg ) := getMeasurement; next( cfg ) := case cfg = getMeasurement : vote; cfg = vote : display; cfg = display : { getMeasurement, failureDisplay }; cfg = failureDisplay : failureDisplay; esac;

SPEC !E[ cfg != vote U cfg = display ]

Abbildung 4.9: SMV–Eingabe

58 4.4 Strukturanalyse mit mcana und SMV

start: JSR getMeasurement STA measurementResult JSR timesTwo1 STA voteValueA LDA measurementResult JSR timesTwo2 STA voteValueB LDA measurementResult JSR timesTwo3 STA voteValueC ; set cursor to pos 7 row 2 LDA #$80+$47 JSR sendcom ; ** vertauscht: Voting und Anzeige JSR display JSR voter ; check whether voting failed BEQ failure JMP start failure: JSR failureDisplay RTS

Abbildung 4.10: Entwurfsfehler (1)

getMeasurement

display

vote

failureDisplay

Abbildung 4.11: Zuverlässigkeitsgraph nach Änderung (1)

59 4 Sichtgraphen und Architekturuntersuchung

start: JSR getMeasurement BNE finish ; ** falscher Sprung STA measurementResult JSR timesTwo1 STA voteValueA LDA measurementResult JSR timesTwo2 STA voteValueB LDA measurementResult JSR timesTwo3 STA voteValueC ; set cursor to pos 7 row 2 LDA #$80+$47 JSR sendcom JSR voter finish: JSR display ;check whether voting failed BEQ failure JMP start failure: JSR failureDisplay RTS

Abbildung 4.12: Entwurfsfehler (2)

60 4.5 Diskussion

getMeasurement

vote

display

failureDisplay

Abbildung 4.13: Zuverlässigkeitsgraph nach Änderung (2)

Entsprechend liefert SMV:

-- specification !E(cfg != vote U cfg = display) is false -- as demonstrated by the following execution sequence state 1.1: cfg = getMeasurement state 1.2: cfg = display

Interessanterweise führt hier die mit der Sichtgrapherzeugung verbundene Abstraktion zum gleichen Gegenbeispiel für zwei (sehr) unterschiedliche Programmierfehler.

4.5 Diskussion

Eine Softwareuntersuchung nach dem vorgestellten Ansatz kann nicht nur eine Analyse von Altsystemen im Rahmen von Reengineering–Massnahmen unterstützen, sondern auch schon während Entwurf und Implementation helfen, Fehler zu vermeiden. Dies wurde bereits am Fallbeispiel deutlich. Der skizzierte Prozess zur Aufdeckung der eingefügten Entwurfsfehler ist weitgehend automatisierbar und benötigt kaum nennenswerte Rechnerressourcen. Auch bei grösseren Programmsystemen kann dies erwartet werden, da die Zustandszahl der Sichtgraphen immer kleiner oder gleich der Anzahl der Anweisungen ist und daher auch bei sehr grossen Systemen im Millionen–Codezeilen–Bereich nicht zu explodierenden Zustandsräumen, dem Hauptproblem beim Model Checking, führt. So kann man bereits in frühen Entwicklungspha- sen ohne grosse Kosten absichern, dass bestimmte Prinzipien der Fehlertoleranz (oder auch an- dere strukturbasierte Kriterien) nicht durch Entwurfs– oder Implementationsfehler unterlaufen werden, die bereits anhand der Kontrollflussstruktur erkennbar sind.

61 4 Sichtgraphen und Architekturuntersuchung

Prinzipiell problematisch ist die exakte Formalisierung der essentiellen Eigenschaften einer Ar- chitektur. Bis heute existieren keine einheitlichen formalen Methoden der Architekturbeschrei- bung. Eine Vielzahl von Ansätzen beschreibt jedoch einzelne Architekturaspekte. Dazu gehö- ren alle Mittel und Vorgehensmodelle des Entwurfs, von einfachen, nichtformalen Beschrei- bungen und Line–Box–Diagrammen über formalisierte Implementationskonzepte wie Design Patterns [26] bis hin zu komplexen Paradigmen wie der UML [29]. Eine allgemeine Forma- lisierung – scheinbar – wohl bekannter Architekturkonzepte wie Client–Server–Modell oder Pipeline–Architektur ist jedoch auch mit solchen Methoden problematisch [63]. Der enge Ar- chitekturbegriff für Software umfasst hauptsächlich die Beziehungen zwischen Modulen [63]. Im wesentlichen sind dies strukturelle Informationen, wie Aufrufhierarchien, Inklusionsstruktu- ren und Datenflüsse. Die darauf basierenden Methoden zielen im Allgemeinen auf die Bestim- mung kleiner Architektureinheiten, die kompositional zu grösseren Architekturbeschreibungen zusammengefügt werden. Andere Vorgehensweisen versuchen, Codeteile zu bestimmen, die an gewissen Anwendungsszenarien (Features) beteiligt sind [22]. Die im Vergleich zur Softwa- rearchitektur umfassenderen Begriffe Rechnerarchitektur und Systemarchitektur decken in der Regel neben rein strukturellen Zusammenhängen von (Hard– oder Software–) Komponenten auch Verfahren ab [19], wie etwa den Ablauf der Befehlsdekodierung und –ausführung sowie Speichermodelle und Kommunikationsprotokolle oder auch die in diesem Kapitel behandelten Fehlertoleranzmassnahmen. Diese zusätzliche dynamische Charakterisierung prägt die Archi- tekturmodelle in der Regel entscheidend und bietet in der Regel – trotz mangelnder Formalisie- rung – unstrittige Hinweise, wie die beschriebenen Architekturen zu prüfen sind. Dies ist auch der Ausgangspunkt für die in diesem Kapitel demonstrierte Anwendung, in der die notwen- digen dynamischen Systemzusammenhänge erst gezielt herauspräpariert und dann untersucht werden.

62 5 Unterstützung beim Testentwurf

In den vorherigen Kapiteln wurde die Analyse von Kontrollflüssen mit Hilfe von Sichtgraphen vorgestellt. Dabei wurde bereits in Kapitel 3 klar, dass die Güte von Testfällen stark variiert und mittels Sichtgraphen ein Qualitätsmass definiert werden kann. Als natürliche Fragestellung ergibt sich, ob die Berücksichtigung solcher Qualitätskriterien bereits beim Entwurf von Test- fällen möglich ist. Dieses Kapitel greift die Frage auf und gibt die Antwort für einen speziellen Anwendungsfall. Es beschreibt die Generierung (abstrakter, nicht mit Werten instanziierter) Testfälle aus automatenbasierten Spezifikationen anhand der Auswahl einer Menge relevanter Zustände. Dabei kommt, wie in Kapitel 4, der Modelchecker SMV zum Einsatz.

5.1 Rechnergestütztes Testen

Validierung und Verifikation sind aufwändige Phasen jeder Systementwicklung und nehmen in ihrer Summe einen grossen Teil des Entwicklungszyklus in Anspruch [29]. Daher wird tradi- tionell – und seit einigen Jahren verstärkt – versucht, die damit verbundenen Arbeitsabläufe zu formalisieren und soweit wie möglich mit automatisierten Methoden zu unterstützen. Neben der bereits in Kapitel 3 beschriebenen Bewertung von Testfällen, die letztlich einer nachgeschalteten Bewertung des Testprozesses entspricht, gewinnt die automatisierte Unter- stützung der Testdurchführung an Bedeutung. Kernstück ist neben einem geeigneten Vorge- hensmodell der Einsatz spezieller Softwarewerkzeuge. Dieses softwaregestützte Vorgehen wird sowohl beim Software– als auch beim Hardwareentwurf eingesetzt. Hardwaresysteme können heute, zumindest im digitalen Fall, in einer simulierbaren Modellierungssprache wie VHDL entworfen werden, bevor man sie physisch realisiert. Dieses Vorgehen hat den Vorteil, dass man wesentliche Funktionsprüfungen bereits vor der konstenintensiven Hardwareproduktion durch- führen kann. Software und Hardware werden sich dadurch aus der Validierungs– und Verifikati- onsperspektive ähnlicher, so dass für die entwicklungsbegleitende Prüfung ähnliche Methoden zum Einsatz kommen können (allerdings ist bei Hardwaresystemen noch ein beträchtlicher Auf- wand für die Prüfung des Endproduktes, der physischen Hardware, zu betreiben).

63 5 Unterstützung beim Testentwurf

Die zur Validierung und Verifikation eingesetzten Softwarewerkzeuge sind meistens für einen bestimmten Anwendungskontext, etwa das Testen grafischer Benutzeroberflächen, entworfen. Sie unterstützen den Tester bei mehreren Aufgaben. Zum einen soll eine auf die Testaufgabe abgestimmte Infrastruktur das Testen erleichtern. Dazu gehört eine Umgebung, die das kontrol- lierte Ausführen des zu testenden Systems ermöglicht. Neben einer möglichst realitätsgetreuen Nachbildung der späteren Einsatzumgebung muss eine Möglichkeit geboten werden, das zu tes- tende System über alle vorgesehenen Schnittstellen mit Eingaben zu versorgen und Ausgaben entgegenzunehmen. Die meisten Werkzeuge bieten die Möglichkeit, mithilfe einer Skriptspra- che oder Menusteuerung Testfälle (als Ein–/Ausgabesequenzen) vorzuformulieren und die ent- sprechenden Testläufe unbeaufsichtigt durchzuführen. Die Resultate werden protokolliert und stehen dann einer späteren Analyse zur Verfügung. Zusätzliche Archivfunktionen erleichtern spätere Regressionstests. Weitergehende Ansätze versuchen, auch die Formulierung der Testfälle zu automatisie- ren (z.B. [1, 2, 27, 40, 43, 55]). Dabei kommen strukturbasierte oder heuristische Verfahren zum Einsatz. Deren Ziel ist häufig das Erreichen eines vorgegebenen Parameterwertes, etwa eines bestimmten Grades an Codeabdeckung (oft Anweisungs– oder Verzweigungsabdeckung). Die Relevanz der einzelnen Testfälle wird in solchen rein quantitativen Ansätzen nicht bewertet. Die automatische Generierung der Testfälle wirft daher Kritikpunkte auf [5], während die Un- terstützung der Testinfrastruktur in der Regel positiv gesehen wird. Auch wenn es kaum empiri- sche Daten zur Fehleraufdeckungsfähigkeit automatisch generierter Testfälle gibt, rechnet man im allgemeinen mit einer geringeren Aussagekraft als bei manuell erstellten Tests [57]. Dane- ben besteht die Gefahr der kritiklosen Akzeptanz eines weitgehend automatisierten Testablaufs, die zu der falschen Annahme führen kann, dass keine Fehler vorhanden sind. Dies betrifft je- doch nicht nur den Test mit automatisch generierten Testfällen, sondern auch andere Bereiche, in denen vermeintlich Arbeit und Zeit gespart werden kann. Ein Beispiel ist die unkritische Übernahme von Regressionstests ohne vorherige Prüfung, ob diese Tests bei einem neuen oder modifizierten System noch die gewünschte Funktion prüfen. Die Gefahr des Scheiterns von Testprojekten aus solchen eher psychisch motivierten Gründen ist als sehr hoch anzusehen [5].

5.2 Generierung von Testentwürfen aus Spezifikationsautomaten

Auch wenn Ansprüche auf vollautomatische Lösungen kritisch zu sehen sind, erscheint eine Rechnerunterstützung beim manuellen Entwurf von Testfällen sinnvoll. In diesem Abschnitt wird an einem Beispiel illustriert, wie man einem Tester automatisch grobe Vorgehensvorschlä- ge unterbreiten kann, die er selbst zu Testfällen konkretisiert. Der Ansatz kann den Testprozess nicht voll automatisieren. Er soll vielmehr zeigen, dass mit einfachen Mitteln bereits unterstüt- zende Massnahmen realisierbar sind.

64 5.2 Generierung von Testentwürfen aus Spezifikationsautomaten

Zunächst wird die formale Spezifikationssprache ADeVA (Advanced Design and Verification of Asics) vorgestellt, mit der parallele Zustandsautomaten in einer tabellarischen Form spezifiziert werden können. Dann wird gezeigt, wie man unter Vorauswahl verifikationsrelevanter Zustände zu einer Menge von Ablaufpfaden kommt, die als Entwurfsvorschläge für spätere Testfälle von Implementationen dienen. Der Tester kann durch die Auswahl der Zustände bei der Testent- wurferzeugung in ähnlicher Weise Akzente setzen wie in der sichtgraphbasierten Analyse. Der Ansatz versucht damit, die Stärken des automatischen Testentwurfs (schnelle Analyse komple- xer Systeme) mit denen des manuellen (kompetente Auswahl geeigneter Tests) zu kombinieren.

5.2.1 ADeVA

Die tabellenbasierte formale Spezifikationssprache ADeVA [34] wurde im Rahmen des BMBF– geförderten Projektes IP2 (Intellectual Property Prinzipien für konfigurierbare Basisband SoCs in Internet–Protokoll basierten Mobilfunknetzen) als Basis eines neuen Entwurfsprozesses für ASIC–basierte Telekommunikationssysteme entwickelt. Die Sprache orientiert sich an den Be- dürfnissen der Telekommunikationsindustrie und entstand aus einer Kooperation der Universi- tät Erlangen–Nürnberg mit Lucent Technologies. Bei der Entwicklung von ADeVA stellte sich vornehmlich die Aufgabe, die Interaktion von Systemkomponenten auf höherem Abstraktions- niveau einfach spezifizierbar zu machen. Dazu wurden verschiedene Spezifikationsparadigmen untersucht und schliesslich ein Ansatz favorisiert, der Elemente der Sprachen Software Cost Reduction (SCR) [39] und Requirements State Machine Language (RSML) [50] kombiniert. Die Semantik von ADeVA ist formal über parallel arbeitende Zustand/Übergang–Systeme defi- niert [33]. Die Spezifikation mit ADeVA ist in einen speziellen Entwicklungs–Workflow eingebunden. ADeVA–Spezifikationen werden nach ihrer Validierung in einem halbautomatischen Prozess in prototypische VHDL–Implementationen umgesetzt und diese zur Produktimplementation wei- ter manuell verfeinert. Am fertig implementierten System werden in einer nachgeschalteten Verifikationsphase Tests durchgeführt, die die Realisierung der gewünschten Funktionen und damit die Konsistenz von Produktbeschreibung, formaler Spezifikation und Implementation si- cherstellen sollen.

Syntax ADeVA besteht im wesentlichen aus zwei Arten von Tabellen und einer Methodik, mit der externe, ausserhalb der ADeVA–Methodik spezifizierte Module (Fremdkomponenten, datenin- tensive Subsysteme) integriert werden können. Hier werden nur die Tabellen kurz vorgestellt.

65 5 Unterstützung beim Testentwurf

current mode AIS INI=0 CPUread PwrStable next mode monitor F @T – – unequipped wait – – – T monitor monitor F F – – latch latch F @T – – unequipped latch – – @T – monitor unequipped F @F – – monitor

Abbildung 5.1: Mode Transition Table für Signal current mode

byteState=stable @T @T – errorRecovery=off – T F AIS F F T byteMON data in data in byteVAL

Abbildung 5.2: Data Transformation Table für Signal byteMON

Eine Mode Transition Table (MTT) beschreibt explizit Zustandsübergänge bzw. Wertewech- sel von Signalen. In der Beispieltabelle aus Abbildung 5.1 wird das Verhalten des Signals current mode beschrieben (Initialzustand unterstrichen). Die zweite Zeile kann als folgen- des VHDL–ähnliches–Fragment interpretiert werden: 1

if (CURRENT_MODE=MONITOR) and (AIS=FALSE) and (INI=0) and (INI’event) then NEXT_MODE <= UNEQUIPPED; end if;

Spaltenwerte stehen für Wahrheitswerte der Bedingung oder deren Wechsel (Ereignisse): T für wahr, F für falsch und – für „don’t care“. Ein zusätzliches @– Symbol zu T oder F steht für einen Wahrheitswertwechsel zu wahr bzw. falsch. Data Transformation Tables (DTT) werden spaltenweise gelesen und beschreiben den Werte- wechsel eines digitalen Signals (in Beispieltabelle aus Abbildung 5.2 das Signal byteMON). Dabei wird implizit angenommen, dass Zustandswechsel von jedem Zustand in jeden Zustand unter der jeweiligen Bedingung möglich sind.

1Bemerkung: Die Bedingung INI=0 ist im Bezug auf ein externes Signal INI definiert.

66 5.2 Generierung von Testentwürfen aus Spezifikationsautomaten

Die zweite Spalte des Beispiels kann VHDL–ähnlich wie folgt notiert werden: if (BYTESTATE=STABLE) and (BYTESTATE’event) and (AIS=FALSE) then BYTEMON <= DATA_IN; end if;

Mit specedit [34] wurde vom Projektpartner ein Werkzeug zur Eingabe und Pflege von ADeVA– Spezifikationen entwickelt, welches zusätzlich verschiedene Konsistenzprüfungen vornimmt und VHDL–Code erzeugt.

Semantik Die Semantik von ADeVA beruht im wesentlichen auf der Interpretation der Tabellen als paral- lele Zustand/Übergang–Systeme [33]. Jeder Tabelle liegt dabei ein deterministischer endlicher Automat zugrunde, dessen Zustände durch die Modes (MTT) beziehungsweise mögliche Zu- weisungswerte (DTT) bestimmt werden. Da die Automaten (Tabellen) über Abfragen der Zustände anderer Automaten gekoppelt sind, ist eine Auflösung der Ereigniszellen (mit „@“–Bedingungen versehene Bedingungen) notwen- dig. Diese wird in [33] über eine Potenzmengenkonstruktion definiert, die die ereignisbehafteten Kanten auflöst und zusätzliche Zustände (trigger states) einführt. Für das später in diesem Ka- pitel vorgestellte Werkzeug Guwen wurde eine andere semantische Fundierung gewählt (über zusätzliche Speichersignale), die aber implizit zu äquivalenten Zustandsräumen führt und somit semantisch identisch ist.

5.2.2 Generierung von Testentwürfen

Die Idee, aus automatenbasierten Spezifikationen Testentwürfen in Form von Pfaden durch den Automatengraph abzuleiten, ist nicht neu. Betrachtet wird der Konformitätstest, bei dem eine Implementation gegen eine Spezifikation auf Konsistenz getestet wird. Obwohl der Themen- kreis im Zusammenhang mit der Verifikation sequentieller Schaltkreise bereits in den siebziger Jahren des 20. Jahrhunderts erstmals untersucht wurde, erfuhr er erst mit dem Aufkommen der formalen Protokollspezifikation in den späten achtziger Jahren eine grössere Beachtung. Dabei wurden zunächst Teststrategien diskutiert, bei denen systematisch Mutanten der ursprünglichen Automatenspezifikation erzeugt werden, deren Verhalten dann simulativ gegen das Implemen- tationsverhalten getestet wird [13]. Dieser Methode liegt stets ein Modell der zu entdeckenden Fehler zugrunde, die in entsprechende Mutationstests umgesetzt werden, d.h. für jeden betrach- teten Fehler wird ein aufdeckendender Test generiert, der auf einer gezielten Veränderung des Spezifikationsautomaten basiert. Neuere Publikationen favorisieren häufiger ein Vorgehen, das ohne Fehlermodell auskommt und auf der Erfüllung nicht–mutationsbezogener Abdeckungs- metriken über Automaten basiert (beispielsweise [28, 40, 43]) oder beide Methoden kombi- niert [2].

67 5 Unterstützung beim Testentwurf

Die diskutierten Strategien erzeugen entweder Tests auf bekannte Fehler (bei Mutationstests ba- sierend auf Fehlermodell) oder unspezifische Testpfade, die gewisse Abdeckungskriterien erfül- len (bei den zuletzt beschriebenen Methoden). Zum gezielten Auffinden unbekannter Fehler in wichtigen Komponenten ist die erste Herangehensweise wenig geeignet, bei der zweiten besteht die Gefahr, dass zu viele Testfälle erzeugt werden, von denen ein grosser Teil als nicht relevant anzusehen ist. Ausserdem kann bei ungeeigneter Auswahl von Testfällen die gewünschte Abde- ckung erreicht werden, ohne dass „interessante“ Spezifikationsteile (etwa die Hauptfunktionen) besonders berücksichtigt werden. ADeVA–Spezifikationen entsprechen einer Menge paralleler endlicher Automaten. Eine Imple- mentation muss im wesentlichen dieselben Kontrollflussstrukturen aufweisen wie die zugrun- deliegende Spezifikation. Daher kann die Spezifikation als Testgrundlage dienen, indem Pfade durch den Gesamtzustandsraum der ADeVA–Spezifikation ausgewählt und als Testentwürfe in- terpretiert werden. Prinzipiell stellt sich jedoch immer das Problem der Auswahl geeigneter Pfade. Eine rein zufällige Auswahl scheint nicht zufriedenstellend (s.o). Aber welche Pfade sind „geeignet“ ? Eine Betrachtung der industriellen Verifikationspraxis zeigt, dass geforderte Systemeigenschaf- ten oft geprüft werden, indem man das System bis zu einem spezifischen Zustand (etwa Fehler- anzeige oder Erreichen einer Zählergrenze) simuliert, dabei das Verhalten beobachtet und be- urteilt, ob die gewünschte Funktion erfüllt wird oder nicht [12, 37]. Normalerweise entspricht dabei ein solcher Zielzustand genau einer zu erfüllenden Systemeigenschaft, die manuell in je einem separaten Testlauf geprüft wird. Die Pfade zwischen initialen Systemzuständen und Zielzuständen sind also offensichtlich zum Testen geeignet. Durch die Untersuchung des Zustand–/Übergang–Graphen der Spezifikation kann man Pfa- de bestimmen, die von einem Ausgangszustand des Systems über alle gewählten Zielzustände führen. Eine Lösung ist im Allgemeinen eine Menge von Pfaden, da es möglicherweise kei- nen Einzelpfad gibt, der alle gewünschten Zustände abdeckt. Die Menge der Zielzustände kann man als die Auswahlmenge einer Testsicht der Spezifikation auffassen. Die gewünschte Lösung besteht aus Pfaden durch den Gesamtzustandsraum und sollte 100% Zustandsabdeckung be- züglich der Testsicht aufweisen. Im hier vorgestellten Ansatz wird die Testsicht nicht explizit berechnet, sondern ein Verfahren beschrieben, mit dem Pfade erzeugt werden, die die Knoten der Testsicht–Auswahlmenge enthalten. Aus diesem Modell ergibt sich eine Möglichkeit zur Optimierung des Testvorganges, indem man die Zielzustände möglichst vieler Tests auf möglichst wenigen Wegen erreicht. Damit wird der Simulationsaufwand unter Umständen drastisch reduziert. Speziell bei der Hardwareverifi- kation mit ihrem sehr ungünstigen Zeitverhältnis Simulation zu Echtzeit (1.000.000:1 ist beim Stand der Technik nicht ungewöhnlich) ist dieser Aufwand ein erheblicher Kostenfaktor. Die Testentwurfbestimmung lässt sich nach diesem Ansatz auf ein Pfadsuchproblem zurück- führen, für das sich – wie im letzten Kapitel – Model Checking als praktische Lösung anbietet. Modelcheck–Werkzeuge haben die Nebeneigenschaft, für eine nicht erfüllbare Formel ein Ge- genbeispiel anzugeben. Diese Eigenschaft nutzt man aus, indem man dem Werkzeug eine For- mel eingibt, die die Existenz eines gewünschten Pfades negiert. Existiert der gewünschte Pfad, wird er als Gegenbeispiel ausgegeben.

68 5.3 Testpfadgenerierung mit Guwen

Ein einfaches Verfahren liefert – unter der Annahme, dass alle Zielzustände erreichbar sind – das gewünschte Ergebnis:

1. Umformung der ADeVA–Tabellen in Kripke–Strukturen.

2. Erzeugung einer Temporallogikformel, die die Existenz des gewünschten Pfades negiert.

3. Start des Modelcheckers. Wird ein Gegenbeispiel ausgegeben, besteht die Lösung aus diesem Pfad. Werden dagegen die Logikformeln als wahr angesehen, wird die Menge der markierten Zusände in Teilmengen aufgespalten und für jede Teilmenge ab Schritt 2 wiederholt, bis alle markierten Zustände durch Pfade abgedeckt sind.

4. Die Menge der erzeugten Gegenbeispiele entspricht der gewünschte Pfadmenge.

Schritt 3 des Verfahrens ist potenziell aufwändig, weil eine ungeschickte Spaltung der Zustands- menge im Extremfall auf einen Pfad für jeden Zielzustand führt. Jedoch ist die Gesamtzahl der Pfade (und damit der durchzuführenden Testläufe) in keinem Fall schlechter als bei der ma- nuellen Verifikation, in der üblicherweise pro Verifikationsziel ein eigener Testlauf gefahren wird. Schliesslich müssen die Ergebnisse der Pfadberechnung noch in einfach zugänglicher Form dargestellt werden.

5.3 Testpfadgenerierung mit Guwen

Das oben beschriebene Verfahren wurde im Werkzeug Guwen (chinesisch: Berater) prototy- pisch implementiert [66]. Guwen realisiert die Pfadbestimmung mit Hilfe des Modelcheckers SMV. Das specedit–Werkzeug liefert dazu eine maschinenlesbare Form der ADeVA–Tabellen, die Guwen als Eingabe benutzt. Guwen bereitet die ADeVA–Spezifikation für die SMV– Eingabe auf und berechnet mit SMV Pfade durch deren Zustandsraum. Die Ergebnisse werden in Form von Testentwürfen wiedergegeben.

5.3.1 Umformung von ADeVA–Tabellen in SMV–Modelle

Die Zustand/Übergangsysteme, die durch eine ADeVA–Spezifikation definiert werden, haben bereits grosse Ähnlichkeit mit den von SMV verwendenden Eingabemodellen. Beide Spezifi- kationssprachen basieren auf dem Konzept paralleler Zustandsautomaten, die durch Zugriff auf Werte anderer Signale kommunizieren.

69 5 Unterstützung beim Testentwurf

Die in SMV für die Zustandsübergänge möglichen Bedingungen und Zuweisungen sind eine Obermenge der in ADeVA zugelassenen entsprechenden Elemente. Daher ist die Transforma- tion mit relativ einfachen Mitteln durchzuführen. Allerdings kennt SMV kein eigenes Ereig- niskonzept, wie es in ADeVA mit @T/@F–Wahrheitswerten für Bedingungen vorhanden ist. Für diese Konstrukte wird daher eine Sonderbehandlung notwendig. Die Nutzung spezieller zusätzlicher Speichersignale erspart dabei die umfangreiche explizite Aufzählung aller mögli- chen Zustände des Systemzustandsraums, repräsentiert aber die gleiche Semantik wie in [33] beschrieben. Die Transformation wird für jede Spezifikation nach den folgenden Prinzipien durchgeführt:

1. Die Gesamtspezifikation wird in ein einziges Modul main transformiert. 2. Jeder Tabelle entspricht eine Variablendefinition in main.

Für jede Tabelle (MTT oder DTT), die das Signal SADeVA beschreibt, wird in der SMV– Spezifikation eine entsprechende Variable SSMV definiert:

1. Der Wertebereich von SSMV ist ein Aufzählungstyp, der genau die Werte von SADeVA ent- hält.

2. Der Initialwert von SSMV entspricht dem Initialwert von SADeVA. 3. Für jede Tabellenbedingung wird zur besseren Handhabung ein Makro b eingeführt. 4. Jede Einzelbedingung der Tabelle wird daraufhin untersucht, ob in den dazugehörigen Zellen ein @T/@F–Eintrag auftaucht. Wenn das der Fall ist, wird für jede solche Bedin- gung ein besonderes Speichersignal lastState b angelegt, das den Wahrheitswert der Bedingung im Vorzustand speichert. 5. Aus den Tabellenzeilen (MTT) bzw. –spalten (DTT) wird die Wertübergangsfunktion next entsprechend der durch sie definierten Übergänge bestimmt. Ereignisbehaftete Bedingun- gen nehmen zusätzlich zu den aktuellen Wahrheitswerten der Bedingungen auf die Spei- chervariablen bezug.

Reine Eingangssignale werden wie in Schritt 1 einfach durch Angabe ihres Definitionsbereiches spezifiziert. Die Beispieltabelle aus Abbildung 5.1 entspricht dem SMV–Fragment in Abbildung 5.3. Die Definition referenziert die Signale AIS, INI, CPURead und PwrStable. Diese wer- den hier mit Wertebereichen angegeben, jedoch nicht in ihren Verläufen definiert. Sie fungie- ren in diesem einfachen Beispiel als externe Signale, könnten aber auch wie current mode mit einer konkreten Automatendefinition näher in ihrem Verhalten bestimmt werden, wenn dieses durch eine entsprechende Tabelle spezifiziert würde. Die Variablen lastState b2 und lastState b3 entsprechen den Speichersignalen der ereignisbehafteten Bedingungen INI = 0 und CPURead. Der Signalwert wait wird als Initialwert von current mode an- genommen (specedit liefert diese Zusatzinformation).

70 5.3 Testpfadgenerierung mit Guwen

MODULE main

VAR current mode : { wait, unequipped, latch, monitor }; AIS : { 0, 1 }; INI : { 0, sonst }; CPURead : { 0, 1 }; PwrStable : { 0, 1 }; lastState b2 : { 0, 1 }; lastState b3 : { 0, 1 };

DEFINE b1 := AIS = 1; b2 := INI = 0; b3 := CPURead = 1; b4 := PwrStable = 1;

ASSIGN init( current mode ) := wait; init( lastState b2 ) := b2; init( lastState b3 ) := b3;

next( current mode ) := case current mode = wait & b4 : monitor; current mode = monitor & !b1 & !lastState b2 & b2: unequipped; current mode = monitor & !b1 & !b2 : latch; current mode = latch & !b1 & !lastState b2 & b2 : unequipped; current mode = latch & !lastState b3 & b3 : monitor; current mode = unequipped & !b1 & lastState b2 & !b2 : monitor; 1 : current mode; esac; next( lastState b2 ) := b2; next( lastState b3 ) := b3;

Abbildung 5.3: SMV–Modell für ADeVA–Tabelle aus Abbildung 5.1

71 5 Unterstützung beim Testentwurf

5.3.2 CTL–Formeln und Pfadbestimmung

In der negierten Formel wird ein Pfad beschrieben, der alle Zielzustände enthält. Weil CTL keine spezielle Konstruktion vorsieht, mit der diese Pfadbedingung ohne Berücksichtigung der Reihenfolge ausgedrückt werden kann, müssen gegebenenfalls alle Formeln für die Pfade aller möglichen Reihenfolgen der markierten Zustände geprüft werden. Wenn keine Einschränkung der Reihenfolgen möglich ist, ergibt sich die Zahl der möglichen Teilformeln aus der Zahl der Permutationen der markierten Zustände, bei n markierten Zuständen also n!. Die damit verbundene schnell wachsende Zahl der Teilformeln kann zu nicht akzeptablen Rechenzeiten führen. Man kann entweder versuchen, die Formelzahl durch Voranalyse des Systems automatisch zu begrenzen [66] oder man bekommt eine gewünschte Reihenfolge bereits mit der Spezifikation geliefert, was zu genau einer CTL–Formel führt. In Guwen sind beide Möglichkeiten vorgese- hen. Im Beispiel seien die Zustände (Modes) wait sowie latch und unequipped Zielzustände der Verifikation. Diese Information wird ebenfalls von specedit übergeben. Die beiden Rei- henfolgemöglichkeiten dieser Zustände in der gegebenen Spezifikation werden von Guwen in folgende CTL–Formel umgesetzt:

!(EF( current_mode = wait & EF( current_mode = unequipped & EF ( current_mode = latch ) ) ) ) !(EF( current_mode = wait & EF( current_mode = latch & EF ( current_mode = unequipped ) ) ) )

Mit dieser Formel kann SMV die gewünschten Pfade aus dem Modell bestimmen.

5.3.3 Interpretation der SMV–Ergebnisse

Die von SMV ermittelten Ablaufpfade decken alle markierten Zustände ab und liefern so im Prinzip schon die gewünschten Testentwürfe. Die Ausgabe von SMV ist aber relativ unhand- lich und enthält Informationen, die für den Tester uninteressant oder sogar irritierend sind. Sie wird daher mit einigen Nachbearbeitungsschritten in verständliche textuelle Testentwürfe um- gesetzt, die nur aus einfachen Anweisungen bestehen. Im Wesentlichen soll dem Tester mitge- teilt werden, wann er für eine Bedingung zu sorgen hat, wann er eine Beobachtung erwarten kann und wann die verifikationsrelevanten Zustände erreicht werden. Dies wird durch Markie- ren der entsprechenden Signalgleichungen in der SMV–Ausgabe mit ENSURE, EXPECT und EXPECT VERIFICATION TARGET erreicht. Das Resultat ist ein Plan, der dem Tester eine Abfolge dieser Aktionen vorschlägt.

72 5.3 Testpfadgenerierung mit Guwen

Test proposal #1:

01. EXPECT VERIFICATION TARGET current mode = wait 02. ENSURE AIS = 1 03. ENSURE INI = sonst 04. ENSURE CPURead = 1 05. ENSURE PwrStable = 1 06. EXPECT current mode = monitor 07. ENSURE AIS = 0 08. ENSURE INI = 0 09. EXPECT VERIFICATION TARGET current mode = unequipped 10. ENSURE AIS = 1 11. ENSURE INI = sonst 12. ENSURE INI = 0 13. ENSURE AIS = 0 14. ENSURE INI = sonst 15. EXPECT current mode = monitor 16. EXPECT VERIFICATION TARGET current mode = latch

Test proposal #2:

01. EXPECT VERIFICATION TARGET current mode = wait 02. ENSURE AIS = 1 03. ENSURE INI = sonst 04. ENSURE CPURead = 1 05. ENSURE PwrStable = 1 06. EXPECT current mode = monitor 07. ENSURE AIS = 0 08. EXPECT VERIFICATION TARGET current mode = latch 09. ENSURE AIS = 1 10. ENSURE AIS = 0 11. ENSURE INI = 0 12. EXPECT VERIFICATION TARGET current mode = unequipped

Abbildung 5.4: Testentwürfe

73 5 Unterstützung beim Testentwurf

Als Beispiel gibt Abbildung 5.4 die gefundenen Testentwürfe für die ADeVA–Tabelle in Abbil- dung 5.1 wieder. Der entsprechende SMV–Output findet sich in Anhang C. Die Ersetzungsstrategie ist wie folgt:

1. Entfernung der Zeilen mit b–Gleichungen (Bedingungsmakros).

2. Entfernung der lastState b–Gleichungen (Speicherzustände).

3. Sortierung der Gleichungen, die den Wechsel von tabellenspezifizierten Signalen be- schreiben, an die Anfänge der state–Blöcke.

4. Entfernung der state .–Zeilen.

5. Entfernung der SMV–Statusmeldungen und Einsetzung von Trennzeilen zwischen den Testentwürfen.

6. Einfügen von ENSURE vor allen Inputwertewechseln.

7. Einfügen von EXPECT vor allen Zustandswechseln in nicht markierte Zustände.

8. Einfügen von EXPECT VERIFICATION TARGET vor allen Zustandswechseln. in markierte Zustände.

9. Löschen aller Zeilen nach dem letzten Zustandswechsel in einen markierten Zustand.

Im Beispiel findet SMV für jede der beiden CTL–Teilformeln einen Pfad, der jeweils in einen Testentwurf umgesetzt wird. Der Tester kann jetzt eine Auswahl treffen. Wie am ersten Test- entwurf auffällt, wählt SMV nicht immer den kürzesten Weg, um die Testziele zu erreichen. Auch hier muss der Tester entscheiden, ob möglicherweise eine Abkürzung (z.B. Auslassen der Schritte 10 bis 13) sinnvoll ist oder vielleicht gerade der gewählte Umweg potenziell Er- kenntnisse verspricht. Hier wäre ggfs. auch der Einsatz von vereinfachenden Regeln zu prüfen (wie etwa das Kennzeichnen von „don’t care“-Bedingungen, die beliebig mit einem Wert belegt wurden). Solche Konzepte wurden im Prototypen Guwen nicht realisiert.

5.4 Diskussion

Konventionell werden Testdaten ad hoc durch Tester ausgewählt. Dies führt nicht unbedingt zu schlechten oder ungezielten Tests, jedoch wird in der Regel in jedem Test genau ein Aspekt der Anforderungsdefinition betrachtet, beispielsweise eine Aktion, die bei einem bestimmten Wert einer Zählvariablen ausgeführt werden soll. Es ergeben sich also viele Einzeltestläufe, die simulativ validiert werden müssen. Dieser Prozess ist auch bei modernster Rechner– und Simu- lationstechnik extrem zeitaufwändig, zudem führen bereits kleinste Fehler in der Definition der Simulationssteuerung zu unnötig wiederholten Tests und damit zu grossen Verzögerungen im Verifikationsablauf, die sich letztlich in verspäteter Fertigstellung des Produktes oder schlech- terer Qualität niederschlagen können. Der hier vorgestellte Ansatz fasst viele, sonst einzeln

74 5.4 Diskussion simulierte Testläufe zu kombinierten Vorschlägen zusammen. Damit lässt sich zum einen die Anzahl der Einzeltests, und damit letztlich die Simulationsdauer, reduzieren. Zum anderen hilft die Vorgabe strukturierter Testentwürfe, Fehler beim manuellen Entwurf der Testablaufsteue- rungen – und damit kostenintensive, nutzlose Mehrfachsimulationen – zu vermeiden. Das vorgestellte Verfahren weist Zufallsaspekte und anwendungsspezifische Planelemente auf und unterscheidet sich daher sowohl von der reinen Zufallsauswahl als auch den an Abdeckung orientierten Verfahren, die nach strukturellen, aber nicht testzielspezifischen Kriterien planen. Dies ist nur mit der Hilfe eines anwendungskompetenten Testers möglich. Die Ausrichtung von Tests an den generierten Plänen legt bereits früh in der Verifikations- planung einen Fokus auf kompakte Testläufe und konkrete, an der Spezifikation ausgerichtete, Testziele. Dies verspricht eine bessere Qualität der letztlich durchgeführten Tests. Bei den in der Literatur zu findenden Verfahren, die auf häufig auf Zufallsauswahl oder der Abdeckung nach Metriken basieren, fehlt diese Ausrichtung in der Regel. Einige Ansätze [1, 27, 40] benutzen ähnliche Vorgehensweisen, um aus Zustand/Übergang–basierten Systemen Testentwürfe mit- tels Model Checking abzuleiten. Dabei wird jedoch hauptsächlich auf das Erreichen strukturel- ler Abdeckungskriterien abgezielt und dem Tester – im Gegensatz zum vorgestellten Vorgehen – neben reinem Anwendungswissen ein hohes Mass an Sorgfalt bei der Formulierung geeigneter Temporallogikformeln abverlangt. Im Unterschied zu anderen – i.d.R. dynamischen – Ansätzen (wie z.B. von Korel [45] vorgeschlagen) werden zum Programm keine Eingabewerte berechnet, sondern nur Strategien vorgegeben. Der Tester muss die konkreten Testfälle selbst bestimmen und damit das Orakelproblem lösen. Nicht zuletzt ist das Verfahren einfach zu verstehen und anzuwenden, hat durch seinen Vor- schlagscharakter eine konservative Natur und ist – wie mit Guwen demonstriert – leicht zu implementieren. Damit verspricht es ein gutes Aufwand/Nutzen–Verhältnis. Zu beachten ist al- lerdings, dass einige aufwändige Arbeiten weiterhin dem Tester obliegen – u.a. das Finden ge- eigneter Eingabewerte und die Bewertung der durchgeführten Testvorgänge (Orakelproblem). Die dem Verfahren zugrundeliegende Testsicht bietet sich auch für eine nachgeschaltete Bewer- tung einer manuellen Testphase an. Dabei sollte stets 100% Zustandsabdeckung in der Testsicht erreicht werden.

75 5 Unterstützung beim Testentwurf

76 6 Perspektiven

In den vorigen Kapiteln wurden drei Anwendungsbereiche der Kontrollflussabstraktion vorge- stellt (wobei die Generierung von Testvorschlägen lediglich implizit auf dem entsprechenden Sichtgraph beruht). Diese Vorstellung hat exemplarischen Charakter und sollte einige der sich bietenden Möglichkeiten aufzeigen. Jedes der drei gezeigten Beispiele ist in einem anderen Umfeld angesiedelt. Die verbindende Klammer ist die konzentrierte Sicht auf eine Menge an- wendungsspezifisch ausgewählter Knoten des Kontrollflusses. Im ersten Anwendungsbeispiel wurde gezeigt, wie anhand der Verhaltenssicht eine Grösse zur Bewertung von Testläufen definiert werden kann. Im Rahmen dieser Ausführungen wurde ein Ansatz zur Modellierung der Fehleraufdeckungsfähigkeiten von Programmen mittels Kontroll- flussgraphen und Fehleraufdeckungsmodellen vorgestellt, dessen Einsatzmöglichkeit sich nicht auf die vorgestellte Studie beschränkt. Im zweiten Beispiel diente die Untersuchung von Zuver- lässigkeitsgraphen der Aufdeckung von Entwurfsfehlern, die gegen bestimmte Strukturanfor- derungen verstossen. Die Fokussierung auf bestimmte Zustände von Automatenspezifikationen schliesslich war Basis eines Ansatzes zur automatisierten Generierung von Testvorschlägen im dritten Anwendungsbeispiel. Die Anwendungsmöglichkeiten der Kontrollflussabstraktion beschränken sich nicht auf die vor- gestellten Gebiete. Prinzipiell sind auf Sichtgraphen alle Verfahren und Theorie anwendbar, die für Kontrollflussgraphen (und endliche Automaten, s.u.) entwickelt wurden. Mit der Anwen- dung auf einen Sichtgraphen werden die Verfahren spezialisiert, quasi auf die Sicht konzentriert, was besondere sichtspezifische Folgerungen aus den Ergebnissen ermöglicht – bei Verwendung des gleichen, sichtunabhängigen Abstraktionsprinzips. Es ergeben sich daher Möglichkeiten für weitere Anwendungs– und Forschungsansätze. Einige werden in den folgenden Abschnitten skizziert.

6.1 Sichtgraphen als Automaten: Sichttypen

Fasst man die möglichen Anweisungen eines Programmiersystems als Alphabet auf, kann man aus Kontrollflussgraphen und Sichtgraphen auch endliche Automaten (Kontrollflussautomaten bzw. Sichtautomaten) mit diesem Alphabet konstruieren. Diese Automaten beschreiben die Menge der möglichen Wörter über dem Alphabet der Anweisungen, die Kontrollflusssprache bzw. Sichtsprache des Graphen.

77 6 Perspektiven

Ein Kontrollflussautomat wird aus einem Kontrollflussgraphen abgeleitet, indem man systema- tisch Knoten– und Kantenbezeichnungen „vertauscht“: 1

Definition (Kontrollflussautomat)

¡

¨¡ ¡

£ £  ¢ 

Sei G V ¢ E ein Kontrollflussgraph. Sei S s v V init terminate eine endliche £

G G v ¥ G Menge von Kontrollflusszuständen, die nach den einzelnen Anweisungen (Knoten in VG) er- reicht werden, dazu enthalte sie den initialen Zustand init vor der Programmausführung, einen Endzustand terminate. 2

Der Kontrollflussautomat AG zu G sei ein nichtdeterministischer endlicher Auto-

¡

¡

Σ ∆ ¡

¢ ¢  ¢  £ mat S ¢ init terminate mit

der Zustandsmenge S,

Σ ε

¡

dem Alphabet V  ,

G £

∆ Σ

¥ ¥

einer Übergangsralation ¤ S S,

¡

der Startzustandsmenge init  und

¡

der Endzustandsmenge terminate  .

Die Relation ∆ ergibt sich aus der Inzidenzstruktur von G:

w

∆ ¡

¦ £  s ¦ s v w E

v w ¥ G

v

¡

¦ £ ¢ 

init ¦ s w v E w v £

v ¥ G

ε

¡

¦ £ 

s ¦ terminate v w E £

v ¥ G

Die Ablaufsemantik entspricht der üblichen Definition für endliche Automaten [41]. Der Wort- begriff ist bei Erreichbarkeit von terminate ebenfalls wie üblich (über Akzeptanz) definiert, ansonsten sei jede endlich lange verarbeitete Kette aus Σ–Elementen ein Wort. Die Kontrollflusszustände sind nicht identisch zu Programmzuständen zwischen einzelnen Kon- strukten während eines Programmlaufs (die den Zustand des Variablenraums des Programms beschreiben). Sie stellen vielmehr eine Abstraktion der Programmzustände dar. Abbildung 6.1 zeigt die Generierung des Kontrollflussautomaten zum Beispiel– Kontrollflussgraphen aus Kapitel 2.

Ist der Zustand terminate erreichbar, so lässt sich die von AG akzeptierte Sprache als wie üblich definierter regulärer Ausdruck darstellen, ansonsten als regulärer Ausdruck mit Hinzunahme des Operators ω für unendliche Wiederholung [42], wobei der Wortbegriff wie oben definiert sein soll. In diesem Falle ist also jedes nichtleere Präfix der durch den Ausdruck generierten unendlich langen Wörter ein gültiges Wort. Der entsprechende (evtl. um ω erweiterte) reguläre Ausdruck sei als Kontrollflusstyp bezeichnet. 1Ähnlich den bereits 1957 von Myhill eingeführten Transition Graphs und den in grosser Variation in der Litera- tur zu findenen ereignisordnenden Graphen (Ereignisgraphen, Message-Sequence-Charts etc.). 2Falls der Kontrollfluss keine Möglichkeit der Termination vorsieht, d.h., es gibt in G keinen Knoten ohne Nach- folger, ist terminate ein nicht erreichbarer Zustand.

78 6.1 Sichtgraphen als Automaten: Sichttypen

read(a) div write(b) read(a) mult if add sub write(b)

write(b) write(c)

div write(b) read(a) s(read(a)) s(div) s(write(b)) add read(a) mult if sub write(b) ε init s(read(a)) s(mult) s(if) s(add) s(sub) s(write(b)) terminate write(b) add write(c) s(write(b)) s(write(c))

Abbildung 6.1: Erzeugung von Kontrollflussautomaten aus Kontrollflussgraphen

read(a) write(b) read(a) write(b)

write(b) write(c)

write(b) read(a) s(read(a)) s(write(b)) write(b) read(a) ε init s(read(a)) write(b) write(b) s(write(b)) terminate write(c) s(write(b)) s(write(c))

a(ab|bc)b

Abbildung 6.2: Automat und Typ zum Verhaltensgraph aus Kapitel 2

Sichtgraphen sind spezielle Kontrollflussgraphen. Deshalb sind auch aus ihnen Kontrollflussau- tomaten ableitbar. Diese Automaten sollen Sichtautomaten heissen, die entsprechenden regulä- ren Ausdrücke Sichttypen. Abbildung 6.2 zeigt den Verhaltensgraph, Verhaltensautomat und Verhaltenstyp zum Beispiel– Kontrollflussgraphen (wobei read(a), write(b) und read(c) durch a, b und c abge- kürzt sind). Mit Sichttypen werden die Ergebnisse der Automatentheorie für die Strukturanalyse von Pro- grammen verfügbar. Eine Anwendungsmöglichkeit ist die Prüfung auf Verhaltensgleichheit zweier Systeme. Wenn man zwei Systeme betrachtet, stellt sich gelegentlich die Frage, ob sie gleiches Verhalten zeigen. Die Frage ist im allgemeinen nicht entscheidbar (Äquivalenzproblem der theoretischen Informatik). Verhaltensautomaten können jedoch ein Kriterium der Falsifizierbarkeit darstellen, d.h., feststellen, dass zwei Systeme kein identisches Verhalten zeigen.

79 6 Perspektiven

Sei angenommen, dass zwei Systeme S1 und S2 mit unterschiedlichen Definitionen das gleiche Verhalten zeigen. Dazu müssen zwei notwendige, aber nicht hinreichende Bedingungen (oder entsprechende symmetrische Bedingungen, die durch Vertauschen von S1 und S2 entstehen) erfüllt sein:

1. Sie müssen ähnliche Schnittstellen besitzen, d.h., die Schnittstelle von S1 enthält mindes- tens alle Ports von S2

2. Sie müssen die gleichen Interaktionsmuster bezüglich der Verhaltenssicht aufweisen.

Bedingung 1 ist offensichtlich. Die Bedingung 2 impliziert, dass die Verhaltensgleichheit zwei- er Systeme dazu führt, dass sie gleiche Abfolgen von E/A–Aktivitäten aufweisen, d.h., zwei Systeme sind in jedem Fall als ungleich zu betrachten, wenn sie unterschiedliche Abfolgen von Ein– und Ausgaben erlauben. Dies ist meist der Fall, auch wenn Randbedingungen denkbar sind, die anderes implizieren (wenn z.B. die Reihenfolge bestimmter benachbarter Anweisun- gen bzw. Portaktivitäten für die Korrektheit des Verhaltens keine Rolle spielen soll). In realen Anwendungen wäre daher diese Grundvoraussetzung zu prüfen. Unter diesen Annahmen ist die Verhaltensgleichheit leicht zu falsifizieren:

1. Zunächst wird Bedingung 1 überprüft. Trifft sie nicht zu, haben die Systeme ungleiches Verhalten. Ansonsten weiter mit Schritt 2.

2. Man bildet zu S1 und S2 jeweils die Verhaltenstypen. Zu den Verhaltenstypen bildet man die Minimalautomaten nach den bekannten Verfahren der theoretischen Informatik [41]. Die Bildung von Minimalautomaten ist kanonisch, d.h., unterschiedliche Verhaltensty- pen, die die gleichen Interaktionsmuster verarbeiten, bilden auf den gleichen Minimal- automaten ab. Erzeugen S1 und S2 also unterschiedliche Minimalautomaten (–typen), so verarbeiten S1 und S2 unterschiedliche Interaktionsmuster und Bedingung 2 ist nicht er- füllt.

3. Erzeugen S1 und S2 gleiche Minimalautomaten, ist keine Aussage möglich.

Das Verfahren ermöglicht keine Entscheidung über die Verhaltensgleichheit zweier Systeme. Erzeugen S1 und S2 gleiche Minimalautomaten, ist zwar klar, dass sie die gleichen Interaktions- muster realisieren, jedoch nicht, dass innerhalb dieser auch die gleichen Datenwerte verwen- det werden. Der Ansatz scheint für Systeme mit vielen Ports mit kleinen Wertebreichen (z.B. Steuerungen) besser geeignet als für Systeme mit wenigen Ports (z.B. Datenkonverter), weil die Schärfe mit der Zahl der verwendeten Ports und Interaktionsmuster zunimmt. Weitere denkbare Anwendungen der Betrachtung von Sichtautomaten als reguläre Ausdrücke sind die Generierung von Testvorschlägen durch Ableitung von Wörtern aus den Ausdrücken und die vereinfachte Untersuchung des Verhaltens von Teilkomponenten.

80 6.2 Numerische Analyse

Einige verwandte Arbeiten beschreiben Ansätze, in denen reguläre Ausdrücke i.d.R. zur Mo- dellierung von Pfaden benutzt werden. In [11] werden reguläre Ausdrücke als Sprache zur Be- schreibung von Kontrollflussstrukturen vorgeschlagen, in [9] werden Ereignisstrukturen zum GUI–Test durch reguläre Ausdrücke beschrieben. Petrinetze, die um reguläre Ausdrücke als Transitionsbedingungen erweitert wurden, werden in [10] dazu benutzt, Testläufe anhand von Abdeckungsmetriken auszuwählen. Andere Arbeiten [47] beschreiben Ansätze, bereits aus der Systemsignatur reguläre Ausdrücke über Programmabläufe zu gewinnen. I/O–Automata [51] ähneln Verhaltensautomaten, erzeugen aber potenziell einen unendlich grossen Zustandsraum.

6.2 Numerische Analyse

Bei der Bestimmung von Sichtgraphen kann man oft auch numerische Daten gewinnen, mit denen sich Knoten und/oder Kanten des Sichtgraphs annotieren lassen. Die Analyse dieser nu- merischen Information ermöglicht zusätzliche Auswertungen. Zwei Beispiele sind die Nutzung von Zeitinformation und Zuverlässigkeitsparametern.

6.2.1 Zeitbehaftete Verhaltensgraphen

Kanten im Sichtgraph entsprechen Pfadmengen im Kontrollflussgraphen. Für die Pfade aus die- ser Menge kann man in der Regel Laufzeitangaben aus dem Kontrollflussgraphen berechnen. Bestimmt man beispielsweise Verhaltensgraphen aus Assemblerprogrammen, wie in Kapitel 4, so ist der Zeitbedarf für den Ablauf eines Pfades leicht aus dem jeweiligen Zeitbedarf der einzel- nen Anweisungen zu berechnen. Oft kann man dazu allerdings keine einzelne Zahl verwenden, weil der Zeitbedarf eines Pfades mit den verwendeten Daten variieren kann (unterschiedliche Laufzeiten der einzelnen Operationen) oder der Pfad Schleifen enthält. In diesen Fällen kann man Zeituntergrenzen, bei geeigneter Einschränkung auf endliche Pfade auch Obergrenzen an- geben. Die Analyse derart annotierter Sichtgraphen kann z.B. Aufschlüsse über maximale/minimale Antwortzeiten eines Systems geben und auf diese Weise sowohl den Test unterstützen als auch Hinweise auf ein mögliches fehlerhaftes Verhalten (durch Zeitüber– oder unterschreitungen) ausserhalb der rein funktionalen Korrektheit geben.

6.2.2 Zuverlässigkeitsparameter

Kennt man die Ausfallwahrscheinlichkeiten der Sichtgraphknoten, kann man diese entspre- chend annotieren und für bestimmte Pfade oder das Gesamtsystem Fehlerwahrscheinlichkeiten berechnen. Der Ansatz ähnelt dem im Kapitel 3 vorgestellten Vorgehen. Allerdings werden hier beliebige Auswahlmengen (der Anweisungen, für die man Ausfallwahrscheinlichkeiten kennt) benutzt und die Wahrscheinlichkeiten i.d.R. aufgrund von Fehlermodellen bestimmt. Aus den so gebildeten Sichtgraphen sind zusätzlich auch kritische Berechnungspfade u.ä. bestimmbar. Das Konzept weist eine gewisse Ähnlichkeit zur Fehlerbaummethode [61] auf.

81 6 Perspektiven

6.3 Erweiterte Architekturuntersuchung

Sichtgraphen können auch, wie in Kapitel 4 bereits angesprochen, durch Suche nach spezifi- schen Graphstrukturen kategorisiert werden. Die dort vorgestellte Kategorisierung nach Pfad- strukturen macht möglicherweise die Spezifikation bestimmter Architekturen schwierig, zusätz- lich erlaubt sie nicht die Erkennung beliebiger Architekturschachtelungen. Direkte Graphsuchansätze, die üblicherweise aber mit weitaus höheren Berechnungskomple- xitäten als die in Kapitel 4 vorgestellte Methode einhergehen, ermöglichen eine detailliertere Analyse und geordnete Darstellung der Ergebnisse. Beispielsweise könnte man die Architektur von Beispiel 4.3 (Kapitel 4, Seite 50) baumartig bzw. in geschachtelter Darstellung als mvp( quicksort, shellsort, insertionsort, rb( quicksort, shellsort, insertionsort, print ) ) notieren und so – als weiteren Abstraktionsschritt – einen Strukturtyp der Sicht angeben. Für Untersuchungen dieser Art müssten aber zunächst weitere Grundlagen – u.U. unter der Einbe- ziehung von Ergebnissen über Graphgrammatiken – erarbeitet werden.

6.4 Verwandte Techniken

Der Sichtgraphansatz zeigt gewisse Ähnlichkeiten zu Techniken zur Visualisierung von Pro- grammabläufen, wie z.B. [46], die in der Regel u.a. aus Programmläufen gewonnene Datenin- formation nutzen. Der Vorteil einer rein statischen Analyse besteht darin, dass kein Laufzeit- system vorhanden sein muss und keine Instrumentierung des Programms oder der Umgebung benötigt wird. Der Nachteil besteht in der fehlenden Analysemöglichkeit für nur zur Laufzeit belegbare Elemente wie Zeiger oder Felder. Die hier vorgestellten Anwendungen kommen ohne Datenanalyse aus. Eine Anwendung der Sichtgraphtechnik auf datenorientierte Strukturen, wie Datenflussgraphen oder durch Sze- narienuntersuchung gewonnene Programmflussgraphen mit belegten Variablen erscheint ei- ne sinnvolle Erweiterung. Beispielsweise könnte man systematisch Benutzungen und Defini- tionen einer bestimmten Variablen durch einen Sichtgraph herauspräparieren und die Abde- ckung vorhandener (legaler) definition-use-Sequenzen messen oder das Vorhandensein (ille- galer) definition-kill-Sequenzen feststellen. Beim Erzeugen von Mutanten können Verhaltens- graphen eine erste Prüfung auf unterschiedliches Programmverhalten im Sinne des Kapitels 5 unterstützen. Arbeiten wie die bereits angesprochenen von Kranzlmüller et al. [46] zeigen einen Weg in Richtung fokussiertes Debugging, der die Aufmerksamkeit des Testers durch die Anwendung von „Sichtgraphfilterung“ auf ausgewählte Programmabschnitte lenken könnte. Der Sichtgraph könnte dabei als Steuerstruktur für die im Debug-Prozess darzustellenden bzw. zu unterdrücken- den Programmabschnitte dienen.

82 6.4 Verwandte Techniken

Eine weitere nah verwandte Technik ist das Slicing (initial vorgeschlagen 1981 durch Wei- ser [65] und seitdem in grosser Breite ausgearbeitet). Hierbei wird aus einem Programm ein lauffähiges Teilprogramm herauspräpariert, dass die Belegung einer gewählten Variable an ei- nem ausgesuchten Punkt im Programm identisch zum Ursprungsprogramm durchführt. Neben rein statischen Varianten existieren auch dynamische Versionen, in denen die durch Programm- läufe belegten Variablen des untersuchten Programms für die Abhängigkeitsanalyse und die dar- auf aufbauende Slice–Operation verwendet werden. Beim Slicing wird die Struktur bestimm- ter Anweisungen (Knoten des Kontrollflussgraphen) in einer Slice zusammengefasst; dies ent- spricht der Bildung von Sichtgraphen. Bei Sichtgraphen wird jedoch keine Annahme über das Auswahlkriterium bezüglich der Knoten getroffen. Technisch gesehen ist daher die Sichtgraph- analyse die Kernoperation des Slicings bzw. eine Verallgemeinerung des Slicingkonzepts auf beliebige Auswahlkriterien.

83 6 Perspektiven

84 Literaturverzeichnis

[1] P.E. Ammann, P.E. Black: „Abstracting Formal Specifications to Generate Software Tests via Model Checking“, Tagungsband 18th Digital Avionics Systems Conference (DASC), St. Louis, USA, IEEE, volume 2, section 10.A.6, 1999, S.1–10. [2] P.E. Ammann, P.E. Black, W. Majurski: „Using Model Checking to Generate Tests from Specifications“, Tagungsband 2nd IEEE International Conference on Formal Engineering Methods (ICFEM’98), Brisbane, Australien, 1998, S.46–54. [3] A. Avizienis: „The N-Version Approach to Fault Tolerance“, IEEE Transactions on Soft- ware Engineering, 11(12), 1985, S.1491–1501. [4] A. Avizienis,L. Chen: „On the Implementation of N-Version Programming for Software Fault Tolerance during Program Execution“, Tagungsband COMPSAC’97, 1997, S.149– 155. [5] J. Bach: „Test Automation Snake Oil“, Tagungsband 14th International Confe- rence and Exposition on Testing Computer Software, Bearbeitete Version 2.1 von http://www.satisfice.com/articles/test automation snake oil.pdf, 1999. [6] R.-J. Back, J. von Wright: Refinement Calculus: A Systematic Introduction, Springer- Verlag, New York (USA), 1998. [7] F. Bastani, B. Cukic, V. Hilford, A. Jamoussi: „Towards dependable safety-critical softwa- re“, Tagungsband WORDS’96, 1996. [8] B. Beizer: Black Box Testing, Wiley, New York, 1995. [9] F. Belli: „Finite-State Testing of Graphical User Interfaces“, Tagungsband 12th Interna- tional Symposium on Software Reliability Engineering (ISSRE), 2001, S.34–43. [10] F. Belli, J. Dreyer: „Program segmentation for controlling test coverage“, Tagungsband 8th International Symposium on Software Reliability Engineering (ISSRE), 1997, S.72–83. [11] F. Belli, K.-E. Grosspietsch: „Specification of fault–tolerant system issues by predica- te/transition nets and regular expressions – approach and case study“, IEEE Transactions on software engineering, 17(6), 1991, S.513–526. [12] J. Bergeron: Writing Testbenches – Functional Verification of HDL Models, 2. Auflage, Kluwer, Boston (USA), 2003.

85 Literaturverzeichnis

[13] G. v.Bochmann, A. Petrenko: „Protocol Testing: Review of Methods and Relevance for Software Testing“, Tagungsband ISSTA 1994, 1994, S.109–124. [14] S.S. Brilliant, J.C. Knight, N. Leveson: „The Consistent Comparison Problem in N- Version Software“, ACM Software Engineering Notes, 1987, S.29–34. [15] C. Capellmann, A. Franzke: GRAL - Eine Sprache für die graphbasierte Modellbildung, Diplomarbeit D 143 des Fachbereichs Informatik der Universität Koblenz-Landau, 1991. [16] E. M. Clarke, O. Grumberg, D. A. Peled: Model Checking, MIT-Press, Cambridge (USA), 1999. [17] P. Dahm, J. Ebert, A. Franzke, M. Kamp, A. Winter: GReQL – Eine Anfragesprache für das GUPRO–Repository – Sprachbeschreibung (Version 1.2), Fachbericht 14–98 des Fachbereichs Informatik der Universität Koblenz-Landau, 1998. [18] M. Dal Cin, „Zur explizit fehlertoleranten Programmierung von Parallelrechnern“, Ta- gungsband PARS Workshop, Gesellschaft für Informatik, München, 1989, S.47–55. [19] M. Dal Cin: Rechnerarchitektur, Teubner, Stuttgart, 1996. [20] J.W. Duran, S.C. Ntafos: „An Evaluation of Random Testing“, IEEE Transactions on Soft- ware Engineering, 10(4), 1984, S.438–445. [21] J. Ebert, B. Kullbach, V. Riediger, A. Winter: „GUPRO – Generic Understanding of Pro- grams, An Overview“, Graph-Based Tools (GraBaTs 2002), Elsevier ENTCS 72/2, Bar- celona, Spanien, 2002. [22] T. Eisenbarth, R. Koschke, D. Simon: „Locating Features in Source Code“, IEEE Tran- sactions on Software Engineering, 29(3), 2003, S.195–209. [23] P.G. Frankl, R.G. Hamlet, B. Littlewood, L. Stringini: „Evaluating Testing Methods by Delivered Reliability“, IEEE Transactions on Software Engineering, 24(8), 1998, S.586– 601. [24] P.G. Frankl, S.N. Weiss: „An Experimental Comparison of the Effectiveness of Branch Testing and Data Flow Testing“, IEEE Transactions on Software Engineering, 19(8), 1993, S.774–787. [25] A. Franzke: GRAL 2.0: A Reference Manual, Fachbericht 3–97 der Fachbereichs Informa- tik der Universität Koblenz-Landau, 1997. [26] E. Gamma, R. Helm, R. Johnson, J. Vlissides: Design Patterns, Addison Wesley, Reading (USA), 1995. [27] A. Gargantini, C. Heitmeyer: „Using Model Checking to Generate Tests from Require- ments Specifications“, Tagungsband ESEC / SIGSOFT FSE 1999, 1999, S.146–162. [28] A. Gargantini, E. Riccobene: „ASM-Based Testing: Coverage Criteria and Automatic Test Sequence Generation“, Journal of Universal Computer Science, 7(11), 2001, S.1050– 1067. [29] C. Ghezzi, M. Jazayeri, D. Mandrioli: Fundamentals of Software Engineering, 2. Auflage, Prentice Hall (Pearson Education), Upper Saddle River, New Jersey (USA), 2003.

86 Literaturverzeichnis

[30] S. Gossens: „Enhancing Validation with Behavioural Types“, Tagungsband 7th IE- EE/IEICE International Symposium on High Assurance Systems Engineering, Tokio, Ja- pan, 2002, S.201–208. [31] S. Gossens, M. Dal Cin: „Strukturelle Analyse explizit fehlertoleranter Programme“, 5. Workshop Software-Reengineering, Bad Honnef, Softwaretechnik-Trends, 23(2), 2003. [32] U. Graf, H.-J. Henning, K. Stange, P.-T. Wilrich: Formeln und Tabellen der mathemati- schen Statistik, 3. Auflage, Springer-Verlag, Berlin, 1987. [33] W. Haas, S. Gossens, U. Heinkel: „Semantics of a Formal Specification Language for Ad- vanced Design and Verification of ASICs (ADeVA)“, Tagungsband 11. E.I.S.-Workshop, Erlangen, April 2003, S.51–56. [34] W. Haas, S. Gossens, U. Heinkel: „Integration of Formal Specification into the Standard ASIC Design Flow“, Tagungsband 7th IEEE/IEICE International Symposium on High Assurance Systems Engineering, Tokio, Japan, 2002, S.189–194. [35] W. Haas, S. Gossens, U. Heinkel: „Behavioural Specification for Advanced Design and Verification of ASICs (ADeVA)“, Tagungsband GI/ITG/GMM Workshop „Methoden und Beschreibungssprachen zur Modellierung und Verifikation von Schaltungen und Syste- men“, Tübingen, 2002. [36] D. Hamlet, R. Taylor: „Partition Testing Does Not Inspire Confidence“, IEEE Transactions on Software Engineering, 16(12), 1990, S.1402–1411. [37] U. Heinkel, C. Mayer, J. Pleickhardt, J. Knäblein, H. Sahm, C. Webb, W. Haas, S. Gos- sens: „An Optimized Flow for Designing high-speed, large-scale CMOS ASIC SoCs“, Tagungsband SAMOS III-Workshop: Systems, Architectures, MOdeling, and Simulation, Samos, Griechenland, 2003. [38] U. Heinkel, C. Mayer, J. Pleickhardt, J. Knäblein, H. Sahm, C. Webb, W. Haas, S. Gossens: „Specification, Design and Verification of Systems-on-Chip in a Telecom Application“, Tagungsband 11. E.I.S.-Workshop, Erlangen, 2003, S.45–50. [39] C. Heitmeyer, R.D. Jeffords, B.G. Labaw: „Automated consistency checking of requi- rements specifications“, ACM Transactions on Software Engineering and Methodology, 5(3), 1996, S.231–261. [40] H.S. Hong, I. Lee, O. Sokolsky, S.D. Cha: „Automatic Test Generation from Statecharts Using Model Checking“, Technical Report MS-CIS-01–07, Department of Computer and Information Science, University of Pennsylvania, 2001. [41] J.E. Hopcroft, R. Motwani, J.D. Ullman: Introduction to Automata Theory, Languages, and Computation, 2. Auflage, Addison Wesley, Boston (USA), 2001. [42] J.P. Katoen: Concepts, Algorithms and Tools for Model Checking, Arbeitsbericht des IMMD, 32(1), 1999. [43] Y.G. Kim, H.S. Hong, S.M. Cho, D.H. Bae, S.D. Cha: „Test Cases Generation from UML State Diagrams“, IEE Proceedings - Software, 146(4), August 1999, S.187–192.

87 Literaturverzeichnis

[44] J.C. Knight, N. Leveson: „An Experimental Evaluation of the Assumption of Indepen- dence in Multiversion Programming“, IEEE Transactions on Software Engineering, 12(1), 1986, S.96–109. [45] B. Korel: „Automated test data generation for programs with procedures“, Tagungsband 1996 ACM SIGSOFT international symposium on Software testing and analysis, San Die- go, USA, 1996, S. 209–215. [46] D. Kranzlmüller, C. Schaubschläger, J. Volkert: „A Brief Overview of the MAD Debug- ging Activities“, Online-Publikation Fourth International Workshop on Automated De- bugging (AADEBUG 2000), München, 2000. [47] R. Lämmel, J. Harm: „Test case characterisation by regular path expressions“, Tagungs- band Formal Approaches to Testing of Software (FATES), 2001, S. 109–124. [48] P.A. Lee, T. Anderson: Fault Tolerance, Principles and Practice, Springer-Verlag, New York, 1990. [49] Lehn, J., Wegmann, H.: Einführung in die Statistik, Teubner Verlag, Stuttgart, 2000. [50] N.G. Leveson, M. Heimdahl, H. Hildreth, J.D. Reese: „Requirements Specification for Process-Control Systems“, IEEE Transactions on Software Engineering, 20(9), 1994, S.684–787. [51] N.A. Lynch, M.R. Tuttle: „Hierarchical Correctness Proofs for Distributed Algorithms“, MIT/LCS/TR-387, MIT, April, 1987. [52] K.L. McMillan: The SMV System, Technical Report CS-92–131, Carnegie-Mellon- University, 1992. [53] —-: HC05, MC68HC705J1A Technical Data, Motorola Inc., 1995. [54] G.J. Myers: The Art of Software Testing, Wiley, New York, 1979. [55] A.J. Offutt, S. Liu: „Generating Test Data from SOFL Specifications“, The Journal of Systems and Software, 49(1), 1999, S.49–62. [56] B. Prahami: „Design of reliable software via general combination of N-Version Program- ming and Acceptance Testing“, Tagungsband 7th International Symposium on Software Reliability Engineering ISSRE’96, 1996. [57] A. Pretschner, J. Philipps: Szenarien modellbasierten Testens, Technischer Bericht TUM– I0205 der Technischen Universität München, 2002. [58] L. L. Pullum: Software Fault Tolerance, Artech House, Boston, 2001. [59] B. Randell: „System Structure for Software Fault Tolerance“, IEEE Transactions on Soft- ware Engineering, 1(2), 1975, S.437–449. [60] D.J. Richardson, M. Thompson: „An Analysis of Test Data Selection Criteria Using the RELAY Model of Fault Detection“, IEEE Transactions on Software Engineering, 19(6), 1993, S.533–553. [61] W. G. Schneeweiss: The Fault-Tree Method, LiLoLe–Verlag, Hagen, 1999.

88 Literaturverzeichnis

[62] U. Schöning: Theoretische Informatik – kurzgefasst, 2. Auflage, Spektrum Akademischer Verlag, Heidelberg, 1995.

[63] M. Shaw, D. Garlan: Software Architecture, Prentice Hall, Upper Saddle River, New Jersey (USA), 1996.

[64] U. Voges: „Software Diversität und ihr Beitrag zur Sicherheit“, Tagungsband Entwicklung von Software-Systemen in ADA, Bremen, 1998, S.13–27.

[65] M. Weiser: „Program Slicing“, Tagungsband 5th International Conference on Software Engineering (ICSE), San Diego, USA, 1981, S.439–449.

[66] F. Wang, S. Gossens, W. Haas, U. Heinkel: „Generierung von Testvorschlägen aus automa- tenbasierten Spezifikationen“, 16. Workshop Testmethoden und Zuverlässigkeit von Schal- tungen und Systemen, Fraunhofer-Institut Integrierte Schaltungen,Dresden, 2004, S.154– 158.

[67] H. Zhu, P.A.V. Hall, J.H.R. May: „Software Unit Test Coverage and Adequacy“, ACM Computing Surveys, 29(4), 1997, S.366–427.

89 Literaturverzeichnis

90 Schriftenverzeichnis

1. Gossens, S.: „Enhancing System Validation with Behavioural Types“, Tagungsband 4. Workshop Software-Reengineering, Bad Honnef, Technischer Bericht der Universität Koblenz-Landau, In- stitut für Informatik, April 2002.

2. W. Haas, S. Gossens, U. Heinkel: „Behavioural Specification for Advanced Design and Verifica- tion of ASICs (ADeVA)“, Tagungsband GI/ITG/GMM Workshop „Methoden und Beschreibungs- sprachen zur Modellierung und Verifikation von Schaltungen und Systemen“, Tübingen, 2002.

3. S. Gossens: „Enhancing Validation with Behavioural Types“, Tagungsband 7th IEEE/IEICE In- ternational Symposium on High Assurance Systems Engineering, Tokio, Japan, 2002.

4. W. Haas, S. Gossens, U. Heinkel: „Integration of Formal Specification into the Standard ASIC De- sign Flow“, Tagungsband 7th IEEE/IEICE International Symposium on High Assurance Systems Engineering, Tokio, Japan, 2002.

5. U. Heinkel, C. Mayer, J. Pleickhardt, J. Knäblein, H. Sahm, C. Webb, W. Haas, S. Gossens: „Spe- cification, Design and Verification of Systems-on-Chip in a Telecom Application“, Tagungsband 11. E.I.S.-Workshop, Erlangen, März 2003.

6. W. Haas, S. Gossens, U. Heinkel: „Semantics of a Formal Specification Language for Advanced Design and Verification of ASICs (ADeVA)“, Tagungsband 11. E.I.S.-Workshop, Erlangen, März 2003.

7. S. Gossens, M. Dal Cin: „Strukturelle Analyse explizit fehlertoleranter Programme“, 5. Workshop Software-Reengineering, Bad Honnef, Softwaretechnik-Trends, 23(2), Mai 2003.

8. U. Heinkel, C. Mayer, J. Pleickhardt, J. Knäblein, H. Sahm, C. Webb, W. Haas, S. Gossens: „An Optimized Flow for Designing high-speed, large-scale CMOS ASIC SoCs“, Tagungsband SAMOS III Workshop: Systems, Architectures, MOdeling, and Simulation, Samos, Griechen- land, 2003.

9. W. Haas, T. Bürner, S. Gossens, U. Heinkel: „Formal Specification of a 40GBit/s Sonet/SDH ASIC with ADeVA“, Tagungsband Forum on specification and Design Languages 2003, Frank- furt, September 2003.

10. F. Wang, S. Gossens, W. Haas, U. Heinkel: „Generierung von Testvorschlägen aus automaten- basierten Spezifikationen“, Tagungsband 16. Workshop Testmethoden und Zuverlässigkeit von Schaltungen und Systemen, Dresden, März 2004.

11. S. Gossens, M. Dal Cin: „Structural Analysis of Explicit Fault-Tolerant Programs“, Tagungsband 8. IEEE High-Assurance System Engineering Symposium 2004, Tampa, USA, März 2004.

91 92 A Programme der Voruntersuchung

Binärdatei Anweisungen E/A-Anw. E/A-Anw. % Verzweigungs-Anw. Verzweigungs-Anw. % bash 132.627 282 0,2126 17.288 13,0350 bc 12.897 62 0,4807 1.586 12,2974 bwbasic 41.540 56 0,1348 3.953 9,5161 c++filt 8.919 25 0,2803 1.136 12,7368 catdoc 16.335 112 0,6856 2.355 14,4168 cc1 433.830 191 0,0440 63.385 14,6105 cc1chill 470.626 137 0,0291 66.439 14,1171 cc1obj 450.628 197 0,0437 64.868 14,3950 cc1plus 546.365 125 0,0228 79.101 14,4776 cccp 21.216 91 0,4289 3.248 15,3092 chmod 5.902 28 0,4744 776 13,1480 chown 11.225 44 0,3919 1.371 12,2138 ci 22.222 94 0,4230 2.652 11,9341 co 21.063 91 0,4320 2.474 11,7457 collect2 15.930 44 0,2762 1.763 11,0671 convertfdprm 970 16 1,6494 122 12,5773 cp 28.240 43 0,1522 4.310 15,2620 cpp 13.940 67 0,4806 1.792 12,8550 cpp0 21.216 91 0,4289 3.248 15,3092 dc 9.595 53 0,5523 1.019 10,6201 dd 8.145 32 0,3928 936 11,4917 df 8.709 43 0,4937 1.070 12,2861 dir 21.905 74 0,3378 3.191 14,5674 dircolors 5.558 39 0,7016 675 12,1446 diskd 3.419 40 1,1699 449 13,1324 diskseekd 3.494 42 1,2020 473 13,5374 du 12.020 42 0,3494 1.760 14,6422 emacs 432.839 304 0,0702 54.178 12,5168 f771 546.314 171 0,0313 75.719 13,8599 fdmount 9.866 56 0,5676 1.210 12,2643 fdrawcmd 1.194 7 0,5862 156 13,0653 flex 18.170 83 0,4567 2.061 11,3428 floppycontrol 3.430 79 2,3032 475 13,8483 floppymeter 4.676 52 1,1120 529 11,3130 formail 7.060 32 0,4532 1.027 14,5467 g++ 13.879 67 0,4827 1.778 12,8107 g77 14.292 68 0,4757 1.864 13,0422 gcj 14.135 67 0,4740 1.798 12,7201

93 A Programme der Voruntersuchung

Binärdatei Anweisungen E/A-Anw, E/A-Anw, % Verzweigungs-Anw, Verzweigungs-Anw, % gcjh 7.422 33 0,4446 865 11,6545 gcov 3.014 30 0,9953 347 11,5129 genattr 5.246 94 1,7918 612 11,6660 genattrtab 19.990 187 0,9354 2.698 13,4967 gencheck 65 4 6,1538 3 4,6153 gencodes 4.575 38 0,8306 563 12,3060 genconfig 4.904 39 0,7952 614 12,5203 genemit 6.063 143 2,3585 780 12,8649 genextract 5.313 71 1,3363 641 12,0647 genflags 4.984 47 0,9430 609 12,2191 gengenrtl 1.071 11 1,0270 109 10,1774 genopinit 4.884 51 1,0442 627 12,8378 genoutput 6.353 119 1,8731 736 11,5850 genpeep 5.324 108 2,0285 629 11,8144 genrecog 7.682 128 1,6662 988 12,8612 getfdprm 2.835 19 0,6701 365 12,8747 ginstall 34.639 50 0,1443 5.121 14,7839 gzip 30.606 50 0,1633 4.650 15,1930 ident 888 31 3,4909 111 12,5000 jc1 458.393 139 0,0303 64.911 14,1605 jcf-dump 12.364 15 0,1213 1.369 11,0724 jv-scan 4.825 22 0,4559 887 18,3834 jvgenmain 1.149 7 0,6092 123 10,7049 link 4.106 27 0,6575 486 11,8363 llines 130.374 265 0,2032 13.738 10,5373 ln 24.507 37 0,1509 3.868 15,7832 lockfile 7.613 10 0,1313 980 12,8727 ls 21.905 74 0,3378 3.191 14,5674 lynx 239.633 271 0,1130 33.764 14,0898 make 50.211 263 0,5237 6.746 13,4353 merge 16.133 53 0,3285 1.836 11,3804 mkdir 6.147 27 0,4392 769 12,5101 mkfifo 4.886 27 0,5525 622 12,7302 mknod 5.316 27 0,5079 673 12,6598 modelgen 60.820 115 0,1890 4.988 8,2012 mt 1.478 37 2,5033 192 12,9905 mtools 45.763 252 0,5506 4.869 10,6395 mv 31.446 45 0,1431 4.611 14,6632 nap 83.655 226 0,2701 9.309 11,1278 nsd8x 312.554 158 0,0505 31.290 10,0110 patch 20.267 120 0,5920 2.553 12,5968 procmail 35.630 55 0,1543 4.802 13,4774 protoize 8.812 16 0,1815 991 11,2460 psql 38.571 297 0,7700 4.201 10,8916 rcs 22.397 92 0,4107 2.677 11,9524 rcsclean 20.738 91 0,4388 2.456 11,8429 rcsdiff 16.522 52 0,3147 1.892 11,4513 rcsmerge 16.352 52 0,3180 1.862 11,3869 rlog 17.799 53 0,2977 2.131 11,9725 rm 26.223 33 0,1258 4.006 15,2766 rmdir 4.246 27 0,6358 513 12,0819 setfdprm 6.884 59 0,8570 891 12,9430 shred 8.829 32 0,3624 981 11,1111 superformat 11.309 100 0,8842 1.305 11,5394 sync 4.033 27 0,6694 480 11,9018

94 Binärdatei Anweisungen E/A-Anw, E/A-Anw, % Verzweigungs-Anw, Verzweigungs-Anw, % tar 42.130 97 0,2302 5.241 12,4400 touch 6.609 29 0,4387 859 12,9974 unlink 4.096 27 0,6591 486 11,8652 unprotoize 7.892 16 0,2027 851 10,7830 vdir 21.905 74 0,3378 3.191 14,5674 workbone 4.730 83 1,7547 532 11,2473 xdfcopy 4.329 34 0,7854 477 11,0187 xgcc 13.523 67 0,4954 1.706 12,6155

95 A Programme der Voruntersuchung

96 B Listen der Sprungbefehle und E/A–Routinen

Mnemonics der Sprungbefehle jmp je jz jne jnz ja jnbe jae jnb jb jnae jbe jna jg jnle jge jnl jl jnge jle jng jc jnc jo jno js jns jpo jnp jpe jp jcxz jecxz loop loopz loopne loopnz loopne

E/A–Routinen der C–Bibliothek libc-2.2.5 <_IO_adjust_column> <_IO_cleanup> <_IO_default_doallocate> <_IO_default_finish> <_IO_default_pbackfail> <_IO_default_setbuf> <_IO_default_sync> <_IO_default_uflow> <_IO_default_xsgetn> <_IO_default_xsputn> <_IO_doallocbuf> <_IO_feof> <_IO_ferror> <_IO_fflush> <_IO_fgets> <_IO_file_close> <_IO_file_doallocate> <_IO_file_open> <_IO_file_read> <_IO_file_seek> <_IO_file_stat> <_IO_flockfile> <_IO_flush_all> <_IO_flush_all_linebuffered> <_IO_flush_all_lockp>

97 B Listen der Sprungbefehle und E/A–Routinen

<_IO_fopen64> <_IO_fputs> <_IO_fread> <_IO_free_backup_area> <_IO_free_wbackup_area> <_IO_ftell> <_IO_funlockfile> <_IO_fwide> <_IO_fwrite> <_IO_getc> <_IO_getdelim> <_IO_getline> <_IO_getline_info> <_IO_init> <_IO_init_marker> <_IO_iter_begin> <_IO_iter_end> <_IO_iter_file> <_IO_iter_next> <_IO_least_marker> <_IO_least_wmarker> <_IO_link_in> <_IO_list_lock> <_IO_list_resetlock> <_IO_list_unlock> <_IO_marker_delta> <_IO_marker_difference> <_IO_new_do_write> <_IO_new_fclose> <_IO_new_fdopen> <_IO_new_file_attach> <_IO_new_file_close_it> <_IO_new_file_fopen> <_IO_new_file_init> <_IO_new_file_overflow> <_IO_new_file_seekoff> <_IO_new_file_setbuf> <_IO_new_file_sync> <_IO_new_file_underflow> <_IO_new_file_write> <_IO_new_file_xsputn> <_IO_new_fopen> <_IO_new_popen> <_IO_new_proc_open> <_IO_no_init> <_IO_padn> <_IO_peekc_locked> <_IO_printf>

98 <_IO_putc> <_IO_puts> <_IO_remove_marker> <_IO_seekmark> <_IO_seekoff> <_IO_seekpos> <_IO_setb> <_IO_setbuffer> <_IO_setvbuf> <_IO_sgetn> <_IO_sputbackc> <_IO_sscanf> <_IO_str_count> <_IO_str_init_static> <_IO_str_overflow> <_IO_sungetc> <_IO_switch_to_backup_area> <_IO_switch_to_get_mode> <_IO_switch_to_main_get_area> <_IO_switch_to_main_wget_area> <_IO_switch_to_wbackup_area> <_IO_switch_to_wget_mode> <_IO_un_link> <_IO_unbuffer_write> <_IO_ungetc> <_IO_unsave_markers> <_IO_vasprintf> <_IO_vdprintf> <_IO_vfprintf> <_IO_vfscanf> <_IO_vfwprintf> <_IO_vsnprintf> <_IO_vsprintf> <_IO_vsscanf> <_IO_wdefault_finish> <_IO_wdefault_pbackfail> <_IO_wdefault_setbuf> <_IO_wdefault_xsputn> <_IO_wdo_write> <_IO_wdoallocbuf> <_IO_wpadn> <_IO_wsetb> <_IO_wstr_count> <_IO_wstr_init_static> <_IO_wstr_overflow>

99 B Listen der Sprungbefehle und E/A–Routinen

100 C SMV-Lauf

-- specification !EF (current_mode = wait & EF (current_m... is false -- as demonstrated by the following execution sequence state 1.1: b4 = 1 b3 = 1 b2 = 0 b1 = 1 current_mode = wait AIS = 1 INI = sonst CPURead = 1 PwrStable = 1 lastState_b2 = 0 lastState_b3 = 1 state 1.2: b2 = 1 b1 = 0 current_mode = monitor AIS = 0 INI = 0 state 1.3: b2 = 0 b1 = 1 current_mode = unequipped AIS = 1 INI = sonst lastState_b2 = 1 state 1.4: b2 = 1 INI = 0 lastState_b2 = 0 state 1.5: b2 = 0 b1 = 0 AIS = 0 INI = sonst lastState_b2 = 1 state 1.6: current_mode = monitor lastState_b2 = 0 state 1.7: b1 = 1 current_mode = latch AIS = 1

101 C SMV-Lauf

-- specification !EF (current_mode = wait & EF (current_m... is false -- as demonstrated by the following execution sequence state 2.1: b4 = 1 b3 = 1 b2 = 0 b1 = 1 current_mode = wait AIS = 1 INI = sonst CPURead = 1 PwrStable = 1 lastState_b2 = 0 lastState_b3 = 1 state 2.2: b1 = 0 current_mode = monitor AIS = 0 state 2.3: b1 = 1 current_mode = latch AIS = 1 state 2.4: b2 = 1 b1 = 0 AIS = 0 INI = 0 state 2.5: b2 = 0 b1 = 1 current_mode = unequipped AIS = 1 INI = sonst lastState_b2 = 1 resources used: user time: 0.01 s, system time: 0 s BDD nodes allocated: 1606 Bytes allocated: 1245184 BDD nodes representing transition relation: 81 + 1

102 Lebenslauf Stefan Gossens

6.2.1970 Geboren in Kranenburg

1976-1980 St.-Michael-Grundschule Kleve

1980-1986 Johanna-Sebus-Gymnasium Kleve

1986 St. Bernhard’s Central Catholic High School, Fitchburg MA (USA)

1987-1990 Konrad-Adenauer-Gymnasium Kleve, Abschluss mit Abitur

1990-1997 Studium der Informatik und Computerlinguistik an der Universität Koblenz-Landau, Abschluss mit Informatik-Diplom am 8.10.1997

1998 Wehrdienst als Informatiker im Amt für militärisches Geowesen

seit 1998 Wissenschaftlicher Mitarbeiter an der Universität Erlangen-Nürnberg, Institut für Informatik, Lehrstuhl 3