Статический анализ кода C++

    Для меня красота C++ заключается, в первую очередь, во вседозволенности и ужасающей мощи языка. Мы можем работать с памятью так же плотно, как и в C, и в то же время имеем такие средства абстракции, как шаблоны и STL, где параметризовать можно что угодно и чем угодно.
    Плата за это соответствующая — не всегда вразумительные ошибки компилятора (попробуйте забыть поставить точку с запятой после определения класса), очень большой срок подготовки и обучения программистов, но самое главное — некоторые баги становятся заметными только во время исполнения программы.
    Мы хотим больше полезных ворнингов до запуска наших программ. Одно из средств получения желаемого — статический анализ кода. Статический — значит, не запуская программу. Интересны не только вероятные ошибки, случаи undefined behaviour, утечки памяти, но и вещи вроде недоступности/неиспользуемости кода, рекомендации по повышению интуитивности стиля программирования.

    Средства получения метрик ПО, добываемых методами статического анализа в этой статье не рассматриваются. Замечания, связанные со стандартами программирования (фигурная скобочка должна находиться на отдельной строчке, ууууу!!) тоже не интересны.
    Критерии оценки простые — количество и полезность находимых багов, простота использования (в частности, отсутствие требований модификации кода), бесплатность/разумная цена/хороший кряк.
    Проводим первичный обзор и выдаем на-гора пачку ссылок:


    Найденные штуки


    Педантичные ключи gcc


    В первую очередь, надо использовать все возможные штатные средства. gcc предоставляет следующие интересные ключи, связанные с повышением бдительности компилятора и препроцессора.
    • -Wall включает все ворнинги, среди которых совместимость с новым стандартом, границы массива (по-моему, не пашет, хотя говорят, что будет работать с -O2), volatile/register переменные (сообщит, что ему пофигу на твои умные слова и что //register//, а что нет, он будет решать сам), точки следования (i++ + ++i)
    • -Wextra — еще пачка ворнингов типа пустых тел в if'ах, сравнение signed и unsigned
    • -pedantic — следование ISO C++ стандарту. Например, запрет типа long long.
    • -Weffc++ must have опция. Не включается с помощью -Wextra или -Wall и содержит проверку рекомендаций Скотта Мейерса:
      • Item 11: Define a copy constructor and an assignment operator for classes with dynamically allocated memory.
      • Item 12: Prefer initialization to assignment in constructors.
      • Item 14: Make destructors virtual in base classes.
      • Item 15: Have «operator=» return a reference to *this.
      • Item 23: Don't try to return a reference when you must return an object.
      • Item 6: Distinguish between prefix and postfix forms of increment and decrement operators.
      • Item 7: Never overload "&&", "||", or ",".
    • -Woverloaded-virtual — перегрузка виртуальных фунций выглядит плохо.
    • -Wctor-dtor-privacy — неиспользуемые классы — с приватным конструкторами и деструктором
    • -Wnon-virtual-dtor — невиртуальный деструктор
    • -Wold-style-cast — приведение в стиле C — это плохо
    • -Werr='тип ворнинга' — воспринимать ворнинг как еррор. Для настроящих самураев -Werr без параметров
    • -Wconversion -Wsign-conversion — ворнинг о преобразовании типа. при котором значение может измениться. Как ни странно, не входит в -Wall
    • -Winit-self — int i = i;
    • -Wunreachable-code — код, который никогда не будет выполнен

    Разумеется, не сам такой умный, а прочитал всё вот в этой ман-статье про ключи, связанные с предупреждениями

    Cppcheck


    Пожалуй, самая достойная из найденных программ.
    Официальный сайт программы и её плагин для эклипсоидов. Распознает довольно много, находит следующие ошибки:
    • некоторые memory leaks, например, отсутствие delete и delete[], отсутствие delete в деструкторе
    • выход за границу массива
    • exception'ы, бросаемые в деструкторе
    • разыменование нулевого указателя
    • разыменование после очистки памяти
    • виртуальность деструктора базового класса
    • использование одного и того же итератора для разных контейнеров
    • разные более мелкие штуки

    Есть возможность помечать классы как умные указатели (чтобы не рапортовало о ложных мемликах), GUI на Qt4.

    Vera++


    Vera++, в отличие от cppcheck, ориентированна на проверку стиля. Имеет пополняемую базу правил. По умолчанию в базе много реально идиотстких штук типа «перед двоеточием должен быть пробел». Единственная полезная возможность — запрет на использование using namespace в заголовочных файлах. Правила, однако можно писать и самому на языке Tcl. :)

    RATS


    RATS рассказывает довольно-таки убедительные страшилки про безопасность и buffer overflow-атаки. Не стал пристально разглядывать потому что не очень-то много знаю про защищенный код.

    Проверялки для C без плюсов


    Удивительно, но программисты на чистом Си, похоже, больше заботятся о статическом анализе. Тут мы имеем список раз и два

    Будут ли они полезны плюсовым разработчикам? Если у вас есть код без классов и вы помните, какие программы на C++ не будут собираться компилятором С, то почему бы и нет?

    Splint


    Вот такая штука для чистого C. Собирается практически без усилий, но работает чистенько и много чего ищет — смотри мануал.

    Simian


    Simian — similarity analyzer. Ищет дублирование кода, значит. Честно говоря, я не придумал ей применения

    CIL


    CIL — С Intermediate Language. Компилирует C в упрощенный C! Упрощенный C уже можно скармливать другим анализаторам, что теоретически должно повышать качество их работы.

    Непонятное, офтопное


    • Oink. Будьте осторожны, если захотите это юзать. При компиляции мне показалось, что я собираю как минимум ядро linux для какой-нибудь экзотической архитектуры. требует Flex и Bison, долго догадывался… (: А еще надо фиксить кучу ошибок при компиляции — такое впечатление, что разработчики свое детище не то, что никогда не запускают — не собирали ни разу. В конце концов зверя одолел, а вот | список фич оказался отнюдь не внушительным. Работает с файлами препроцессора, но выдает по ним какую-то чушь: натравив на простую ошибку с границей массива — получаю тишину. Если же скормить oink'у что-нибудь на C++ с STL — он разразится тирадой на много-много строк. И это я получил ценой 3 часов компиляния и правки исходников?
    • Mozilla Dehydra — нечто, базируещееся на этом самом Oink'е. Буду рад, если кто-нибудь расскажет об этой чекалке, ибо слово Mozilla в этот раз отнюдь не означало «все просто и понятно». Список находимых багов не увидел, компилять не хотелось после Oink'a.
    • Еще есть компиляторы, которые предоставляют больше ворнингов на основе статического анализа. Например Rose
    • Rational Purify — прославленная компания IBM Rational имеет свой набор инструментов для статического и динамического анализа. Буду рад, если кто-нибудь расскажем об этой программе, триальник для линукса у них оказался только для x64-архитектуры.


    Триальное/крякнутое ПО


    А мало его такого. Много анализаторов, стоящих много долларов и не имеют кряков.
    Вот пример такого анализатора, можно зайти на их сайт и попросить триальник Cleanscape. Возможности не сильно отличаются от cppcheck.

    Что бы еще хотелось


    Не все ошибки в коде, поддающиеся статическому анализу, были представлены в существующих программах. А хотелось бы:
    • Политику спецификации исключений как в Java.
    • использование auto_ptr в контейнерах STL, разыменование auto_ptr после присвоения другому auto_ptr.
    • using namespace в h-файлах
    • переопределенный delete без new или new без delete
    • вызов delete[] для немассивов
    • использование vector с bool-значениями внутри
    Поделиться публикацией
    Комментарии 43
      +1
      С Eclipse что-нибудь интегрируется?
      Например, когда работаю с PyDev и подключен lint, анализ происходит на лету.
      Такого для C++ нет?
        +1
        cppcheck интегрируется.
        Еще мне понравилось, что его в систему сборки легко включить.
          +1
          О, спасибо, пропустил в статье, точно есть!
          Будем пробовать :-)
        +3
        Статья хорошая, но
        имеем такие средства, как шаблоны и STL, превосходящие по уровню абстрактности все, что я когда-либо видел


        Мне кажется, вы видели не все =)
          +1
          Сочтем это гиперболой. (:
            0
            Ну ладно, ладно, убрал!
            0
            не всегда вразумительные ошибки компилятора

            тут автор наверно хотел сказать: «всегда невразумительные ошибки компилятора» (:
              +3
              Думаю он хотел сказать то, что хотел. Наверно вы просто хотите развести Holy War?
                +1
                Ни в коем случае, я исключительно делюсь личными наблюдениями.
                Еслиб я хотел раззвести холивар, то придрался-бы к той-же фразе, что и предыдущий комментатор =))
              +1
              Вы не знаете, есть ли подобные опции и анализ в компиляторах Intel и Microsoft? Может быть вы сделаете серию статей и исследуете в них эту функциональность?
                0
                хорошая идея. почитаю ключи icc
                  +2
                  достаточно доплатить ~5k$ за Visual Studio TeamSystem и ключик /analyze для cl.exe ваш :)
                    +1
                    Хотя если вам не хочется делать таких пожертвований Майкрософту, то есть другой вполне легальный способ того как скачать этот анализатор.
                  +1
                  А что вы имеете против использования std::vector?
                    0
                    Что я могу иметь против контейнера, который рекомендован для использования по умолчанию? А вот vector — странный он немного. Почитайте, например, вот тут: alenacpp.blogspot.com/2005/06/vector.html
                      +1
                      по ссылке про vector а не про vector
                        +1
                        парсер… он такой… парсер…
                        там про специализацию для bool непонятно зачем включенную в стандарт
                          +1
                          долбанный парсер!!! Я понял, в чем вопрос. У меня bool тоже убежал
                    +1
                    >Dehydra… компилять не хотелось после Oink'a
                    Скоро будет идти плагином для gcc4.5. Так что можно будет использовать так же легко как и остальные продукты mozilla :)

                    и как можно было забыть про такой замечательный Российский продукт Viva
                    +2
                    Еще забыли про -Wconversion — клёвый флаг
                    А delete[] не для new[] никак не проверишь статическим анализом, для этого есть valgrind
                      0
                      большое спасибо. Я проглядел его мельком, думал, что он включен в -Wall. Ан нет!
                      Добавил в статью
                        0
                        Почему не проверишь?

                        Такое же легко можно проверить:

                        int * px = new int;
                        delete [] px;
                          +1
                          ну да, простейшие случаи-то можно было бы и обрабатывать…
                            +2
                            Ну как бы под статическим анализатором кода понимается попытка проверить и обработать как можно большее количество случаев. Если бы статически можно было определить всё, то уже давно бы существовала верификация кода для С++.

                            Собственно случай с delete/delete [] по сути ничем не отличается от выхода за пределы массива. Где-то мы можем обнаружить выход, а где-то нет, хотя он там на самом деле может быть.
                        +1
                        > = вместо == в if'ах

                        int main(int argc, char* argv[]) {
                        if (argc = 1) return 1;
                        return 0;
                        }


                        $ gcc -Wall test.c

                        test.c: In function ‘main’:
                        test.c:2:3: warning: suggest parentheses around assignment used as truth value
                          0
                          виноват, убрано
                          +1
                          анализ шаблонов есть где? :)
                            0
                            можно поконкретнее?
                              0
                              да хотя бы варнинги выдавать какой именно шаблон выбрался из нескольких (и почему другие не выбрались)

                              или правильно выдавать ошибки взаимосвязей шаблонов (например gcc часто тупо выдает вам ошибку на конец файла, и упоминает имя шаблона изза которого инстанциация не получилась, в таких случаях приходится долго курить код чтобы понять отчего инстанциация не удалась)

                              нормализатор шаблонов тоже бы пригодился (генерирует класс который получается в результате инстанцирования всех шаблонов)

                              и тд и тп…
                            +1
                            кстати, free trial есть и у лидера на этом рынке Coverity
                              +1
                              А Вы пробовали получить этот trial?
                              У меня не получилось… :-(
                              P.S. Прошу откликнуться, кому удалось.
                                0
                                Я заполнил какую-то ацкую анкету и подал запрос. В ответ — тишина.
                              +1
                              Simian гибко настраивается на игнорировани констант, типов прочего, что позволяет:
                              а) увидеть общий код (т.е. код, где алгоритмы очень похожи)
                              б) дрючить программеров за копипасты
                                0
                                хммм, ну цели подрючить-то я не ставлю. А вот если над проектом работает несколько команд и они написали сходный код… Не, все равно не понимаю, зачем это может быть надо.
                                +3
                                Со временем сюда можно будет добавить и анализатор из Clang'а, который уже в некотором роде поддерживает C/Obj-C и сейчас полным ходом идет работа над поддержкой С++. Apple добавила нативную поддержку анализатора в свой последний xcode и выглядит это теперь ну очень красиво (а главное удобно):
                                  0
                                  Ой зря вы забыли упомянуть PC-LINT, а ведь это самый мощный (если кто-то сможет это оспорить то я определенно узнаю что-то новое) инструмент
                                    0
                                    A license for one PC workstation is $389
                                    Найти б 389 баксов или хорошую крякалку… Но, по-моему, в этой области мало самоотверженных людей, доводящих хорошие продукты до потребителя.
                                    0
                                    Тут есть Rational Software Analyzer в триале
                                    www14.software.ibm.com/webapp/download/search.jsp?pn=Rational+Software+Analyzer
                                    с интерфейсом Eclipse для различных Linux и Windows
                                    Тут о нем кратко написано
                                    www-01.ibm.com/software/awdtools/swanalyzer/developer/support/
                                    (Enterprise редакция в основном дает возможность автоматического запуска стат. анализа)
                                    А тут — полная документация он-лайн
                                    www-01.ibm.com/support/docview.wss?rs=3352&uid=swg27012920
                                      0
                                      Вы не подскажите как сказать gcc, чтоб он выводил warring-и связанные только с моим кодом?
                                        0
                                        Вы не могли бы переформулировать вопрос? Просто не очень понятно, как узнать, где ваш код, а где нет.
                                          0
                                          Ну допустим, я использую Qt и gcc начинает ругаться на его библиотеки. Возможно ли указать ему чтоб он не выводил warring-и связанные с Qt?

                                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                      Самое читаемое