天天看點

Valgrind的用法

一、valgrind介紹

1、valgrind體系結構

(1)valgrind有核心(core)以及基于核心的其他調試工具組成。

(2)核心類似于一個架構(framework),它模拟了一個CPU環境,并提供服務給其他工具。

(3)其他工具則類似于插件(plug-in),利用核心提供的服務完成各種特點的記憶體調試任務。

Valgrind的用法

2、valgrind工具集

(1)Memcheck:valgrind應用最廣泛的工具,一個重量級的記憶體檢查器,能夠發現開發中絕大多數記憶體錯誤使用情況。

(2)Callgrind:它主要用來檢查程式中函數調用過程中出現的問題。

(3)Cachegrind:它主要用來檢查程式中緩存使用出現的問題。

(4)Helgrind:它主要用來檢查多線程程式中出現的競争問題。

(5)Massif:它主要用來檢查程式中堆棧使用中出現的問題。

(6)Extension:可以利用core提供的功能,自己編寫特定的記憶體調試工具。

二、valgrind記憶體檢查

1、linux程式的記憶體布局 (1)代碼段(.text) 存放的是CPU要執行的指令。代碼段是可以共享的,相同的代碼在記憶體中隻會有一個拷貝,同時這個段是隻讀的, 防止程式由于錯誤而修改自身的指令。 (2)初始化資料段(.data) 存放的是程式中需要明确賦初始值的變量,核心在調用exec函數啟動該程式時從源程式檔案中讀入。int val = 100; (3)未初始化資料段(.bss) 位于這一段中的資料,核心在執行該程式前,将其初始化為0或者null。int sum; (4)堆(Heap) 用于在程式中進行動态記憶體申請,如malloc,new等函數。 (5)棧(Stack) 函數中的局部變量,在函數調用過程中産生的臨時變量。

Valgrind的用法

2、記憶體檢查原理 Memcheck能夠檢測出記憶體問題,關鍵在于其建立了兩個全局表。 (1)Valid-Value表 對于程序的整個位址空間中的每一個位元組(byte),都有與之對應的8個bits。 對于CPU的每個寄存器,也有一個與之對應的bit向量。 這些bits負責記錄該位元組或者寄存器值是否具有有效的、已初始化的值。 (2)Valid-Address表 對于程序整個位址空間中的每一個位元組(byte),還有與之對應的1個bit, 負責記錄該位址是否能夠被讀寫。 (3)當要讀寫記憶體中某個位元組時,首先檢查這個位元組對應的A bit。 如果該A bit顯示該位置是無效位置,memcheck則報告讀寫錯誤。 (4)核心類似于一個虛拟的CPU環境,當記憶體中的某個位元組被加載到真實的CPU中,該位元組對應的V bit也被加載到 虛拟的CPU環境中。一旦寄存器中的值,被用來産生記憶體位址,或者該值能夠影響程式輸出,則memcheck會檢查 對應的V bit,如果該值尚未初始化,則會報告使用未初始化記憶體錯誤。

Valgrind的用法

三、valgrind的用法 為了使valgrind發現的錯誤更精确,建議在編譯時加上-g參數,編譯優化選項選擇O0,雖然這會降低程式的執行效率。

gcc -g -O0 prog.c -o prog
           

調用valgrind的通用格式為

valgrind [valgrind-options] prog [prog-options]
           

記憶體非法使用的檢測方法

valgrind --tool=memcheck --leak-check=yes prog
           

1、檢測記憶體洩漏 // test1.c

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char *p = malloc(10);
    return EXIT_SUCCESS;
}
           
$ gcc -g -O0 test1.c -o test1
$ valgrind --tool=memcheck --leak-check=yes test1
==37444== Memcheck, a memory error detector
==37444== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==37444== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==37444== Command: test1
==37444==
==37444==
==37444== HEAP SUMMARY:
==37444==     in use at exit: 10 bytes in 1 blocks
==37444==   total heap usage: 1 allocs, 0 frees, 10 bytes allocated
==37444==
==37444== 10 bytes in 1 blocks are definitely lost in loss record 1 of 1
==37444==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==37444==    by 0x400537: main (test1.c:6)
==37444==
==37444== LEAK SUMMARY:
==37444==    definitely lost: 10 bytes in 1 blocks
==37444==    indirectly lost: 0 bytes in 0 blocks
==37444==      possibly lost: 0 bytes in 0 blocks
==37444==    still reachable: 0 bytes in 0 blocks
==37444==         suppressed: 0 bytes in 0 blocks
==37444==
==37444== For counts of detected and suppressed errors, rerun with: -v
==37444== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
           

2、檢測對非法記憶體位址的通路 // test2.c

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char *p = malloc(10);
    p[10] = 1;
    free(p);
    return EXIT_SUCCESS;
}
           
$ gcc -g -O0 test2.c -o test2
$ valgrind --tool=memcheck --leak-check=yes test2
==37481== Memcheck, a memory error detector
==37481== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==37481== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==37481== Command: test2
==37481==
==37481== Invalid write of size 1
==37481==    at 0x400584: main (test2.c:7)
==37481==  Address 0x520304a is 0 bytes after a block of size 10 alloc'd
==37481==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==37481==    by 0x400577: main (test2.c:6)
==37481==
==37481==
==37481== HEAP SUMMARY:
==37481==     in use at exit: 0 bytes in 0 blocks
==37481==   total heap usage: 1 allocs, 1 frees, 10 bytes allocated
==37481==
==37481== All heap blocks were freed -- no leaks are possible
==37481==
==37481== For counts of detected and suppressed errors, rerun with: -v
==37481== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
           

3、讀取未初始化區域 // test3.c

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int *x = malloc(sizeof(int));
    int a = *x + 1;
    free(x);
    return a;
}
           
$ gcc -g -O0 test3.c -o test3
$ valgrind --tool=memcheck --leak-check=yes test3
==37505== Memcheck, a memory error detector
==37505== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==37505== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==37505== Command: test3
==37505==
==37505== Syscall param exit_group(status) contains uninitialised byte(s)
==37505==    at 0x4F05B98: _Exit (_exit.c:31)
==37505==    by 0x4E73FAA: __run_exit_handlers (exit.c:97)
==37505==    by 0x4E74044: exit (exit.c:104)
==37505==    by 0x4E5A836: (below main) (libc-start.c:325)
==37505==
==37505==
==37505== HEAP SUMMARY:
==37505==     in use at exit: 0 bytes in 0 blocks
==37505==   total heap usage: 1 allocs, 1 frees, 4 bytes allocated
==37505==
==37505== All heap blocks were freed -- no leaks are possible
==37505==
==37505== For counts of detected and suppressed errors, rerun with: -v
==37505== Use --track-origins=yes to see where uninitialised values come from
==37505== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
           

4、通路已釋放的區域

// test4.c

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int *x = malloc(sizeof(int));
    free(x);
    int a = *x + 1;
    return a;
}
           
$ gcc -g -O0 test4.c -o test4
$ valgrind --tool=memcheck --leak-check=yes test4
==37533== Memcheck, a memory error detector
==37533== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==37533== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==37533== Command: test4
==37533==
==37533== Invalid read of size 4
==37533==    at 0x40058C: main (test4.c:8)
==37533==  Address 0x5203040 is 0 bytes inside a block of size 4 free'd
==37533==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==37533==    by 0x400587: main (test4.c:7)
==37533==  Block was alloc'd at
==37533==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==37533==    by 0x400577: main (test4.c:6)
==37533==
==37533==
==37533== HEAP SUMMARY:
==37533==     in use at exit: 0 bytes in 0 blocks
==37533==   total heap usage: 1 allocs, 1 frees, 4 bytes allocated
==37533==
==37533== All heap blocks were freed -- no leaks are possible
==37533==
==37533== For counts of detected and suppressed errors, rerun with: -v
==37533== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
           

5、記憶體雙重釋放

// test5.c

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char *x = malloc(sizeof(int));
    free(x);
    free(x);
    return EXIT_SUCCESS;
}
           
$ gcc -g -O0 test5.c -o test5
$ valgrind --tool=memcheck --leak-check=yes test5
==37554== Memcheck, a memory error detector
==37554== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==37554== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==37554== Command: test5
==37554==
==37554== Invalid free() / delete / delete[] / realloc()
==37554==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==37554==    by 0x400593: main (test5.c:8)
==37554==  Address 0x5203040 is 0 bytes inside a block of size 4 free'd
==37554==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==37554==    by 0x400587: main (test5.c:7)
==37554==  Block was alloc'd at
==37554==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==37554==    by 0x400577: main (test5.c:6)
==37554==
==37554==
==37554== HEAP SUMMARY:
==37554==     in use at exit: 0 bytes in 0 blocks
==37554==   total heap usage: 1 allocs, 2 frees, 4 bytes allocated
==37554==
==37554== All heap blocks were freed -- no leaks are possible
==37554==
==37554== For counts of detected and suppressed errors, rerun with: -v
==37554== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
           

6、記憶體覆寫

// test6.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
  char x[50];
  int i;
  for(i = 0; i < 50; i++)
  {
    x[i] = i + 1;
  }
  strncpy(x+20, x, 20);  // ok
  strncpy(x+20, x, 21);  // overlap
  strncpy(x, x+20, 20);  // ok
  strncpy(x, x+20, 21);  // overlap

  x[39] = '\0';
  strcpy(x, x+20);       // ok

  x[39] = 39;
  x[40] = '\0';
  strcpy(x, x+20);       // overlap

  return 0;
}
           
$ gcc -g -O0 test6.c -o test6
$ valgrind --tool=memcheck --leak-check=yes test6
==37692== Memcheck, a memory error detector
==37692== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==37692== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==37692== Command: test6
==37692==
==37692== Source and destination overlap in strncpy(0xffefffb49, 0xffefffb35, 21)
==37692==    at 0x4C31626: __strncpy_sse2_unaligned (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==37692==    by 0x40064F: main (test6.c:14)
==37692==
==37692== Source and destination overlap in strncpy(0xffefffb35, 0xffefffb49, 21)
==37692==    at 0x4C31626: __strncpy_sse2_unaligned (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==37692==    by 0x400687: main (test6.c:16)
==37692==
==37692== Source and destination overlap in strcpy(0xffefffb20, 0xffefffb34)
==37692==    at 0x4C310E6: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==37692==    by 0x4006C1: main (test6.c:23)
==37692==
==37692==
==37692== HEAP SUMMARY:
==37692==     in use at exit: 0 bytes in 0 blocks
==37692==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==37692==
==37692== All heap blocks were freed -- no leaks are possible
==37692==
==37692== For counts of detected and suppressed errors, rerun with: -v
==37692== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
           

7、valgrind不能檢測的錯誤

valgrind不對靜态數組(配置設定在棧上)進行邊界檢查

// test7.c

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
  char x[10];
  x[11] = 'a';
  return EXIT_SUCCESS;
}
           
$ valgrind --vgdb=yes --tool=memcheck --leak-check=yes test7
==37863== Memcheck, a memory error detector
==37863== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==37863== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==37863== Command: test7
==37863==
==37863==
==37863== HEAP SUMMARY:
==37863==     in use at exit: 0 bytes in 0 blocks
==37863==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==37863==
==37863== All heap blocks were freed -- no leaks are possible
==37863==
==37863== For counts of detected and suppressed errors, rerun with: -v
==37863== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
           

繼續閱讀