to the top
close form
Для получения триального ключа
заполните форму ниже
Team license
Enterprise license
** Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Запросите информацию о ценах
Новая лицензия
Продление лицензии
--Выберите валюту--
USD
EUR
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Бесплатная лицензия PVS-Studio для специалистов Microsoft MVP
** Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Для получения лицензии для вашего открытого
проекта заполните, пожалуйста, эту форму
** Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Мне интересно попробовать плагин на:
** Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
check circle
Ваше сообщение отправлено.

Мы ответим вам на


Если вы так и не получили ответ, пожалуйста, проверьте папку
Spam/Junk и нажмите на письме кнопку "Не спам".
Так Вы не пропустите ответы от нашей команды.

>
>
>
Как PVS-Studio оказался внимательнее, ч…

Как PVS-Studio оказался внимательнее, чем три с половиной программиста

22 Окт 2018

PVS-Studio, как и другие статические анализаторы кода, часто выдаёт ложные срабатывания. Но не стоит спешить считать странные срабатывания ложными. Это короткая история о том, как PVS-Studio вновь оказался внимательнее нескольких человек.

0587_PVS_Studio_and_3_5_programmers_ru/image1.png

Нам в поддержку написал пользователь, утверждая, что анализатор выдаёт сразу четыре ложных срабатывания на одну строчку кода. Письмо, написанное в поддержку, изначально попало к Евгению Рыжкову, который, бегло прочитав его и не заметив аномального в фидбеке, сразу переслал его ведущему разработчику Святославу Размыслову. Евгений не всматривался в код, так что будет честно посчитать его только за половину программиста :).

Святослав прочитал письмо и засомневался, что анализатор мог так грубо ошибиться. Поэтому он пришёл ко мне на консультацию. У Святослава была надежда, что мой глаз намётан и я замечу что-то такое, что подскажет, почему анализатор выдал все эти странные сообщения. К сожалению, я только подтвердил, что сообщения действительно очень странные и их не должно быть. Однако что же послужило причиной их возникновения, я заметить не смог. Было решено открыть задачу в багтрекере и начать разбираться, что же не так.

И только когда Святослав начал делать синтетические примеры, чтобы подробно расписать проблему в багтрекере, на него снизошло озарение. Давайте теперь посмотрим, сможете ли вы быстро найти причину, почему анализатор выдаёт 4 сообщения.

Вот текст письма, публикуемый с разрешения автора. И поясняющая картинка, которая была прикреплена к письму.

V560 warnings here are all false. Running with most recent version of PVS-Studio for personal use. Basically, "IF" statement is correct. Outer one is done for speed - inner ones are still needed and non are always true or false.

0587_PVS_Studio_and_3_5_programmers_ru/image2.png

Нажмите на картинку для увеличения.

Теперь, уважаемый читатель, ваше время проверить себя! Видите ошибку?

Ваше время проявить внимательность. А единорог пока немного подождёт.

0587_PVS_Studio_and_3_5_programmers_ru/image4.png

После вводной части статьи, скорее всего многие нашли ошибку. Когда настроен найти ошибку, она находится. Намного сложнее заметить ляп после прочтения письма, где это называется "ложными срабатываниями" :).

Теперь пояснение для тех, кто поленился искать баг. Ещё раз рассмотрим условие:

if (!((ch >= 0x0FF10) && (ch <= 0x0FF19)) ||
     ((ch >= 0x0FF21) && (ch <= 0x0FF3A)) ||
     ((ch >= 0x0FF41) && (ch <= 0x0FF5A)))

Автор кода планировал проверить, что символ не входит ни в один из трёх диапазонов.

Ошибка в том, что оператор логический NOT (!) применяется только к первому подвыражению.

Если выполнилось условие

!((ch >= 0x0FF10) && (ch <= 0x0FF19))

то вычисление выражения прерывается согласно short-circuit evaluation. Если условие не выполняется, то значение переменной ch лежит в диапазоне [0xFF10..0xFF19]. Соответственно, четыре дальнейших сравнения не имеют смысла. Все они будут ложными или истинными.

Ещё раз. Смотрите, если ch лежит в диапазоне [0xFF10..0xFF19] и продолжается вычисление выражения, то:

  • ch >= 0x0FF21 - всегда false
  • ch <= 0x0FF3A - всегда true
  • ch >= 0x0FF41 - всегда false
  • ch <= 0x0FF5A - всегда true

Об этом и предупреждает анализатор PVS-Studio.

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

Чтобы исправить ситуацию, надо добавить дополнительные скобки:

if (!(((ch >= 0x0FF10) && (ch <= 0x0FF19)) ||
      ((ch >= 0x0FF21) && (ch <= 0x0FF3A)) ||
      ((ch >= 0x0FF41) && (ch <= 0x0FF5A))))

Или переписать условие:

if (((ch < 0x0FF10) || (ch > 0x0FF19)) &&
    ((ch < 0x0FF21) || (ch > 0x0FF3A)) &&
    ((ch < 0x0FF41) || (ch > 0x0FF5A)))

Впрочем, я не могу рекомендовать к использованию ни один из этих вариантов. Я бы для упрощения чтения кода написал так:

const bool isLetterOrDigit =    (ch >= 0x0FF10 && ch <= 0x0FF19)  // 0..9
                             || (ch >= 0x0FF21 && ch <= 0x0FF3A)  // A..Z
                             || (ch >= 0x0FF41 && ch <= 0x0FF5A); // a..z
if (!isLetterOrDigit)

Обратите внимание, что я убрал часть скобок. Как только что мы видели, большое количество скобок вовсе не помогло избежать ошибки. Скобки должны облегчать чтение кода, а не усложнять. Программисты хорошо помнят, что приоритет сравнений =<, => выше, чем у оператора &&. Поэтому здесь скобки не нужны. А вот если спросить, что приоритетней - && или ||, многие растеряются. Поэтому для задания последовательности вычислений &&, || скобки лучше поставить.

Почему лучше писать || в начале я описывал в статье "Главный вопрос программирования, рефакторинга и всего такого" (см. главу: Выравнивайте однотипный код "таблицей").

Всем спасибо за внимание. Скачивайте и начинайте использовать PVS-Studio. Он поможет выявлять многие ошибки и потенциальные уязвимости на самых ранних этапах.

Популярные статьи по теме
Под капотом SAST: как инструменты анализа кода ищут дефекты безопасности

Дата: 26 Янв 2023

Автор: Сергей Васильев

Сегодня речь о том, как SAST-решения ищут дефекты безопасности. Расскажу, как разные подходы к поиску потенциальных уязвимостей дополняют друг друга, зачем нужен каждый из них и как теория ложится на…
Ложные представления программистов о неопределённом поведении

Дата: 17 Янв 2023

Автор: Гость

Неопределённое поведение (UB) – непростая концепция в языках программирования и компиляторах. Я слышал много заблуждений в том, что гарантирует компилятор при наличии UB. Это печально, но неудивитель…
Топ-10 ошибок в C++ проектах за 2022 год

Дата: 29 Дек 2022

Автор: Владислав Столяров

Дело идёт к Новому году, а значит, самое время традиционно вспомнить десять самых интересных срабатываний, которые нашёл PVS-Studio в 2022 году.
PVS-Studio и RPCS3: лучшие предупреждения в один клик

Дата: 12 Дек 2022

Автор: Александр Куренев

Best Warnings — режим анализатора, оставляющий в окне вывода 10 лучших предупреждений. Мы предлагаем вам ознакомиться с обновлённым режимом Best Warnings на примере проверки проекта RPCS3.
Holy C++

Дата: 23 Ноя 2022

Автор: Гость

В этой статье постараюсь затронуть все вещи, которые можно без зазрения совести выкинуть из С++, не потеряв ничего (кроме боли), уменьшить стандарт, нагрузку на создателей компиляторов, студентов, из…

Комментарии (0)

Следующие комментарии next comments
close comment form
Unicorn with delicious cookie
Мы используем куки, чтобы пользоваться сайтом было удобно.
Хорошо