1. Trang chủ
  2. » Công Nghệ Thông Tin

Digitale Hardware/ Software-Systeme- P22 ppt

20 127 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 20
Dung lượng 229,22 KB

Nội dung

414 7 Software-Verifikation all p-uses- ¨ Uberdeckungstest Im all p-uses- ¨ Uberdeckungstest wird gefordert, dass f ¨ ur jede Entscheidung und f ¨ ur jede darin verwendete Variable jede Kombination mit deren Definitionen, welche die Entscheidung erreichen, gepr ¨ uft wird. Die Testf ¨ alle m ¨ ussen also das folgende Krite- rium erf ¨ ullen: F ¨ ur jeden Knoten v i im datenflussattributierten Kontrollflussgraph und jeder Variablen x ∈ de fs(v i ) muss mindestens ein definitionsfreier Pfad bez ¨ uglich x von Knoten v i zu jeder Kante in dpu(x, v i ) getestet werden. Beispiel 7.2.20. Betrachtet wird das Programm aus Beispiel 7.2.16. Um 100% all p-uses- ¨ Uberdeckung zu erzielen, sind zwei Testfalleingaben notwendig: (v in ,v 1 ,v 3 , v out ) und (v in ,v 1 ,v 2 ,v 3 ,v out ). Damit werden die beiden Kanten (v 1 ,v 3 ) und (v 1 ,v 2 ), die mit p-uses attributiert sind, getestet. Somit subsumiert der all p-uses- ¨ Uberdeckungstest den Zweig ¨ uberdeckungstest. all c-uses- ¨ Uberdeckungstest Analog zum all p-uses- ¨ Uberdeckungstest wird im all c-uses- ¨ Uberdeckungstest ge- fordert, dass f ¨ ur jeden globalen berechnenden Zugriff und f ¨ ur jede darin verwendete Variable jede Kombination mit deren Definitionen, die den Zugriff erreichen, gepr ¨ uft wird. Die Testf ¨ alle m ¨ ussen somit das folgende Kriterium erf ¨ ullen: F ¨ ur jeden Knoten v i im datenflussattributierten Kontrollflussgraph und jeder Variablen x ∈ defs(v i ) muss mindestens ein definitionsfreier Pfad bez ¨ uglich x von Knoten v i zu jedem Kno- ten in dcu(x, v i ) getestet werden. Beispiel 7.2.21. F ¨ ur das Programm aus Beispiel 7.2.16 f ¨ uhrt die Testfalleingabe (v in ,v 1 ,v 2 ,v 3 ,v out ) zu einer 100%-igen all c-uses- ¨ Uberdeckung. Der all c-uses- ¨ Uberdeckungstest subsumiert weder Zweig-, Anweisungs- noch einen anderen defs/uses- ¨ Uberdeckungstest. all c-uses/some p-uses- ¨ Uberdeckungstest Der all c-uses- ¨ Uberdeckungstest pr ¨ uft offensichtlich lediglich Variablendefinitionen, die in berechnenden Zugriffen m ¨ unden. Variablen, die ausschließlich pr ¨ adikativ ver- wendet werden, werden somit nicht getestet. Der all c-uses/some p-uses- ¨ Uberde- ckungstest erweitert den all c-uses- ¨ Uberdeckungstest dahingehend, dass f ¨ ur aus- schließlich pr ¨ adikativ verwendete Variablen ebenfalls Testf ¨ alle gefordert werden. Somit m ¨ ussen die Testf ¨ alle das folgende Kriterium erf ¨ ullen: • F ¨ ur jeden Knoten v i im datenflussattributierten Kontrollflussgraph und jeder Va- riablen x ∈ de fs(v i ) muss mindestens ein definitionsfreier Pfad bez ¨ uglich x von Knoten v i zu jedem Knoten in dcu(x, v i ) getestet werden. • Ist dcu(x, v i ) leer, so muss mindestens ein definitionsfreier Pfad bez ¨ uglich x von Knoten v i zu einer Kante in dpu(x, v i ) getestet werden. 7.2 Testfallgenerierung zur simulativen Eigenschaftspr ¨ ufung 415 Beispiel 7.2.22. F ¨ ur das Programm aus Beispiel 7.2.16 fordert der all c-uses/some p- uses- ¨ Uberdeckungstest die Testfalleingabe (v in ,v 1 ,v 2 ,v 3 ,v out ). Die Definitionen in v in und v 2 erfordern den Test der berechnenden Zugriffe in v 2 und v out . Da damit bereits alle definierten Variablen getestet wurden, m ¨ ussen keine weiteren Testf ¨ alle hinzugenommen werden, obwohl der Zweig (v 1 ,v 3 ) noch nicht getestet wurde. Der all c-uses/some p-uses- ¨ Uberdeckungstest subsumiert den all defs- ¨ Uberde- ckungstest. Er subsumiert aber weder den Zweig- noch den Anweisungs ¨ uberde- ckungstest. all p-uses/some c-uses- ¨ Uberdeckungstest Analog zum all c-uses/some p-uses- ¨ Uberdeckungstest existiert der all p-uses/some c- uses- ¨ Uberdeckungstest. Bei diesem wird zus ¨ atzlich zu den Testf ¨ allen des all p-uses- ¨ Uberdeckungstests gefordert, dass f ¨ ur eine Variable, die ausschließlich berechnend verwendet wird, also in keiner pr ¨ adikativen Benutzung auftaucht, weitere Testf ¨ alle generiert werden m ¨ ussen. Das Kriterium f ¨ ur die Testf ¨ alle lautet somit: • F ¨ ur jeden Knoten v i im datenflussattributierten Kontrollflussgraph und jeder Va- riablen x ∈ de f s(v i ) muss mindestens ein definitionsfreier Pfad bez ¨ uglich x von Knoten v i zu jeder Kante in dpu(x, v i ) getestet werden. • Ist dpu(x, v i ) leer, so muss mindestens ein definitionsfreier Pfad bez ¨ uglich x von Knoten v i zu einem Knoten in dcu(x, v i ) getestet werden. Beispiel 7.2.23. Betrachtet wird das Programm aus Beispiel 7.2.16 auf Seite 411. F ¨ ur eine 100%-ige all p-uses/some c-uses- ¨ Uberdeckung sind die beiden Testfalleingaben (v in ,v 1 ,v 3 ,v out ) und (v in ,v 1 ,v 2 ,v 3 ,v out ) notwendig. Die Definitionen von min und max in v in erfordern den Test der pr ¨ adikativen Verwendung in (v 1 ,v 3 ) und (v 1 ,v 2 ). Zus ¨ atzlich wird aber durch die Definitionen in Knoten v 2 gefordert, dass der berech- nende Zugriff in v out getestet wird. Dies ist allerdings bereits im zweiten Testfall enthalten. Der all p-uses/some c-uses- ¨ Uberdeckungstest subsumiert Zweig, Anweisungs- und all p-uses- ¨ Uberdeckungstest. all uses- ¨ Uberdeckungstest Die Kombination aus den all c-uses/some p-uses- und all p-uses/some c-uses- ¨ Uber- deckungstests f ¨ uhrt zu dem all uses- ¨ Uberdeckungstest. Es wird dabei gefordert, dass f ¨ ur jede globale Definition jede erreichbare berechnende und pr ¨ adikative Verwen- dung getestet wird. Das Kriterium f ¨ ur die Testf ¨ alle lautet somit: F ¨ ur jeden Knoten v i im datenflussattributierten Kontrollflussgraph und jeder Variablen x ∈ defs(v i ) muss mindestens ein definitionsfreier Pfad bez ¨ uglich x von Knoten v i zu jedem Knoten in dpu(x, v i ) und zu jeder Kante in dpu(x, v i ) getestet werden. Der all uses- ¨ Uber- deckungstest subsumiert somit den all c-uses/some p-uses- und den all p-uses/some c-uses- ¨ Uberdeckungstest. Die Subsumierungsrelationen der in diesem Abschnitt vorgestellten Verfahren zur Generierung strukturorientierter Testf ¨ alle ist zusammenfassend in Abb. 7.20 dar- gestellt. 416 7 Software-Verifikation ¨ uberdeckungstest Mehrfach- Bedingungs- ¨ uberdeckungstest Bedingungs- minimaler Mehrfach- ¨ uberdeckungstest Bedingungs-/ Entscheidungs- ¨ uberdeckungstest Bedingungs- einfacher ¨ uberdeckungstest Anweisungs- ¨ uberdeckungstest Zweig- ¨ Uberdeckungstest all p-uses- ¨ Uberdeckungstest all defs- ¨ Uberdeckungstest all c-uses- ¨ Uberdeckungstest all p-uses/ some c-uses- ¨ Uberdeckungstest all c-uses/ some p-uses- ¨ Uberdeckungstest all uses- strukturierter Pfad- ¨ uberdeckungstest Pfad- ¨ uberdeckungstest Abb. 7.20. Subsumierungsrelation zwischen den Verfahren zur Generierung strukturorientier- ter Testf ¨ alle 7.3 Formale funktionale Eigenschaftspr ¨ ufung von Programmen Die automatischen Verfahren zur formalen funktionalen Eigenschaftspr ¨ ufung von Programmen haben in den vergangenen Jahren enorme Fortschritte verzeichnet. Einen guten ¨ Uberblick hier ¨ uber gibt die Ver ¨ offentlichung [140]. Im Folgenden wer- den in Anlehnung an [140] einige Techniken n ¨ aher betrachtet. 7.3.1 Statische Programmanalyse Der Begriff statische Programmanalyse beschreibt Techniken, mit deren Hilfe Infor- mationen ¨ uber das Verhalten von Programmen ermittelt werden k ¨ onnen, ohne diese auszuf ¨ uhren. Viele dieser Techniken wurden f ¨ ur die Optimierungsphase in Com- pilern konzipiert. Dennoch ist deren Anwendungsgebiet nicht auf diese Aufgabe beschr ¨ ankt. Hier wird statische Programmanalyse im Kontext der formalen Eigen- schaftspr ¨ ufung von Programmen betrachtet. Ein grundlegendes Problem in der Programmverifikation ist, dass viele Verifika- tionsfragen unentscheidbar oder zu rechenintensiv sind, um sie zu beantworten. Des- halb berechnen Techniken zur statischen Programmanalyse typischerweise lediglich Approximationen f ¨ ur Eigenschaften. Diese m ¨ ussen allerdings Korrektheitsgarantien liefern, d. h. nicht zu Fehlschl ¨ ussen verleiten. 7.3 Formale funktionale Eigenschaftspr ¨ ufung von Programmen 417 Beispiel 7.3.1. Ein statisches Verfahren zur Detektion von ” Division durch Null“- Fehlern in einem gegeben Programm muss s ¨ amtliche Werte eines Divisors, die zur Laufzeit des Programms auftreten k ¨ onnen, ber ¨ ucksichtigen. Da eine Aufz ¨ ahlung al- ler potentiellen Werte in der Regel aus Zeitgr ¨ unden nicht m ¨ oglich ist, arbeiten Ver- fahren zur statischen Programmanalyse typischerweise mit Teil- bzw. Obermengen. Verwendet die Analyse eine Teilmenge aller m ¨ oglichen Werte und findet dabei keine Fehler, kann keine endg ¨ ultige Aussage ¨ uber die Abwesenheit von ” Division durch Null“-Fehlern gemacht werden. Liefert das Analyseverfahren dennoch dieses Ergeb- nis, so kann diese Aussage falsch sein, da die verwendet Approximation inkorrekt ist. Verwendet das Verfahren hingegen eine Obermenge aller m ¨ oglichen Werte eines Divisors, so ist die Approximation korrekt, und die Aussage, dass keine ” Division durch Null“-Fehlern existieren, gerechtfertigt. Allerdings kann eine solche ¨ Uberap- proximation zu falschnegativen Ergebnissen f ¨ uhren, d. h. der Fehler tritt lediglich unter Verwendung von Werten auf, die zwar in der Obermenge, nicht aber in der ur- spr ¨ unglichen Menge m ¨ oglicher Werte des Divisors liegt. In diesem Zusammenhang spricht man auch von unzul ¨ assigen Gegenbeispielen. Im Gegensatz zu falschnegativen Ergebnissen k ¨ onnen bei der statischen Pro- grammanalyse auch falschpositive Ergebnisse auftreten. Hierbei handelt es sich um Testf ¨ alle, die als fehlerfrei angesehen werden, es aber in Wirklichkeit gar nicht sind. Aufgrund der Unentscheidbarkeit statischer Analyseprobleme kann nicht garantiert werden, dass eine Methode sowohl keine falschnegativen als auch keine falschposi- tiven Ergebnisse erzeugt. Statische Programmanalyse beruht auf der Idee der Fixpunktberechnung (siehe auch Anhang C.4). Dabei werden Wertemengen solange durch ein Programm pro- pagiert und angepasst, bis diese Mengen sich nicht weiter ¨ andern. Dies wird anhand des Beispiels aus [140] illustriert: Beispiel 7.3.2. Gegeben ist folgender Ausschnitt eines C-Programms: 1 int i = 0; 2do{ 3 assert(i <= 10); 4 i = i+2; 5 } while (i < 5); Es sollen nun alle Werte, welche die Variable i annehmen kann, ermittelt werden. Dies ist beispielsweise sinnvoll, wenn i als Index f ¨ ur Arrays verwendet wird und ein Zugriff außerhalb des deklarierten Array-Bereichs verhindert werden soll. Der Kontroll-Datenflussgraph zu dem obigen Programmsegment ist in Abb. 7.21 zu se- hen. Der Zustand v 2 repr ¨ asentiert dabei die Programmzeilen 2 und 3. Der Zustand v 5 repr ¨ asentiert das Verlassen des Programmabschnitts und der Zustand v e den Fehler- zustand, der durch die assert-Anweisung erreicht wird. Links in Abb. 7.21 sind f ¨ ur die ersten beiden Iterationen f ¨ ur jeden Knoten des Kontrollflussgraphen die zugeh ¨ orige Wertemenge f ¨ ur die Variable i angegeben. Die- se enth ¨ alt diejenigen Werte, welche die Variable i bei Erreichen des repr ¨ asentierten 418 7 Software-Verifikation CFG i < 5 i > 10 1. Iteration 2. Iteration i ≥ 5 i ≤ 10 NOP NOP NOP NOP v 5 v 1 v 2 v 3 v 4 v e {0} { 0} INT {2} ∅∅ { 0,2} { 0,2} { 2,4} i=0; i=i+2; Abb. 7.21. Kontroll-Datenflussgraph zu dem Programmsegment aus Beispiel 7.3.2 Zustands tragen kann. Zu Beginn der ersten Iteration im Zustand v 1 h ¨ alt die Varia- ble i einen beliebigen Wert. Die Wertemenge ist somit die Menge aller Werte in INT, die eine Variable von Typ int in der Programmiersprache C annehmen kann. F ¨ ur die statische Programmanalyse werden nun die Wertemengen entlang der Kon- trollflusskanten propagiert und entsprechend der Operationen im Datenflussgraphen manipuliert. Die beiden ersten Iterationen laufen wie folgt ab: 1. Zu Beginn ist die Variable i nicht initialisiert und nimmt somit einen beliebi- gen Wert aus der Menge INT an. Bei Erreichen von Zustand v 2 wurde i bereits initialisiert und besitzt den Wert 0. Somit ergibt sich die Wertemenge {0} mit lediglich einem Element. Die assert-Anweisung in Zeile 3 ¨ andert an dieser Wertebelegung nichts. Bei Erreichen von Zustand v 4 wurde die Variable i be- reits um 2 erh ¨ oht, weshalb die Wertemenge als einziges Element die 2 enth ¨ alt. Zustand v 5 und v e werden in der ersten Iteration aufgrund der Kontrollanweisun- gen 2 < 5 bzw. 0 ≤ 10 nicht erreicht. 2. Die Wertemenge {2} wird nun von Zustand v 4 zu Zustand v 2 propagiert. Da v 2 mehrere Eingangskanten besitzt, kann sich in diesem Knoten die Wertemenge vergr ¨ oßern, da die Vereinigung aller ankommenden Wertemengen gebildet wer- den muss. Das Ergebnis ist somit die Wertemenge {0,2}, wobei das Element 0 noch aus der ersten Iteration stammt. Da beide Werte kleiner gleich zehn sind, wird die Wertemenge nicht an Zustand v e propagiert. Man beachte aber auch, dass der Knoten v 1 in diesem Durchlauf nicht wieder betrachtet werden muss, 7.3 Formale funktionale Eigenschaftspr ¨ ufung von Programmen 419 da sich die dort ermittelte Wertemenge nicht ge ¨ andert hat. Die Menge {0,2} wird nun unver ¨ andert weiter an Knoten v 3 propagiert. Dort werden die Elemente um zwei erh ¨ oht, weshalb sich f ¨ ur Zustand v 4 die Wertemenge {2,4} ergibt. Da beide Elemente echt kleiner f ¨ unf sind, wird die Wertemenge nicht an v 5 jedoch aber an v 2 propagiert. Die Iteration wird solange fortgesetzt, bis ein Fixpunkt erreicht ist, d. h. keine ¨ Ande- rungen in den Wertemengen auftreten. Die eben gerade beschriebene Programmanalyse wird als konkrete Interpretation bezeichnet. Dies liegt darin begr ¨ undet, dass Elemente aus INT und beliebigen Teil- mengen daraus konkrete Werte und somit einen konkreten Wertebereich darstellen. Abstrakte Interpretation Konkrete Interpretation l ¨ asst sich in der Praxis nicht anwenden, da die Wertemen- gen schnell anwachsen. Bereits 1965 stellte Peter Naur fest, dass es ausreichend sein kann, abstrakte Werte bei der Programmanalyse zu verwenden [341]. Basierend auf diesem Ergebnis entwickelten Cousot und Cousot 1977 die Methode der abstrak- ten Interpretation [118]. Abstrakte Interpretation bedient sich zweier zentraler Kon- zepte: dem sog. abstrakten Wertebereich, der eine Approximation eines konkreten Wertebereichs ist, und sog. abstrakter Funktionen, die dazu dienen, konkrete Werte in abstrakte Werte zu ¨ ubersetzen. Abstrakte Interpretation hat zum Ziel, eine appro- ximative L ¨ osung des Programmanalyseproblems zu liefern. Dabei wird das Verhal- ten eines Programms f ¨ ur abstrakte Wertebereiche analysiert. Dies geschieht, indem die Operationen auf den konkreten Wertebereichen aus der konkreten Interpretation durch geeignete Funktionen ersetzt werden. Abstrakte Wertebereiche lassen sich in relationale und nichtrelationale abstrak- te Wertebereiche einteilen. Beispiele f ¨ ur nichtrelationale Wertebereiche sind Vo r - zeichen-Wertebereiche, Intervall-Wertebereiche oder Kongruenz-Wertebereiche.Der Vorzeichen-Wertebereich besitzt drei Elemente {pos,neg,zero} zur Unterscheidung positiver und negativer Zahlen, sowie der Null. Intervall-Wertebereiche sind expres- siver, da der Vorzeichen-Wertebereich durch {[−∞,0),[0,0],(0, ∞]} repr ¨ asentiert werden kann. Beispiel 7.3.3. Betrachtet wird wiederum das Programmsegment aus Beispiel 7.3.2 mit dem Kontroll-Datenflussgraphen aus Abb. 7.21. Ein m ¨ oglicher abstrakter Werte- bereich ist z. B. die Menge der Intervalle {[a,b] | a ≤ b∧a,b ∈ Z}. Die in der konkre- ten Interpretation verwendeten Operationen Addition und Vereinigung m ¨ ussen f ¨ ur die abstrakte Interpretation ersetzt werden durch Addition und Vereinigung von In- tervallen. Die abstrakte Interpretation ist in Abb. 7.22 an dem Beispiel durchgef ¨ uhrt. Im Folgenden seien min bzw. max der minimale bzw. maximale Wert, der sich im Wertebereich INT darstellen l ¨ asst. In Zustand v 1 , zu Beginn der ersten Iteration, ist die Variable i noch nicht initialisiert und kann somit einen beliebigen Wert im Intervall [min,max] annehmen. Nach der Initialisierung (Zustand v 2 ) besitzt i den 420 7 Software-Verifikation CFG i ≤ 10 i < 5 i > 10 1. Iteration 2. Iteration 3. + 4. Iteration i ≥ 5 NOP NOP NOP NOP v 5 v 1 i=0; i=i+2; v 2 v 3 v 4 v e [] [] [5,6] [min,max] [0,0] [0,0] [2,2] [0,2] [0,2] [2,4] [0,4] [0,4] [2,6] Abb. 7.22. Abstrakte Interpretation mit Intervallen konkreten Wert 0, was als Intervall [0,0] geschrieben wird. Bis auf die Intervall- schreibweise der Wertemengen verl ¨ auft die erste Iteration der abstrakten Interpre- tation ¨ aquivalent zur konkreten Interpretation aus Beispiel 7.3.2. Man beachte aber, dass Zuweisung und Addition sich jeweils auf Unter- und Obergrenze des Intervalls auswirkt. Nach Beendigung der ersten Iteration wird das Intervall [2,2] von Zustand v 4 an Zustand v 2 propagiert. Zusammen mit dem Intervall [0,0] aus der Initialisie- rung von i ergibt sich eine ¨ Uberapproximation des Wertebereichs durch das Intervall [0,2]. Man sieht also, dass die Mengenvereinigung in der Intervallarithmetik durch die Minimums- bzw. Maximumsoperation ¨ uber die Bereichsgrenzen ersetzt wurde. Bei Erreichen von Zustand v 4 in der zweiten Iteration wird die Wertemenge mit dem Intervall [2,4] approximiert. Zu Beginn der dritten Iteration ergibt sich somit die Wertemenge f ¨ ur v 2 von [min{0,2},max{0,4}]=[0, 4]. Die Wertemenge f ¨ ur v 4 wird in dieser Iteration mit [2,6] approximiert. In diesem Fall ist die Obergrenze erstmals gr ¨ oßer als die Schran- ke 5, die zur Steuerung der while-Schleife verwendet wird. Aus diesem Grund muss die Wertemenge geteilt werden, um eine Fallunterscheidung zu erreichen. Die appro- ximierte Wertemenge [2, 4] wird zur ¨ uck an v 2 propagiert, w ¨ ahrend das verbleibende Intervall [5,6] an Zustand v 5 ¨ ubertragen wird. Nach dieser Aufteilung der Wertemen- ge ist das an v 2 propagierte Intervall aber das selbe, das auch am Ende von Iteration zwei propagiert wurde. Eine vierte Iteration offenbart somit den Fixpunkt in der ab- strakten Interpretation. 7.3 Formale funktionale Eigenschaftspr ¨ ufung von Programmen 421 Da es sich bei der Intervallbildung um eine ¨ Uberapproximation handelt, kann man auch f ¨ ur jede konkrete Programmausf ¨ uhrung schließen, dass die Zusicherung assert(x <= 10) immer g ¨ ultig ist. Kongruenz-Wertebereiche repr ¨ asentieren den Wert value(x) einer Variablen x als (value(x) mod k) f ¨ ur ein gegebenes k.F ¨ ur k = 2erh ¨ alt man den sog. Parit ¨ atswertebe- reich {odd,even}. Man beachte, dass der Intervall-Wertebereich zwar deutlich mehr Elemente enthalten kann, aber dennoch nicht expressiver ist als der Parit ¨ atswerte- bereich, da die geraden und ungeraden Zahlen nicht durch eine endliche Anzahl an Intervallen repr ¨ asentiert werden k ¨ onnen. Das folgende Beispiel zu Kongruenz- Wertebereichen stammt aus [140]. Beispiel 7.3.4. Betrachtet wird der Ausdruck 1/(x − y). Kann unter Verwendung der abstrakten Interpretation mit Kongruenz-Wertebereichen f ¨ ur ein gegebenes, aber be- liebiges k gezeigt werden, dass (x mod k) =(y mod k) ist, so kann daraus geschlossen werden, dass eine Division durch Null in dieser Anweisung nicht auftreten kann. Nicht relationale abstrakte Wertebereiche lassen sich leicht handhaben. Aller- dings k ¨ onnen mit ihnen bereits Zusicherungen der Form x ≤ y nicht mehr ¨ uberpr ¨ uft werden. Relationale abstrakte Wertebereiche l ¨ osen dieses Problem. Eine einfache Form relationaler abstrakter Wertebereiche sind die sog. differenzenbeschr ¨ ankten Matrizen (engl. difference bound matrices, DBMs). Diese bestehen aus Konjunk- tionen von Ungleichungen der Form x −y ≤ c. Obwohl DBM-Wertebereiche expres- siver als Intervall-Wertebereiche sind besteht dennoch eine Einschr ¨ ankung in der Form, dass Beschr ¨ ankungen der Art −x − y ≤ c nicht ausgedr ¨ uckt werden k ¨ onnen. Oktagon-Wertebereiche beseitigen diese Einschr ¨ ankung, indem sie Beschr ¨ ankungen der Form ax + by ≤ c erlauben, wobei a,b ∈{−1,0,1} sind. Eine Erweiterung neh- men schließlich Oktaeder-Wertebereiche durch Verallgemeinerung auf mehr als zwei Variablen vor. Eine der ersten relationalen abstrakten Wertebereiche sind Polyeder-Wertebe- reiche. Diese werden durch die Konjunktion von Ungleichungen der Form a 1 x 1 + a 2 x 2 + ···+ a n x n ≤ c beschrieben, wobei a 1 , ,a n ,c ∈ Z sind. Die Manipulation von Polyeder-Wertebereichen ist allerdings nicht trivial und bedarf der Berechnung sog. konvexer H ¨ ullen. Die Komplexit ¨ at dieser Berechnungen ist exponentiell in der Anzahl der Variablen. Die Expressivit ¨ at eines Wertebereichs entscheidet dar ¨ uber, welche funktionalen Eigenschaften mit abstrakter Interpretation gezeigt werden k ¨ onnen. Einige von den oben genannten abstrakten Wertebereichen lassen sich aber nicht hinsichtlich ih- rer Expressivit ¨ at vergleichen. Hier sei nochmals das Beispiel des Parit ¨ atswertebe- reichs und des Intervall-Wertebereichs genannt. Die Vorzeichen-, Intervall-, DBM-, Oktagon-, Oktaeder- und Polyeder-Wertebereiche bilden eine Hierarchie. Obwohl Polyeder-Wertebereiche die Expressivsten in dieser Hierarchie sind, reichen diese nicht aus, um Eigenschaften ¨ uber Ungleichheiten zu zeigen. Beispiel 7.3.5. Gegeben ist der Ausdruck 1/(2·x + 1 − y) [140]. Um mittels abstrak- ter Interpretation zu zeigen, dass keine Division durch Null in dieser Anweisung auf- treten kann, muss ein abstrakter Wertebereich gew ¨ ahlt werden, in dem 2 · x + 1 = y 422 7 Software-Verifikation gezeigt werden kann. Dies ist nicht mit den oben beschriebenen relationalen abstrak- ten Wertebereichen m ¨ oglich. Der abstrakte Wertebereich der linearen Kongruenzen verbindet Polyeder-Wertebereiche mit Kongruenz-Wertebereichen. Diese enthalten auch Gleichungen der Form a 1 x 1 + ···+ a n x n = c mod k f ¨ ur ein gegebenes k.Damit kann gezeigt werden, dass (2· x + 1) mod k ungleich y mod k ist, was auch die Frage nach einer m ¨ oglichen Division durch Null beantwortet. 7.3.2 SAT-basierte Modellpr ¨ ufung von C-Programmen F ¨ ur die SAT-basierte Modellpr ¨ ufung (siehe Abschnitt 5.3.2) wird, neben der zu pr ¨ ufenden Eigenschaft, ein Modell des Programms ben ¨ otigt. Dieses muss ein end- licher Automat sein, der aus Zust ¨ anden und Zustands ¨ uberg ¨ angen besteht. In einem Programm fasst ein Zustand den Wert des Programmz ¨ ahlers, die Werte der Pro- grammvariablen und den Zustand des Speichers zusammen. Zustands ¨ uberg ¨ ange be- schreiben m ¨ ogliche ¨ Anderungen bei der Programmausf ¨ uhrung von einem Zustand zum n ¨ achsten. Da der Kontrollfluss lediglich am Ende eines Grundblocks verzweigen und am Anfang eines Grundblocks eintreten kann, kann es sinnvoll sein, anstatt jede An- weisung einzeln zu codieren, eine Codierung auf Grundbl ¨ ocken vorzunehmen. Ein solches Verfahren ist in [242] beschrieben. Beispiel 7.3.6. Gegeben ist das folgende C-Programm [242]: 1 void func1() { 2 int x = 3; 3 inty=x-3; 4 while (x <= 4) { 5 y++; 6 x = func2(x); 7} 8 y = func2(y); 9} 10 11 int func2(int s) { 12 int t = s + 2; 13 if (t > 6) 14 t -= 3; 15 else 16 t ; 17 return t; 18 } Der resultierende Kontroll-Datenflussgraph ist in Abb. 7.23 zu sehen. Man erkennt, dass jeder Zustand v i im Kontrollflussgraphen einem Grundblock im Programm ent- spricht. Außerdem ist gezeigt, wie Parameter im Falle nichtrekursiver Funktions- aufrufe ¨ ubergeben werden. Dabei werden Argumente i n der Variable l ¨ ubergeben 7.3 Formale funktionale Eigenschaftspr ¨ ufung von Programmen 423 und mittels der Variablen r wird unterschieden, an welche Variable das Ergebnis zu ¨ ubertragen ist. NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP x ≤ 4x > 4 r = 1r = 0 t ≤ 6t > 6 NOP NOP NOP NOP l=x; r=0; y=t; l=y; t-=3; t ; x=t; x=3; y=0; r=1; v 3 v 5 v 4 v 1 v 2 t=l+2; v 11 v 10 v 9 v 7 v 8 y++; v 6 Abb. 7.23. Kontroll-Datenflussgraph f ¨ ur das Programm aus Beispiel 7.3.6 Jedem Grundblock i (Zustand im Kontrollflussgraphen) wird nun eine einzel- ne bin ¨ are Variable b i ∈ B zugeordnet, die anzeigt, ob der Kontrollfluss gerade in diesem Grundblock liegt. Die Belegung der Variablen b i kann direkt aus dem Pro- grammz ¨ ahler abgeleitet werden. Man beachte, dass b i = T impliziert, dass ∀ j =i b j = F ist. Nach der Konstruktion des Kontroll-Datenflussgraphen werden zun ¨ achst die Da- tenflussgraphen zu jedem Basisblock einzeln in Booleschen Formeln codiert. Dabei wird f ¨ ur jede Zuweisung var = expr eine kombinatorische Schaltung f ¨ ur expr er-

Ngày đăng: 03/07/2014, 08:20