Kapitel 5 Statische Programmanalyse

Ähnliche Dokumente
Software Engineering. Statische Analyse! Kapitel 11

Kapitel 5: Statische Analyse

Visualisierung feingranularer Abhängigkeiten

C.3 Funktionen und Prozeduren

Seminar Werkzeuggestütze. tze Softwareprüfung. fung. Slicing. Sebastian Meyer

Elementare Konzepte von

Interpreter - Gliederung

Programmiersprachen und Übersetzer

4.Grundsätzliche Programmentwicklungsmethoden

JavaScript. Dies ist normales HTML. Hallo Welt! Dies ist JavaScript. Wieder normales HTML.

Definition Compiler. Bekannte Compiler

EIGENSCHAFTEN VON SPRACHEN

VBA-Programmierung: Zusammenfassung

zu große Programme (Bildschirmseite!) zerlegen in (weitgehend) unabhängige Einheiten: Unterprogramme

Einführung in den Einsatz von Objekt-Orientierung mit C++ I

C++ Teil 2. Sven Groß. 16. Apr IGPM, RWTH Aachen. Sven Groß (IGPM, RWTH Aachen) C++ Teil Apr / 22

zu große Programme (Bildschirmseite!) zerlegen in (weitgehend) unabhängige Einheiten: Unterprogramme

Static-Single-Assignment-Form

3.4 Struktur von Programmen

Informatik I Übung, Woche 41

Schachtelung der 2. Variante (Bedingungs-Kaskade): if (B1) A1 else if (B2) A2 else if (B3) A3 else if (B4) A4 else A

9.4 Grundlagen des Compilerbaus

Vorlesung Software-Reengineering

Einführung Datentypen Verzweigung Schleifen. Java Crashkurs. Kim-Manuel Klein May 4, 2015

Einführung in die C-Programmierung

Werkzeuge zur Programmentwicklung

Lehrstuhl Informatik VI Grundzüge der Informatik * WS 2008/2009 Prof. Dr. Joachim Biskup

Funktionen. Überblick über Stored Functions. Syntax zum Schreiben einer Funktion. Schreiben einer Funktion

Grundlagen der Programmierung Prof. H. Mössenböck. 6. Methoden

Grundlagen der Informatik I (Studiengang Medieninformatik)

Einführung in die Programmierung mit VBA

Prozedurale Datenbank- Anwendungsprogrammierung

Compilerbau mit Phoenix

Zwischencodeerzeugung Compiler II

Repetitorium Informatik (Java)

Programmierung 2. Übersetzer: Das Frontend. Sebastian Hack. Klaas Boesche. Sommersemester

Array-Zuweisungen. Array-Zuweisungen können über die Position, den Namen oder gemischt erfolgen.

2. Algorithmenbegriff

Software-Praktikum. Überblick und Zeitplan

Grundlagen der Datenflußanalyse. und Programmabhängigkeitsgraphen

Fachseminar. Semantische Analyse

Programmierkurs Python I

Theoretische Informatik I

Vorkurs C++ Programmierung

Ausarbeitung des Interpreter Referats

Informatik I Übung, Woche 40

C- Kurs 04 Anweisungen

Rechnerarchitektur Teil 2

StuPro Visualisierung der Ergebnisse von Programmanalysen

Assembler - Einleitung

1. Grundzüge der Objektorientierung 2. Methoden, Unterprogramme und Parameter 3. Datenabstraktion 4. Konstruktoren 5. Vordefinierte Klassen

Typ : void* aktuelle Parameter Pointer von beliebigem Typ

Aufgabe Total Punkte

Berichte aus der Informatik. Dieter Pawelczak. Start in die C-Programmierung

Programmieren in C. Eine Einführung in die Programmiersprache C. Prof. Dr. Nikolaus Wulff

ALGOL 68 im Aspekt einer modernen Programmiersprache???

Kurze Einführung in die Programmiersprache C++ und in Root

Algorithmen & Programmierung. Steuerstrukturen im Detail Selektion und Iteration

Präzedenz von Operatoren

Informatik I - Programmierung Globalübung Hoare-Kalkül. Thomas Weiler. Fachgruppe Informatik RWTH Aachen. T. Weiler, RWTH Aachen - 1 -

Programmieren in Haskell. Stefan Janssen. Strukturelle Rekursion. Universität Bielefeld AG Praktische Informatik. 10.

EIDI 1 Einführung in die Informatik 1. PGdP Praktikum Grundlagen der Programmierung. Harald Räcke 2/217

SOMA Reverse Engineering

Theoretische Informatik 2 bzw. Formale Sprachen und Berechenbarkeit. Sommersemester Herzlich willkommen!

Javakurs für Anfänger

Semantik von Programmiersprachen Theorie und Anwendungen (Informatik III, Wintersemester 03/04)

1 Aufgaben 1.1 Umgebungsvariable setzen: CLASSPATH

Lexikalische Programmanalyse der Scanner

Validating the Object Calisthenics

Programmieren I. Kapitel 5. Kontrollfluss

Kapitel 4: Syntaxdiagramme und Grammatikregeln

8. Stateflow Grundlagen. Daniel Schrammel - BA Stuttgart -

GTI. Hannes Diener. 18. Juni. ENC B-0123,

1.) Zahlensysteme (10 Punkte)

Taschenrechner Version 6.1

Programmiersprachen Einführung in C. Unser erstes C-Programm. Unser erstes C-Programm. Unser erstes C-Programm. Unser erstes C-Programm

6. Iteration (Schleifenanweisungen)

Einführung in die Informatik I (autip)

Einführung in die Programmierung

Inhaltsverzeichnis. Einführende Bemerkungen 11. Das Fach Informatik 11 Zielsetzung der Vorlesung Grundbegriffe

Programmieren in C / C++ Grundlagen C 4

6 Systematisches Testen von Programmen

Klassen und Objekte. Klassen sind Vorlagen für Objekte. Objekte haben. Attribute. Konstruktoren. Methoden. Merkblatt

Programmierkurs II. C und Assembler

Programmiersprache 1 (C++) Prof. Dr. Stefan Enderle NTA Isny

Grundlagen der Fortran Sprache

Verschlüsseln eines Bildes. Visuelle Kryptographie. Verschlüsseln eines Bildes. Verschlüsseln eines Bildes

Transkript:

Kapitel 5 Statische Programmanalyse Harald Gall Software Engineering Group seal.ifi.unizh.ch Universität Zürich Institut für Informatik

Inhalt Grundlagen Analyse von Programmen Darstellungen für die Programmanalyse Program Slicing 2

Grundlagen Statische Analyse ist die Untersuchung des statischen Aufbaus eines Prüflings auf die Erfüllung vorgegebener Kriterien. Die Prüfung ist statisch. Sie grenzt sich damit vom (dynamischen) Test ab. Sie ist formal durchführbar und damit automatisierbar. Sie grenzt sich damit vom Review ab. Ziele Bewertung von Qualitätsmerkmalen, z.b. Pflegbarkeit, Testbarkeit aufgrund struktureller Eigenschaften des Prüflings (zum Beispiel Komplexität, Anomalien) Erkennung von Fehlern und Anomalien in neu erstellter Software Erkennung und Analyse von Programmstrukturen bei der Pflege und beim Reengineering von Altsystemen (legacy systems) Prüfen, ob ein Programm formale Vorgaben (zum Beispiel Codierrichtlinien,Namenskonventionen, etc.) einhält slide by Martin Glinz 3

Analyse von Programmen Syntax Analyse durch den Compiler Datentypen, Typverträglichkeit typ-unverträgliche Operationen typ-unverträgliche Zuweisungen typ-unverträgliche Operationsaufrufe slide by Martin Glinz 4

Programm- und Datenstrukturen Formale Eigenschaften Strukturfehler bzw. -anomalien Richtlinien eingehalten nicht erreichbarer Code Art und Menge der internen Dokumentation vorhandene, aber nicht benutzte Operationen Strukturkomplexität des Progamms Einhaltung von Strukturierungsregeln benutzte, aber nicht vorhandene Operationen Fehler / Anomalien in den Daten Art und Tiefe von Verschachtelungen nicht deklarierte Variablen nicht benutzte Variablen Benutzung nicht initialisierter Variablen slide by Martin Glinz 5

Vorgehen Bei Programmen immer mit Werkzeugen Compiler syntaxgestützte Editoren spezielle Analyse-Werkzeuge Programm wird wie bei der Übersetzung durch ein Werkzeug zerlegt (parsing) und in einer analysefreundlichen internen Struktur repräsentiert Dabei werden Syntaxfehler erkannt und erste Kenngrößen (z. B. Anzahl Codezeilen, Anzahl Kommentare) ermittelt Die resultierende interne Repräsentation des Programms wird verschiedenen Analysen unterworfen (z.b. statische Aufrufhierarchie, Strukturkomplexität, Datenflussanalyse) Die Befunde werden gesammelt, ggf. verdichtet und bewertet slide by Martin Glinz 6

Weitere Analysen Analyse von Algorithmen Laufzeiteffizienz Speichereffizienz Gültigkeitsbereich Erfolgt weitestgehend manuell Analyse von Spezifikationen, Entwürfen, Prüfvorschriften Syntaxanalyse der formal beschriebenen Teile Teilweise Struktur- und Flussanalysen (je nach verwendeter Modellierungsmethode) Analyse der Anforderungsverfolgung, wenn dokumentiert ist, welche Anforderung wo umgesetzt bzw. geprüft wird (werkzeuggestützt möglich) slide by Martin Glinz 7

Darstellungen für die Programmanalyse Abstrakte Syntaxbäume Kontrollflussanalyse Datenflussanalyse Universität Zürich Institut für Informatik

Inhalt Lernziele Grundlagen für Programmanalysen Unterschiedliche Anforderungen innerhalb des (Re)Engineerings Verständnis der Abstraktionsebenen von Programmdarstellungen Kontext Grundlegende Programmanalysen sind Basis aller weiteren Analysen 9

Compiler Struktur 10

Analysator Struktur 11

Phasen eines Compilers Wissen über das Programm nimmt zu syntaktische Dekomposition semantische Attributierung Namensbindung Kontrollflussinformation Datenflussinformation Abstraktion nimmt ab abstrakter Syntaxbaum maschinennahe einheitliche Zwischensprache, z.b. Register Transfer Language (RTL) von Gnu GCC Maschinensprache 12

Unterschiede Compiler / Analysator lokal versus global optimistisch versus pessimistisch quellennah versus sprachenunabhängig 13

Der Tokenstrom Für das Programmstück declare X : real; begin X := A * 5; end liefert der Lexer neben der Quellposition die Lexeme (Token) durch Integer-Kennung der erkannten Kategorie und ggf. die Zeichenkette: 9 -- declare 4 -- id, X 7 -- : 4 -- id, real 5 -- ; 6 -- begin 4 -- id, X 3 -- := 4 -- id, A 8 -- * 10 -- int_lit, 5 5 -- ; 11 -- end 14

Der Lexer Grammatik D [0-9] L [a-z,a-z] else { return(else); } {L} ( {L} {D} )* { yylval.id = register_name(yytext); return (ID); } Lexergenerator Lexer 15

Abstrakte Syntaxbäume (AST) Darstellung der syntaktischen Dekomposition des Eingabeprogramms vereinfachter Ableitungsbaum: keine Kettenregeln, Sequenzen ersetzen Rekursionen etc. syntaktische Kanten bilden einen Baum Eine formale Syntaxbeschreibung (BNF) legt die syntaktische Struktur fest: Proc ::= PROCEDURE Id PL ";". PL ::= "(" Params ")" e. Params ::= Param "," Params Param. Param ::= Id. 16

Ableitungsbaum / abstrakter Syntaxbaum 17

Beispiel eines ASTs 18

Anforderungen an Zwischendarstellungen widersprüchliche Anforderungen möglichst quellennah, da Informationen an Wartungsprogrammierer ausgegeben werden sollen bzw. tatsächlicher Code wieder generiert werden soll d.h. alle spezifischen Konstrukte müssen dargestellt werden möglichst vereinheitlicht, um das Schreiben von Programmanalysen für verschiedene Programmiersprachen zu vereinfachen d.h. möglichst wenige, allgemeine Konstrukte 19

Quellennahe Betrachtung 20

Einfache allgemeine Konstrukte 21

Vereinigung der Sichten 22

Zwischendarstellungen Im Folgenden präsentieren wir die wichtigsten Elemente der Darstellung dynamischer Semantik und deren Herleitung... Kontrollflussanalyse Datenflussanalyse 23

Kontrollflussinformation intraprozedural: Flussgraph Knoten: Grundblöcke Kanten: (bedingter/unbedingter Kontrollfluss ergibts sich aus syntaktischer Struktur und etwaigen Goto s, Exit s, Continue s, etc. interprozedural: Aufrufgraph Multigraph Knoten: Prozeduren Kanten: Aufruf ergibt sich aus expliziten Aufrufen im Programmcode sowie Aufrufe über Funktionszeiger 24

Intra- und interproz. Kontrollfluss 25

Kontrollabhängigkeit Kontrollabhängigkeit = Bedingung B, von welcher die Ausführung eines anderen Knotens X abhängt. B muss mehrere direkte Nachfolger haben B hat einen Pfad zum Endknoten, der X vermeidet (d.h. B kann nicht von X postdominiert werden) B hat einen Pfad zu X, d.h. insgesamt hat B mindestens 2 Pfade: einer führt zu X einer umgeht X B ist der letzte Knoten mit einer solchen Eigenschaft 26

Dominanz Fragestellungen Welche Prozeduren sind lokal zueinander? Genauer: Gibt es eine Prozedur D, über nur die ein Aufruf von N erfolgt? Welcher Block D im Flussgraph muss in jedem Falle passiert werden, damit Block N ausgeführt werden kann? Antwort: D ist der Dominator von N Ein Knoten D dominiert einen Knoten N, wenn D auf allen Pfaden vom Startknoten zu N liegt. Ein Knoten D ist der direkte Dominator von N, wenn D dominiert N und alle weiteren Dominatoren von N dominieren D 27

Dominanz II 28

Postdominanz Ein Knoten D postdominiert einen Knoten N, wenn jeder Pfad von N zum Endknoten den Knoten D enthält (entspricht Dominanz des umgekehrten Graphen). 29

Kontrollabhängigkeit I Kontrollabhängigkeit = Bedingung B, von welcher die Ausführung eines anderen Knotens X abhängt. B muss mehrere direkte Nachfolger haben und B hat einen Pfad zum Endknoten, der X vermeidet (d.h. B kann nicht von X postdominiert werden) und B hat einen Pfad zu X, d.h. insgesamt hat B mindestens 2 Pfade: einer führt zu X einer umgeht X und B ist der letzte Knoten mit einer solchen Eigenschaft 30

Kontrollabhängigkeit II Ein Knoten X ist kontrollabhängig von einem Knoten B genau dann, wenn es einen nicht-leeren Pfad von B nach X gibt, so dass X jeden Knoten auf dem Pfad (ohne B) postdominiert entweder X = B oder X postdominiert B nicht 31

Kontrollabhängigkeit Für strukturierte Programme eine Anweisung ist kontrollabhängig von der Bedingung der nächstumgebenden Schleife oder bedingten Anweisung while a loop if b then x := y; --- kontrollabhängig von b end if; z := 1; --- kontrollabhängig von a end loop; N.B.: Bedingungen in repeat-schleifen sind von sich und dem umgebenden Konstrukt abhängig 32

Repräsentation der Kontrollabhängigkeit 33

Datenabhängigkeitsanalyse Set = Setzen eines Wertes Use = Verwendung eines Wertes Daraus ergeben sich folgende relevanten Beziehungen zwischen zwei Anweisungen (resp. Knoten) A und B: Set-Use Beziehung (Datenabhängigkeit) A setzt den Wert, der von B verwendet wird Use-Set Beziehung (Anti-Dependency) A liest den Wert und B überschreibt ihn danach Set-Set Beziehung (Output-Dependency) der von A gesetzte Wert wird von B überschrieben Codetransformationen müssen diese Beziehungen erhalten. 34

Datenabhängigkeit (Set-Use) Für die Zwecke der Analyse ist die Set-Use Beziehung die wichtigste Beziehung und wird intern oft explizit repräsentiert (meist in der umgekehrten Richtung). Zwischen der 2. und 3. Anweisung besteht eine Use-Set, zwischen der 1. und 3. Anweisung eine Set-Set -Beziehung. 35

Repräsentation der Datenabhängigkeit 36

Weiterführende Literatur Robert Morgan, Building an Optimizing Compiler, Addison Wesley beschreibt Zwischendarstellungen sowie Kontroll- und Datenflussanalysen R. Koschke, J.-F. Girard, M. Würthner, An Intermediate Representation for Reverse Engineering Analyses, Proceedings of the Working Conference on Reverse Engineering, IEEE CS, 1998 beschreibt Zwischendarstellungen für das Reverse Engineering und dessen spezielle Anforderungen 37

Program Slicing und seine Anwendung Program Slicing, by Mark Weiser, IEEE Transactions on Software Engineering, July 1984 Universität Zürich Institut für Informatik

Program Slicing Lernziel Verständnis von Slicing-Varianten einschließlich ihrer Berechnung und Anwendbarkeit Kontext Erste unmittelbare Anwendung von Compilerbau- Technologie zur Unterstützung des Programmverstehens Program Slicing ist Basis-Technologie für viele weitere (Re)Engineering-Techniken 39

Das tägliche Brot des Wartungsprogrammierers read (n); i:= 1; sum := 0; product := 1; while i <= n loop sum := sum + i; product := product * i; i := i + 1; end loop; write (sum); write (product); Was wird durch diese Anweisung beeinflusst? Wie kommt es zu diesem Wert? 40

Programmanalyse /1 read (n); i:= 1; sum := 0; product := 1; while i <= n loop sum := sum + i; product := product * i; i := i + 1; end loop; write (sum); write (product); Wie kommt es zu diesem Wert? 41

Programmanalyse /2 Was wird durch diese read (n); Anweisung beeinflusst? i:= 1; sum := 0; product := 1; while i <= n loop sum := sum + i; product := product * i; i := i + 1; end loop; write (sum); write (product); 42

Wie kommt es zu diesem Wert? Backward Slice (write(product)): read (n); i:= 1; sum := 0; product := 1; while i <= n loop sum := sum + i; product := product * i; i := i + 1; end loop; write (sum); write (product); 43

Was wird durch diese Anweisung beeinflusst? Forward Slice (sum := 0): read (n); i:= 1; sum := 0; product := 1; while i <= n loop sum := sum + i; product := product * i; i := i + 1; end loop; write (sum); write (product); 44

Was ist ein Slice? Slicing (P, S) bezüglich eines Programmpunktes S entfernt jene Teile eines Programms P, die das Verhalten an S nicht beeinflussen. Ein Forward Slice enthält nur solche Anweisungen von P, die von der Ausführung von S beeinflusst werden. Ein Backward Slice enthält nur solche Anweisungen von P, die das Programmverhalten an S beeinflussen. Ein Punkt S beeinflusst einen Punkt S, wenn S kontrolloder datenabhängig von S ist. 45

Slicing Die Idee und die erste Technik des Slicings stammt von Mark Weiser (1984). Moderne SlicingTechniken basieren auf dem Program Dependency Graph (PDG) bzw. System Dependency Graph (SDG) für interprozedurales Slicing: Kanten A--> B im PDG: B ist daten- bzw. kontrollabhängig von A Forward Slicing: Graph-Traversierung in Richtung der Kontrollund Datenabhängigkeitskanten Backward Slicing: Graph-Traversierung in umgekehrter Richtung der Kontroll- und Datenabhängigkeitskanten 46

Program Dependency Graph (PDG) PDG = gerichteter Multigraph für Daten- und Kontrollflussabhängigkeiten Knoten repräsentieren Zuweisungen und Prädikate zusätzlich einen speziellen Entry-Knoten zusätzlich Ø-Knoten zur Reduktion der Datenabhängigkeitskanten (sowie einen Initial-Definition-Knoten für jede Variable, die benutzt werden kann, bevor sie gesetzt wird) Kontroll-Kanten repräsentieren Kontrollabhängigkeiten Startknoten jeder Kontrollabhängigkeitskante ist entweder der Entry-Knoten oder ein Prädikatsknoten Fluss-Kanten repräsentieren Set-Use-Abhängigkeiten 47

Program Slicing mit PDG B ist datenabhängig von A A B B ist kontrollabhängig von A A B 48

Program Slicing mit PDG 49

Interprozedurales Slicing procedure Main is sum, i : Integer; begin sum := 0; i := 1; while i < 11 loop A (sum, i); end loop; end Main; procedure A (x : in out Integer; y : in out Integer) is begin Add (x, y); Inc (y); end A; procedure Add (a : in out Integer; b : in out Integer) is begin a := a + b; end Add; procedure Inc (z : in out Integer) is one : Integer := 1; begin Add (z, one); end Inc; Annahme: Parameterübergabe per copy-in/copy-out 50

PDG PDG stellt Abhängigkeiten innerhalb einer Funktion dar System Dependency Graph (SDG) stellt globale Abhängigkeiten dar: PDGs für verschiedene Unterprogramme werden vernetzt über interprozedurale Kontroll- und Datenflusskanten Aufruf: Call-Knoten aktuelle Parameter: actual-in / actual-out-knoten (copy-in/copy-out- Parameterübergabe vorausgesetzt) formale Parameter: formal-in / formal-out-knoten transitive Abhängigkeiten via PDG: Summary-Edges 51

Modellierung des Prozeduraufrufs x_in := sum3; y_in := i3; A; sum2 := x_out; i2 := y_out; procedure A is begin x0 := x_in; y0 := y_in;... x_out := x1; y_out := y1; end A; 52

System Dependence Graph 53

Naives interprozedurales Slicing Folge allen Flow- und Control-Kanten Problem: Formale in-parameter können mehrere Vorgänger haben, formale out-parameter mehrere Nachfolger 54

Interprozedurales Slicing (Traversierung) Backward-Slicing (Prozedur P, Statement S): Phase 1: Folge rückwärts Flow- (inklusive Summary-)/Control-/Call- und Parameter-In-Kanten ausgehend von S Identifiziert Knoten in Prozeduren, die P (transitiv) aufrufen und von denen S abhängt. Da Parameter-Out-Edges ausgenommen sind, werden nur aufrufende Prozeduren besucht. Die Effekte nicht-besuchter Prozeduren werden aber nicht ignoriert, da Summary-Edges traversiert werden. 55

Interprozedurales Slicing II Phase 2: Folge rückwärts Flow -(inklusive Summary-) / Control- und Parameter- Out-Kanten ausgehend von allen Knoten, die in Phase 1 identifiziert wurden. Identifiziert Knoten in Prozeduren, die von P (transitiv) aufgerufen werden und von denen S abhängt. Da Parameter-In-Edges ausgenommen sind, werden nur aufgerufene Prozeduren besucht. Es gilt wieder: Die Effekte nicht-besuchter Prozeduren werden nicht ignoriert, da Summary-Edges traversiert werden. 56

Summary Edges repräsentieren (transitive) Abhängigkeiten der aktuellen In- und Out- Parameter an einer gegebenen Aufrufstelle helfen während des Slicings, unnötige Abstiege in aufgerufene Prozeduren zu vermeiden werden in zwei Schritten ermittelt: direkte Abhängigkeiten zwischen den formalen Parametern innerhalb der aufrufenden Prozedur indirekte Abhängigkeiten, die sich transitiv durch Aufruf anderer Prozeduren ergeben werden hergeleitet mit bekannten Techniken zu Abhängigkeiten in Attributgrammatiken 57

Slicing Variante: Chopping Abhängigkeiten zwischen zwei Punkten: read (n); i:= 1; sum := 0; product := 1; while i <= n loop sum := sum + i; product := product * i; i := i + 1; end loop; write (sum); write (product); 58

Anwendungen von Slicing Programmverstehen Reduzierung des Codes auf das für das Verständnis notwendige Maß Änderungsanalyse alle von einer Änderung betroffenen Stellen Regressionstesten Reduktion des zu testenden Codes Restrukturierung z.b. Aufteilung von Unterprogrammen, die mehrere logisch verschiedene Funktionen implementieren Bewertung der Änderbarkeit (und somit der Wartbarkeit) eines Systems Messung von Kohäsion 59