Windows System Software -- Consulting, Training, Development -- Unique Expertise, Guaranteed Results
The free OSR Learning Library has more than 50 articles on a wide variety of topics about writing and debugging device drivers and Minifilters. From introductory level to advanced. All the articles have been recently reviewed and updated, and are written using the clear and definitive style you've come to expect from OSR over the years.
Check out The OSR Learning Library at: https://www.osr.com/osr-learning-library/
Hi all,
I have a behavoir which I do not understand why this happen.
I have the changed SysVad-Audio driver as a child device of my USB driver and I use a DeviceExtentione more less the same way like in the sample driver.
if I get a call into my PnpHandle IRP_MN_REMOVE_DEVICE I will delete the allocated memory in my DeviceExtention
case IRP_MN_QUERY_REMOVE_DEVICE: case IRP_MN_REMOVE_DEVICE: case IRP_MN_SURPRISE_REMOVAL: case IRP_MN_REMOVE_DEVICE: pExt = static_cast<MyInterFace*>(_DeviceObject->DeviceExtension); if (pExt->m_pCommonAdapter != NULL) { RemoveAllCaptureFilters(pExt->m_pCommonAdapter); RemoveAllRenderFilters(pExt->m_pCommonAdapter); pExt->m_pCommonAdapter->Cleanup(); pExt->m_pCommonAdapter->Release(); if (stack->MinorFunction == IRP_MN_REMOVE_DEVICE) { if (pExt->m_pCommonAdapter) { delete pExt->m_pCommonAdapter; pExt->m_pCommonAdapter = NULL; } } } break;
during unplug. Everything is fine and the code works.
If I do an uninstall of the driver the code above bugchecks right after a delte the pExt->m_pCommonAdapter and I pass it over into
ntStatus = PcDispatchIrp(_DeviceObject, _Irp);
with this:
PAGE_FAULT_IN_NONPAGED_AREA (50) Invalid system memory was referenced. This cannot be protected by try-except. Typically the address is just plain bad or it is pointing at freed memory. Arguments: Arg1: ffffd80755a7cf88, memory referenced. Arg2: 0000000000000000, value 0 = read operation, 1 = write operation. Arg3: fffff80422a3ce4f, If non-zero, the instruction address which referenced the bad memory address. Arg4: 0000000000000002, (reserved) Debugging Details: ------------------ KEY_VALUES_STRING: 1 STACKHASH_ANALYSIS: 1 TIMELINE_ANALYSIS: 1 DUMP_CLASS: 1 DUMP_QUALIFIER: 0 BUILD_VERSION_STRING: 19041.1.amd64fre.vb_release.191206-1406 DUMP_TYPE: 0 BUGCHECK_P1: ffffd80755a7cf88 BUGCHECK_P2: 0 BUGCHECK_P3: fffff80422a3ce4f BUGCHECK_P4: 2 READ_ADDRESS: Unable to get offset of nt!_MI_VISIBLE_STATE.SpecialPool Unable to get value of nt!_MI_VISIBLE_STATE.SessionSpecialPool ffffd80755a7cf88 Nonpaged pool FAULTING_IP: portcls!PnpStopDevice+223 fffff804`22a3ce4f 488b01 mov rax,qword ptr [rcx]
This will only happen if I enable verifier with the standard settings for my driver and just when I do a "uninstall" of the driver.
Not if I unplug the device.
Any idea what happen?
Thanks!
K_W
Upcoming OSR Seminars | ||
---|---|---|
OSR has suspended in-person seminars due to the Covid-19 outbreak. But, don't miss your training! Attend via the internet instead! | ||
Internals & Software Drivers | 19-23 June 2023 | Live, Online |
Writing WDF Drivers | 10-14 July 2023 | Live, Online |
Kernel Debugging | 16-20 October 2023 | Live, Online |
Developing Minifilters | 13-17 November 2023 | Live, Online |
Comments
Maybe the Callstack is intersting too:
Your code is handling IRP_MN_QUERY_REMOVE the same as stop, remove, and surprise remove, and that is wrong. Just pass the query down the stack and do nothing about it. You also have IRP_MN_REMOVE_DEVICE twice in your switch condition, that does no harm, but I would have thought that this produced at least a warning during compilation.
Also:
The query remove is going to call cleanup and release, and then stop is likely trying to use something cleanup and release deleted?
The original code in sysvad is this:
```
Note that cleanup and release are protected by a conditional expression that tests the state of m_pCommon, and that IRP_MN_QUERY_REMOVE is not in the switch condition, and that any of the request types in the condition go through the same path.
Hi Mark,
thanks a lot for your answer.
Well of course you are right. My call is not exactly the same. The second
IRP_MN_REMOVE_DEVICE
was a copy paste error. My original code is a bit messed up with comments and Dbg prints etc.
Let me start a bit more from beginning:
If I have the same sequence like you mentioned above, the memory of the m_pCommon will not get freed.
In this case this will happen:
So I decided to free the memory...
Why I check for IRP_MN_REMOVE_DEVICE to free it:
If I delete the m_pCommon in one of the earlier calls some other destructors will BugCheck because they still make use of the m_pCommon.
So that is why I have my conditional expression which will delete the allocated memory only in the last call, which is
IRP_MN_REMOVE_DEVICE
Now everything seems to work as expected until I try to Remove and Uninstall the driver.
In this case:
IRP_MN_SURPRISE_REMOVAL
norIRP_MN_STOP_DEVICE
will be called to start my clean up here.So I added
IRP_MN_QUERY_REMOVE_DEVICE
which will get called before
IRP_MN_REMOVE_DEVICE
But still, if I delete the memory in the last step, I will get this bug check from above after I pass the query down the stack.
So I do not understand why, because I actually nicely clean up everything I have used so far.
One issue I think of:
the PnPHandler is:
But the m_pCommon has the PoolType: NonPagedPool
Is this an issue!?
If so, my question would be, at which point I need to free the memory and where is this done in the original sample.
Probably I messed something here?
This is NOT the way things are done in an audio driver. The Port Class driver owns the DeviceExtension. It allocates the extension for you in PcAdapterDevice, and takes care of releasing it later. It ASSUMES that extension contains ITS data. You can't allocate your own. If you want a custom extension, you specify the size you want (as PORT_CLASS_DEVICE_EXTENSION_SIZE + sizeof(MY_DEVICE_EXTENSION)) as the last parameter to PcAddApterDevice. Then, you create a simple function to find your part of the extension when you need it:
Tim Roberts, [email protected]
Providenza & Boekelheide, Inc.
Thanks Tim,
it is actually already implemented like you mentioned.
I do not see a correct freeing of the memory if I give the responsibility to the Port Class driver.
One difference to the original sample code is my own extension. And I place the m_pCommon pointer into my own area.
So I do something wrong somewhere else I guess.
Is there any hint where and what I can double check?
Thanks!
What's the point of this? Is that your CAdapterCommon object? If so, that should be cleaned up for you. Port Class is handed an instance of that object as part of StartDevice, and it takes care of cleanup through the normal COM Release process. If not, then why isn't everything you need inside your device extension extension? You ought to be able to use one of the methods that are automatically cleaned up. Why add something else to screw up?
Tim Roberts, [email protected]
Providenza & Boekelheide, Inc.
Thanks again Tim,
It seems I have found the reason why the CAdapterCommon was not released proper from the Port Class.
I accidently increased the ref count at one place in my code and did to call release. So I guess the Port Class did not triggered the deletion of it.
Thanks for helping me with this!
Best regards
Good find. Every COM programmer has encountered this issue.
Tim Roberts, [email protected]
Providenza & Boekelheide, Inc.