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

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

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

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

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

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

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


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

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

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

18 Апр 2022

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

0936_Blender_prevents_rash_code_changes_N5_ru/image1.png

Каждый день система для регулярного мониторинга проекта Blender присылает мне отчёт о потенциальных ошибках в новом или изменённом коде. Описывать каждый новый баг и писать 100500 заметок про это неинтересно, но сегодня особый случай.

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

Суть технологии символьного выполнения в том, чтобы вычислять выражения, не зная значений переменных. Звучит таинственно, но сейчас мы разберём это на практическом примере, и всё сразу станет понятно. Рассмотрим вот этот коммит в проекте Blender.

PVS-Studio выдаёт предупреждение на 868-ую строчку кода:

memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));

Анализатор считает подозрительным, что функция memset на самом деле не заполняет память:

[CWE-628] V575: The 'memset' function processes '0' elements. Inspect the third argument.

Давайте разберёмся, как он пришёл к такому выводу.

Анализатор не знает, какие числовые значения могут храниться в переменной path->len. Он знает про эту переменную кое-что другое, но про это позже.

Про переменную i известно чуть больше.

for (int i = 0; i < path->len; i++) {
  ....
  if (i != 0) {
    ....
    memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));

Из этого кода анализатор может извлечь следующую информацию:

  • Переменная i меньше path->len. Это известно из анализа цикла.
  • Переменная i больше 0. Это следует из инициализации этой переменной в цикле и последующей проверки на неравенство нулю.

Итого, значения переменной i лежат в диапазоне от 1 до path->len.

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

Анализатор видит, что перед вызовом функции memset значение path->len меняется следующим образом:

path->len = i;
if (i != 0) {
  memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i));

Переменная path->len равна значению i. Поэтому, даже не зная диапазоны возможных значений переменных, можно вычислить выражение. Для этого анализатор делает подстановку:

sizeof(path->ptr[i]) * (i - i)

И получает 0 в качестве третьего аргумента функции:

sizeof(path->ptr[i]) * 0

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

Примечание. Поскольку в статье приводится только маленькая часть кода, то присваивание path->len = i может показаться вообще очень странным. Ведь это означает, что цикл всегда завершается после первой итерации. На самом деле, рассмотренный в статье фрагмент находится под условиями, и такой код имеет смысл. Вы можете сами изучить тело цикла целиком.

Предыдущие публикации:

Популярные статьи по теме
Интервью с Джейсоном Тернером, одним из ведущих подкаста "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
Мы используем куки, чтобы пользоваться сайтом было удобно. Хотите узнать подробнее?
Принять