Increasing Code Coverage during Driver Testing

Updated: June 14, 2004
On This Page
IntroductionIntroduction
Use PREfast for DriversUse PREfast for Drivers
Simulate Low Resource ConditionsSimulate Low Resource Conditions
Simulate Other ErrorsSimulate Other Errors
Use Device Path ExerciserUse Device Path Exerciser
Monitor Code Coverage during TestingMonitor Code Coverage during Testing
Use Code Coverage ToolsUse Code Coverage Tools
ResourcesResources

Introduction

One of the best ways to find errors in a driver is to exercise more driver code during testing. Drivers commonly include code to handle rare events, such as inadequate resources or unusual failure scenarios. Testing more such code paths before releasing a driver can improve the reliability of the driver in the field.

The following are several simple tips for testing more of your driver code.

Use PREfast for Drivers

PREfast is a static code analysis tool that analyzes C code at function level. That is, it applies a set of rules to one function in the driver at a time, verifying that the flow of control within the function conforms to the rules.

Although PREfast does not perform live, operational tests, it is nevertheless useful in identifying code paths that contain potential errors. PREfast can find attempts to use uninitialized variables, failures to release resources such as memory and locks, and failures to check function return values.

The Windows Server SP1 DDK contains a version of PREfast that includes driver-specific rules, along with a reference guide and a "Getting Started" document.

Simulate Low Resource Conditions

Windows provides two simple ways to test driver operation in low resource conditions:

Use Driver Verifier.

Change system boot parameters to limit the amount of memory available to the system.

Driver Verifier (verifier.exe) includes an option to simulate low resource conditions. You can enable the Low Resources Simulation option on the Driver Verifier command line or through the Driver Verifier Manager. When this option is enabled, Verifier causes randomly selected memory allocations to fail, beginning at least seven minutes after system startup. (If you enable the option without rebooting, fault injection starts approximately seven minutes later.) The seven-minute delay avoids fault injection during boot itself and thus provides a more realistic low-resource scenario.

These randomly injected memory allocation faults provide a way to test a driver's response to low-memory conditions and to exercise related code. Because the faults occur randomly and therefore can affect any part of your driver, you can test many code paths in a short period of time.

Another way to simulate low-memory conditions is to change system boot parameters to limit the amount of memory available to Windows. Keep in mind, however, that many drivers fail soon after startup when system memory is severely restricted. Consequently, this method tests a more limited number of code paths.

On Windows XP and later systems, use Bootcfg to add the /burnmemory parameter to an entry in the boot.ini file. When the /burnmemory parameter is enabled, some physical memory is reserved so that it is unavailable to the system. For example, the following reduces the amount of memory on the system by 896 megabytes:

bootcfg /raw "/burnmemory=896" /A /ID 1

In the preceding Bootcfg command, the /raw switch adds the contents of the string "/burnmemory=896" to a boot entry. The /A switch appends the string to the existing entry, rather than replacing all boot parameters for the entry. The /ID switch identifies the boot entry.

On Windows 2000 systems, use Bootcfg to add the /maxmem parameter to an entry in the boot.ini file. The /maxmem parameter limits the amount of memory to a specified value. To add the /maxmem parameter, use the /MM switch in Bootcfg. For example:

bootcfg /addsw /MM 256 /ID 1 

This command uses the Bootcfg /addsw (add switch) switch with the /MM argument and a value of 128 to add the /maxmem parameter and to set it to a value of 128, thus limiting to 128 MB the amount of memory available to Windows. The /ID switch identifies the boot entry.

Simulate Other Errors

You can simulate other types of failures by including driver-specific code that an external application can use to signal an error. One simple technique is to define an I/O control code (IOCTL) that a user-mode test application can send. When the driver receives the IOCTL, it exercises the code related to the error. Such IOCTLs can be as numerous or as complicated as required to test the relevant driver code.

For example, to test code paths related to disk corruption, the IOCTL might specify a driver-defined function code for disk error testing, with specific error data included in the input buffer. The driver's DispatchDeviceControl routine parses the control code and the contents of the buffer to determine exactly which error conditions to test, sets up any additional data required for testing, and then calls the corresponding error-handling routine in the driver.

In addition, the driver must perform security checks on each incoming IOCTL request. The DispatchDeviceControl routine must ensure that each incoming request matches the complete IOCTL definition and that the caller has adequate privileges to perform the requested operation.

You can also use the Device Path Exerciser's Active Control Test option to test the DispatchDeviceControl routine itself.

Use Device Path Exerciser

The Device Path Exerciser (dc2.exe) utility is provided with the WDK.

Device Path Exerciser tests a driver's robustness by rapidly sending thousands of similar calls to the driver. The calls request I/O operations with varying access methods, buffer lengths, addresses, and parameters - some are valid, but many are not. The tests ensure that the driver responds correctly to the requests, either by returning valid data or by failing the request appropriately, without causing a system crash, corrupting the memory pool, or leaking memory.

Device Path Exerciser can help you find driver errors related to:

Unexpected I/O requests, such as file system query requests directed to a sound card.

Query requests with buffers that are too small to contain all the requested data.

IOCTL/FSCTL requests with missing buffers, buffers that are too small, or buffers that contain meaningless information.

IOCTL/FSCTL requests for direct I/O or METHOD_NEITHER I/O in which the data is changing asynchronously.

IOCTL/FSCTL requests for METHOD_NEITHER I/O with invalid pointers.

IOCTL/FSCTL requests and fast path query requests in which the mapping of the user buffer changes asynchronously, causing the pages to become unreadable.

Relative open requests with arbitrary or hard-to-parse file names and open requests for fictitious device objects.

On Windows XP and later systems, you can use the Active Control Test feature of Device Path Exerciser together with driver-defined IOCTLs to test specific IOCTL code paths. To use this feature, you create a list of driver-specific IOCTLs for Device Path Exerciser to send to the driver. The list must appear in an ASCII text file and must be formatted in the same way as entries in the DC2WMIParser log file.

The Active Control Test sends many similar DeviceIoControl requests to the driver, specifying the I/O control codes (no FSCTLs) in the input file and varying those I/O control codes to include randomly generated function codes and function codes that are numerically above, below, and between those listed in the input file. The device types, buffer lengths, addresses, and buffer contents also vary in these requests, so that the DispatchDeviceControl routine and any related error handling code can be thoroughly tested.

Monitor Code Coverage during Testing

To determine how much of your driver code is being exercised, build in ways to monitor the number of times particular code paths are executed. Here are some simple techniques:

Increment a counter upon entry to functions and loops.

Use Event Tracing for Windows to log the entry into a function, the occurrence of various errors, or any other such condition.

Use the counters available in Driver Verifier, which can tell you how many times the driver acquired a spin lock, allocated memory, or raised the interrupt request level (IRQL).

Use the IRP logging feature of Driver Verifier to monitor the IOCTLs that the driver handles. (This feature is available only on Windows Server 2003 and later versions.)

Use Code Coverage Tools

Third-party code coverage tools are also available. You can find such tools by searching for "Windows driver code coverage" in your favorite Internet search engine. Microsoft does not endorse any particular tools.

Microsoft is investigating the addition of code coverage techniques to Driver Verifier and other driver testing tools. In addition, Windows Hardware Quality Labs (WHQL) started a pilot code coverage program in December 2003 for kernel-mode drivers that do not fit into any of the current "Designed for Windows" logo programs. Participation is limited to 100 drivers, and drivers must meet certain criteria. For details, see the WHQL and Windows Logo Program Testing News for March 1, 2004.

Resources

Microsoft Windows Driver Development Kit (DDK)

In the DDK documentation, see the following sections:

For information about Bootcfg:
"Boot Options for Driver Testing and Debugging" in the "Driver Development Tools" section

For information about Driver Verifier and Device Path Exerciser:
"Tools for Testing Drivers" in the "Driver Development Tools" section

For information about defining IOCTLs:
"Handling IRPs" in the "Design Guide" section of "Kernel Mode Driver Architecture"

In the DDK installation directory, see the following files for information about PREfast:

help\vcprefast.chm

\bin\x86\drvfast\doc\prefast_install.htm

Microsoft Hardware and Driver Developer Information


Looking for help with your personal computer?