<Linux,G++> 标准库Bug? 析构函数中删除动态数组时出错.
时间:2010-09-03
来源:互联网
本帖最后由 wonderbeyond 于 2010-09-03 12:41 编辑
经过苦苦探寻, 我发现我的程序错误出在智能指针的析构函数的调用中.
那是在程序结束时, 智能指针的引用计数降为0, 所以释放该智能指针, 智能指针的析构函数的任务是:
释放其持有的 char 型动态分配的内存. 可错误就出在智能指针释放内存时. 为了便于研究, 我把相关部分单独抽出来, 作为一个示例程序:
/////////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <cstring>
using namespace std;
class SmartPtr
{
public:
SmartPtr(char* p) : buf(p), use(1) {}
~SmartPtr() { std::cout << "~SmartPtr() called\n"; delete [] buf; }
char* buf;
int use;
};
int main(int argc, char** argv)
{
SmartPtr ptr(new char(100));
memcpy(ptr.buf, argv[1], strlen(argv[1]));
cout << "got: " << ptr.buf << endl;
return 0;
}
/////////////////////////////////////////////////////////
$g++ test.cc -o test
当程序结束时, ptr超出作用域, 自然就会调用其析构函数释放我们分配的size为100的内存, 但如果
argv[1]的长度大于13时, 程序结束时会产生一大堆错误输出.
下面是执行 ./test "12345678901234" 的输出:
got: 12345678901234
~SmartPtr() called
*** glibc detected *** ./a.out: free(): invalid next size (fast): 0x08981008 ***
======= Backtrace: =========
/lib/tls/i686/cmov/libc.so.6(+0x6b591)[0x246591]
/lib/tls/i686/cmov/libc.so.6(+0x6cde
[0x247de8]
/lib/tls/i686/cmov/libc.so.6(cfree+0x6d)[0x24aecd]
/usr/lib/libstdc++.so.6(_ZdlPv+0x21)[0xe77741]
/usr/lib/libstdc++.so.6(_ZdaPv+0x1d)[0xe7779d]
./a.out[0x80489ac]
./a.out[0x80488e1]
/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe6)[0x1f1bd6]
./a.out[0x80487b1]
======= Memory map: ========
001be000-001d9000 r-xp 00000000 08:02 1179674 /lib/ld-2.11.1.so
001d9000-001da000 r--p 0001a000 08:02 1179674 /lib/ld-2.11.1.so
001da000-001db000 rw-p 0001b000 08:02 1179674 /lib/ld-2.11.1.so
001db000-0032e000 r-xp 00000000 08:02 1311275 /lib/tls/i686/cmov/libc-2.11.1.so
0032e000-0032f000 ---p 00153000 08:02 1311275 /lib/tls/i686/cmov/libc-2.11.1.so
0032f000-00331000 r--p 00153000 08:02 1311275 /lib/tls/i686/cmov/libc-2.11.1.so
00331000-00332000 rw-p 00155000 08:02 1311275 /lib/tls/i686/cmov/libc-2.11.1.so
00332000-00335000 rw-p 00000000 00:00 0
0037c000-0037d000 r-xp 00000000 00:00 0 [vdso]
00a5d000-00a81000 r-xp 00000000 08:02 1311283 /lib/tls/i686/cmov/libm-2.11.1.so
00a81000-00a82000 r--p 00023000 08:02 1311283 /lib/tls/i686/cmov/libm-2.11.1.so
00a82000-00a83000 rw-p 00024000 08:02 1311283 /lib/tls/i686/cmov/libm-2.11.1.so
00c78000-00c95000 r-xp 00000000 08:02 1179732 /lib/libgcc_s.so.1
00c95000-00c96000 r--p 0001c000 08:02 1179732 /lib/libgcc_s.so.1
00c96000-00c97000 rw-p 0001d000 08:02 1179732 /lib/libgcc_s.so.1
00dbc000-00ea5000 r-xp 00000000 08:02 1052341 /usr/lib/libstdc++.so.6.0.13
00ea5000-00ea6000 ---p 000e9000 08:02 1052341 /usr/lib/libstdc++.so.6.0.13
00ea6000-00eaa000 r--p 000e9000 08:02 1052341 /usr/lib/libstdc++.so.6.0.13
00eaa000-00eab000 rw-p 000ed000 08:02 1052341 /usr/lib/libstdc++.so.6.0.13
00eab000-00eb2000 rw-p 00000000 00:00 0
08048000-08049000 r-xp 00000000 08:03 403110 /home/wonder/lab/a.out
08049000-0804a000 r--p 00000000 08:03 403110 /home/wonder/lab/a.out
0804a000-0804b000 rw-p 00001000 08:03 403110 /home/wonder/lab/a.out
08981000-089a2000 rw-p 00000000 00:00 0 [heap]
b7700000-b7721000 rw-p 00000000 00:00 0
b7721000-b7800000 ---p 00000000 00:00 0
b78ea000-b78ec000 rw-p 00000000 00:00 0
b78fc000-b78ff000 rw-p 00000000 00:00 0
bff44000-bff59000 rw-p 00000000 00:00 0 [stack]
已放弃
经过苦苦探寻, 我发现我的程序错误出在智能指针的析构函数的调用中.
那是在程序结束时, 智能指针的引用计数降为0, 所以释放该智能指针, 智能指针的析构函数的任务是:
释放其持有的 char 型动态分配的内存. 可错误就出在智能指针释放内存时. 为了便于研究, 我把相关部分单独抽出来, 作为一个示例程序:
/////////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <cstring>
using namespace std;
class SmartPtr
{
public:
SmartPtr(char* p) : buf(p), use(1) {}
~SmartPtr() { std::cout << "~SmartPtr() called\n"; delete [] buf; }
char* buf;
int use;
};
int main(int argc, char** argv)
{
SmartPtr ptr(new char(100));
memcpy(ptr.buf, argv[1], strlen(argv[1]));
cout << "got: " << ptr.buf << endl;
return 0;
}
/////////////////////////////////////////////////////////
$g++ test.cc -o test
当程序结束时, ptr超出作用域, 自然就会调用其析构函数释放我们分配的size为100的内存, 但如果
argv[1]的长度大于13时, 程序结束时会产生一大堆错误输出.
下面是执行 ./test "12345678901234" 的输出:
got: 12345678901234
~SmartPtr() called
*** glibc detected *** ./a.out: free(): invalid next size (fast): 0x08981008 ***
======= Backtrace: =========
/lib/tls/i686/cmov/libc.so.6(+0x6b591)[0x246591]
/lib/tls/i686/cmov/libc.so.6(+0x6cde

/lib/tls/i686/cmov/libc.so.6(cfree+0x6d)[0x24aecd]
/usr/lib/libstdc++.so.6(_ZdlPv+0x21)[0xe77741]
/usr/lib/libstdc++.so.6(_ZdaPv+0x1d)[0xe7779d]
./a.out[0x80489ac]
./a.out[0x80488e1]
/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe6)[0x1f1bd6]
./a.out[0x80487b1]
======= Memory map: ========
001be000-001d9000 r-xp 00000000 08:02 1179674 /lib/ld-2.11.1.so
001d9000-001da000 r--p 0001a000 08:02 1179674 /lib/ld-2.11.1.so
001da000-001db000 rw-p 0001b000 08:02 1179674 /lib/ld-2.11.1.so
001db000-0032e000 r-xp 00000000 08:02 1311275 /lib/tls/i686/cmov/libc-2.11.1.so
0032e000-0032f000 ---p 00153000 08:02 1311275 /lib/tls/i686/cmov/libc-2.11.1.so
0032f000-00331000 r--p 00153000 08:02 1311275 /lib/tls/i686/cmov/libc-2.11.1.so
00331000-00332000 rw-p 00155000 08:02 1311275 /lib/tls/i686/cmov/libc-2.11.1.so
00332000-00335000 rw-p 00000000 00:00 0
0037c000-0037d000 r-xp 00000000 00:00 0 [vdso]
00a5d000-00a81000 r-xp 00000000 08:02 1311283 /lib/tls/i686/cmov/libm-2.11.1.so
00a81000-00a82000 r--p 00023000 08:02 1311283 /lib/tls/i686/cmov/libm-2.11.1.so
00a82000-00a83000 rw-p 00024000 08:02 1311283 /lib/tls/i686/cmov/libm-2.11.1.so
00c78000-00c95000 r-xp 00000000 08:02 1179732 /lib/libgcc_s.so.1
00c95000-00c96000 r--p 0001c000 08:02 1179732 /lib/libgcc_s.so.1
00c96000-00c97000 rw-p 0001d000 08:02 1179732 /lib/libgcc_s.so.1
00dbc000-00ea5000 r-xp 00000000 08:02 1052341 /usr/lib/libstdc++.so.6.0.13
00ea5000-00ea6000 ---p 000e9000 08:02 1052341 /usr/lib/libstdc++.so.6.0.13
00ea6000-00eaa000 r--p 000e9000 08:02 1052341 /usr/lib/libstdc++.so.6.0.13
00eaa000-00eab000 rw-p 000ed000 08:02 1052341 /usr/lib/libstdc++.so.6.0.13
00eab000-00eb2000 rw-p 00000000 00:00 0
08048000-08049000 r-xp 00000000 08:03 403110 /home/wonder/lab/a.out
08049000-0804a000 r--p 00000000 08:03 403110 /home/wonder/lab/a.out
0804a000-0804b000 rw-p 00001000 08:03 403110 /home/wonder/lab/a.out
08981000-089a2000 rw-p 00000000 00:00 0 [heap]
b7700000-b7721000 rw-p 00000000 00:00 0
b7721000-b7800000 ---p 00000000 00:00 0
b78ea000-b78ec000 rw-p 00000000 00:00 0
b78fc000-b78ff000 rw-p 00000000 00:00 0
bff44000-bff59000 rw-p 00000000 00:00 0 [stack]
已放弃
作者: wonderbeyond 发布时间: 2010-09-03
本帖最后由 wonderbeyond 于 2010-09-03 12:14 编辑
我现在有点怀疑是标准库Bug了...
我现在有点怀疑是标准库Bug了...
作者: wonderbeyond 发布时间: 2010-09-03
这个程序是否free(): invalid next size,完全是随机的,和13没有关系。
错误的原因是SmartPtr ptr(new char(100));应该是new char[100]
分配的空间根本不够用来存储argv[1]的字符串,所以free的时候就会出错。
错误的原因是SmartPtr ptr(new char(100));应该是new char[100]
分配的空间根本不够用来存储argv[1]的字符串,所以free的时候就会出错。
作者: insnowind 发布时间: 2010-09-03
QUOTE:
这个程序是否free(): invalid next size,完全是随机的,和13没有关系。
错误的原因是SmartPtr ptr(new ch ...
insnowind 发表于 2010-09-03 12:51
错误的原因是SmartPtr ptr(new ch ...
insnowind 发表于 2010-09-03 12:51
大哥, 看了你的回复,我突然抓狂了,

惭愧!
作者: wonderbeyond 发布时间: 2010-09-03
热门阅读
-
office 2019专业增强版最新2021版激活秘钥/序列号/激活码推荐 附激活工具
阅读:74
-
如何安装mysql8.0
阅读:31
-
Word快速设置标题样式步骤详解
阅读:28
-
20+道必知必会的Vue面试题(附答案解析)
阅读:37
-
HTML如何制作表单
阅读:22
-
百词斩可以改天数吗?当然可以,4个步骤轻松修改天数!
阅读:31
-
ET文件格式和XLS格式文件之间如何转化?
阅读:24
-
react和vue的区别及优缺点是什么
阅读:121
-
支付宝人脸识别如何关闭?
阅读:21
-
腾讯微云怎么修改照片或视频备份路径?
阅读:28