美文网首页
[Valgrind]检测动态分配的内存DAM(Dynamical

[Valgrind]检测动态分配的内存DAM(Dynamical

作者: AkuRinbu | 来源:发表于2018-09-24 00:58 被阅读20次

    目录

    一、示例代码
    二、DAM问题
    三、使用Valgrind查看内存使用信息
    四、工具安装与参考
    

    一、实例代码

    配书代码包Chapter_07/pg_222/memprobs.c

    1   #include <malloc.h>
    2   #include <stdio.h>
    3   
    4   
    5   
    6   int main( void )
    7   {
    8       int *a = (int *) malloc( 3*sizeof(int) ); // malloc return not checked
    9       int *b = (int *) malloc( 3*sizeof(int) ); // malloc return not checked
    10  
    11      for( int i = -1; i <= 3; ++i )
    12          a[i] = i; // a bad write for i = -1 and 3.
    13
    14      free(a);
    15      printf("%d\n", a[1]); // a read from freed memory
    16      free(a); // a double free on pointer a.
    17  
    18      return 0; // program ends without freeing *b.
    19  }
    

    配书代码包Chapter_07/pg_222/Makefile

    TARGET = memprobs
    CC     = clang
    CFLAGS = -g3 -Wall -Wextra -std=c99
    
    all: $(TARGET)
    .PHONY: clean
    
    clean:
        $(RM) core $(TARGET)
    

    run

    $ ls
    Makefile  memprobs.c
    
    $ make memprobs
    clang -g3 -Wall -Wextra -std=c99    memprobs.c   -o memprobs
    memprobs.c:9:7: warning: unused variable 'b' [-Wunused-variable]
            int *b = (int *) malloc( 3*sizeof(int) ); // malloc return not checked
                 ^
    1 warning generated.
    
    $ ./memprobs
    *** Error in `./memprobs': double free or corruption (out): 0x0000000000cbd010 ***
    Aborted (core dumped)
    

    二、DAM 问题

    1、内存泄漏

    • 没有释放动态分配的内存,int *b指向的 3个int内存 始终没有得到释放;
    • 内存泄漏会不断消耗内存,造成程序可用的内存越来越少;
    • 当存在内存泄漏的程序终止时,有些操作系统会回收这些内存,有些则要等到系统重启才会回收;

    2、对malloc()的调用失败

    • 解决方法:可以通过检测malloc()的返回值来检测;
    • 计算中的程序错误可能导致请求一个数值太大或者为负值的DAM(指malloc()的调用参数),造成调用失败;
    • 系统真的没有内存可用的时候,也会调用失败;

    3、访问错误

    • DAM段之外的地址执读和写操作;
    • 释放DAM段之后,对DAM区域中的内存执行读写操作;

    4、重复释放(double free)

    • 对动态内存的同一段调用两次free()

    三、使用Valgrind查看内存使用信息

    • $ valgrind --tool=memcheck --leak-check=full ./memprobs
    $ valgrind --tool=memcheck --leak-check=full ./memprobs
    ==4126== Memcheck, a memory error detector
    ==4126== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
    ==4126== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
    ==4126== Command: ./memprobs
    ==4126== 
    ==4126== Invalid write of size 4
    ==4126==    at 0x4005D4: main (memprobs.c:12)
    ==4126==  Address 0x51fc03c is 4 bytes before a block of size 12 alloc'd
    ==4126==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==4126==    by 0x40059D: main (memprobs.c:8)
    ==4126== 
    ==4126== Invalid read of size 4
    ==4126==    at 0x4005FF: main (memprobs.c:15)
    ==4126==  Address 0x51fc044 is 4 bytes inside a block of size 12 free'd
    ==4126==    at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==4126==    by 0x4005F2: main (memprobs.c:14)
    ==4126== 
    1
    ==4126== Invalid free() / delete / delete[] / realloc()
    ==4126==    at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==4126==    by 0x400614: main (memprobs.c:16)
    ==4126==  Address 0x51fc040 is 0 bytes inside a block of size 12 free'd
    ==4126==    at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==4126==    by 0x4005F2: main (memprobs.c:14)
    ==4126== 
    ==4126== 
    ==4126== HEAP SUMMARY:
    ==4126==     in use at exit: 12 bytes in 1 blocks
    ==4126==   total heap usage: 2 allocs, 2 frees, 24 bytes allocated
    ==4126== 
    ==4126== 12 bytes in 1 blocks are definitely lost in loss record 1 of 1
    ==4126==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==4126==    by 0x4005B0: main (memprobs.c:9)
    ==4126== 
    ==4126== LEAK SUMMARY:
    ==4126==    definitely lost: 12 bytes in 1 blocks
    ==4126==    indirectly lost: 0 bytes in 0 blocks
    ==4126==      possibly lost: 0 bytes in 0 blocks
    ==4126==    still reachable: 0 bytes in 0 blocks
    ==4126==         suppressed: 0 bytes in 0 blocks
    ==4126== 
    ==4126== For counts of detected and suppressed errors, rerun with: -v
    ==4126== ERROR SUMMARY: 5 errors from 4 contexts (suppressed: 0 from 0)
    

    错误信息分析

    Line:12 第一次循环会访问a[-1] 越界数组

    • 描述为==4126== Invalid write of size 4 at 0x4005D4: main (memprobs.c:12) Address 0x51fc03c is 4 bytes before a block of size 12 alloc'd
    • 你访问的位置在一块分配好的12字节内存之前
    • 核心词是Invalid readbeforealloc'd

    Line:15的访问错误,访问已经释放过的DAM段

    • 描述为Invalid read of size 4 at 0x4005FF: main (memprobs.c:15) Address 0x51fc044 is 4 bytes inside a block of size 12 free'd
    • 没错你访问了一块分配了12个字节的内存块,但是这个内存块已经被释放了free'd`
    • 核心词是Invalid readinsidefree'd

    Line: 16double free()

    • 描述为Invalid free() / delete / delete[] / realloc() ... Address 0x51fc040 is 0 bytes inside a block of size 12 free'd
    • 这里有一行无效的释放,原因在于你释放了一块已经释放过的区域重复释放
    • 核心词是Invalid free()insidefree'd

    Line:9的那个没有释放过的int *b

    • 描述为12 bytes in 1 blocks are definitely lost in loss record 1 of 1
    • 一个确定的内存泄露,12字节刚好就就是3个int
    • 核心词就是definitely lost

    四、工具安装与参考

    Valgrind

    • 安装
      sudo apt-get install valgrind

    • Quick Start

    http://valgrind.org/docs/manual/quick-start.html

    • Memcheck: 所有类型的错误信息解释

    4.2. Explanation of error messages from Memcheck
    http://valgrind.org/docs/manual/mc-manual.html#mc-manual.errormsgs

    • 官方 manual

    http://valgrind.org/docs/manual/manual.html

    • 应用 Valgrind 发现 Linux 程序的内存问题

    https://www.ibm.com/developerworks/cn/linux/l-cn-valgrind/

    使用书籍与相关笔记

    [书籍]《软件调试的艺术》(《 The Art of Debugging with GDB, DDD, and Eclipse》)
    https://www.jianshu.com/p/0805ba683126

    相关文章

      网友评论

          本文标题:[Valgrind]检测动态分配的内存DAM(Dynamical

          本文链接:https://www.haomeiwen.com/subject/gmccoftx.html