头文件不匹配导致的崩溃问题
来源:互联网 发布:免费收银软件哪个好 编辑:程序博客网 时间:2024/04/29 17:38
虽然问题解决了,但其中的奥秘还不甚了解,这里只是暂时做一个存档。
今天项目中遇到一个崩溃问题,崩溃点随机,调试的时候,单步跟踪调试也很诡异,处理了好一段时间也没有解决 ,然后组长说该项目其他人也在维护,他们修改了某个模块,但是头文件好像没有上传,更新头文件后,重新编译运行,果然不再崩溃了,bug解决了。
总结:
问题的原因是:头文件和源文件不匹配导致的,但是能够编译过。
这样的问题这是第二次遇到,在遇到运行时崩溃,崩溃点随机,且单步跟踪调试代码比较诡异(如感觉调试时代码不匹配,某个变量值发生莫名的变化(赋值之后不应该变化)等)的现象时,可以考虑是不是头文件与库文件或是源文件不匹配的情况。但是头文件不匹配会怎样,原理是什么还没有搞明白。
以下是转载:原文链接:http://blog.csdn.net/zdl1016/article/details/8690061
头文件和.a(库文件不匹配)导致虚函数错位,进而导致的bug
头文件和.a(库文件不匹配)导致虚函数错位,进而导致的bug
该bug的快速定位技巧
bt查看函数调用堆栈. 如果堆栈的顺序错乱, 则可能是虚函数表错乱导致.
本例中, GetTPLContent 的上层很明显不应该是 DealInput, 因为DealInput没有调用GetTPLContent
故障回顾:
某日遇到一个奇葩bug, 进程core, 查看堆栈, core的位置没有任何异常, 在一个不可能出问题的地方出错了. 只根据core文件在生产环境无法排查.
在开发机生把cgi编译成可执行文件, 用gdb跟踪, 发现在 单步跟进 BeforeProcess() 函数时, 却意外的跳到了 GetTPLContent()函数接下来就是core了.
中断现场如下:
rogram received signal SIGSEGV, Segmentation fault.
[Switching to Thread -1211028832 (LWP 10060)]
0xb7ef2422 in std::string::compare () from /usr/lib/libstdc++.so.6
(gdb) bt
#0 0xb7ef2422 in std::string::compare () from /usr/lib/libstdc++.so.6
#1 0x08055e5c in std::operator==<char, std::char_traits<char>, std::allocator<char> > (__lhs=@0xbfcd60ec, __rhs=0x82a080e "json")
at /usr/include/c++/4.1.0/bits/basic_string.h:2163
#2 0x0804eea0 in CMyCGI::GetTPLContent (this=0xbfcd505c) at src/mb_get_app_friends.cpp:165
#3 0x08260eb0 in COpenAPIBase::DealInput (this=0xbfcd4128, params=@0xbfcd505c) at src/openapi_base.cpp:239
#4 0x0821b9af in CCGIEx::Run (this=0xbfcd4128, pszTemplateFile=0x0) at cgiex.cpp:248
#5 0x08051205 in main () at src/mb_get_app_friends.cpp:386
把栈帧定位到COpenAPIBase::DealInput上
(gdb) frame 3
#3 0x08260eb0 in COpenAPIBase::DealInput (this=0xbfcd4128, params=@0xbfcd505c) at src/openapi_base.cpp:239
239 BeforeProcess(params);
(gdb) l
234 //把参数转化成值
235 TransParams(params);
236 //填充出authinfo
237 FillOpenAPIInfo();
238
239 BeforeProcess(params);
240 m_mod_ret = Process(params);
241 AfterProcess(params);
242 return true;
243 }
查看汇编
(gdb) disassemble
Dump of assembler code for function _ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE:
0x08260e76 <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+0>: push %ebp
0x08260e77 <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+1>: mov %esp,%ebp
0x08260e79 <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+3>: push %esi
0x08260e7a <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+4>: push %ebx
0x08260e7b <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+5>: sub $0x10,%esp
0x08260e7e <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+8>: mov 0x8(%ebp),%ebx
0x08260e81 <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+11>: mov 0xc(%ebp),%esi
0x08260e84 <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+14>: mov (%ebx),%eax
0x08260e86 <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+16>: mov %esi,0x4(%esp)
0x08260e8a <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+20>: mov %ebx,(%esp)
0x08260e8d <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+23>: call *0x10(%eax) // 虚函数 GetDftParams
0x08260e90 <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+26>: mov %esi,0x4(%esp)
0x08260e94 <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+30>: mov %ebx,(%esp)
0x08260e97 <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+33>: call 0x8260684 <_ZN12COpenAPIBase11TransParamsERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE>
0x08260e9c <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+38>: mov %ebx,(%esp)
0x08260e9f <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+41>: call 0x825fbcc <_ZN12COpenAPIBase15FillOpenAPIInfoEv>
0x08260ea4 <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+46>: mov (%ebx),%eax
0x08260ea6 <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+48>: mov %esi,0x4(%esp)
0x08260eaa <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+52>: mov %ebx,(%esp)
0x08260ead <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+55>: call *0x18(%eax) // 虚函数 BeforeProcess
0x08260eb0 <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+58>: mov (%ebx),%eax
0x08260eb2 <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+60>: mov %esi,0x4(%esp)
0x08260eb6 <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+64>: mov %ebx,(%esp)
0x08260eb9 <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+67>: call *0x20(%eax) // 虚函数 Process
0x08260ebc <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+70>: mov %eax,0xf94(%ebx)
0x08260ec2 <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+76>: mov (%ebx),%eax
0x08260ec4 <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+78>: mov %esi,0x4(%esp)
0x08260ec8 <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+82>: mov %ebx,(%esp)
0x08260ecb <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+85>: call *0x1c(%eax) // 虚函数 AfterProcess
0x08260ece <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+88>: mov $0x1,%eax
0x08260ed3 <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+93>: add $0x10,%esp
0x08260ed6 <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+96>: pop %ebx
0x08260ed7 <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+97>: pop %esi
0x08260ed8 <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+98>: pop %ebp
0x08260ed9 <_ZN12COpenAPIBase9DealInputERSt3mapISsSsSt4lessISsESaISt4pairIKSsSsEEE+99>: ret
这个时候, 如果嗅觉敏锐就已经可以看到问题了, TransParams 在头文件里是个虚函数, 理论上是无法在反汇编里直接看到函数符号的 (因为虚函数的具体的地址, 只有在运行时才能决定)
进一步验证
单步执行时, 当执行到BeforeProcess时, s跳进去, 代码却跳到 GetTPLContent, 因此严重怀疑是 我使用的头文件 和 .a库不匹配导致.
头文件更新了, .a库却没有更新, 如果头文件中新增虚函数, 将导致虚函数表中各个虚函数的位置发生改变, 而.a却使用旧的虚函数表!
重新编译.a库后bug消失.
这个bug让我想起了以前在windows环境下遭遇的著名的"dll地狱"bug, 都是由于虚函数表错位导致的.
- 头文件不匹配导致的崩溃问题
- 头文件和.a(库文件不匹配)导致虚函数错位,进而导致的bug
- iOS开发笔记之二十一——类型不匹配导致的app崩溃问题(bug总结二)
- 动态库的头文件和 .lib 文件不匹配引发的问题
- 超级崩溃之头文件错误导致error LNK1120: 1 个无法解析的外部命令
- 头文件和Dll不一致导致的问题
- 浅谈自定义头文件可能导致的重定义问题
- String数据编码导致不匹配问题
- 因WKWebview导致视图控制器释放不掉而内存崩溃的问题
- 因WKWebview导致视图控制器释放不掉而内存崩溃的问题
- ListView 添加footView导致崩溃的问题
- findContours导致MFC程序崩溃的问题
- gradle更新导致的litpal崩溃问题
- WriteFile导致程序崩溃的问题
- VMware6.5安装Fedora14 安装 VMware Tools 头文件不匹配的处理过程
- snprintf类型不匹配导致的core dump问题分析与定位
- 头文件相互包含导致的错误
- 缺少头文件导致的段错误
- STL algorithm算法equal(12)
- 实际用户ID”、“有效用户ID”和“保存的设置用户ID”
- Android学习之路
- Linux下vim的配置
- ios-使用ios 6苹果地图定位和跟踪
- 头文件不匹配导致的崩溃问题
- qt 解决空间中文显示问题
- 迅为三星四核 cortex a9 + Linux开发板特点介绍
- handler thread asynctask runnable 分析
- 使用uploadify3上传图片的示例支持图片预览
- MongoDB基本管理命令
- Linux下的最基本的几个命令
- Longest Palindromic Substring
- 田寨村葡萄