`
wengshanjin
  • 浏览: 22668 次
  • 性别: Icon_minigender_1
  • 来自: 广州
最近访客 更多访客>>
社区版块
存档分类
最新评论

C++程序coredump及调试过程

阅读更多
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个字符来说非常浪费。

不知这样实现是否还有问题,欢迎看官拍板
分享到:
评论

相关推荐

    调试Release程序--Dump文件方式

    在Windows平台下用C++开发应用程序,最不想见到的情况恐怕就是程序崩溃,而要想解决引起问题的bug,最困难的应该就是调试release版本了。目前有一些方法可以解决:崩溃地址 + MAP文件;MAP文件;...

    C++(Qt)软件崩溃调试-学会使用ProcDump (5)20230402.pdf

    1. 之前用过的方法DbgHelp、qBreakpad生成Dump、Linux下配置ulimit -c unlimited生成core的方式功能都比较单一,并且需要配置环境,在程序中调用库,使用较为复杂。 2. 而ProcDump 使用非常简单,不需要配置环境,不...

    C++(Qt)软件崩溃调试-学会使用ProcDump.7z

    1. 之前用过的方法DbgHelp、qBreakpad生成Dump、Linux下配置ulimit -c unlimited生成core的方式功能都比较单一,并且需要配置环境,在程序中调用库,使用较为复杂。 2. 而ProcDump 使用非常简单,不需要配置环境,不...

    C++(Qt)软件崩溃调试-学会使用ProcDump(5)20230403.pdf

    1. 之前用过的方法DbgHelp、qBreakpad生成Dump、Linux下配置ulimit -c unlimited生成core的方式功能都比较单一,并且需要配置环境,在程序中调用库,使用较为复杂。 2. 而ProcDump 使用非常简单,不需要配置环境,不...

    cpp-nocoredump可以捕获指针异常内存溢出等错误的代码

    nocoredump是一个可用于捕捉程序中出现严重的错误的程序,它能够捕捉到如下引起程序崩溃的严重bug,同时能够跳过出问题的程序,继续运行程序。 同时在出问题的地方会打印出问题堆栈帮助调试。

    ARM、MIPS、X86、PowerPC反汇编工具V2.0.3

    V1.25.00相对上一版本,相关功能支持动态库文件,查询代码支持无符号目标文件+有符号目标文件,COREDUMP统计、与问题单关联、目标文件/CORE文件/问题单同步;V1.24.02相对上一版本,针对进程主动捕捉异常的信息定制...

    heapdump.rar

    用于定位C++程序内存泄露问题,对于C++内存泄露问题定位较为复杂,同时多数内存泄露定位方式都是事前预判,对于事后的core、dump束手无策

    ARM、MIPS、X86、PowerPC反汇编工具V2.0.2

    V1.25.00相对上一版本,相关功能支持动态库文件,查询代码支持无符号目标文件+有符号目标文件,COREDUMP统计、与问题单关联、目标文件/CORE文件/问题单同步;V1.24.02相对上一版本,针对进程主动捕捉异常的信息定制...

    google_breakpad源码

    breakpad是google开发的一个跨平台C/C++ dump捕获开源库和工具套件,可用来发布删除了编译器调试信息的应用程序。在程序崩溃时,将崩溃信息记录在一个小巧的微软minidump格式文件中,支持将其发送回服务器,并且可以...

    C语言FAQ 常见问题列表

    o 3.14 程序运行正确, 但退出时却 ``core dump''了,怎么回事? o 3.15 可以初始化一个联合吗? o 3.16 枚举和一组预处理的 #define 有什么不同? o 3.17 有什么容易的显示枚举值符号的方法? * 4. 表达式 o...

    你必须知道的495个C语言问题

    2.19 程序运行正确,但退出时却“coredump”(核心转储)了,怎么回事? 联合 2.20 结构和联合有什么区别? 2.21 有办法初始化联合吗? 2.22 有没有一种自动方法来跟踪联合的哪个域在使用? 枚举 2.23 枚举...

    《你必须知道的495个C语言问题》

    2.19 程序运行正确,但退出时却“core dump ”(核心转储)了,怎么回事? 29 联合 30 2.20 结构和联合有什么区别? 30 2.21 有办法初始化联合吗? 30 2.22 有没有一种自动方法来跟踪联合的哪个域在使用? ...

    你必须知道的495个C语言问题(PDF)

    2.14 程序运行正确, 但退出时却“core dump”了,怎么回事? . . . . . 10 2.15 可以初始化一个联合吗? . . . . . . . . . . . . . . . . . . . . . . . 10 2.16 枚举和一组预处理的#define 有什么不同? . . . . ....

    SimIt-ARM-3.0 ARM指令模拟器

    SimIt-ARM-3.0 给予命令行ARM指令模拟器,短小精悍,是研究ARM处理器的好工具,该模拟器既可以运行用户级别的ELF程序,又可以模拟运行Linux操作系统;提供了简单易用的调试命令,可以逐条跟踪指令的执行。 SimIt-...

Global site tag (gtag.js) - Google Analytics