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

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

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

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

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

** На сайте установлена reCAPTCHA и применяются
Политика конфиденциальности и Условия использования Google.
Ваше сообщение отправлено.

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


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

>
>
Философия статического анализатора PVS-…

Философия статического анализатора PVS-Studio

26 Июн 2017

Нам регулярно поступают предложения и рекомендации по улучшению диагностических возможностей анализатора. Большинство предложений мы помещаем во внутренний todo-список и со временем реализовываем. Мы благодарны нашим пользователям за присылаемые отзывы и предложения и пользуясь случаям, я хочу сказать им спасибо. Спасибо! Итак, многое мы реализуем, но не всё. Дело в том, что некоторые виды предлагаемых диагностик не укладываются в философию разрабатываемого нами анализатора PVS-Studio. Чтобы нашим пользователям была понятна наша позиция и как мы приходим к заключению, что можно реализовывать, а что нет, я решил написать эту подробную заметку.

0516_Philosophy_behind_PVS_Studio_ru/image1.png

Есть два философских подхода в реализации статических анализаторов кода:

  • Ругаемся на всё, про что не можем сказать, что оно правильное.
  • Ругаемся на то, которое по какой-то причине скорее всего неправильное.

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

К нам поступают предложения по диагностикам следующего вида:

  • Следует выдавать предупреждение на A / B, если нет уверенности, что B != 0.
  • Следует выдавать предупреждение, если нет уверенности, что при вызове функции strcpy(DST, SRC) буфер DST достаточного размера.
  • Следует выдавать предупреждение при разыменовывании указателя, если нет уверенности, что pointer != NULL.
  • Следует выдавать предупреждение на sqrt(X), если нет уверенности, что X >= 0.
  • И так далее.

По отдельности каждое из таких предупреждений выглядит разумным и полезным. Но вместе они убьют анализатор кода. Каждая диагностика, реализованная подобным образом, порождает большое количество ложных срабатываний. Конечно, если реализовать только одну диагностику, беды не случится. Однако, если мы реализуем поиск делений, в которых не уверены, то почему мы должны не реализовывать поиск недостоверных sqrt? Нет границы или критерия где надо остановиться, реализуя подобные диагностики.

Здесь проявляет себя теория разбитых окон. Стоит сделать пару диагностик в духе философии "ругаемся на всё, про что не можем сказать, что оно правильное" и процесс будет необратим. Подобные диагностики открывают ящик Пандоры. Например, непонятно как отказаться от реализации поиска сложения двух переменных "A+B" типа int, если нет уверенности, что не возникнет переполнение. И так далее и так далее.

Идя по этому пути, анализатор начнёт выдавать предупреждение на код:

void Foo(int &i)
{
  i++;  // Возможно переполнение.
}

Формально всё верно и диагностика полезна. Переполнение переменной типа int приводит к неопределённому поведению. Анализатор должен ругаться, если не может убедиться, что безопасны все диапазоны значения переменной, переданной в функцию.

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

Читатель может возразить: вы преувеличиваете и доводите до абсурда, давайте сделаем диагностику, которая ругается на использование непроверенного указателя и остановимся.

В том-то всё и дело, что остановиться не получится. Если мы сделаем для одного пользователя поиск указателей, то как мы обоснуем другому пользователю, что не будем искать непроверенные деления? Разыменовывание нулевого указателя не более серьезно, чем деление на 0.

Означает ли это, что анализатор PVS-Studio не ищет разыменование нулевых указателей или деление на ноль? Конечно же ищет.

Но поиск ошибок реализован согласно философии "ругаемся на то, которое по какой-то причине скорее всего неправильное". Другими словами, должны существовать некие признаки, которые указывают на то, что код может содержать ошибку.

Давайте рассмотрим это на примерах.

void F(int *P)
{
  *P = 1;
}

Анализатор PVS-Studio не ругается на этот код, так как у него нет для этого оснований. То, что указатель P используется без проверки, вовсе не означает, что программа содержит ошибку.

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

void F(int *P)
{
  *P = 1;
}
void Foo()
{
  F(0);
}

PVS-Studio: V522 Dereferencing of the null pointer 'P' might take place. The null pointer is passed into 'F' function. Inspect the first argument. Check lines: 'simple.cpp:69'. simple.cpp 64

Здесь все понятно, раз явно передаём в функцию NULL, то это ошибка. Конечно, на практике подобный код практически не встречается, поэтому рассмотрим что-то более приближённое к реальности:

void F(int *P)
{
  *P = 1;
}
void Foo()
{
  int *X = (int *)malloc(sizeof(int));
  F(X);
  free(X);
}

PVS-Studio: V522 Dereferencing of the null pointer 'P' might take place. The potential null pointer is passed into 'F' function. Inspect the first argument. Check lines: 'simple.cpp:70'. simple.cpp 64

Анализатор вновь выдал предупреждение, но теперь речь идёт о "потенциально нулевом указателе". Имеется в виду, что функция malloc может вернуть NULL, и возвращаемый указатель надо обязательно проверить перед использованием.

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

Например, если мы изменим код следующим образом, то анализатор вновь будет молчать:

void F(int *P)
{
  *P = 1;
}
void Foo()
{
  int *X = (int *)malloc(sizeof(int));
  if (!X)
    return;
  F(X);
  free(X);
}

Теперь все хорошо и предупреждений нет.

А есть ли другие ситуации, когда анализатор выдаст предупреждения? Да. Для демонстрации я выбрал короткий пример из списка ошибок, найденных в открытых проектах с помощью диагностики V595.

FName UKismetNodeHelperLibrary::GetEnumeratorName(
  const UEnum* Enum, uint8 EnumeratorValue)
{
  int32 EnumeratorIndex = Enum->GetIndexByValue(EnumeratorValue);
  return (NULL != Enum) ?
         Enum->GetEnum(EnumeratorIndex) : NAME_None;
}

PVS-Studio: V595 The 'Enum' pointer was utilized before it was verified against nullptr. Check lines: 146, 147. kismetnodehelperlibrary.cpp 146

Что заставляет анализатор PVS-Studio выдать предупреждение на разыменование указателя? То, что после разыменования этот указатель проверяется на равенство NULL. Наличие такой проверки является поводом выдать предупреждение.

Рассмотрим другой пример.

void F(char *A, char *B)
{
  strcpy(A, B);
}

Следует выдавать здесь предупреждение? С нашей точки зрения нет. Использование функции strcpy само по себе не является ошибкой.

Если хочется проверить корректность вызова всех таких функций, то анализатор PVS-Studio тут ни при чём. Можно просто сделать поиск в программе всех strcpy и изучить соответствующий код.

Конечно, искать вручную вызов функций strcpy и аналогичных не удобно. Поэтому Visual C++ предупреждает о наличии таких функций и предлагает заменить их на безопасные аналоги. Для приведённого выше кода, он выдаст:

warning C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.

Когда анализатор PVS-Studio выдаёт предупреждение на strcpy? Когда для этого есть повод. Пример:

void F()
{
  size_t bad_buf_size = strlen("string"); // забыли + 1
  char *A = (char *)malloc(bad_buf_size);
  if (A)
    strcpy(A, "string");
  free(A);
}

V512 A call of the 'strcpy' function will lead to overflow of the buffer 'A'. consoleapplication1.cpp 14

Надеюсь мне удалось пояснить нашу философию. Исходя из неё, мы делим предложенные диагностики на две категории:

  • Опасно всё, что не проверено - нерационально и не реализуется.
  • Опасно только то, что подозрительно - постепенно реализуем, если это технически возможно.

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

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

Дата: 22 Окт 2018

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

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

Дата: 17 Янв 2019

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

В седьмой версии статического анализатора PVS-Studio мы добавили поддержку языка Java. Пришло время немного рассказать, как мы начинали делать поддержку языка Java, что у нас получилось и какие дальн…
Статический анализ как часть процесса разработки Unreal Engine

Дата: 27 Июн 2017

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

Проект Unreal Engine развивается - добавляется новый код и изменятся уже написанный. Неизбежное следствие развития проекта - появление в коде новых ошибок, которые желательно выявлять как можно раньш…
Технологии, используемые в анализаторе кода PVS-Studio для поиска ошибок и потенциальных уязвимостей

Дата: 21 Ноя 2018

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

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

Дата: 20 Мар 2017

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

В своей предыдущей статье я писал, что мне не нравится подход, при котором статические анализаторы кода оцениваются с помощью синтетических тестов. В статье приводился пример, воспринимаемый анализат…
Главный вопрос программирования, рефакторинга и всего такого

Дата: 14 Апр 2016

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

Вы угадали, ответ - "42". Здесь приводится 42 рекомендации по программированию, которые помогут избежать множества ошибок, сэкономить время и нервы. Автором рекомендаций выступает Андрей Карпов - тех…
Эффект последней строки

Дата: 31 Май 2014

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

Я изучил множество ошибок, возникающих в результате копирования кода. И утверждаю, что чаще всего ошибки допускают в последнем фрагменте однотипного кода. Ранее я не встречал в книгах описания этого …
Зло живёт в функциях сравнения

Дата: 19 Май 2017

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

Возможно, читатели помнят мою статью под названием "Эффект последней строки". В ней идёт речь о замеченной мной закономерности: ошибка чаще всего допускается в последней строке однотипных блоков текс…
Любите статический анализ кода!

Дата: 16 Окт 2017

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

Я в шоке от возможностей статического анализа кода, хотя сам участвую в разработке инструмента PVS-Studio. На днях я был искренне удивлён тому, что анализатор оказался умнее и внимательнее меня.
Характеристики анализатора PVS-Studio на примере EFL Core Libraries, 10-15% ложных срабатываний

Дата: 31 Июл 2017

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

После большой статьи про проверку операционной системы Tizen мне было задано много вопросов о проценте ложных срабатываний и о плотности ошибок (сколько ошибок PVS-Studio выявляет на 1000 строк кода)…

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

Следующие комментарии

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