一次浅拷贝导致的double free

#include <vector>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

using namespace std;
class demo
{
public:
    demo() :buffer(NULL)
    { 
        buffer = new char[200]; 
        strcpy(buffer, "hello world");
    }
    ~demo()
    {
        if (buffer != NULL)
            delete buffer;
        buffer = NULL;
    }
public:
    char *buffer;
};
 
void fun()
{
    demo a;
    vector<demo>  haha;
    haha.push_back(a);
}
 
int main(int argc, char* argv[])
{
    fun();
    printf("执行完毕\r\n");
    getchar();
    return 0;
}
[root@]# g++ test1.cpp -g3 -O0 
[root@]# ./a.out 
*** Error in `./a.out': double free or corruption (!prev): 0x0000000001cc4010 ***
======= Backtrace: =========
/lib64/libc.so.6(+0x7c619)[0x7f3fa5f19619]
./a.out[0x400b09]
./a.out[0x400a2c]
./a.out[0x400a74]
/lib64/libc.so.6(__libc_start_main+0xf5)[0x7f3fa5ebec05]
./a.out[0x400919]
======= Memory map: ========
00400000-00403000 r-xp 00000000 fd:00 151184408                          /home/shiyuefeng/core/1/a.out
00602000-00603000 r--p 00002000 fd:00 151184408                          /home/shiyuefeng/core/1/a.out
00603000-00604000 rw-p 00003000 fd:00 151184408                          /home/shiyuefeng/core/1/a.out
01cc4000-01ce5000 rw-p 00000000 00:00 0                                  [heap]
7f3fa0000000-7f3fa0021000 rw-p 00000000 00:00 0 
7f3fa0021000-7f3fa4000000 ---p 00000000 00:00 0 
7f3fa5e9d000-7f3fa6055000 r-xp 00000000 fd:00 33597608                   /usr/lib64/libc-2.17.so
7f3fa6055000-7f3fa6255000 ---p 001b8000 fd:00 33597608                   /usr/lib64/libc-2.17.so
7f3fa6255000-7f3fa6259000 r--p 001b8000 fd:00 33597608                   /usr/lib64/libc-2.17.so
7f3fa6259000-7f3fa625b000 rw-p 001bc000 fd:00 33597608                   /usr/lib64/libc-2.17.so
7f3fa625b000-7f3fa6260000 rw-p 00000000 00:00 0 
7f3fa6260000-7f3fa6275000 r-xp 00000000 fd:00 35340465                   /usr/lib64/libgcc_s-4.8.5-20150702.so.1
7f3fa6275000-7f3fa6474000 ---p 00015000 fd:00 35340465                   /usr/lib64/libgcc_s-4.8.5-20150702.so.1
7f3fa6474000-7f3fa6475000 r--p 00014000 fd:00 35340465                   /usr/lib64/libgcc_s-4.8.5-20150702.so.1
7f3fa6475000-7f3fa6476000 rw-p 00015000 fd:00 35340465                   /usr/lib64/libgcc_s-4.8.5-20150702.so.1
7f3fa6476000-7f3fa6577000 r-xp 00000000 fd:00 33827070                   /usr/lib64/libm-2.17.so
7f3fa6577000-7f3fa6776000 ---p 00101000 fd:00 33827070                   /usr/lib64/libm-2.17.so
7f3fa6776000-7f3fa6777000 r--p 00100000 fd:00 33827070                   /usr/lib64/libm-2.17.so
7f3fa6777000-7f3fa6778000 rw-p 00101000 fd:00 33827070                   /usr/lib64/libm-2.17.so
7f3fa6778000-7f3fa6861000 r-xp 00000000 fd:00 35340469                   /usr/lib64/libstdc++.so.6.0.19
7f3fa6861000-7f3fa6a61000 ---p 000e9000 fd:00 35340469                   /usr/lib64/libstdc++.so.6.0.19
7f3fa6a61000-7f3fa6a69000 r--p 000e9000 fd:00 35340469                   /usr/lib64/libstdc++.so.6.0.19
7f3fa6a69000-7f3fa6a6b000 rw-p 000f1000 fd:00 35340469                   /usr/lib64/libstdc++.so.6.0.19
7f3fa6a6b000-7f3fa6a80000 rw-p 00000000 00:00 0 
7f3fa6a80000-7f3fa6aa1000 r-xp 00000000 fd:00 33597596                   /usr/lib64/ld-2.17.so
7f3fa6c8f000-7f3fa6c94000 rw-p 00000000 00:00 0 
7f3fa6c9f000-7f3fa6ca1000 rw-p 00000000 00:00 0 
7f3fa6ca1000-7f3fa6ca2000 r--p 00021000 fd:00 33597596                   /usr/lib64/ld-2.17.so
7f3fa6ca2000-7f3fa6ca3000 rw-p 00022000 fd:00 33597596                   /usr/lib64/ld-2.17.so
7f3fa6ca3000-7f3fa6ca4000 rw-p 00000000 00:00 0 
7ffc9f004000-7ffc9f025000 rw-p 00000000 00:00 0                          [stack]
7ffc9f0e5000-7ffc9f0e7000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
已放弃(吐核)
[root@1]# addr2line -e  a.out  0x400a74
/home/shiyuefeng/core/1/test1.cpp:35

addr2line 可以先大概的定位一下core的位置,当然这个不是重点!


接下来解释一波为什么会有double free?

1.首先可以确定double free的对象是char* buff, 因为其他的对象的内存都是在栈上申请的!

2.STL vector 在push 结构体的时候进行拷贝构造函数

补充拷贝构造函数进行测试

#include <vector>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

using namespace std;
class demo
{
public:
    demo() :buffer(NULL)
    { 
        buffer = new char[200]; 
        strcpy(buffer, "hello world");
    }
    
	demo(const demo& src)
	{
		printf("copy assign function\r\n");
	}
	~demo()
	{
		if (buffer != NULL)
			delete buffer;
		buffer = NULL;
	}
public:
    char *buffer;
};
 
void fun()
{
    demo a;
    vector<demo>  haha;
    haha.push_back(a);
}
 
int main(int argc, char* argv[])
{
    fun();
    printf("执行完毕\r\n");
    getchar();
    return 0;
}

运行结果如下:

# ./a.out 
copy assign function
执行完毕

很神奇,这个时候没有core了! 因为刚添加的拷贝构造函数的话 没有对成员变量进行复制,所以fun函数执行结束char* buff 就释放了一次!

默认的拷贝构造的话 会进行浅拷贝,直接将char*buff的指针给复制过去! 所以我们也加上去试试!

#include <vector>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

using namespace std;
class demo
{
public:
    demo() :buffer(NULL)
    { 
        buffer = new char[200]; 
        strcpy(buffer, "hello world");
    }
	demo(const demo& src)
	{
		buffer = src.buffer;
		printf("copy assign function\r\n");
	}
    ~demo()
    {
        if (buffer != NULL)
            delete buffer;
        buffer = NULL;
    }
public:
    char *buffer;
};
 
void fun()
{
    demo a;
    vector<demo>  haha;
    haha.push_back(a);
}
 
int main(int argc, char* argv[])
{
    fun();
    printf("执行完毕\r\n");
    getchar();
    return 0;
}

运行结果:

copy assign function
*** Error in `./a.out': double free or corruption (!prev): 0x0000000001278010 ***
======= Backtrace: =========
/lib64/libc.so.6(+0x7c619)[0x7fc1e2029619]
./a.out[0x400b41]
./a.out[0x400a2c]
./a.out[0x400a74]
/lib64/libc.so.6(__libc_start_main+0xf5)[0x7fc1e1fcec05]
./a.out[0x400919]

这里说明一下: 当删除其中的元素 比如erase clear或pop_back的时候 都会进行析构!

说回那个指针的事情:很明显那个指针会引用了两次,一次是在demo a 这边,另外一个是在vector里面 所以就导致了一个double free的问题,所以要解决这个问题,必须进行深拷贝!

修改代码如下:

#include <vector>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

using namespace std;
class demo
{
public:
    demo() :buffer(NULL)
    { 
        buffer = new char[200]; 
        strcpy(buffer, "hello world");
    }
	demo(const demo& src)
	{
		buffer = new char[200]; 
		memcpy(buffer,src.buffer,strlen(src.buffer));
		printf("copy assign function\r\n");
	}
    ~demo()
    {
		printf("~demo\r\n");
        if (buffer != NULL)
            delete buffer;
        buffer = NULL;
    }
public:
    char *buffer;
};
 
void fun()
{
    demo a;
    vector<demo>  haha;
    haha.push_back(a);
}
 
int main(int argc, char* argv[])
{
    fun();
    printf("执行完毕\r\n");
    getchar();
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值