This article will show you how to avoid those subtle yet common errors and introduce several techniques to help engineers find hidden errors in 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 fail to detect many common errors in today's complex systems.
Structural testing, or white box testing, is effective in finding logic, control flow, calculation, and data errors in code. This testing requires a clear view of the inner workings of the software (hence the term "white box" or "glass box") to understand the details of the software structure. It checks every conditional expression, mathematical operation, input, and output. Because of the many details that need to be tested, structural testing checks one unit of software at a time, usually a function or class.
Code review also uses the same complex techniques to find implementation defects and potential problems. Like white box testing, reviews are usually conducted on individual units of software because an effective review process requires focused and detailed inspection.
Unlike reviews and white box testing, functional testing, or black box testing, assumes no knowledge of the software's implementation and tests outputs driven by controlled inputs. Functional testing consists of test procedures written by testers or developers that specify the expected program outputs for a specific set of program inputs. After the tests are run, testers compare the actual outputs to the expected outputs to look for problems. Black-box testing is effective in finding unimplemented requirements, interface problems, performance problems, and bugs in the most commonly used functions of a program.
While these techniques combined can find most of the bugs hidden in a particular software program, they have limitations. Code review and white-box testing focus on only a small portion of the code at a time, ignoring the rest of the system. Black-box testing typically treats the system as a whole, ignoring implementation details. Some important problems can only be discovered when the details of their interaction within the entire system are focused; traditional methods cannot reliably find these problems. The software system must be examined as a whole to find the specific cause of a specific problem. Because 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 focus on specific aspects of the program that are known to cause problems. This article will explore three of these potential problem areas:
* Stack overflows
* Race conditions
* Deadlocks
Readers can read the second part of this article online, which will explore the following issues:
* Timing problems
* Reentrancy conditions
All of the above problems are quite common in systems that use multitasking real-time design techniques.
Stack Overflows
Processors use stacks to store temporary variables, pass parameters to called functions, save 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 is fixed to the size it was shipped with. If for some reason the stack grows beyond the amount allocated by the programmer, the program becomes undefined. This instability can cause serious system failure. Therefore, it is critical to ensure that the system can allocate enough stack in the worst case.
The only way to ensure that stack overflows will never occur 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. It is unlikely that the test will trigger a specific combination of transient inputs that will cause the system to behave in the worst case.
The concept of stack depth analysis is simple:
1. Build a call tree for each independent thread.
2. Determine the stack usage of each function in the call tree.
3. Examine each call tree and determine which call path from the root to the outer "leaves" requires the most stack usage.
4. Add the maximum stack usage of each individual thread call tree.
5. Determine the maximum stack usage of each interrupt service routine (ISR) within each interrupt priority level and calculate the sum. However, if the ISR does not have its own stack and uses the stack of the interrupted thread, then add the maximum stack used by the ISR to the stack of each thread.
6. For each priority level, add the amount of stack used to save the processor state when an interrupt occurs.
7. If an RTOS is used, add the maximum amount of stack required for the RTOS's own internal purposes (as opposed to system calls initiated by the application code, which are included in step 2).
There are two more important things to consider. First, the call tree built from high-level language source code alone is likely to be incomplete. Most compilers use a run-time library to optimize common computational tasks, such as multiplication and division of large integers, floating-point operations, etc. These calls are only visible in the assembly language generated by the compiler. Runtime library functions themselves may use a lot of stack space, so they must be included in the analysis. If using C++, all of the following types of functions (methods) must also be included in the call tree: constructors, destructors, overloaded operators, copy constructors, and conversion functions. All function pointers must also be resolved and the functions they call included in the analysis.
Keywords:stack overflow
Reference address:Three potential problems of embedded software and their testing technologies
Structural testing, or white box testing, is effective in finding logic, control flow, calculation, and data errors in code. This testing requires a clear view of the inner workings of the software (hence the term "white box" or "glass box") to understand the details of the software structure. It checks every conditional expression, mathematical operation, input, and output. Because of the many details that need to be tested, structural testing checks one unit of software at a time, usually a function or class.
Code review also uses the same complex techniques to find implementation defects and potential problems. Like white box testing, reviews are usually conducted on individual units of software because an effective review process requires focused and detailed inspection.
Unlike reviews and white box testing, functional testing, or black box testing, assumes no knowledge of the software's implementation and tests outputs driven by controlled inputs. Functional testing consists of test procedures written by testers or developers that specify the expected program outputs for a specific set of program inputs. After the tests are run, testers compare the actual outputs to the expected outputs to look for problems. Black-box testing is effective in finding unimplemented requirements, interface problems, performance problems, and bugs in the most commonly used functions of a program.
While these techniques combined can find most of the bugs hidden in a particular software program, they have limitations. Code review and white-box testing focus on only a small portion of the code at a time, ignoring the rest of the system. Black-box testing typically treats the system as a whole, ignoring implementation details. Some important problems can only be discovered when the details of their interaction within the entire system are focused; traditional methods cannot reliably find these problems. The software system must be examined as a whole to find the specific cause of a specific problem. Because 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 focus on specific aspects of the program that are known to cause problems. This article will explore three of these potential problem areas:
* Stack overflows
* Race conditions
* Deadlocks
Readers can read the second part of this article online, which will explore the following issues:
* Timing problems
* Reentrancy conditions
All of the above problems are quite common in systems that use multitasking real-time design techniques.
Stack Overflows
Processors use stacks to store temporary variables, pass parameters to called functions, save 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 is fixed to the size it was shipped with. If for some reason the stack grows beyond the amount allocated by the programmer, the program becomes undefined. This instability can cause serious system failure. Therefore, it is critical to ensure that the system can allocate enough stack in the worst case.
The only way to ensure that stack overflows will never occur 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. It is unlikely that the test will trigger a specific combination of transient inputs that will cause the system to behave in the worst case.
The concept of stack depth analysis is simple:
1. Build a call tree for each independent thread.
2. Determine the stack usage of each function in the call tree.
3. Examine each call tree and determine which call path from the root to the outer "leaves" requires the most stack usage.
4. Add the maximum stack usage of each individual thread call tree.
5. Determine the maximum stack usage of each interrupt service routine (ISR) within each interrupt priority level and calculate the sum. However, if the ISR does not have its own stack and uses the stack of the interrupted thread, then add the maximum stack used by the ISR to the stack of each thread.
6. For each priority level, add the amount of stack used to save the processor state when an interrupt occurs.
7. If an RTOS is used, add the maximum amount of stack required for the RTOS's own internal purposes (as opposed to system calls initiated by the application code, which are included in step 2).
There are two more important things to consider. First, the call tree built from high-level language source code alone is likely to be incomplete. Most compilers use a run-time library to optimize common computational tasks, such as multiplication and division of large integers, floating-point operations, etc. These calls are only visible in the assembly language generated by the compiler. Runtime library functions themselves may use a lot of stack space, so they must be included in the analysis. If using C++, all of the following types of functions (methods) must also be included in the call tree: constructors, destructors, overloaded operators, copy constructors, and conversion functions. All function pointers must also be resolved and the functions they call included in the analysis.
Previous article:Research on gear fault diagnosis based on torsional vibration signal
Next article:Simulation System Structure Design in Embedded Software System Testing
Recommended Content
Latest Test Measurement Articles
- Keysight Technologies Helps Samsung Electronics Successfully Validate FiRa® 2.0 Safe Distance Measurement Test Case
- From probes to power supplies, Tektronix is leading the way in comprehensive innovation in power electronics testing
- Seizing the Opportunities in the Chinese Application Market: NI's Challenges and Answers
- Tektronix Launches Breakthrough Power Measurement Tools to Accelerate Innovation as Global Electrification Accelerates
- Not all oscilloscopes are created equal: Why ADCs and low noise floor matter
- Enable TekHSI high-speed interface function to accelerate the remote transmission of waveform data
- How to measure the quality of soft start thyristor
- How to use a multimeter to judge whether a soft starter is good or bad
- What are the advantages and disadvantages of non-contact temperature sensors?
MoreSelected Circuit Diagrams
MorePopular Articles
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
MoreDaily News
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
Guess you like