Chr*_*ris 71 c malloc gcc 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);
}
Run Code Online (Sandbox Code Playgroud)
我用a检查了大小fprintf
,它是一个正整数(此时通常为50).我尝试malloc
用普通号码打电话,但我仍然得到错误.我只是对正在发生的事情感到难过,到目前为止我发现的谷歌没有任何帮助.
有什么想法发生了什么?我正在试图弄清楚如何编译一个更新的GCC,如果它是编译器错误,但我真的怀疑它.
Jon*_*set 65
为了让您更好地理解为什么会发生这种情况,我想对@ r-samuel-klatchko的答案进行一些扩展.
当你打电话时malloc
,真正发生的事情比仅仅给你一大块内存要复杂一点.在引擎盖下,malloc
还会保留一些关于它给你的内存(最重要的是它的大小)的内务处理信息,这样当你打电话时free
,就会知道要释放多少内存.此信息通常保留在内存位置返回给您之前malloc
.更多详尽的信息可以在互联网上找到,但(非常)基本的想法是这样的:
+------+-------------------------------------------------+
+ size | malloc'd memory +
+------+-------------------------------------------------+
^-- location in pointer returned by malloc
Run Code Online (Sandbox Code Playgroud)
在此基础上(并大大简化了事情),当您调用时malloc
,它需要获得指向可用内存的下一部分的指针.一种非常简单的方法是查看它给出的前一位内存,并size
在内存中进一步向下(或向上)移动字节.通过这种实现,您在分配后最终会看到类似的内存p1
,p2
并且p3
:
+------+----------------+------+--------------------+------+----------+
+ size | | size | | size | +
+------+----------------+------+--------------------+------+----------+
^- p1 ^- p2 ^- p3
Run Code Online (Sandbox Code Playgroud)
那么,是什么导致了您的错误?
好吧,想象一下你的代码错误地写了你已经分配的内存量(因为你分配的内容少于你需要的问题,或者因为你在代码中的某个地方使用了错误的边界条件).假设你的代码这么多的数据写入到p2
它启动覆盖是什么p3
的size
领域.当你现在下一次调用时malloc
,它将查看它返回的最后一个内存位置,查看其大小字段,移动到p3 + size
然后从那里开始分配内存.size
但是,由于您的代码已被覆盖,因此该内存位置不再位于先前分配的内存之后.
毋庸置疑,这可能会造成严重破坏!因此,实现者malloc
已经提出了许多"断言"或检查,如果它们即将发生,它们会尝试进行一系列的理智检查来捕获这个(以及其他问题).在您的特定情况下,这些断言被违反,因此malloc
中止,告诉您您的代码即将执行它不应该做的事情.
如前所述,这是一个粗略的过度简化,但足以说明这一点.glibc的实现malloc
是超过5k行,并且已经有大量关于如何构建良好的动态内存分配机制的研究,因此无法在SO答案中覆盖它.希望这能让您对实际导致问题的原因有所了解!
我使用Valgrind的替代解决方案:
我很高兴,因为我只是帮助我的朋友调试了程序。他的程序遇到了这个确切的问题(malloc()
导致中止),并带有来自GDB的相同错误消息。
我编译使用他的程序地址消毒剂与
gcc -Wall -g3 -fsanitize=address -o new new.c
^^^^^^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)
然后跑了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)
Run Code Online (Sandbox Code Playgroud)
让我们看一下输出,尤其是堆栈跟踪:
第一部分说的写操作无效new.c:59
。那行读
memset(len,0,sizeof(int*)*p);
^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)
第二部分说发生错误写入的内存在处创建new.c:55
。那行读
if(!(len=(int*)malloc(sizeof(int)*p))){
^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)
而已。我只花了不到半分钟的时间就找到了困扰我朋友几个小时的错误。他设法找到了故障,但是这是随后的malloc()
调用失败,而无法在以前的代码中发现此错误。
总结:尝试使用-fsanitize=address
GCC或Clang。在调试内存问题时,它可能非常有用。