Анализатор обнаружил опасную работу со сложными типами. Если объект не является 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));
Данная диагностика классифицируется как:
|
Взгляните на примеры ошибок, обнаруженных с помощью диагностики V780. |