Seminar Werkzeuggestütze Softwareprüfung Slicing Sebastian Meyer Überblick • Einführung und Begriffe • Static Slicing • Dynamic Slicing • Erweiterte Slicing-Techniken • Fazit Sebastian Meyer: Slicing 2 Was ist Slicing? (I) • Program slicing is a method for automatically decomposing programs by analyzing their data flow and control flow. • Starting from a subset of a program’s behavior, slicing reduces that program to a minimal form which still produces that behavior. • The reduced program, called a „slice“, is an independent program guaranteed to represent faithfully the original program within the domain of the specified subset of behavior. Mark Weiser, 1979 Sebastian Meyer: Slicing 3 Was ist Slicing? (II) • Slicing wurde 1979 erstmals von Weiser definiert. – Mark Weiser, Program slices, formals, psychological and practical investigation of an automatic program abstraction method. PhD thesis, University of Michigan, Ann Arbor, 1979. • Slicing beantwortet allgemein die Frage „welche Anweisung beeinflusst die Berechnung einer anderen Anweisung“ Sebastian Meyer: Slicing 4 Beispiel 1: int OddNumsSum(int n) 2: { 3: int i = 0; 4: int sum = 0; 5: while (i <= n) 6: { 7: if (i % 2 == 1) 8: sum++; 9: i++; 10: } 11: return sum; 12: } Sebastian Meyer: Slicing 5 Begriffe (I) • Slice – Ein Slice ist eine Menge von Anweisungen, eines Programms P, die eine Variable v an einem bestimmten Programmpunkt s beeinflussen oder von ihr beeinflusst werden. • Slicing – Slicing ist der Vorgang des Berechnens eines Slice. Sebastian Meyer: Slicing 6 Begriffe (II) • Slicing-Kriterium – Das Tupel aus Variable v und deren Programmpunkt s wird Slicing-Kriterium (v,s) genannt • Startkonfiguration – Die Menge der Werte aller Parameter eines Programms, welche beim Programmaufruf übergeben bzw. während des Programmablaufs eingelesen werden können. Sebastian Meyer: Slicing 7 Beispiel zu den Begriffen 1: int OddNumsSum(int n) int OddNumsSum(int n) 2: { { 3: int i = 0; int i = 0; 4: int sum = 0; while (i <= n) 5: while (i <= n) { Slicing 6: { i++; 7: if (i % 2 == 1) } 8: sum++; } 9: i++; Slice 10: } (i,9) n=6 11: return sum; 12: } Slicing-Kriterium Start-Konfiguration Programm Sebastian Meyer: Slicing 8 Arten von Slicing (I) • Static Slicing – Die Analyse erfolgt unabhängig von einer bestimmten Startkonfiguration • (Exact) Dynamic Slicing – Die Analyse erfolgt abhängig von einer bestimmten Startkonfiguration Sebastian Meyer: Slicing 9 Arten von Slicing (II) • Backward Slicing – Beinhaltet alle Anweisungen, die die Variable des Slicing-Kriteriums beeinflussen können. • Forward Slicing – Beinhaltet alle Anweisungen, die von der Variable des Slicing-Kriteriums beeinflusst werden. Sebastian Meyer: Slicing 10 Einsatzzwecke von Slicing • Debuggen • Testen • Zusammenfügen zweier Programme • Software Wartung • Compilerbau Sebastian Meyer: Slicing 11 Static Slicing (I) • Die Analyse erfolgt unabhängig von einer bestimmten Startkonfiguration. • Berechnung des Control flow graphs (CFG) Sebastian Meyer: Slicing 12 Control flow graph (I) • Ein CFG ist ein gerichteter Graph – Die Knoten repräsentieren die Anweisungen des Programms – Die Kanten repräsentieren den Kontrollfluss des Programms • Zu jedem Knoten kann notiert werden, welche Variablen definiert oder geschrieben werden (def) und welche Variablen gelesen werden (ref). • Bei Verzweigungen wird jede ausgehende Kante mit einem eindeutigen Label beschriftet. Sebastian Meyer: Slicing 13 Control flow graph (II) START int i = 0; def = {i} int sum = 0; while (i <= n ) def = {sum} ref = {i,n} true if (i % 2 == 1) false true ref = {i} sum++; false def = {sum} i++; def = {i} return sum; ref = {sum} EXIT Sebastian Meyer: Slicing 14 Static Slicing (II) • Die Analyse erfolgt unabhängig von einer bestimmten Startkonfiguration. • Berechnung des Control flow graphs (CFG) • Berechnung des Program dependence graph (PDG) Sebastian Meyer: Slicing 15 Program dependence graph (I) • Besteht aus dem Data dependence graph – Ein gerichteter Graph G, dessen Knoten N die Anweisungen des Programms enthalten. – Die Kanten K geben die Abhängigkeit der Variablenbenutzung an • Berechnungsvorschrift: 1. ∃ Weg p von n nach m im CFG (n →* m) 2. ∃ Variable v, mit v ∈ def(n) und v ∈ ref(m) 3. ∀ Knoten k ≠ n im Pfad p gilt: v ∉ def(k) Sebastian Meyer: Slicing 16 Program dependence graph (II) int i = 0; int sum = 0; while (i <= n ) if (i % 2 == 1) return sum; i++; sum++; Sebastian Meyer: Slicing 17 Program dependence graph (III) • Besteht aus dem Control dependence graph – Ein gerichteter Graph G, dessen Knoten N die Anweisungen des Programms plus den Startpunkt enthalten. – Die Kanten geben die Abhängigkeiten der Anweisungen untereinander an. Sebastian Meyer: Slicing 18 Program dependence graph (IV) • Control dependence graph: Berechnung – Erweitern des CFG um eine Kante von Start zu Stop – Berechnung der Post-Dominatoren – Berechnung des CDG 1. ∃ Pfad p von n nach m im CFG (n →* m) 2. m ist ein Post-Dominator für jeden Knoten in p, außer für n 3. m ist kein Post-Dominator für n. Sebastian Meyer: Slicing 19 Program dependence graph (V) Sebastian Meyer: Slicing 20 Program dependence graph (VI) • Das Zusammenfügen des Control und des Data dependence graphs ergibt den Program dependence graph. Sebastian Meyer: Slicing 21 Static Slicing (III) • Die Analyse erfolgt unabhängig von einer bestimmten Startkonfiguration. • Berechnung des Control flow graphs (CFG) • Berechnung des Program dependence graph (PDG) • Berechnung des static slice aus dem PDG Sebastian Meyer: Slicing 22 Static Slicing (IV) • Nach Berechnung des PDG lässt sich aus diesem ein static slice berechnen. • Ein backward slice S(n) über den PDG am Knoten n besteht aus allen Knoten m, von denen n (transitiv) abhängt: S(n) = {m | m →* n} • Ein forward slice SF(n) über den PDG am Knoten n besteht aus allen Knoten m, die (transitiv) von n abhängen: SF(n) = {m | n → * m} • n ist dann das Slicing-Kriterium. Sebastian Meyer: Slicing 23 Static Slicing (V) 1: int OddNumsSum(int n) 2: { 3: int i = 0; 4: 5: while (i <= n) 6: { 7: 8: 9: i++; 10: } 11: 12: } Static Backward Slice für (i,8) 1: int OddNumsSum(int n) 2: { 3: 4: 5: while (i <= n) 6: { 7: if (i % 2 == 1) 8: sum++; 9: i++; 10: } 11: return sum; 12: } Static Forward Slice für (i,8) Sebastian Meyer: Slicing 24 Fortgeschrittenes Static Slicing • Beachtung von Nebeneffekten bei Strukturen/Arrays • Pointer-Arithmetik • Slicing über mehrere Prozeduren • Slicing von Vererbungen • Slicing von Nebenläufigen Programmen Sebastian Meyer: Slicing 25 Fazit Static Slicing • Aufwand hängt im wesentlichen von der Anzahl der verwendeten Variablen und den Knoten und Kanten im CFG ab. • Die Überführung in einen PDC kann leicht mittels syntaktischer Analyse vorgenommen werden. – Dies ist ein Vorteil bei der Berechnung von mehreren Slices • Die Berechnung eines static backward slices kann immer in endlich vielen Schritten vorgenommen werden. • Static Slicing liefert eine Abschätzung nach oben. Sebastian Meyer: Slicing 26 Dynamic Slicing • Zusätzlich zum Slicing-Kriterium muss auch noch Startkonfiguration berücksichtigt werden. – Abhängig von der Startkonfiguration kann für ein Kriterium verschiedene Slices berechnet werden • Es muss eine semantische Analyse vorgenommen werden um einen vollständigen Program-Execution-Trace zu erhalten – Probleme bei Endlosschleifen • Aus dem Programm und dem Program-Execution-Trace kann für die spezielle Startkonfiguration zu einem Slicing-Kriterium der dynamic slice berechnet werden. Sebastian Meyer: Slicing 27 Unterschiedliche Startkonfigurationen 1: int OddNumsSum(int n) 2: { 3: int i = 0; 4: int sum = 0; 5: while (i <= n) 6: { 7: if (i % 2 == 1) 8: 9: i++; 10: } 11: return sum; 12: } Dynamic Backward Slice für (sum, 10) und n=0 1: int OddNumsSum(int n) 2: { 3: int i = 0; 4: int sum = 0; 5: while (i <= n) 6: { 7: if (i % 2 == 1) 8: sum++; 9: i++; 10: } 11: return sum; 12: } Dynamic Backward Slice für (sum, 10) und n=1 Sebastian Meyer: Slicing 28 Program execution trace • Problem: Berechnung des PET • Ideen: – Ergänzung des Programms um Anweisungen zur Erzeugung eines PET – Interpretation des Quellcodes • Bei Anweisungen mit Nebeneffekten kann es aufgrund der schwierigen Berechnung zu Ungenauigkeiten kommen. Sebastian Meyer: Slicing 29 Fazit Dynamic Slicing • Der Aufwand zur Berechnung des PET kann schnell sehr gross werden. • Durch die unbedingte Ausführung des Programms kann der Aufwand so groß werden, dass er in keinem Verhältnis zur eingesetzten Zeit steht. • Dynamic Slicing liefert eine Abschätzung nach unten. Sebastian Meyer: Slicing 30 Operationen auf Slices • Schnitt zwischen zwei Slices – Ergibt die gemeinsam genutzten Anweisungen. • Schnitt zwischen Forward und Backward Slice – Anweisungen, die eine Eingabe zu einer Ausgabe transformiert. Sebastian Meyer: Slicing 31 Approximate Dynamic Slicing • Mischung aus Static Slicing und (Exact) Dynamic Slicing • Zunächst wird der PET gebildet • Darauf wird ein Static Slice für das Slicing-Kriterium berechnet Sebastian Meyer: Slicing 32 Fazit • Static slicing kann mit geringem Aufwand berechnet werden, Slices sind jedoch nicht unbedingt minimal. • Dynamic slicing liefert genauere Slices hat aber teilweise einen unverhältnismäßigen Berechnungsaufwand. • Slicing ist immer noch Gegenstand aktueller Forschung. • Static Slicing ist Handwerkszeug des Compilerbaus. Sebastian Meyer: Slicing 33