由于对错误指针的free()调用,我的程序在单一测试中严重崩溃,并显示以下错误消息:
*** glibc detected *** /home/user/main.out: free(): invalid pointer: 0x006d0065 ***
代码看起来大致如下:
// constructor is MyObj( const std::string & )
// and copies the string in its own std:string member
MyObject *obj = new MyObject("some string arg");
if(obj->isValid)
{
log("Success\n");
}
delete obj; // if I remove this, the program doesn't crash...
我的调查经历了这个:
我试图跟踪我创建和释放的指针,但它发生在不同的地址空间中,我得到(成功)删除,如下所示:Delete buffer @0x850ed0
。所以我怀疑某些东西试图释放一个静态字符指针。此外,地址在多次尝试中保持不变,这使我在这个谓词中感到安慰。
我不能使用GDB,因为我正在使用的平台似乎拯救了:
Program received signal SIGABRT, Aborted.
[Switching to Thread 0x344314e8 (LWP 1443)]
0x2a3dd658 in raise () from /lib/libc.so.6
(gdb) bt
#0 0x2a3dd658 in raise () from /lib/libc.so.6
#1 0x2a3dea2c in abort () from /lib/libc.so.6
Backtrace stopped: frame did not save the PC
我尝试使用hexdump转储free()失败的程序中的地址:hexdump -C ~/main.out -s 0x6d0000 -n 2000
它给了我这个(错误是free(0x6d0065)
):
006d0060 e8 32 06 00 2c e6 02 5f 5a 4e 4b 53 73 34 66 69 |.2..,.._ZNKSs4fi|
006d0070 6e 64 45 63 6a 00 ab 00 00 00 01 3e 58 00 00 1d |ndEcj......>X...|
看起来像std :: string函数,这很奇怪...... 我认为这可能是对hexdump的错误使用,因为当程序加载到内存中时内存会被重定位。
我尝试了readelf ~/main.out -a | grep 6d0065
也无济于事(没有打击)
在这些条件下,我不是专业的调试人员;你知道我怎么能得到这个地址对程序意味着什么吗?
修改:
该程序在嵌入式平台(SH4)上运行;这是valgrind不支持的(很遗憾......)。
关于此类的功能的更多详细信息:它使用CUrl library在Internet上检索XML文件,然后继续使用pugixml库进行解析。
答案 0 :(得分:1)
黑暗中的狂野镜头......你有一个没有虚拟析构函数的基类,你实际上是在实例化派生类并将new的结果存储在指向基类的指针中。您通过基指针删除,并且在此特定情况下未定义的行为导致该效果。
为什么我相信?传递给free
的指针未被malloc
返回,因为它是一个奇怪的地址,无法正确对齐,malloc
始终提供对齐的内存块。这意味着new
返回的指针和存储的指针的内存有一个偏移量,表明它可能是一个基类。如果类具有虚拟析构函数,那么delete
将能够确定最派生的对象类型,并且在这样做时,它将更正指针以引用使用{{1}分配的地址。 }。如果没有虚拟析构函数,new
将转换为delete
而不更正偏移量。
可能导致相同类型问题的另一件事是使用obj->~MyObject(); free( obj );
进行分配,并且使用new[]
解除分配(delete
将分配额外的空间来存储元素的数量,通常在之前返回的指针)。同样问题是,new[]
的实现传递给free
的指针没有更正以匹配delete
返回的指针...但在这种特殊情况下,偏移可能不是一个奇数。
答案 1 :(得分:0)
你的MyObject正在做一些非常非常糟糕的事情。
你总能(好吧,几乎总是)使用调试器。在某些领域,例如实时编程,这有点具有挑战性,但这似乎并非如此。
要以有意义的方式使用调试器,必须在启用调试的情况下编译代码,使用GNU编译器编译-g选项。
编辑:关于“做非常非常糟糕的事情”的猜测是,该类正在删除没有业务删除的内容。例如:class MyObject {
public:
MyObject(const char * strarg) : str(strarg) {}
~MyObject() { delete str; }
private:
const char * str;
};
答案 2 :(得分:0)
好的,最后把这个错误钉了下来。
对于那些感兴趣的人来说,这是一个在使用它的类的构造函数中没有归零的结构。
架构是这样的:
MyObj ---> BaseClass ---> structure member not initialized
由于此结构包含一些指向字符串的指针,因此NULL检查失败并且我释放了一个错误的指针。
令人遗憾的是,基类通常会填满结构的每个字段,覆盖默认的垃圾值。只有当我继承基类时才遇到问题。
回过头来看,我想我可以通过有效的GDB调试更快地找到 way 。 我想我将不得不调查这个问题。