一般来说,什么可能导致程序中的双重释放不包含任何动态内存分配?
更准确地说,我的代码都没有使用动态分配。我正在使用STL,但它更有可能是我做错了,而不是G ++ / glibc / STL的破坏。
我一直在寻找答案,但是我没有找到任何没有任何动态内存分配的错误生成示例。
我很乐意分享产生此错误的代码,但我不允许发布它,我不知道如何将问题减少到足够小到可以在这里给出的东西。我会尽力描述我的代码所做的事情。
离开函数时抛出了错误,堆栈跟踪显示它来自std::vector<std::set<std::string>>
的析构函数。向量中的一些元素由emplace_back()
初始化。在最后一次尝试中,我将其更改为push_back({{}})
,问题就消失了。通过设置环境变量 MALLOC_CHECK_ = 2 也可以避免此问题。根据我的理解,该环境变量应该导致glibc中止更多信息,而不是导致错误消失。
这个问题只是被要求服务于我的好奇心,所以我会在黑暗的答案中找到答案。我能想到的最好的是它是一个编译器错误,但是it's always my fault。
答案 0 :(得分:3)
通常,什么可能导致程序中的双重释放不包含任何动态内存分配?
通常,当您制作动态分配内存但不遵循 rule of three
的类型的副本时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.
}
}
答案 1 :(得分:1)
我提取了一个可呈现的示例,展示了我所做的导致“双重释放或损坏”运行时错误的错误。请注意,struct不会显式使用任何动态内存分配,但内部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 size成员)。见Will memcpy or memmove cause problems copying classes?。显然,这也适用于具有非基本类型成员的结构(如此处的情况)。
也许你也错误地复制了一个std :: vector并看到了相同的行为,也许你没有。最后,这完全是我的错:)。