Statyczna analiza kodu, czyli jak komputer może szukać błędów
03.02.2010 - Krzysztof Skrzętnicki
A teraz na serioBardzo wiele rzeczy działa dobrze na małą skalę. Problemy zaczynają się, gdy przechodzimy od problemów zabawkowych do prawdziwych zastosowań. Z zadowoleniem mogę jednak stwierdzić, że scan-build doskonale spisuje się nawet przy projektach o znacznej wielkości. Osobiście pracuję od kilku nad rozwojem internetowej gry tekstowej Killer MUD. Kod gry jest bardzo złożony i rozległy - ponad 260 tysięcy linii kodu ANSI C. Wielokrotnie w trakcie prac pojawiały się błędy których wytropienie i naprawienie było bardzo czasochłonne. Czasami było to nawet kilka dni pracy. O ile prościej byłoby, gdyby błędy te można było znaleźć z góry. Znalezienie błędu zanim on wystąpi w grze jest jednak praktycznie nierealne - jeżeli miałby to robić człowiek. Co innego komputer. Uruchomiłem scan-build: 622 bugs found. scan-build: Run 'scan-view /tmp/scan-build-2010-02-03-1' to examine bug reports. Całkiem niezły wynik - na pewno jest co analizować. Statystyki pokazane na początku raportu mówią nam nieco o najczęściej napotykanych błędach: Widzimy dwie kategorie błędów: Dead store i Logic errors. Pokazaliśmy na naszym poprzednim przykładzie, że błędów Dead store nie można ignorować. Mimo tego druga kategoria błędów zwykle jest o wiele poważniejsza. Łatamy prawdziwe błędyPo otworzeniu pierwszego lepszego przypadku ujrzałem taki widok. W poniższym kodzie poprawnie zauważone zostało użycie niezainicjowanej zmiennej Gdyby makro
to w trakcie wykonania odpowiedniej funkcji wystąpi błąd, który unieruchomi serwer. Kontynuujemy polowanieZałatawszy poprzedni błąd możemy przejść do kolejnego. Zanim to nastąpi, zastanówmy się najpierw, co wiemy o błędach z pierwszego ekranu raportu? Po pierwsze znamy kategorię - to może nam sugerować powagę błędu. Wiemy w jakim pliku, a co za tym idzie w jakim elemencie programu występuje błąd. Bez znajomości projektu nie mówi nam to jednak wiele. Mamy też podaną statystykę o nazwie "Path Length". "Path Length" oznacza po angielsku "długość ścieżki". Co oznacza ta wielkość? Oznacza ona liczbę kroków, które muszą zostać wykonane, aby wystąpił błąd. Jako wykonanie kroku rozumiane jest wykonanie jakiejś instrukcji sterującej, np. Im krótsza długość ścieżki, tym łatwiej jest zrozumieć o co chodzi w raporcie błędu. Z drugiej strony dłuższa ścieżka wskazuje skomplikowany kod, w którym wychwycenie błędów bez pomocy programu może być trudne, albo wręcz niemożliwe. Rekordowa ścieżka znaleziona w kodzie Killer MUDa wynosiła 63 kroki i odnosiła się do dokładnie 500 linii kodu. To bardzo dużo i analiza tych wszystkich warunków jest trudna. Najlepszym rozwiązaniem jest nie tworzyć tak skomplikowanego kodu i dzielić złożone funkcje na mniejsze fragmenty, o jasno określonych zadaniach. Fałszywy alarmPo przejrzeniu kilku raportów staje się jednak jasne, że nie wszystkie ostrzeżenia otrzymane od narzędzia faktycznie prowadzą nas do błędów. Zdarza się, że zgłoszony błąd to fałszywy alarm. (Należy jednak zdawać sobie sprawę z tego, że napisanie narzędzia idealnego, które znajduje każdy błąd, jest niemożliwe.) Przykładowo,
Program ten jest poprawny i zawsze wyświetli "x = 5". warning: Pass-by-value argument in function call is undefined. printf("x = %d\n", x); ^ ~ Argumentuje to tym, że w przypadku, gdy gałąź kodu dla (3 ocen) |
Copyright © 2008-2010 Wrocławski Portal Informatyczny
design: rafalpolito.com