Analysis and summary of common C++ software exception scenarios

Based on the experience and experience of troubleshooting software exceptions, a brief summary of the scenarios and causes of software exceptions is provided for reference.

1. Wild pointer problem
It may be that the pointer is used without initialization. It is also possible that the memory pointed to by the pointer has been released, but the pointer is not set to NULL, once such a pointer is accessed, there will be problems. In many cases (including the case of accessing a null pointer), the NULL pointer memory area within 64KB that is prohibited by the system may be accessed, and the system will directly terminate the program. Here, a certain variable has not been initialized, and it is also possible that a certain dll library has not been initialized, so the interface in the library is called.

2. Null pointer problem
It is possible that the memory has been released and the pointer has been set to NULL, but the null pointer is still accessed later. For example, after a library has been unInitialized, the interface in the library is called or the code running in the library accesses the null pointer. It is also possible that the calling interface returned a null pointer, and the caller did not add whether the pointer is null or not.

3. Memory access out of bounds
Destroying the content in the adjacent memory, or tampering with the content in the adjacent memory, various unexpected problems will occur. For example, it will trigger the exception of accessing the NULL pointer memory area, and the subsequent memory copy will be tampered with because of the length, resulting in another memory out-of-bounds operation. Whether the heap memory is out of bounds or the stack memory is out of bounds, it may cause an exception. The most immediate exception might be a memory access violation when the bounds are exceeded.

4. Stack memory is released as heap memory.
For example, the memory of the current class object is automatically released in the function of the class, that is, delete this. However, when using the object defined by the class, there is a problem with using delete to release the stack memory. up.

5. Memory leak
The heap memory is not released.
Another piece of memory is managed when the pointer is assigned, and the previous memory is not released and managed.
Memory allocators (C: malloc, calloc, realloc, free, C++: new, delete, new[], delete[]) are mixed and used indiscriminately.

6. The problem of direct access to class objects without initialization
1) For example, critical section objects, if they enter directly without calling the initialization interface, an exception will occur. It is possible to jump out of an exception in the code and skip the initialization code.
2) The constructor registers the member function to the callback function.

7. The heap memory is released twice
. It has been released, but it is released once by calling free or delete, that is, it is released twice. For null pointers, freeing multiple times is fine.

8. Iterator failure
STL iterator failure scenario summary

9. The creation and release of static and global objects have sequential dependencies
. For example: static objects A and B are created by the system, so the order of creation cannot be determined. But the B object is called in the constructor of A.

10. Circular reference of shared pointer (shared_ptr)
Reference: Use of C++ weak reference smart pointer weak_ptr (2)

11. Secondary addressing when calling virtual functions
The virtual functions of C++ are stored in the virtual function table. If you want to call a virtual function of a class object, you need to get the first address of the virtual function table through the first address of the class object, and then find the address of the virtual function in the virtual function according to the name of the called virtual function, and then call this address. In the assembly code, you can see the detailed process of secondary addressing.

12. Object release memory leaks during inheritance.
There are virtual functions in the base class member functions, and the destructor should declare non-virtual functions. To ensure that the object memory is released normally.

13. Stack overflow
1) Reason: There are too many local variables in the recursive process and the recursion depth is too large, which is the cause of the system stack overflow, especially when the recursive column loop will definitely occur.
2) Processing method:
Tail recursive optimization.
Objects with large memory are changed from stack to heap

14. Insufficient system memory
Solution:
1) Release unused memory as early as possible in the program, and release temporarily idle memory
2) Reduce redundant copies
3) Set up a method to deal with insufficient memory std::set_new_handler
4) Use memory pool
5) Use virtual memory
6) Use a 64-bit system to increase the physical memory size

15. Infinite loop problem
Infinite loop will generally lead to higher CPU usage of the system. If it is the UI main thread, it is easier to handle, that is, thread 0, switch to thread 0, and then go several times to check whether the stack is the same. If it is the same, you can use bp to set multiple breakpoints in the stack to see which function the bottom infinite loop occurs in. Generally, it is caused by a large number of cycles in the loop body, or there is a problem with the setting of the loop condition, which is always TRUE. You can look at the values ​​of local variables related to the loop condition in the stack to locate the problem. If the value transmitted from the remote end is used as the number of cycles, an upper limit protection may be added to prevent abnormal values ​​from being transmitted. If it is the underlying thread, you can use Process Explorer to check the stack, find the thread id and stack, switch to the target thread in windbg and set a breakpoint to determine whether there is an infinite loop. You can also use the !runaway command directly in windbg to check which thread occupies the most CPU. If necessary, you may also need to check whether the kernel mode occupies more or the user mode occupies more.

16. Conditional judgment error
The conditional judgment logic is missing, and the situation of else and default is not considered

17. Type conversion
Type conversion does not consider conversion failure and abnormal conditions.

18. Different compilers have different implementations of STL.
For example, VS and MinGW are incompatible in std::string\std::map.

19. The problem of stack imbalance caused by inconsistent function calling conventions.
For example, when setting a callback function in the dll library, the callback function does not specify a calling convention, and the default C call of VS is used. But when the dll is called by C#, the header file of the dll is included, and the standard call is used by default in C#. The callback function is set as a standard call when it is implemented in the C# layer. The function is responsible for cleaning the stack inside the function. However, when the callback function is called in the dll, the dll thinks that the function is a C call. When the callback function is called in the dll, the stack will be cleaned outside the function. After the callback function is called, the stack is cleaned up one more time, so the stack is unbalanced.

20. The problem of mixed use of debug and release libraries.
It is possible that the heap memory applied by the dll export interface inside the dll needs to be released externally by the caller. If the dll is in the release version and the caller is in the debug version, an exception will occur when the caller releases the memory. Because the memory management under debug and release is different. Debug contains debugging information, and the requested memory is relatively large.

21. Problems caused by data type usage violations
For example, if you don’t understand the constraints of a certain type, you can use its interface at will, resulting in usage violations and triggering exceptions.

22. The problem that part of the code is skipped after an exception is thrown.
When an exception is encountered in the class and an exception is thrown, the program is still running, but some code is skipped, resulting in an exception in the code logic. For example, when initializing the CTime object, an abnormal value is passed in and an exception is reported. Another example is that a newcomer performs a memset operation on objects such as vetctor in stl, which destroys the structural data inside stl, causing an exception inside stl. Of course, there is another scenario where the memset operation is performed directly on CString, which destroys the data of the maintenance structure in the class, and generally triggers an exception. Generally, memset operates on the structure, but if the structure contains non-basic data types, such as class objects, you should pay attention. It can only be initialized in the constructor, and you cannot directly memset. So when using memset, you must pay attention to class objects.

23. There is data competition in multi-threading, and there is no synchronization problem.
Multi-threading locks, the knowledge design is very deep, and it will be developed here.

24. One thread maintains the variable value, and the other thread reads it through a loop
1) Problem:
Hot access (without delay) causes CPU resources to be occupied. Adding a
delay to each loop makes it easy to miss the variable change process, and the efficiency of frequent task switching Low
2) Processing method:
condition variable, event mechanism

25. Deadlock Troubleshooting
The "Parallel Stack" window tool of VS can directly analyze
logs and other tools.
At present, it is relatively simple to use windbg to troubleshoot the deadlock of key codes, because the key code segments are objects in user mode.
If it is a lock of a kernel object, debugging in the kernel mode is required, but the debugging in the kernel mode is more complicated.

26. Thread hot running
1) The loop in the thread keeps running, does not exit for a long time, and takes up a lot of CPU.
2) The spin lock competes for a long time, or multiple threads are in the competition of self-selected locks.
Reference: C++11 atomic quantity implements spin lock

27. The cache causes data unsynchronized errors.
For example, the values ​​​​of objects in memory and registers are inconsistent.

If there are any mistakes or deficiencies, welcome to comment and point out! Creation is not easy, please indicate the source for reprinting. If it is helpful, remember to like and follow (⊙o⊙)
For more content, please follow my personal blog: https://blog.csdn.net/qq_43148810

Guess you like

Origin blog.csdn.net/qq_43148810/article/details/128937797