7 uses for a static code analyzer
One of the problems with a standard C compiler is that it doesn’t look for potential flaws in a program's design, only in its coding. The use of a static code analyzer can help to improve firmware and catch problems that the compiler could never imagine. The following are seven uses for static code analyzers that every embedded software engineer should be familiar with.
The standard C compiler does a pretty good job of determining whether the code written in a program is valid and can be compiled into a working program. But it assumes that if it can compile the code then it’s all good. That still leaves a lot of room for error. A static code analyzer can be an invaluable tool when used as follows.
Use #1 - Catching potential bugs -- One of the most well-known uses for a static code analyzer is to scan software for potential issues and bugs. These issues could range from forgetting a break statement in a switch case to the potential for a buffer overflow. Static code analyzers have the ability to spot issues with software that might normally be overlooked by the compiler and engineers reviewing the code. Setting up a static code analyzer early in the implementation phase is a great practice to ensure that potential issues are dealt with immediately rather than late in the development cycle.
Use #2 - Enforcing coding standards -- Using a coding standard is a great way to ensure that software is developed in a consistent and readable manner. A coding standard will not only specify issues of readability but it can also be used to enforce best practices. A great example of a coding standard that many static code analyzers support is MISRA C. The static code analyzer can be used to ensure that developers aren't violating most of the recommendations or best practices of the standard (Some rules require visual inspection, however, and compliance can’t be automatically determined). If a violation did occur, the static analyzer would report the violation to the developer and corrective actions could be taken. The result of using a static analyzer to enforce a coding standard is a quick determination whether or not the code follows the defined standards.
Use #3 - Supporting strict adherence to ANSI-C -- Developers who are concerned with writing portable software that meets the ANSI-C standard can use a static analyzer to determine if any non-standard language features are being used. Setting the analyzer to "strict" will identify area of interest where portability to different compilers or platforms could become an issue. Developers can then review those areas and improve the software to better comply with the ANSI-C standard or at least document which areas of the software may require additional effort to port.
Use #4 - Performing strong type checking -- The C programming language does not support strong type checking. In C, if a developer were to create his own type, the compiler will ignore the new type and instead use the underlying C type. An example of how this works can be seen in Figure 1.
Figure 1 – Weakly Typed
In the example in Figure 1, a compiler will view Var1 as having the underlying type int (implementation defined) and not as a new type MyEnum_t. A developer may want to provide a distinction between an int and MyType_t and have the compiler warn if they are used interchangeably. Unfortunately, on line 13 the compiler views setting Var1 (underlying type int) with the value of Var2 (underlying type int) as not being an issue. A static analysis tool can be set to perform strong type checking which would highlight Var1 = Var2 as being an assignment of two different types and something that a developer probably doesn’t really want to do.
Use #5 - Provide dimensional checking -- One of my favorite spacecraft losses of all time was the Mars Climate Orbiter that was launched back in December of 1998. The spacecraft was lost due to sending its orbital insertion parameters in Non-SI units of lbs * s instead of N * s (Oops!).
The loss of the Mars Climate Orbiter has forever engrained the importance of making sure that correct units are being used. But the C programming language offers no way to provide any type of dimensional analysis to ensure consistency of calculations. A static code analyzer, though, can perform these checks and ensure that kilometers isn't accidentally multiplied by feet to yield an incorrect result. Setup for dimensional analysis varies from one tool to the next, but it is an important feature that developers should take advantage of.
Use #6 - Supporting basic stack analysis -- Understanding the worst case stack usage is critical to developing any real-time based embedded system. There are many ways to go about analyzing and determining what the worst case stack usage is, but one way to start to get a feel for the stack usage is to use the static code analyzer. A static analyzer can calculate a function's stack usage and call graph to provide a basic feel for about how deep the stack needs to be. The static analyzer tool can also provide insights into how the program functions are used and whether or not they are deemed to be deterministic. Using the static analyzer to get a feel for stack usage and the worst case function is a good first step to understanding the worst case stack analysis.
Use #7 - Assisting thread checking -- Static analysis tools can also be used to identify problems with threads and tasks that are running concurrently on a processor. For example, an analysis tool can identify if there are any abnormalities associated with locking or unlocking a mutex. Thread checking can be an extremely useful tool to identify issues in a real-time system but setup for such analysis is usually not trivial. None-the-less the setup effort can be well worth the discovery of an elusive or abnormal thread occurrence.
Static analysis is an invaluable tool to developers who are looking to develop real-time systems. These seven uses for a static analyzer are just a few examples of the powerful features available in many available analysis tools. The use of a static code analyzer can drastically improve the quality and robustness of a code base and, if setup properly, even ensure consistency and conformance to well-known or customized coding standards.
Jacob Beningo is principal consultant at Beningo Engineering, an embedded software consulting company. Jacob has experience developing, reviewing and critiquing drivers, frameworks and application code for companies requiring robust and scalable firmware. Jacob is actively involved in improving the general understanding of embedded software development through workshops, webinars and blogging. Feel free to contact him at firstname.lastname@example.org, at his website www.beningo.com, and sign-up for his monthly Embedded Bytes Newsletter here.