Ha szoftvert fejlesztünk, akkor abban lesz hiba is. Semmi gond, majd készítünk unit tesztet, funkcionális tesztet, integrációs tesztet. Sőt a felhasználók is fogják tesztelni. Ha elegendően sok tesztet készítünk, futtatunk akkor minden rendben lesz. De nem! A tesztekkel egy dolgot tudunk igazolni: A szoftver az adott teszteket futtatva az adott környezetben hiba nélkül futott. Ha ezt sokszor mormoljuk mint az imát és minden nap örülünk, hogy ismét felkelt a nap, mert minden reggel ezt szokta tenni, akkor hajlamosak vagyunk elhinni, hogy nincs komoly hiba a szoftverünkben. A mormolás megkönnyítésére használhatunk Continous Integration szervert és minden commit után kapunk megnyugtató email-t, még mindig nincs benne hiba. Pedig van. Na jó, de biztos nincs minden funkció lefedve és a code coverage mérés, az majd segít. Hát nem.
Lássunk egy konkrét példát. Történt a minap, hogy egy C++ kódot kellett egy titkosítási funkcióval kibővíteni. A titkosításhoz szükséges password összeállításának egyik lépése az volt, hogy a Registry-ből ki kell olvasni a szerver azomosítóját. Mivel Windows operációs rendszert használunk mi sem egyszerűbb az erre használható függvényt meg kell hívni és már kapjuk is az eredményt. A függvény többek között két paramétert vár:
- az egyik egy buffer ahova az eredményt fogja tenni
- a másik a buffer részére lefoglalt méret, ebben eredményül a buffer-be töltött hosszat kapjuk vissza
A függvény eredménye 0 vagy hiba kód. Az igazi eredmény persze a buffer-ből olvasható ki. Ezt az akadályt látszólag sikerrel vettük, hiszen a teszteken minden rendben volt. A titkosítás után a kititkosítás is rendben lefutott, pedig az egy másik modulban java-ban került megvalósításra (annyi könnyítés azért volt benne, hogy mind a két modul az openssl-t használta). A tesztek után a felhasználói tesztek is rendben voltak és használatba került a kód több ügyfélnél is. Aztán egyszercsak az egyik support-os kolléga jelezte, hogy nem tudta kititkosítani a titkosított állományt. Fejvakarás, log level állítás és nyomozás után arra jutottunk, hogy itt bizony súlyos hiba történt. Ezt az állományt a mai számítási kapacitások mellett senki sem fogja tudni kititkosítani. Márpedig ez a két funkció (titkosítás és kititkosítás) csak együtt értelmes. Esetleg a kititkosítás megállja helyét egyedül is olyan értelemeben, hogy nem okoz kárt, azonban hasznot sem hoz, de a titkosítás önmagában vetekszik a csak írható memóriával.
És akkor mi történt???? Több hibát is vétettünk.
- A függvény visszatérő értékét nem vettük figyelembe. Emocionálisan azzal magyarázható, hogy az eredmény a buffer-ben van.
- A buffer-nek ugyan lefoglaltunk elég helyet (256 byte), de ezt a méretet nem adtuk át paraméterként. Ott csak a buffer-be töltött eredmény méretét vártuk.
Mivel nem töltöttük ki a lefoglalt terület méretét ennek következtében azon az egy byte-on egy véletlen szám szerepelt ami ott maradt a stack-en. Ez ugye 0 és 255 közötti lehetett bármi. Ha ez a bármi éppen több volt mint a kiolvasni kívánt registry érték hossza, esetünkben 29, akkor rendben lefutott a függvény. A probléma akkor jött csak elő ha a "véletlen számunk" kisebb volt mint 29.
De akkor volt rá több mint 10% esély, hogy megtaláljuk a hibát!? Csak akkor ha egyforma eséllyel kapjuk bármelyik értéket.
Vajon mennyire volt ez a véletlen véletlen? Telepítés függő? Indítás függő? Futás függő? Ki tudja. Az biztos, hogy több száz titkosítás során nem jött elő a probléma.
És akkor most hogyan tovább? Ne teszteljünk? Vagy mit tegyünk még?
Azt eddig is tudtuk, hogy a tesztelés nem javítja meg a talált hibákat. Most tegyük hozzá, hogy nem minden hibát lehet megtalálni teszteléssel. Szerencsére vannak egyéb módszerek is.
- Válasszunk olyan programozási nyelvet ami eleve kizárja az ilyen jellegű hibák elkövetését pl. Java. Nincs inicializálatlan memória terület, a hibákat kivétel kezeléssel oldja meg, típusos adatátadás, hogy csak azokat említsem ami ebben az esetben segített volna.
- Tervezési és/vagy kódolási formális/ nem formális felülvizsgálat.
- Kódolási konvenciók automatizált ellenőrzése
- pair programming
- quality assurance
Erről részletesebben itt. És gondoskodjunk olyan support-os kollégákról akik még az ilyen véletlenszerű rejtett hibákat is felfedik.