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

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

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

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

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

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

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


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

>
>
>
Как PVS-Studio защищает от поспешных пр…

Как PVS-Studio защищает от поспешных правок кода, пример N4

18 Фев 2022

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

0924_Blender_prevents_rash_code_changes_N4_ru/image1.png

Думал сделать перерыв в серии маленьких заметок про то, как анализатор PVS-Studio оперативно находит ошибки в новом коде. Но, увидев в почте отчёт от системы автоматической проверки проекта Blender, не выдержал. Предлагаю вашему вниманию очередную простую, но именно из-за этого красивую ошибку.

Итак, жил-был вот такой код для обработки вектора значений. Суть — не дать значениям выходить за определённый диапазон.

#define CLAMP(a, b, c) \
  { \
    if ((a) < (b)) { \
      (a) = (b); \
    } \
    else if ((a) > (c)) { \
      (a) = (c); \
    } \
  } \
  (void)0

template <typename T> inline T
clamp(const T &a, const bT &min_v, const bT &max_v)
{
  T result = a;
  for (int i = 0; i < T::type_length; i++) {
    CLAMP(result[i], min_v, max_v);
  }
  return result;
}

И было всё хорошо. А потом программист решил, что нет смысла использовать самодельный макрос CLAMP, а лучше воспользоваться стандартной функцией std::clamp. И в коммите, призванном сделать мир лучше, код стал таким:

template <typename T, int Size>
inline vec_base<T, Size>
  clamp(const vec_base<T, Size> &a, const T &min, const T &max)
{
  vec_base<T, Size> result = a;
  for (int i = 0; i < Size; i++) {
    std::clamp(result[i], min, max);
  }
  return result;
}

Вот только поспешил. Видите ошибку? Возможно, видите, возможно, нет. В любом случае, программист, написавший этот код, явно не заметил, что код сломался.

Зато дотошный статический анализатор кода PVS-Studio тут как тут с сообщением:

[CWE-252] V530: The return value of function 'clamp' is required to be utilized. BLI_math_vector.hh 88

Дело в том, что функция std::clamp не меняет значение элемента в контейнере:

template <class T>
constexpr const T&
clamp( const T& v, const T& lo, const T& hi );

Макрос CLAMP раньше изменял значение, а стандартная функция нет. Поэтому теперь код сломан и ждёт, когда кто-то заметит проявление ошибки и пойдёт искать её причину. Такую ошибку можно было бы заметить и исправить ещё на этапе написания кода, если бы использовался PVS-Studio. Не будьте как разработчики Blender :). Используйте статический анализ кода на регулярной основе. И вы сэкономите свои силы и время.

Примечание. Кстати, рядом в коде есть ещё одно неправильное использование std::clamp.

Правильный вариант кода:

template <typename T, int Size>
inline vec_base<T, Size>
clamp(const vec_base<T, Size> &a, const T &min, const T &max)
{
  vec_base<T, Size> result = a;
  for (int i = 0; i < Size; i++) {
    result[i] = std::clamp(result[i], min, max);
  }
  return result;
}

Спасибо за внимание. И, если ещё не видели, заглядывайте почитать про топ-10 ошибок в C++ открытых проектах, которые мы нашли за 2021 год.

Популярные статьи по теме
Интервью с Джейсоном Тернером, одним из ведущих подкаста "CppCast": история и причины закрытия проекта

Дата: 27 Сен 2022

Автор: Ульяна Гришина

В этой статье мы поговорим с Джейсоном Тернером, одним из основателей CppCast. CppCast – это первый С++ подкаст, основанный С++ разработчиками. Начиная с 2015 года каждую неделю на CppCast выходили п…
Боремся с 16-летним легаси-кодом, или исправляем C и C++ front-end в PVS-Studio

Дата: 22 Сен 2022

Автор: Сергей Ларин

В 2022 году статическому анализатору PVS-Studio для языков C и C++ исполняется 16 лет. Если бы анализатор был человеком, то он бы уже заканчивал школу. Это очень старый проект, и система типов в нем …
Как фидбек помог улучшить наш C++ квиз

Дата: 31 Авг 2022

Автор: Алексей Саркисов

Ранее в нашем блоге мы рассказывали о квизе для C++ разработчиков. С момента запуска мы тщательно собирали обратную связь. Часть из неё касалась ошибок в работе квиза, которые мы естественно решили и…
Концепция умного указателя static_ptr<T> в C++

Дата: 30 Авг 2022

Автор: Гость

В C++ есть несколько "умных указателей" – 'std::unique_ptr', 'std::shared_ptr', 'std::weak_ptr'.
"Так исторически сложилось", или за что разделили V512

Дата: 12 Авг 2022

Автор: Михаил Гельвих

Как говорится, в любом деле самое сложное — это начать. Так и мы, очень долго откладывали разделение диагностики V512, но время пришло. Ну а о причинах и последствиях этого решения можно прочитать в …

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

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