FORMÁLIS SZOFTVERVERIFIKÁCIÓS ESZKÖZÖK ALKALMAZÁSÁNAK NEHÉZSÉGEI A GYAKORLATBAN PRACTICAL DIFFICULTIES OF THE APPLICATION OF FORMAL VERIFICATION TOOLS Dávid Ákos Pannon Egyetem, Műszaki Informatikai Kar Összefoglaló Napjainkban egyre nagyobb jelentőséggel bír a szoftverek megbízható, helyes működése. Nem csupán az utólag felfedezett hibák és problémák meglehetősen költséges javítása, valamint az ebből adódó időveszteség okoz komoly fejtörést a programozóknak és rendszerépítészeknek, hanem a tervezési fázis után megmaradó rejtett hibák jelentette biztonsági kockázat a biztonságkritikus alkalmazásoknál, mint amilyen az autók biztonsági rendszereit vezérlő elektronika. A formális módszerek és az ezeket támogató eszközök is rendkívül sokat fejlődtek az elmúlt időszak folyamán, már egy közepes teljesítményű számítógép erőforrásait használva is vizsgálható egy szoftverrendszer adott specifikációra vonatkozó helyessége. A módszer számos esetben automatikusan végezhető, mint például a modellellenőrzésnél. Ez utóbbi módszert számos ingyenes, illetve kereskedelmi eszköz támogatja, ám használatuk legalább annyi gyakorlati problémát felvet, mint amennyi haszonnal kecsegtet. Írásomban példákat szeretnék adni a felmerülő problémákra, valamint az esetleges megoldási javaslatokra. Kulcsszavak komponens, modell, verifikáció, modellellenőrzés Abstract Nowadays there is an increase in the significance of the reliable and correct functioning of software products. It is not only the costly fixing of errors and problems discovered later or the loss of time caused by this that intrigues programmers and system architects, but also the security risk of hidden errors left in the code after the design phase at the safety-critical applications, such as the electronics controlling the safety systems of a car. Both formal methods and the tools supporting them have made a considerable development during the past few years, so the correctness of a software system for a given specification can now be verified by using the resources of a moderate-size computer. In several cases the process can be fully automatic like in the case of model checking. This method is supported by a number of free and commercial tools. However, their use raises just as many practical problems as benefits. In this paper my goal is to present examples for these problems and the possible solutions to them. Keywords component, model, verification, model checking 1
1. Bevezetés Az egyes modellellenőrző eszközök szinte mindegyike saját bemeneti definíciós nyelvet (IDL) használ, ami megnehezíti, a különböző környezetben fejlesztett, illetve verifikált szoftverkomponensek együttműködésének ellenőrzését. Külön problémát jelenthetnek az ún. polcról levehető, harmadik fél által készített komponensek (COTS), amelyek belső működése egyáltalán nem vagy csak részben ismert. Egy, a környezetét félreértelmező komponens működése potenciális katasztrófához vezethet, amennyiben a verifikációs folyamat nem derít fényt a helytelen együttműködésből fakadó problémára. Ezért különösen fontos az ellenőrzéshez használt specifikáció részletessége, pontossága. Ehhez kiváló segítséget nyújthatnak olyan példarendszerek, esettanulmányok, amelyek lehetőséget biztosítanak a hallgatóság számára, hogy még a tervezés korai szakaszában megismerkedjenek egy adott verifikációs eszköz (pl.: az NuSMV) specifikációs, illetve modellező nyelvének korlátjaival, a tervezett komponens(ek) granularitási kérdéseivel, a rendszerelemek közötti együttműködés szükséges és elégséges feltételeinek rögzítésével. Szintén jó lehetőség a nagyobb és összetettebb rendszerek verifikációs folyamatának hatékonyságát vizsgálni, ami nagyban meghatározza a formális módszerek ipari környezetben történő felhasználásának sikerességét. A Pannon Egyetem Műszaki Informatikai Karán tanuló hallgatók számára 2007. őszétől vált elérhetővé a Programozási technikák és modellezés című tárgy, amely a szoftvertechnológia korszerű paradigmái mellett komoly hangsúlyt fektet a modell-alapú szoftverfejlesztésre és az így elkészült rendszerek megbízhatóságának ellenőrzésére. A formális módszerek megjelenését a szoftververifikációban az indokolja, hogy a mai napig elterjedt tesztelési technikák nem képesek kiszűrni a rendszerben maradt rejtett hibákat, ami számos esetben nem elfogadható (gondoljunk a biztonság-kritikus alkalmazásokra). Ezzel szemben a formális módszerek garantálják, hogy egy rendszer működése az adott specifikációra nézve helyes. Ez teszi lehetővé az ipari környezetben történő felhasználásukat, például a hardver- és szoftverellenőrzéseknél. Sajnos, a formális módszerek nem mindegyike képes a laboratóriumi körülményeken kívül is jól teljesíteni, mind a tételbizonyítás, mind pedig a szintézismódszerek túlságosan sok manuális lépést tartalmaznak. Oktatási céllal azonban ezek is jól használhatók. Természetesen a fő hangsúly a már gyakorlatban is bizonyított modellellenőrzésre kerül, amelynek során a hallgatók tetszőlegesen absztrakt szinten írják le a rendszer viselkedését, majd még a kód generálása előtt megvizsgálhatják, hogy egy adott program összes végrehajtási formája megőrzi-e a specifikációban rögzített attribútumokat. 2. Komponens-elvűség Napjaink felgyorsult világában egyre kevésbé használhatók a hagyományos szoftvertechnológiai módszerek. A sürgető határidők miatt a munkát részfeladatokra kell bontani, amelyen független csapatok dolgoznak. Ez az igény hívta életre a komponens-elvű szoftverfejlesztést (CBSD), amelynek vezérelvei: az újrahasznosíthatóság és a fejleszthetőség (Szyperski, 2002). Előbbi a már meglévő programrészek módosítás nélküli újbóli felhasználását, utóbbi pedig a komponens-alapú szoftverek karbantartási költségeinek alacsonyan tartását jelenti. Ez úgy lehetséges, hogy a rendszerkomponensek cseréje nincs hatással a rendszer többi részére. 2
A vezérelvek használatához három feltételnek kell eleget tenni: szükség van egy komponens-könyvtárra, egy komponens-modellre és valamilyen szoftverarchitektúrára. 2.1. A komponens-könyvtár A nagy és komplex rendszerek fejlesztésénél kétségkívüli a komponens-elvű szoftverfejlesztés előnye a tradicionális módszerek felett. A fejlesztőknek nem kell csupán a saját programjaikra hagyatkozniuk, hanem igénybe vehetik más szakértők tudását is, amennyiben harmadik fél által készített komponenseket (COTS) használnak fel. Ez nyilvánvalóan felgyorsítaná az összetett rendszerek fejlesztését, ugyanakkor felveti a kérdést, hogy az ilyen komponensek mennyire lesznek megbízhatóak új környezetükben. Fontos tudni, hogy nem csupán a fejlesztői és a valós felhasználási környezet közötti különbség okozhat problémát, hanem előfordulhat, hogy a készítője nem arra szánta a komponenst, amelyre ténylegesen felhasználják majd. Mivel a legtöbb komponens általános célú az újrahasznosíthatóság jegyében, egy komponensekből összeállított rendszer helyes működéséről nem könnyű meggyőződni. A problémához kapcsolódó megoldási javaslatot Hans Gerhard Gross veti fel (Gross, 2005). Ahogy fentebb is szerepel, a komponens-elvű fejlesztés egyik kulcsgondolata a már megírt kódrészek újrahasznosítása, azonban a szoftverfejlesztők jelentős része még most is inkább megírja a saját komponensét, ahelyett, hogy a már meglévőket integrálná a rendszerbe. Ennek oka valószínűleg a produktivitás régimódi mércéje, amely a kódsorok számát jelenti (Sparling, 2000). Ezért is fontos, hogy létrejöjjön egy oktatási célú komponens-könyvtár, amely lehetőséget ad a leendő informatikusok számára, hogy a meglévő komponensek rendszerbe illesztésére fókuszáljanak ahelyett, hogy tonnaszámra készítenének kódot. 2.2. A komponens-modell A különböző szoftverkomponensek együttműködéséhez szükséges, hogy azok valamilyen szabványra illeszkedjenek. Sajnos, ezek a szabványok nem átjárhatóak. Jelenleg az iparban az alábbi három komponens használata a legelterjedtebb: az OMG (Object Management Group) által fejlesztett CCM (CORBA Component Model), a Microsoft által fémjelzett DCOM és.net, valamint a Sun által fejlesztett EJB (Enterprise JavaBeans). Jelenleg is érdekes terület a különböző szabványú komponensek együttműködésének biztosítása és verifikációja. 2.3. Szoftverarchitektúra A szoftverarchitektúra adja tulajdonképpen a fejlesztendő rendszer gerincét, hisz magában foglalja a rendszer struktúráját, beleértve a szoftverelemeket, ezek kívülről elérhető tulajdonságait és az egyes elemek közötti interakciókat. Jelentősége három gondolatban összefoglalható: magas szintű rendszermodellt nyújt, megmutatja a korai tervezési döntéseket, valamint hordozható struktúrát képez, amely átvihető más, hasonló felépítésű és méretű rendszerekre (Bass et al., 2003). 3. Verifikációs módszerek 3.1. Tesztelés és helyességbizonyítás Napjaink tesztelési módszerei nem bizonyultak alkalmasnak a nagy és összetett rendszerek ellenőrzésére, mivel nem képesek garantálni, hogy nem marad rejtett hiba a rendszer tervében vagy programkódjában. A komponens-alapú alkalmazások általában elosztott rendszerek, ami különösen nehézkessé teszi a tesztelésüket. Az ilyen rendszerek tesztelése két szinten zajlik: a különálló komponensek tesztjéből és az integrációs tesztből. Ehhez azonban szükség van egy 3
felhasználói interfész vagy egy tesztpad létrehozására. Az interfész kifejlesztése sokszor legalább annyi időt vesz igénybe, mint a komponens elkészítése, a tesztpad kialakítása pedig mindegyik komponens-modellhez szintén körülményes. Ezen felül az időzítési problémák kezelése is szinte teljesen lehetetlen. A helyességbizonyításos módszereknél a legnagyobb probléma, hogy a klasszikus logika használata nem teszi lehetővé, hogy az idő explicit módon megjelenjen a specifikációban. Ily módon szinte lehetetlen a konkurens rendszerek idő függvényében változó tulajdonságait kifejezni. A temporális logika megjelenése próbálta orvosolni a problémát, de csak laboratóriumi körülmények között működött (Kroger, 1987). 3.2. Szintézis módszerek A helyes konkurens programok derivációs módszerei tulajdonképpen megfordítják a helyességbizonyítás lépéseit. A különböző szintézis módszerek különféle specifikációs eszközöket használnak, úgy mint a klasszikus logika és a temporális logika (Emerson, Clarke, 1982). A korai szintézis módszereknél a kielégíthetőség vizsgálatát végző algoritmus a tabló módszert használta, hogy az egyes temporális tulajdonságokról eldöntse, hogy kielégíthetőek vagy sem. Az egyik legfőbb probléma az volt, hogy n egymástól független, konkurens folyamat esetében az állapottér 2 n volt. Attie és Emerson ugyan bemutatott egy olyan módszert, amellyel leküzdhetővé vált az állapotrobbanás, de a módszer csak egy roppant szűk tartományon belül alkalmazható (Attie, Emerson, 1998; Attie, Emerson, 2001). 3.3. Modellellenőrzés A modellellenőrzés az előzőekkel szemben egy teljesen automatikus módszer véges állapotú, konkurens rendszerek ellenőrzéséhez (Clarke et al., 2000). Számos előnye van a tradicionális módszerekkel szemben. A felhasználónak elegendő csupán a tervezett rendszer egy magas szintű modelljét, valamint az elvárt tulajdonságokat rögzítő specifikációt megadni, majd a módszer megvizsgálja az összes lehetséges állapotátmentet, és igaz válasszal tér vissza, ha a rendszer modellje teljesíti a tulajdonságokat. Amennyiben hamis válasszal tér vissza, akkor megadja azt a végrehajtási szekvenciát, ami a tulajdonság megsértéséhez vezetett, ami nagy segítség a hiba javításához. A modellellenőrzés viszonylag gyors, még a közepes teljesítményű (akár asztali) számítógépeken. Némely esetben nem véges állapotú rendszerek is ellenőrizhetők, ehhez különböző absztrakciós és indukciós feltevések szükségesek. A specifikáció megadásához használt temporális logika biztosítja, hogy a konkurens rendszerek időbeli viselkedését vizsgálni tudjuk. Az állapottér robbanása okozza itt is a legnagyobb gondot, de az utóbbi időben komoly eredmények születtek ennek leküzdéséhez: a bináris döntési fák (BDD), a szimbolikus modellellenőrzés, a részleges sorrendiségen alapuló redukció, vagy a különösen ígéretes a rendszerek bővítésével csak a megváltozott részek újraellenőrzését megkívánó nyílt inkrementális modellellenőrzés (OIMC). Ezen felül folynak kutatások a modellellenőrzés és a fentebbi verifikációs módszerek együttes használatára vonatkozóan is. 4. Nehézségek 4.1. Keretrendszer hiánya Jelenleg nem elérhető olyan oktatási célú keretrendszer, amely biztosítani az ideális komponens-elvű építkezést, amely leginkább a LEGO játékok összerakására emlékeztet (Bertolino, Polini, 2003). Szintén probléma, hogy amennyiben nem saját komponenseket 4
használunk, akkor szinte bizonyos, hogy az eredeti fejlesztői környezet eltér az általunk használt keretrendszertől, így meg kell vizsgálni a komponens viselkedését, hogy együtt tud-e működni a környezetével. Ehhez még az is kevés, ha csak ellenőrzött komponensekből építkezünk, hisz a használat módja is eltérhet az eredetileg tervezettől. Ezért szükség van az elvégzett helyességi információk programkódba történő beépítésére (és ott tartására), amelyek kontraktusok formájában rögzítik a felek (az együttműködni kívánó komponensek) jogait. Ily módon az integráció pillanatában már kiderül, ha egy komponens nem tud együtt dolgozni a rendszer többi részével. 4.2. Komponens-könyvtár hiánya A keretrendszer mellett hiányzik egy kimondottan oktatási céllal használható komponensgyűjtemény. Hiába érhető el most már több cég honlapján ún. komponens-piac, az ott lévő professzionális szintű komponensek amellett, hogy pénzbe kerülnek, általában túl összetettek és túl specifikusak ahhoz, hogy oktatási környezetben leessen rajtuk szemléltetni az újrahasznosíthatóság elvét például. 4.3. Granularitás Roppant fontos még a tervezés korai szakaszában eldönteni, hogy az általunk készítendő komponens milyen szemcsézettségű legyen. Egy túlságosan finom komponens valószínűleg nem túl általános, így az újrahasznosíthatóság elve kerül veszélybe. Ugyanakkor egy túlságosan durva szemcsézettségű komponens jóval összetettebb interfészekkel rendelkezik, és sokkal nagyobb eséllyel lesz szükség a menet közbeni megváltoztatására. 4.4. Modelltől való függetlenség Az egyes komponensek adott komponens-modellre kell, hogy illeszkedjenek. Ez viszont sérti a komponensek nyújtotta szabadságot, hisz hiába van EJB komponensem egy adott feladatra, ha a rendszer többi része a.net szabványt használja. Gyakorlatilag az első pillanatban el kell dönteni, hogy melyik modell szabványára építjük fel a rendszerünket. Ezen a téren is vannak törekvések, amelyek általában egy platform-független nyelv (általában az XML) használatával kívánják egy absztrakciós szinten elfedni a különböző modellre illeszkedő komponensek közötti különbségeket. 4.5. Inkrementalitás kérdése Egyre többeket foglalkoztat az igény, hogy egy rendszerkomponens megváltoztatásakor ne kelljen a teljes rendszert ismételten verifikálni, hanem csak az érintett, szűkebb részét. Amíg ez nem valósul meg, addig a komponens-alapú szoftverfejlesztés nem tud kilépni elődje, az objektum-orintált programtervezés árnyékából (Meyer, 1997). 5. Konklúzió A fent vázolt problémákból világosan látszik, hogy a komponens-elvű szoftverfejlesztős lehet a szoftvertechnológia megújítója, de ehhez még számos nyitott kérdést és felmerülő problémát meg kell oldani (Vitharana, 2003). Napjaink egyre növekvő elvárásai pedig egyszerűen nem teszik lehetővé, hogy nem megfelelően működő szoftverterméket hozzunk létre. Ennek két oka: egyrészt az ember egyre jobban függ az informatikai rendszerektől, amelyek átszövik a hétköznapjait, így már a tervezés fázisában ki kell küszöbölni a hibákat, másrészt az ehhez kapcsolódó pénzügyi költségeket is jelentősen lehet csökkenteni. A célunk az, hogy a jövő informatikusainak fókuszát elmozdítsuk a kódírásról a modellezés és a 5
rendszertervezés irányába. Ezzel együtt remélhetőleg a formális módszerek megértéséhez és gyakorlatban történő jobb alkalmazásához is hozzájárulunk. Irodalomjegyzék [1] Attie, P. C., Emerson, E. A. (1998) Synthesis of Concurrent Systems with Many Similar Processes, ACM TOPLAS Vol. 20, No. 1, pp. 51-115. [2] Attie, P. C., Emerson, E. A. (2001) Synthesis of Concurrent Programs for an Atomic Read/Write Model of Computation, ACM TOPLAS Vol. 23 (2), pp. 187-242. [3] Bass, L., Clements, P., Kazmar, R. (2003) Software Architecture in Practice (Second Edition), Addison-Wesley, 2003. [4] Bertolino, A., Polini, A. (2003) A Framework for Component Deployment Testing, Pro-ceedings of the 25th International Conference on Software Engineering. [5] Clarke, E., Grumberg, O., Peled, D. (2000) Model Checking, MIT Press. [6] Emerson, E. A., Clarke, E. M. (1982) Using Branching Time Temporal Logic to Synthesize Synchronization Skeletons, Sci. Comput. Program. 2, pp. 241-266. [7] Gross, H. G. (2005) Component-Based Software Testing with UML, Springer. [8] Kroger, F. (1987) Temporal Logic of Programs, Springer-Verlag. [9] Meyer, B. (1997) Object-Oriented Software Construction Second Edition, Prentice Hall. [10] Sparling, M. (2000) Lessons learned through six years of component-based development, Communications of the ACM, Vol. 43, pp. 47-53. [11] Szyperski, Clemens (2002) Component Software Beyond Object-Oriented Programming Second Edition, Addison-Wesley/ACM Press. [12] Vitharana, P. (2003) Risks and Challenges of Component-based Software Development, Communications of the ACM, Vol. 46, pp. 67-72. 6