Анализатор обнаружил опасную работу со сложными типами. Если объект не является 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. |