malloc(): memory corruption 解决方案
·
现象
使用malloc使用,出现memory corruption,程序异常退出。
原因
发生了内存异常使用,malloc在申请内存的时候,发现内存冲突,接收到SIGABRT信号退出。
样例
memory corruption 不一定是当前的 malloc出现问题,很有可能是前一次的内存处理有问题,比如memset越界、memcpy越界之类的。
如下的代码样例,在某个项目中出现了下面的情况。原有的实现功能是,header_buf的长度<header的长度,从而只复制header_buf的有效长度。
然而在某些设备上,由于长度信息与设备相关,导致复制的长度超过了申请的长度。导致后续的malloc或者free出现异常。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> int main(void) { char *header, *header_buf, *next_buf; int min_io_size, header_len; min_io_size = 64; /* 实际是从设备读取的,此处打桩演示 */ header_len = 108; /* 实际是通过计算出来的,此处打桩演示 */ header = (char *) malloc(min_io_size); if (!header) { printf("%d\n", errno); return -1; } header_buf = (char *) malloc(header_len); if (!header_buf) { printf("%d\n", errno); return -1; } memset(header, 0xf, min_io_size); memset(header_buf, 0xe, header_len); memcpy(header, header_buf, header_len); /* 此处memcpy108B到64B的空间,会引起后续异常 */ next_buf = (char *) malloc(64); free(header_buf); free(header); free(next_buf); return 0; } gdb调试信息
memcpy前的数据长度,一个是64B,一个108,正常。
(gdb) n 118 memcpy(header, header_buf, header_len); /* 此处memcpy108B到64B的空间,会引起后续异常 */ (gdb) p header $1 = 0x603010 '\017' <repeats 64 times> (gdb) p header_buf $2 = 0x603060 '\016' <repeats 108 times> memcpy后的数据长度,64B的数据异常变为188B。
(gdb) $4 = 0x603010 '\016' <repeats 188 times> (gdb) p header_buf $5 = 0x603060 '\016' <repeats 108 times> (gdb) 经过越界的memcpy,出现如下error log。
Error in `/home/work/t/mem-list/test_list': munmap_chunk(): invalid pointer: 0x0000000000603060 *** ======= Backtrace: ========= /lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7ffff78677e5] /lib/x86_64-linux-gnu/libc.so.6(cfree+0x1a8)[0x7ffff7874698] /home/work/t/mem-list/test_list[0x400c13] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7ffff7810830] /home/work/t/mem-list/test_list[0x400769] ======= Memory map: ======== 00400000-00402000 r-xp 00000000 08:01 1068805 /home/work/t/mem-list/test_list 00601000-00602000 r--p 00001000 08:01 1068805 /home/work/t/mem-list/test_list 00602000-00603000 rw-p 00002000 08:01 1068805 /home/work/t/mem-list/test_list 00603000-00624000 rw-p 00000000 00:00 0 [heap] 7ffff75da000-7ffff75f0000 r-xp 00000000 08:01 3674661 /lib/x86_64-linux-gnu/libgcc_s.so.1 7ffff75f0000-7ffff77ef000 ---p 00016000 08:01 3674661 /lib/x86_64-linux-gnu/libgcc_s.so.1 7ffff77ef000-7ffff77f0000 rw-p 00015000 08:01 3674661 /lib/x86_64-linux-gnu/libgcc_s.so.1 7ffff77f0000-7ffff79b0000 r-xp 00000000 08:01 3676047 /lib/x86_64-linux-gnu/libc-2.23.so 7ffff79b0000-7ffff7bb0000 ---p 001c0000 08:01 3676047 /lib/x86_64-linux-gnu/libc-2.23.so 7ffff7bb0000-7ffff7bb4000 r--p 001c0000 08:01 3676047 /lib/x86_64-linux-gnu/libc-2.23.so 7ffff7bb4000-7ffff7bb6000 rw-p 001c4000 08:01 3676047 /lib/x86_64-linux-gnu/libc-2.23.so 7ffff7bb6000-7ffff7bba000 rw-p 00000000 00:00 0 7ffff7bba000-7ffff7bd2000 r-xp 00000000 08:01 3676034 /lib/x86_64-linux-gnu/libpthread-2.23.so 7ffff7bd2000-7ffff7dd1000 ---p 00018000 08:01 3676034 /lib/x86_64-linux-gnu/libpthread-2.23.so 7ffff7dd1000-7ffff7dd2000 r--p 00017000 08:01 3676034 /lib/x86_64-linux-gnu/libpthread-2.23.so 7ffff7dd2000-7ffff7dd3000 rw-p 00018000 08:01 3676034 /lib/x86_64-linux-gnu/libpthread-2.23.so 7ffff7dd3000-7ffff7dd7000 rw-p 00000000 00:00 0 7ffff7dd7000-7ffff7dfd000 r-xp 00000000 08:01 3676033 /lib/x86_64-linux-gnu/ld-2.23.so 7ffff7fdb000-7ffff7fdf000 rw-p 00000000 00:00 0 7ffff7ff6000-7ffff7ff7000 rw-p 00000000 00:00 0 7ffff7ff7000-7ffff7ffa000 r--p 00000000 00:00 0 [vvar] 7ffff7ffa000-7ffff7ffc000 r-xp 00000000 00:00 0 [vdso] 7ffff7ffc000-7ffff7ffd000 r--p 00025000 08:01 3676033 /lib/x86_64-linux-gnu/ld-2.23.so 7ffff7ffd000-7ffff7ffe000 rw-p 00026000 08:01 3676033 /lib/x86_64-linux-gnu/ld-2.23.so 7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0 7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0 [stack] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] Program received signal SIGABRT, Aborted. 0x00007ffff7825428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54 54 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory. 经验总结
1、出现 memory corruption,不要局限于当前的代码,需要往上回溯代码。
2、可以使用一些工具检查代码。比如coverity 会提示 “不可信任的值作为了参数,将未经检查的不可信任来源的值用作了函数的参数”
valgrind也会检测出内存异常位置。
3、如果此问题是必现的话,可以将此部分代码单独剥离出来。或者放在进程头部,减少其他模块影响,再采用二分法的方式逐步缩小出问题的代码范围。
新一代开源开发者平台 GitCode,通过集成代码托管服务、代码仓库以及可信赖的开源组件库,让开发者可以在云端进行代码托管和开发。旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。
更多推荐

所有评论(0)