When engineering any kind of system, checking for defects and fixing errors early (and often) enables teams to significantly reduce the amount of downstream work added to the project, and is a surefire method to avoid multiple headaches along the way.
In software development, instead of engineering better software in the first place, it is tempting to fall into a common mousetrap and try and simply test quality into the software project (usually at the end). But it’s important to avoid the temptation to follow such an approach, that relies on unit or functional testing to test quality into the product. To build more quality into the software from the beginning, the developer can take control, by employing static analysis, the simplest and most effective activity that software engineers can perform to prevent defects and harden code while accelerating application delivery.
Static code analysis (or static analysis) is a software testing activity in software development, in which the source code is analyzed for constructs known to be associated with software errors or security vulnerabilities. When a high-risk construct is detected, the static analysis tool reports a violation for the developer to view and remediate.
Before we review some of the main benefits of static analysis, let’s review the different types of static analysis and the differences between them.
There are a few main types of static analysis, each with its own strengths and weaknesses. The terms for each are below.
In its simplest form, a static analysis tool scans the source code and checks it against one or more sets of rules. For example, engineers sometimes make the mistake of using the string “\0” when the null character ‘\0’ is actually intended. This mistake can result in memory corruption and cause the program to crash or do other nasty things. A static analysis tool looks for these patterns in the code and reports them as possible errors. This kind of static analysis is known as pattern-based static analysis. Some patterns are simple syntax checkers, akin to a spell-checker when writing. Other patterns can be much more sophisticated, analyzing and detecting complete patterns associated with subtle problems. This kind of static analysis almost never suffers from false positives.
Modern software engineering standards like Motor Industry Software Reliability Association (MISRA) and Joint Strike Fighter (JSF) are based on the idea that certain constructs should be avoided in code that is safety critical, because of the possibility for code in such systems to have problems.
By providing “safer” alternatives to “unsafe” facilities, known problems with low-level features are avoided. In essence, programs are written in a “safer” subset of a superset.
From Joint Strike Fighter Air Vehicle C++ Coding Standards – Introduction
Flow analysis, sometimes called control-flow or data-flow analysis, is somewhat different. This type of code analysis checks for problematic constructions against a set of rules, while simulating decision paths to dig deeper into the application and root out hard-to-find defects, such as null pointer dereferences, buffer overflows, and security defects such as tainted data. Flow analysis is great in that it can find real bugs, but a certain number of false positives are always part of this method.
There are other types of static analysis that achieve different types of goals. For example, metrics analysis tools measure code characteristics, such as lines of code and complexity. Coverage analysis tools track unit and application tests to enable a better understanding of how well the code is tested. When used together as part of an automated development testing process, these types of analyses provide significant visibility into the safety, security, and reliability of the application.
The state of software is becoming more and more complex. Today, for example, the average automobile may contain over 1,000 code-executing MCUs and as much as 100 million lines of code! That much electronic surface area, especially in safety-critical applications, such as automotive, medical devices, or avionics, demands a rigorous engineering approach to software in order to approach defect-free code.
The good news is that organizations such as OWASP, CERT, and MITRE are committed to researching and publishing programming best practices to help software engineers succeed with their software projects. There are also industry-specific standards organizations (such as MISRA, focusing on automotive software systems), which publish best practices that are often required by regulatory bodies. These best practices can be codified into static analysis tools as rules, that you can choose to implement as part of your organization’s policy for developers to follow.
Using a static analysis tool that can implement these programming standards while integrating with your development process is critical. From a business perspective, failing to check your work with at least one static analysis tool significantly raises the risk of deploying or releasing your applications. Defects can lead to exploitable code that malicious hackers can use to crash the system, expose sensitive data, etc. In the case of safety-critical software, the consequences of software vulnerabilities can be far more serious.
Running static analysis on the desktop will provide some benefits and may work for small teams or projects; however, in large organizations, static analysis should also be automated as part of nightly builds and continuous integration. When implemented as an integral part of the development process, analyzing your code with static analysis provides a number of benefits, including the following:
Consistently running static analysis from the early stages of the project enables you to find and fix systemic defects when the cost of remediation is at its lowest. The process may initially take more time than rapidly developing the software without running analysis, but the gains in efficiency become exponential over the development lifecycle. Remember that some of the more dangerous errors may be difficult to address late in the cycle, so finding them early is crucial.
Good static analysis tools also include descriptive documentation about the programming standard being implemented, which extends software engineers’ programming knowledge and professional development. Over time, compliance with these standards improves the average quality of the code by improving the programmers through constant feedback. If your static analysis tool has a broader ecosystem that can automatically prioritize defect remediation tasks, then you’ll be able to deliver the software even faster.
Static analysis helps you find and fix defects early, which can prevent the recurrence of systemic defects downstream. With a policy of early detection, you can more easily implement a policy of defect prevention, which reduces the rate of defects over the development lifecycle. (Shameless plug: Parasoft C/C++test, which not only reports static analysis violations but also integrates with an incredibly sophisticated analytics platform, can give you a broader understanding of all of the instances of the reported defect and its overall impact on the quality of your codebase.)
The term DevOps is often used to describe a collection of practices that facilitate the cross-departmental collaboration and communication necessary to help organizations optimize and accelerate their development and delivery processes. By sharing knowledge and tasks across departments, organizations create an efficient process for accelerating the SDLC while improving quality processes.
For this approach to be effective, however, an automated feedback loop must be implemented that enables the consistent application of quality policies as requirements progress from creation to production.
Automated static analysis is not only the mechanism for the feedback loop, but it also generates the data that other departments need to access and collaborate effectively under the DevOps model. Especially when used with unit and regression testing, static analysis serves a few roles, including:
As a result, static analysis becomes an agent for continuous, automated process improvement. It provides a way for developers to understand and examine an error detected during release, or for QA to determine if there is a way to harden code and eliminate the possibility of these defects to occur in the future.
There are several static analysis tools on the market, ranging from open source utilities to full development testing suites. Parasoft’s software testing solution provides an integrated platform for automating a broad range of software quality practices for multiple coding languages, while providing meaningful, comprehensive reports and the option for intelligent analytics, powered by Parasoft DTP.
For C and C++, in addition to a full range of static code analysis capabilities and over 2,200 rules (the most of any tool on the market, based on implementations of MISRA, MISRA C++, FDA, Scott Meyers’ Effective C++, Effective STL, and other established sources), Parasoft C/C++test provides a unified solution for your development testing practices. It generates and executes unit tests; enables several types of code coverage, including line, statement, block, path, decision (branch), simple condition, and MC/DC coverage; provides runtime analysis, and comes with a tool qualification kit for complying with functional safety standards.
Parasoft also has full static code analysis support for Java language, with Parasoft Jtest, and for the .NET language, with Parasoft dotTEST. Just like with C and C++, these are fully integrated solutions that provide more than just static analysis, so you get a comprehensive solution to bring efficiency and ease to your software testing. A user can analyze code with Parasoft static analysis on the desktop and also integrate it into your automated builds to enable you to prevent defects continuously and automatically.
To gain automated workflows that enhance collaboration and efficiency, these static analysis engines integrate with Parasoft DTP, which provides workflows for integrating quality into your SDLC, so you can define your development policy and then automatically enforce non-functional requirements. For example, static analysis is automatically executed during the build, violations are reported to DTP, where they are processed, and results are sent back to the engineer’s IDE, to view for remediation.
DTP also performs intelligent analytics, which enable these workflows to automatically assess the quality and risk of your software development. For instance, DTP can look for systemic issues associated with the programming process, or correlate a severe violation in code produced by a junior engineer with a set of unit tests and coverage information to determine how much risk is associated with the module. If the correlation points to a risk level above a specific threshold, then the violation may trigger a specific continuous process improvement workflow that involves peer code review and additional analysis, in addition to the normal defect remediation tasks.
Static code analysis is an important part of ensuring that applications function as expected. It not only improves the overall development team velocity, but also reduces risks associated with releasing potentially dangerous software. While some analysis is always better than no analysis, static analysis should be integrated into a larger software testing infrastructure to maximize the effectiveness of the practice. Parasoft offers an enterprise-grade code analysis and testing suite in C/C++test, Jtest, and dotTEST, as well as an advanced analytics and reporting system in DTP. Combining these technologies enables software engineering teams to accelerate software delivery, while ensuring that their applications function as expected.
Arthur has been involved in software security and test automation at Parasoft for over 25 years, helping research new methods and techniques (including 5 patents) while helping clients improve their software practices.