AA_kehrmaschine_123rf-14573229_digifuture.jpg

© digifuture, 123RF

Kehraus

Splint und Co: Tools zur statischen Code-Analyse

18.10.2012
Zwar finden Compiler Syntaxfehler in Programmen, aber auch syntaktisch korrekter Code kann Ungenauigkeiten, logische Fehler oder veraltete Funktionen beinhalten. Solche Probleme spüren Sie mit Quellcode-Analyzern auf.

Compiler und Interpreter beanstanden zwar ungültigen Programmcode, in vielen Programmiersprachen sind aber selbst sehr ungewöhnliche Codezeilen noch gültig. Man kann Code auch absichtlich verwirrend gestalten – es gibt sogar diverse Obfuscated Coding Contests ([1],[2]), also Wettbewerbe, die zum Ziel haben, ein Programm absichtlich möglichst unleserlich zu gestalten. Viel öfter allerdings geschieht das unabsichtlich, insbesondere wenn (wie in vielen Open-Source-Projekten) mehrere Entwickler gemeinsam an einem Programm arbeiten. Nicht immer bemerkt der Compiler die daraus resultierenden Schnitzer.

Glücklicherweise gibt es Tools, die hier ansetzen und solche ungewöhnlichen Codekonstruktionen aufspüren. Damit helfen sie, mögliche Fehlerquellen zu beseitigen, und sorgen so für bessere Codequalität. Im Folgenden stellen wir einige ausgewählte Vertreter dieser Gattung vor, wobei unsere Aufstellung keinen AAnspruchauf Vollständigkeit erhebt: Ähnliche Open- und Closed-Source-Werkzeuge gibt es für praktisch jede Programmiersprache.

Splint – Codeprüfung für C

Das erste Werkzeug zur statischen Quellcodeprüfung, Lint, kam bereits 1979 mit Unix zur Auslieferung. Das Programm wurde schnell so populär, dass es den Programmierer-Jargon um den Ausdruck "linten" für statische Codeprüfungen bereicherte. In der Folge diente es dann als Namensgeber für viele ähnliche Tools. Zu diesen gehört das Open-Source-Programm Splint ("Secure Programming Lint", [3]), das wie sein Vorbild mögliche Problemquellen in C-Code aufspürt.

Als Beispiel sehen wir uns das kurze C-Programm aus Listing 1 (Zeile 2 bis 10) dienen, das melden soll, wenn zehn Argumente auf der Kommandozeile übergeben werden. Dies prüft es, indem es argc auswertet: Diese Variable enthält bekanntlich immer die Anzahl der übergebenen Argumente plus Eins, weil es den Programmnamen als erstes Argument mitzählt.

Listing 1

$ cat main.c
#include <stdio.h>
int main(int argc, char * argv[])
{
  if (argc = 10+1) {
    printf("10 Argumente!\n");
  }
  return 0;
  printf("Programm beendet.\n");
}
$ gcc main.c
$ gcc -Wall main.c
main.c: In function 'main':
main.c:4:2: warning: suggest parentheses around assignment used as truth value [-Wparentheses]

Der Compiler GCC meldet beim Übersetzen des Quellcodes normalerweise gar nichts (Zeile 11). Erst wenn Sie mittels der Option -Wall alle Warnungen einschalten (Zeile 12) wirft er eine kurze kryptische Meldung aus, weil der Code anstatt eines Vergleichs (==) eine Zuweisung (=) verwendet (Zeile 5).

Sehen Sie sich zum Vergleich die Ausgabe von Splint in Listing 2 an: Das Tool findet nicht weniger als vier mögliche Fehler in main.c. Außerdem beschreibt es ausführlich die Art der Probleme und die möglichen Ursachen. Daneben liefert es Hinweise, mit welchen Änderungen am Code oder den Parametern Sie die vermuteten Fehler korrigieren oder die Ausgabe unterdrücken können.

Listing 2

$ splint main.c
Splint 3.1.2 --- 29 Oct 2011
main.c: (in function main)
main.c:4:6: Test expression for if is assignment expression: argc = 10 + 1
  The condition test is an assignment expression. Probably, you mean to use ==
  instead of =. If an assignment is intended, add an extra parentheses nesting
  (e.g., if ((a = b)) ...) to suppress this message. (Use -predassign to
  inhibit warning)
main.c:4:6: Test expression for if not boolean, type int: argc = 10 + 1
  Test expression type is not boolean or int. (Use -predboolint to inhibit
  warning)
main.c:8:2: Unreachable code: printf("Programm...
  This code will never be reached on any possible execution. (Use -unreachable
  to inhibit warning)
main.c:2:27: Parameter argv not used
  A function parameter is not used in the body of the function. If the argument
  is needed for type compatibility or future plans, use /*@unused@*/ in the
  argument declaration. (Use -paramuse to inhibit warning)
Finished checking --- 4 code warnings

Neben der schon von GCC bemerkten fehlerhaften Zuweisung im If-Statement, zu der Splint gleich zwei Anmerkungen liefert, findet der Analyzer auch noch eine unbenutzte Variable (argv) sowie Programmcode, der niemals ausgeführt wird. Beim Kommentar /*@unused@*/, dem Splint in der vierten Warnung vorschlägt, handelt es sich um eine sogenannte Annotation. Ein solcher spezieller Kommentar steuert das Verhalten von Splint, indem er beispielweise gewisse Prüfungen (de-)aktiviert und Splint weitere Hinweise gibt, welche die Prüfungen unterstützen. Der Aufruf splint --help annotations gibt einen Überblick über die Möglichkeiten.

Neben der Hilfe-Funktion, die mittels splint --help einen ersten Überblick über die Themen liefert, kennt Splint noch zahlreiche weitere Kommandozeilenoptionen. Für Einsteiger sind wahrscheinlich die Optionen --weak, --standard, --checks und --strict am interessantesten, die steuern, wie pedantisch sich Splint gibt. Der Aufruf splint --help modes gibt Ihnen einen ersten Überblick über die (de-)aktivierten Optionen in diesen Einstellungen.

Übrigens bemerkt auch GCC durchaus, dass der Befehl printf("Programm beendet\n") nie ausgeführt wird. Er optimiert den Befehl daraufhin schlicht weg, sprich: erzeugt gar nicht erst Code dafür. Das erkennen Sie unschwer, indem Sie sich mit dem Kommando strings die Texte im generierten Executable ansehen. Etwas lesbarer fällt die Variante aus, mit gcc -S main.c die Assembler-Datei main.s zu erzeugen. In jedem Fall unterschlägt der Compiler jedoch hier die Information, dass hier völlig überflüssiger Code vorhanden ist. Klar, er soll ja auch übersetzen und nicht Fehler suchen – zur Verbesserung der Codequalität trägt das aber nicht gerade bei.

Auch andere C-Compiler schlagen sich hier nicht viel besser: Der Open64-Compiler meldet standardmäßig das selbe wie GCC: Nichts. Der Sun/Oracle-Compiler beanstandet zwar das nicht erreichbare Statement, findet aber an der wahrscheinlich fehlerhaften Zuweisung in der If-Abfrage nichts auszusetzen. LLVM/Clang bemerkt zwar die falsche Zuweisung, meldet aber ebenfalls nichts zum nicht ausführbaren Code.

Perl::Critic

Die Programmiersprache Perl tritt explizit mit dem Motto "There is more than one way to do it" an – sie erlaubt also viele Wege, um ein Problem zu lösen. Für möglichst seltsame und unlesbare Wege gibt es sogar einen eigenen Wettbewerb, den Obfuscated Perl Contest [2] . Dazu passend hat der Code-Analyzer Perl::Critic das Motto "Some Ways Are Better Than Others". Perl::Critic hilft wie Splint, mögliche Fehler zu finden und einen einheitlichen Programmierstil durchzusetzen.

Möchten Sie sich Perl::Critic ohne Installation ansehen, können Sie dazu den entsprechenden Webservice [4] nutzen (Abbildung 1). Dort laden Sie Ihren Perl-Code hoch und sehen dann sofort das Ergebnis der Evaluierung. Dabei unterstützt das Analysetool fünf verschiedene "Härtegrade".

Abbildung 1: Der Perl::Critic-Webservice liefert nach dem Hochladen des zu prüfenden Codes sofort Ergebnisse.

Auf der Kommandozeile rufen Sie das einmal installierte Werkzeug mit einem schlichten perlcritic auf. Auch hier kennt Perl::Critic die bereits erwähnten fünf Prüfstufen, die von 1 ("brutal") bis 5 ("gentle") reichen. Im Beispiel aus Listing 3 rufen wir den Analyzer mit dem dritten Level ("harsh") auf, damit er bei dem kurzen Programm (Zeilen 2 bis 5) auch etwas zu reklamieren findet.

TIPP

In OpenSuse 12.1 fehlt (im Gegensatz zu anderen gängigen Distributionen) das Executable-Bit bei der Datei /usr/bin/perlcritic. Sie müssen es entweder nachträglich setzen oder das Analyse-Tool explizit mit perl /usr/bin/perlcritic aufrufen, um es zu nutzen.

Listing 3

$ cat test.pl
#!/usr/bin/perl
print `cat test.pl`
print "Return drücken";
my $filename = <STDIN>;
$ perlcritic --severity 3 test.pl
Code before strictures are enabled at line 2, column 1.  See page 429 of PBP.  (Severity: 5)
Code before warnings are enabled at line 2, column 1.  See page 431 of PBP.  (Severity: 4)
Backtick operator used at line 2, column 7.  Use IPC::Open3 instead.  (Severity: 3)
Use "<>" or "<ARGV>" or a prompting module instead of "<STDIN>" at line 4, column 16.  See pages 216,220,221 of PBP.  (Severity: 4)

Tatsächlich macht Perl::Critic auf gleich vier Verbesserungsmöglichkeiten aufmerksam (Zeilen 7 bis 10). Dabei gibt es jeweils eine Beurteilung des Schweregrads und häufig auch eine Referenz auf das Buch "Perl Best Practices" (PBP) von Damian Conway aus. Ähnlich wie Splint können Sie auch Perl::Critic mit speziellen Kommentaren (## no critic) am Ende einer Zeile anweisen, diese nicht zu untersuchen. Daneben verzichtet das Tool darauf, Code zwischen den Marken ## no critic und ## use critic zu prüfen.

Genau wie Splint bietet Perl::Critic daneben auch noch wesentlich mehr Einstellungsmöglichkeiten. Zum einen dürfen Sie vorgeben, welche Prüf-Policies es anwenden soll, zum anderen können Sie dem vorhandenen Fundus auch eigene Policies hinzuzufügen. Der Befehl perlcritic --help liefert eine erste Übersicht, auch eine umfangreiche Manpage (man perlcritic) steht zur Verfügung.

Als Teil der kommerziellen Activestate-Perl-Distribution [5] gibt es auch eine grafische Oberfläche für Perl::Critic (perlcritic-gui, Abbildung 2), mit der Sie sich einen groben Überblick über die vielfältigen Optionen verschaffen können. Active State Perl lässt sich kostenlos herunterladen und nutzen, ist jedoch keine freie Software.

Abbildung 2: Active State Perl bringt eine grafische Oberfläche für Perl::Critic mit.

Diesen Artikel als PDF kaufen

Express-Kauf als PDF

Umfang: 4 Heftseiten

Preis € 0,99
(inkl. 19% MwSt.)

LinuxCommunity kaufen

Einzelne Ausgabe
 
Abonnements
 

Ähnliche Artikel

Kommentare
Weitere interessante Sourcecode-Analyzer.
Wolfgang Dautermann, Sonntag, 14. Juli 2013 10:08:35
Ein/Ausklappen

* http://www.shellcheck.net/ Shellskript-Analyzer
* http://cppcheck.sourceforge.net/ Ein weiterer interessanter C/C++ Checker
* http://www.jslint.com/ Javascript-Checker


Bewertung: 144 Punkte bei 10 Stimmen.
Den Beitrag bewerten: Gut / Schlecht

Infos zur Publikation

LU 01/2015: E-Books im Griff

Digitale Ausgabe: Preis € 4,95
(inkl. 19% MwSt.)

Mit der Zeitschrift LinuxUser sind Sie als Power-User, Shell-Guru oder Administrator im kleinen Unternehmen monatlich auf dem aktuelle Stand in Sachen Linux und Open Source.

Sie sind sich nicht sicher, ob die Themen Ihnen liegen? Im Probeabo erhalten Sie drei Ausgaben zum reduzierten Preis. Einzelhefte, Abonnements sowie digitale Ausgaben erwerben Sie ganz einfach in unserem Online-Shop.

NEU: DIGITALE AUSGABEN FÜR TABLET & SMARTPHONE

HINWEIS ZU PAYPAL: Die Zahlung ist auch ohne eigenes Paypal-Konto ganz einfach per Kreditkarte oder Lastschrift möglich!       

Tipp der Woche

Ubuntu 14.10 und VirtualBox
Ubuntu 14.10 und VirtualBox
Tim Schürmann, 08.11.2014 18:45, 0 Kommentare

Wer Ubuntu 14.10 in einer virtuellen Maschine unter VirtualBox startet, der landet unter Umständen in einem Fenster mit Grafikmüll. Zu einem korrekt ...

Aktuelle Fragen

PCLinuxOS Version 2014.08 "FullMonty" Umstellung auf deutsch
Karl-Heinz Welz, 19.12.2014 09:55, 3 Antworten
Hallo, liebe Community, ich bin 63 Jahre alt und möchte jetzt nach Jahrzehnten Windows zu Linux...
ICEauthority
Thomas Mann, 17.12.2014 14:49, 2 Antworten
Fehlermeldung beim Start von Linux Mint: Could not update ICEauthority file / home/user/.ICEauth...
Linux einrichten
Sigrid Bölke, 10.12.2014 10:46, 5 Antworten
Hallo, liebe Community, bin hier ganz neu,also entschuldigt,wenn ich hier falsch bin. Mein Prob...
Externe USB-Festplatte mit Ext4 formatiert, USB-Stick wird nicht mehr eingebunden
Wimpy *, 02.12.2014 16:31, 0 Antworten
Hallo, ich habe die externe USB-FP, die nur für Daten-Backup benutzt wird, mit dem YaST-Partition...
Steuern mit Linux
Siegfried Markner, 01.12.2014 11:56, 2 Antworten
Welches Linux eignet sich am besten für Steuerungen.