driver verifier检测驱动死锁

    最近,在写字符驱动练手,读写相关的派遣函数以异步StartIo方式处理IRP。测试时发现:当应用层发出了几次ReadFile请求后,驱动居然就无响应了。由于驱动是异步处理IO请求,因此,我猜测可能是驱动死锁了。本想借助windbg的!locks命令查看死锁,无奈,输出为空...绝望之余,想到可能可以用verifier工具检测驱动中潜在的死锁。

    命令行下有2种方式激活verifier.exe的死锁检测功能(方便起见,我选方式2):

我驱动的名字是SampleChar.sys
1.重启生效的方式:
verifier /flags 0x20 /driver SampleChar.sys
2.立刻生效的方式:
verifier /volatile /flags 0x20 /adddriver SampleChar.sys

注:/flags 0x20用于设置死锁检测项---verifier.exe的死锁检测选项位于 Bit 5 (0x20)
     激活这个选项后,并不能马上将潜在驱动中的死锁分析出来,而是需要借助测试程序来覆盖驱动中的代码。

    下面是verifier分析出存在潜在死锁的代码片,代码原意是:当应用层调用ReadFile时,驱动调用IoStartPacket函数将IRP插入设备队列,然后异步返回。后续操作由StartIo完成。

#pragma code_seg()
void SampleStartIo(PDEVICE_OBJECT devObj, PIRP irp)
{
	KEVENT workEvt, completeEvt;
	KIRQL origIrql;
	NTSTATUS status = STATUS_SUCCESS;
	unsigned long readLen;
	SampleCharDevContext* devCtx = (SampleCharDevContext*)devObj->DeviceExtension;
	IO_STACK_LOCATION* curStack = IoGetCurrentIrpStackLocation(irp);
	LARGE_INTEGER waitTime = RtlConvertLongToLargeInteger(-10*1000*1000*3);
	
	KeInitializeEvent(&workEvt,SynchronizationEvent,FALSE);
	KeInitializeEvent(&completeEvt, NotificationEvent, FALSE);
	
	KeWaitForSingleObject(&workEvt, Executive, KernelMode, FALSE, &waitTime);

	if (curStack->Parameters.Read.Length > 4096)
	{
		status = irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
		irp->IoStatus.Information = 0;

		IoCompleteRequest(irp, IO_NO_INCREMENT);
		IoStartNextPacket(devObj, FALSE);
		return;
	}

	KeAcquireSpinLock(&devCtx->devSpinLock, &origIrql);
	
	if(devCtx->buffPos != 0x00UL)
	{
		readLen = devCtx->buffPos >= curStack->Parameters.Read.Length ? curStack->Parameters.Read.Length : devCtx->buffPos;
		RtlCopyMemory(irp->AssociatedIrp.SystemBuffer,
			devCtx->SampleBuff,
			readLen);
		devCtx->buffRemained += readLen;
		devCtx->buffPos -= readLen;
	}
	else
	{
		KeReleaseSpinLock(&devCtx->devSpinLock, origIrql);
		
		irp->IoStatus.Status = STATUS_SUCCESS;
		irp->IoStatus.Information = 0x00UL;
		IoCompleteRequest(irp, IO_NO_INCREMENT);
		return;
	}

	KeReleaseSpinLock(&devCtx->devSpinLock, origIrql);

	IoCopyCurrentIrpStackLocationToNext(irp);
	IoSetCompletionRoutine(irp, IrpAsyncReadCompleteRoutine, &completeEvt, TRUE, TRUE, TRUE);
	
	status = IoCallDriver(devCtx->lowerDev,irp);
	if (status == STATUS_PENDING)
	{
		KeWaitForSingleObject(&completeEvt, Executive, KernelMode, FALSE, NULL);
	}
	
	irp->IoStatus.Status = STATUS_SUCCESS;
	irp->IoStatus.Information = readLen;
	IoCompleteRequest(irp, IO_NO_INCREMENT);

	IoStartNextPacket(devObj,FALSE);
}

NTSTATUS SampleCharReadAsync(PDEVICE_OBJECT devObj, PIRP irp)
{
	IoMarkIrpPending(irp);
	IoStartPacket(devObj,irp,NULL,NULL);
	return STATUS_PENDING;
}

    只要测试程序一运行,立马会触发0xC4的错误:

kd> g

*** Fatal System Error: 0x000000c4
                       (0x00000122,0x00000002,0xA2047BA8,0xA2047BC8)

Break instruction exception - code 80000003 (first chance)

A fatal system error has occurred.
Debugger entered on first try; Bugcheck callbacks have not been invoked.

A fatal system error has occurred.
通过Windbg !analyze -v命令可以得到错误的原因(这里仅截取重要的信息):

DRIVER_VERIFIER_DETECTED_VIOLATION (c4)  ----> C4是由driver verifer引发的错误

Arguments:
Arg1: 00000122, Waiting at DISPATCH_LEVEL, with a timeout different than zero. 参数1:0x122用于查看windbg help error code
Arg2: 00000002, IRQL value.
Arg3: a2047ba8, Object to wait on.
Arg4: a2047bc8, Address of the time out value.

FAULTING_SOURCE_CODE:  
   244: 	KeInitializeEvent(&completeEvt, NotificationEvent, FALSE);
   245: 	
   246: 	KeWaitForSingleObject(&workEvt, Executive, KernelMode, FALSE, &waitTime);
   247: 
>  248: 	if (curStack->Parameters.Read.Length > 4096) ---->定位到引起蓝屏的函数栈
   249: 	{
   250: 		status = irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
   251: 		irp->IoStatus.Information = 0;
   252: 
   253: 		IoCompleteRequest(irp, IO_NO_INCREMENT);
    windbg给出了这么多信息,其实已经够定位错误原因了。再参考windbg Help对错误号0x122给出的解释:

The thread waits at DISPATCH_LEVEL and Timeout value is not equal to zero (0). 
If the Timeout != 0, the callers of KeWaitForSingleObject or 
KeWaitForMultipleObjects must run at IRQL <= APC_LEVEL.
基本知道是在高IRQL级别上调用了等待相关的函数,就是这一句。
KeWaitForSingleObject(&workEvt, Executive, KernelMode, FALSE, &waitTime);

    我的代码参考了windows驱动开发详解第9章关于StartIo部分实现,其中用到定时器使得驱动在StartIo上等待一段时间然后再继续执行。开始时,我没有注意到StartIo调用时IRQL==DPC,不宜调用线程等待的函数(其实,不用driver verifier测试时,驱动运行的也还看得过去,至少没蓝屏)。去掉这段wait代码后再次编译加载,再用Driver verifier测试驱动死锁,倒是没有再次蓝屏的现象~

    虽然,还没有解决死锁问题,但意外解决了一个隐藏的错误,也挺不错~

最后附上相关的链接:

死锁检测

!deadlock

### 回答1: driver_verifier_dma_violation是一个Windows操作系统的错误代码,通常发生在设备驱动程序中存在DMA(直接内存访问)错误时。这可能是由于驱动程序中的错误代码或硬件故障引起的。为了解决这个问题,可以尝试更新或卸载驱动程序,或者检查硬件是否正常工作。如果问题仍然存在,建议联系技术支持或专业人员进行进一步的故障排除。 ### 回答2: Driver Verifier DMA Violation是Windows系统的一种蓝屏错误,其原因可能是驱动程序在处理直接内存存取(DMA)时发生了错误或难以管理。 DMA是一种用于在集成电路之间传输数据的技术,它可以比处理器更快地进行数据传输。然而,在操作系统中,驱动程序需要负责管理DMA过程。如果驱动程序出现问题,可能会导致数据传输错误或内存访问冲突。这就是Driver Verifier DMA Violation错误的可能原因之一。 在Windows系统中,可以使用驱动程序验证器(Driver Verifier)来检查驱动程序是否存在错误。如果出现DMA Violation错误,驱动程序验证器将停止该驱动程序并向用户显示错误信息。用户可以尝试更新驱动程序或卸载有问题的驱动程序来解决此错误。 另一种可能导致此错误的情况是硬件故障。由于DMA涉及直接内存存取,因此如果硬件存在问题,例如损坏的内存或I/O设备,也可能导致DMA Violation错误。用户可以尝试使用Windows系统自带的故障排除工具来检测硬件问题,或者联系厂商进行更进一步的检测和修复。 总之,如果您在使用Windows操作系统时遇到Driver Verifier DMA Violation错误,需要及时采取措施,例如更新驱动程序或诊断硬件问题。在处理此错误时,如果需要更多帮助和支持,请联系Windows技术支持团队。 ### 回答3: driver_verifier_dma_violation是Windows操作系统中的一个错误代码,通常是由于驱动程序的内存泄漏或错误使用Direct Memory Access(DMA)操作引起的。DMA是一种硬件技术,允许设备直接访问主板的内存,从而提高数据传输速度。当设备驱动程序使用DMA操作时,它需要遵循一些规则以确保正确的内存访问和释放,否则就会导致driver_verifier_dma_violation错误。 常见的导致DMA错误的原因包括: 1.驱动程序过时或不兼容。驱动程序应该是最新版本,并且与操作系统兼容。 2.设备驱动程序没有正确配置DMA操作。要执行DMA操作,必须正确配置DMA通道,并使用正确的缓冲区大小。 3.内存泄漏。如果驱动程序没有适当地释放内存,那么可以导致DMA错误。 如果发现driver_verifier_dma_violation错误,可以采取以下步骤: 1.更新驱动程序。确定驱动程序是否过时,如果是,则需要更新。 2.使用设备管理器检查设备。用设备管理器检查设备是否正常工作,是否有任何出错或警告信息。 3.检查系统日志。检查系统事件日志是否包含有关DMA错误的信息和详细信息。 4.运行系统文件检查器。使用系统文件检查器扫描系统文件是否有损坏或缺失。 5.检查硬件。检查硬件是否与操作系统兼容,是否需要维修或更换。 在进行这些步骤之后,如果driver_verifier_dma_violation错误仍然存在,则可能需要进行更深入的故障排除,或者寻求专业技术支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值