PSS ID Number: 192486
Article Last Modified on 5/8/2003
The information in this article applies to:
- Microsoft Windows NT 4.0 Driver Development Kit (DDK), when used with:
- the operating system: Microsoft Windows NT 4.0
- Microsoft Windows 2000 Driver Development Kit (DDK), when used with:
- the operating system: Microsoft Windows 2000
- Microsoft Windows XP Driver Development Kit (DDK), when used with:
- the operating system: Microsoft Windows XP
This article was previously published under Q192486
IMPORTANT: This article contains information about modifying the registry. Before you
modify the registry, make sure to back it up and make sure that you understand how to restore
the registry if a problem occurs. For information about how to back up, restore, and edit the
registry, click the following article number to view the article in the Microsoft Knowledge Base:
256986 Description of the Microsoft Windows Registry
SUMMARY
Kernel pool corruption has been difficult to debug on the Windows NT platform typically because the system crashes in an unrelated code section that was expecting valid data in the corrupted pool. Some common causes of kernel pool corruption include:
- Code that allocates N bytes of pool and then reads or writes N+1 bytes.
- Code that frees pool and then accesses or modifies it after freeing it.
- Code that frees the same pool multiple times.
- Code that accesses memory in front of the allocation.
A feature called Kernel Special Pool is included, on Windows NT 4.0 Service Pack 4 and later operating systems, which can be used to find these types of problems. This article describes how the Kernel Special Pool works and how you can use it to debug pool corruption issues in your driver.
MORE INFORMATION
When drivers allocate memory, they usually call ExAllocatePool(). This function in turn calls ExAllocatePoolWithTag with a system specified tag (such as 'Wdm' or 'Ddk'). Alternatively, drivers can call ExAllocatePoolWithTag() directly and specify a unique tag value. The special pool feature tracks either the pool tags or the pool allocation size.
The special pool feature checks the registry for a pool tag or allocation size value. It then causes a complete page of memory to be allocated for each request that matches the specified tag or allocation size. Therefore, Kernel Special Pool is only in effect when the requested allocation size is less than PAGE_SIZE. A special "guard page" is then reserved either before or after this pool which is used to trap buffer underrun and overrun errors respectively.
Overrun Detection vs. Underrun Detection
Buffer overrun detection (the default) is a check to ensure that you do not access memory past your allocation. This is accomplished by 8-byte aligning the request to the end of the allocated page and marking the guard-page, following the allocation, as no-access. If you try to access past the end of the allocated pool, a system trap occurs.
Buffer underrun detection is a check to insure that you do not access memory in front of your allocation. This is accomplished by aligning the request to the beginning of the allocated page and marking the guard-page, before the allocation, as no-access. If you try to access prior to the beginning of the allocated page, a system trap occurs.
In both cases, single-byte corruption within the alignment portion of the page is also detected. If it exists, this slush space, which is less than the alignment size 8-bytes, is at the end of the page for overruns or in the rest of the page for underruns. Corruption in these portions of the page causes a bug check upon release of the memory instead of at the time of the bad access because these cannot be enforced using existing hardware mechanisms.
Therefore, your driver bug checks the system if any of the following conditions occur while special pool is enabled:
- If you enable buffer overrun detection and then try to access memory beyond your allocation. If you enable buffer underrun detection and then access memory before your allocation.
- If you touch your memory allocation after freeing it.
- If you free your memory allocation twice (provided the allocation has not been reused). When the allocation is freed, the page or pages are marked invalid until they are reused. A Least Recently Used (LRU) algorithm insures that freed pools are not reused immediately, but obviously cannot protect the page's reuse forever.
Kernel Special Pool Characteristics- It catches almost all problems associated with pool corruption, and it catches them early enough so that you can fix them easily.
- It works on both the checked and free versions of the operating system.
- Unlike regular pool, which is Last In First Out (LIFO), special pool is First In First Out (FIFO).
- Computers with more memory are given a bigger range of special pool virtual addresses.
- The stack at failure reflects the exact instruction that caused the system to crash. Using the debugger, you can identify the culprit and the information you need to fix the problem.
- It should be used during debugging. Do not enable it in a production environment because it increases the amount of pool that is used and committed (such as page file space) on the system. It can also cause premature paging since the memory usage is greater than average.
Methods for Specifying Pool Allocations
There are two methods that you can use to specify pool allocations:
- By pool tag (ASCII characters):
Use this method to track a specific component's allocations. You can use wild cards ("?" matches any single character and "*" matches multiple characters). For example: - By size in pool blocks:
Use this method to track corruption based on a specific allocation size, regardless of the tag value. You should use one of the following decimal values (for 32-bit systems):
40 for pool blocks in range (0..32] bytes
72 for pool blocks in range (32..64] bytes
104 for pool blocks in range (64..96] bytes
136 for pool blocks in range (96..128] bytes
Enabling Kernel Special Pool
WARNING: If you use Registry Editor incorrectly, you may cause serious problems that may
require you to reinstall your operating system. Microsoft cannot guarantee that you can solve
problems that result from using Registry Editor incorrectly. Use Registry Editor at your own
risk.
There are two different ways to enable Kernel Special Pool. Each requires you to restart the operating system.
- Add two new registry values, PoolTag and PoolTagOverruns, to the following registry (click Start, click Run, and the type RegEdit):
HKEY_LOCAL_MACHINE/CurrentControlSet/Control Session Manager/Memory Management
PoolTag : REG_DWORD : PoolTag_Data
PoolTagOverruns : REG_DWORD : PoolTagOverruns_Data
The PoolTag data represents either four ASCII characters or an allocation size. Because Intel and Alpha processors are little-endian, the ASCII tag must be stored in reverse order. If the data entered is less than PAGE_SIZE, it is assumed to be an allocation size (the exception being the wild card characters "?" and "*," discussed later in this section). Otherwise, the data value is assumed to be an ASCII tag.
The PoolTagOverruns data represents the direction to monitor: 0 (zero) for underrun detection, or 1 (one) for overrun detection. The system defaults to overrun detection if the PoolTagOverruns value is not defined. To create a tag called XyzA manually:
- Start with string XyzA.
- Reverse the string to AzyX.
- Use an ASCII table to get the value of each letter. AzyX is represented as 0x417a7958.
- Enter the DWORD into the registry.
Remember that uppercase and lowercase letters have different ASCII values. The question mark "?" represents any single character and an asterisk "*" represents multiple characters. To track all tags that start with "G," use "G*" as a PoolTag. Use just "*" (0x0000002A) to track all allocations. - Run the GFLAGS utility from the Windows NT Resource Kit.
In the Kernel Special Pool Tag section, select either Hex or Text, and type the pool tag that you want in the box. To remove the tag value, clear the string in the tag box and select Apply.
If you are typing the text, the tag value appears in the box in the normal, forward direction. The GFLAGS utility reverses the string and enters the correct numeric value. By selecting Text and typing XyzA, you store PoolTag as 0x417a7958.
To use a numeric value, the digits that you type in the box are stored in the registry in exactly the same order. By selecting Hex and typing 12345678, you store 0x12345678 as the PoolTag data.
GFLAGS currently cannot set the PoolTagOverrruns value (that is, it cannot specify overrun or underrun), so the default setting of overrun detection will be enabled unless you manually add the PoolTagOverruns value to the registry as described earlier.
Pool Corruption Debugging Strategies
You might need to focus on a specific pool tag if it looks like the beginning or end of your allocation is corrupted. For a corruption at the beginning, you have to find the tag of the allocation before the corrupted one and focus on it. For a corruption at the end, you have to find the tag of the allocation after the corrupted one and focus on it. It might be difficult to find the correct tag for an overrun, because the corruption will likely invalidate the pool header that has control information.
If you are unsure of the corrupting component, but you are sure of the allocation size that is causing problems, you can set the PoolTag value in the registry to the size that corresponds to the size range that the corrupter might be using. If you do this, memory management will allocate these blocks in the special pool. Look at the header prior to the one you think is corrupted. That might be the one that is overwriting past the end of its allocation and corrupting your allocation. If the end of your pool allocation seems corrupted (possibly caused by the next allocation writing backward over your allocation), then you can set PoolTag to the size of the next block and also set PoolTagOverruns to zero to enable underrun detection.
Debugging Failures for Special Pool
If some kernel component writes beyond the limit of the block allocated, a memory fault occurs. The typical bug check is 0x50 (PAGE_FAULT_IN_NONPAGED_AREA) or 0xA (IRQL_NOT_LESS_OR_EQUAL) and the top of the stack should be similar to the following:
ntkrnlmp!RtlpBreakWithStatusInstruction
ntkrnlmp!KeBugCheckEx+[ASCII 133]
ntkrnlmp!MmAccessFault+[ASCII 133]
ntkrnlmp!KiTrap0E+[ASCII 133]
Module!Function ...
This indicates a high probability that the "Module" code accesses memory beyond what is allocated.
Conclusion
Use Kernel Special Pool to catch driver memory problems before you release your driver.
Use ExAllocatePoolWithTag to allocate memory, rather then ExAllocatePool. Choose useful, unique tag values.
Use the kernel debugger and become familiar with debugging driver problems.
REFERENCES
See the Windows NT DDK for additional driver and debugging information.
Keywords: kbBug kbDebug kbinfo KB192486
Technology: kbAudDeveloper kbOSWin2000 kbOSWinNT400 kbOSWinNTSearch kbOSWinSearch kbOSWinXP kbOSWinXPSearch kbwin2000DDK kbwin2000Search kbWinDDK kbWinDDKSearch kbWinNT400DDK kbWinNT400search kbWinNTsearch kbWinXPDDKSearch