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

来源:互联网 发布:ab模板源码 百度网盘 编辑:程序博客网 时间:2024/05/23 01:23

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

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


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

#include <cstdio>#include <iostream>#include <string>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 runtimetaoge@localhost test> lsa.out  test.cpptaoge@localhost test> ./a.out Illegal instruction (core dumped)taoge@localhost test> lsa.out  core.2740  test.cpptaoge@localhost test> 

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

taoge@localhost test> lsa.out  core.2740  test.cpptaoge@localhost test> cleartaoge@localhost test> lsa.out  core.2740  test.cpptaoge@localhost test> cat test.cpp -n     1  #include <cstdio>     2  #include <iostream>     3  #include <string>     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 <http://gnu.org/licenses/gpl.html>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:<http://www.gnu.org/software/gdb/bugs/>...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/d23352fd770753e375bd0caecf375bd77bded5Reading symbols from /usr/lib/libstdc++.so.6...(no debugging symbols found)...done.Loaded symbols for /usr/lib/libstdc++.so.6Reading symbols from /lib/libm.so.6...(no debugging symbols found)...done.Loaded symbols for /lib/libm.so.6Reading symbols from /lib/libgcc_s.so.1...(no debugging symbols found)...done.Loaded symbols for /lib/libgcc_s.so.1Reading symbols from /lib/libc.so.6...(no debugging symbols found)...done.Loaded symbols for /lib/libc.so.6Reading symbols from /lib/ld-linux.so.2...(no debugging symbols found)...done.Loaded symbols for /lib/ld-linux.so.2Core was generated by `./a.out'.Program terminated with signal 4, Illegal instruction.#0  0x080486b1 in main () at test.cpp:88               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, 你妹的!



1 0
原创粉丝点击