Common program debugging errors

Source: Internet
Author: User

As methods such as code refactoring and unit testing are introduced into practice, debugging skills are gradually weakened, and some people even advocate
Except the debugger. This makes sense because the debugging cost is too high, especially after system integration debugging.
A bug that takes days or even weeks is not uncommon.
These hard-to-locate bugs can be classified into two categories: Memory Errors and concurrency problems. The most memory error occurs.
It is common. Even veteran who have been on the battlefield for a long time may inevitably fall into a trap. Learn more about future generations.
Pay attention to Common Errors During programming to minimize the probability of errors, which can save a lot of time.
Some common memory errors are listed for reference.

1. Memory leakage

As we all know, if the memory allocated on the stack is no longer used, release it so that it can be used later.
Places can be reused. In C/C ++, the memory manager does not automatically recycle memory that is no longer in use. If you forget to release
If the memory is no longer used, the memory cannot be reused, resulting in Memory leakage.
Listing memory leaks as the top priority is not because of its serious consequences, but because it is the most common type.
Error. One or two memory leaks do not usually cause program crashes or logical errors.
The system will automatically release all memory related to the process, so the memory leakage is relatively mild.
Of course, the quantitative change will produce qualitative changes. Once the memory leaks too much, the memory will be exhausted, and the subsequent memory allocation will fail.
The order may crash.
The current PC memory is large enough, and the process has independent memory space. For some small programs, memory leakage
It is no longer a big threat. However, for large software, especially long-running software, or embedded systems,
Memory leakage is still one of the critical factors.
No matter under what circumstances, it is advisable to adopt a more cautious attitude to prevent memory leaks. On the contrary,
I think there is some memory, and it is not responsible for letting the Memory Leak flow. Although some tools can help us check the memory
I think we should be careful in programming to eliminate such errors early. The tool is only used for verification.
Means.

2. Out-of-bounds memory access

Memory out-of-bounds access can be divided into two types: read out-of-bounds access, that is, read data that does not belong to the user, if the Read Memory Address
Is invalid, and the degree immediately crashes. If the READ memory address is valid, there will be no problems during reading,
The read data is random, which has unpredictable consequences. The other is write overbounds, also known as buffer overflow.
The data written is random for others, and it has unpredictable consequences.
Memory out-of-bounds access has serious consequences and is one of the critical threats to program stability. What's more troublesome is that it creates
The consequence is random, and the symptoms and timing are also random, making the bug phenomenon and nature seem nothing
Contact, which makes it very difficult to locate bugs.
Some tools can help you check out-of-boundary memory access problems, but they cannot rely too much on the tools. Out-of-bounds memory access
It usually appears dynamically, that is, it depends on test data. In extreme cases, it appears unless the test data is carefully designed.
Tools are powerless. The tool itself has some limitations, and even in some large projects, the tool becomes completely unavailable.
. Be careful when programming a safer method, especially for parameters passed in from outside.

3. Wild pointer

The wild pointer refers to the memory pointers you have released. When you call free (P), you actually know this action
? You will say that the memory pointed to by P is released. Is P itself changing? The answer is that P has not changed.
. The memory that it points to is still valid. You can continue to read and write the memory that P points to. No one can block you.
The released memory will be re-allocated by the memory manager. At this time, the memory pointed by the wild pointer has been given a new meaning.
. The access to the wild pointer pointing to the memory, whether intentionally or unintentionally, will incur a huge cost, because it causes
The consequences are as unpredictable as cross-border access.
Immediately after the memory is released, the corresponding pointer is set to a null value, which is a common method to avoid wild pointers. This method is simple and effective.
Of course, when the pointer is passed in from the outer layer of the function, the pointer is set to null in the function, and the pointer at the external layer
No effect. For example, if you set this pointer to a null value in the destructor, it will have no effect.
Layer sets the pointer to a null value.

4. Access a null pointer

A null pointer occupies a special address in C/C ++ and is usually used to judge the validity of a pointer. Null Pointer
0. The modern operating system retains a piece of memory starting from 0. The size of the memory depends on the operating system.
. Once the program tries to access this memory, the system will trigger an exception.
Why does the operating system need to retain a piece of memory instead of just one byte of memory? The reason is: Generally
Storage Management is managed by page. You cannot keep only one byte. You must keep at least one page. Retain one piece of memory
You can also check for memory errors such as P = NULL and P [1.
In some embedded systems (such as ARM7), a piece of memory starting from 0 is used to install the interrupt vector, without MMU
Protection, direct access to this memory does not seem to cause exceptions. However, this memory is a code segment and is not valid in the program.
Variable address, so it is still feasible to use a null pointer to determine the validity of the pointer.
Make sure that the pointer is not a null pointer when accessing the memory pointed to by the pointer. Accessing the memory pointed by a null pointer usually causes
Crash or unexpected errors.

5. Reference uninitialized variables

The content of uninitialized variables is random. using such data can cause unpredictable consequences. debugging such a bug
It is also very difficult.
For those with rigorous attitudes, it is very easy to prevent such bugs. Initialize the variable when it is declared.
Is a good habit of programming. In addition, we should pay attention to the warning information of the compiler and find that there is a reference to uninitialized variables.
It is changed.

6. Unclear pointer operation

For some new users, pointers often confuse them. For example:
Int * P = ...; P + 1; equals (size_t) p + 1?
The veteran knows clearly, and the novice may be confused. In fact:
P + N; equal to (size_t) P + N * sizeof (* P );

Pointers are the most powerful weapons in C/C ++ and are very powerful.
Master is very skilled. If there is any uncertainty, immediately write a small program to verify it. Every detail is detailed in
Chest, saving a lot of time in programming.

7. errors caused by changes in the structure's member Sequence

When initializing a structure, the veteran may rarely be as honest as the novice.
Structure initialization, but uses shortcuts, such:

Struct s
{
Int L;
Char * P;
};

Int main (INT argc, char * argv [])
{
Struct s S1 = {4, "ABCD "};
Return 0;
}

The above method is very dangerous because you make assumptions about the memory layout of the structure. If the structure is
Provided by a third party, it is likely to adjust the relative position of the members in the structure. Such adjustments are often not described in the document.
Obviously, you seldom pay attention to it. If the adjusted two Members have the same data type, there will be no warning during compilation,
The program may be logically 108,000 miles apart.
The correct initialization method should be (of course, the initialization of one member can also be done ):

Struct s
{
Int L;
Char * P;
};
Int main (INT argc, char * argv [])
{
Struct s S1 = {. L = 4,. P = "ABCD "};
Struct s S2 = {L: 4, P: "ABCD "};
Return 0;
}

8. errors caused by changes in the structure size

Let's take a look at the following example:

Struct Base
{
Int N;
};
Struct s
{
Struct Base B;
Int m;
};

In Oop, we can think that the second structure inherits the first structure. Is there any problem? Of course not.
It is the basic method for implementing inheritance in C language.
Assume that the first structure is provided by a third party, and the second structure is yours. The libraries provided by third parties are
DLL distribution, the biggest benefit of DLL is that it can be replaced independently. But with the evolution of software, the problem may come.
When the third party adds a new member int K in the first structure; after compilation, the DLL is given to you.
Customer. There will be no problems during program loading, and the running logic may be completely changed! The reason is that the memory of the two structures
The layout overlaps. The only way to solve such errors is to repeat the relevant code.
The only way to solve such errors is to recompile all the code. From this point of view, DLL does not necessarily support dynamic replacement.
In other words, if you want to know more about the content, we recommend that you read "com essence theory".

9. Allocate/release unpaired

We all know that malloc needs to be paired with free, new needs to be paired with delete/Delete [], and the class is reloaded.
The new operation should also overload the delete/Delete [] operation of the class. These are all repeatedly mentioned in the book, unless
Dizzy, generally do not make such a low-level error.
Sometimes we are stuck in the dark. Both codes seem to call the free function, but they actually do not.
Same implementation. For example, in Win32, the debug and publish versions have different runtime libraries for single threads and multithreading.
The Runtime library uses different memory managers. If you accidentally link the wrong library, you will be in trouble. The program may be
The cause of the crash is that the memory allocated in one memory manager is released in another memory manager.
Question.

10. Returns a pointer to a temporary variable.

As we all know, the variables in the stack are temporary. Related temporary variables and parameters when the current function execution is complete
All are cleared. The pointer pointing to these temporary variables cannot be returned to the caller.
Will cause unexpected consequences to the program.
The following is an example of an error:

Char * get_str (void)
{
Char STR [] = {"ABCD "};
Return STR;
}

Int main (INT argc, char * argv [])
{
Char * P = get_str ();
Printf ("% s/n", P );
Return 0;
}

There is no problem in the following example. Do you know why?

Char * get_str (void)
{
Char * STR = {"ABCD "};
Return STR;
}
Int main (INT argc, char * argv [])
{
Char * P = get_str ();
Printf ("% s/n", P );
Return 0;
}

11. Trying to modify Constants

The const modifier is added before the function parameter, only used to check the type of the compiler. The Compiler prohibits such modification.
. However, this is not mandatory. You can use forced type conversion to bypass it. Generally, nothing will happen.
However, when global constants and strings are forcibly converted, an error still occurs during running. The reason is that they are
In the constant area, but the memory page of the constant area cannot be modified. Attempts to modify them will cause a memory error.

The following program will encounter an error during running:

Int main (INT argc, char * argv [])
{
Char * P = "ABCD ";
* P = '1 ';
Return 0;
}

12. misinterpret data transfer and reference

In C/C ++, the default parameter passing method is to pass the value, that is, the parameter is copied when it is imported into the stack. Modify in Function
These parameters do not affect external callers. For example:

# Include <stdlib. h>
# Include <stdio. h>

Void get_str (char * P)
{
P = malloc (sizeof ("ABCD "));
Strcpy (P, "ABCD ");
Return;
}

Int main (INT argc, char * argv [])
{
Char * P = NULL;
Get_str (P );
Printf ("P = % P/N", P );
Return 0;
}

In the main function, the value of P is still null.

13. cognominal symbols

Whether it is a function name or a variable name, if the name is repeated within different scopes, it is naturally no problem. But if two
There are overlapping scopes of symbols, such as global variables and local variables. There is a certain phenomenon of duplicate names between global variables and global variables.
We must resolutely avoid it. GCC has some implicit rules to determine how to process variables with the same name. There may be no warnings or
Errors, but the results are generally not what you expect.

14. Stack Overflow

As we have mentioned in the previous section about stack, on a PC, the stack space of common threads is also dozens of MB, which is usually enough.
, It is no problem to define a larger temporary variable.
In some embedded systems, the stack size of a thread may be only 5 kb, or even as small as 256 bytes. In this case
Stack Overflow is one of the most common errors in the platform. When programming, you should be clear about the limitations of your platform to avoid stack overflow.
Yes.

15. Misuse of sizeof.

Although C/C ++ is usually passing parameters by value, while arrays are exceptions, when passing array parameters, the array degrades
The size of the array cannot be obtained with sizeof.
The following example shows that:

Void test (char STR [20])
{
Printf ("test: size = % d/N", sizeof (STR ));
}

Int main (INT argc, char * argv [])
{
Char STR [20];
Test (STR );
Printf ("Main: size = % d/N", sizeof (STR ));
Return 0;
}

Test: size = 4
Main: size = 20

16. byte alignment

Byte alignment mainly aims to improve memory access efficiency. However, on some platforms (such as ARM7), it is not just about efficiency.
If the question is not aligned, the data is incorrect.
Fortunately, in most cases, compilation ensures that global variables and temporary variables are aligned correctly. Memory Tube
The handler ensures that the dynamic memory is aligned in the correct way. Be careful when converting different types of Variables
If you want to forcibly convert char * to int *, be careful.
In addition, the byte alignment also changes the structure size, and the sizeof is used inside the program to obtain the structure size.
That's enough. If data is to be transmitted between different machines, the alignment mode should be specified in the communication protocol to avoid alignment.
Type inconsistency.

17. byte order

The byte sequence has always been a headache for cross-platform software design. The byte sequence is about the distribution of data in the physical memory.
The most common problems are the large-end mode and small-end mode.
In the big-end mode, the high-byte data is stored at the low address, and the low-byte data is stored at the high address.
In the small-end mode, low-byte data is stored at the low address in the memory, and high-byte data is stored at the Internal High address;
For example, long n = 0x11223344

Mode 1st byte 2nd byte 3rd byte 4th byte
Big end Mode 0x11 0x22 0x33 0x44
Small-end Mode 0x44 0x33 0x22 0x11

In common software, the byte sequence problem is not noticeable. When developing software related to network communication and data exchange
, You must pay special attention to the byte order problem.

18. multi-threaded shared variables are not modified with valotile

In the section on global memory, we talked about the role of valotile, which tells the compiler not to optimize variables.
To the Register. When developing multi-thread concurrent software, if these threads share some global variables, these global variables

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.