I am testing my NDIS (5.1) miniport driver with a WDM lower edge with CUV
enabled on W2k3. The driver uses queued spinlocks for protecting shared
resources in the WDM path of the driver. I am getting the following CUV
errors:
DDK+ Driver Error: Calling KeAcquireInStackQueuedSpinLock(…) at File ?,
Line 1064
??? The Lock Queue Handle specified as parameter 2 [addr1]
??? must be located in non-paged memory but is instead
??? located on the stack
DDK+ Driver Error: Calling KeReleaseInStackQueuedSpinLock(…) at File ?,
Line 1072
The Lock Queue Handle specified as parameter 1 [addr1]
has not been previously initialized by this driver.
The DDK documentation says for KeAcquireInStackQueuedSpinLock:
The driver allocates a KLOCK_QUEUE_HANDLE structure that it passes by
pointer to KeAcquireInStackQueuedSpinLock. The driver passes the same
structure by pointer to KeReleaseInStackQueuedSpinLock when it releases the
spin lock. Drivers should normally allocate the structure on the stack each
time they acquire the lock.
OK, I follow the DDK:
void MyFunc(PMY_ADAPTER adapter)
{
?
KLOCK_QUEUE_HANDLE??? hLock;
?
KeAcquireInStackQueuedSpinLock(&adapter->WdmLock, &hLock); // Line
1064
?
// access shred resource
?
KeReleaseInStackQueuedSpinLock(&hLock); // Line 1072
}
The function can be called from passive as well as dispatch level.
I see the same CUV errors reported when using
KeAcquireInStackQueuedSpinLockAtDpcLevel /
KeReleaseInStackQueuedSpinLockFromDpcLevel in a timer DPC routine.
So, then I find this explanation in the DDK:
CUV Limitations
Call Usage Verifier (CUV) is a diagnostic tool for finding otherwise
hard-to-spot driver errors. However, shared data structures and stack-based
data structures can cause CUV to report false errors.
Shared Data Structures
Most CUV error checks keep track of calls that your driver makes to specific
driver support routines. When a driver attempts to use a data structure,
such as a list head or spin lock, in a call to a routine that CUV tracks,
and CUV has not seen the driver previously call an initialization routine
for that data structure, CUV reports an error.
Therefore, if a driver uses a data structure that has been properly
initialized by a component other than that driver, CUV will report an error.
You can ignore such errors, if you are sure that the data structure has been
properly initialized. If your driver frequently uses shared data structures
for lists or spin locks, you should probably not use CUV.
Stack-Based Structures
In general, CUV does not track or validate data structures that are located
on the stack, because stack-based variables are valid only within the scope
of the current function. However, due to the way Windows manages stacks in
deferred procedure calls (DPCs) and interrupt service routines (ISRs), CUV
might incorrectly identify stack-based variables used by these routines as
not being on the stack. This can cause CUV to report false errors for such
variables. For example, CUV might report that a data structure has already
been initialized, when in fact it has not.
Most data structures that would typically be tracked by CUV are not tracked
or validated if CUV determines that they are located on the stack. However,
CUV can be “fooled” by data structures that are located on the stack within
DPCs and ISRs. Therefore, CUV can report false errors for stack-based data
structures ? such as reporting that such a data structure has already been
initialized, when in fact it has not.
CUV does not consider the stack to be a valid storage location for
structures that must reside in nonpaged memory. Although the stack can
safely be used for temporary storage of nonpaged data structures under some
very specific conditions, such cases are very rare. So, for example, if a
driver allocates an IRP or a spin lock on the stack, CUV will report this as
an error.
My questions:
-
Is this a CUV bug that it reports a false error or is the DDK
documentation wrong? -
If the DDK documentation is wrong then what would be the correct way
allocating the lock handle? I think allocating the lock handle on the device
(adapter) extension would be wrong. The lock handles contain per thread
information about the queues. Multiple threads on different processors may
use the same handle and cause corruption of the queue if the lock handles
are allocated on the adapter extension.
Allocating and freeing the lock handle in nonpaged pool using
ExAllocatePool/ExFreePool every time the function is called doesn?t seem to
be an efficient way, but it shuts CUV up. -
Is there a way to disable this particular check so that CUV won?t break
into the debugger?
Thanks
Gernot Seidler