>
>
>
PVS-Studio для проверки лабораторных ра…

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

PVS-Studio для проверки лабораторных работ на C и C++

Встретил очередной вопрос на Stack Overflow от человека, изучающего язык C++. Количество подобных вопросов можно сократить, используя PVS-Studio. Человек сразу может получить ответ, не отвлекая других.

Я уже описывал здесь, что online версия анализатора PVS-Studio может существенно облегчить жизнь начинающим программистам. Рассмотрим ещё один подобный случай.

Заглянем в дискуссию "C++ error: "pointer being freed was not allocated" на сайте Stack Overflow и посмотрим на этот код:

#include <stdexcept>
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>

using std::cout;
using std::endl;
using std::vector;      

typedef vector<int> ints;

void print_ints(vector<int>);
void print_ints_vec(vector<vector<int>>);
void int_part(int, vector<vector<int>>&);

int main() 
{
  vector<vector<int>> partition;
  int_part(5, partition);
  print_ints_vec(partition);

  return 0;
}

void int_part(int sum, vector<vector<int>>& res)
{
  vector<int> init_xs = vector<int>{sum};
  vector<int>* xs = &init_xs; // POINTER INITIALIZED TO vector<int>
  int current_sum = sum;

  while (true) 
  {
    current_sum = accumulate(xs->begin(), xs->end(), 0);

    if (current_sum == sum)
    {
      res.push_back(*xs);
      vector<int> next_xs;
      vector<int>::iterator it = find(xs->begin(), xs->end(), 1);
      if (it == xs->begin()) return;
      copy(xs->begin(), it, back_inserter(next_xs));
      next_xs[next_xs.size() - 1] -= 1;
      xs = &next_xs; // POINTER REASSIGNED TO ANOTHER vector<int>
    }
    else 
    {
      int tail = xs->back();
      int diff = sum - current_sum;
      int m = std::min(tail, sum - tail);
      int next_tail = current_sum + m > sum ? diff : m;
      xs->push_back(next_tail);
    }
  }
}

void print_ints(ints v) // PRINT UTILITY
{
  cout << "[ ";
  for (const int& n : v) { cout << n << "; "; }
  cout << "]" << endl;
}

void print_ints_vec(vector<ints> v) // PRINT UTILITY
{
  cout << "[ \n";
  for (const vector<int>& xs : v) { cout << "  "; print_ints(xs); }
  cout << "]" << endl;
}

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

Вот что он сообщает: V506 Pointer to local variable 'next_xs' is stored outside the scope of this variable. Such a pointer will become invalid.

Строка:

xs = &next_xs; // POINTER REASSIGNED TO ANOTHER vector<int>

И действительно, ошибка в том, что сохраняется ссылка на объект, который будет разрушен. На эту ошибку указали другие люди и объяснили, в чём состоит проблема. Однако можно было бы обойтись вообще без ожидания ответа от более опытных коллег. Ведь объяснение ошибки вполне можно получить и из документации анализатора PVS-Studio по диагностике V506.

Вывод

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

Дополнительные ссылки: