On This Page简介驱动程序经常发生与内存访问和分配相关的错误。这种错误会导致内存破坏,并最终导致系统崩溃。最常见的错误包括: | • | 试图访问已经释放的内存 | | • | 试图访问所分配内存结束地址后面的内存(内存溢出) | | • | 试图访问所分配内存开始地址前面的内存(内存下溢 (underrun)) |
应该在发布之前为每个驱动程序测试这种错误,即使驱动程序似乎能正常工作。内存错误导致的崩溃可能在驱动程序访问无效位置很长时间之后发生。破坏的内存会导致与错误驱动程序完全无关的进程发生错误和崩溃。 这里阐述的工具和技巧可以帮助您发现使用其他工具未检测到的问题。 分配内存时使用标记使用 ExAllocatePoolWithTag、ExAllocatePoolWithQuotaTag 和 ExAllocatePoolWithTagPriority 在驱动程序中分配内存。这些例程允许您为每次内存分配指定一个 1 到 4 个字符的标记(内存池标记)。确保您使用了唯一的标记,以将您的驱动程序与系统中所有其它驱动程序区分开来。如果您的驱动程序很大,那么可以考虑为每种内存分配类指定不同的标记。较小的驱动程序常常仅为所有分配使用一个标记。 Driver Verifier、GFlags、PoolMon 和 PoolTag 在跟踪内存池分配过程中使用这些标记。此外,调试器会显示标记和缓冲区的内容。 将驱动程序与 Call Usage Verifier (CUV) 链接Call Usage Verifier(CUV)提供一些与 Driver Verifier 相同的功能。它还检查那些操作自旋锁、链表(包括后备链表)和 IRP 栈位置的系统例程调用,以确保: | • | 驱动程序数据结构位于未分页的内存中(如有需要)。 | | • | 数据结构被正确初始化。 | | • | 数据结构被一致地使用。 |
CUV 是一个与内核模式 Windows Driver Model (WDM) 驱动程序链接的静态库。要使用 CUV 构建驱动程序: | • | 请确保 sources 文件将 TARGETTYPE 构建宏设置为等于 DRIVER 并且未使用 DRIVERTYPE 宏。 | | • | 在驱动程序开发工具包 (DDK) 构建环境中设置 VERIFIER_DDK_EXTENSIONS=1。 |
要在测试中使用 CUV,请在运行驱动程序时附加上调试器。CUV 需要使用调试器报告错误。 CUV 仅在 Windows XP 和以后的 DDK 中提供。使用 CUV 构建的驱动程序只能在 Windows XP 和更高版本上运行。避免使用 CUV 构建零售版驱动程序;它会极大地降低驱动程序的运行速度。 使用 Driver Verifier查找与内存使用相关的问题的最佳方法是将 Driver Verifier 与 CUV 一起运行。Driver Verifier 有 4 个选项可用来检测这种问题: | • | 特殊内存池 | | • | 内存池跟踪 | | • | DMA 检查 | | • | 资源不足模拟 |
当您为驱动程序启用特殊内存池选项时,Windows 会尝试从特殊内存池来满足所有驱动程序的内存分配请求。根据测试系统上存在的物理内存量,特殊内存池的大小有所限制。当特殊内存池用光后,Windows 从常规内存池分配内存。 当您启用内存池跟踪选项时,Driver Verifier 将: | • | 监视驱动程序所作的内存分配。 | | • | 检查驱动程序是否释放了它分配的所有内存。 | | • | 检查写到驱动程序所分配内存之外的内存的尝试。 |
您应该使用特殊内存池和内存池跟踪选项来测试每个驱动程序。但是,内存池跟踪不用于图形驱动程序。 直接内存访问 (Direct Memory Access, DMA) 检查在 Windows XP 和更高版本的 Windows 中提供。当启用这个选项时,Driver Verifier 检查与 DMA 相关的各种错误,例如缓冲区溢出、缓存分配错误和地址映射错误。应该在每个直接使用 DMA 的驱动程序和所有微型端口驱动程序(这类驱动程序通过调用使用 DMA 的端口驱动程序来间接使用 DMA)上使用这个选项。与内存池跟踪类似,DMA 检查不用于图形驱动程序。 如果驱动程序在任何特殊内存池、内存池跟踪和 DMA 检查中失败,Driver Verifier 都产生一个错误检查 (bug check)。 Driver Verifier 还可以模拟资源不足,从而帮助您检测在驱动程序无法分配其请求的所有内存时可能发生的错误。当启用这个选项时,Driver Verifier 会导致内存分配请求随机失败,大约在系统启动后 7 分钟开始。 在 Windows XP 和更高版本的 Windows 中,特殊内存池、内存池跟踪和 DMA 验证选项都是 Driver Verifier 的标准选项的一部分。也即,如果您从命令行使用 /standard 参数启动 Driver Verifier 或者在第一个 Driver Verifier Manager 对话框中选择“创建标准设置”,那么它们都会被启用。要启用资源不足模拟,您必须在对话框中选择“创建自定义设置”或在命令行上使用 /flags 0x4 参数。 设置全局标志全局标志实用工具 (GFlags.exe) 控制对内存使用问题测试有用的两项功能: 启用内存池标记选项时,Windows 收集数据并计算关于内存池内存分配的统计信息。可以使用 PoolMon 或 PoolTag 显示此数据。 内核特殊内存池标记选项控制 Driver Verifier 是否对从特殊内存池分配的内存执行溢出或下溢检测。此外,您可以使用这些选项来请求具有指定标记或大小范围的所有内存分配都从特殊内存池进行。 启用 GFlags 选项的最简单方法是从命令行启动 GFlags,然后使用如下所示的对话框: | • | 要启用内存池标记,请选择“启用内存池标记”。(在 Microsoft Windows Server 2003 上,这个选项被永久启用。) | | • | 要启用溢出检测,请在“内核特殊内存池标记”框中选择“验证结束地址”。 | | • | 要启用下溢检测,请在“内核特殊内存池标记”框中选择“验证开始地址”。 | | • | 要从内核特殊内存池中分配具有特定标记或大小的内存,请在文本框中输入标记或大小范围。(关于如何指定大小范围的详细信息,请参阅 Windows DDK。) |
只有在重新启动目标系统之后选项才会生效。 GFlags 和 Driver Verifier 在特殊内存池使用方面的功能有所重复。如果您同时使用两种工具来设置特殊内存池选项,那么 Windows 将为与指定内存池标记或大小匹配的任何分配请求或者来自所验证驱动程序的任何分配请求尝试使用特殊内存池。 如果您的驱动程序不分配大量内存,那么使用 Driver Verifier 从特殊内存池分配所有请求可能已经足够;可能无需根据特定标记或大小来设置分配。但是,如果您有一个需要请求大量内存的大型驱动程序,那么请考虑在驱动程序中使用多个内存池标记并使用 GFlags 每次激活一个。用这种方式限制从特殊内存池进行分配可以帮助您防止内存池耗尽,从而确保您测试了所有内存分配。 使用 PoolMon 和 PoolTag 监视带标记的内存分配PoolMon 和 PoolTag 显示与带标记的内存分配相关的数据。PoolMon 在命令窗口中运行,PoolTag 是该工具基于 GUI 的版本。 可以在驱动程序运行的同时(甚至与 Driver Verifier 一起运行)长时间运行 PoolMon 和 PoolTag 来显示与内存分配相关的数据。此数据可以帮助您发现内存泄漏。 如果您怀疑问题与特定的内存分配有关,那么可以使用这些工具来单独监视该分配。 注意: 在 Windows XP 和 Windows Server 2003 上,当驱动程序在 Driver Verifier 中以“特殊内存池”选项运行时,内存池标记不会跟踪从特殊内存池进行的分配。因此,这些分配不会显示在 PoolMon 和 PoolTag 数据中。 结合使用这些技巧测试可能的内存访问问题的最佳方法是结合使用这些技巧。例如: 1. | 使用 Call Usage Verifier (CUV) 构建驱动程序。 | 2. | 运行 GFlags 来启用内存池标记、选择溢出或下溢检测,并为从内核特殊内存池进行的内存分配指定标记(如有必要)。 | 3. | 在目标系统上为您的驱动程序启用 Driver Verifier。 | 4. | 重新启动目标系统。 | 5. | 在加载调试器的情况下运行驱动程序。要从 Driver Verifier 获得调试器内的信息,请使用 !verifier 命令(或者对于图形驱动程序,使用 !gdikdx.verifier 命令。) | 6. | 在目标计算机上启动 PoolMon 或 PoolTag,指定内存分配的类型(分页或不分页)和驱动程序指定的标记。 |
在 Windows XP 和 Windows Server 2003 上,您应该至少执行两个测试周期。在第一个周期中,执行前面列表中的步骤。在第二个周期中,在 Driver Verifier 中禁用特殊内存池选项,然后运行 PoolMon 或 PoolTag 来检查带标记的分配中的内存泄漏。 资源Microsoft 硬件和驱动程序开发人员信息 http://www.microsoft.com/whdc/default.mspx Microsoft Windows Driver Development Kit (DDK) http://www.microsoft.com/whdc/DevTools/ddk/default.mspx
|