footer: Cocoaheads Frankfurt - Januar 2015 - Arno Appenzeller slidenumbers: true
Der Clang Static Analyzer ist in Xcode integriert und Bestandteil des Compilers. Er wird dazu genutzt um den Code "statisch zu analysieren"
Statisch bedeutet der Code wird ohne ausgeführt zu werden auf bestimmte Eigenschaften untersucht.
Der Analyzer besteht aus mehreren Checkern, die alle auf verschiedene Eigenschaften prüfen.
-
Ungenutzte Variablen finden
-
Unerreichbare Code Abschnitt (Goto Fail Bug -> neuere Version von Clang hätte diesen finden müssen)
-
Division durch Null feststellen
-
Bestimmte andere Eigenschaften (z.B. super Call bei bestimmten Funktionen -> viewDidLoad)
- Vollständige Liste: http://clang-analyzer.llvm.org/available_checks.html
![inline](checker webseite.png)
-
Xcode Clang ist dem eigentlichen Clang in der Regel einige Versionsnummern hinten dran.
-
Selbst wenn man den Clang nicht erweitern möchte, findet ein neuerer Clang durchaus mehr oder andere Probleme im Code
Siehe Xcode LLVM/Clang Version:
VS. LLVM Release Schedule:
- LLVM & Clang auschecken. Siehe http://llvm.org/docs/GettingStarted.html#getting-started-quickly-a-summary
- Build-Ordner erstellen
- Im Ordner Terminal öffnen und
pathToLLVM/configure
ausführen - Im Terminal:
make -jN
wobeiN
= Anzahl Prozessor + 1 (wesentlich schneller)
#Eigenen Clang-Analyzer benutzen
Zwei Möglichkeiten:
- Konsolenoutput für eine Datei:
yourClang -cc1 yourOBJCFile.m
- ScanBuild HTML Ouput (mit ScanView): (Im Projektordner)
pathToScanBuild xcodebuild
(Hinweis: scanBuild
muss sich im Überordner relativ zum bin
-Ordner des kompilierten Clang befinden)
#Eigenen Clang-Analyzer benutzen
Den aktuellsten Build findet man auch fertig kompiliert unter: http://clang-analyzer.llvm.org
#Eigenen Clang-Analyzer in Xcode einbinden
- In den Clang Quellen existiert Tool namens:
set-xcode-analyzer
- ScanBuild muss wie oben beschrieben im übergeordneten Ordner zum Clang-bin-Ordner platziert sein
- Eignen Clang einstellen:
sudo ./set-xcode-analyzer --use-checker-build=PATH_TO_CLANGPARENTFOLDER_WITH_SCANBUILD
#Eigenen Clang-Analyzer in Xcode einbinden
- Xcode Clang zurücksetzen:
sudo ./set-xcode-analyzer --use-xcode-clang
- Funktioniert nun über Analyze-Button
#Eigenen Clang-Analyzer in Xcode einbinden
-
Umsetzung von (Unternehmens)-Richtlinien (Verbotene Funktionen, etc.)
-
Verifizierung von Framework Verwendung
-
Coding Styles
-
Sicherheitserweiterungen, etc.
-
(Außerdem ist es recht spannend 😜)
-
Man kann aus der Clang Source ein Xcodeproject erstellen
-
wesentlich angenehmer zu entwicklen als mit Editor und Terminal
-
cmake -G Xcode -DCMAKE_BUILD_TYPE=Debug pathToLLVMSource
###Checker Plugin entwickeln - Basics
-
Bestehende Checker befinden sich in
tools/clang/lib/StaticAnalyzer/Checkers
-
Checker, wie der gesamte LLVM/Clang, werden in C++ entwickelt
-
Für einen neuen Checker einfach eine neue Datei im Checkers Ordner erstellen.
###Checker Plugin entwickeln - Basics
-
Datei muss in der CMakeLists.txt im Ordner hinzugefügt werden
-
Checker muss in Checkers.td registriert werden (später mehr)
###Checker Plugin entwickeln - Einfacher eigener Checker
Wir möchten auf C-Funktionsaufrufe wie printf,strcat,strcpy,strncat finden und davor warnen
(Neuere Xcode Version haben dies bereits als Option für Warnings)
###Checker Plugin entwickeln - Aufbau Checker I
-
Ein Checker prüft auf bestimmte Events (z.B.
checkPreCall
das Statements vor ihrem "Aufruf" prüft -> Standardevent) -
Weitere Events:
checkPostCall
,checkPreObjCMessage
,checkEndFunction
,checkDeadSymbols
,etc. -
Ein Event übergibt immer den aktuelle
CheckerContext
, der z.B. aktuellen CalleeIdentifier oder ASTContext enthält.
###Checker Plugin entwickeln - Aufbau Checker II
-
Der aktuelle Callee wird als IdentifierInfo gespeichert, wir suchen in unserem Fall etwas wie printf
-
printf ist nicht immer printf - wir müssen den passenden Identifier anhand des aktuellen AST initiieren:
IIprintf = &ASTContext.Idents.get("printf");
###Checker Plugin entwickeln - Aufbau Checker III
- Nun können wir im Event prüfen, ob der Identifier des aktuellen Context printf ist:
void CocoaheadSecurityFunctionChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const {
initIdentifierInfo(C.getASTContext()); //initiiert die Identifier
const IdentifierInfo *ID = Call.getCalleeIdentifier();
//check if printf
if ( ID == IIprintf){
//throw bug
}
}
###Checker Plugin entwickeln - Aufbau Checker IV
- Bugs erstellt man indem man sie zuerst Global definiert, via reset
boBug.reset(new BugType(this, "Potential BufferOverflow Function", "CocoaheadSecurityFunctionChecker Error"));
- Man wirft sie aus indem man dem Context einen Bugreport mit Bug-Art,Beschreibung und Location übergibt
ExplodedNode *ErrNode = C.generateSink(); //Location anhand des Context (Hinweis: Sink beendet alle weiteren Checks anhand dieses Ablaufs)
BugReport *bug = new BugReport(*boBug, "CocoaheadSecurityFunctionChecker: Use of a unsafe file handeling function. Usage is not allowed.", ErrNode);
C.emitReport(bug); //auslösen des reports
###Checker Plugin entwickeln - Checker registrieren I
Ein Checker muss dem CheckerManager mitteilen, dass es ihn gibt:
void ento::registerCocoaheadSecurityFunctionChecker(CheckerManager &mgr) {
mgr.registerChecker<CocoaheadSecurityFunctionChecker>();
}
###Checker Plugin entwickeln - Checker registrieren II
-
In Checkers.td sind alle Checker aufgelistet und in bestimmte Kategorien eingeteilt
-
Um entwickelt Checker hinzuzufügen folgenden Code einfügen (in bestehende Kategorien - wir wählen Security)
let ParentPackage = Security in {
//a lot of other code
def CocoaheadSecurityFunctionChecker :Checker<"CocoaheadSecurityFunctionChecker">,
HelpText<"Checks for security">,
DescFile<"CocoaheadSecurityFunctionChecker.cpp">;
}
###Checker Plugin entwickeln - Fertigstellung
Konfiguration ALL_BUILD bauen:
Neuer Clang befindet sich nun in: "Debug/bin" (je nach Konfiguration)
(Kompletter Code hier: github.com/arnoappenzeller)
###Checker Plugin entwickeln - Fazit
-
Anhand dieser Grundlage lässt sich bereits ein einfacher eigner Checker erstellen.
-
Für Objective-C ist das ganze etwas komplizierter, da hier mit Nachrichten und Selectors gearbeitet wird.
-
Ein komplexeres Beispiel ist auf Github (prüft ob ein JailbreakCheck durchgeführt wird, wenn ein bestimmter Parameter gesetzt ist)
#Links
- Clang Analyzer Seite
- [Checker Developer Manual] (http://clang-analyzer.llvm.org/checker_dev_manual.html)
- Clang Doxygen (Für komplexere Entwicklungen notwendig!)
- "Building a Checker in 24 hours" (Talk von LLVM Dev Conference) Slides Video
#Fragen/Kontakt?
-
Per Twitter unter @arno_app
-
Github: github.com/arnoappenzeller
-
Mehr über mich und meine iOS Projekte: app-enzeller.com