头文件不匹配导致的崩溃问题

来源:互联网 发布:免费收银软件哪个好 编辑:程序博客网 时间: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, 都是由于虚函数表错位导致的.





0 0