Для получения триального ключа
заполните форму ниже
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 может показаться вообще очень странным. Ведь это означает, что цикл всегда завершается после первой итерации. На самом деле, рассмотренный в статье фрагмент находится под условиями, и такой код имеет смысл. Вы можете сами изучить тело цикла целиком.

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

Популярные статьи по теме
Как различить C и C++ разработчиков по их коду

Дата: 12 Май 2022

Автор: Гость

Так уж случилось, что я пишу код для разных IoT-железок, связанных с электричеством, типа зарядных станций автомобилей. Поскольку аппаратных ресурсов, как правило, вполне достаточно, то основным фоку…
Отладочный вывод на микроконтроллерах: как Concepts и Ranges отправили мой printf на покой

Дата: 06 Май 2022

Автор: Гость

Здравствуйте! Меня зовут Александр, и я работаю программистом микроконтроллеров.
Нереальный baselining или доработки PVS-Studio для Unreal Engine проектов

Дата: 26 Апр 2022

Автор: Валерий Комаров

Статический анализатор PVS-Studio постоянно развивается: улучшаются различные механизмы, происходит интеграция с игровыми движками, IDE, CI/CD и другими системами и сервисами. Благодаря этому несколь…
Разбор некоторых вредных советов для С++ программиста

Дата: 21 Апр 2022

Автор: Андрей Карпов

Юмор юмором, но осторожность не повредит. Вдруг кому-то не до конца понятно, почему какой-то из советов является вредным. Здесь можно найти соответствующие пояснения.
Четыре причины проверять, что вернула функция malloc

Дата: 20 Апр 2022

Автор: Андрей Карпов

Некоторые разработчики пренебрежительно относятся к проверкам: удалось ли выделить память с помощью функции malloc или нет. Их логика проста – памяти всегда должно хватить. А если не хватит, всё равн…

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

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