论坛首页 编程语言技术论坛

C++程序coredump及调试过程

浏览 4769 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2010-05-22   最后修改:2010-05-22
C++
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); }

这两行代码都没有初始化就使用了m_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个字符来说非常浪费。

不知这样实现是否还有问题,欢迎看官拍板
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics