Werkzeuge zur Codeanalyse

Thomas G¨ngler a
Technische Universit¨t Dresden, Fakult¨t Informatik, a a Institut Software- und Multimediatechnik, Lehrstuhl Softwaretechnologie, 01062 Dresden, Deutschland s9736463@mail.inf.tu-dresden.de

Zusammenfassung. Der Bereich der Software-Qualit¨tssicherung bea kommt in letzter Zeit eine immer gr¨ßere Bedeutung. Nachdem fast o allt¨glich Nachrichten von Programmierfehlern in großen Projekten die a Schlagzeilen machen, sind die Hersteller nun gefordert geeignete L¨suno gen zu entwickeln und einzusetzen um diesen negativen Trend entgegenzuwirken. Durch die enorm gestiegene Komplexit¨t von modernen a Software-Systemen ist es wirtschaftlich und technisch fast nicht mehr m¨glich diese Aufgaben manuell zu erledigen. Werkzeuge zur Codeanao lyse automatisieren einen großen Teil dieser Arbeit und sollen in diesen Aufsatz umfassend vorgestellt, unterschieden und klassifiziert werden und somit dem Entwickler helfen den richtigen Einstieg in diesen Bereich zu finden.

1

Einleitung

Software-Qualit¨t und das damit verbundene Code-Quality-Management spiea len eine große Rolle bei modernen Software-Entwicklern. Dass die Wahrung von Qualit¨tskriterien mit wachsender Codezeilenanzahl eines Projektes immer koma plexer und schwieriger wird, ist ein einfache logische und allseits bekannte Folge. Die immer umfangreicheren Entwicklungsumgebungen oder separate Werkzeuge sollen dem Entwickler dabei einen großen Teil der manuelle Test- und Analysearbeit abnehmen. Trotzdem herrscht bei den beteiligten Rollen im Softwareentwicklungsprozess noch oft Unklarheit bei folgenden Fragen. Welche M¨glicho keiten zum Test- und Analysieren gibt es berhaupt? Welches Werkzeug erledigt welche Aufgabe im Qualit¨tssicherungszyklus? Deshalb soll dieser Aufsatz einen a ¨ Einblick und Uberblick in die Vielzahl vorhandener Test- und Analysewerkzeuge und deren Einsatzgebiete beschrieben. Als Erstes soll eine Typisierung f¨r Werku zeuge zur Sicherung von Software-Qualit¨t vorgestellt werden und insbesondere a auf die Kategorien zum Testen und zur Codeanalyse eingegangen werden (s. Kap. 2). Dabei werden immer wieder Beispielwerkzeuge genannt, wobei der Fokus i.A. auf frei erh¨ltlichen Vertretern liegt und diese oft auch als Plug-in f¨r a u die Eclipse Entwicklungsumgebung erh¨ltlich sind. a Danach wird auf die, erweiterten statischen Analysewerkzeuge eingegangen, welche durch kurze Beschreibungen von zwei Beispielen abgerundet wird (s. Kap. 3). Anschließend folgt ein Kapitel uber Portale (s. Kap. 4). Diese Form ver¨ eint mehrere Werkzeugtypen in auf sinnvolle Art und Weise, und erleichtert die

2

Zusammenarbeit zwischen den verschiedenen Rollen in der Softwareentwicklung. Letztendlich gibt das Fazit zum Schluss noch einmal ein kurze Zusammenfassung uber die Vorteile und den Nutzen des Einsatzes von Werkzeugen zur Codeana¨ lyse.

2

Werkzeugtypen

Die Unterteilung der Werkzeugtypen h¨lt sich grob an die Vorlage von Liggesa meyer [6]. Dabei wird insbesondere auf die Typen dynamische Testwerkzeuge (s. Kap. 2.1) und statische Analysewerkzeuge (s. Kap. 2.2) eingegangen. Diese kooperieren oft miteinander bzw. sind ineinander integriert und bilden generell die zahlenm¨ßig st¨rkste Kategorie. Deshalb werden sie in diesem Aufsatz a a besonders analysiert. Des weiteren werden anschließend noch die beiden Werkzeugtypen formale Verifikationswerkzeuge (s. Kap. 2.3), und modellierende und analysierende Werkzeuge (s. Kap. 2.4) vorgestellt, welche zwar Grundlagen f¨r u die erweiterten statischen Analysewerkzeuge (s. Kap. 3) bereitstellen, generell aber gesondert und ausf¨hrlicher betrachtet werden m¨ssen. u u 2.1 Dynamische Testwerkzeuge

Die Kategorie der dynamischen Testwerkzeuge kann in verschiedene Unterkategorien unterteilt werden, wobei die einzelnen Werkzeugtypen eng miteinander in Verbindung stehen. Generell wird durch Vertreter dieser Kategorie das Programm w¨hrend des Tests mit ausgef¨hrt und somit Daten uber die Leia u ¨ stungsf¨higkeit und Funktionsweise der Anwendung ermittelt. Im Folgenden wera den nun die vier Typisierungen der dynamischen Testwerkzeuge erl¨utert. a Strukturorientierte Testwerkzeuge. Vertreter dieser Unterkategorie stellen dem Entwickler Informationen uber den Stand der Pr¨fung bereit. Zum Nachweis der u ¨ ordungsgem¨ßen Durchf¨hrung von Tests werden diverse Test¨berdeckungsproa u u tokolle angewandt, d.h. es wird i.A. immer eine vollst¨ndige Abdeckung des jea ¨ weiligen Uberdeckungstests gefordert1 . Der Bekannteste ist dabei der Zweig¨beru ¨ deckungstest, welcher die Ausf¨hrung aller Zweige bzw. die Uberdeckung aller u Kanten fordert [6]. Das Testwerkzeug visualisiert dann die bereits ausgef¨hrten u ¨ Zweige mittels eines automatisch generierten Kontrollflussgraphens. Als Uberdeckungsmaß dient hierbei die Zweig¨berdeckungsrate (absolut oder relativ). Ein u ¨ weiteres Beispiel ist der Statement-Uberdeckungstest, welcher die Ausf¨hrung alu ler Codezeilen eines Programms fordert. Generell gibt es zwei Arbeitsweisen bei strukturorientierten Testwerkzeugen. Die Mehrheit arbeitet instrumentierend, d.h. es werden dem Quellcode zus¨tzliche a Anweisungen hinzugef¨gt (Annotationen). Dies hat den Vorteil, dass das Testu werkzeug beim eigentlichen Test nicht mehr aktiv sein muss; gleichzeitig aber
1

Bei komplexen Programmen kann dies zu einem Zeit intensiven und teuren Prozess werden, wenn alle Testf¨lle von Hand abgewickelt werden m¨ssen [2] a u

3

den Nachteil, dass sich durch die Anweisungsanreicherung die Ausf¨hrungszeit u verl¨ngert. Durch diese Form kann aber eine Merkmalsauswertung bei der Syna taxanalyse mit durchgef¨hrt werden (z.B. Ermittleln der zyklomatischen Zahl ; s. u Kap. 2.2), d.h. statische Analysefunktionalit¨ten sind mit in diesem dynamischen a Testwerkzeug integriert. Dieser Arbeitsweise gegen¨ber steht die nicht Instruu mentierende. Hierbei werden die von der Testausf¨hrung genutzten Adressen diu rekt uber eine Hardware-Schnittstelle abgegriffen, was oft mittels eines separaten ¨ ¨ Computers erledigt wird. Somit k¨nnen Uberdeckungen auf einem niedrigeren o Niveau registriert werden. Durch Caching-Strategien gelangen aber nicht immer alle Adressen die sich auf dem Adressbus befinden zur Ausf¨hrung, was sich u wiederum nachteilig auf die Analyse auswirken kann. Die strukturorientierten Testwerkzeuge bieten unterschiedliche Formen der Darstellung f¨r die jeweiligen Testtypen an. Zum einen sind die grafischen Formen u mit den bereits erw¨hnten Kontrollflussgraphen, welche bei Modultests genutzt a werden, und Strukturdiagramme f¨r Integrationstests. Zum anderen ist die texu tuelle Form, welche eine Aufbereitung des Quelltextes wiedergibt. Oft werden diese Darstellungsformen miteinander kombiniert und es ist z.B. m¨glich von o einer Stelle im Kontrollflussgraphen zum zugeh¨rigen Quelltext zu gelangen. o Diese Form der Testwerkzeuge ist generell programmiersprachen-abh¨ngig durch a die speziellen programmiersprachlichen Konstrukte der jeweiligen Programmiersprache. Es gibt umfassende Unterst¨tzung f¨r C, C++ und Java. Des weiteu u ren gibt es jedoch auch Werkzeuge f¨r spezifischere Programmiersprachen wie u Ada, Pascal und Fortran f¨r den naturwissenschaftlichen Bereich, oder Cobol f¨r u u ¨ den kaufm¨nnischen Bereich (s. Ubersicht auf [1]). Ein Beispiel einer Werkzeua gumgebung, welche strukturorientierte Tests mit durchf¨hren kann, ist die frei u erh¨ltliche Test and Performance Tools Platform 2 (TPTP) von Eclipse. Dieses a Plug-in kann insbesondere einfache und verteilte Java-Anwendungen analysieren und testen. Eine weiteres Beispiel ist das kommerzielle Prevent von der Firma Coverity3 , welches die Programmiersprachen C, C++ und Java unterst¨tzt. u

Funktionsorientierte Testwerkzeuge. Damit eine nahezu vollst¨ndige Testaba deckung gew¨hrleistet werden kann, m¨ssen Tests strukturiert geplant und Testa u f¨lle erzeugt werden. Funktionsorientierte Testwerkzeuge sollen dem Entwickler a helfen Testf¨lle nach diversen Testtechniken planen zu k¨nnen und somit den a o ¨ Komfort zu erh¨hen und einen Uberblick uber die Testplanung bereitzustellen. o ¨ Deshalb ist diese Kategorie durch ihre Abstraktion i.d.R. programmiersprachen¨ unabh¨ngig. Ein Bespiel f¨r eine Testtechnik ist die funktionale Aquivalenzklasa u ¨ senbildung, wobei Testf¨lle aus der Spezifikation des Programmes durch Aquia valenzklassenbildung abgeleitet werden. Dar¨ber hinaus bieten diese Testwerkzeuge die M¨glichkeit zur Definition von u o Testdaten bzw. erwarteten Testergebnissen. Diese Beispieldaten k¨nnen dadurch o
2 3

http://www.eclipse.org/tptp/ http://www.coverity.com/

4

immer wieder verwendet werden4 und erleichtern somit die Testautomatisierung bzw. Wiederverwendbarkeit. Ein Beispieltyp f¨r funktionsorientierte Testwerku zeuge sind Zusicherungswerkzeuge, wo formale Aussagennotationen nach einer festen Syntax in den Quellcode eingef¨gt werden (engl. assertions). Als Beispiel u f¨r diese Unterkategorie kann wieder das TPTP -Plug-in f¨r die Eclipse Interface u u Development Environment (IDE) genannt werden, welches eine Testplanungsund erzeugungsansicht besitzt (inklusive Anlegen und Verwalten von Testdatenpools). Hierbei wird das bekannte Framework zur Testfallgenerierung f¨r Javau Anwendungen, JUnit, mit integriert. Regressionstestwerkzeuge. Nachdem nun mittels funktionsorientierter Testwerkzeuge Tests geplant und Testf¨lle erzeugt, und mittels strukturorientierter Testa werkzeuge w¨hrend der Durchf¨hrung visualisiert werden k¨nnen; ben¨tigt der a u o o Entwickler noch einen Werkzeugtyp zur Automatisierung der Testdurchf¨hrung. u Regressionstestwerkzeuge erm¨glichen das Einspielen von Testdaten und das o Aufzeichnen von Testergebnissen. Somit ist ein Vergleich zwischen unterschiedlichen Testdurchl¨ufen gew¨hrleistet und demzufolge eine automatisierte Meldung a a von Abweichungen realisierbar. Generell sollten Regressionstests nach jeder Fehlerkorrektur und Funktionserweiterung5 des Programmes durchgef¨hrt werden. Dies ist wiederum nur durch eine u automatische Testdurchf¨hrung technisch und wirtschaftlich sinnvoll. Im Allgeu meinen k¨nnen diese Werkzeugtypen programmiersprachen-unabh¨ngig arbeio a ten. Sie sind aber manchmal programmiersprachen-spezifisch, wie im Fall von JUnit f¨r Java. Deshalb kann als konkretes Beispiel wieder das TPTP -Plugu in f¨r die Eclipse IDE genannt werden, was u.a. Komponenten zur Historienu Analyse und zur Berichterstattung enth¨lt. a Leistungs- und Stresstestwerkzeuge. Oft mit interegriert in Regressionstestwerkzeuge sind die Unterkategorien f¨r Leistungs- und Stresstests. Die erste Form u ¨ generiert Lasten im Normalbereich an der (vorher festgelegten) Grenze zur Uber¨ last. Die zweite Art simuliert den Betrieb bei Uberlast. Eine, nach festen Vorgaben definierte, Lastenerzeugung kann i.d.R. nur noch werkzeugunterst¨tzt vorgenommen werden, da i.A. Lasten f¨r moderne Mehrbeu u nutzer-Anwendungen nicht mehr von Hand erzeugt werden k¨nnen. Die Lasteno erzeugung kann z.B. durch Vervielf¨ltigung und Modifikation von Regressionsa test-Mitschnitten erstellt werden. Diese Werkzeugtypen enthalten zus¨tzlich dia verse Messfunktionen zum Registrieren von Antwortzeiten und Ressourcenauslastungen. Als Beispiel kommt abermals das TPTP -Plug-in f¨r die Eclipse IDE u in Frage, welches ein Performanz-Testwerkzeug f¨r Webanwendungen enth¨lt. u a 2.2 Statische Analysewerkzeuge

Im Gegensatz zu den Testf¨llen wird bei statischen Analysen nur der Quella code oder dessen Kompilat analysiert und ausgewertet, d.h. es sind keine kon4 5

Weil sie i.d.R. persistent abgespeichert werden, z.B. in einer relationalen Datenbank Wobei hier ggf. die Testf¨lle mit erweitert werden m¨ssen a u

5

kreten Testf¨llen und Testdaten n¨tig. Durch den engen Bezug zum Quellcode a o sind Werkzeuge dieser Kategorie oft programmiersprachen-spezifisch. Wie schon beschrieben, bilden die statischen Analysewerkzeuge oft eine Einheit mit den dynamischen Testwerkzeugen. Analog zu Diesen gibt es hier eine weitere Unterkategorisierung, welche nun vorgestellt wird. Messwerkzeuge. Als erste, sehr verbreitete und recht alte Unterkategorie stehen die Messwerkzeuge. Sie dienen zur Informationsgewinnung und -darstellung mittels statischer Analyse. Hierbei wird der gesamte Quellcode eines Programms analysiert und bestimmte Merkmale registriert. Verbreitete Maße hierf¨r sind: u zyklomatische Zahl, Halstead -Maße, Maße zur Datenkomplexit¨t (z.B. Anzahl a der Klassen) oder Anzahl der Codezeilen (engl. Lines of Code) durch den Nutzer. Diese Maße m¨ssen pr¨zise definiert sein, d.h. es darf kein manueller Eingriff u a w¨hrend der Analyse vom Nutzer stattfinden. a Die Ergebnisse lassen sich entweder in textueller (Tabellen, B¨ume) oder in graa fischer Form (Graphen, Diagramme) darstellen. Die Messwerkzeuge erm¨glichen o es dem Entwickler oft Grenzewerte f¨r diverse Maße zu definieren und in der Eru gebnisdarstellung Grenz¨berschreitungen aufzeigen zu lassen. Die abstrakte Deu finition der Maßberechnungen ist zwar i.A. programmiersprachen-unabh¨ngig a aber zur Ermittlung dieser sind die Werkzeuge i.d.R. programmiersprachenspezifisch. Beispiele sind das bekannte Open-Source Metrics-Plug-in f¨r die Eclipse IDE u von Frank Sauer6 und SemmleCode von der Firma Semmle7 , welches ebenfalls ein frei erh¨ltliches Plug-in f¨r die Eclipse Entwicklungsumgebung ist und u.a. a u Metriken berechnen kann. Stilanalysatoren. Diese Unterkategorie analysiert den Quellcode nach bestimmten vordefinierten oder einstellbaren Verletzungen von Programmierregeln. Dies sind z.B. Einschr¨nkungen von zu verwendenden programmiersprachlichen Kona strukten oder die Definition von zus¨tzlichen Forderungen um strengere Codea Konventionen festzulegen. Stilanalysatoren tragen damit gut zur Vereinheitlichung von Programmcode in großen Projekten bei. Des weiteren sind sie teilweise Voraussetzung f¨r bestimmte Programmiersprachen in bestimmten Anwenu dungsgebieten (z.B. sicherheitskritische Anwendungen). Als ¨ltester Vertreter dieses Werkzeugtyps tritt Lint f¨r die Programmiersprache a u C auf, welche von Natur aus eher schwache Stildefinitionen hat. In der Eclipse IDE ist ein Code Style Dialog schon durch das Java Development Toolkit mit eingebettet, welcher diverse Funktionen zur Code-Formatierung und Stilanalyse bereitstellt. Dar¨ber hinaus ist das Open-Source-Plug-in Checkstyle 8 f¨r diese u u Entwicklerumgebung erh¨ltlich. Dieses Werkzeug besitzt eine anpassbare Kona figuration, welche Standards wie die Sun Code Conventions f¨r Java umsetzen u
6

7 8

http://metrics.sourceforge.net/; nicht zu verwechseln mit dem gleichnamigen Plugin von State Of Flow (http://eclipse-metrics.sourceforge.net/) http://semmle.com/ http://checkstyle.sourceforge.net/

6

kann. Zus¨tzlich kann es noch diverse andere Probleme uberpr¨fen (z.B. Erkena u ¨ nung von dupliziertem Code). Werkzeuge zur Erzeugung von Tabellen und Grafiken. Werkzeuge dieses Typs stellen im eigentlichen Sinn keine separate Unterkategorie von statischen Analysewerkzeugen dar. Sie sind aber i.A. Bestandteil von vielen Werkzeugumgebungen. Wie schon aus der Bezeichnung abgeleitet werden kann, dient dieser Werkzeugtyp zur Erzeugung verschiedenster Ergebnisdarstellungen, z.B. Kontrollfluss- und Aufrufgraphen, oder Variablen-Quer-Verweis-Tabellen. Das Metrics-Plug-in von Frank Sauer kann solche Abh¨ngigkeitsgraphen genea rieren oder die Analyseergebnisse in Tabellen mit B¨umen darstellen. Weitere a Beispiele f¨r Werkzeugumbebungen, die eine solche Visualisierung erm¨glichen u o sind das kommerzielle CodeSonar von Grammatech9 oder SemmleCode, welches Anfragen als Tabelle, Baum, Graph oder Diagramm ausgeben kann10 . Slicing-Werkzeuge. Generell dient Slicing zum Vereinfachen von Programmen, indem nur ein bestimmter semantischer Aspekt betrachtet wird (engl. point of interest) [4]. Dieses Prinzip blendet einfach nicht relevante Programmteile aus. Dabei gibt es verschiedene Typen und Formen von Slicing. Die einfachste Form ist das statische Slicing, wo die irrelevanten Teile einfach bei der Darstellung gel¨scht werden. Darauf aufbauend befindet sich das dynamische Slicing, wo o zu¨tzlich konkrete Eingabewerte mit ausgewertet werden. Als Vermischung von a statischen und dynamischen Slicing steht der Typ bedingtes Slicing. Hierbei werden keine konkreten Eingabewerte mehr ausgewertet sondern abstrakt definierte Bedingungen. Somit wird schnell ein großer Bereich abgedeckt. Als letzter Typ, ist das formlose Slicing zu nennen, was unabh¨ngig von den anderen Fora men, jede Programmtransformation nutzt um das Programm zu vereinfachen. Der Programminhalt/ -zweck wird dabei aber beibehalten. Im Allgemeinen bietet das Slicing vielf¨ltige Anwendungsgebiete, z.B. zum Tea sten, Fehlersuchen, Umgestaltungen, Verstehen oder Vermessen von Programmen. Im Speziellen, f¨r den Anwendungsfall der Codeanalyse, unterst¨tzt Sliu u cing den Entwickler bei der Fehlersuche nach Erkennung eines Fehlverhaltens (engl. debugging). Hierbei werden dann nur die Bereiche betrachtet, die potentiell den Fehler enthalten k¨nnen, d.h. z.B. Variablen die mit dem Problem in o Zusammenhang stehen. Die Debug-Perspektive in der Eclipse Entwicklungsumgebung bietet verschiedene Funktionalit¨ten zum Eingrenzen und Fokussieren von Programmteilen. Des a weiteren kann das kommerzielle Slicing-Werkzeug Wisconsin Program Slicing System 11 von GrammaTech C-Programme in einer annehmbaren Zeit zerteilen. Datenflussanomalieanalysatoren. Dieser Werkzeugtyp ist eigentlich selbst beschreibend - er dient zum Auffinden von Datenflussanomalien, d.h. fehlerhafte
9 10

11

http://www.grammatech.com/index.html Wobei nicht immer jede Ausgabeform f¨r jede Anfrage sinnvoll ist und deshalb der u Ergebnistyp festgelegt werden kann http://www.cs.wisc.edu/wpis/html/

7

Zugriffssequenzen auf eine Variable (z.B. lesender Zugriff auf eine nicht initialisierte Variable). Durch ihre essenzielle Funktionalit¨t sind sie oftmals schon a in Compiler integriert. Die Analyse ist auf statischem Wege mit wenig Aufwand realisierbar und stets automatisierbar. Dadurch bietet sie sichere und zuverl¨sslia che Ergebnisse. In der Eclipse Entwicklungsumgebung werden solche Fehler teilweise schon adhoc bei der Programmierung ausgewertet und angezeigt (mittels Online-Fehler¨ Uberpr¨fung). Generell sind solche Werkzeuge in allen g¨ngigen statischen Anau a ¨ lysewerkzeugen mit enthalten (z.B. die Uberpr¨fung auf Null-Pointer-Derefeu renzierung). 2.3 Formale Verifikationswerkzeuge

¨ Diese Werkzeugkategorie dient zur Uberpr¨fung der Konsistenz zwischen Speu zifikation und Realisierung (d.h. des Programmcodes) mittels mathematischer Mittel [6]. Sie hat dabei ihre speziellen Anwendungsbereiche gr¨ßtenteils in der o Automatisierungs- und Steuerungstechnik. Dort muss die eingebettete Software im sicherheitskritischen Umfeld unbedingt verifiziert werden (z.B. in Geldautomaten oder milit¨rischen Software-Entwicklungen). a Dabei gibt es verschiedene Verfahren und Techniken zur formalen Verifikation von Programmen. F¨r diesen Aufsatz von Bedeutung sind die automatenbasieru ten Techniken und das symbolische Testen. Unter den ersten Ansatz f¨llt das a Symbolic Model Checking, welches eine formale Nachweistechnik f¨r Eigenschafu ten zustandsendlich beschriebener Systeme ist. Beim zweiten Ansatz werden Tests mit allgemeinen symbolischen Werten durchgef¨hrt. u Ein Beispiel Werkzeug f¨r diese Kategorie ist UPPAAL12 , welches von der Uppu sala Universit¨t in Schweden und der Alborg Universit¨t in D¨nemark entwickelt a a a wurde. Es dient zum Modellieren, Simulieren und Verifizieren von Echtzeitsystemen. 2.4 Modellierende und analysierende Werkzeuge

Diese Kategorie von Werkzeugen soll nur kurz erw¨hnt werden, weil sie nicht dem a Hauptthema des Aufsatzes entspricht13 . Werkzeuge diesen Typs haben ihre Anwendungsbereiche in der Risiko-, Sicherheits-, Zuverl¨ssigkeits- und Verf¨gbara u keitsanalyse. Sie sind generell eher programmiersprachen-unabh¨ngig. Diese Art a beinhaltet effiziente Spezialisierungen bzw. Unterkategorien, z.B. FMECA14 -, Fehlerbaumanalyse- oder Markov -Werzeuge. Die Werkzeugumgebungen sind dabei h¨ufig im kommerziellen Bereich angesiea delt und beinhalten oft mehrere Werkzeugtypen dieser Kategorie. Des weiteren besitzen die Software-Firmen oft eine langj¨hrige Erfahrung in der Entwicklung. a
12 13 14

http://www.uppaal.com/ f¨r einen detaillierteren Einstieg bitte das zugeh¨rigen Kapitel in [6] lesen u o engl. Failure, Mode, Effects and Criticality Analysis

8

Abb. 1. Aufbau erweiterter statischer Analysewerkzeuge [8]

Beispielhafte Vertreter sind der Isograph Reliability Workbench 15 und das Relex Reliability Studio 16 .

3

Erweiterte statische Analysewerkzeuge

Diese Kategorie der statischen Analysewerkzeuge hat sich aus den vorhandenen Werkzeugumgebungen in den letzten Jahren stark hervorgetan. Sie sind ¨hna lich strukturiert und nutzen i.A. die gleichen grundlegenden Techniken, d.h. es k¨nnen eigene Abfragen zur Erkennung von Problemmustern formuliert wero den. Dazu soll im folgenden der Aufbau (s. Kap. 3.1) und danach die genutzten Techniken (s. Kap. 3.2) dieser Werkzeuge erkl¨rt werden. Dar¨ber hinaus wera u den verwendete Begriffe erl¨utert (s. Kap. 3.3) und die derzeitigen Grenzen der a erweiterten statischen Analysewerkzeuge aufgezeigt (s. Kap. 3.4). Abschlieend werden bekannte Vertreter vorgestellt (s. Kap. 3.5). 3.1 Grundstruktur

Der Aufbau dieser Analysewerkzeuge ist grafisch in der Abb. 1 visualisiert. Hier sind klar die vier Grundkomponenten: Faktenextraktor / Dekorierer, Datenbanksystem (DBS), Analyse- und Reportkomponente zu erkennen. Dabei ist die zweite Komponente nicht zwingend erforderlich, wenn die entstandenen Daten nicht in einer Datenbank abgespeichert werden sollen. Wie aus der Grafik gut zu erkennen ist, l¨sst sich der gesamte Knowledge-Discovery-Prozess leicht autoa matisieren und z.B. das Werkzeug im Batch-Betrieb als Cron-Job ausf¨hren. Im u Folgenden werden nun die einzelnen Bestandteile der Grundstruktur erkl¨rt. a Faktenextraktor/ Dekorierer. Als Ausgangsdaten nehmen diese Analysewerkzeuge, wie bei der statischen Codeanalyse ublich, den Quellcode oder die Kom¨ pilation des Programmcodes. Hierbei extrahiert zun¨chst der Faktenextraktor a
15 16

http://www.isograph-software.com/index.htm http://www.relex.com/

9

ein Systemmodell aus den Daten. Dessen Struktur und Inhalt wird durch ein Systemmetamodell vorgegeben. Dabei werden Artefakte wie z.B. Verzeichnisse, Quellcode-Dateien, Pakete, Klassen, Methoden oder Attribute erfasst. Des weiteren werden noch die Referenzen zwischen bestimmten Artefakttypen ermittelt. Das sind Eigenschaften wie z.B. Enthaltenssein- und Vererbungsbeziehungen oder Methodenaufrufe und Attributbenutzungen. Diese Artefakttypen und Referenzarten variieren je nach Programmiersprache (z.B. friend in C++ und implements in Java). Daraus ergibt sich das Problem der Definition des Systemmetamodells. Entweder es werden alle vorhandenen Unterschiede in einem universellen bzw. generischen Systemmetamodell vereinigt, oder es wird ein separates Modell f¨r jede Programmiersprache erstellt. u Optional hingegen ist die Systenmodellanreicherung durch Dekorierer. Sie bestimmen noch nicht ermittelte Merkmale aus dem Quellcode oder Log-Dateien eines Konfigurations-Management-Systems (z.B. CVS oder Subversion). Bei¨ spiele f¨r solche Merkmale sind u.a. Anderungsh¨ufigkeit oder Angaben uber u a ¨ die Vollst¨ndigkeit der Javadoc- oder Doxygen-Kommentare. Zus¨tzlich k¨nnen a a o mit Dekorierern Vorberechnungen f¨r wiederholt ben¨tigte Daten f¨r die Anau o u lysephase vorgenommen werden (z.B. Berechnung der transitiven H¨lle der Veru erbungsbeziehungen). Generell f¨hren diese Vorberechnungen zu einem sp¨teren u a Performance-Gewinn. Die eigentliche Datenmenge wird durch den Faktenextraktor und Dekorierer reduziert und es ist damit keine vollst¨ndige R¨ckw¨rtsgenerierung m¨glich. a u a o Datenbanksystem. Das nun extrahierte Systemmodell des Programmes wird h¨ufig in einer relationalen Datenbank abgespeichert. Dies hat mehrere Vora teile. Als Erstes k¨nnen DBSe i.A. gut mit großen Datenmengen umgehen. Als o Zweites k¨nnen damit Relationen effizient berechnet werden. Als Drittes werden o die Daten persistent abgespeichert und es kann immer wieder auf sie zugegriffen werden. Die Werkzeuge besitzen teilweise ein internes DBS. Diese sind i.A. nicht so leistungsstark und effizient wie externe DBSe, welche groe Datenmengen schnell verarbeiten k¨nnen. Dar¨ber hinaus besteht dann aber oft die M¨glichkeit mit o u o externen DBSen zu kooperieren (z.B. PostgreSQL oder Oracle). Analysekomponente. Nachdem nun die Daten persistent in einer Datenbank abgespeichert wurden, k¨nnen nun vordefinierte oder neu erstellte Anfragen auf o das Systemmodell ausge¨bt werden. Die Analysekomponente ist durch Nutzung u einer Datenbank zeitlich unabh¨ngig von der Faktenextraktion und der Dekoa rierung17 . Zus¨tzlich erm¨glicht dies eine Wiederholung oder Modifikation der a o Analyse auf einfachen Wege. Eine Qualit¨tsanalyse setzt sich generell aus vielen Teilanalysen zusammen. Diea se Anfragen werden durch eine Anfragesprache, wie z.B. SQL, oder durch werkzeugspezifische Erweiterungen beschr¨nkt. Der dabei wichtigste Faktor ist die a
17

Werkzeuge die diese Anforderung nicht erf¨llen verarbeiten die anfallenden Daten u sofort weiter

10

Laufzeit der Berechnungen, welche durch Wahl geeigneter Hardware, Wahl eines geeigneten DBSs und Anfrageoptimierung verbessert werden kann. Reportkomponente. Die Ergebnisse der Analysekomponente werden i.A. in Tabellen und Diagrammen dargestellt. Des weiteren kann die Reportkomponente die Resultate aber als Berichte aufarbeiten und somit in verschiedenen Abstraktionsstufen wiedergeben (z.B. f¨r das Management oder den Entwickler). u 3.2 Technik

Die erweiterte statische Analyse hat ihre Wurzeln, in den schon erw¨hnten, a Model-Checking-Technologien und in der abstrakten Interpretation [2]. Sie nutzt symbolischen Eingaben, d.h. abstrakte Werte, um viele konkrete Werte gleichzeitig abzudecken und somit effizient zu arbeiten. Folglich arbeiten diese Werkzeuge im Kontrast zu dynamischen Testwerkzeugen, wo konkrete Werte verwendet werden. Dies hat den Vorteil, das i.A. einen h¨here Abdeckung erzielt wird ohne o spezielle Testfallgenerierungen. Dies geschieht durch die abstrakte Betrachtung und Auswertung der Pfade und Bedingungen. 3.3 Fachterminologie

Die Technologie der erweiterten statischen Analyse f¨hrte zur Bildung einer u Reihe von neuen Fachbegriffen. Die Grundlage bilden die Fehlermuster, welche Problemmuster genannt werden. Dies ist die spezielle Beschreibung eines wiederkehrenden und i.d.R. erkennbaren Fehlverhaltens von Programmcode. Sie entstehen z.B. durch die unterschiedlichen Eigenschaften der Programmiersprachen, falsch verstandene Schnittstellen-Methoden oder einfache kleine Versehen (z.B. Nutzung des falschen Boolean-Operators). Diese Fehlermuster werden dann nach ihrer Art in Fehlerklassen zusammengefasst. Dabei gibt es verschiedene Ans¨tze und Kategorisierungen. Beispiele f¨r Fehlerklassen sind unvorhersehbaa u re/ kritische Fehler (z.B. Puffer¨berlauf/-unterlauf), Speicher-Allokations-Fehler u (z.B. doppeltes Freigeben) oder Konkurrenz-Fehler (z.B. doppeltes Sperren von kritischen Abschnitten). Manche Kategorien beziehen sich nur auf bestimmte Programmiersprachen. Demzufolge spielen Speicher-Allokierungs-Fehler in Java, welches eine automatische Speicherverwaltung besitzt, keine Rolle. Letztendlich werden die Problemmuster in Qualit¨tsindikatorenkataloge [8] oder Fehlermua sterkatalogen zusammengefasst. Diese variieren dann von Werkzeug zu Werkzeug und k¨nnen teilweise noch selbst von den Entwicklern definiert werden. o Ein wichtiger Vergleichswert zwischen der Leistungsf¨higkeit der verschiedenen a Werkzeuge ist die sogenannte False-Positive-Rate [9]. Diese fasst die Warnungen zusammen, welche gar keine richtigen Fehler sind. Dem gegen¨ber steht u die False-Negative-Rate, welche die Anzahl der nicht gefunden Fehler widerspiegelt. Generell sind die Entwickler von erweiterten statischen Analysewerkzeugen bestrebt ein geringe False-Positive-Rate bei ihren Analysen zu erzielen. Diese variiert aber von Fehlermuster zu Fehlermuster.

11

3.4 1 2 3 4 5 void void void ... void

Probleme und Grenzen f 0 ( ) { i f ( ∗ ) { A; } e l s e { B ; } } // 2 Pfade f 1 ( ) { f 0 ( ) ; f 0 ( ) ; } // 4 Pfade f 2 ( ) { f 1 ( ) ; f 1 ( ) ; } // 16 Pfade f i ( ) { f i − 1 ( ) ; f i − 1 ( ) ; } // 2ˆ(2ˆ i ) Pfade Listing 1.1. Beispiel f¨r die Entwicklung der Pfadanzahl [9] u

Nach dem derzeitigen Stand der Technik k¨nnen erweiterte statische Analyseo werkzeuge trotzdem keine 100%-ige Pfadabdeckung18 erm¨glichen [9]. Dies liegt o in der exponentiellen Pfadanzahlerh¨hung bei Schleifen und Rekursionen. o Wie man im Listing 1.1 sieht, steigt die Anzahl der Pfade recht schnell an. In der ersten Methode befindet sich eine Bedingung woraus sich zwei Pfade ergeben. Danach werden in den nachfolgenden Methoden die Vorherigen jeweils zweimal aufgerufen. Somit ergibt sich durch die azyklischen, interprozeduralen Methodenaufrufe ein doppelt exponentieller Anstieg der Anzahl der Pfade. Des weiteren gew¨hrleisten die Zeiger-Analyse-Algorithmen noch keine exaka te Analyse [9]. Die Folge sind falsche Verweise (nicht durchf¨hrbare Verweise) u die in den Aufrufgraphen auftauchen oder fehlende Verweise, welche z.B. durch redundante Bedingungen entstehen. Generell ignorieren die Werkzeuge solche Ausnahmen die zu unvorhersehbaren Ausf¨hrungspfaden f¨hren. Auf der andeu u ren Seite fordern aber diverse Sicherheitsstandards (z.B. DO-178B Standard f¨r u die Luftfahrt) 100%-ige Abdeckung in verschiedenen Risikoklassen. Eine andere Grenze der erweiterten statischen Codeanalyse ist die eingeschr¨nkte a Modellierung von konkurrienden Thread -Zugriffen (engl. mutlithreading). Hierbei werden oft nur Ann¨herungen vorgenommen. a Dem allgemeinen Problem, der Reduzierung der False-Positive-Rate, wird versucht sich mit verschiedenen Techniken anzun¨hern. Auf der einen Seite werden a die Werkzeuge mit automatischen Lernfunktionen ausgestattet. Diese versuchen gebr¨uchlichen Programmierausdr¨cke/ -muster und deren Absichten zu verstea u hen. Auf der anderen Seite kann der Nutzer selbst bestimmte Verhaltensweisen definieren um somit die False-Positive-Rate zu verringern. Letztendlich k¨nnen diese Werkzeugtypen aber keine logischen Fehler im Proo grammablauf erkennen. Diese lassen sich aber gut durch dymamische Tests herausfinden. 3.5 Beispiele Hierbei sollen nun kurz zwei frei erh¨ltliche Beispielwerkzeuge f¨r die erweitera u te statische Analyse betrachtet werden und weitere Anwendungen nur genannt werden. FindBugs. Dies ist ein Open-Source-Projekt von der Universit¨t von Maryland a f¨r die Programmiersprache Java und als Eclipse Plug-in erh¨ltlich19 . Es analyu a
18 19

Obwohl es andere Hersteller behaupten; s. [7] http://findbugs.sourceforge.net/

12

siert mittels Detektoren, die auf den Visitor -Entwurfsmuster beruhen, den JavaBytecode. Dabei behaupten die Entwickler immer eine False-Positive-Rate geringer als 50% zu erzielen [5]. Durch seine Struktur ist es beliebig mit neuen Fehler-Detektoren erweiterbar. Bei der Analyse werden die anfallenden Daten direkt weiter verarbeitet und ausgewertet. Mittlerweile besitzt das Werkzeug schon einen ziemlich umfangreichen Fehlermusterkatalog der sich in verschiedene Kategorien unterteilt. Des weiteren erm¨go licht es durch diverse Filter die Analyse einzuschr¨nken und diese z.B. nur mit a gewissen Detektoren durchzuf¨hren oder nur auf bestimmte Klassen anzuwenu den. Letztendlich kann man die Ergebnisse als XML-Report exportieren und immer wieder in das Programm zur Fehlerauswertung und -beseitigung laden. SemmleCode. Das schon bereits erw¨hnte Werkzeug SemmleCode ist ein ziemlich a umfangreiches und flexibles Analysewerkzeug. Es ist als frei erh¨ltiches Eclipse a Plug-in verf¨gbar und basiert auf der objekt-orientierten, Allzweck-Anfragesprau ¨ che .QL, welche mehrere Ans¨tze in sich vereint. Somit hat sie eine starke Ahna lichkeit zu SQL, nutzt die Fixpunkt-Semantik von Datalog 20 , und gebraucht die Eindhoven Quantifier Notation zur simplen Konstruktion von AggregatFunktionen21 . Durch diese erweiterte Anfragesprache ist es m¨glich eine Vielzahl der Aufgaben o der statischen Analyse abzudecken und mit einer guten Performance zu berechnen und ausgeben zu lassen, z.B. Fehler finden, Metriken berechnen, Abh¨ngiga keiten zu verstehen oder Anfragen anzupassen und neu zu definieren. Die anfallenden Daten der Analyse werden in einer relationalen Datenbank abgespeichert. Weitere Beispiele. Andere Vertreter erweiterte statische Analysewerkzeugen die ein DBS nutzen sind die kommerzielle CAST Application Intelligence Platform 22 und das schon erw¨hnte CodeSonar. Dar¨ber hinaus erzielt Prevent sehr gute a u Ergebnisse und TPTP besitzt eine Komponente zur erweiterten statischen Analyse.

4

Portale

Wie der aufmerksame Leser vielleicht schon w¨hrend des Lesen dieses Aufsatzes a festgestellt hat, reicht ein einzelnes Werkzeug heutzutage nicht mehr aus um alle Bereiche der Codeanalyse zur Qualit¨tssicherung abzudecken. Deshalb werden a die einzelnen Werkzeugtypen oft in einer Werkzeugumgebung zusammengef¨hrt u (z.B. TPTP ) oder ein Werkzeug ist so flexibel um mehrere Kategorien gleichzeitig abzudecken (z.B. SemmleCode). Darauf aufbauend erstreckt sich das Gebiet der Portale zur Codeanalyse, welche eine zentralisierte, komplexe Datenerhebung systemweit erm¨glichen und diese o
20 21 22

Welches eine einfache Form von logischer Programmierung ist F¨r eine detailierte Beschreibung von .QL bitte [3] lesen u http://www.castsoftware.com/Default.aspx

13

Abb. 2. Rollenstruktur in der Software-Entwicklung [8]

nat¨rlich umfangreich analysieren k¨nnen um daraus variable Berichte zu geneu o rieren. Die verschiedenen Rollen in der Software-Entwicklung (Entwickler, Projektleiter und Manager) haben unterschiedliche Sichten auf die zu entwickelnden Systeme (s. Abb. 2). Durch die zentralisierte Speicherung der Daten ist es nun m¨glich Reporte f¨r jeden dieser Bereiche zu erstellen und von der Granularit¨t o u a anzupassen, d.h. Analysen auf Codeebene f¨r den Entwickler23 , Analysen auf u Architekturebene f¨r den Projektleiter und eine mehrere Systeme ubergreifende u ¨ Sicht f¨r den Manager (engl. Application Portfolio Management). Des weiteren u k¨nnen dadurch zus¨tzliche Metriken ermittelt werden. o a Oft werden Portale uber Webserver verwaltet. Dies erm¨glicht es den beteiligo ¨ ten Personen mehrfach und ortsunabh¨ngig auf die Berichte zuzugreifen und a eine Personalisierung der Daten vorzunehmen (damit ist i.A. die Explorationstiefe der Berichte gemeint). Dies hat den Vorteil einer einheitlichen Datenbasis, welche konsistente Sichten der Ergebnisse und somit eine Vergleichbarkeit zul¨sst (z.B. Trendbeobachtungen auf Tages- oder Versionsbasis). Um Daten der a zentralen Datenbank aktuell zu halten ist ein hoher Automatisierungsgrad erforderlich, welcher einen relativ großen Aktualisierungsintervall zur Folge hat. Die Vernachl¨ssigung der lokalen G¨ltigkeit der Analyse steht dabei deutlich im a u Kontrast zu den Vorteilen die ein Unternehmen aus einer Portal -Nutzung ziehen kann. Diese sind Maximierung des Nutzen des ermittelten Daten, Minimierung des Ressourcenbedarfts f¨r die Analyse und geringe Wartungskosten. u Beispielhaft zeigt Abb. 3 den Aufbau von CodeSonar, welches eine zentralen Hub hat. Dieser stellt den Zugang uber ein Web-Interface zu den automatisch ¨ generierten Berichten bereit und erm¨glicht es den beteiligten Entwicklern ihre o Daten zur Analyse von Hand oder automatisch einzuspeisen. Weitere Beispiele

23

Welche auch nur auf die zu bearbeitenden Module beschr¨nkt werden k¨nnen a o

14

Abb. 3. Aufbau der Portal -Struktur von CodeSonar [9]

f¨r Portale sind das schon erw¨hnte Prevent 24 , Insight von Klocwork25 und die u a Client/ Server-Werkzeuge von PolySpace26 .

5

Fazit

Nachdem nun eine Vielzahl von Werkzeugtypen, deren Einsatzgebiete mit Beispielen vorgestellt wurde, sollte klar sein, dass die Nutzung solcher Hilfsmittel in einem guten Software-Entwicklungs-Prozess unerl¨sslich aber auch teilweia se recht einfach ist. Die modernen Werkzeugumgebungen zum Testen und zur Codeanalyse erg¨nzen oft die komplexen Entwicklungsumgebungen oder binden a sich gut in diese als Plug-in ein. Die Vertreter aus dem Open-Source-Bereich brauchen sich nicht vor den kommerziellen Konkurrenten zu verstecken, da die kostenlosen Projekte oft ein breites Industriekonsortium hinter sich haben (s. TPTP ). Eine logische Folge, ist auch die Vereinigung mehrere Kategorien in einer Werkzeugumgebung. Generell bilden die statischen Typen eine gute Erg¨nzung zu a den dynamischen Testwerkzeugen, ersetzen diese aber nicht. Sie helfen dem Entwickler trotzdem effizient echte Fehler zu finden und somit die Software-Qualit¨t a zu steigern. Durch die breite Automatisierung reduzieren statische Analysewerkzeuge die Kosten im Entwicklungsprozess und sparen nat¨rlich eine Menge Zeit ein. Mittels u
24

25 26

Welches sehr gut mit dem ThreadAnalyzer von Coverity zusammenarbeitet und auch als Eclipse Plug-in in der Java-Version erh¨ltlich ist a http://www.klocwork.com/default.asp http://www.mathworks.com/

15

variabler Berichterstellung optimieren Portale zus¨tzlich die Wege zur Zusama menarbeit und den Kommunikationsfluss zwischen den beteiligten Rollen in der Software-Entwicklung. Deshalb sollte gerade die recht leicht zu erlernenden, frei erh¨ltlichen Vertreter a zum Einsatz in allen (m¨glichen) Software-Projekt kommen, wobei diese sich o oft nur auf g¨ngigen Programmiersprachen wie C, C++ und Java beschr¨nken a a damit aber eine große Anzahl an Systemen abdecken.

Literatur
1. Liggesmeyer Home [online]. Available from: http://www.liggesmeyer.de. 2. P. Anderson. Detecting Bugs in Saftey-Critical Code. Dr. Dobb’s Journal, March, 2008. 3. O. de Moor, M. Verbaere, E. Hajiyev, P. Avgustinov, T. Ekman, N. Ongkingco, D. Sereni, and J. Tibble. Keynote Address: .QL for Source Code Analysis. Technical report, Semmle Limited, 2007. 4. M. Harman and R. M. Hierons. An Overview of Program Slicing [online]. Available from: http://www.dcs.kcl.ac.uk/staff/mark/sf.html. 5. D. Hovemeyer and W. Pugh. Finding Bugs is Easy. Technical report, Dept. of Computer Science, University of Maryland, 2004. 6. P. Liggesmeyer. Software-Qualit¨t: Testen, Analysieren und Verifizieren von Softa ware. Spektrum, Akademischer Verlag, 2002. 7. Misc. Prevent SQS C/C++. Technical report, Coverity, Inc., 2008. 8. F. Simon, O. Seng, and T. Mohaupt. Code-Quality-Management. dpunkt.verlag, 2006. 9. M. Zarins. Overview of GrammaTech Static-Analysis Technology. Technical report, GrammaTech, Inc., 2008.