Programming the Microsoft Windows Driver Model

The Kernel-Mode Programming Environment

Figure 3-1 illustrates some of the components that make up the MicrosoftWindows XP operating system. Each component exports service functions whose names begin with a particular two-letter or three-letter prefix:

Using Standard Run-Time Library Functions

Historically, the Windows NT architects preferred that drivers not use the run-time libraries supplied by vendors of C compilers. In part, the initial disapproval arose from simple timing. Windows NT was designed at a time when there was no ANSI standard for what functions belonged in a standard library and when many compiler vendors existed, each with its own idea of what might be cool to include and its own unique quality standards. Another factor is that standard run-time library routines sometimes rely on initialization that can happen only in a user-mode application and are sometimes implemented in a thread-unsafe or multiprocessor-unsafe way.

I suggested in the first edition that it would be OK to use a number of standard runtime library functions for string processing. That was probably bad advice, though, because most of us (including me!) have a hard time using them safely. It s true (at least at the time I m writing this paragraph) that the kernel exports standard string functions such as strcpy, wcscmp, and strncpy. Since these functions work with null-terminated strings, though, it s just too easy to make mistakes with them. Are you sure you ve provided a large enough target buffer for strcpy? Are you sure that both of the strings you re comparing with wcscmp have a null terminator before they tail off into a not-present page? Were you aware that strncpy can fail to null-terminate the target string if the source string is longer than the target?

Because of all the potential problems with run-time library functions, Microsoft now recommends using the set of safe string functions declared in NtStrsafe.h. I ll discuss these functions, and the very few standard string and byte functions that it s safe to use in a driver, later in this chapter.

A Caution About Side Effects

Many of the support functions that you use in a driver are defined as macros in the DDK header files. We were all taught to avoid using expressions that have side effects (that is, expressions that alter the state of the computer in some persistent way) as arguments to macros for the obvious reason that the macro can invoke the argument more or less than exactly once. Consider, for example, the following code:

int a = 2, b = 42, c; c = min(a++, b);

What s the value of a afterward? (For that matter, what s the value of c?) Take a look at a plausible implementation of min as a macro:

#define min(x,y) (((x) < (y)) ? (x) : (y))

If you substitute a++ for x, you can see that a will equal 4 because the expression a++ gets executed twice. The value of the function min will be 3 instead of the expected 2 because the second invocation of a++ delivers the value.

You basically can t tell when the DDK will use a macro and when it will declare a real external function. Sometimes a particular service function will be a macro for some platforms and a function call for other platforms. Furthermore, Microsoft is free to change its mind in the future. Consequently, you should follow this rule when programming a WDM driver:

Never use an expression that has side effects as an argument to a kernel-mode service function.

Категории