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, 你妹的!
- printf大坑等着很多人------一次core dump经历及定位过程(printf打印C++ string的时候忘了.c_st()转化)
- printf的时候打印%号
- 为什么打印log(比如printf)会经常碰到core dump?
- 又是打印log引发的core dump------类似printf("msg is %s", 1);
- 关于delete的时候core dump的调试经历
- c语言中 printf的打印类型
- 关于C语言的printf打印对齐
- VS打印printf等传出的打印信息
- printf 的打印格式
- printf的打印格式
- C语言中控制printf的打印颜色实例及vt100的控制符文档
- C语言中控制printf的打印颜色实例及vt100的控制符文档
- C语言中控制printf的打印颜色实例及vt100的控制符文档
- C语言中控制printf的打印颜色实例及vt100的控制符文档-转
- C语言中控制printf的打印颜色实例及vt100的控制符
- 一个低概率core dump问题的定位------打印log时访问了长度为0的vector
- printf打印
- printf打印
- python网络爬虫的记录
- Android高级控件----AdapterView与Adapter
- Linux 初始化 init 系统,第 1 部分: sysvinit
- 例题5-1 UVA 11292 The Dragon of Loowater勇者斗恶龙
- docker安装gitlab记录
- printf大坑等着很多人------一次core dump经历及定位过程(printf打印C++ string的时候忘了.c_st()转化)
- 使用Caffe尝试DeepID
- Android Studio从4.4升级所有版本SDK
- 【C语言提高33】数组指针类型定义
- Linux 初始化 init 系统,第 2 部分: UpStart
- redis基本命令及应用场景
- LeetCode 172:Factorial Trailing Zeroes
- Linux 初始化 init 系统,第 3 部分: Systemd
- Android之基于xmpp openfire smack开发之smack类库介绍和使用[2]