двойное освобождение без динамического выделения памяти

В общем, что может вызвать двойное освобождение в программе, которая не содержит динамического выделения памяти?

Чтобы быть более точным, ни один из мой код использует динамическое распределение. Я использую STL, но, скорее всего, я что-то сделал не так, как если бы это было неправильное использование G ++ / glibc / STL.

Я искал, пытаясь найти ответ на этот вопрос, но я не смог найти ни одного примера возникновения этой ошибки без динамического выделения памяти.

Мне бы хотелось поделиться кодом, который генерировал эту ошибку, но мне не разрешено ее выпускать, и я не знаю, как свести проблему к чему-то достаточно маленькому, чтобы ее можно было здесь представить. Я сделаю все возможное, чтобы описать суть того, что делал мой код.

При выходе из функции возникала ошибка, и трассировка стека показала, что она исходит от деструктора std::vector<std::set<std::string>>, Некоторое количество элементов в векторе было инициализировано emplace_back(), В последней попытке я изменил это на push_back({{}}) и проблема ушла. Эту проблему также можно избежать, установив переменную среды MALLOC_CHECK_ = 2. Насколько я понимаю, эта переменная среды должна была заставить glibc прекратить работу с большим количеством информации, а не убрать ошибку.

Этот вопрос задают только для того, чтобы удовлетворить мое любопытство, поэтому я согласен на ответ в темноте. Лучшее, что я смог придумать, это то, что это была ошибка компилятора, но это всегда моя вина.

3

Решение

В общем, что может вызвать двойное освобождение в программе, которая не содержит динамического выделения памяти?

Обычно, когда вы делаете копию типа, который динамически распределяет память, но не следует правило трех

struct Type
{
Type() : ptr = new int(3) { }
~Type() { delete ptr; }
// no copy constructor is defined
// no copy assign operator is defined

private:
int * ptr;
};

void func()
{
{
std::vector<Type> objs;
Type t; // allocates ptr
objs.push_back(t); // make a copy of t, now t->ptr and objs[0]->ptr point to same memory location
// when this scope finishes, t will be destroyed, its destructor will be called and it will try to delete ptr;
// objs go out of scope, elements in objs will be destroyed, their destructors are called, and delete ptr; will be executed again. That's double free on same pointer.
}
}
3

Другие решения

Я извлек презентабельный пример, демонстрирующий ошибку, которую я совершил, которая привела к ошибке времени выполнения «двойное освобождение или повреждение». Обратите внимание, что структура явно не использует динамическое выделение памяти, однако внутренне использует std :: vector (так как ее содержимое может увеличиваться для размещения большего количества элементов). Поэтому эту проблему было немного сложно диагностировать, поскольку она не нарушает принцип «правила 3».

#include <vector>
#include <string.h>

typedef struct message {
std::vector<int> options;
void push(int o) { this->options.push_back(o); }
} message;

int main( int argc, const char* argv[] )
{
message m;
m.push(1);
m.push(2);

message m_copy;
memcpy(&m_copy, &m, sizeof(m));
//m_copy = m; // This is the correct method for copying object instances, it calls the default assignment operator generated 'behind the scenes' by the compiler
}

Когда main () возвращает, m_copy уничтожается, что вызывает деструктор std :: vector. Это пытается удалить память, которая уже была освобождена, когда объект m был уничтожен.

По иронии судьбы, я использовал memcpy, чтобы попытаться получить «глубокую копию». Вот где вина лежит в моем случае. Я предполагаю, что с помощью оператора присваивания все члены message.options фактически копируются в «вновь выделенную память», тогда как memcpy будет копировать только те члены, которые были выделены во время компиляции (например, элемент размера uint32_t). Увидеть Будет ли memcpy или memmove вызывать проблемы при копировании классов?. Очевидно, что это также относится к структурам с неосновными типизированными членами (как в данном случае).

Может быть, вы также неправильно скопировали std :: vector и видели то же поведение, а может и нет. В конце концов, это была моя полная вина :).

1

По вопросам рекламы [email protected]