Продолжаем серию маленьких заметок про то, как анализатор PVS-Studio может быстро находить новые ошибки в коде. При условии, конечно, что он регулярно используется :). Итак, перед нами очередной баг в проекте Blender.
Ради развлечения я мониторю проект Blender. Каждый день мне приходит отчёт PVS-Studio с предупреждениями, относящимися к новому коду. Иногда какая-то ошибка мне нравится, и я пишу про неё. Именно этим я занимаюсь и сейчас :).
На предыдущие статьи я ссылки давать не буду, так как они однотипны. Этими статьями я демонстрирую, что если регулярно использовать статический анализатор, то многие баги можно обнаружить очень быстро. А чем раньше ошибка найдена, тем дешевле её исправление.
В этот раз моё внимание привлекло два предупреждения PVS-Studio, указывающих на одну строчку кода:
Это нормально. Одна аномалия в коде может быть подозрительна с точки зрения разных диагностических правил. Перед нами как раз такой случай:
if (is_object_active && !(base->object->mode & OB_MODE_OBJECT)) {
Если вы прочитали сообщения анализатора, то, думаю, уже догадались, в чём дело. Однако если просто смотреть на этот код, то он кажется совершенно нормальным. Скажем так, эта строчка может не вызвать ни у кого подозрения в процессе обзора кода.
Чтобы понять, что код неверен, нужно посмотреть, как объявлена именованная константа в перечислении eObjectMode:
typedef enum eObjectMode {
OB_MODE_OBJECT = 0,
OB_MODE_EDIT = 1 << 0,
OB_MODE_SCULPT = 1 << 1,
OB_MODE_VERTEX_PAINT = 1 << 2,
OB_MODE_WEIGHT_PAINT = 1 << 3,
OB_MODE_TEXTURE_PAINT = 1 << 4,
OB_MODE_PARTICLE_EDIT = 1 << 5,
OB_MODE_POSE = 1 << 6,
OB_MODE_EDIT_GPENCIL = 1 << 7,
OB_MODE_PAINT_GPENCIL = 1 << 8,
OB_MODE_SCULPT_GPENCIL = 1 << 9,
OB_MODE_WEIGHT_GPENCIL = 1 << 10,
OB_MODE_VERTEX_GPENCIL = 1 << 11,
} eObjectMode;
Итак, константа OB_MODE_OBJECT равна нулю! Ещё раз взглянем на условие:
if (is_object_active && !(base->object->mode & OB_MODE_OBJECT)) {
Получается, что результат операции "побитовый И" (&) всегда равен 0. Про это первое сообщение анализатора.
Применим к 0 оператор "!", и получается, что перед нами выражение:
if (is_object_active && true) {
Про то, что часть выражения всегда истинна, нам говорит уже второе предупреждение PVS-Studio.
Скорее всего, правильным вариантом будет:
if (is_object_active && base->object->mode != OB_MODE_OBJECT) {
Впрочем, я не уверен, так как не разбираюсь в исходном коде Blender. Задача анализатора – указать на ошибку, а что с ней делать, должен решать уже разработчик проекта.
Спасибо за внимание и подписывайтесь на мой Twitter: @Code_Analysis.
Дополнительные ссылки: