printf大坑等着很多人------一次core dump经历及定位过程(printf打印C++ string的时候忘了.c_st()转化)

        听一位前辈说过, 某次, 在某工程中, 一句打印日志的代码导致程序低概率性崩溃, 很多人一起搞了3-4天才找出元凶, 本质上就是printf的误用。 代码本该要写成printf("decoded msg is %s", szDecode); 结果代码写成了printf("decoded msg is %s");  在实际开发中, 很多打印日志的函数都与printf类似, 当要打印的参数较多时, 经常容易漏参、多参, 或者参数类型不匹配。 有些时候, 编译器不报错。

        我亲自见证过, 有些低概率崩溃问题, 非常不好重现, 但必须解决, 很多人一起尝试重现、定位、修改、验证, 动辄就是一个星期甚至更长。


        最近呢,我终于踩上了printf的坑了, 在利用printf打印C++ string的时候, 忘了带上.c_str().  害得浪费我半小时。 为了简便起见, 我仅用示意代码test.cpp:

#include 
#include 
#include 
using namespace std;

int main()
{
        string s = "good";
        printf("%s\n", s);
        return 0;
}
       为了方便后面的调试, 先用ulimit -c 1000命令打开core开关(之前博文有讲过)。 编译运行如下:

taoge@localhost test> g++ -g test.cpp 
test.cpp: In function 鈥榠nt main()鈥

                                      test.cpp:9: warning: cannot pass objects of non-POD type 鈥榮truct std::string鈥through 鈥..鈥 call will abort at runtime
taoge@localhost test> ls
a.out  test.cpp
taoge@localhost test> ./a.out 
Illegal instruction (core dumped)
taoge@localhost test> ls
a.out  core.2740  test.cpp
taoge@localhost test> 

       可以看到, 编译的时候是有warning的, 运行的时候, 出现了core dump.  实际上, 在大型代码开发中, 很少有人去关注编译过程中的告警(因为太多)。 下面我们用博文中之前介绍过的方法来调试core, 如下:

taoge@localhost test> ls
a.out  core.2740  test.cpp
taoge@localhost test> clear
taoge@localhost test> ls
a.out  core.2740  test.cpp
taoge@localhost test> cat test.cpp -n
     1  #include 
     2  #include 
     3  #include 
     4  using namespace std;
     5
     6  int main()
     7  {
     8          string s = "good";
     9          printf("%s\n", s);
    10          return 0;
    11  }
taoge@localhost test> 
taoge@localhost test> 
taoge@localhost test> 
taoge@localhost test> gdb a.out core.2740 
GNU gdb (GDB) Red Hat Enterprise Linux (7.1-29.el6)
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later 
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-redhat-linux-gnu".
For bug reporting instructions, please see:
...
Reading symbols from /home/taoge/test/a.out...done.
[New Thread 2740]
Missing separate debuginfo for 
Try: yum --disablerepo='*' --enablerepo='*-debuginfo' install /usr/lib/debug/.build-id/74/d23352fd770753e375bd0caecf375bd77bded5
Reading symbols from /usr/lib/libstdc++.so.6...(no debugging symbols found)...done.
Loaded symbols for /usr/lib/libstdc++.so.6
Reading symbols from /lib/libm.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib/libm.so.6
Reading symbols from /lib/libgcc_s.so.1...(no debugging symbols found)...done.
Loaded symbols for /lib/libgcc_s.so.1
Reading symbols from /lib/libc.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib/ld-linux.so.2
Core was generated by `./a.out'.
Program terminated with signal 4, Illegal instruction.
#0  0x080486b1 in main () at test.cpp:8
8               string s = "good";
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.7.el6.i686 libgcc-4.4.4-13.el6.i686 libstdc++-4.4.4-13.el6.i686
(gdb) 
(gdb) 
(gdb) 
(gdb) bt
#0  0x080486b1 in main () at test.cpp:8
(gdb) 
       可以看到, 定位到了代码的第8行。


       如上是有core的core dump问题, 如果是没有core的core dump问题, 那就更惨了。 在大型代码中, 这种问题非常不好找, 如果体现出低概率性, 那就几乎是要命了。 所以, 我们千万不能小看日志的打印, 参数个数、类型都要严格匹配。

       总结一下:

        1. 程序员自己写代码的时, 要提前警惕此类错误。

        2. 公司要引进自动检测工具(静态和动态都需要考虑, 但是, 很多公司买不起)

        3. 定期代码走查和检视。

        4. 万一出了此类问题, 要学会定位处理哈。



        最后, 不好意思说一句, 其实, 我没有踩过一次printf坑, 因为, 我已经踩过两次了。 

        core dump, 你妹的!



你可能感兴趣的:(S1:,C/C++,s2:,软件进阶,s2:,Linux编程,s2:,Linux杂项,s2:,嵌入式,s2:,后台开发)