我正在维护用C ++编写的遗留应用程序。它时不时地崩溃,Valgrind告诉我它是对某个对象的双重删除。
找出导致您无法完全理解的应用程序中的双重删除以及哪个太大而无法重写的错误的最佳方法是什么?
请分享您的最佳提示和技巧!
答案 0 :(得分:4)
以下是一些在这种情况下帮助我的一般性建议:
cout << "class Foo constructed, ptr= " << this << endl;
语句(以及相应的delete
/析构函数打印)。答案 1 :(得分:2)
是的。 @OliCharlesworth说的话。没有万无一失的方法来测试指针,看它是否指向已分配的内存,因为它本身就只是内存位置。
您的问题所暗示的最大问题是缺乏可重复性。继续考虑到这一点,您仍然坚持将简单的“删除”结构更改为delete foo;foo = NULL;
。
即便如此,最好的情况是“它似乎发生的更少”,直到你真的盖章了。
我还会问Valgrind有什么证据表明这是一个双重删除问题。可能是一个更好的线索在那里挥之不去。
这是一个更简单的真正令人讨厌的问题。
答案 2 :(得分:2)
这可能适用于您,也可能不适合您。
很久以前,我正在研究当时15岁的1M +线路计划。面对完全相同的问题 - 用大量数据集双删除。有了这样的数据,任何开箱即用的“内存分析器”都是不行的。
我身边的事情:
现在的诀窍/想法:
my_malloc(int size)
{
static int allocation_num = 0; // it was single threaded
void* p = builtin_malloc(size+16);
*(int*)p = ++allocation_num;
*((char*)p+sizeof(int)) = 0; // not freed
return (char*)p+16; // check for NULL in order here
}
my_free(void* p)
{
if (*((char*)p+sizeof(int)))
{
// this is double free, check allocation_number
// then rerun app with this in my_alloc
// if (alloc_num == XXX) debug_break();
}
*((char*)p+sizeof(int)) = 1; // freed
//built_in_free((char*)p-16); // do not do this until problem is figured out
}
使用new / delete可能会更棘手,但仍然使用LD_PRELOAD,您甚至可以在不重新编译应用程序的情况下替换malloc / free。
答案 3 :(得分:0)
您可能正在从处理删除的版本升级到新版本。
可能是以前的版本在调用delete
时执行的操作,它对if (X != NULL){ delete X; X = NULL;}
执行了静态检查,然后在新版本中执行delete
操作。
您可能需要检查指针分配,并跟踪从构造到删除的对象名称的引用。
答案 4 :(得分:0)
我发现这很有用:backtrace() on linux。 (你必须使用-rdynamic进行编译。)这可以通过在所有内存操作(new / delete)周围放置一个try / catch块然后在catch块中找出双重释放的来源,打印出堆栈跟踪。
通过这种方式,您可以比运行valgrind更快地缩小嫌疑人范围。
我在一个方便的小课程中包裹了回溯,以便我可以说:
try {
...
} catch (...) {
StackTrace trace;
std::cerr << "Double free!!!\n" << trace << std::endl;
throw;
}
答案 5 :(得分:0)
在Windows上,假设应用程序是使用MSVC ++构建的,您可以利用标准库调试版本中内置的大量heap debugging工具。
同样在Windows上,您可以使用Application Verifier。如果我没记错的话,它有一种模式,强制每个分配到一个单独的页面,其间有受保护的保护页面。它在查找缓冲区溢出方面非常有效,但我怀疑它对双重自由情况也很有用。
你可以做的另一件事(在任何平台上)都是制作转换源(可能带有宏)的副本,以便每个实例:
delete foo;
替换为:
{ delete foo; foo = nullptr; }
(大括号在很多情况下都有帮助,虽然它并不完美。)这会将许多双自由实例转换为空指针引用,使其更易于检测。它并没有抓住一切;你可能有一个陈旧指针的副本,但它可以帮助压缩许多常见的使用后删除方案。