One of my goals of my static analysis tool, NStatic, is to support parameter validation of API calls. My initial approach was to scan the Rotor (SSCLI) code base to automatically infer requirements on each of the parameters in the Base Class Library of the Framework. I also looked at using Reflector and the FileDisassembler addin to handle closed parts of the Frameworks including the recently released .NET 3.0.
However, I found this approach to be unsatisfactory:
- There may be legal restrictions placed on the license regarding commercial use of the Shared Source Common Language Implementation as well as the decompiling of the standard system libraries, however widespread the practice currently is.
- Validation is tied to a particular version and platform (eg, 32 bit) of the framework, which may not be the one that is actually used by code being scan. There are also differences between the SSCLI and the shipping runtime, I have detected mostly in signatures.
- Validation only encompasses a proper subset of available Microsoft managed libraries and doesn't even address third-party component or proprietary libraries.
Therefore, I decided to interpret IL directly. This has a number of advantages:
- Any managed call from any library (Microsoft, third-party and proprietary) can be processed symbolically without the availability of source code.
- This sets the product up to eventually support static code analysis of IL binaries from any managed language (VB, C++/CLI, Delphi) with debug symbols information extracted from PDB files to support code highlighting.
- While C# also has source code analysis, it would also gain binary analysis which is more exact and wouldn't be reliant on the accuracy of the NStatic compiler. On the other hand, binary analysis of C# does not handle features specific to the C# language and may have inferior error highlighting. Also, source code analysis doesn't require that a project be built, completely written or even fully compilable.
This task has added a few more weeks to my product release, but should be well worth it.
On a related note, I long abandoned another idea of mine. Symbolic processing, which operates at the conceptual level, leaves the door open for optional reflection-based calls of methods of immutable data types, if all the parameters are fully specified. However, this turns out to be complex for many reasons such as nonterminating function calls, presence of side effects, and the inability of reflection-only assemblies to execute code.