>
>
>
V780. The object of non-passive (non-PD…


V780. The object of non-passive (non-PDS) type cannot be used with the function.

Анализатор обнаружил опасную работу со сложными типами. Если объект не является Passive Data Structure (PDS), то нельзя использовать низкоуровневые функции по работе с памятью: memset, memcpy и т.д. Это может нарушить логику работы класса и привести к утечке памяти, двойному очищению одного ресурса или Undefined Behavior.

Пример классов, над которыми нельзя совершать такие действия: std::vector, std::string и другие подобные контейнеры.

Иногда такая диагностика находит опечатки. Рассмотрим пример:

struct Buffer {
  std::vector<char>* m_data;

  void load(char *buf, size_t len) {
    m_data->resize(len);
    memcpy(&m_data[0], buf, len);
  }
};

Функция 'memcpy' копирует данные не в содержимое контейнера, а в объект, на который указывает 'm_data'. Такой код нужно переписать следующим образом:

memcpy(&(*m_data)[0], buf, len);

или:

memcpy(m_data->data(), buf, len);

Другой способ ошибиться - это использовать memset/memcpy для структуры, полями которой являются non-PDS объекты. Рассмотрим пример:

struct Buffer {
  std::vector<char> m_data;
  ....
};

void F() {
  Buffer a;
  memset(&a, 0, sizeof(Buffer));
  ....
}

Чтобы избежать таких ошибок можно рекомендовать использовать value initialization. Такой подход корректно работает и с POD-данными, и с объектами с нетривиальным конструктором.

Для копирования можно положиться на генерируемый компилятором конструктор копирования или написать свой.

Анализатор также ищет структуры, использование memset/memcpy над которыми может быть опасно, исходя из их логики или представления в памяти. К первому случаю относятся классы, в которых одновременно есть указатели, конструкторы и деструкторы. Если в классе содержится нетривиальная работа с указателями (например, управление памятью или ресурсом), то нельзя использовать для него memcpy/memset. Пример такого класса:

struct Buffer {
  char *buf;

  Buffer() : buf(new char[16]) {}
  ~Buffer() { delete[] buf; }
};

Buffer buf1, buf2;
memcpy(&buf1, &buf2, sizeof(Buffer));

Ко второму случаю относятся классы, не являющиеся standard layout:

struct BufferImpl {
  virtual bool read(char *, size_t) { return false; }
};

struct Buffer {
  BufferImpl impl;
};

Buffer buf1, buf2;
memcpy(&buf1, &buf2, sizeof(Buffer));

Данная диагностика классифицируется как:

  • CERT-EXP62-CPP
  • CERT-OOP57-CPP

Взгляните на примеры ошибок, обнаруженных с помощью диагностики V780.