C language memory leak sample resolution

  • 2020-04-02 01:23:49
  • OfStack

The importance of proper memory management
C and C++ programs with memory errors can cause problems. If they leak memory, they slow down and eventually stop running. If memory is overwritten, it becomes very fragile and vulnerable to attacks by malicious users. Everything from the famous morris worm attack of 1988 to the latest security alerts about Flash Player and other key retail-level programs are about buffer overflows: "most computer security vulnerabilities are buffer overflows," Rodney Bates wrote in 2004.

Where C or C++ is available, many other general-purpose languages (such as Java™ , Ruby, Haskell, C#, Perl, Smalltalk, etc.), each language has many fans and its own advantages. However, from a computational point of view, the main advantages of each programming language over C or C++ are closely related to ease of memory management. Memory-related programming is so important, and so difficult to apply correctly in practice, that it dominates all other variables or theories of object-oriented programming languages, functional programming languages, high-level programming languages, declarative programming languages, and other programming languages.

Like a few other types of common errors, memory errors are also a hidden hazard: they are hard to reproduce, and symptoms are often not found in the corresponding source code. For example, whenever and wherever a memory leak occurs, it may appear to be completely unacceptable to the application, and the memory leak may not be obvious.

Therefore, for all these reasons, you need to pay special attention to the memory problems of C and C++ programming. Let's take a look at how to solve these problems, not to mention the language.

Category of memory errors
First, don't lose heart. There are many ways to deal with memory problems. Let's start with a list of all possible practical problems:

The & # 8226; A memory leak
The & # 8226; Misallocation, including a large increase in free() freed memory and uninitialized references
The & # 8226; Dangling Pointers
The & # 8226; Array boundary violation

These are all types. Even if you move to the C++ object-oriented language, these types will not change significantly; Whether the data is a simple type or a C struct or C++ class, the memory management and reference model in C and C++ is the same in principle. The following is mostly a "pure C" language, reserved for exercises in extending to C++.

A memory leak
Memory leaks occur when resources are allocated, but it is never recovered. Here's a model that could go wrong (see listing 1) :

Listing 1. Simple potential heap memory loss and buffer coverage


void f1(char *explanation) { char *p1; p1 = malloc(100); sprintf(p1,"The f1 error occurred because of '%s'.", explanation); local_log(p1); }

Do you see the problem? Unless local_log() is unusually responsive to free() freeing memory, every call to f1 leaks 100 bytes. A leak is trivial when the memory stick is incrementally distributing megabytes of memory, but after hours of continuous operation, even such a small leak can weaken the application.

In real C and C++ programming, this is not enough to affect your use of malloc() or new, and the sentence at the beginning of this section mentions "resources" not just "memory," because there are examples like this (see listing 2). FILE handles may differ from memory blocks, but they must be given equal attention:

Listing 2. Potential heap memory loss from resource error management


int getkey(char *filename) { FILE *fp; int key; fp = fopen(filename, "r"); fscanf(fp, "%d", &key); return key; }

The semantics of fopen require complementary fclose. In the absence of fclose(), when the C standard cannot specify what is happening, it is most likely a memory leak. Other resources (such as semaphores, network handles, database connections, and so on) are also worth considering.

Memory error allocation
Misallocation management is not difficult. Here is an example of an allocation error (see listing 3) :

Listing 3. An uninitialized pointer


void f2(int datum) { int *p2;  *p2 = datum; ... }

The good news about such errors is that they generally have significant results. In AIX® Under, the assignment of an uninitialized pointer usually results in an immediate segmentation fault. The advantage is that any such errors are detected quickly; Such errors are much cheaper to detect than ones that take months to identify and are difficult to reproduce.

There are several variations in this error type. Free () frees memory more frequently than malloc() (see listing 4) :

Listing 4. Two incorrect memory releases


 void f3() { char *p, *pp; p = malloc(10);
pp=p;
free(p); ... free(pp); }  void f4() { char *p;
...
 free(p); }

These errors are usually not too serious. Although the C standard does not define specific behavior in these cases, a typical implementation would ignore errors or quickly and explicitly flag them; Anyway, these are safe situations.

Dangling Pointers
Dangling Pointers are tricky. A dangling pointer occurs when a programmer USES a memory resource after it has been freed (see listing 5) :

Listing 5. Dangling Pointers


void f8() { struct x *xp; xp = (struct x *) malloc(sizeof (struct x)); xp.q = 13; ... free(xp); ...  return xp.q; }

Traditional "debugging" is difficult to isolate dangling Pointers. They are difficult to reproduce for two obvious reasons:

The & # 8226; Even if the code that affects the range of memory that can be pre-freed is localized, memory usage can still depend on other execution locations in the application and even (in extreme cases) in different processes.

The & # 8226; Dangling Pointers can occur in code that USES memory in subtle ways. As a result, even if the memory is overwritten immediately after it is released, and the new value points to something different than the expected value, it is difficult to recognize the new value as an error value.

Dangling Pointers constantly threaten the running state of C or C++ programs.

Array boundary violation
Array boundary violations are dangerous and are the last major category of memory error management. Go back to listing 1; What happens if the length of explanation exceeds 80? Answer: hard to predict, but it may be far from good. In particular, C copies a string that is not suitable for the 100 characters assigned to it. In any normal implementation, the exceeded character overrides other data in memory. The layout of data allocation in memory is very complex and difficult to reproduce, so it is impossible to trace any symptoms back to a specific error at the source code level. These errors often cost millions of dollars.

. A tricky memory leak


static char *important_pointer = NULL; void f9() { if (!important_pointer) important_pointer = malloc(IMPORTANT_SIZE); ... if (condition)  important_pointer = malloc(DIFFERENT_SIZE); ... }
do not Returns a pointer to a local pointer variable or to a local variable, unless it is a pointer static A local variable 
char *f0() {     char temp[]="123456789"; //Static is the right thing to do
return temp; }


Related articles: