c++畢業(yè)設(shè)計外文翻譯--修正內(nèi)存問題_第1頁
已閱讀1頁,還剩6頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、<p>  Fixing Memory Problems</p><p>  This chapter is about finding bugs in C/C++ programs with the help of a memory</p><p>  debugger. A memory debugger is a runtime tool designed to trace

2、 and detect bugs</p><p>  in C/C++ memory management and access. It does not replace a general debugger.</p><p>  In the following sections, we will describe the memory access bugs that typicall

3、y</p><p>  occur in C/C++ programs, introduce memory debuggers, and show with two examples</p><p>  how these tools find bugs. We will then show how to run memory and source</p><p>

4、  code debuggers together, how to deal with unwanted error messages by writing a</p><p>  suppression file, and what restrictions need to be considered.</p><p>  4.1 Memory Management in C/C++ –

5、 Powerful but Dangerous</p><p>  The C/C++ language is able to manage memory resources, and can access memory</p><p>  directly through pointers. Efficient memory handling and “programming close

6、 to the</p><p>  hardware” are reasons why C/C++ replaced assembly language in the implementation</p><p>  of large software projects such as operating systems, where performance and</p>

7、<p>  low overhead play a major role. The allocation of dynamic memory (also known as</p><p>  heap memory) in C/C++ is under the control of the programmer. New memory is</p><p>  allocated

8、 with functions such as malloc() and various forms of the operator new.</p><p>  Unused memory is returned with free() or delete.</p><p>  The memory handling in C/C++ gives a large degree of fr

9、eedom, control, and</p><p>  performance, but comes at a high price: the memory access is a frequent source of</p><p>  bugs. The most frequent sources of memory access bugs are memory leaks, in

10、correct</p><p>  use of memory management, buffer overruns, and reading uninitialized memory.</p><p><b>  33</b></p><p>  34 4 Fixing Memory Problems</p><p>

11、;  4.1.1 Memory Leaks</p><p>  Memory leaks are data structures that are allocated at runtime, but not deallocated</p><p>  once they are no longer needed in the program. If the leaks are freque

12、nt or large,</p><p>  eventually all available main memory in your computer will be consumed. The program</p><p>  will first slow down, as the computer starts swapping pages to virtual memory,&

13、lt;/p><p>  and then fail with an out-of-memory error. Finding leaks with a general debugger is</p><p>  difficult because there is no obvious faulty statement. The bug is that a statement is</p

14、><p>  missing or not called.</p><p>  4.1.2 Incorrect Use of Memory Management</p><p>  A whole class of bugs is associated with incorrect calls to memory management:</p><p

15、>  freeing a block of memory more than once, accessing memory after freeing it,</p><p>  or freeing a block that was never allocated. Also belonging to this class is using</p><p>  delete ins

16、tead of delete[] for C++ array deallocation, as well as using</p><p>  malloc() together with delete, and using new together with free().</p><p>  4.1.3 Buffer Overruns</p><p>  Buf

17、fer overruns are bugs where memory outside of the allocated boundaries is overwritten,</p><p>  or corrupted. Buffer overruns can occur for global variables, local variables</p><p>  on the stac

18、k, and dynamic variables that were allocated on the heap with memory</p><p>  management.</p><p>  One nasty artifact of memory corruption is that the bug may not become visible</p><p

19、>  at the statement where the memory is overwritten. Only later, another statement in</p><p>  the program will access this memory location. Because the memory location has an</p><p>  illega

20、l value, the program can behave incorrectly in a number of ways: the program</p><p>  may compute a wrong result, or, if the illegal value is in a pointer, the program will</p><p>  try to acces

21、s protected memory and crash. If a function pointer variable is overwritten,</p><p>  the program will do a jump and try to execute data as program code. The</p><p>  key point is that there may

22、 be no strict relation between the statement causing the</p><p>  memory corruption and the statement triggering the visible bug.</p><p>  4.1.4 Uninitialized Memory Bugs</p><p>  R

23、eading uninitialized memory can occur because C/C++ allows creation of variables</p><p>  without an initial value. The programmer is fully responsible to initialize</p><p>  all global and loca

24、l variables, either through assignment statements or through the</p><p>  4.2 Memory Debuggers to the Rescue 35</p><p>  various C++ constructors. The memory allocation function malloc() and ope

25、rator</p><p>  new also do not initialize or zero out the allocated memory blocks. Uninitialized</p><p>  variables will contain unpredictable values.</p><p>  4.2 Memory Debuggers

26、to the Rescue</p><p>  The above categories of memory access bugs created a need for adequate debugging</p><p>  tools. Finding bugs related to leaked, corrupted, or uninitialized memory with<

27、;/p><p>  a conventional debugger such as GDB turned out to be unproductive. To deal with</p><p>  memory leaks in large software projects, many programmers came up with the same</p><p&g

28、t;  idea. They created memory management functions/operators with special instrumentation</p><p>  to track where a memory block was allocated, and if each block was</p><p>  properly deallocate

29、d at the end of the program.</p><p>  Since everybody had the same memory bugs in their C/C++ programs, and since</p><p>  everybody improvised with custom instrumentation to track down at least

30、 some of</p><p>  these bugs, a market for a tool called memory debugger was created. The most wellknown</p><p>  tool is Purify, released in 1991 by Pure Software. Purify’s name has since</p

31、><p>  become synonymous with memory debugging. There is also Insure++, Valgrind, and</p><p>  BoundsChecker, among others. See the tools Appendix B.4 starting on page 198 for</p><p> 

32、 references and the survey in [Luecke06] for a comparison of features.</p><p>  Memory debuggers do detailed bookkeeping of all allocated/deallocated dynamic</p><p>  memory. They also intercept

33、 and check access to dynamic memory. Some</p><p>  memory debuggers can check access to local variables on the stack and statically allocated</p><p>  memory. Purify and BoundsChecker do this by

34、 object code instrumentation</p><p>  at program link time, Insure++ uses source code instrumentation, and Valgrind executes</p><p>  the program on a virtual machine and monitors all memory tra

35、nsactions. The</p><p>  code instrumentation allows the tools to pinpoint the source code statement where a</p><p>  memory bug occurred.</p><p>  The following bugs are detectable

36、by a memory debugger:</p><p>  ? Memory leaks</p><p>  ? Accessing memory that was already freed</p><p>  ? Freeing the same memory location more than once</p><p>  ? F

37、reeing memory that was never allocated</p><p>  ? Mixing C malloc()/free()with C++ new/delete</p><p>  ? Using delete instead of delete[] for arrays</p><p>  ? Array out-of-bound er

38、rors</p><p>  ? Accessing memory that was never allocated</p><p>  ? Uninitialized memory read</p><p>  ? Null pointer read or write</p><p>  We will show in the next s

39、ection how to attach a memory debugger to your program,</p><p>  and how the tool finds and reports bugs.</p><p>  36 4 Fixing Memory Problems</p><p>  4.3 Example 1: Detecting Memo

40、ry Access Errors</p><p>  Our first example is a program that allocates an array in dynamic memory, accesses</p><p>  an element outside the final array element, reads an uninitialized array ele

41、ment, and</p><p>  finally forgets to deallocate the array. We use the public domain tool Valgrind on</p><p>  Linux as the memory debugger, and demonstrate how the tool automatically detects<

42、;/p><p>  these bugs. This is the code of our program main1.c:</p><p>  1 /* main1.c */</p><p>  2 #include <stdio.h></p><p>  3 int main(int argc, char* argv[]) {&l

43、t;/p><p>  4 const int size=100;</p><p>  5 int n, sum=0;</p><p>  6 int* A = (int*)malloc( sizeof(int)*size );</p><p><b>  7</b></p><p>  8 for (

44、n=size; n>0; n--) /* walk through A[100]...A[1] */</p><p>  9 A[n] = n; /* error: A[100] invalid write*/</p><p>  10 for (n=0;n<size; n++) /* walk through A[0]...A[99] */</p><p&

45、gt;  11 sum += A[n]; /* error: A[0] not initialized*/</p><p>  12 printf ("sum=%d\n", sum);</p><p>  13 return 0; /* mem leak: A[] */</p><p><b>  14 }</b></

46、p><p>  We compile the program with debug information and then run under Valgrind:</p><p>  > gcc -g main1.c</p><p>  > valgrind --tool=memcheck --leak-check=yes ./a.out</p>

47、;<p>  In the following sections we go through the error list reported by Valgrind.</p><p>  4.3.1 Detecting an Invalid Write Access</p><p>  The first – and perhaps most severe – error i

48、s a buffer overrun: the accidental write</p><p>  access to array element A[100]. Because the array has only 100 elements, the</p><p>  highest valid index is 99. A[100] points to unallocated me

49、mory that is located</p><p>  just after the memory allocated for array A. Valgrind thus reports an “invalid write”</p><p><b>  error:</b></p><p>  ==11323== Invalid wri

50、te of size 4</p><p>  ==11323== at 0x8048518: main (main1.c:9)</p><p>  ==11323== Address 0x1BB261B8 is 0 bytes after a block</p><p>  ==11323== of size 400 alloc’d</p><p

51、>  ==11323== at 0x1B903F40: malloc</p><p>  ==11323== (in /usr/lib/valgrind/vgpreload_memcheck.so)</p><p>  ==11323== by 0x80484F2: main (main1.c:6)</p><p>  The string "==1

52、1323==" refers to the process ID and is useful when Valgrind is</p><p>  checking multiple processes 1. The important piece of information is that an invalid</p><p>  1 Valgrind will, per d

53、efault, check only the first (parent) process that has been invoked. Use option</p><p>  --trace-children=yes to check all child processes as well.</p><p>  4.3 Example 1: Detecting Memory Acces

54、s Errors 37</p><p>  write occurs in line 9 of main1.c. There is also additional information revealing</p><p>  the address of the closest allocated memory block and how it was allocated. The<

55、;/p><p>  memory debugger guesses that the invalid write in line 9 is related to this memory</p><p>  block. The guess is correct because both belong to the same array A.</p><p>  Note

56、 that Valgrind is able to catch an out-of-array-bounds errors only when the</p><p>  array is allocated as dynamic memory with malloc() or new. This is the case in</p><p>  the example with the

57、statement in line 6:</p><p>  6 int* A = (int*)malloc( sizeof(int)*size );</p><p>  If the example were instead written as int A[size] in line 6, then A would be</p><p>  a local va

58、riable located on the stack and not on the heap. It turns out that Valgrind</p><p>  does not detect such an error but Purify is able to catch it. This shows that not all</p><p>  memory debugge

59、rs will report exactly the same errors.</p><p><b>  修正內(nèi)存問題</b></p><p>  本章是關(guān)于利用內(nèi)存BUG調(diào)試器的幫助,來發(fā)現(xiàn)C或C++程序中的BUG。內(nèi)存調(diào)試器是在C或C++程序管理或存儲時用于追蹤和發(fā)現(xiàn)BUG的運行時工具。它不能取代一個正規(guī)的調(diào)試器。在一下的章節(jié),我們將描述幾個代表性的在C或C++

60、程序中處理的內(nèi)容BUG,介紹內(nèi)容調(diào)試器,并且介紹兩個內(nèi)存如何發(fā)現(xiàn)BUG的例子。我們?nèi)缓髮⒀菔救绾问箖?nèi)存與編碼調(diào)試器一起運行,怎么去處理不需要的錯誤信息通過寫文件,需要去考慮程序需要的限制。</p><p>  4.1 內(nèi)存管理在C或C++中強健但是危險</p><p>  C或C++語言能夠管理內(nèi)存資源,并且通過指針直接讀取內(nèi)存。高效的內(nèi)存處理和“直接控制硬件”是規(guī)劃大型例如操作系統(tǒng)的軟件

61、工程取代匯編語言的原因,高性能和低限制是它作為一個重要角色的原因。動態(tài)內(nèi)存的分配(眾所周知的堆內(nèi)存)在C或C++中是在程序員的控制之下的。新內(nèi)存被分配擔(dān)任起例如malloc()和各種有程序員構(gòu)成的新的指針。不被使用的內(nèi)存被free()或delete回收。</p><p>  4.1.1 內(nèi)存泄漏</p><p>  內(nèi)存泄漏是在運行時的內(nèi)存分配結(jié)構(gòu),但是它們只需要我們分配一次,我們卻分配了

62、多次。如果內(nèi)存泄漏經(jīng)常發(fā)生或者十分巨大,最后你電腦的主要內(nèi)存將被耗盡。程序首先會變慢,然后電腦開始使用分頁技術(shù)虛擬內(nèi)存,然后以內(nèi)存溢出錯誤宣告失敗。用普遍的調(diào)試器發(fā)現(xiàn)內(nèi)存溢出錯誤是困難的因為它沒有一個明顯的錯誤聲明。BUG會丟失或不能被聲明。</p><p>  4.1.2 錯誤的內(nèi)存管理用法</p><p>  一套完整BUG集合與錯誤聲明對于內(nèi)存管理來說:解除一個錯誤的內(nèi)存超過一次,在

63、解除以后訪問內(nèi)存,或解除一個從分配過的阻塞內(nèi)存。用delete代替delete[]在C++數(shù)組中也屬于這個類,也可以用malloc()和delete一起使用,用new和free()一起使用。</p><p>  4.1.3 緩存溢出</p><p>  緩存溢出內(nèi)存被重載時超出范圍的BUG,或損壞。緩存溢出會由屬性引起,在堆中的局部變量,通過內(nèi)存管理分配在棧上的動態(tài)變量。</p>

64、;<p>  在內(nèi)存中令人討厭的事是內(nèi)存重載的時候BUG沒有被聲明。只有在以后,另一個在問題中的聲明將存取在內(nèi)存中。因為內(nèi)存含有一個不合法的變量,內(nèi)存會在一下幾個方面表現(xiàn)出異常:這個問題得出一個錯誤的結(jié)果,或者如果一個不合法的值在指針上,這個問題將試圖存取和保護內(nèi)存。如果在存取的過程中一個動態(tài)指針可變,程序?qū)⑻幚硭凑粘绦虼a。鍵指針不是引起內(nèi)存溢出和嚴重問題的關(guān)鍵。</p><p>  4.1.4

65、 非原始內(nèi)存BUG</p><p>  讀非原始內(nèi)存是因為C或C++允許創(chuàng)建變量在沒有一個原始值的情況下。程序員有完全的責(zé)任給所有的屬性和局部變量賦值,也可以通過聲明,或各種C++的構(gòu)造器。內(nèi)存引導(dǎo)功能malloc()和操作new也不能夠定義變量或者是內(nèi)存為空。未定義的變量中包含不穩(wěn)定的值。</p><p>  4.2 內(nèi)存調(diào)試解決</p><p>  上述問題處理

66、BUG需要創(chuàng)建一個強大的BUG處理工具。尋找BUG與漏洞有關(guān),不完善的,只有普通BUG調(diào)試器GDB內(nèi)存變得不安全。應(yīng)付大型軟件工程中的系統(tǒng)漏洞,很多程序員都提出了相同的意見。他們建立內(nèi)存管理機制為一個被分配阻塞內(nèi)存利用不同的機制,并且確保是否每個阻塞內(nèi)存在最后都得到了分配。</p><p>  自從每個人在各自的C或C++程序中遇到相同的內(nèi)存BUG,自從每個人用傳統(tǒng)的內(nèi)存處理器追蹤到很少的幾個BUG,一系列叫內(nèi)存

67、調(diào)試器的工具誕生了。最總所周知的是Purify,在1991年被Pure軟件公司發(fā)布。Purify一直被用于一些同類的內(nèi)存調(diào)試器。也有Insure++,Valgrind,也有BoundsChecker,除此之外的一些其他同類工具。</p><p>  內(nèi)存調(diào)試器作用于所有被動態(tài)分配的內(nèi)存。他們同樣攔截和檢查分配過的內(nèi)存。一些內(nèi)存調(diào)試器能夠檢查一些被分配在棧上的局部變量和被分配過的內(nèi)存。Purify和BoundsCh

68、ecker用代碼編譯工具完成這些工作在程序連接期間,Insure++利用源代碼編譯工具,Valgrind則把程序先執(zhí)行在虛擬機上并且監(jiān)聽所有的內(nèi)存處理。源代碼編譯工具允許一個BUG發(fā)生的時候精確的找到代碼發(fā)生的位置。</p><p>  一下的BUG被內(nèi)存調(diào)試器處理:</p><p><b>  內(nèi)存泄漏</b></p><p>  訪問已經(jīng)被

69、釋放的內(nèi)存</p><p>  釋放一段內(nèi)存空間不止一次</p><p>  釋放從未被分配過的內(nèi)存</p><p>  把C中的malloc(),free()與C++中的 new/delette混雜在一起</p><p>  在數(shù)組中用delete代替delete[]</p><p><b>  數(shù)組越界錯

70、誤</b></p><p>  訪問從未被分配過的內(nèi)存</p><p>  未被定義過的內(nèi)存讀取</p><p><b>  空指針讀或?qū)?lt;/b></p><p>  我們將在下一章節(jié)演示如何為你的程序附屬內(nèi)存調(diào)試器,內(nèi)存調(diào)試器如何發(fā)現(xiàn)和報告錯誤。</p><p>  4.3 例1檢測

71、內(nèi)存訪問錯誤</p><p>  我們第一個例子是在動態(tài)內(nèi)存中分配一列,存取最后一個在數(shù)組序列外的元素,讀一個未定義的數(shù)組元素,最終忘記分配這個數(shù)組。我們用公共范圍工具Valgrind在Linux上作為內(nèi)存調(diào)試器,演示內(nèi)存調(diào)試器如何自動的解決這些BUG。</p><p>  4.3.1 檢查一個無用的寫操作</p><p>  第一個最大最嚴重的錯誤是緩存溢出:對這

72、個數(shù)組以外的寫操作。因為這個數(shù)組只有100個元素,最大的有效索引是99。100指針超過了這個數(shù)組的有效范圍。一次報告一個無用的寫錯誤。</p><p>  ==11323== Invalid write of size 4</p><p>  ==11323== at 0x8048518: main (main1.c:9)</p><p>  ==11323== A

73、ddress 0x1BB261B8 is 0 bytes after a block</p><p>  ==11323== of size 400 alloc’d</p><p>  ==11323== at 0x1B903F40: malloc</p><p>  ==11323== (in /usr/lib/valgrind/vgpreload_memchec

74、k.so)</p><p>  ==11323== by 0x80484F2: main (main1.c:6)</p><p>  這個字符串,應(yīng)用一個過程ID,當(dāng)Valgrind檢查過程的時候是十分必要的。最重要的信息塊是在第9行的寫操作。這依然有信息補充說明根據(jù)以離內(nèi)存最近的區(qū)域和它是怎么被分配的。內(nèi)存調(diào)試器猜測第9行與內(nèi)存阻塞有關(guān)。這個猜測被修正因為兩個都屬于數(shù)組A。</p&

75、gt;<p>  在Valgrind中內(nèi)存中數(shù)組下標越界錯誤只有當(dāng)動態(tài)內(nèi)存被定義為malloc()或new的情況下。這個是第6行的實例:</p><p>  6 int*A = (int * )malloc (sizeof(int) * size)</p><p>  如果例子中書寫A[size]在第6行,A將被定義在一個局部變量上,堆而不是棧上。它表現(xiàn)出Valgrind

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 眾賞文庫僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論