This article will introduce how to avoid those hidden but common errors, and introduce several techniques to help engineers find hidden errors in PCB copy software. Most software development projects rely on a combination of code inspection, structural testing, and functional testing to identify software defects. Although these traditional techniques are very important and can find most software problems, they cannot detect many common errors in today's complex systems.
Structural testing or white box testing can effectively find logic, control flow, calculation and data errors in the code. This test requires a complete overview of the internal workings of the software (hence the term "white box" or "glass box") in order to understand the details of the software structure. It checks every conditional expression, mathematical operation, input and output. Due to the numerous details to be tested, structural testing checks one software unit at a time, usually a function or class.
Code review also uses the same complex techniques as implementation defects and potential problems to find. Like white box testing, reviews are usually conducted for each unit of the software, because an effective review process requires centralized and detailed inspections.
Different from review and white box testing, functional testing or black box testing assumes that nothing is known about the implementation of the software. It tests the output driven by the controlled input. Functional tests are composed of test procedures written by testers or developers, which specify the expected program output corresponding to a set of specific program inputs. After the test is run, the tester compares the actual output with the expected output to find the problem. Black box testing can effectively find unfulfilled requirements, interface problems, performance problems, and errors in the most commonly used functions of the program.
Although combining these technologies can find most of the errors hidden in a particular software program, they also have limitations. Code review and white box testing only target a small part of the code at a time, ignoring the rest of the system. Black box testing usually treats the system as a whole, ignoring the implementation details. Some important problems can only be discovered by focusing on the details of their interaction in the entire system; traditional methods cannot reliably identify these problems. The software system must be checked as a whole to find the specific cause of the specific problem. Since it is usually impossible to thoroughly analyze every detail in the program and its interaction with all other parts of the code, the analysis should be aimed at the specific aspects of the program that are known to cause problems.
This article will explore three potential problem areas:
* stack overflow
* Race conditions
* deadlock
Readers can read the second part of this article online, which will explore the following issues:
* Timing issues
* Reentrant conditions
All of the above problems are quite common in systems that use multi-task real-time design technology.
stack overflow
The processor uses the stack to store temporary variables, pass parameters to the called function, save the thread "state", and so on. If the system does not use virtual memory (in other words, it cannot transfer memory pages to disk to free up memory space for other uses), the stack will be fixed at the size of the product when it leaves the factory. If for some reason the stack goes out of the range allocated by the programmer, the program will become uncertain. This instability can cause serious system failures. Therefore, it is essential to ensure that the system can allocate enough stacks in the worst case.
The only way to ensure that a stack overflow never occurs is to analyze the code, determine the maximum stack usage of the program under various possible conditions, and then check whether enough stack is allocated. The test is unlikely to trigger a specific combination of instantaneous inputs and cause the worst-case scenario in the system.
The concept of stack depth analysis is relatively simple:
1. Create a call tree for each independent thread.
2. Determine the stack usage of each function in the call tree.
3. Check each call tree to determine which call path from the root of the tree to the external "leaf" requires the most stack.
4. Add the maximum stack usage of each independent thread call tree.
5. Determine the maximum stack usage of each interrupt service routine (ISR) in each interrupt priority level and calculate the total. However, if the ISR itself does not have a stack and uses the stack of the interrupted thread, the maximum number of stacks used by the ISR should be added to the stack of each thread.
6. For each priority level, add the number of stacks used to save the processor state when an interrupt occurs.
7. If you use RTOS, add the maximum number of stacks required for the internal use of the RTOS itself (different from the system call caused by the application code, which is included in step 2).
In addition, there are two important things to consider. First, a call tree built only from high-level language source code is likely to be incomplete. Most compilers use run-time libraries to optimize common computing tasks, such as multiplication and division of large-value integers, floating-point operations, etc. These calls are only visible in the assembly language generated by the compiler. The runtime library functions themselves may use a lot of stack space, and they must be included in the analysis. If you are using the C++ language, all the following types of functions (methods) must also be included in the call tree: structurers, destructors, overloaded operators, copy structures, and conversion functions. All function pointers must also be parsed, and the functions they call are included in the analysis.