双释放错误释放 1000 个字节

Posted

技术标签:

【中文标题】双释放错误释放 1000 个字节【英文标题】:double free error freeing 1000 bytes 【发布时间】:2013-08-25 17:32:21 【问题描述】:

我写了一个小程序来测试内存中的分配+访问时间:

#include <stdio.h>
#include <stdlib.h>

int main (int argc, char *argv[])

    if (argc < 2)
    
        printf("fail, %d args\n", argc);
        return 1;
    

    char *a;
    int i;

    long long int stress_size = atoi(argv[1]);

    a = malloc(stress_size);
    printf("%Ld bytes allocated\n", stress_size);
    printf("a is here:     %p\n", a);
    for (i = 0; i < stress_size; ++i)
    
        a++;
        *a = 4;
    
    printf("a is here now: %p\n", a);

    a -= stress_size / sizeof(char);
    printf("back to original position\n");
    printf("a is here now: %p\n", a);
    printf("pre-free\n");
    free(a);
    printf("free ok\n");
    return 0;
 

该程序甚至适用于高值(400M 字节),但它在确切的字节数时失败:1000。

$ ./main 1000
1000 bytes allocated
a is here:     0x1c81010
a is here now: 0x1c813f8
back to original position
a is here now: 0x1c81010
pre-free
*** glibc detected *** ./main: double free or corruption (!prev): 0x0000000001c81010 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x76d76)[0x7f9133438d76]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x6c)[0x7f913343daac]
./main[0x4008cf]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xfd)[0x7f91333e0ead]
./main[0x4006e9]
======= Memory map: ========
00400000-00401000 r-xp 00000000 08:03 928478                             /home/alex/programmazione/c/memory_long_stress_test/main
00600000-00601000 rw-p 00000000 08:03 928478                             /home/alex/programmazione/c/memory_long_stress_test/main
01c81000-01ca2000 rw-p 00000000 00:00 0                                  [heap]
7f912c000000-7f912c021000 rw-p 00000000 00:00 0 
7f912c021000-7f9130000000 ---p 00000000 00:00 0 
7f91331ac000-7f91331c1000 r-xp 00000000 08:03 1966084                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f91331c1000-7f91333c1000 ---p 00015000 08:03 1966084                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f91333c1000-7f91333c2000 rw-p 00015000 08:03 1966084                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f91333c2000-7f9133542000 r-xp 00000000 08:03 1966099                    /lib/x86_64-linux-gnu/libc-2.13.so
7f9133542000-7f9133742000 ---p 00180000 08:03 1966099                    /lib/x86_64-linux-gnu/libc-2.13.so
7f9133742000-7f9133746000 r--p 00180000 08:03 1966099                    /lib/x86_64-linux-gnu/libc-2.13.so
7f9133746000-7f9133747000 rw-p 00184000 08:03 1966099                    /lib/x86_64-linux-gnu/libc-2.13.so
7f9133747000-7f913374c000 rw-p 00000000 00:00 0 
7f913374c000-7f91337b3000 r-xp 00000000 08:03 2502762                    /usr/lib/x86_64-linux-gnu/libgmp.so.10.0.5
7f91337b3000-7f91339b3000 ---p 00067000 08:03 2502762                    /usr/lib/x86_64-linux-gnu/libgmp.so.10.0.5
7f91339b3000-7f91339bb000 rw-p 00067000 08:03 2502762                    /usr/lib/x86_64-linux-gnu/libgmp.so.10.0.5
7f91339bb000-7f9133a3c000 r-xp 00000000 08:03 1966096                    /lib/x86_64-linux-gnu/libm-2.13.so
7f9133a3c000-7f9133c3b000 ---p 00081000 08:03 1966096                    /lib/x86_64-linux-gnu/libm-2.13.so
7f9133c3b000-7f9133c3c000 r--p 00080000 08:03 1966096                    /lib/x86_64-linux-gnu/libm-2.13.so
7f9133c3c000-7f9133c3d000 rw-p 00081000 08:03 1966096                    /lib/x86_64-linux-gnu/libm-2.13.so
7f9133c3d000-7f9133c5d000 r-xp 00000000 08:03 1966102                    /lib/x86_64-linux-gnu/ld-2.13.so
7f9133e37000-7f9133e3a000 rw-p 00000000 00:00 0 
7f9133e59000-7f9133e5c000 rw-p 00000000 00:00 0 
7f9133e5c000-7f9133e5d000 r--p 0001f000 08:03 1966102                    /lib/x86_64-linux-gnu/ld-2.13.so
7f9133e5d000-7f9133e5e000 rw-p 00020000 08:03 1966102                    /lib/x86_64-linux-gnu/ld-2.13.so
7f9133e5e000-7f9133e5f000 rw-p 00000000 00:00 0 
7fff41490000-7fff414b1000 rw-p 00000000 00:00 0                          [stack]
7fff41511000-7fff41512000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

继续尝试,我发现同样的问题也会影响以下值: 200, 600, 1000, 1400, ... 一般是 400n + 200。我真的不明白为什么会这样。

我在 Linux 3.2.0-4-amd64 #1 SMP Debian 3.2.46-1 x86_64 GNU/ 下使用 gcc (Debian 4.7.2-5) 4.7.2 编译了这个Linux

【问题讨论】:

在您的循环中,您正在递增 before 分配... 你没有保存 a = a + sizeof(char) 所以你应该有: a -= stress_size;但是只写 a[i] = 4 会更容易,永远不要改变 a。 @OliCharlesworth:这是一个非常愚蠢的疏忽。我重新编译了它,现在它似乎工作了。 【参考方案1】:

您正在写一个超出您所拥有的位置的位置。 (见@Oli Charlesworth 评论)

for (i = 0; i < stress_size; ++i)

    a++;  
    *a = 4;  // Bad: Setting array a_original[1] to a_original[stress_size].

改为:

for (i = 0; i < stress_size; ++i)

    *a = 4;  // Setting array a_original[0] to a_original[stress_size-1].
    a++;  

顺便说一句:你想要更低的l吗:printf("%Ld bytes allocated\n"...

【讨论】:

printf 内的%Ld 没问题,我使用的是 long long 变量;否则我会收到警告。 @Blex,你使用什么编译器接受“%Ld”? “%lld”是long long 的标准。 我一直认为“%Ld”是正确的。 gcc 编译它没有警告。

以上是关于双释放错误释放 1000 个字节的主要内容,如果未能解决你的问题,请参考以下文章

释放堆栈

指针指向空间的申请和释放易错点

退出程序后Crouton环境不释放内存?

TypeScript 中的内存释放

10.19编写一个函数 alloc(n) 用来在内存区开辟一个连续的空间(n个字节) 。 和 free(char * p),将地址p开始的各单元释放。

C语言堆内存管理上出现的问题,内存泄露,野指针使用,非法释放指针