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、如果此问题是必现的话,可以将此部分代码单独剥离出来。或者放在进程头部,减少其他模块影响,再采用二分法的方式逐步缩小出问题的代码范围。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值