最近的一个C++项目遇到了一个bug,程序会自己退出,日志无报错。反馈来的系统错误信息如下:
*** glibc detected *** ./a: munmap_chunk(): invalid pointer: 0x000000000c67eb28 ***
======= Backtrace: =========
/lib64/libc.so.6(cfree+0x166)[0x375d2729d6]
./a[0x4c8ec3]
./a[0x4ca65b]
./a[0x4d7139]
./a[0x4d7457]
./a[0x4dc049]
./a[0x4dc092]
./a[0x4dc0d0]
./a[0x4dc0ee]
/usr/lib64/libboost_thread.so.1.53.0[0x2b992b0ba114]
/lib64/libpthread.so.0[0x375de0673d]
/lib64/libc.so.6(clone+0x6d)[0x375d2d40cd]
======= Memory map: ========
00400000-005bd000 r-xp 00000000 08:03 2733788 /home/path/a/bin/a
007bd000-007bf000 rw-p 001bd000 08:03 2733788 /home/path/a/bin/a
0c5ba000-0c72e000 rw-p 0c5ba000 00:00 0 [heap]
410ce000-410cf000 ---p 410ce000 00:00 0
410cf000-41acf000 rwxp 410cf000 00:00 0
41acf000-41ad0000 ---p 41acf000 00:00 0
41ad0000-424d0000 rwxp 41ad0000 00:00 0
424d0000-424d1000 ---p 424d0000 00:00 0
424d1000-42ed1000 rwxp 424d1000 00:00 0
42ed1000-42ed2000 ---p 42ed1000 00:00 0
42ed2000-438d2000 rwxp 42ed2000 00:00 0
438d2000-438d3000 ---p 438d2000 00:00 0
438d3000-442d3000 rwxp 438d3000 00:00 0
442d3000-442d4000 ---p 442d3000 00:00 0
442d4000-44cd4000 rwxp 442d4000 00:00 0
44cd4000-44cd5000 ---p 44cd4000 00:00 0
44cd5000-456d5000 rwxp 44cd5000 00:00 0
456d5000-456d6000 ---p 456d5000 00:00 0
456d6000-460d6000 rwxp 456d6000 00:00 0
460d6000-460d7000 ---p 460d6000 00:00 0
460d7000-46ad7000 rwxp 460d7000 00:00 0
375ca00000-375ca1c000 r-xp 00000000 08:03 1660075 /lib64/ld-2.5.so
375cc1b000-375cc1c000 r--p 0001b000 08:03 1660075 /lib64/ld-2.5.so
375cc1c000-375cc1d000 rw-p 0001c000 08:03 1660075 /lib64/ld-2.5.so
375ce00000-375ce14000 r-xp 00000000 08:03 3265266 /usr/lib64/libz.so.1.2.3
375ce14000-375d013000 ---p 00014000 08:03 3265266 /usr/lib64/libz.so.1.2.3
375d013000-375d014000 rw-p 00013000 08:03 3265266 /usr/lib64/libz.so.1.2.3
375d200000-375d34e000 r-xp 00000000 08:03 1660080 /lib64/libc-2.5.so
375d34e000-375d54e000 ---p 0014e000 08:03 1660080 /lib64/libc-2.5.so
375d54e000-375d552000 r--p 0014e000 08:03 1660080 /lib64/libc-2.5.so
375d552000-375d553000 rw-p 00152000 08:03 1660080 /lib64/libc-2.5.so
375d553000-375d558000 rw-p 375d553000 00:00 0
375d600000-375d682000 r-xp 00000000 08:03 1660096 /lib64/libm-2.5.so
375d682000-375d881000 ---p 00082000 08:03 1660096 /lib64/libm-2.5.so
375d881000-375d882000 r--p 00081000 08:03 1660096 /lib64/libm-2.5.so
375d882000-375d883000 rw-p 00082000 08:03 1660096 /lib64/libm-2.5.so
375da00000-375da02000 r-xp 00000000 08:03 1660081 /lib64/libdl-2.5.so
375da02000-375dc02000 ---p 00002000 08:03 1660081 /lib64/libdl-2.5.so
375dc02000-375dc03000 r--p 00002000 08:03 1660081 /lib64/libdl-2.5.so
375dc03000-375dc04000 rw-p 00003000 08:03 1660081 /lib64/libdl-2.5.so
375de00000-375de16000 r-xp 00000000 08:03 1660087 /lib64/libpthread-2.5.so
375de16000-375e015000 ---p 00016000 08:03 1660087 /lib64/libpthread-2.5.so
375e015000-375e016000 r--p 00015000 08:03 1660087 /lib64/libpthread-2.5.so
375e016000-375e017000 rw-p 00016000 08:03 1660087 /lib64/libpthread-2.5.so
375e017000-375e01b000 rw-p 375e017000 00:00 0
3760600000-3760607000 r-xp 00000000 08:03 1660091 /lib64/librt-2.5.so
3760607000-3760807000 ---p 00007000 08:03 1660091 /lib64/librt-2.5.so
3760807000-3760808000 r--p 00007000 08:03 1660091 /lib64/librt-2.5.so
3760808000-3760809000 rw-p 00008000 08:03 1660091 /lib64/librt-2.5.so
3761e00000-3761e0d000 r-xp 00000000 08:03 1660099 /lib64/libgcc_s-4.1.2-20080825.so.1
3761e0d000-376200d000 ---p 0000d000 08:03 1660099 /lib64/libgcc_s-4.1.2-20080825.so.1
376200d000-376200e000 rw-p 0000d000 08:03 1660099 /lib64/libgcc_s-4.1.2-20080825.so.1
3763200000-37632e6000 r-xp 00000000 08:03 3265297 /usr/lib64/libstdc++.so.6.0.8
37632e6000-37634e5000 ---p 000e6000 08:03 3265297 /usr/lib64/libstdc++.so.6.0.8
37634e5000-37634eb000 r--p 000e5000 08:03 3265297 /usr/lib64/libstdc++.so.6.0.8
37634eb000-37634ee000 rw-p 000eb000 08:03 3265297 /usr/lib64/libstdc++.so.6.0.8
37634ee000-3763500000 rw-p 37634ee000 00:00 0
3765c00000-3765c15000 r-xp 00000000 08:03 1660103 /lib64/libnsl-2.5.so
3765c15000-3765e14000 ---p 00015000 08:03 1660103 /lib64/libnsl-2.5.so
3765e14000-3765e15000 r--p 00014000 08:03 1660103 /lib64/libnsl-2.5.so
3765e15000-3765e16000 rw-p 00015000 08:03 1660103 /lib64/libnsl-2.5.so
3765e16000-3765e18000 rw-p 3765e16000 00:00 0
3dd5a00000-3dd7fd7000 r-xp 00000000 08:03 292898 /usr/lib/oracle/11.2/client64/lib/libclntsh.so.11.1
3dd7fd7000-3dd80d6000 ---p 025d7000 08:03 292898 /usr/lib/oracle/11.2/client64/lib/libclntsh.so.11.1
3dd80d6000-3dd826c000 rw-p 025d6000 08:03 292898 /usr/lib/oracle/11.2/client64/lib/libclntsh.so.11.1
3dd826c000-3dd8291000 rw-p 3dd826c000 00:00 0
3dd8400000-3dd8689000 r-xp 00000000 08:03 292897 /usr/lib/oracle/11.2/client64/lib/libnnz11.so
3dd8689000-3dd8788000 ---p 00289000 08:03 292897 /usr/lib/oracle/11.2/client64/lib/libnnz11.so
3dd8788000-3dd87ca000 rw-p 00288000 08:03 292897 /usr/lib/oracle/11.2/client64/lib/libnnz11.so
3dd87ca000-3dd87cc000 rw-p 3dd87ca000 00:00 0
2aaaaaaab000-2aaaac297000 rw-p 2aaaaaaab000 00:00 0
2b992a276000-2b992a29d000 rw-p 2b992a276000 00:00 0
2b992a2a6000-2b992a326000 r-xp 00000000 08:03 3265653 /usr/lib64/liblog4cplus-1.1.so.7
2b992a326000-2b992a525000 ---p 00080000 08:03 3265653 /usr/lib64/liblog4cplus-1.1.so.7
2b992a525000-2b992a52b000 rw-p 0007f000 08:03 3265653 /usr/lib64/liblog4cplus-1.1.so.7
2b992a52b000-2b992a52c000 rw-p 2b992a52b000 00:00 0
2b992a52c000-2b992a538000 r-xp 00000000 08:03 3265656 /usr/lib64/librabbitmq.so.1
2b992a538000-2b992a737000 ---p 0000c000 08:03 3265656 /usr/lib64/librabbitmq.so.1
2b992a737000-2b992a738000 rw-p 0000b000 08:03 3265656 /usr/lib64/librabbitmq.so.1
2b992a738000-2b992a76e000 r-xp 00000000 08:03 3265657 /usr/lib64/libSimpleAmqpClient.so.2
2b992a76e000-2b992a96d000 ---p 00036000 08:03 3265657 /usr/lib64/libSimpleAmqpClient.so.2
2b992a96d000-2b992a970000 rw-p 00035000 08:03 3265657 /usr/lib64/libSimpleAmqpClient.so.2
2b992a970000-2b992a971000 rw-p 2b992a970000 00:00 0
2b992a971000-2b992aabc000 r-xp 00000000 08:03 1432281 /usr/lib/oracle/11.2/client64/lib/libocci.so.11.1
2b992aabc000-2b992abbc000 ---p 0014b000 08:03 1432281 /usr/lib/oracle/11.2/client64/lib/libocci.so.11.1
2b992abbc000-2b992abc7000 rw-p 0014b000 08:03 1432281 /usr/lib/oracle/11.2/client64/lib/libocci.so.11.1
2b992abc7000-2b992abc8000 rw-p 2b992abc7000 00:00 0
2b992abc8000-2b992aca8000 r-xp 00000000 08:03 3131049 /usr/lib64/libiconv.so.2.5.0
2b992aca8000-2b992aea8000 ---p 000e0000 08:03 3131049 /usr/lib64/libiconv.so.2.5.0
2b992aea8000-2b992aeaa000 rw-p 000e0000 08:03 3131049 /usr/lib64/libiconv.so.2.5.0
2b992aeaa000-2b992aeac000 r-xp 00000000 08:03 3265649 /usr/lib64/libboost_system.so.1.53.0
2b992aeac000-2b992b0ac000 ---p 00002000 08:03 3265649 /usr/lib64/libboost_system.so.1.53.0
2b992b0ac000-2b992b0ad000 rw-p 00002000 08:03 3265649 /usr/lib64/libboost_system.so.1.53.0
2b992b0ad000-2b992b0ae000 rw-p 2b992b0ad000 00:00 0
2b992b0ae000-2b992b0c4000 r-xp 00000000 08:03 3265651 /usr/lib64/libboost_thread.so.1.53.0
2b992b0c4000-2b992b2c4000 ---p 00016000 08:03 3265651 /usr/lib64/libboost_thread.so.1.53.0
2b992b2c4000-2b992b2c6000 rw-p 00016000 08:03 3265651 /usr/lib64/libboost_thread.so.1.53.0
2b992b2c6000-2b992b2dc000 r-xp 00000000 08:03 3265660 /usr/lib64/libboost_filesystem.so.1.53.0
2b992b2dc000-2b992b4dc000 ---p 00016000 08:03 3265660 /usr/lib64/libboost_filesystem.so.1.53.0
2b992b4dc000-2b992b4dd000 rw-p 00016000 08:03 3265660 /usr/lib64/libboost_filesystem.so.1.53.0
2b992b4dd000-2b992b4ec000 r-xp 00000000 08:03 585793 /usr/lib64/libboost_date_time.so.1.53.0
2b992b4ec000-2b992b6eb000 ---p 0000f000 08:03 585793 /usr/lib64/libboost_date_time.so.1.53.0
2b992b6eb000-2b992b6ed000 rw-p 0000e000 08:03 585793 /usr/lib64/libboost_date_time.so.1.53.0
2b992b6ed000-2b992b6ee000 rw-p 2b992b6ed000 00:00 0
2b992b6ee000-2b992b7dc000 r-xp 00000000 08:03 3265650 /usr/lib64/libboost_regex.so.1.53.0
2b992b7dc000-2b992b9db000 ---p 000ee000 08:03 3265650 /usr/lib64/libboost_regex.so.1.53.0
2b992b9db000-2b992b9e1000 rw-p 000ed000 08:03 3265650 /usr/lib64/libboost_regex.so.1.53.0
2b992b9e1000-2b992ba5a000 r-xp 00000000 08:03 3328435 /usr/lib64/libboost_serialization.so.1.53.0
2b992ba5a000-2b992bc59000 ---p 00079000 08:03 3328435 /usr/lib64/libboost_serialization.so.1.53.0
2b992bc59000-2b992bc5e000 rw-p 00078000 08:03 3328435 /usr/lib64/libboost_serialization.so.1.53.0
2b992bc5e000-2b992bc61000 rw-p 2b992bc5e000 00:00 0
2b992bc61000-2b992bc69000 r-xp 00000000 08:03 3265659 /usr/lib64/libboost_chrono.so.1.53.0
2b992bc69000-2b992be68000 ---p 00008000 08:03 3265659 /usr/lib64/libboost_chrono.so.1.53.0
2b992be68000-2b992be69000 rw-p 00007000 08:03 3265659 /usr/lib64/libboost_chrono.so.1.53.0
2b992be69000-2b992be6a000 rw-p 2b992be69000 00:00 0
2b992be6a000-2b992be6b000 r-xp 00000000 08:03 3143106 /usr/lib64/libaio.so.1.0.1
2b992be6b000-2b992c06a000 ---p 00001000 08:03 3143106 /usr/lib64/libaio.so.1.0.1
2b992c06a000-2b992c06b000 rw-p 00000000 08:03 3143106 /usr/lib64/libaio.so.1.0.1
2b992c06b000-2b992c06e000 rw-p 2b992c06b000 00:00 0
2b992c06e000-2b9933159000 r-xp 00000000 08:03 1432282 /usr/lib/oracle/11.2/client64/lib/libociei.so
2b9933159000-2b9933258000 ---p 070eb000 08:03 1432282 /usr/lib/oracle/11.2/client64/lib/libociei.so
2b9933258000-2b9933259000 rw-p 070ea000 08:03 1432282 /usr/lib/oracle/11.2/client64/lib/libociei.so
2b9933259000-2b9933263000 r-xp 00000000 08:03 1659771 /lib64/libnss_files-2.5.so
2b9933263000-2b9933462000 ---p 0000a000 08:03 1659771 /lib64/libnss_files-2.5.so
2b9933462000-2b9933463000 r--p 00009000 08:03 1659771 /lib64/libnss_files-2.5.so
2b9933463000-2b9933464000 rw-p 0000a000 08:03 1659771 /lib64/libnss_files-2.5.so
2b9933464000-2b9933469000 r-xp 00000000 08:03 3142822 /usr/lib64/libnuma.so.1
2b9933469000-2b9933668000 ---p 00005000 08:03 3142822 /usr/lib64/libnuma.so.1
2b9933668000-2b9933669000 rw-p 00004000 08:03 3142822 /usr/lib64/libnuma.so.1
2b9933669000-2b993373c000 rw-p 2b9933669000 00:00 0
7fff7d6c1000-7fff7d6d6000 rwxp 7ffffffe9000 00:00 0 [stack]
7fff7d7fc000-7fff7d800000 r-xp 7fff7d7fc000 00:00 0 [vdso]
ffffffffff600000-ffffffffffe00000 ---p 00000000 00:00 0 [vsyscall]
这里一大堆信息,
munmap_chunk(): invalid pointer
也就只有这句可以看了,“无效的指针”。查阅一些资料后,大致了解这个问题可能是new的一个指针,中间经过了改动,再调用delete出现的问题。
仔细看自己动过的代码的部分,是有一个函数开头有new出来的数组,函数结束时delete[]掉,中间的代码,有一句是这样的,
char *a = new char[300];
char b[30] = { 0 };
memset(a, 0, sizeof(Contect));
sprintf(b, "%u", temp->EventID);
OneClass oneClass;
a = const_cast(oneClass.mFunction(b).c_str());
boost::shared_ptr< std::string> buff(new std::string(a));
doSomething(buff);
delete[]a;
return 0;
仔细看
a = const_cast(oneClass.mFunction(b).c_str());
这一行代码写的很差,首先就是这个地方确实改变了指针a,a本身的值变化了。delete时就会出现无效指针的错误。
至少给数组赋值应该用memcpy或snprintf函数来做。
另外这这个直接这样也可能会溢出。
然后决定用std::string替换char[]。事实上也确实不需要用char[]的,转化来转化去,增加了复杂度和风险。
这个问题也就解决了。
无效指针没了。段错误(Segmentation fault)来了,表现也是程序自己退出。
gdb直接运行的信息。
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x40a00940 (LWP 28517)]
0x00000037632b76d2 in __gnu_cxx::__exchange_and_add(int volatile*, int) () from /usr/lib64/libstdc++.so.6
好在gdb可以方便的调试,至少告知大概位置,好去修改,自己也肉眼排查了一些代码。
看到了一个地方
log("u: , info: %s ", u, info.c_str());
这个是写日志的一行,类型不匹配,u是一个unsigned int型的,这里漏写了一个%u,实际效果是把u当成一个字符串,会去寻找‘\0’,单测这句就会段错误。
几乎可以得出结论,是这行代码的问题了,输出日志本来是为了定位问题,结果却制造了麻烦。
还是用gdb调试一下,在段错误之后。执行where或bt命令,会输出数字编号的数条信息,从最内层一直到最外层,在中间的某些层,可以看到自己熟悉的自己的几个函数。
信息明确的指向错误发生在某个函数之中。考虑各函数调用关系,可以看到自己肉眼找到那行也在这个范围之内。当然后面肯定第一时间用gdb而不是肉眼,毕竟有运气的成分。
在这个过程中,已修改了其它部分的一些代码,主要就是替换一些旧代码里的char[],确实c风格的字符数组并不是一个好的选择,如非必要尽量少用。
当然也告诉我们,角角落落的每一个分支都要测试到,不然可能某些貌似简单的地方也会出大问题。