什么是Core Dump?
Core的意思是内存, Dump的意思是扔出来, 堆出来.
开发和使用Unix程序时, 有时程序莫名其妙的down了, 却没有任何的提示(有时候会提示core dumped). 这时候可以查看一下有没有形如core.进程号的文件生成, 这个文件便是操作系统把程序down掉时的内存内容扔出来生成的, 它可以做为调试程序的参考.
core dump又叫核心转储, 当程序运行过程中发生异常, 程序异常退出时, 由操作系统把程序当前的内存状况存储在一个core文件中, 叫core dump.
如何使用core文件?
gdb -c core文件路径 [应用程序的路径]
进去后输入where回车, 就可以显示程序在哪一行当掉的, 在哪个函数中.
为什么没有core文件生成呢?
有时候程序down了, 但是core文件却没有生成. core文件的生成跟你当前系统的环境设置有关系, 可以用下面的语句设置一下, 然后再运行程序便成生成core文件.
ulimit -c unlimited
core文件生成的位置一般于运行程序的路径相同, 文件名一般为core.进程号
4. 用gdb查看core文件:
下面我们可以在发生运行时信号引起的错误时发生core dump了.
发生core dump之后, 用gdb进行查看core文件的内容, 以定位文件中引发core dump的行.
gdb [exec file] [core file]
如:
gdb ./test test.core
在进入gdb后, 用bt命令查看backtrace以检查发生程序运行到哪里, 来定位core dump的文件->行.
文章出处:飞诺网(www.diybl.com):http://www.diybl.com/course/3_program/c++/cppjs/20090307/158855.html
- class TSimpleString
- {
- public:
- typedef char charT;
- TSimpleString() : m_pStorage(NULL) {}
- ~TSimpleString() { clear(); }
- TSimpleString(const TSimpleString& p) { reset(p.m_pStorage); }
- TSimpleString(const charT * pStorage) { reset(pStorage); }
- TSimpleString & operator = (const TSimpleString& p) { reset(p.m_pStorage); return *this; }
- TSimpleString & operator = (const charT * pStorage) { reset(pStorage); return *this; }
- bool empty(void) const { return (m_pStorage == NULL); }
- void clear(void);
- void reset(const charT * pSrc);
- const charT * get(void) const; //如果m_pStorage==NULL, return TStringHelper::g_strEmptyString
- private:
- charT * m_pStorage;
- };
- void TSimpleString::clear()
- {
- if( m_pStorage != NULL )
- {
- delete []m_pStorage;
- m_pStorage = NULL;
- }
- }
- void TSimpleString::reset(const TSimpleString::charT * pSrc)
- {
- if( m_pStorage == pSrc )
- return;
- clear();
- size_t nLen = (pSrc == NULL) ? 0 : TStringHelper::length(pSrc);
- if( nLen > 0 )
- {
- m_pStorage = new charT [nLen + 1];
- TStringHelper::strCpyByCount(m_pStorage, pSrc, nLen);
- }
- }
- const TSimpleString::charT * TSimpleString::get(void) const
- {
- if( m_pStorage == NULL )
- return TStringHelper::g_strEmptyString.c_str();
- return m_pStorage;
- }
- void onTestSimpleString()
- {
- TSimpleString str1;
- std::cout << "str1:" << str1.get() << std::endl;
- TSimpleString str2("str2");
- std::cout << "str2:" << str2.get() << std::endl;
- TSimpleString str3(str2);
- std::cout << "str3:" << str3.get() << std::endl;
- str3 = "str3";
- std::cout << "str3:" << str3.get() << std::endl;
- TSimpleString str4 = str3;
- std::cout << "str4:" << str4.get() << std::endl;
- }
class TSimpleString { public: typedef char charT; TSimpleString() : m_pStorage(NULL) {} ~TSimpleString() { clear(); } TSimpleString(const TSimpleString& p) { reset(p.m_pStorage); } TSimpleString(const charT * pStorage) { reset(pStorage); } TSimpleString & operator = (const TSimpleString& p) { reset(p.m_pStorage); return *this; } TSimpleString & operator = (const charT * pStorage) { reset(pStorage); return *this; } bool empty(void) const { return (m_pStorage == NULL); } void clear(void); void reset(const charT * pSrc); const charT * get(void) const; //如果m_pStorage==NULL, return TStringHelper::g_strEmptyString private: charT * m_pStorage; }; void TSimpleString::clear() { if( m_pStorage != NULL ) { delete []m_pStorage; m_pStorage = NULL; } } void TSimpleString::reset(const TSimpleString::charT * pSrc) { if( m_pStorage == pSrc ) return; clear(); size_t nLen = (pSrc == NULL) ? 0 : TStringHelper::length(pSrc); if( nLen > 0 ) { m_pStorage = new charT [nLen + 1]; TStringHelper::strCpyByCount(m_pStorage, pSrc, nLen); } } const TSimpleString::charT * TSimpleString::get(void) const { if( m_pStorage == NULL ) return TStringHelper::g_strEmptyString.c_str(); return m_pStorage; } void onTestSimpleString() { TSimpleString str1; std::cout << "str1:" << str1.get() << std::endl; TSimpleString str2("str2"); std::cout << "str2:" << str2.get() << std::endl; TSimpleString str3(str2); std::cout << "str3:" << str3.get() << std::endl; str3 = "str3"; std::cout << "str3:" << str3.get() << std::endl; TSimpleString str4 = str3; std::cout << "str4:" << str4.get() << std::endl; }
上面这段代码,运行onTestSimpleString()会coredump,运行结果是
str1:
*** glibc detected *** free(): invalid pointer: 0x00cacff4 ***
Abort
刚开始还看不出哪里的问题,于是想到先让程序coredump,有了core调试就容易很多。
1,切换到root用户,再用ulimit -c 1234567设置生成core
2,执行程序,输出的结果看到已经生成core文件了
str1:
*** glibc detected *** free(): invalid pointer: 0x00cacff4 ***
已放弃 (core dumped)
3,分析core
(gdb) bt
#0 0x00b687a2 in _dl_sysinfo_int80 () from /lib/ld-linux.so.2
#1 0x00bad7a5 in raise () from /lib/tls/libc.so.6
#2 0x00baf209 in abort () from /lib/tls/libc.so.6
#3 0x00be171a in __libc_message () from /lib/tls/libc.so.6
#4 0x00be7fbf in _int_free () from /lib/tls/libc.so.6
#5 0x00be833a in free () from /lib/tls/libc.so.6
#6 0x001dbfd1 in operator delete () from /usr/lib/libstdc++.so.6
#7 0x001dc01d in operator delete[] () from /usr/lib/libstdc++.so.6
#8 0x08052375 in cmx::TSimpleString::clear (this=0xbff2b880) at ../util/testsimplestring.cpp:25
#9 0x080523a2 in cmx::TSimpleString::reset (this=0xbff2b880, pSrc=0x842e4d8 "str2") at ../util/testsimplestring.cpp:35
#10 0x08062aaa in TSimpleString (this=0xbff2b880, pStorage=0x842e4d8 "str2") at ../util/testsimplestring.cpp:8
#11 0x0805249b in cmx::onTestSimpleString () at ../util/testsimplestring.cpp:68
分析core以为是TSimpleString::reset不应该判断if( m_pStorage == pSrc ),但是去掉这个判断再运行还是出错。分析core搞不定,只好用上valgrind,用valgrind一运行,错误的地方就全部出来了。
4,运行valgrind
==30827== Conditional jump or move depends on uninitialised value(s)
==30827== at 0x8052393: TSimpleString::reset(char const*) (testsimplestring.cpp:32)
==30827== by 0x8062AA9: TSimpleString::TSimpleString(char const*) (testsimplestring.cpp:8)
==30827== by 0x805249A: onTestSimpleString() (testsimplestring.cpp:68)
可看出在第8行根据const charT * pStorage构造TSimpleString时调用了TSimpleString::reset,而在TSimpleString::reset的32行使用了未初始化的m_pStorage。这时再看回TSimpleString(const charT * pStorage) { reset(pStorage); }就知道,确实是还没初始化m_pStorage。杯具阿
- TSimpleString(const TSimpleString& p) { reset(p.m_pStorage); }
- TSimpleString(const charT * pStorage) { reset(pStorage); }
TSimpleString(const TSimpleString& p) { reset(p.m_pStorage); } TSimpleString(const charT * pStorage) { reset(pStorage); }
这两行代码都没有初始化就使用了m_pStorage,应该改成
- TSimpleString(const TSimpleString& p) : m_pStorage(NULL) { reset(p.m_pStorage); }
- TSimpleString(const charT * pStorage) : m_pStorage(NULL) { reset(pStorage); }
TSimpleString(const TSimpleString& p) : m_pStorage(NULL) { reset(p.m_pStorage); } TSimpleString(const charT * pStorage) : m_pStorage(NULL) { reset(pStorage); }
再说下写这个类的目的:
因为要存储很多长度很短(只有10来个字符)的字符串对象,这些对象一旦保存后就不再修改,并且很多时候这些字符串是空的,所以不想用std::string来保存。因为std::string不管有没有存储内容都要用3个指针,这对于只存储10个字符来说非常浪费。
不知这样实现是否还有问题,欢迎看官拍板