Checker -=-=-=-=- Hardware met Software on the road to Changtse. Software said: "You are the Yin and I am the Yang. If we travel together we will become famous and earn vast sums of money." And so the pair set forth together, thinking to conquer the world. Presently, they met Firmware, who was dressed in tattered rags, and hobbled along propped on a thorny stick. Firmware said to them: "The Tao lies beyond Yin and Yang. It is silent and still as a pool of water. It does not seek fame, therefore nobody knows its presence. It does not seeks fortune, for it is complete within itself. It exists beyond space and time." Software and Hardware, ashamed, returned to their homes. -- Geoffrey James, "The Tao of Programming" Checker je rozhodně nejdůkladnějším řešením, které jsem viděl. Jeho cílem je najít prostě všechno. Vytváří si svoji mapu paměti, kde si o každém byte pamatuje, zda je přistupný, inicializovaný apod. Díky tomu je schopný odchytit přístupy za hranicemi bloku s přesností na jeden byte a dokonce i čtení neinicializovaných dat. Toto všechno provádí navíc jak v haldě, tak na zásobníku i v inicializovaných datech. Odchytí například i takové věci, jako používání neinicializované proměnné. Toho všeho je docíleno pomocí nemalého patche do gcc. Naštěstí ale tento patch je integrován jak v gcc 2.8.1, tak v egcs a proto nemusíte patchovat překladač. Vzniklý kód potom kontroluje téměř všechny přístupy do paměti a proto je hodně pomalý (autoři uvádějí běh asi 10x pomalejší). To znamená, že často potřebujete hodně trpělivosti na to, aby se program vůbec spustil. U XaoSe to je řádově několik minut. Je ale pravda, že XaoS na začátku provádí poměrně agresivní alokace a proto je spomalení znatelné i u efence. Dalším problémem je nutnost uzavřenosti kódu. Kontrolovaný kód nelze kombinovat z nekontrolovaným kódem v knihovnách. Naštěstí ale v neovějších verzích checkeru není nutné knihovny specielne překládat, protože existují tzv. stubs. Ty zařizují interface mezi knihovní funkcí a kontrolovaným kódem. Označí byte tak, jak je funkce použije a zavolají původní funkci. Takové stuby jsou napsány pro obdivuhodné množství funkcí (veškeré knihovní funkce, curses a další knihovny). U XaoSe jsem se potýkal z problémem, že nejsou stuby pro Xlib. Musel jsem to nakonec vyřešit tak, že jsem zkompiloval aalib pro checker a použil curses. Zajímavý je také garbage collector. To je velmi šikovný mechanizmus na hledání zapomenutých bloků. Checker projde veškerou paměť a zjistí, na které bloky má program ještě přístupné odkazy a vypíše nepřístupné bloky. Ty jsou téměř určitě zapomenuté. Jediná možnost by snad byla, že by program ukazatel nějakým způsobem schoval - třeba uložil na disk. To se ale často neděje. Díky své robusnosti checker suktečně odhalil většinu chyb: Chyby pro použití haldy zapomenuté naalokované bloky paměti garbage collector najde oba bloky uvolnění nenaalokovaného bloku (fbm) free called before malloc. vícenásobné uvolnění bloku (ffb) free an already free block. alokace a realokace bloku o velikosti 0 alloc vrátí 0, realloc funguje použití paměti bez testu na selhání malloc Chyby pro použití ukazatelů použití uvolněného bloku pro zápis (wfb) write/modify a free block. použití uvolněného bloku pro čtení (rfb) read in a free block. zápis za koncem pole v zásobníku (buffer owerflow) zápis za koncem alokovaného bloku (bvh) block bounds violation in the heap. čtení za koncem alokovaného bloku (bvh) block bounds violation in the heap. zápis daleko za koncem alokovaného bloku zápis před koncem alokovaného bloku (bvh) block bounds violation in the heap. čtení před koncem alokovaného bloku (bvh) block bounds violation in the heap. čtení neinicalizované paměti (ruh) read uninitialized byte(s) in a block. Poměrně mě překvapilo, že checker neobjevil buffer owerflow. Sice objeví neinicializované čtení, ale neumisťuje "red zones" mezi pole na zásobníku (pouze při volání funkcí). Je to ale v TODO a tak se toho snad brzo dočkáme (podobně jako zón mezi statickými poli). Také u zápisu daleko za koncem se podařilo přestřelit z jednoho alokovaného bloku do druhého. Jinak ale checker udělal skvělou práci. Podobně jako u lclintu, možnosti checkeru nekončí objevováním chyb z mých testů a najde i mnoho dalších (špatné zarovnávání apod.). Na požádání objeví například i tu chybu z alokací velikosti 0. Použití je už také poměrně snadné. Díky integraci patche do gcc a stubům nyní stačí stáhnout asi 500KB balík, zkompilovat a ladit. Toto řešení je ale bohužel téměř nepřenositelné a proto existuje verze pouze pro Linux na Intelu. Samotný checker je ale napsán přenositelně a proto by asi nebyl problém napsat podporu i pro jine operační systémy a architektury. Zdrojové kódy najdete na ftp.prep.ai.mit.edu/pub/gnu výheň