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

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

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

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

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

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

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


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

>
>
>
Да, PVS-Studio умеет выявлять утечки па…

Да, PVS-Studio умеет выявлять утечки памяти

29 Ноя 2017

Нас часто спрашивают, умеет ли статический анализатор кода PVS-Studio выявлять утечки памяти (memory leaks). Чтобы много раз не писать похожие тексты в письмах, мы решили дать подробный ответ в блоге. Да, PVS-Studio умеет выявлять утечки памяти и других ресурсов. Для этого в PVS-Studio реализовано несколько диагностик и в статье будут продемонстрированы примеры обнаружения ошибок в реальных проектах.

0543_Memory_leaks_ru/image1.png

Выявление утечек памяти и ресурсов

Утечка памяти (memory leak) - это процесс неконтролируемого уменьшения объёма свободной оперативной или виртуальной памяти компьютера, связанный с ошибками в работающих программах, вовремя не освобождающих ненужные уже участки памяти. Согласно CWE утечки памяти классифицируются как дефект CWE-401.

Утечки памяти являются одной из разновидностей ошибок утечек ресурсов (resource leak). Примером утечки другого вида ресурса может служить ошибка, именуемая утечкой файлового дескриптора: файл открывается, но не закрывается, и дескриптор не возвращается операционной системе. Согласно CWE такие ошибки можно классифицировать как CWE-404.

Утечки памяти или других ресурсов могут приводить к ошибкам отказа обслуживания (Denial of Service).

Для выявления утечек памяти и других ресурсов используются инструменты динамического и статического анализа кода. К числу таких инструментов принадлежит и анализатор PVS-Studio.

Для выявления рассматриваемого класса ошибок в PVS-Studio реализованы следующие диагностики:

  • V599. The virtual destructor is not present, although the 'Foo' class contains virtual functions.
  • V680. The 'delete A, B' expression only destroys the 'A' object. Then the ',' operator returns a resulting value from the right side of the expression.
  • V689. The destructor of the 'Foo' class is not declared as a virtual. It is possible that a smart pointer will not destroy an object correctly.
  • V701. realloc() possible leak: when realloc() fails in allocating memory, original pointer is lost. Consider assigning realloc() to a temporary pointer.
  • V772. Calling a 'delete' operator for a void pointer will cause undefined behavior.
  • V773. The function was exited without releasing the pointer/handle. A memory/resource leak is possible.
  • V779. Unreachable code detected. It is possible that an error is present.
  • V1002. A class, containing pointers, constructor and destructor, is copied by the automatically generated operator= or copy constructor.
  • V1005. The resource was acquired using 'X' function but was released using incompatible 'Y' function.

Примеры

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

Пример N1.

Проект NetDefender. Предупреждение PVS-Studio: V773 The 'm_pColumns' pointer was not released in destructor. A memory leak is possible. fireview.cpp 95

Обратите внимание, что в конструкторе создаются два объекта:

  • Указатель на объект типа CBrush сохраняется в переменной m_pBrush.
  • Указатель на объект типа CStringList сохраняется в переменной m_pColumns.
CFireView::CFireView() : CFormView(CFireView::IDD)
{
  m_pBrush = new CBrush;
  ASSERT(m_pBrush);
  m_clrBk = RGB(148, 210, 252);
  m_clrText = RGB(0, 0, 0);
  m_pBrush->CreateSolidBrush(m_clrBk);

  m_pColumns = new CStringList;
  ASSERT(m_pColumns);
  _rows = 1;
  start = TRUE;
  block = TRUE;
  allow = TRUE;
  ping = TRUE;
  m_style=StyleTile;
}

В деструкторе же, происходит уничтожение только одного объекта, адрес которого хранится в переменной m_pBrush:

CFireView::~CFireView()
{
  if(m_pBrush)
  {
     delete m_pBrush;
  }
}

Про переменную m_pColumns видимо просто забыли. В результате возникает утечка памяти.

Пример N2.

Проект Far2l (Linux port of FAR v2). Рассматриваема ошибка интересна тем, что она обнаруживается сразу двумя различными диагностиками PVS-Studio:

  • V779 Unreachable code detected. It is possible that an error is present. 7z.cpp 203
  • V773 The function was exited without releasing the 't' pointer. A memory leak is possible. 7z.cpp 202
BOOL WINAPI _export SEVENZ_OpenArchive(const char *Name,
                                       int *Type)
{
  Traverser *t = new Traverser(Name);
  if (!t->Valid())
  {
    return FALSE;
    delete t;
  }

  delete s_selected_traverser;
  s_selected_traverser = t;
  return TRUE;
}

Местами перепутаны оператор return и оператор delete. В результате оператор delete никогда не выполняется. Анализатор предупреждает об этом, выдавая сообщение о недостижимом коде и сообщение об утечке памяти.

Пример N3.

Проект Firebird. Предупреждение PVS-Studio: V701 realloc() possible leak: when realloc() fails in allocating memory, original pointer 's->base' is lost. Consider assigning realloc() to a temporary pointer. mstring.c 42

int mputchar(struct mstring *s, int ch)
{
  if (!s || !s->base) return ch;
  if (s->ptr == s->end) {
    int len = s->end - s->base;
    if ((s->base = realloc(s->base, len+len+TAIL))) {
      s->ptr = s->base + len;
      s->end = s->base + len+len+TAIL; }
    else {
      s->ptr = s->end = 0;
      return ch;
    }
  }
  *s->ptr++ = ch;
  return ch;
}

Рассматриваемая функция предназначена для добавления к строке символа. Буфер, который используется для хранения строки, увеличивается с помощью вызова функции realloc. Ошибка заключается в том, что если функция realloc не может увеличить размер буфера памяти, то произойдёт утечка памяти. Причина в том, что если нет блока памяти достаточного размера, то функция realloc возвращает NULL и при этом она не освобождает предыдущий буфер памяти. Поскольку результат работы функции сразу записывается в переменную s->base, то нет никакой возможности освободить ранее выделенный блок.

Ошибку можно исправить, добавив временную переменную и вызов функции free:

int mputchar(struct mstring *s, int ch)
{
  if (!s || !s->base) return ch;
  if (s->ptr == s->end) {
    void *old = s->base;
    int len = s->end - s->base;
    if ((s->base = realloc(s->base, len+len+TAIL))) {
      s->ptr = s->base + len;
      s->end = s->base + len+len+TAIL; }
    else {
      free(old);
      s->ptr = s->end = 0;
      return ch;
    }
  }
  *s->ptr++ = ch;
  return ch;
}

Статический и динамический анализ

На примере PVS-Studio видно, что статические анализаторы умеют выявлять различные виды утечек ресурсов. Однако, ради справедливости следует отметить, что в целом статические анализаторы проигрывают в сфере поиска утечек динамическим анализаторам кода.

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

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

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

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

Заключение

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

Команда PVS-Studio желает Вам безбажного кода.

Популярные статьи по теме
Главный вопрос программирования, рефакторинга и всего такого

Дата: 14 Апр 2016

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

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

Дата: 19 Май 2017

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

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

Дата: 30 Янв 2019

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

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

Дата: 22 Дек 2018

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

В канун празднования нового 2019 года команда PVS-Studio решила сделать приятный подарок всем контрибьюторам open-source проектов, хостящихся на GitHub, GitLab или Bitbucket. Им предоставляется возмо…
Технологии, используемые в анализаторе кода PVS-Studio для поиска ошибок и потенциальных уязвимостей

Дата: 21 Ноя 2018

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

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

Дата: 20 Мар 2017

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

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

Дата: 27 Июн 2017

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

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

Дата: 17 Янв 2019

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

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

Дата: 31 Май 2014

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

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

Дата: 31 Июл 2017

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

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

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

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