The Code Analyser LCLint
Soon after C was born without function prototyping, it was agreed that code debugging was an excessively complex task. As a result, a very powerful tool, lint, was created which was able to make a large number of static verifications of the code. This interesting program was written by S.C. Johnson in the early '70s, and it was the first static code-validation tool.
With the creation of the ANSI C standard, some lint verifications became superfluous. However, lint continued to be used while other tools were being created. John Guttag and Jim Horning took a step forward by programming LCLint. In a rough approximation, it works the same way as lint, and lint's users will need very little time to understand how to use it. However, with a bit of work, we can improve the detail of analysis we received from lint by using LCLint. Since its birth it has received the financial support of ARPA, NSF and DEC ERP.
Today, the LClint source code is freely available. It was written in C; therefore, anyone with a standard ANSI C compiler can recompile it for their machine. Linux users can download it as a tar archive file and as an RPM package. It is available in both source and executable format. Some distributions, such as SuSE Linux 5.3, currently provide it as part of the distribution. It can be downloaded from http://linuxdoc.org/.
The original lint has far fewer commands than LCLint, and all can be emulated using LCLint. That is why we can use LCLint to replace lint. Much of the difference between lint and LCLint is that lint's annotations are related to minimizing the number of spurious messages, while LCLint's annotations have more features, only some of which are used for this purpose.
All lint commands are fully supported by LCLint, but we can obtain a more accurate analysis using LCLint annotations. The equivalencies between the most common annotations of lint and a more accurate version of the commands are shown in the sidebar “lint Commands”.
The basic idea of LCLint is to run it on our code before compiling. lint will search for many possible bugs in the program and return its findings. However, the quantity of bug candidates, though larger than the -Wall option of gcc, is still small because LCLint makes an analysis of specified code, but does not know if that code was written according to its semantics. As a result, we can use LCLint in one of several forms. The first is to use it as a simple static analyser of raw code. Although, in this mode, LCLint recognizes many mistakes without a big-time investment in the process, it is recommended only for debugging code written by other programmers. This mode of analysis is not the best, because LCLint does not know the semantics used when the code was written and therefore it cannot discover if the program does whatever it theoretically is supposed to do.
When we wish to use it on our own programs, we indicate the semantics of our program through annotations which give LCLint more information on the program functions. LCLint uses that information for deducing whether the program does what we intended and not something else. This form of using LCLint allows us to reduce the debugging effort of large amounts of code with a minimal time investment. I will discuss some annotations to demonstrate the use of LCLint. For more information, read the manual.
A third analysis method is based on the specification of abstract data types. We can specify interfaces, functions, types and predicates using the pseudo-language LCL. LCLint will automatically generate the corresponding header files to such specifications and verify that the code agrees with these specifications. However, although LCL is an algebraic-specification language, LCLint will not prove theorems or properties, verify correctness or completeness of the algebraic definition, or generate code. It will generate headings and verify that the code corresponds to the algebraic definition.
LCLint is a versatile tool because it can do code analysis at any level of abstraction we wish. LCLint has several levels of analysis, corresponding to a greater or smaller quantity of different checking techniques. These levels are:
weak, which does minimal monitoring. This level should be used only for C code without annotations. LCLint static analysis could be used as a first pass.
standard is the default analysis. It does the same as weak analysis, plus a bit more. It needs a few annotations to be truly useful.
checks does all the checks of standard, plus complete monitoring of the function parameters and inconsistencies. It is a good level for proving definitely that no statically verifiable mistakes are present before using other software testing techniques.
strict makes absurdly strict checks. Should be used only if there is a very subtle but annoying mistake, or if we are fanatics of strong-typed and strong-structured languages. It includes checks such as if the global variables specified within a function are usable in that function (usable or not as marked by annotations), and checking of types is quite strict. The programmers of LCLint assure me that they will give a prize to anyone who writes a real program that receives no warning when using LCLint in this mode.
In addition to these generic analysis options, for each possible check we have an option to enable one and disable another.
We can gain the best use of LCLint using an incremental approach. First of all, compiling the program using Wall can help us find the biggest errors; for example, truly strange operations with pointers or arguments passed to functions in the wrong way.
After this, we can begin with the weak analysis. If we use a naming convention—strongly recommended—it is a good time to use the flags to test that we used the right names and used variables and macros in the right way. This is a deeper level of analysis than we can do without annotations; if we used annotations, we can get that kind of analysis.
The highest level of analysis commonly used is checks. If we obtain only spurious analysis, it is time for dynamic debugging techniques.
The strict level of analysis is good for pieces of code where we cannot find an error that we know exists.
|Speed Up Your Web Site with Varnish||Jun 19, 2013|
|Non-Linux FOSS: libnotify, OS X Style||Jun 18, 2013|
|Containers—Not Virtual Machines—Are the Future Cloud||Jun 17, 2013|
|Lock-Free Multi-Producer Multi-Consumer Queue on Ring Buffer||Jun 12, 2013|
|Weechat, Irssi's Little Brother||Jun 11, 2013|
|One Tail Just Isn't Enough||Jun 07, 2013|
- Speed Up Your Web Site with Varnish
- Containers—Not Virtual Machines—Are the Future Cloud
- Linux Systems Administrator
- Lock-Free Multi-Producer Multi-Consumer Queue on Ring Buffer
- RSS Feeds
- Senior Perl Developer
- Technical Support Rep
- Non-Linux FOSS: libnotify, OS X Style
- UX Designer
14 min 20 sec ago
- Reply to comment | Linux Journal
36 min 39 sec ago
- Android has been dominating
41 min 11 sec ago
- It is quiet helping
3 hours 26 min ago
3 hours 44 min ago
- Reachli - Amplifying your
5 hours 23 sec ago
5 hours 49 min ago
- good point!
5 hours 52 min ago
- Varnish works!
6 hours 1 min ago
- Reply to comment | Linux Journal
6 hours 30 min ago
Free Webinar: Hadoop
How to Build an Optimal Hadoop Cluster to Store and Maintain Unlimited Amounts of Data Using Microservers
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Some of key questions to be discussed are:
- What is the “typical” Hadoop cluster and what should be installed on the different machine types?
- Why should you consider the typical workload patterns when making your hardware decisions?
- Are all microservers created equal for Hadoop deployments?
- How do I plan for expansion if I require more compute, memory, storage or networking?