Анализируем исходный код с помощью cppcheck

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

Совсем недавно cppcheck помог найти уязвимость в проекте Xorg, которая существовала там почти 23 года! Он помог уже тысячам программистов по всему миру, на официальном сайте можно найти информацию о найденных с помощью cppcheck уязвимостях в программах, и этот список постоянно растёт. Итак, если вы хотите знать, почему нужно использовать cppcheck всегда и везде — прошу под кат.

CppCat и cppcheck


Начну со сравнения этих утилит, поскольку данная просьба озвучивалась неоднократно в комментариях. Разработчики CppCat уже самостоятельно провели такое сравнение (с PVS-Studio), но с тех пор утекло много воды, а сравнение не очень объективно, так как PVS-Studio (насколько я понимаю всю замысловатость фразы «Please write us to get a price for PVS-Studio. Please specify interesting license type.») не предназначена для программистов-одиночек. CppCat же, как и cppcheck, доступен каждому (с оговоркой на привязку к VisualStudio определённых версий и лицензию на год).

Сравнить эти анализаторы будет непросто: у меня не имеется под руками ни одной версии Visual Studio под Linux. Поэтому сначала я ограничусь анализом уже проанализированного кода в недавнем обзоре CppCat: натравлю cppcheck на Notepad++, приведу статистику ошибок/предупреждений, которые можно будет сравнить с уже готовым анализом CppCat.

Параллельно пробую поставить в виртуальной машине CppCat. Надо сказать, что после того как Visual Studio 2010 был установлен, инсталлятор недолго думая выдал следующее:

image

Из-за чего тестирование усложнилось квестом найди-поставь-Visual-Studio-2013-переустанови-IE-11-перезагрузись-обновись, что на виртуалке, не обременённой обновлениями, заняло ровно полдня.

Что в итоге? При открытии проекта Notepad++ Visual Studio гордо завис. Попытка создать новый проект привела к тому, что в анализе CppCat посыпались ошибки о не найденных заголовочных файлах. По сему сравнивать придётся с тем, что имеем в предыдущей статье. Хотя Visual Studio я ставлю практически в первый раз, но эффект «юзабилити» налицо.

Подготовка

Так как cppcheck — проект с открытым исходным кодом, никто не мешает загрузить самую свежую версию из гита и скомпилировать её самостоятельно. Cppcheck предназначен для разработчиков, поэтому компиляция программы из исходного кода не должна вызывать каких-либо проблем:
unzip cppcheck-master.zip
cd cppcheck-master
make

Готово. Я специально взял свежую версию из гита и положил её в отдельную папку — с ней будет проще работать, так как в дальнейшем cppcheck можно сильно улучшить и настроить «под себя».

Тестовая конфигурация: RHEL 6.1, процессор i5-2400 @ 3.10GHz (для оценки времени работы анализатора).

Удобства ради действия будут производится в командной строке — при желании их можно будет повторить (в Linux:). Конечно, cppcheck имеет несколько плагинов для популярных IDE, но сегодня не об этом.

Анализ Notepad++

cppcheck устроен так, что все предупреждения отсортированы по категориям. По умолчанию включён только один вид анализа — error (ошибки). Ошибки нельзя игнорировать, так как если cppcheck выдал error — это место придётся переписывать в 99% случаев. Основной улов cppcheck — утечки памяти и переполнение буфера, а это уже чего-то стоит.

Может возникнуть резонный вопрос — как анализировать notepad++ в операционной системе Linux, если notepad++ использует исключительно WInAPI? Ответ прост — cppcheck на моей памяти единственный анализатор, который не привязан к сборочной среде или операционной системе. Он использует свой лексический анализатор, не требует обязательного присутствия всех заголовочных файлов, лояльно относится к хитросплетениям классов и т. п. Это замечательное свойство позволяет использовать cppcheck где угодно и для чего угодно, чего не скажешь о CppCat (см. квест по установке выше).

Анализ с помощью cppcheck прост до безобразия:
./cppcheck-master/cppcheck -q -j4 npp.6.5.3.src/

Пока проводится простейший анализ «из коробки». Команда определяет два параметра -q («тихий» режим — не выводить прогресс выполнения на экран) и -j4 — многопоточный анализ в 4 потока по количесву ядер процессора.

Результат выполнения предыдущей команды:
[npp.6.5.3.src/PowerEditor/src/tools/ChangeIcon/ChangeIcon.cpp:214]: (error) Mismatching allocation and deallocation: resData
[npp.6.5.3.src/PowerEditor/src/tools/ChangeIcon/ChangeIcon.cpp:216]: (error) Mismatching allocation and deallocation: resData
[npp.6.5.3.src/scintilla/lexers/LexBash.cxx] -> [npp.6.5.3.src/scintilla/lexers/LexBash.cxx:194]: (error) Internal error. Token::Match called with varid 0. Please report this to Cppcheck developers

Время работы — 5 минут. В глаза сразу бросается ошибка "(error) Internal error. Token::Match called with varid 0. Please report this to Cppcheck developers". Это означает, что вместо бага в анализируемой программе нашёлся баг в самом анализаторе:) Сделаем скидку на то, что проект заточен под Win, и cppcheck не подозревает, что означают DWORD, LPTR и т. п. Возможно, в Win он покажет себя иначе.

Реально нашлась всего одна ошибка (с разницей в 2 строчки). Неплохо, возможно, что автор notepad++ сам пользуется cppcheck. Участок кода, который вызвал у cppcheck подозрение:

	BYTE* resData = new BYTE[cbRes];
	LPBYTE writePtr = resData;
...
	if(!UpdateResource(hUpdate, RT_GROUP_ICON, lpResName, resLangId, resData, cbRes)) { _tprintf(_T("Unable to update icon group\n")); delete resData; return false; }
	IFDEBUG( _tprintf(_T("Updated group %d (lang %d)\n"), lpResName, resLangId); )
	delete resData;
	}


Это выглядит как ложное срабатывание, хотя исходники, честно говоря, шокируют. UPD: это всё-таки undefined behaviour, массив нужно освобождать с помощью оператора delete [].

Но это ещё не всё. Дело в том, что девизом cppcheck является отсутствие ложных срабатываний, то есть по умолчанию сканер ищет только очень критические ошибки — переполнение буфера, утечки памяти. После того как все ошибки найдены, можно просканировать повторно, включив флаги предупреждений:

./cppcheck-master/cppcheck -q -j4 --enable=performance,portability,warning,style npp.6.5.3.src/ 2> npp.out


Используется параметр --enable, который включает категории проверок:

— performance — проблемы производительности;
— portability — проблемы совместимости;
— warning — предупреждения — подозрительные места программы;
— style — ошибки стиля программирования.

В таком режиме вылавливается львиная доля стилистических/логических ошибок и потенциальных багов (т. е. ошибки, в которых cppcheck «не уверен»). Время сканирования — 5 минут. Результат я сразу отправил в файл, чтобы собрать статистику.

Всего сообщений:
wc -l < npp.out
379


Небольшая статистика по типу найденных ошибок:
tr '()' '*' < npp.out | cut -d* -f2 | sort | uniq -c
      3 error
     39 performance
     14 portability
    211 style
    112 warning


Статистика по сообщениям
sort -t] -k2 npp.out | grep -v '(error)' | cut -d\) -f2- | sed "s/'[^']*'/%{VAR}/g" | sort | uniq -c | sort -n
      1  Function parameter %{VAR} should be passed by reference.
      1  memset() called to fill 0 bytes of %{VAR}.
      1  scanf without field width limits can crash with huge input data.
      1  The class %{VAR} does not have a constructor.
      1  Unused variable: ent
      1  Unused variable: loc
      2  Array index %{VAR} is used before limits check.
      2  Checking if unsigned variable %{VAR} is less than zero.
      2  Found duplicate branches for %{VAR} and %{VAR}.
      2  The class %{VAR} defines member variable with name %{VAR} also defined in its parent class %{VAR}.
      2  Unsigned variable %{VAR} can't be negative so it is unnecessary to test it.
      2  %{VAR} should return %{VAR}.
      3  scanf without field width limits can crash with huge input data on some versions of libc.
      4  Same expression on both sides of %{VAR}.
      4  %{VAR} does not have a copy constructor which is recommended since the class contains a pointer to allocated memory.
      5  Assignment of function parameter has no effect outside the function.
      5  Ineffective call of function %{VAR}. Did you intend to call %{VAR} instead?
      7  Consecutive return, break, continue, goto or throw statements are unnecessary.
     11  Exception should be caught by reference.
     11  The extra qualification %{VAR} is unnecessary and is considered an error by many compilers.
     12  Variable %{VAR} is reassigned a value before the old one has been used.
     22  Variable %{VAR} is assigned a value that is never used.
     26  Variable %{VAR} is assigned in constructor body. Consider performing initialization in initialization list.
     42  C-style pointer casting
     98  Member variable %{VAR} is not initialized in the constructor.
    108  The scope of the variable %{VAR} can be reduced.



Всего 28 уникальных сообщений.

Сообщения «The scope of the variable %{VAR} can be reduced», «C-style pointer casting», «Variable %{VAR} is assigned in constructor body.» можно не рассматривать — это стилистические рекомендации, очень характерные для многих проектов, написанных на старых плюсах.

Море переменных не инициализировано в конструкторе: (warning) Member variable %{VAR} is not initialized in the constructor. Это ошибку cppcheck считает предупреждением. Возможно, поведение такого кода зависит от компилятора, потому что npp каким-то чудом работает.

Пример
//[npp.6.5.3.src/PowerEditor/src/WinControls/AnsiCharPanel/ansiCharPanel.h:46]: (warning) Member variable 'AnsiCharPanel::_ppEditView' is not initialized in the constructor.
class AnsiCharPanel : public DockingDlgInterface {
public:
	AnsiCharPanel(): DockingDlgInterface(IDD_ANSIASCII_PANEL) {};

	void init(HINSTANCE hInst, HWND hPere, ScintillaEditView **ppEditView) {
		DockingDlgInterface::init(hInst, hPere);
		_ppEditView = ppEditView;
	};

    virtual void display(bool toShow = true) const {
        DockingDlgInterface::display(toShow);
    };

    void setParent(HWND parent2set){
        _hParent = parent2set;
    };

	void switchEncoding();
	void insertChar(unsigned char char2insert) const;

protected:
	virtual BOOL CALLBACK AnsiCharPanel::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam);

private:
	ScintillaEditView **_ppEditView;
	ListView _listView;
};

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


(style) Same expression on both sides of '||'. Проверка одного и того же условия. Эту же ошибку выдавал CppCat, однако то ли в той статье версия npp старая, то ли ошибку уже пофиксили, но сейчас тот самый код выглядит так:
while (closeFound.success && (styleAt == SCE_H_DOUBLESTRING || styleAt == SCE_H_SINGLESTRING) && searchStartPoint <= caret);


А это — новая добыча cppcheck:

if (!(!commentLineSybol || !commentLineSybol[0] || commentLineSybol == NULL))


(performance) Variable 'lineIndent' is reassigned a value before the old one has been used. По сути — двойное присваивание. Обычно это следствие копипасты, но cppckeck характеризует такую ошибку как ошибку производительности. Этот код стоит проверить, так как неизвестно, что подразумевал автор программы. Таких двойных присваиваний, а также неиспользуемых значений переменных по коду очень много:

        int lineIndent = lineStart;
...
        lineIndent = _pEditView->execute(SCI_GETLINEINDENTPOSITION, i);
		_pEditView->getGenericText(linebuf, linebufferSize, lineIndent, lineEnd);


Это предупреждение обычно бесполезно — редко, когда в данном участке кода есть ошибка, просто при рефакторинге забыли удалить старое значение.

(portability) The extra qualification 'FunctionListPanel::' is unnecessary and is considered an error by many compilers. Полезное предупреждение, которого физически нет и не планируется в CppCat: ошибки переносимости между разными платформами (portability). Данный кусок кода будет работать не во всех компиляторах:

virtual BOOL CALLBACK FunctionListPanel::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam);


Это «политкорректное» сообщение на самом деле означает, что код не соберётся без костылей в компиляторе gcc. Если вы планируете запускать приложение больше чем на одной платформе — cppcheck станет хорошим подспорьем.

(style) Exception should be caught by reference. Интересное предупреждение — ловить исключение следует по ссылке, а не по значению:

        catch(std::exception e) {
		::MessageBoxA(NULL, e.what(), "Exception", MB_OK);
		return -1;
	}


(style) Consecutive return, break, continue, goto or throw statements are unnecessary. Мёртвый код: break после return:
		switch(lpnm->wID) {
			case REBAR_BAR_TOOLBAR: {
...
				return TRUE;
				break; }
		}

(warning) Assignment of function parameter has no effect outside the function. Обычно это полезное предупреждение, сигнализирующее об опечатке — значение, присвоенное внутри функции, никуда не передаётся. Однако здесь это очевидно ложное срабатывание, так как value — переменная класса:

void SetValue( const TCHAR* _value )	{ value = _value; }


(portability) scanf without field width limits can crash with huge input data on some versions of libc. Подобная привычка использования scanf может привести к опасному переполнению буфера. В случае числовых переменных это банальный undefined behaviour:

if ( sscanf( value.c_str(), "%d", ival ) == 1 )


Для преобразования чисел лучше использовать безопасный strtol.

Ещё один представитель:
sscanf( wordBuffer, "%[^.<>|&=\\/]", sKeywordBuffer );


Здесь нет переполнения буфера только потому, что wordBuffer и sKeywordBuffer одинакового размера.

(style) 'TiXmlStringA::operator=' should return 'TiXmlStringA &'. Оператор = возвращает void:

void operator = (const TiXmlStringA & copy);

С таким оператором нельзя использовать стандартную для C++ цепочку:
a = b = c;


(warning) The class 'ControlsTab' defines member variable with name '_isVertical' also defined in its parent class 'TabBar'. Ошибка двойного определения переменной в классе:
class ControlsTab : public TabBar
{
public :
...
private :
...
    bool _isVertical;
};

которая уже определена в родительском классе:
class TabBar : public Window
{
...
protected:
...
	bool _isVertical;
};

Не являясь экспертом в плюсах, не могу сразу ответить, можно ли так делать (protected/private).

(style) Found duplicate branches for 'if' and 'else'. Аналогичные ошибки нашёл и CppCat. Лишнее условие:
		if(eol_mode == SC_EOL_CRLF)
			extraEOLLength = 2;
		else if(eol_mode == SC_EOL_LF)
			extraEOLLength = 1;
		else // SC_EOL_CR
			extraEOLLength = 1;


(style) Checking if unsigned variable 'lenFile' is less than zero. Аналогичное сообщение выдавал CppCat за исключением того, что cppcheck, не обнаружив файла windows.h не стал строить гипотезы относительно типов вроде WPARAM. Недочёт неориентированности исключительно на Windows всё же есть.
		size_t lenFile = 0;
...
			if (lenFile <= 0) break;


Думаю, если бы у меня были заголовочные файлы винды, можно указать путь к ним через параметр -I, тогда ошибок будет значительно больше.

(style) Array index 'j' is used before limits check. Несмотря на то что предупреждение низкоприоритетное, найденная ошибка представляет опасность выхода за границы массива:
     int j;
     int ReturnValue;
     j=startcol;
     if(direction == 1){j++;}
     if(direction != 1){j--;}

     while((BGHS[SI].columnwidths[j] == 0)&&(j<=BGHS[SI].cols)&&(j>0))

Учитывая, что параметр startcol внешний, можно вылететь за границу массива, не говоря об индексе -1.

(style) Unsigned variable 'i' can't be negative so it is unnecessary to test it. Условие в цикле всегда положительно => бесконечный цикл:
for(unsigned int i = position_of_click; i >= 0; --i)

Этой ошибки можно было бы избежать при сборке проекта компилятором gcc и флагами -Wall -Wextra. Думаю, такая ошибка часто появляется при рефакторинге проекта по другой ошибке компилятора — несоответствие типов. Было int — стало unsigned, вот и результат.

Мелкие недочёты

(style) Unused variable: ent. Это предупреждение умеют выдавать и компиляторы, ничего интересного.

(warning) %d in format string (no. 2) requires 'int' but the argument type is 'DWORD {aka unsigned long}' — очень популярная ошибка, программисты в printf пишут тип, не соответствующий типу переменной. Это тоже отстреливается большинством компиляторов.

Класс без конструктора:
	class CachedValue
	{
		generic_string fullname;
		int index;
	};


(performance) Function parameter 'range' should be passed by reference. cppcheck рекомендует передавать параметр по ссылке, чтобы избежать копирования аргумента:
XYScrollPosition XYScrollToMakeVisible(const SelectionRange range, const XYScrollOptions options);


(warning) Ineffective call of function 'empty()'. Did you intend to call 'clear()' instead? Метод empty имеет смысл только внутри условия и не очищает строку. Это ложное срабатывание, cppcheck не подозревал, что автор сделает свой класс String:) Следует проверить логику именования методов.

(style) 'class ByteArray' does not have a copy constructor which is recommended since the class contains a pointer to allocated memory. cppcheck просто рекомендует создать в классе отсутствующий конструктор копирования на случай, если программист забыл его реализовать.

Вывод


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

Из этого анализа можно сделать вывод, что инструменты хорошо друг друга дополняют. Для кого-то главным минусом cppcheck является отсутствие плагина под Visual Studio, поэтому авторы cppcheck любезно предлагают попробовать PVS-Studio. Несмотря на интерфейс командной строки, пользоваться cppcheck очень удобно. Не требуется ни компилятора, ни IDE, ни заголовочных файлов — это самый простой в использовании статический анализатор, который я только видел. Кроме того, я специально поставил в виртуальной машине сборку cppcheck для Windows — она имеет приятный графический интерфейс, устанавливается быстро и без проблем выполняет анализ:

image

Результат анализа можно экспортировать в XML и смотреть в браузере.

Обоим проектам стоит пожелать успехов в развитии — это действительно очень нужные программы. А в развитии cppcheck вы можете принять участие самостоятельно прямо сейчас: проверяйте свои проекты, пишите разработчику cppcheck о найденных или не найденных ошибках, сообщайте о багах, присылайте полезные патчи на гитхаб. Если ещё недавно cppcheck не мог найти ошибку if(malloc()), то сейчас просто сыпет сообщениями об утечках памяти — результат конкуренции налицо.

Данный анализ можно было бы сильно улучшить, если явно указать cppcheck, где искать заголовочные файлы, какие функции выделяют и освобождают память. Так как статья получилась большой, про то, как настроить cppcheck под конкретный проект, улучшить качество анализа и писать свои правила для cppcheck — в следующий раз.

P. S. Прошу простить одну глупость. Cppcheck имеет в настройках возможность анализировать код специально для Windows, из-за чего очень много интересных ошибок было пропущено. Нужно было анализировать npp с флагом --platform=win32A.
Share post

Similar posts

AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 27

    –41
    Взяли Феррари (это я из скромности). По пустыне — не едет! В сугробе — застревает. А если кабриолет, то еще и с зонтом ехать надо, чтобы голову не намочить. Говно, а не машина!
      –20
      Поясню чуть более подробно :-).

      CppCat предназначен для тех, кто использует в своей работе Visual Studio. Если вы не используете эту среду, то CppCat не лучший выбор, скажем честно.

      Так вот, если вы разрабатываете свой софт в Visual Studio, то вы просто устанавливаете продукт и все работает само.

      Приведенное в статье описание ситуации по установке и запуску в виртуальной машине говорит о том, что Вы что-то делаете не так. Например, сообщение о том, что Visual Studio не найдено означает, что Вы не устанавливали эту среду. А как-то то ли скопировали ее, то ли еще что-то. Проблемы с компиляцией, упомянутые в статье, свидетельствуют об этом же.

      В результате хорошая идея сравнения с CppCheck, которое можно только всячески приветствовать, вылилась в описание крайне некорректного запуска.
        +5
        от чего же, вполне объективно всё описано.
        • UFO just landed and posted this here
            +4
            Сообщение о не найденной Visual Studio обозначает что вы её установили, но ни разу не запускали. На этом много народу погорело: вроде как использовали продукт уже много раз, начали настраивать buildbot — а оно «в упор не видит» Visual Studio. Что делать? Обычно достаточно просто запустить Visual Studio хотя бы раз, хотя иногда это и не помогает.
              +1
              Шаманство какое-то…
                +7
                Причем тут шаманство? Microsoft же :)
          +4
          Спасибо за статью!
          Хочу остановиться на двух моментах.

          1) Я уже писал к предыдущей статье комментарий, что Notepad++ не очень удачный проект для сравнений. Напомню:

          Надо учитывать, что многие из ошибок, могли бы быть обнаружены в Notepad++ с помощью CppCat, если бы не PVS-Studio. Мы уже два раза проверяли этот проект:

          И действительно, они вроде как исправлены. Это значит, что CppCat мог бы показать себя намного лучше.
          С другой стороны, так как Notepad++ очень известный проект, он уже мог быть не раз проверен и анализатором Cppcheck. И тогда он тоже в нечестном проигрыше.

          В общем, Notepad++ — неудачный полигон для сравнений.

          2)
          Надо сказать, что после того как Visual Studio 2010 был установлен, инсталлятор недолго думая выдал следующее

          Вы Visual Studio 2010 через копирование что ли устанавливали?
            +5
            1) Я действительно думал над тем, что лучше взять для сравнения — npp или что-то, что заранее дырявое и ранее ничем не проверялось (хорошим примером мог стать X86 старых версий, но как завести его под VS для меня лично загадка века). В итоге это заняло больше времени, чем планировалось, и так уж сложилось, что VS «не взлетела». Но всё равно акцент в статье сделан на обзор cppcheck и пример работы с данным инструментом, так как подобных статей ранее не было. Цель не в сравнении, кто лучше, а в том, чтобы стимулировать разработчиков пользоваться анализаторами. Далее, читатель при желании сам сможет проверить оба анализатора в действии.

            2) Я скачал её с сайта Microsoft, ставил инсталлятором. И ожидал хотя бы сообщения, что у меня неправильная версия студии, могу дать информацию о баге, но это уже лучше в PM. Похоже, надо было с трекера качать:) Думаю, пользователь CodeBlocks столкнулся бы с теми же проблемами, если бы хотел просто «поиграться» с триалкой. 2010 ставил, чтобы не загружать объёмную 2013, а 2013 в свою очередь отказался грузить проект с npp из-за несовместимости версий.
              +2
              Я не понимаю, почему Вы называете VS2013 объемной. Дистрибутивы 2010 и 2013 одинаковые. Может Вы express-версию пробовали?
                +1
                Очень вероятно, что express. Я в них не сильно разбираюсь:) А есть разница?
                  0
                  Express версии не поддерживают расширения. И как следствие, работа CppCat/PVS-Studio невозможна.
                    +6
                    Вот это поворот. Тогда понятно, в чём дело, но сообщение об ошибке могло бы быть более информативным. Попробую тогда найти нормальную версию, если получится натравить анализатор на ядро Linux Xorg — попробую сделать сравнение:) Это самый убитый OpenSource проект из которых мне довелось держать в руках. Можно специально взять старую версию 2005 года, когда никаких анализаторов ещё не было.
                      –2
                      Лучше не надо. Если хочется извращений, возьмите PVS-Studio Stand Alone. Не издевайтесь над CppCat. :)
                        0
                        Так на странице CppCat написано, что Visual Studio Express не поддерживается. Вы что, не читали?
                          +4
                          На cppcat.com фраза «Visual Studio Express is not supported» не находится даже поиском. Не все же разбираются в сортах Visual Studio.
                          • UFO just landed and posted this here
                              0
                              Так инсталлятор явно писал, что поддерживаемые версии не найдены. Понятно, что улучшить сообщение стоит.
              +2
              Пятница. В Хабре тишина и покой. Так что я думаю, никому не помешаю, если ещё пофилософствую. :)

              В статье приводится ссылка на примеры ошибок, обнаруженных в различных проектах. Я хотел напомнить, что у нас тоже есть аналогичная база. И мы ей очень гордимся. Дело в том, что примеры выписываются вручную и редактируются, чтобы они были коротким и понятными. Это базу можно использовать для изучения типовых опечаток и выработки каких-то рекомендаций, разработке стандартов кодирования и т.д.

              PVS-Studio насколько я понимаю всю замысловатость фразы «Please write us to get a price for PVS-Studio. Please specify interesting license type.» не предназначена для программистов-одиночек.

              На самом деле, это была попытка работать с небольшими командами (история вопроса). А так да, для одиночных пользователей теперь есть CppCat.

              Море переменных не инициализировано в конструкторе: (warning) Member variable %{VAR} is not initialized in the constructor. Это ошибку cppcheck считает предупреждением. Возможно, поведение такого кода зависит от компилятора, потому что npp каким-то чудом работает.

              На самом деле, неинициализированные переменные в конструкторе, это очень даже часто не ошибки. Часто, это отложенная инициализация или оптимизация (не надо заполнять сразу все поля). А поведение компилятора тут ни причём. Если не читать неинициализированную переменную, то и беды не будет. Так что это конечно Warning, причём не очень сильный. Мы пока не хотим его делать в PVS-Studio/CppCat. Вреда от ложных срабатываний будет больше, чем пользы он найденных ошибок. Вот и вы пишите «море переменных не инициализировано». В этом море можно утонуть и не заметить настоящих бед. :)

              (style) Unsigned variable 'i' can't be negative so it is unnecessary to test it. Довольно мелкая придирка:
              for(unsigned int i = position_of_click; i >= 0; --i)

              А вот тут не понятно. Какой же это «style». Это полновесная ошибка. И CppCat тоже должен был её тоже заметить. Беззнаковая переменная всегда будет >= 0. Мы такие ошибки любим.
                +5
                Это базу можно использовать для изучения типовых опечаток и выработки каких-то рекомендаций, разработке стандартов кодирования и т.д.

                Этим уже давно активно занимается CERT:
                www.securecoding.cert.org/confluence/pages/viewpage.action?pageId=637
                Кстати, у них ещё есть база анализаторов с галочками, какие анализаторы какие ошибки умеют вылавливать. Интересное чтиво для разработчиков в целом и разработчиков инструментов анализа в частности.

                А поведение компилятора тут ни причём. Если не читать неинициализированную переменную, то и беды не будет.

                За такие дела, ЕМНИП, cppcheck влепит жирный error, трудно будет не заметить. В этом их философия — скрывать по умолчанию сообщения, в которых анализатор «не уверен».

                for(unsigned int i = position_of_click; i >= 0; --i)

                Моя неправда. Полноценный бесконечный цикл:)

                P. S. Удивился, когда узнал, что Notepad++ собирается с полным арсеналом ворнингов. clang и gcc очень активно ругаются на несоответствие типов и неиспользуемые переменные.
                  +13
                  я специально поставил в виртуальной машине сборку cppcheck для Windows — она имеет приятный графический интерфейс

                  Линуксовый cppcheck-gui имеет точно такой же интерфейс, один в один (ибо Qt) :-)
                    0
                    А удобная, оказывается, штука
                      0
                      Жалко, что cppcheck не сможет обработать исходники Qt программ, а только после обработки через moc, что усложняет анализ в разы.
                        0
                        В cppcheck недавно добавили поддержку библиотек, включая Qt, что теоретически даёт возможность анализа без препроцессинга. В следующей статье я как раз расскажу, как этим пользоваться. Я не уверен, что поддержка Qt там стопроцентная, но она есть.
                      0
                      CppCheck можно подключить к студии как внешний инструмент. Там есть флажок --template=vs как раз для форматирования вывода под студию. Работает с любой версией начиная с шестой.
                        0
                        Разработчики CppCat уже самостоятельно провели такое сравнение (с PVS-Studio), но с тех пор утекло много воды, а сравнение не очень объективно, так как PVS-Studio не предназначена для программистов-одиночек.

                        Обновлённое сравнение: habrahabr.ru/company/pvs-studio/blog/215469/

                        Only users with full accounts can post comments. Log in, please.