OSRLogo
OSRLogoOSRLogoOSRLogo x Subscribe to The NT Insider
OSRLogo
x

Everything Windows Driver Development

x
x
x
GoToHomePage xLoginx
 
 

    Fri, 20 Oct 2017     115100 members

   Login
   Join


 
 
Contents
  Online Dump Analyzer
OSR Dev Blog
The NT Insider
Downloads
ListServer / Forum
Driver Jobs
  Express Links
  · The NT Insider Digital Edition - May-June 2016 Now Available!
  · Windows 8.1 Update: VS Express Now Supported
  · HCK Client install on Windows N versions
  · There's a WDFSTRING?
  · When CAN You Call WdfIoQueueP...ously

All About Lint - PC Lint and Windows Drivers

 Click Here to Download: Code Associated With This Article Zip Archive, 68KB

If you’ve wasted your time reading Peter Pontificates in the past couple of issues, you’ll already know that Peter’s been whining about what a lousy job the compiler does at detecting errors.  Several readers have written over the past months to suggest tools to address this problem.  One of the more dedicated of these individuals is Udo Eberhardt, who works for a company named Thesycon GmbH.

The reason we all, including you, are grateful to Udo is that he has taken the time to send us a nice, clean, set of control and configuration files for running PC-lint on Windows drivers.  He has even zipped up these files with some comments and a sample driver to demonstrate PC-lint’s use on a real project.  We’ll make Udo’s original ZIP file available for download from OSR (www.osr.com/ntinsider_2002.shtml).  But before we go on much further, let’s discuss what lint is.  Then we’ll discuss whether it’s a tool that’s worth your time in terms of catching bugs, and how it might be best deployed in driver development projects.

PC-lint is Not Lint

Lint is a utility that’s been around since the dawn of time, and mostly seen on Unix systems.  It started as a tool to catch sloppy coding and logic errors that the C compiler didn’t or couldn’t catch. Gimpel Software (www.gimpel.com) has been enhancing, evolving, and otherwise developing its own version of lint for more than ten years.  They make a commercial binary version of lint available for the PC, named PC-lint, which you can purchase (US$239 for 1 workstation, US$1500 for a 10-user license) from their web site.

The Gimpel version of lint is the defacto standard for the PC space. We purchased and tested PC-lint V8.0 for this article, and all following references to lint or PC-lint are meant to refer to that product.

The first thing that needs to be stated is that PC-lint is a far cry from the lint of days gone by.  Under Gimpel’s direction, PC-lint has evolved into a powerful static analysis tool focused on the C and C++ languages.  It knows about most of the extensions, peculiarities, and implementation-specific details of Microsoft C and C++ implementation, so it doesn’t (always) arbitrarily complain about the use of a compiler-specific extension or practice.  While you can run it within the VS IDE (just like build), you gui-philes will want to note that PC-lint is a command-line utility.  Output goes to a plain text file.  You read that output with an editor.

The most useful and interesting enhancements implemented to PC-lint in recent years are sophisticated flow-of-control analyses, where variables are tracked for initialization errors, and inter-statement value tracking, which deduces and follows the paths of variables through a function.  PC-lint is, in fact, smart enough to look across multiple modules to find all sorts of subtle errors.  In short, PC-lint V8 is not your father’s Unix-based lint.

PC-lint can be used to find subtle logic and syntax errors in complex C or C++ code.  It can also be used to help enforce programming standards, if you’re into that sort of thing.  PC-lint can be used for testing drivers and applications alike.

PC-lint allows you to create reusable configuration files.  One configuration file, supplied by Gimpel, deals with MSVC compiler-specific tailoring.  Our colleague Mr. Eberhardt has provided us with a couple additional files, aimed directly at making things work better with the specific perversions in the DDK’s header files.

Integrating PC-lint with Build

So, how difficult is it to integrate PC-lint in the driver development process?  You might be surprised to learn the support for PC-lint is already integrated into the “build” utility via makefile.def.  So, assuming that you use the standard DDK build environment (either directly from the command line or via an external build procedure from Visual Studio), integrating PC-lint into your build is easy.  Just set a few environment variables, and “build” does the rest.

Also, a casual glance through a variety of DDK-supplied header files will turn-up a number of PC-lint control commands.  This is very useful, as it helps to keep the count of nonsense errors down.  It’s clear that at least some development teams at Microsoft, or perhaps some individual developers, use PC-lint. 

Mr. Eberhardt has thoughtfully supplied a command procedure that serves to illustrate how the various PC-lint environment variables are used.  It’s a good starting place for creating your own procedure, and it’ll get you going using PC-lint without having to do much (er, any) thinking.  Later, if you get into this PC-lint thing, can peruse makefile.def (just search for “lint”) and you’ll find all the underlying details.

What Errors Does It Find?  Do We Care?

The original Unix-based lint tool was famous for a lot of things.  Mostly, it was famous for producing reams of output, and tons of annoying and mostly useless error messages.  You may rest assured: Many of those messages are all still there.  The good news, however, is that the compiler-specific config files distributed with PC-lint and Mr. Eberhardt’s driver-specific config files cut down the number of error, warning, and info messages generated significantly.  But you’ve got to remember: Generating messages that make you think about and check your code is what PC-lint is all about.  So, basically, if you make the decision to use PC-lint, get used to looking through the messages.

Let’s examine the sorts of things PC-lint complains about.  In testing PC-lint, we ran it on an assorted list of in-house drivers and kernel mode “stuff”, plus a few samples from the DDK.  While we certainly could have, we didn’t make any effort whatsoever to refine Mr. Eberhardt’s config files.  Heck, we’ve got to leave something for you guys to do, right?

One thing we noticed right away was that PC-lint will place any messages generated by the #pragma message(“xxx”) construct in its log file. You’re probably wondering why you would care, but this is great, to put it mildly.  Sure, these same messages get barfed into your build log file.  But, who ever reads that?  Think these messages aren’t useful or important? 

C:\WINDDK\3615\src\wdm\usb\bulkusb\sys\bulkpwr.c(274):
Warning 644: Variable 'ntStatus' (line 75) may not have been initialized

I’m thinkin’ this is a message that I’d prefer not be buried in the log and discovered “by accident”.  Score one for PC-lint.

The next thing we noticed was that PC-lint is unusually good at identifying “stuff” that’s not used in your code.  And it’s not just unreferenced local variables that it picks up, either.  It’ll also attempt to identify unreferenced globals, and even unused structure fields.  It is also smart enough to not be fooled by assignments to variables during initialization.  So, for example a declaration with initialization such as:

     PUCHAR pInf=NULL;

 will be reported with the following message:

 C:\WINDDK\3615\src\wdm\usb\bulkusb\sys\bulkpnp.c(819):
Warning 529: Symbol 'pInf' (line 640) not subsequently referenced

Score another point for PC-lint.  Pretty amusing so far, right?  But you’re probably wondering: Did it find any real errors?  Well, in a word, yes, it did. For example, check out the following message:

C:\ddkext_CHECKED_IN\src\validate.cpp(1334):
Warning 613: Possible use of null pointer 'Irp' in left argument to operator '->'

[Reference: file C:\ddkext_CHECKED_IN\src\validate.cpp: line 1303]

I first saw this error amid a flurry of messages accusing me of “suspicious casts” and variables that are “not subsequently referenced.” I figured that PC-lint was going to slap my hand for not explicitly checking that the IRP pointer passed into one of my dispatch routines was non-NULL before dereferencing it.  I don’t know about you, but checking to see if IoCallDriver has called me with an IRP pointer that’s NULL is pretty far beyond my idea of a necessary check to ensure driver quality.  Plus, the code I was checking had been extensively tested (and, ah, had already been checked in).

To my surprise, the error wasn’t what I had expected at all. In fact, PC-lint found a case where I’d been bitten with a cut and paste bug, and actually could dereference a NULL pointer. Ooops.  In fact, it found this same bug (in the, ahem, same code sequence) in two different places.  Well done, PC-lint!  I must remember to log a bug against myself for this.

PC-lint also found a couple of solid cases in the drivers we tested where there was a path through a complicated function that could result in the function trying to return the value from an uninitialized variable.  It took us a couple of minutes to recognize the error message, though, which was:

C:\WINDDK\3615\src\wdm\usb\bulkusb\sys\bulkpwr.c(274):
Warning 644: Variable 'ntStatus' (line 75) may not have been initialized

Checking the code, I discovered that the variable in question (“ntStatus”) held the return value for the function.  This is clearly a nasty error, and PC-lint found it.  In fact, PC-lint found a couple of these during our tests, as well as a couple of cases where a potentially uninitialized variable was being tested in if statements.

Unfortunately, PC-lint’s much vaunted flow-of-control processing and value tracking don’t always work the way they should.  I was initially psyched to see the following message:

 C:\WINDDK\3615\src\wdm\usb\bulkusb\sys\bulkpnp.c(575):

Info 774: Boolean within 'if' always evaluates to True [Reference: file C:\WINDDK\3615\src\wdm\usb\bulkusb\sys\bulkpnp.c: line 540]

This message is saying, in essence, that the statement at line 575 will always evaluate to TRUE, because of the test or assignment that previously took place on this same variable at line 540.  For example:

BOOLEAN bob;
.
.
.
 if(bob) {
    //
    // a ton of code and conditionals and stuff goes here
    //
   
    // later..
    if (fred || bob) {
     }
}

While rarely as obvious as the error shown above, when you can find these errors, it’s great.  They usually point to a larger logic or structure problem in your code (I know I often find these errors in code that’s “evolved” a great deal, or perhaps been cut and pasted from elsewhere).

Unfortunately, the error PC-lint “discovered” in our test code happened not to be an error at all in this case.  PC-lint apparently lost-track of the nesting-level of the if’s… and complained about a perfectly valid if statement.  Sigh!  Such is the cost of lint.  You’re always going to be smarter than it is.

Also on the down-side, PC-lint seems to be fond of whining about a number of things that you probably won’t care about.  Consider, for example, an array like the following, used to convert PnP minor function codes to text:

static PSTR pnpMinorCodes[] =
{

    "IRP_MN_START_DEVICE",
    "IRP_MN_QUERY_REMOVE_DEVICE",
    "IRP_MN_REMOVE_DEVICE",
       ...

PC-lint whined about every single line above, saying:
C:\my_wdm\driver\fredpnp.cpp(250): Info 1776:
Converting a string literal to char * is not const safe (arg. no. 1)

Seeing those errors got old, fast.  Of course, whining is a big part of what PC-lint does.  So, for example, if I were committed to lint, all I’d have to do to suppress these messages is put a single PC-lint control command in this declaration, in comments, as follows:

 :
static PSTR pnpMinorCodes[] =
{                            
// lint –e{1776}
    "IRP_MN_START_DEVICE",
              ...

So, Does It Suck?

In fact, we were surprised to discover that PC-lint does not suck.  The major hurdles of getting PC-lint to run quickly and easily within your build environment and reducing the DDK-specific messages it generates are largely overcome by its integration with the build utility and Mr. Eberhardt’s quick-start package.  This doesn’t mean that there isn’t room for improvement, of course.  For example, I found a few macros and features in the DDK that, when used, generated a pile of useless errors.  Undoubtedly, you’ll be able to reduce these with time.  And, of course, you’ll send your contributions back to us, so we can share them with the community, just as we’ve shared Mr. Eberhardt’s work.

But you definitely do pay a significant start-up cost for using PC-lint.  The best way to use it is certainly “early and often.”  You certainly won’t want to run PC-lint on every build, but by the same token it would be an error to wait until your project is complete before giving it a go.  So, as you get portions of your code done, you’ll want to run PC-lint on your sources.  Then review the output, and insert PC-lint control commands to disable the spurious ones.  This’ll eliminate those messages from subsequent runs.

Sure, PC-lint can be annoying.  But you’ve got to ask yourself: Will it save you more time by finding possible bugs than it costs you in sorting through the messages and inserting weird little PC-lint control commands?  Given our tests here at OSR, we’d say it’s worth the effort.

I’m going to go file those bugs on the problems it found now.

Again, on behalf of OSR and the driver development community, our thanks to Udo Eberhardt for his PC-lint config file contribution.

Related Articles
Enabling Debugging on the Local Machine for Windows XP®
You're Testing Me - Testing WDM/Win2K Drivers
Analyze This - Analyzing a Crash Dump
More on Kernel Debugging - KMODE_EXCEPTION_NOT_HANDLED
Making WinDbg Your Friend - Creating Debugger Extensions
Life Support for WinDbg - New Windows NT Support Tools
Life After Death? - Understanding Blue Screens
Must Use New DDK Compiler
Bagging Bugs — Avoidance and Detection Tips to Consider
Choose Your Weapon: Kernel Mode Debuggers - a Choice at Last

User Comments
Rate this article and give us feedback. Do you find anything missing? Share your opinion with the community!
Post Your Comment

Post Your Comments.
Print this article.
Email this article.

Writing WDF Drivers I: Core Concepts
LAB

Nashua (Amherst), NH
15-19 May 2017

Writing WDF Drivers II: Advanced Implementation Techniques
LAB

Nashua (Amherst), NH
23-26 May 2017

Kernel Debugging and Crash Analysis
LAB

Dulles (Sterling), VA
26-30 Jun 2017

Windows Internals and Software Driver Development
LAB

Nashua (Amherst), NH
24-28 Jul 2017

 
 
 
 
x
LetUsHelp
 

Need to develop a Windows file system solution?

We've got a kit for that.

Need Windows internals or kernel driver expertise?

Bring us your most challenging project - we can help!

System hangs/crashes?

We've got a special diagnostic team that's standing by.

Visit the OSR Corporate Web site for more information about how OSR can help!

 
bottom nav links