EXCEPTION_DIVIDED_BY_ZERO in volmgr.sys

Hi, I 'm writing some a disk class upper filter driver. Everything was working fine untill I added a routine (called by StartDevice) which converts a UNICODE string to ANSI string and perform a string comparison. And now I’m getting BSOD with following message in the winDbg. I have no clue why this is happening in volmgr. I ran prefast but it did not show any problems. Help. Thanks.

BugCheck 7F, {0, 0, 0, 0}

Probably caused by : volmgr.sys ( volmgr!VmReadWrite+1b7 )

Followup: MachineOwner

nt!RtlpBreakWithStatusInstruction:
818818d0 cc int 3
1: kd> !analyze -v
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************

UNEXPECTED_KERNEL_MODE_TRAP (7f)
This means a trap occurred in kernel mode, and it’s a trap of a kind
that the kernel isn’t allowed to have/catch (bound trap) or that
is always instant death (double fault). The first number in the
bugcheck params is the number of the trap (8 = double fault, etc)
Consult an Intel x86 family manual to learn more about what these
traps are. Here is a *portion* of those codes:
If kv shows a taskGate
use .tss on the part before the colon, then kv.
Else if kv shows a trapframe
use .trap on that value
Else
.trap on the appropriate frame will show where the trap was taken
(on x86, this will be the ebp that goes with the procedure KiTrap)
Endif
kb will then show the corrected stack.
Arguments:
Arg1: 00000000, EXCEPTION_DIVIDED_BY_ZERO
Arg2: 00000000
Arg3: 00000000
Arg4: 00000000

Debugging Details:

BUGCHECK_STR: 0x7f_0

TRAP_FRAME: 881d4670 – (.trap 0xffffffff881d4670)
.trap 0xffffffff881d4670
ErrCode = 00000000
eax=00000000 ebx=84ab18f8 ecx=00000000 edx=00000000 esi=846a5530 edi=00000000
eip=818821cb esp=881d46e4 ebp=881d4720 iopl=0 nv up ei pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00210246
nt!_alldiv+0x4b:
818821cb f7f1 div eax,ecx
.trap
Resetting default scope

DEFAULT_BUCKET_ID: VISTA_DRIVER_FAULT

PROCESS_NAME: System

CURRENT_IRQL: 1

LAST_CONTROL_TRANSFER: from 818d87f7 to 818818d0

STACK_TEXT:
881d41f4 818d87f7 00000003 881df904 00000000 nt!RtlpBreakWithStatusInstruction
881d4244 818d9264 00000003 818821cb 846a5530 nt!KiBugCheckDebugBreak+0x1c
881d45f0 818d8652 0000007f 00000000 00000000 nt!KeBugCheck2+0x5f4
881d4610 819bd157 0000007f 881dfd24 818821cb nt!KeBugCheck+0x14
881d4664 8188d808 881d4670 881d4720 818821cb nt!Ki386CheckDivideByZeroTrap+0x44
881d4664 818821cb 881d4670 881d4720 818821cb nt!KiTrap00+0x88
881d4720 81827f83 846a5530 83fd1e28 83fd1e28 nt!_alldiv+0x4b
881d4738 818b06e7 806266f5 00000000 00000000 nt!IofCallDriver+0x63
881d473c 806266f5 00000000 00000000 00000000 nt!IoCallDriverStackSafe+0x5
881d4760 81827f83 84ab1840 83fd1e28 00000000 volmgr!VmReadWrite+0x1b7
881d4778 818b06e7 877e3ac2 00000000 00000000 nt!IofCallDriver+0x63
881d477c 877e3ac2 00000000 00000000 83fd1f94 nt!IoCallDriverStackSafe+0x5
881d47ac 877e46e8 849ae758 83fd1e28 00000000 ecache!EcDeviceIoCallLowerDriver+0x1d6
881d4874 81827f83 849ae6a0 83fd1e28 83fd1f94 ecache!EcDispatchReadWrite+0xbe4
881d488c 818b06e7 87430390 00000000 00000000 nt!IofCallDriver+0x63
881d4890 87430390 00000000 00000000 83ff2008 nt!IoCallDriverStackSafe+0x5
881d48c4 8742388d 83fd1e28 849ae6a0 00000003 volsnap!VspSynchronousIo+0xba
881d4910 8744a5a1 84c230d8 83ff2008 00000000 volsnap!VspOnline+0x19d
881d493c 81827f83 83ff2198 83ff2008 00000000 volsnap!VolSnapDeviceControl+0x5b1
881d4954 8061b8a7 83688918 88040000 00000000 nt!IofCallDriver+0x63
881d497c 8062148f 84c23020 806173c0 881d4d00 mountmgr!SendOnlineNotification+0x73
881d4c54 80621585 83688910 881d4d38 00000000 mountmgr!MountMgrMountedDeviceArrival+0xa47
881d4c78 8199fee9 881d4cec 83688910 89a91b40 mountmgr!MountMgrMountedDeviceNotification+0x4b
881d4cb8 8199f65a 881d4cec 881d4ce8 00000000 nt!PnpNotifyDriverCallback+0xfe
881d4d18 819a9712 8833c2ac 881d4d38 818fde7c nt!PnpNotifyDeviceClassChange+0x147
881d4d44 81878fa0 847a8078 00000000 832922d8 nt!PnpDeviceEventWorker+0x1d0
881d4d7c 81a254e0 847a8078 881df680 00000000 nt!ExpWorkerThread+0xfd
881d4dc0 8189159e 81878ea3 00000001 00000000 nt!PspSystemThreadStartup+0x9d
00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16

STACK_COMMAND: kb

FOLLOWUP_IP:
volmgr!VmReadWrite+1b7
806266f5 eb1e jmp volmgr!VmReadWrite+0x1d7 (80626715)

SYMBOL_STACK_INDEX: 9

SYMBOL_NAME: volmgr!VmReadWrite+1b7

FOLLOWUP_NAME: MachineOwner

MODULE_NAME: volmgr

IMAGE_NAME: volmgr.sys

DEBUG_FLR_IMAGE_TIMESTAMP: 4549b1a0

FAILURE_BUCKET_ID: 0x7f_0_volmgr!VmReadWrite+1b7

BUCKET_ID: 0x7f_0_volmgr!VmReadWrite+1b7

The very first thing that gets into my mind is that, by doing your operation improperly, you just corrupt memory
that does not even belong to your driver, which results in exception when the owner (in this case it happens to be volmgr) tries to access it…

Anton Bassov

Thanks Anton for the pointer. Is there any tool that can help me in identifying the problematic code section?

xxxxx@yahoo.com wrote:

Thanks Anton for the pointer. Is there any tool that can help me in identifying the problematic code section?

Yes; show us the code that changed (plus or minus 20 lines or so).
Usually, another set of eyes is all it takes to find problems like this.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

> Is there any tool that can help me in identifying the problematic code section?

The only “tool” that can help you here is your head - examine the code carefully, and try to find out where is the bug. Unfortunately, debuggers can help you only with the most obvious errors. However, when it comes to really nasty bugs like memory corruption (so that no exceptions get raised at the time you actually do it) or deadlocks, debugger is of rather limited help. The only thing that may help you here is code review…

Anton Bassov

THe following is the new function GetDiskSignature that I added.

NTSTATUS GetDiskSignature (IN PDEVICE_OBJECT DeviceObject,
OUT PANSI_STRING DiskSignature)
{
NTSTATUS status = STATUS_SUCCESS;
IO_STATUS_BLOCK ioStatus;
KEVENT event;
PDEVICE_EXTENSION deviceExtension;
PIRP irp = NULL;
PATA_PASS_THROUGH_EX ataData;
PIDENTIFY_DEVICE_DATA identifyData;
ULONG size;
ANSI_STRING serialModelNumber;

PAGED_CODE ();

deviceExtension = DeviceObject->DeviceExtension;
size = sizeof (ATA_PASS_THROUGH_EX) + sizeof (IDENTIFY_DEVICE_DATA);
/* Allocate memory for ATA_PASS_THROUGH_EX and clear the contents
*/
ataData = (PATA_PASS_THROUGH_EX) ExAllocatePool (PagedPool, size);
if (NULL == ataData) {
status = STATUS_INSUFFICIENT_RESOURCES;
MyDbgPrint (DPFLTR_ERROR_LEVEL,
“GetDiskSignature: Fail to build AtaData\n”);
goto END;
}
RtlZeroMemory (ataData, size);
/* Fill in the IDENTIFY DEVICE query data
*/
ataData->Length = sizeof (ATA_PASS_THROUGH_EX);
ataData->DataBufferOffset = sizeof (ATA_PASS_THROUGH_EX);
ataData->DataTransferLength = sizeof (IDENTIFY_DEVICE_DATA);
ataData->AtaFlags = ATA_FLAGS_DATA_IN;
ataData->TimeOutValue = 2;
ataData->CurrentTaskFile[6] = 0xEC;

KeInitializeEvent (&event, NotificationEvent, FALSE);
/* Request for the IDENTIFY DEVICE data
*/
irp = IoBuildDeviceIoControlRequest (IOCTL_ATA_PASS_THROUGH,
deviceExtension->TargetDeviceObject,
(PVOID)ataData,
size,
(PVOID)ataData,
size,
FALSE,
&event,
&ioStatus);
if (NULL == irp) {
status = STATUS_INSUFFICIENT_RESOURCES;
DbgPrint (DPFLTR_ERROR_LEVEL,
“GetDiskSignature: Fail to get build Irp\n”);
goto END;
}
status = IoCallDriver (deviceExtension->TargetDeviceObject, irp);

if (STATUS_PENDING == status) {
KeWaitForSingleObject (&event, Executive, KernelMode, FALSE, NULL);
status = ioStatus.Status;
}
if (!NT_SUCCESS (status)) {
MyDbgPrint (DPFLTR_ERROR_LEVEL,
"GetDiskSignature: IoBuildDeviceIoControlRequest "
“failed with status = 0x%X\n”,
status);
goto END;
}
/* get the disk signature {serial # (20 bytes) and model # (40 bytes)}
*/
identifyData = (PIDENTIFY_DEVICE_DATA)((ULONG)ataData + sizeof (ATA_PASS_THROUGH_EX));
{
USHORT i, j;
PUCHAR buffer = ExAllocatePool (PagedPool, 61);

if (NULL == buffer) {
MyLogError (DeviceObject,
DEVICE_OBJECT_SIZE,
256,
STATUS_SUCCESS,
IO_ERR_INSUFFICIENT_RESOURCES);
MyDbgPrint (DPFLTR_ERROR_LEVEL,
“GetDiskSignature: ExAllocatePool failed to allocate buffer\n”);
status = STATUS_INSUFFICIENT_RESOURCES;
goto END;
}
for (i = 0; i < 20; i++) {
buffer[i] = identifyData->SerialNumber[i];
}
for (j = 0; j < 40; j++, i++) {
buffer[i] = identifyData->ModelNumber[j];
}
buffer[i] = ‘\0’;
MyDbgPrint (DPFLTR_INFO_LEVEL,
“GetDiskSignature: buffer = %s\n”,
buffer);

RtlInitAnsiString (DiskSignature, buffer);
}

END:
if (ataData != NULL) {
ExFreePool (ataData);
}
if (NT_SUCCESS (status)) {
MyDbgPrint (DPFLTR_INFO_LEVEL,
GetDiskSignature: Disk signature"
“(Serial # Model #) %s\n”,
DiskSignature->Buffer);
}
else if (DiskSignature->Buffer != NULL) {
ExFreePool (DiskSignature->Buffer);
}

return status;
}

VOID FromSomeOtherFunction ()
{

RtlInitAnsiString (&diskSignature, NULL);

if (NT_SUCCESS (GetDiskSignature (DeviceObject, &diskSignature)) &&
RtlEqualString (&TargetDiskSignature,
&diskSignature,
TRUE)) {
MyDbgPrint (“DPFLTR_INFO_LEVEL”, “Disk Found\n”);
}
}

In the caller, after RtlEqualString(), you placed a call to the macro like:

MyDbgPrint (“DPFLTR_INFO_LEVEL”, “Disk Found\n”);

According to your other lines, the DPFLTR_INFO_LEVEL should not be quoted:)

Regards,
Huang Le

You are truncating ataData to an ULONG. From your crash output you are
running on x64, there pointers are 8 bytes in size and ULONGs 4 bytes so
this is never going to work. Make that a one byte pointer type (char*) so
you will still have the pointer arithmentic done properly.

//Daniel

wrote in message news:xxxxx@ntdev…
> identifyData = (PIDENTIFY_DEVICE_DATA)((ULONG)ataData + sizeof
> (ATA_PASS_THROUGH_EX));

BTW may I suggest you compile with /w3 then that would have generated two
warning messages.

//Daniel

wrote in message news:xxxxx@ntdev…
> You are truncating ataData to an ULONG. From your crash output you are
> running on x64, there pointers are 8 bytes in size and ULONGs 4 bytes so
> this is never going to work. Make that a one byte pointer type (char*) so
> you will still have the pointer arithmentic done properly.
>
> //Daniel
>
>
> wrote in message news:xxxxx@ntdev…
>> identifyData = (PIDENTIFY_DEVICE_DATA)((ULONG)ataData + sizeof
>> (ATA_PASS_THROUGH_EX));
>
>

Thanks everybody for your suggestions. Tim and Anton were absolutely correct it requires a careful code review to find these kind of bugs. I reviewed my code once again (carefully) and I figured out the problem. I was dividing by a variable initialized to zero.

@Daniel: My code is running on x86. Thanks for the /w3 switch. I didn;t know about that.

The /W4 option is even better. Some of Microsoft’s headers won’t pass /W4
at least in the NDIS stack, but with careful use of pragmas you can handle
that easily. Don’t forget prefast too.

wrote in message news:xxxxx@ntdev…
> Thanks everybody for your suggestions. Tim and Anton were absolutely
> correct it requires a careful code review to find these kind of bugs. I
> reviewed my code once again (carefully) and I figured out the problem. I
> was dividing by a variable initialized to zero.
>
> @Daniel: My code is running on x86. Thanks for the /w3 switch. I didn;t
> know about that.
>

I build all my code with /W4


Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

“David Craig” wrote in message news:xxxxx@ntdev…
> The /W4 option is even better. Some of Microsoft’s headers won’t pass /W4
> at least in the NDIS stack, but with careful use of pragmas you can handle
> that easily. Don’t forget prefast too.
>
> wrote in message news:xxxxx@ntdev…
> > Thanks everybody for your suggestions. Tim and Anton were absolutely
> > correct it requires a careful code review to find these kind of bugs. I
> > reviewed my code once again (carefully) and I figured out the problem. I
> > was dividing by a variable initialized to zero.
> >
> > @Daniel: My code is running on x86. Thanks for the /w3 switch. I didn;t
> > know about that.
> >
>
>
>