为什么我的C malloc断言失败了?

时间:2010-06-07 05:15:48

标签: c gcc malloc assertion

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

  

malloc.c:3096: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)'失败。   中止

有问题的一行是:

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,但我仍然得到错误。我只是对正在发生的事情感到困惑,到目前为止我发现的谷歌没有任何帮助。

任何想法发生了什么?我正在试图弄清楚如何编译一个更新的GCC,以防它是编译错误,但我真的很怀疑。

8 个答案:

答案 0 :(得分:81)

99.9%的可能是你有内存损坏(缓冲区流量过大或流量不足,在释放后写入指针,在同一指针上调用两次等等)。

Valgrind下运行您的代码,以查看您的程序执行错误的位置。

答案 1 :(得分:58)

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

当你致电malloc时,真正发生的事情比给你一大块内存要复杂得多。在引擎盖下,malloc还会保存一些关于它给你的内存(最重要的是它的大小)的内务处理信息,这样当你调用free时,就会知道要释放多少内存。此信息通常保存在malloc返回给您的内存位置之前。可以找到更详尽的信息on the internet™,但(非常)基本的想法是这样的:

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

在此基础上(并大大简化了事情),当您调用malloc时,它需要获得指向可用内存的下一部分的指针。一个非常简单的方法是查看它给出的前一位内存,并将size字节进一步向下(或向上)移动到内存中。通过此实现,在分配p1p2p3之后,您最终会看到类似内容:

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

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

好吧,想象一下你的代码错误地写了你已分配的内存量(因为你分配的内存少于你需要的问题,或者因为你在你的某个地方使用了错误的边界条件码)。假设您的代码将大量数据写入p2,它会开始覆盖p3的{​​{1}}字段中的内容。当您现在接下来调用size时,它将查看它返回的最后一个内存位置,查看其大小字段,移至malloc然后从那里开始分配内存。但是,由于您的代码已被覆盖p3 + size,因此该内存位置不再位于先前分配的内存之后。

毋庸置疑,这可能会造成严重破坏!因此,size的实现者已经输入了许多"断言"或检查,如果它们即将发生,它们会尝试进行一系列健全性检查以捕获这个(以及其他问题) 。在您的特定情况下,这些断言被违反,因此malloc中止,告诉您您的代码即将执行它应该做的事情。

如前所述,这是一个粗略的过度简化,但足以说明这一点。 malloc的glibc实现超过5k行,并且已经有大量关于如何构建良好的动态内存分配机制的研究,因此无法在SO答案中覆盖它。希望这能让您对实际导致问题的原因有所了解!

答案 2 :(得分:6)

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

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

我使用Address Sanitizer

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=address的GCC或Clang。在调试内存问题时,它会非常有用。

答案 3 :(得分:2)

你可能在某处超出分配的内存超出范围。 然后在你调用malloc

之前,底层的sw不会接收它

可能有一个被malloc捕获的警卫值被破坏。

编辑...为边界检查帮助添加了这个

http://www.lrde.epita.fr/~akim/ccmp/doc/bounds-checking.html

答案 4 :(得分:2)

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


    program: malloc.c:2372: 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.

在使用malloc之前,错误地调用了一些方法。错误地覆盖了乘法符号' *'使用' +',在sizeof() - 运算符之后更新因子时将字段添加到unsigned char数组。

以下是我的案例中负责错误的代码:


    UCHAR* b=(UCHAR*)malloc(sizeof(UCHAR)+5);
    b[INTBITS]=(some calculation);
    b[BUFSPC]=(some calculation);
    b[BUFOVR]=(some calculation);
    b[BUFMEM]=(some calculation);
    b[MATCHBITS]=(some calculation);

在后来的另一种方法中,我再次使用了malloc,它产生了上面显示的错误信息。电话很简单(


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

在第一次调用时使用' +' -sign,这会导致错误演算并结合立即初始化数组(覆盖未分配给数组的内存) ),给malloc的内存映射带来了一些困惑。因此第二次调用出错了。

答案 5 :(得分:1)

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

答案 6 :(得分:0)

我将一个应用程序从Visual C移植到Linux上的gcc,我遇到了与

相同的问题
  

malloc.c:3096:sYSMALLOc:在UBUNTU 11上使用gcc断言。

我将相同的代码移到了Suse发行版(在其他计算机上),我没有任何问题。

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

答案 7 :(得分:0)

我遇到了同样的问题,我在循环中使用了malloc over n,以添加新的char *字符串数据。我遇到了同样的问题,但在释放分配的内存void free()之后问题被排序了