The most powerful form of analysis is global — that is, interprocedural — in scope. Patterns detected in one function or method are correlated with patterns found elsewhere in a program. The analyzer watches the flow of data throughout the entire program, creates a model of the program, and simulates execution paths. The Coverity and Fortify analyzers fall into this category, as does PREfix, Microsoft’s centralized tool. Microsoft’s desktop tool, PREfast, is instead an intraprocedural analyzer mainly focused on local pattern matching. Programmers can, however, annotate functions using SAL (structured annotation language), a notation that enables PREfast to undertake more powerful interprocedural analysis. Another pattern-matching intraprocedural analyzer is the one included with Compuware’s DevPartner Studio. Its domain of analysis is VB.Net and C#.
Analysis that comprehends the complete scope of a program still benefits from knowledge of the context in which that program runs. Fortify’s analyzer, for example, traces from Java methods into database-stored procedures and back again. “Conventional wisdom says that if you use parameter binding, you won’t be subject to SQL injection attacks,” Chess says. But since stored procedure can also construct SQL code, they too are included in the analysis. Similarly, Fortify’s tool looks at how programs interact with their XML configuration files. “If you don’t stitch configuration files together with code,” Chess says, “you don’t really know how the program will behave.”
Coverity’s approach, though, places less emphasis on specific platform knowledge. Using statistical analysis of the patterns seen in a program, it infers that deviations from the norm are probably errors. To illustrate, Engler describes the kinds of rules implicit in programs: “If you do A, then you must do B. In context X, you can never do Y.” How does automatic inferencing work? “Count how often A is followed by B, versus how often A appears by itself,” Engler says. “If you see that A and B are paired 1,000 times, and not paired once, you can be pretty sure that one time is an error.”
Microsoft’s Lucas embraces both strategies. PREfast, and a companion tool called FxCop that works with the .Net languages, grew out of Microsoft’s study of its own programming practices. Some of the rules that emerged are heavily domain-specific, describing correct use of APIs and frameworks. In the .Net realm, for example, FxCop finds “problems with COM interop, common security violations, and common errors that lead to poor-performing code,” Lucas says. Compuware’s analyzer performs similar kinds of checks. A rule called “open to file path hacking,” for example, ensures that if a file system path is protected, the corresponding UNC (Universal Naming Convention) path is also protected.
In general, Java and .Net analyzers are more likely to focus on domain-specific issues. That’s because the memory-related errors that preoccupy C and C++ analyzers, making programs unstable or vulnerable to attack, are mostly absent in managed-code environments. That doesn’t mean there are no memory-management issues to worry about. Managed programs can, for example, still “leak objects,” but the emphasis tends to shift to a higher level of analysis.
Making the Rules