Clang Static Analyzer belülről Nagy Donát 2015. október 6.
Áttekintés 1 Clang Static Analyzer kívülről 2 A statikus elemzés folyamata 3 Az eszköz felépítése 4 Egy checker felépítése
Rövid definíciók Clang Static Analyzer: statikus elemző eszköz, azaz a kód futtatása nélkül keres hibákat/gyanús dolgokat (C, C++, Objective-C) programokban A Clang Static Analyzer a Clang projekt része, a projekt többi részét alkotó függvénykönyvtárak alkalmazása Clang: modern C/C++/Objective-C fordító; moduláris felépítésének köszönhetően a forráskódot manipuláló függvénykönyvtárai külön is használhatóak A Clang projekt egy az LLVM projektbe tartozó számos eszköz közül LLVM: nyílt forrású eszköztár fordításhoz és egyéb kódmanipulációhoz
Az LLVM részei LLVM Core LLVM köztes reprezentációban lévő kód optimalizálása és gépi kóddá fordítása (backend) Clang frontend a C/C++/Objective-C nyelvekhez, ezen nyelvekbeli kód kezelése és köztes reprezentációra fordítása dragonegg LLVM backend összekapcsolása a GCC-nek az Ada, Fortran stb. frontendjeivel LLDB debugger libc++ C++ Standard Library implementáció és még 8 más projekt...
Hivatalos megoldás clang --analyze -Xanalyzer -arg... hívásokkal lehet manuálisan meghívni az elemzőt, de ez meglehetősen kellemetlen lenne egy nagy projektnél A scan-build eszköz megfigyeli a fordítás menetét és futtatja az elemzőt minden, a C/C++/Objective-C fordító által lefordított forrásfájlra Használatához meg kell adni a tényleges fordítást kiváltó parancsot (pl. scan-build make -j4) Primitív mechanizmus: a $CC és $CXX környezeti változókat felüĺırva beszúr egy szkriptet, ami minden fordítás előtt lefut... ha a build rendszer elviseli ezt a belepiszkálást
Ericssonos megoldás A CodeChecker alapvetően a scan-buildhez hasonló csak összetettebb Használata: CodeChecker check paraméterek -b make... miután a felhasználó beálĺıtotta a szükséges adatbázist és pythonos virtualenv-et Szofisztikáltabb mechanizmus: a $LD_PRELOAD környezeti változóba piszkál bele Továbbá dinamikus webes bugnézegetőt biztosít
Az elemzés menete A statikus elemzés során az elemző szimbolikusan futtat minden függvényt Azonos fordítási egységbeli függvényhívást követ, azon kívül technikai okokból nem A részben vagy teljesen ismeretlen értékek (pl. a függvény paraméterei, külső függvények által visszaadott érték, memória adott pozíciójából kiolvasható érték, stb.) helyett szimbólumokat vezet be A szimbólumokról különféle ismereteket tárol (pl. ez a szám nagyobb, mint 5; az a pointer nem lehet NULL)
Az ExplodedGraph A végrehajtás menetét egy irányított gráf, az ExplodedGraph követi Csúcsai egy hely a kódban, ismeretgyűjtemény a változókról párok Élei a végrehajtás elemi lépéseinek felelnek meg Legtöbb állapotnak egy őse és egy leszármazottja van, de lehet több ős, több leszármazott ill. nulla leszármazott is
A checkerek A tényleges munkát a checkerek végzik Egy checker egy hibatípusért/nyelvi elemért felel A checker megfelelő helyen csúcsokat szúrhat be az ExplodedGraph-ba; ezek gyakran nyelők (ha a hiba után nem definiált az állapot) Megfelelő helyen: pl. egy függvény meghívása előtt/után, egy változó deklarációjakor, amikor egy szimbólum elérhetetlenné válik, egy függvény elhagyásakor... A checkernek magának nincs állapota, de a definíciójakor lehet állapotot definiálni számára az ismeretgyűjtemény típusban (ami a gráf minden csúcsában szerepel)
Néhány példa checkerekre core.dividezero nullával osztás core.nulldereference NULL dereferencia cplusplus.newdelete new/delete nem szépen párban használata unix.malloc ugyanez malloc()/free()-re core.uninitialized.* inicializálatlan érték használata security.insecureapi.* a getpw, gets, mktemp, strcpy, vfork függvények használata alpha.unix.stream fájlműveletek (fopen() után fclose() kellene, nem nyitott fájlból olvasás) alpha.cplusplus.virtualcall konstruktorban/destruktorban virtuális függvény hívása alpha.core.pointersub pointerek különbségének képzése, ha nem egy blokkba mutatnak
A SimpleStreamChecker feladata és alaptulajdonságai Ez egy demo checker, az alpha.unix.stream checkernek egy egyszerűbb változata Feladata: Jelez, ha egy fájl nyitva marad Jelez, ha egy bezárt fáljból akar olvasni a programozó Ez egy viszonylag egyszerű checker, pl. a MallocChecker, ami kb. 6 checkert definiál dinamikus memóriakezelés hibáira, tízszer ekkora Nem lép sok interakcióba más checkerekkel ezek a függvények más checkert nem érdekelnek, és őt sem nagyon érdekli más checker adata