Methods and tools for reducing memory defects in c ++ Coding

Source: Internet
Author: User
Tags coding standards exit in

Cheng zhenlin, Fang Jinyun, Tang Zhimin
(Institute of computing technology, Chinese Emy of Sciences, Beijing 100080, China)

Abstract: Most of the defects and errors of C ++-based software are related to memory, preventing, discovering, and eliminating memory-related defects in code, it becomes an important task for programmers to write, debug, and maintain code. This article is based on the engineering practices of the project "large-scale GIS for massive network space information, the methods and tools for how to use the C ++ language mechanism, development environment, and Related Quality Assurance tools to prevent and discover various memory defects during compilation and runtime are proposed and summarized.

Key words: C ++; memory errors; Memory leakage; Quality assurance

Techniques and tools of defending memory-related defects in software coded Inc ++
Cheng zhenlin, Fang Jinyun, Tang Zhimin
(Institute of computing technology, Chinese Emy of sciences, beijing100080)
[Abstract] Most of the defects and errors in the softwarecoded in C ++ are memory-related. based on the practice in the "Network, large volumespatial information oriented GIS" project, this paperpresentsthe techniques and tools to find and fix the memory problems
During thecoding, debugging and production release phase with the support of the C ++ language mechanic, development environment and related quality-assurancetools.
[Key Words] C ++; memory errors; Memory leak; Quality assurance

C ++ is a mainstream development language for desktop systems, especially system software and large-scale application software. C ++ is known for its flexibility and complexity. Using C ++ to write robust code is more challenging. C ++ allows dynamic memory management and can easily cause more memory-related problems. In general, apart from system design defects, C ++-Based Software defects and errors are mostly related to memory defects (mainly including memory access errors and memory leaks. Therefore, Eliminating Memory-related defects in the Code has become a task for programmers to write, debug, and maintain code. It is also the key to ensuring software quality.
This article is based on the "863" project "large-scale GIS for massive network space information. The system is written based on C ++/MFC and the development environment is Visual Studio. NET 2003. Based on the engineering practices of this project, it summarizes the methods and tools for using the C ++ language mechanism, development environment, and Related Quality Assurance tools to prevent and discover various defects related to compilation, runtime, and memory.
1. Compliance with C ++ coding standards and practices to prevent Defects
Coding standards are language-related rules and are lessons learned from practice. Good programming standards will effectively help developers avoid developing potentially dangerous code. Generally, to reduce memory defects, the following encoding rules should be followed:
(1) The destructor of a base class or class with a virtual function should be declared as a virtual function.
(2) prevent memory leakage in constructor. Do not throw exceptions in destructor.
(3) Use the corresponding form of new and delete. That is, delete is used to release the memory applied for new. Delete [] releases the memory applied for by new.
(4) the pointer must be initialized before use. The pointer pointing to the dynamic memory should be set to null immediately after being released.
(5) if resources are allocated to the class constructor, You need to explicitly provide the copy constructor and the value assignment operator, and release resources in the destructor.
It is worth noting the conventional usage of raiI in C ++. The core idea of raiI is to use objects to manage resources, obtain resources in object constructors, and release resources in their destructor [2]. To ensure that the dynamically applied memory can be released even when exceptions occur, it is ideal to use local variables to manage the ownership of the dynamic memory (ownership ), is the so-called smart pointer. Auto_ptr in STL is designed to solve the problem of resource ownership, but it lacks support for the number of references and arrays and cannot be used in STL containers. The boost Library [3] provides relatively mature smart pointers with high practical value. Where,Shared_ptrThread security and can be used in STL containers. For more information, see [3].
1.1 CodeWizard
CodeWizard can automatically scan, analyze, and check the source program. Once an violation is found, information is generated to indicate which rule does not match and an explanation is given. Taking CodeWizard 4.3 as an example, more than 500 encoding standards are built in. CodeWizard can select the encoding standards to be executed for the current project. CodeWizard can be closely integrated with VC ++. After installation, there will be a CodeWizard toolbar in VC ++.
1.2 code check tool PC-Lint
PC-Lint can check for errors that are not easily discovered by the compiler. PC-Lint can check more than 100 c-library functions and discover more than common errors in Standard C/C ++ code. To integrate PC-lint with Visual Studio, You need to configure it yourself. Jon zyzyck provides a Report Generator to help with this task. Can be downloaded in the http://www.ddj.com. Document [4] explains how to integrate PC-lint in the VC ++ environment.
2. Use language mechanisms, development environments, and related tools to prevent and detect memory Defects
Discovering a problem is a prerequisite for solving the problem. Compared with fixing memory defects, it is more time-consuming and labor-consuming to discover memory defects and accurately locate the code that causes the defects. Early and accurate detection of memory defects is very important for improving development efficiency.
2.1 Early Exposure of memory defects using assertions
Assertions are Boolean debugging statements used to check whether the value of a condition is always true when the program is running. Assertions are often used to confirm the input and output of functions, and check whether the current state of an object is valid. Assertions can be used in the following scenarios to help identify errors related to illegal memory access:
(1) verify whether the pointer is readable/written. At the function entrance, it is often necessary to verify whether the content area pointed to by the pointer is readable/written. Usually assert (P! = NULL. However, if the pointer value is not null, it does not mean that the Pointer Points to the legal read/write memory. Win32 API provides functions such as isbadreadptr, isbadwriteptr, isbadstringptr, and isbadcodeptr to detect whether the memory area pointed to by the pointer is readable/written. The C Runtime Library provides functions such as _ crtis validpointer and _ crtisvalidheappointer. The MFC Library provides functions such as afxisvalidaddress and afxisvalidstring to complete similar functions.
(2) For an MFC-based program, the assert_valid macro calls the overloaded assertvalid function to determine whether the pointer to the cobject derived class object is valid. The assert_valid macro mainly calls the afxisvalidaddress function and the assertvalid function of the cobject derived class Object (refer to the source code afx. h and objcore. cpp of MFC ).
2.2 Use the C Runtime Library to check memory leakage
The C Runtime Library (CRT) of VC ++ provides a wide range of functions to help users detect memory leaks. CRT provides functions such as _ crtmemcheckpoint, _ crtdumpmemoryleaks, and _ crtsetdbgflag to help debug memory leaks.
For non-MFC projects, to enable the effective Memory Leak report function, you need to perform the following settings:

(1) Add the following code in the stdafx. h header and enable the compiler/YU option:

# DEFINE _ crtdbg_map_alloc

# Include <stdlib. h>

# Include <crtdbg. h>

# Define debug_new new (_ normal_block, this_file, _ line __)

(2) ensure that the header of each. cpp file contains the following content:

# Include "stdafx. H"

# Ifdef _ debug

# Define new debug_new

# UNDEF this_file

Static char this_file [] = _ file __;

# Endif

(3) Enable the report Memory leakage switch at the beginning of the program:
_ Crtsetdbgflag (_ crtdbg_alloc_mem_df | _ crtdbg_leak_check_df );
For the MFC project, MFC has done the relevant work, just confirm that the header of each. cpp file contains the content at (2) above.
In some cases, you need to know the content of the memory block in which memory leakage occurs, but the standard memory dump is only in the hexadecimal format of the memory block header. To obtain more useful information, you need to apply for memory as a user block (_ client _ block) and use _ crtsetdumpclient to create a dump function for user block memory. Specifically, for classes not inherited from cobject, You need:

(1) specify a user block subtype for each class/Structure (refer to crtdbg. h ).

(2) When applying for memory, use the reloaded new form: void * _ cdecl operator new (size_tnsize, int ntype, lpcstr lpszfilename, int nline) (refer to the afxmem source code of MFC. CPP), where ntype is the child type of the user block.

(3) create a user block memory dump function to process each sub-type to be dump (which must contain dbgint. h ).

(4) use _ crtsetdumpclient to register the user block memory dump function (refer to the MFC source code dumpinit. cpp ).

For Classes inherited from cobject, MFC has done the basic work according to the above method (refer to the MFC source code afxmem. cpp, dumpinit. cpp ). To effectively dump objects inherited from cobject, You need to: (1) Reload the virtual function dump for each class inherited from cobject. (2) Add the code afxdump. setdepth (1) in the initialization part of the program to enable the deep dump.

2.3 use purify and insure ++ to find runtime memory Defects
Rational purify and parasoft insure ++ are tools used for runtime error checks. Purify mainly checks: Array Memory out-of-bounds read/write, use uninitialized memory, read/write the released memory, and memory leakage. Insure ++ uses its patented technology (source code plug-in and runtime pointer tracking) to detect a large number of Memory Operation errors and Report incorrect source code lines and execution tracks. According to the author's test (based on 98 c ++ programs with various memory errors, covering typical cases), insure ++ 6.1 can be accurately detected.
3. Use the debugging and diagnosis functions in the VC ++ environment to check and discover common memory Defects
Understanding common memory defect problems and symptoms in the VC ++ environment can help us reduce the problem occurrence and timely modify the problem.
Stack-related errors are classified into two types: Stack Overflow and function return information destruction.

(1) Stack Overflow)

There are two main scenarios for such errors:

1) excessive local variables. By default, Windows reserves 1 MB of stack space for each thread. Choose project> Properties> configurationproperties> linker> system. The stack reserve Size Option is displayed to adjust the size of the reserved stack space.

2) The number of recursive calls is too deep. During the debugging process, the call Stack window shows the recursive call mode of the function.

(2) Information returned by the function is damaged.

There are two main scenarios for such errors:
1) write operations on local variables are out of the range (overflow ). During the debugging process, the obvious indicator of the function stack being destroyed is that the call stack cannot be displayed, and the error occurs in the location where the called function is about to return.
2) If there is a mismatch between the called function and the called function, or the call specification is inconsistent.
To check for such errors, enable/GS and/RTCs during code compilation (in the menu project> Properties> configurationproperties> C/C ++> code generation ).
Another type of error is a dynamic memory error. The typical situation is as follows:
(1) memory write out of bounds. In the debugging version, if the write overflow occurs, the system will receive "damage: After block... ", if it is a write overflow, it will receive" damage: Before block....
(2) Delete invalid pointers. In the debugging version, when uninitialized or non-heap pointers are deleted, the _ crtisvalidheappointer asserted error is returned.
(3) Multiple releases. In the debug version, if you delete the same pointer multiple times, the _ block_type_is_valid asserted error is returned. To prevent such errors, delete a pointer to the dynamic memory and immediately leave it blank.

4. Use Windows structured exception handling mechanism to handle memory crashes of released software versions
During the program release stage, program errors, especially memory crashes, should be minimized. If the program crashes, you should exit elegantly and try to collect running information when the program crashes to help the program supplier with subsequent debugging. To capture illegal memory access and obtain the instruction address and register content for illegal access, you need to use the Windows structured exception handling (seh) mechanism [6]. Minidumpwritedump is dbghelp. an API function provided by DLL (refer to msdn), used to dump some information of user mode programs (such as stack conditions) and co-exist as a file (such. DMP file). This file can be used by Microsoft's debugger (VC ++ or windbg) for post-event debugging. To use this function, dbghelp. H, dbghelp. Lib, and dbghelp. dll are required.
In Platform SDK ).
To debug the code based on the. dmp file afterwards, you need to generate the debug symbols (PDB) file for the released software version (enable the compiler/debug option ). After obtaining the. dmp file, use VC ++ to open the. dmp file and debug the file (Press F5 ). In this way, the crash scene will reappear. Document [5] implements the crash reporting system based on the above method.

5 conclusion
Practice has proved that the methods and tools to reduce Software Memory defects supported by the above methods and tools can effectively prevent and find out memory errors and memory leaks in the code, in addition, it can be seamlessly integrated with the daily coding of developers and can be executed very efficiently. The above methods work with unit testing, code review, daily building, bug tracking, and other measures to form an efficient quality assurance process, which plays an important role in the software development process of our large-scale platform.

References
1 Sutter H, Alexandrescu A. C ++ coding standards: 101 rules, guidelines, andbest practices [M]. Addison-Wesley professional, 2004-10.
2 stroustrup B. The design and evolution of C ++ [M]. Addison-wesleyprofessional, 1994-03.
3 Karlsson B. Beyond the C ++ standard library: An Introduction to boost [M]. Addison-Wesley professional, 2005-08.
4 zyzyck J. A Report Generator for PC-Lint [J]. dr. Dobb's journal, 2003, 28 (2): 52.
5 Dietrich H. xcrash Report: Exception Handling and crash reporting [Z]. 2003-10. http://www.codeproject.com/debug/ xcrash reportpt4.asp.
6 Richter j m. Programming applications for Microsoft Windows [M]. microsoftpress, 1999-09.

 

 

 

One of the most powerful functions of the C/C ++ programming language is its dynamic allocation and release of memory. However, the Chinese saying goes: "The greatest strength may also become the biggest weakness ", then the C/C ++ application confirms this sentence. During C/C ++ application development, improper processing of dynamically allocated memory is the most common problem. Among them, one of the most elusive and most difficult errors to detect is the memory leakage, that is, the error of failing to correctly release the previously allocated memory. Occasionally, a small amount of memory leakage may not attract our attention, but programs that leak a large amount of memory or leak an increasing number of programs may show a variety of symptoms: from poor performance (and gradually decreasing) to completely exhausted memory. Worse, the leaked program may use too much memory, causing another program to crash, making it impossible for users to find the real root cause of the problem. In addition, even harmless memory leaks may affect the pool.

Fortunately, the Visual Studio debugger and the C Runtime (CRT) library provide us with an effective way to detect and identify memory leaks. Share the following with me: How can I use the CRT debugging function to detect memory leaks?

I. How to enable the memory leakage detection mechanism

The default status of VC ++ ide does not enable the memory leakage detection mechanism. That is to say, even if a piece of code has memory leakage, the debug page of the output window of the debugging session will not output information about the memory leakage. You must set two basic mechanisms to enable the Memory Leak Detection mechanism.

First, use the debug heap function:

# DEFINE _ crtdbg_map_alloc
# Include <stdlib. h>

# Include <crtdbg. h>

Note: # include statement order. If you change this order, the function used may not work properly.

By including the crtdbg. h header file, you can map the malloc and free functions to its "debug" version _ malloc_dbg and _ free_dbg. These functions track memory allocation and release. This ing is only valid for debugging (Debug) versions (that is, to define _ Debug. The release version (release) uses common malloc and free functions. # The define statement maps the basic version of the CRT heap function to the corresponding "debug" version. This statement is not required, but if it is not available, the information about memory leakage will be incomplete.

The second is to add the following statement to output Memory leakage information where the memory leak needs to be detected:

_ Crtdumpmemoryleaks ();

When running a program in the debugger, _ crtdumpmemoryleaks will display Memory leakage information on the debug page of the output window. For example, detected memoryleaks!

Dumping objects->

C: \ temp \ memleak. cpp (15): {45} normal block at 0x00441ba0, 2 byteslong.

Data: <AB> 41 42

C: \ Program Files \ Microsoft Visual Studio \ vc98 \ include \ crtdbg. H (552): {44} normal
Block at 0x00441bd0, 33 bytes long.

Data: <C> 00 43 00 CD

C: \ Program Files \ Microsoft Visual Studio \ vc98 \ include \ crtdbg. H (552): {43} normal
Block at 0x00441c20, 40 bytes long.

Data: <C> 08 02 43 00 16 00 00 00 00 00 00 00 00 00 00 00 00 00

Object dump complete.

If the # DEFINE _ crtdbg_map_alloc statement is not used, the output of Memory leakage is as follows:

Detected memory leaks!

Dumping objects->

{45} normal block at 0x00441ba0, 2 bytes long.
Data: <AB> 41 42

{44} normal block at 0x00441bd0, 33 bytes long.
Data: <C> 00 43 00 CD

{43} normal block at 0x00441c20, 40 bytes long.
Data: <C> C0 01 43 00 16 00 00 00 00 00 00 00 00 00 00 00 00 00

Object dump complete.

Based on this output, you cannot know which source program file has a memory leak. Next we will study the output information format. There is nothing to say about the first and second rows, starting from the third row:

XX}: the number in the arc is the memory allocation number. In this example, It is {45 },{ 44 },{ 43 };
Block: memory block type. There are three common types: normal (normal), client (client), or CRT (runtime). In this example, normal block is used;
Memory location in hexadecimal format, for example, at 0x00441ba0;
Memory block size in bytes, for example, 32 bytes long;
The content of the first 16 bytes (also expressed in hexadecimal format), for example, data: 41 42;

If _ crtdbg_map_alloc is defined, the file name for allocating leaked memory is displayed before the memory allocation sequence number, and the numbers in the brackets after the file name indicate the leaked code line number, for example:

C: \ temp \ memleak. cpp (15)

Double-click the output line of the file name in the output window to jump to the code line for allocating the memory to the source file (you can also select this line and press F4. The effect is the same ), in this way, it is easy to locate where memory leakage occurs. Therefore, _ crtdbg_map_alloc has obvious functions.

Use _ crtsetdbgflag
If the program has only one exit, it is easy to choose the location of the call _ crtdumpmemoryleaks. But what if the program may exit in multiple places? Calling _ crtdumpmemoryleaks at every possible exit is definitely not advisable, so the following call can be included at the beginning of the program: _ crtsetdbgflag (_ crtdbg_alloc_mem_df | _ crtdbg_leak_check_df ); this statement automatically calls _ crtdumpmemoryleaks no matter where the program exits. Note: You must set two bits: _ crtdbg_alloc_mem_df.
And _ crtdbg_leak_check_df.

Set the CRT report mode
By default, _ crtdumpmemoryleaks dumps Memory leakage information to the debug page of the output window. If you want to export this information to another place, you can use _ crtsetreportmode to reset it. If you use a library, it may direct the output to another location. In this case, you only need to use the following statement to set the output position back to the output window:

_ Crtsetreportmode (_ crt_error, _ crtdbg_mode_debug );

For more information about using _ crtsetreportmode, see the description of _ crtsetreportmode in the msdn library.

Ii. Explain the memory block type

As mentioned above, in the memory leak report, each leaked memory is divided into normal (common block), client (client block), and CRT block. In fact, you need to pay attention to normal and client blocks, that is, common blocks and client blocks.
1. normalblock: This is the memory allocated by your program.
2. clientblock (customer block): This is a special type of memory block, which is specially used for the object that requires destructor in the MFC program. The mfcnew operator can create both common blocks and customer blocks for the created objects based on actual conditions.
3. CRT block: it is the memory block allocated by the C Runtime Library for your own use. The CRT Library manages the allocation and release of these memories. we generally do not find the CRT Memory leakage in the memory leakage report unless the program has a serious error (such as the CRT library crash ).

In addition to the above types, there are two types of memory blocks that will not appear in the memory leakage report:
1. Free block: the memory block that has been released (free.
2. ignoreblock (ignore block): This is the memory block explicitly declared by the programmer not to appear in the memory leak report.

 

3. How to set a breakpoint at the memory allocation sequence number

In the memory leak report, the file name and line number can tell the location of the leaked Memory code, but it is not enough to rely solely on this information to understand the complete cause of the leak. When a program is running, a piece of memory allocation code may be called many times, as long as the memory is not released after one call, it will cause memory leakage. To determine which memory is not released, you must know not only where the leaked memory is allocated, but also the conditions for leakage. In this case, the memory allocation sequence number is particularly useful-this sequence number is the number in the ARC after the file name and the row number.

For example, in the output information of the sample code in this article, "45" indicates the memory allocation sequence number, indicating that the leaked memory is the 45th memory blocks allocated in your program:

Detected memory leaks!

Dumping objects->

C: \ temp \ memleak. cpp (15): {45} normal block at 0x00441ba0, 2 byteslong.

Data: <AB> 41 42

......

Object dump complete.

The CRT library counts all memory blocks allocated during the running of the program, including the memory allocated by the CRT library itself and the memory allocated by other libraries (such as MFC. Therefore, an object with the allocation number n is the nth object allocated in the program, but not necessarily the nth object allocated by the Code. (This is not the case in most cases .) In this way, you can use the allocation sequence number to set a breakpoint at the location of the allocated memory. The method is to set a position breakpoint near the start of the program. When the program is interrupted at this point, you can set a memory allocation breakpoint in the quickwatch dialog box or watch window:

For example, in the watch window, type the following expression in the name column:

_ Crtbreakalloc

To use the multi-threaded dll version (/MD option) of the CRT library, the context operator must be included, as shown in the following code:

{, Msvcrtd. dll} _ crtbreakalloc

Press enter. The debugger calculates the value and places the result in the value column. If no breakpoint is set at the memory allocation point, the value is-1.

Replace the value in the value column with the Allocation Number of the memory allocation you want to interrupt at its location. For example, enter 45. This will interrupt the allocation where the serial number is 45.

You can continue debugging after a breakpoint is set at the memory allocation you are interested in. At this time, be careful when running the program, and ensure that the order of memory block allocation will not change. When the program is interrupted at the specified memory allocation, you can view the call Stack window and other debugger information to determine the memory allocation situation. If necessary, you can continue to execute the program from this point to see what happened to the object. You may be able to determine the cause of the incorrect object release.

Although it is usually easier to set memory allocation breakpoints in the debugger, you can also set these breakpoints in the Code if you want. To set a memory allocation breakpoint in the code, you can add such a line (for 45th memory allocations ):

_ Crtbreakalloc = 45;

You can also use the _ crtsetbreakalloc function with the same effect:

_ Crtsetbreakalloc (45 );

4. How to compare the memory status

Another way to locate Memory leakage is to obtain a snapshot of the application's memory status at a critical point. The CRT Library provides a structure type of _ crtmemstate. You can use it to store snapshots of memory status:

_ Crtmemstate S1, S2, S3;

To obtain a memory status snapshot at a specified point, you can pass a _ crtmemstate structure to the _ crtmemcheckpoint function. This function fills the structure with snapshots in the current memory status:

_ Crtmemcheckpoint (& S1 );

By passing the _ crtmemdumpstatistics structure to the _ crtmemstate function, you can dump the content of this structure anywhere:

_ Crtmemdumpstatistics (& S1 );

This function outputs dump memory allocation information in the following format:

0 bytes in 0 free blocks.
75 bytes in 3 normal blocks.
5037 bytes in 41 CRT blocks.
0 bytes in 0 ignore blocks.
0 bytes in 0 client blocks.
Largest number used: 5308 bytes.
Total allocations: 7559 bytes.

To determine whether memory leakage has occurred in a code segment, you can obtain the memory status snapshots before and after the code segment, and then use _ crtmemdifference to compare the two states:

_ Crtmemcheckpoint (& S1); // gets the first memory status Snapshot

// Allocate memory here

_ Crtmemcheckpoint (& S2); // gets the second memory status Snapshot

// Compare the differences between two memory snapshots
If (_ crtmemdifference (& S3, & S1, & S2 ))
_ Crtmemdumpstatistics (& S3); // dump difference result

As the name suggests, _ crtmemdifference compares two memory States (the first two parameters) and generates the result of the difference between the two States (the third parameter ). Put _ crtmemcheckpoint at the beginning and end of the program and use _ crtmemdifference to compare the results. This is another way to check memory leakage. If leakage is detected, you can use _ crtmemcheckpoint to call the binary search technology to split the program and locate the leakage.

V. Conclusion

Although VC ++ has a mechanism for debugging the MFC application, the memory allocation discussed above is very simple and does not involve the MFC object, so these contents are also suitable for the MFC program. You can find a lot of information about VC ++ debugging in the msdn library. If you can make good use of the msdn library, I believe that you may become a debugging master in a short time.

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.