пятница, 21 августа 2015 г.

Мой опыт статического анализа кода с PVS-Studio

Имеется у меня графический движок, с уклоном в разработку игр, который вырос из студенческого проекта и разрабатывается мной в свободное от основных занятий время.

Писался он изначально из-за желания изучить OpenGL, и поднять уровень знаний языка C++ и его инфраструктуры, а также, потому что хотелось написать игру. Игра так и осталась впереди, а движок пришлось несколько раз переделать, из-за проблем в коде.

Сейчас, я частенько дописываю те или иные возможности в данном проекте. Со студенческих времен он сильно изменился: появилась более-менее нормальная архитектура, появились тесты, которые позволяют худо-бедно проверять стабильность серьезных изменений в архитектуре проекта, которые нет-нет, да и возникнут.

Статический анализ до этого я применял на данном проекте, но не срослось с ним: Cppcheck последний раз, отработав часа три, показал три замечания и все оказались несущественными, так как могли воспроизвестись только на древних компиляторах.

Начитавшись статей на хабре и других ресурсах, решил попробовать PVS-Studio и прогнать его из-за интереса на своем проекте и посмотреть, что из этого получится.

Результаты первого прохода меня удивили: 80+ ошибок нашлось в главном проекте! Конечно, некоторые оказались дубликатами или не приводили к серьезным проблемам (пока), но, тем не менее, исправить предстояло много чего. Конечно же, подвел старый код, в котором оказалось много проблем:  деструкторы, которые должны были быть виртуальными, отсутствие в некоторых местах проверок на NULL и прочее. Однако и в относительно новых участках кода нашлись  странные вещи.

Приведу несколько примеров, чтобы не быть голословным.

Например, оказалось, что PVS-Studio хорошо находит дублирующие проверки:


Возможно, здесь остались следы от процесса отладки некого бага, но проверка явно здесь не нужна (animationswayinstance.cpp).

Также обнаружилась целое множество однотипных сообщений об ошибках:


Оказалось, что проблема находилась в макросе: был неверно выбран тип поля. Код работал, но расход памяти благодаря замене типа на правильный  сократился (object.h):



Нашлась и куда более серьезная ошибка в самописном загрузчике формата TGA (tgaloader.cpp).


Ошибка здесь заключается в том, что в сравнениях необходимо изменить равенство на неравенство, так как это следует из последующего текста.  Приятно, что статический анализатор нашел такую серьезную ошибку.

Ещё интересной подсказкой для меня стало требование замены CreateThread:


Каким-то образом, я пропустил то, что это API стало deprecated, и было довольно приятно узнать, что его стоит заменить.

PVS-Studio для моего проекта показал гораздо лучшие результаты, чем  Cppcheck по количеству найденных ошибок. Хоть здесь и приведены лишь наиболее критичные, но применение данного инструмента позволило мне существенно повысить качество моего небольшого проекта.