为什么会出现C malloc断言失败?


85

我正在实现分而治之多项式算法,因此可以将其对照OpenCL实现进行基准测试,但无法malloc正常工作。当我运行程序时,它会分配一堆东西,检查一些东西,然后将其发送size/2给算法。然后,当我malloc再次点击该行时,它会吐出以下内容:

malloc.c:3096: sYSMALLOc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 * (sizeof(size_t))) - 1)) & ~((2 * (sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long)old_end & pagemask) == 0)' failed.
Aborted

有问题的行是:

int *mult(int size, int *a, int *b) {
    int *out,i, j, *tmp1, *tmp2, *tmp3, *tmpa1, *tmpa2, *tmpb1, *tmpb2,d, *res1, *res2;
    fprintf(stdout, "size: %d\n", size);

    out = (int *)malloc(sizeof(int) * size * 2);
}

我用来检查大小fprintf,它是一个正整数(通常是50)。我也尝试malloc使用纯数字进行呼叫,但仍然出现错误。我只是对正在发生的事情感到困惑,到目前为止,我发现Google都没有任何帮助。

有什么想法吗?我试图弄清楚如何编译更新的GCC以防出现编译器错误,但我真的对此表示怀疑。


我怀疑问题实际上出在那之前。也许是双重免费?
米奇小麦

程序中的第三行:int * mult(int size,int * a,int * b){int * out,i,j,* tmp1,* tmp2,* tmp3,* tmpa1,* tmpa2,* tmpb1,* tmpb2 ,d,* res1,* res2; fprintf(stdout,“ size:%d \ n”,size); out =(int *)malloc(sizeof(int)* size * 2);
克里斯(Chris

Answers:


98

99.9%的可能性是您损坏了内存(缓冲区溢出或下溢,在释放指针后将其写入指针,在同一指针上两次调用free,等等)

Valgrind下运行代码,以查看程序在哪里做错了什么。


1
固定。Valgrind绝对提供了帮助。我错误地转录了旧的matlab代码,并在j上进行了一个for循环,然后在其中执行了j ++,这最重写了所写的数组,并以某种方式导致malloc失败。谢谢您的帮助!
克里斯(Chris

Valgrind只是我需要弄清楚发生此错误时正在发生什么的工具。感谢您提及。
alexwells

77

为了让您更好地理解为什么会发生这种情况,我想对@ r-samuel-klatchko的答案进行一些扩展。

当您致电时malloc,实际发生的事情比仅仅给您一块内存玩起来要复杂得多。在后台,malloc还保留一些有关它给您的内存的管家信息(最重要的是其大小),以便在您致电时free,它知道要释放多少内存之类的信息。该信息通常在之前将存储位置保留给您malloc。可以在internet™上找到更详尽的信息,但是(非常)基本的想法是这样的:

+------+-------------------------------------------------+
+ size |                  malloc'd memory                +
+------+-------------------------------------------------+
       ^-- location in pointer returned by malloc

在此基础上(并极大简化),当您调用时malloc,它需要获取一个指向可用内存下一部分的指针。一种非常简单的方法是查看它释放的内存的前一位,然后将size字节进一步向下(或向上)移动到内存中。有了这个实现,你结束了你的内存分配后看起来像这样p1p2p3

+------+----------------+------+--------------------+------+----------+
+ size |                | size |                    | size |          +
+------+----------------+------+--------------------+------+----------+
       ^- p1                   ^- p2                       ^- p3

那么,是什么导致您的错误?

好吧,想象一下您的代码错误地写了超出分配的内存量(要么是因为您分配的内存少于问题,要么是因为您在代码的某个位置使用了错误的边界条件)。假设你的代码这么多的数据写入到p2它启动覆盖是什么p3size领域。现在malloc,当您下次调用时,它将查看它返回的最后一个内存位置,查看其大小字段,移至p3 + size,然后从那里开始分配内存。size但是,由于您的代码已被覆盖,因此该内存位置不再位于先前分配的内存之后。

不用说,这可能会造成破坏!因此,的实施者malloc提出了许多“断言”或检查,如果它们即将发生,它们会尝试进行一系列的健全性检查以捕获此问题(以及其他问题)。在您的特定情况下,这些断言被违反,因此malloc中止,告诉您您的代码将要执行它实际上不应该做的事情。

如前所述,这是一个过分的简化,但是足以说明这一点。glibc的实现malloc超过5k行,并且对如何构建良好的动态内存分配机制进行了大量研究,因此不可能在SO答案中涵盖所有内容。希望这使您对真正导致问题的原因有所了解!


14

我使用Valgrind的替代解决方案:

我很高兴,因为我只是帮助我的朋友调试了程序。他的程序遇到了这个确切的问题(malloc()导致中止),并带有来自GDB的相同错误消息。

我编译使用他的程序地址消毒剂

gcc -Wall -g3 -fsanitize=address -o new new.c
              ^^^^^^^^^^^^^^^^^^

然后跑了gdb new。当程序SIGABRT由于后续原因而终止时malloc(),将打印很多有用的信息:

=================================================================
==407==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6060000000b4 at pc 0x7ffffe49ed1a bp 0x7ffffffedc20 sp 0x7ffffffed3c8
WRITE of size 104 at 0x6060000000b4 thread T0
    #0 0x7ffffe49ed19  (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x5ed19)
    #1 0x8001dab in CreatHT2 /home/wsl/Desktop/hash/new.c:59
    #2 0x80031cf in main /home/wsl/Desktop/hash/new.c:209
    #3 0x7ffffe061b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
    #4 0x8001679 in _start (/mnt/d/Desktop/hash/new+0x1679)

0x6060000000b4 is located 0 bytes to the right of 52-byte region [0x606000000080,0x6060000000b4)
allocated by thread T0 here:
    #0 0x7ffffe51eb50 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb50)
    #1 0x8001d56 in CreatHT2 /home/wsl/Desktop/hash/new.c:55
    #2 0x80031cf in main /home/wsl/Desktop/hash/new.c:209
    #3 0x7ffffe061b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)

让我们看一下输出,尤其是堆栈跟踪:

第一部分说处有一个无效的写操作new.c:59。那行读

memset(len,0,sizeof(int*)*p);
             ^^^^^^^^^^^^

第二部分说发生错误写入的内存在处创建new.c:55。那行读

if(!(len=(int*)malloc(sizeof(int)*p))){
                      ^^^^^^^^^^^

而已。我只花了不到半分钟的时间就找到了困扰我朋友几个小时的错误。他设法找到了故障,但是这是随后的malloc()调用失败,而无法在以前的代码中发现此错误。

总结:尝试使用-fsanitize=addressGCC或Clang。在调试内存问题时,它会非常有用。


1
你刚刚救了我的命。
Nate Symer


2

我收到以下消息,类似于您的消息:

    程序:malloc.c:2372:sysmalloc:声明`(old_top ==((((mbinptr)((((char *)&((av)-> bins [(((1)-1)* 2])))-__builtin_offsetof (struct malloc_chunk,fd))))&& old_size == 0)|| [[unsigned long)(old_size)> =(unsigned long)((((((__ builtin_offsetof(struct malloc_chunk,fd_nextsize))+((2 *(sizeof(size_t)))-1))&〜((2 *(sizeof (size_t)))-1)))&&(((old_top)-> size&0x1)&&(((unsigned long)old_end&pagemask)== 0)'失败。

使用malloc之前,在某些方法调用中犯了一个错误。在将sizeof()运算符添加到无符号char数组中后更新因子时,错误地将乘号'*'改写为'+'。

这是导致我的错误的代码:

    UCHAR * b =(UCHAR *)malloc(sizeof(UCHAR)+5);
    b [INTBITS] =(一些计算);
    b [BUFSPC] =(一些计算);
    b [BUFOVR] =(一些计算);
    b [BUFMEM] =(一些计算);
    b [MATCHBITS] =(一些计算);

稍后在另一种方法中,我再次使用了malloc,它产生了上面显示的错误消息。通话非常简单:

    UCHAR * b =(UCHAR *)malloc(sizeof(UCHAR)* 50);

想想在第一个调用上使用“ +”号,这会导致错误的演算,并在对数组进行立即初始化(覆盖未分配给该数组的内存)后立即初始化数组,给malloc的内存映射带来一些混乱。因此,第二通电话出了错。


0

我们收到这个错误是因为我们忘记乘以sizeof(int)。请注意,malloc(..)的参数是字节数,而不是机器字数或其他内容。


0

我遇到了同样的问题,我在循环中再次使用了malloc来添加新的char * string数据。我遇到了同样的问题,但在释放分配的内存后void free()进行了排序


-2

我正在通过Linux将一个应用程序从Visual C移植到gcc,但我遇到了同样的问题

malloc.c:3096:sYSMALLOc:在UBUNTU 11上使用gcc声明。

我将相同的代码移至Suse发行版(在另一台计算机上),没有任何问题。

我怀疑问题不在我们的程序中,而在我们自己的libc中。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.