日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

内存问题分析的利器——valgrind的memcheck

發(fā)布時間:2023/11/27 生活经验 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 内存问题分析的利器——valgrind的memcheck 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

? ? ? ? 在《內(nèi)存、性能問題分析的利器——valgrind》一文中我們簡單介紹了下valgrind工具集,本文將使用memcheck工具分析各種內(nèi)存問題。(轉(zhuǎn)載請指明出于breaksoftware的csdn博客)

? ? ? ? 本文所有的代碼都是使用g++ -O0 -g mem_error.c -o mem_erro編譯;分析都是使用valgrind --tool=memcheck ./mem_error指定(除非特殊說明)。

寫違例

#include <stdlib.h>int main() {const int array_count = 4;int* p = malloc(array_count * sizeof(int));p[array_count] = 0; // Illegal read?free(p);return 0;
}

? ? ? ? 上述代碼只分配了4個int型大小的空間,但是第6行要往該空間之后的空間寫入數(shù)據(jù),這就造成了寫違例。使用valgrind分析會顯示

==18100== Invalid write of size 4
==18100==    at 0x400658: main (mem_error.c:6)
==18100==  Address 0x51e0050 is 0 bytes after a block of size 16 alloc'd
==18100==    at 0x4C27BC3: malloc (vg_replace_malloc.c:299)
==18100==    by 0x40063F: main (mem_error.c:5)

? ? ? ? 第一行顯示有4個字節(jié)被違例寫入,第三行顯示寫入的位置在分配的16個字節(jié)之后。

讀違例

#include <stdlib.h>int main() {const int array_count = 4;int* p = malloc(array_count * sizeof(int));int error_num = p[array_count]; // Illegal readfree(p);return 0;
}

? ? ? ? 錯誤的位置和上例一樣,區(qū)別在于這次是讀取不合法的地址的數(shù)據(jù)。使用valgrind分析顯示

==31461== Invalid read of size 4
==31461==    at 0x400658: main (mem_error.c:6)
==31461==  Address 0x51e0050 is 0 bytes after a block of size 16 alloc'd
==31461==    at 0x4C27BC3: malloc (vg_replace_malloc.c:299)
==31461==    by 0x40063F: main (mem_error.c:5)

? ? ? ? 第一行顯示有4個字節(jié)被違例讀取,第三行顯示讀取的位置在分配的16個字節(jié)之后。

使用未初始化變量

? ? ? ? 這是初學C/C++編程的人非常容易犯的錯誤。

#include <stdlib.h>
#include <stdio.h>int main() {const int array_count = 4;int* p = malloc(array_count * sizeof(int));printf("%d",  p[array_count - 1]);free(p);int undefine_num;printf("%d", undefine_num);return 0;
}

? ? ? ? 第7行和第11行分別訪問了堆上、棧上未初始化的變量。valgrind分析顯示

==24104== Conditional jump or move depends on uninitialised value(s)
==24104==    at 0x4E79F7F: vfprintf (in /home/opt/gcc-4.8.2.bpkg-r4/gcc-4.8.2.bpkg-r4/lib64/libc-2.18.so)
==24104==    by 0x4E837A8: printf (in /home/opt/gcc-4.8.2.bpkg-r4/gcc-4.8.2.bpkg-r4/lib64/libc-2.18.so)
==24104==    by 0x4006BA: main (mem_error.c:7)
==24104== 
==24104== Conditional jump or move depends on uninitialised value(s)
==24104==    at 0x4E79E37: vfprintf (in /home/opt/gcc-4.8.2.bpkg-r4/gcc-4.8.2.bpkg-r4/lib64/libc-2.18.so)
==24104==    by 0x4E837A8: printf (in /home/opt/gcc-4.8.2.bpkg-r4/gcc-4.8.2.bpkg-r4/lib64/libc-2.18.so)
==24104==    by 0x4006DA: main (mem_error.c:11)
==24104== 

? ? ? ? 雖然這個報告已經(jīng)非常詳細,但是我們還可以給valgrind增加--track-origins=yes,以打印問題出現(xiàn)在哪個結(jié)構(gòu)上。當然這也會導致valgrind分析的比較慢

==29911== Conditional jump or move depends on uninitialised value(s)
==29911==    at 0x4E79F7F: vfprintf (in /home/opt/gcc-4.8.2.bpkg-r4/gcc-4.8.2.bpkg-r4/lib64/libc-2.18.so)
==29911==    by 0x4E837A8: printf (in /home/opt/gcc-4.8.2.bpkg-r4/gcc-4.8.2.bpkg-r4/lib64/libc-2.18.so)
==29911==    by 0x4006BA: main (mem_error.c:7)
==29911==  Uninitialised value was created by a heap allocation
==29911==    at 0x4C27BC3: malloc (vg_replace_malloc.c:299)
==29911==    by 0x40068F: main (mem_error.c:6)
==29911== 
==29911== Conditional jump or move depends on uninitialised value(s)
==29911==    at 0x4E79E37: vfprintf (in /home/opt/gcc-4.8.2.bpkg-r4/gcc-4.8.2.bpkg-r4/lib64/libc-2.18.so)
==29911==    by 0x4E837A8: printf (in /home/opt/gcc-4.8.2.bpkg-r4/gcc-4.8.2.bpkg-r4/lib64/libc-2.18.so)
==29911==    by 0x4006DA: main (mem_error.c:11)
==29911==  Uninitialised value was created by a stack allocation
==29911==    at 0x400670: main (mem_error.c:4)

在系統(tǒng)函數(shù)中使用未初始化變量

? ? ? ? 我們看一個稍微復雜點的例子。下例中,test函數(shù)操作的是一個未初始化的變量,所以其結(jié)果是不可預知的。

#include <stdlib.h>
#include <stdio.h>void test(int n) {n = n + 1;
}int main() {const int array_count = 4;int* p = malloc(array_count * sizeof(int));test(p[array_count - 1]);free(p);return 0;
}

? ? ? ? valgrind并不知道上述代碼的作者想表達什么,所以它并沒有報錯

==28259== Command: ./mem_error
==28259== 
==28259== 
==28259== HEAP SUMMARY:
==28259==     in use at exit: 0 bytes in 0 blocks
==28259==   total heap usage: 1 allocs, 1 frees, 16 bytes allocated
==28259== 
==28259== All heap blocks were freed -- no leaks are possible
==28259== 
==28259== For counts of detected and suppressed errors, rerun with: -v
==28259== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

? ? ? ?但是如果錯誤調(diào)用是針對系統(tǒng)函數(shù)。valgrind是知道系統(tǒng)函數(shù)的輸入要求的,于是就可以判定這種行為違例。我們稍微改下代碼

#include <stdlib.h>
#include <stdio.h>void test(int n) {n = n + 1;write(stdout, "xxx", n); 
}int main() {const int array_count = 4;int* p = malloc(array_count * sizeof(int));test(p[array_count - 1]);free(p);return 0;
}

? ? ? ? valgrind就會分析出第6行系統(tǒng)方法write的第三個參數(shù)未初始化。

==4344== Syscall param write(count) contains uninitialised byte(s)
==4344==    at 0x4F0BED0: __write_nocancel (in /home/opt/gcc-4.8.2.bpkg-r4/gcc-4.8.2.bpkg-r4/lib64/libc-2.18.so)
==4344==    by 0x4006CA: test (mem_error.c:6)
==4344==    by 0x40070D: main (mem_error.c:12)

釋放空間出錯

? ? ? ? 我們可能重復釋放同一段空間,或者給釋放函數(shù)傳入不是堆上的地址,或者使用了不對稱的方法申請釋放函數(shù)。這類錯誤發(fā)生在free,delete,delete[]和realloc上。

? ? ? ? 反復free同一段空間

#include <stdlib.h>int main() {const int array_count = 4;int* p = malloc(array_count * sizeof(int));free(p);free(p);return 0;
}

? ? ? ?使用valgrind分析,報告顯示第7行釋放了第6行已經(jīng)釋放了的空間,這個空間是在第5行申請的。

==6537== Invalid free() / delete / delete[] / realloc()
==6537==    at 0x4C28CBD: free (vg_replace_malloc.c:530)
==6537==    by 0x40065B: main (mem_error.c:7)
==6537==  Address 0x51e0040 is 0 bytes inside a block of size 16 free'd
==6537==    at 0x4C28CBD: free (vg_replace_malloc.c:530)
==6537==    by 0x40064F: main (mem_error.c:6)
==6537==  Block was alloc'd at
==6537==    at 0x4C27BC3: malloc (vg_replace_malloc.c:299)
==6537==    by 0x40063F: main (mem_error.c:5)

? ? ? ? 釋放一個不是堆的空間

#include <stdlib.h>int main() {int n = 1;int* p = &n;free(p);return 0;
}

? ? ? ? valgrind會報告錯誤的釋放棧上空間

==32411== Invalid free() / delete / delete[] / realloc()
==32411==    at 0x4C28CBD: free (vg_replace_malloc.c:530)
==32411==    by 0x4005F2: main (mem_error.c:6)
==32411==  Address 0x1fff000234 is on thread 1's stack
==32411==  in frame #1, created by main (mem_error.c:3)

? ? ? ? 申請釋放方法不對稱

? ? ? ? 對稱的方法是指:

  • new使用delete釋放
  • new[]使用delete[]釋放
  • alloc類函數(shù),如malloc,realloc等使用free釋放
#include <stdlib.h>int main() {int* p = new int(1);free(p);return 0;
}

? ? ? ? valgrind可以分析出這種不對稱調(diào)用——new申請空間,free釋放空間。

==5666== Mismatched free() / delete / delete []
==5666==    at 0x4C28CBD: free (vg_replace_malloc.c:530)
==5666==    by 0x400737: main (mem_error.c:5)
==5666==  Address 0x59fc040 is 0 bytes inside a block of size 4 alloc'd
==5666==    at 0x4C281E3: operator new(unsigned long) (vg_replace_malloc.c:334)
==5666==    by 0x400721: main (mem_error.c:4)

空間覆蓋

? ? ? ? 當我們操作內(nèi)存時,可能會發(fā)生內(nèi)存覆蓋。

#include <stdlib.h>
#include <string.h>                                                                                                                                                        int main() {const int array_size = 8;char p[array_size] = {0};memcpy(p + 1, p, sizeof(char) * array_size);return 0;
}

? ? ? ? 這段代碼的目的空間覆蓋了源空間

? ? ? ? valgrind分析的報告也說明了這個錯誤

==25991== Source and destination overlap in memcpy(0x1fff000231, 0x1fff000230, 8)
==25991==    at 0x4C2BFEC: memcpy@@GLIBC_2.14 (vg_replace_strmem.c:1022)
==25991==    by 0x4006E2: main (mem_error.c:7)

可疑的參數(shù)

? ? ? ? 在C/C++中,有符號數(shù)的負數(shù)的二進制最高位是0x1。如果把一個負數(shù)看成一個無符號類型的數(shù),則可以表達出極大數(shù),比如0xFFFFFFFF(無符號值4294967295,有符號值-1),因為它們的底層二進制值是一致的。

? ? ? ? 有事我們在調(diào)用內(nèi)存分配時,不小心將空間大小設(shè)置為一個負數(shù),就要求申請一個極大的空間,這明顯是有問題的。

#include <stdlib.h>int main() {const int array_size = -1;void* p = malloc(array_size);free(p);return 0;
}

? ? ? ? 這個時候valgrind就會檢測出參數(shù)可疑

==3364== Argument 'size' of function malloc has a fishy (possibly negative) value: -1
==3364==    at 0x4C27BC3: malloc (vg_replace_malloc.c:299)
==3364==    by 0x40070A: main (mem_error.c:5)

內(nèi)存泄露

? ? ? ? 內(nèi)存泄露是比較常見的問題,往往也是非常難以排查的問題。

#include <stdlib.h>int main() {const int array_size = 32; void* p = malloc(array_size);return 0;
}

? ? ? ? 這次我們給valgrind增加選項--leak-check=full以顯示出詳細信息

valgrind --tool=memcheck --leak-check=full ./mem_error

? ? ? ? valgrind分析出第5行分配的空間沒有釋放。其中definitely lost是指“確認泄露”,

==17393== HEAP SUMMARY:
==17393==     in use at exit: 32 bytes in 1 blocks
==17393==   total heap usage: 1 allocs, 0 frees, 32 bytes allocated
==17393== 
==17393== 32 bytes in 1 blocks are definitely lost in loss record 1 of 1
==17393==    at 0x4C27BC3: malloc (vg_replace_malloc.c:299)
==17393==    by 0x4006B8: main (mem_error.c:5)
==17393== 
==17393== LEAK SUMMARY:
==17393==    definitely lost: 32 bytes in 1 blocks
==17393==    indirectly lost: 0 bytes in 0 blocks
==17393==      possibly lost: 0 bytes in 0 blocks
==17393==    still reachable: 0 bytes in 0 blocks
==17393==         suppressed: 0 bytes in 0 blocks

總結(jié)

以上是生活随笔為你收集整理的内存问题分析的利器——valgrind的memcheck的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。