Original address: http://blog.csdn.net/slvher/article/details/9150597
Memory management is a big challenge for C + + programmers, it is absolutely worth the cautious, otherwise it is painful to let the module of tens of thousands of lines of code run up before the memory crashes. Because the location of the crash is in time and space, it is usually shown after a distance from the real source of the error. A few days ago on-line module due to heap memory write out of 1 bytes caused by various strange crashes, positioning problems in the process of tossing still vivid, today read the "in-depth understanding of computer systems," the 9th chapter-Virtual memory, found in the book summarizes the C program in the common memory operation of 10 typical programming errors , Summary of the more comprehensive. Therefore, as a note, recorded here.
1. Indirect reference Invalid pointer
Some address ranges of the process virtual address space may not be mapped to any meaningful data, and if we attempt to indirectly reference a pointer to those addresses, the operating system terminates the process with segment fault. Also, some areas of the virtual storage are read-only (such as. text or. rodata), and attempting to write these areas will abort the current process with a protection exception.
If an int variable is read from stdin, scanf ("%d", &val) is the correct usage, and if it is mistakenly written as scanf ("%d", Val), the Val value is interpreted as an address and an attempt is made to write data to that address. In the best case, the process immediately aborts abnormally. In the worst case, Val's value corresponds exactly to a valid memory area of the virtual memory that has read/write permission, and the memory unit is rewritten, which usually has disastrous and confusing consequences over a long period of time.
2. Read Uninitialized memory
The C-language malloc is not responsible for initializing the requested memory area, so a common mistake is to assume that the heap memory is initialized to 0, for example:
[CPP]View PlainCopy
- int * FOO (int **a, int *x, int n)
- {
- int I, J;
- int * y = (int *) Malloc (n * sizeof (int));
- For (i = 0; i < n; i++) {
- For (j = 0; J < N; j + +) {
- Y[i] + = a[i][j] * X[j];
- }
- }
- return y;
- }
In the above code, it is incorrectly assumed that Y is initialized to 0. The correct implementation is to explicitly set Y[i] to 0 or use calloc.
3. Stack buffer Overflow
For example:
[CPP]View PlainCopy
- Char buf[5];
- sprintf (buf, "%s", "Hello World");
The above code causes a stack buffer overflow, and security is: 1) use snprintf (buf, sizeof (BUF), "%s", "Hello World") to truncate in a timely manner by defining the appropriate buffer;2 as required.
4. Mistakenly think that the pointer is the same size as the object it points to
For example:
[CPP]View PlainCopy
- int **makearray (int n, int m)
- {
- int i;
- int **a = (int * *) Malloc (nsizeof (int)); //The int * is mistakenly assumed to have the same size as the INT two variable type
- For (i = 0; i < n; i++) {
- A[i] = (int *) Malloc (M * sizeof (int));
- }
- return A;
- }
The purpose of the code above is to create an array of n pointers, each pointing to an array containing M int, but mistakenly writing sizeof (int *) as sizeof (int). This code works well on machines with the same size as int and int *. If you run this code on a machine like Core i7, because the pointer variable has a size greater than sizeof (int), the For loop write out of the code is thrown out of bounds. Because one of these words is likely to be the boundary marker foot of the allocated block, we may not find this error immediately until the process has freed the memory block for a long time, and the merge code in the allocator will fail dramatically without any apparent reason. This is a covert example of "working in the Distance" (action at distance), which is a typical case of memory-related programming errors, such as "working in the distance".
5. Error caused by dislocation
Misplaced (off-by-one) errors are another common source of coverage errors:
[CPP]View PlainCopy
- int * * MAKEARRAY (int n, int m)
- {
- int i;
- int **a = (int * *) Malloc (n * sizeof (int *));
- For (i = 0; I <= N; i++) {
- A[i] = (int *) Malloc (M * sizeof (int));
- }
- return A;
- }
Obviously, the For loop times out of expectation, resulting in a write out of bounds. Fortunately, the process crashes immediately; Unfortunately, it takes a long time to throw up all sorts of weird problems.
6. Reference the pointer, not the object it points to
If you do not pay attention to the precedence and associativity of the C operator, the pointer is manipulated incorrectly, not the object that the pointer points to.
For example, the following function is intended to delete the first item in a two-fork heap with *size items, and then rebuild the heap for the remainder of the *size-1:
[CPP]View PlainCopy
- int * BINHEAPDELETE (int **binheap, int *size)
- {
- int *packet = binheap[0];
- Binheap[0] = binheap[*size-1];
- *size--; //here should be (*size)--
- Heapify (binheap, *size, 0);
- return (packet);
- }
In the code above, because--and * precedence--are combined right-to-left, so *size--actually reduces the value of the pointer's own value, not the integer it points to. So remember: when you have questions about priorities and bonding, you should use parentheses.
7. Misunderstanding pointer arithmetic
The arithmetic operations of pointers are performed in C/s + + in units of the size of the object they point to. For example, the function of the following function is to scan an array of int and return a pointer to the first occurrence of Val:
[CPP]View PlainCopy
- int * search (int *p, int val)
- {
- While (*p && *p! = val) {
- p + = sizeof (int); ///This should be p++, otherwise p + = 4 will cause most elements to be skipped
- }
- }
8. Referencing a non-existent variable
If a novice/C + + beginner does not understand the rules of a stack, it may refer to local variables that are no longer valid, such as:
[CPP]View PlainCopy
- int * STACKREF ()
- {
- int val;
- return &val;
- }
The pointer returned by the function (assuming p) points to a local variable in the stack, but the variable is no longer valid as the STACKREF stack frame is destroyed after the function returns. That is, even though the pointer p returned by the function still points to a valid memory address, it no longer points to a valid variable. When the program subsequently calls other functions, the memory will reuse the memory area where the stack frame was just destroyed. Later, if the program assigns a value to *p, it may actually be modifying the data in another function stack frame, potentially with disastrous and confusing consequences.
9. Referencing data in a free heap block
A typical error is referencing data from a heap block that has been freed, for example:
[CPP]View PlainCopy
- int * HEAPREF (int n, int m)
- {
- int i;
- int *x, *y;
- x = (int *) Malloc (n * sizeof (int));
- / * Various operations * /
- Free (x);
- y = (int *) Malloc (M * sizeof (int));
- For (i = 0; i < m; i++) {
- Y[i] = x[i]++; //The x here has been released before!
- }
- }
10. Memory leaks
Memory leaks are slow, recessive killers that can occur when programmers forget to release allocated blocks, such as:
[CPP]View PlainCopy
- void leak (int n)
- {
- int *x = (int *) Malloc (n * sizeof (int));
- return;
- }
If leak is called only a few times throughout the lifetime of the program, the problem is not very serious (but it still wastes memory space) because the operating system reclaims the memory space as the process ends. However, if leak () is called frequently, a serious memory leak will occur, and in the worst case, the entire virtual address space will be consumed. For programs like daemons and servers, memory leaks are serious bugs that must be valued.
Resources
"In-depth understanding of computer Systems" Chapter 9th-Virtual memory
============== EOF ==================
Typical programming errors related to memory operations commonly found in "in-depth understanding of computer systems" C programs