В очередной раз анализатор PVS-Studio оказался внимательнее человека
Изучая предупреждения анализатора PVS-Studio в процессе проверки различных открытых проектов, мы вновь и вновь убеждаемся, сколь полезен может быть этот инструмент. Анализатор кода невероятно внимателен и никогда не устаёт. Он указывает на ошибки, которые ускользают даже при внимательном обзоре кода. Рассмотрим очередной такой случай.
В предыдущий раз я написал аналогичную заметку, изучая исходный код проекта StarEngine: 2D Game Engine. Теперь анализатор показал своё превосходство надо мной в ходе проверки фреймворка Qt.
Прошло много времени, проект изменился, а в анализаторе PVS-Studio появилось много новых диагностик. Последний раз мы проверяли фреймворк Qt в 2014 году. Значит, вполне можно написать очередную статью, чем я и занялся.
Выписывая интересные примеры ошибок, я повстречал вот такой код:
QWindowsCursor::CursorState QWindowsCursor::cursorState()
; CURSORINFO cursorInfo; cursorInfo.cbSize = sizeof(CURSORINFO); if (GetCursorInfo(&cursorInfo)) { if (cursorInfo.flags & CursorShowing) // <= V616 ....
}
Для этого кода PVS-Studio выдал предупреждение:
qwindowscursor.cpp 669 V616 CWE-480 The 'CursorShowing' named constant with the value of 0 is used in the bitwise operation.
«Эх, что-то мы сломали в механизмах обработки неименованных перечислений», — вздохнул я, и выписал этот случай в багтрекер как ошибку, приводящую к ложному срабатыванию. Для проверки использовалась нестабильная версия PVS-Studio, поэтому моя вера в анализатор дрогнула.
Ведь всего несколькими строчками выше написано, что константа CursorShowing равна 1. Я был абсолютно уверен, что ошибается именно анализатор.
Я несколько раз просмотрел код, чтобы убедиться, что анализатор неправ. При этом я старался быть внимательным! Я оформил этот фрагмент кода и соответствующее сообщение как ошибку в багтрекере.
Прав именно анализатор, а не человек. Я провёл внимательный обзор этого маленького участка кода и всё равно облажался.
Разница только в первой букве! При подробном изучении ситуации выяснилось, что выше объявляется именованная константа cursorShowing, а в условии используется константа CursorShowing. В одном месте она строчная, а в другом прописная.
Потому, что константа CursorShowing тоже существует. Почему код компилируется? Вот её объявление:
class QWindowsCursor : public QPlatformCursor
{
public: enum CursorState { CursorShowing, CursorHidden, CursorSuppressed }; ....
}
Как видите, константа CursorShowing равна 0. Поэтому анализатор PVS-Studio абсолютно прав, сообщая, что условие (cursorInfo.flags & CursorShowing) не имеет смысла. Условие является всегда ложным.
Любите статический анализ кода! Анализатор нашёл замечательную опечатку. 🙂
Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Andrey Karpov. Once again the PVS-Studio analyzer has proved to be more attentive than a person.