суббота, 17 декабря 2011 г.

cppcheck


cppcheck - инструмент для статического анализа кода на C и C++. Он служит для обнаружения ошибок и потенциальных уязвимостей, которые не обнаруживаются компилятором. cppcheck имеет как консольный интерфейс, так и графический, основанный на Qt4.
Есть даже его плагины для различных IDE: Code::Blocks, CodeLite, Eclipse, Hudson, Jenkins, можно также подключить к Visual Studio как внешний инструмент. В описании разработчики декларируют малое количество ложных срабатываний, а также совместимость с любым компилятором, поддерживающим последний стандарт C++.

cppcheck - довольно интересный инструмент, т.к. может работать в несколько потоков (только на POSIX системах), имеет весьма удобный GUI, который может по выделенному предупреждению открыть текстовый редактор на нужной строчке, позволяет фильтровать сообщения по типу и подстроке, кушает не очень много памяти, сам ищет файлы с исходниками и много чего ещё.

Отчёты помимо тех, что отображаются во время анализа в окне анализатора, могут быть сохранены в текстовом виде, csv, xml, после чего преобразованы в html.

Теперь о том, какие именно ошибки он может находить. Их очень много, приведу краткий список:
  • Выход за границу массива
  • Неиспользуемые переменные
  • Неиспользуемые функции
  • Разыменование нулевого указателя
  • Утечки памяти
  • Утечки ресурсов
  • Возможные проблемы с переносимостью между компиляторами
  • Проблемы переносимости на 64 битные платформы
  • Валидность указателей на локальные переменные
  • Ошибки в проектировании классов (некорректные операторы =,
    отсутствие конструкторов, применение memset для объектов)
  • Безопасность исключений (неотлавливаемые throw)
  • Ошибки в условиях (проверка на истинность/ложность)
  • Ошибки в использовании stl
  • Присвоение переменной самой себе
  • Члены, не инициализированные в конструкторе
В общем то уже неплохой список, подробнее можно почитать на wiki разработчиков.

В теории выглядит классно. Как оно поведёт себя на практике? К сожалению, у меня пока что нет нормальных синтетических тестов для проверки анализаторов, поэтому я решил прогнать его на каком-нибудь реальном проекте. Для примера я взял firefox-3.0. Проект довольно большой. Состоит из 9349 файлов с исходными кодами (C и C++), занимают они 48 Мб. Самый большой файл - sqlite3.c размером 4,1 Мб (это 113968 строк кода). При этом сам cppcheck почему-то обнаружил только 5458 файлов.

Работал cppcheck почти 9 часов, но при этом потребление оперативной памяти оставалось примерно на уровне 150 Мб., что очень важно, ведь было бы обидно потерять результаты нескольких часов работы программы из-за нехватки памяти. Надо заметить, что анализ производился в один поток на процессоре Core i5, 2.67GHz, 64 битная система. Большая часть этого времени ушла на анализ всего нескольких файлов - sqlite3.c (есть 2 файла с этим именем, оба большие) и wrap_XPCOM.cpp (тоже весьма немаленький).

В сумме он выдал 275 ошибок, 3025 предупреждений, 2675 стилистических предупреждений, 315 вероятных предупреждений. Отчёт без проблем сохранился в xml. В html он преобразовываться почему-то отказался и выдал мне стек вызовов питоновских функций (тулза для преобразования xml в html у них написана на питоне). csv отчёт получился нормальный.

Что же входит в эти ошибки и предупреждения? Среди ошибок большинство указывает на утечку ресурсов или памяти (на сколько правильно - вопрос спорный), указания о возможном разыменовании нулевых указателей (обычно обоснованно), встречаются предупреждения о приравнивании переменных самим себе (ну тут уж сложно дать ложное сообщение). Очень порадовало стилистическое предупреждение о том, что член-функцию можно сделать константной. Многим было бы полезно. Нашлось много неиспользуемых переменных. Интересное предупреждение о том, что переменную можно урезать. Т.е. есть возможность сохранить корректность программы не выделяя памяти под переменную. Встречаются сообщения о неиспользованных структурах. Множественные сообщения о возможности проблем при портировании на другой компилятор.

Теперь о ложных срабатываниях. Очень похоже, что он не умеет различать typedef и из-за этого на типах-синонимах почти все срабатывания ложные. Если выделенный массив памяти присвоить внешней переменной и не отчистить его, считается, что была утечка памяти. На самом деле - это не так, но согласен, лучше предупредить. Не очень качественно обрабатывает макросы. Тоже встречаются ложные срабатывания. Почему-то посчитал, что int является беззнаковым типом.

В целом данной программой я остался доволен. В будущем я планирую посмотреть ещё несколько инструментов для анализа и попытаться провести их сравнение, а также составить несколько примеров с ошибками для их тестирования.

Комментариев нет:

Отправить комментарий