首页 > 其他分享 >Wdf框架之WdfObject状态机(2) 一文再补充

Wdf框架之WdfObject状态机(2) 一文再补充

时间:2022-11-07 19:02:44浏览次数:56  
标签:pHeader __ Wdf FxObject c1763a40 状态机 NULL WdfObject EvtCleanupCallback


    万万没想到<Wdf框架之WdfObject状态机(2) >的内容如此之多,2篇博客的篇幅还不够承载,需要第三篇来完成最后一击。本文将进入FxObject::DeleteWorkerAndUnlock的else分支,分析DrvDestroyCallback/DrvCleanupCallback的调用时机。

    进入else分支后,首先遇到的函数是FxObject::DisposeChildrenWorker函数,这个函数用来清空所有隶属于本FxObject的子对象,因为kmdfdrv驱动是个空驱动,不存在子对象,所以将跳过两个for循环,直接进入DisposeChildrenWorker尾部的CallCleanup()语句:

kd> kb ;中断在Unload函数,观察句柄drvObj对应的FxObject信息
ChildEBP RetAddr Args to Child
8afabba0 8ad7c2de 5997b8a8 c1763a40 c1763a40 KMDFdrv!Unload+0x4 [g:\kmdfdrv\kmdfdrv\kmdf.c @ 15]
...
8afabbe8 81ecac5f c1763a40 00000000 8f436040 nt!IopLoadUnloadDriver+0x87
kd> !wdfobject 0xa6684750
The type for object 0xa6684750 is FxDriver ;<-------drvObj对应的FxDriver对象的地址
State: FxObjectStateCreated (0x1)
!wdfhandle 0x5997b8a8
dt FxDriver 0xa6684750
...
kd> dt wdf01000!FxDriver 0xa6684750 -y m_ChildListHead ;m_ChildListHead是子对象列表,查看列表中的对象
+0x014 m_ChildListHead : _LIST_ENTRY [ 0xa6684764 - 0xa6684764 ] ;FLink和BLink都指向列表头,所以子对象列表是个空列表
BOOLEAN
FxObject::DisposeChildrenWorker(FxObjectState NewDeferedState,KIRQL OldIrql,BOOLEAN CanDefer)
{
...
if ((m_ObjectFlags & FXOBJECT_FLAGS_DISPOSE_OVERRIDE) == 0x00 || Dispose()) {
CallCleanup();
}
}

CallCleanup调用FxObject::CallCleanupCallbacks,并最终进入KMDFdrv!EvtCleanupCallback函数:

VOID FxObject::CallCleanupCallbacks(VOID)
{
FxContextHeader* pHeader;
WDFOBJECT h;

if (IsCommitted() == FALSE) {
return;
}

h = GetObjectHandle();

for (pHeader = GetContextHeader();
pHeader != NULL;
pHeader = pHeader->NextHeader) {
if (pHeader->EvtCleanupCallback != NULL) {
pHeader->EvtCleanupCallback(h);
pHeader->EvtCleanupCallback = NULL;
}
}

m_ObjectFlags &= ~FXOBJECT_FLAGS_HAS_CLEANUP;
}

FxObject::CallCleanupCallbacks的实现比较简单,因为EvtCleanupCallback存放在FxObject的扩展部分(!wdfobject扩展命令也是把EvtCleanupCallback和EvtDestroyCallback放在FxObject中一起显示),所以代码中首先获得FxObject扩展部分,并调用EvtCleanupCallback,最后把EvtCleanupCallback置空。(FxObject扩展的相关内容以后我会单独分析)。

    结合源码,可以发现,调用EvtCleanupCallback时,只有FxObject!m_ObjectState发生改变,至于引用计数,它还没有发生改变,保持进入Unload函数前的值。

kd> kb ;进入EvtCleanupCallback回调时的windbg输出
ChildEBP RetAddr Args to Child
8afabb70 8ad4b9c5 5997b8a8 a6684750 a6684764 KMDFdrv!DrvCleanupCallback [g:\kmdfdrv\kmdfdrv\kmdf.c @ 26]
8afabb84 8ad5119a b8b14bc8 a6684750 c1763a40 Wdf01000!FxObject::CallCleanupCallbacks+0x35 [minkernel\wdf\framework\shared\object\fxobject.cpp @ 354]
8afabba8 8ad7c310 c1763a40 8f436040 8afabbc4 Wdf01000!FxObject::DeleteObject+0x24dba [minkernel\wdf\framework\shared\object\fxobjectstatemachine.cpp @ 124]
8afabbb8 ab0b1324 c1f0c5a8 8afabbe8 820eedfd Wdf01000!FxDriver::Unload+0xa1 [minkernel\wdf\framework\shared\core\fxdriver.cpp @ 179]
8afabbc4 820eedfd c1f0c5a8 89e51540 8f436040 KMDFdrv!FxStubDriverUnload+0x1a [d:\th\minkernel\wdf\framework\kmdf\src\dynamic\stub\stub.cpp @ 159]
8afabbe8 81ecac5f c1763a40 00000000 8f436040 nt!IopLoadUnloadDriver+0x87
kd> ?? drvObj
void * 0x5997b8a8
kd> !wdfhandle 0x5997b8a8

Dumping WDFHANDLE 0x5997b8a8
=============================
Handle type is WDFDRIVER
Refcount: 1 ;<----引用计数值==1
Contexts:
context: dt 0xa6684830 DrvCtx (size is 0xc bytes)
EvtCleanupCallback ab0b10a0 KMDFdrv!DrvCleanupCallback
EvtDestroyCallback ab0b10c0 KMDFdrv!DrvDestroyCallback

!wdfobject 0xa6684750

    执行完DisposeChildrenWorker后,旋即进入FxObject::DeletedAndDisposedWorkerLocked函数:

VOID
FxObject::DeletedAndDisposedWorkerLocked(
__in __drv_when(Unlock, __drv_restoresIRQL) KIRQL OldIrql,
__in BOOLEAN Unlock
)
{
SetObjectStateLocked(FxObjectStateDeletedAndDisposed); //设置FxObject状态

if (Unlock) {
m_SpinLock.Release(OldIrql);
}
//对应这个空驱动,FxDriver没有子对象,所以就不跟进这个函数
DestroyChildren();
//敲黑板划重点
RELEASE(NULL);
}

RELEASE(NULL)是段宏,因为source insight中满是Release的引用,从茫茫人海中定位那个它,真的很困难:

//FxObject.hpp
#define RELEASE(_tag) Release(_tag, __LINE__, __FILE__)

virtual ULONG Release(PVOID Tag = NULL,LONG Line = 0,PCSTR File = NULL)
{
ULONG c;
c = InterlockedDecrement(&m_Refcnt);
if (c == 0) {
FinalRelease();
}
return c;
}

    执行RELEASE时,会减少引用计数,如果引用计数归零,则调用FinalRelease,由它调用EvtDestroyCallback函数。之后,FxDriver对象的内存被框架释放,不宜再被使用。

VOID FxObject::ProcessDestroy(VOID)
{
//...
for (pHeader = GetContextHeader();
pHeader != NULL;
pHeader = pHeader->NextHeader) {

if (pHeader->EvtCleanupCallback != NULL) {
pHeader->EvtCleanupCallback(h);
pHeader->EvtCleanupCallback = NULL;
}

if (pHeader->EvtDestroyCallback != NULL) {
pHeader->EvtDestroyCallback(h);
pHeader->EvtDestroyCallback = NULL;
}
}
...
//
SelfDestruct(); //SelfDestruct是delete this的封装
}
kd> kb
ChildEBP RetAddr Args to Child
8afabb80 8ad51245 5997b8a8 b8b14bc8 a6684750 KMDFdrv!DrvDestroyCallback [g:\kmdfdrv\kmdfdrv\kmdf.c @ 20]
8afabba8 8ad7c310 c1763a40 8f436040 8afabbc4 Wdf01000!FxObject::DeleteObject+0x24e65 [minkernel\wdf\framework\shared\object\fxobjectstatemachine.cpp @ 124]
8afabbb8 ab0b1324 c1f0c5a8 8afabbe8 820eedfd Wdf01000!FxDriver::Unload+0xa1 [minkernel\wdf\framework\shared\core\fxdriver.cpp @ 179]
8afabbc4 820eedfd c1f0c5a8 89e51540 8f436040 KMDFdrv!FxStubDriverUnload+0x1a [d:\th\minkernel\wdf\framework\kmdf\src\dynamic\stub\stub.cpp @ 159]
8afabbe8 81ecac5f c1763a40 00000000 8f436040 nt!IopLoadUnloadDriver+0x87
kd> !wdfhandle 0x5997b8a8

Dumping WDFHANDLE 0x5997b8a8
=============================
Handle type is WDFDRIVER
Refcount: 0 ;引用计数值==0

!wdfobject 0xa6684750
kd> !wdfobject 0xa6684750
State: FxObjectStateDeletedAndDisposed (0xa) ;FxObject状态

在EvtDestroyCallback中,引用计数已经为0,这种情况下再减少引用计数会造成数据溢出,所以很多书在介绍EvtCleanupCallback时会提到减少FxObject引用计数,却从没见过有哪本书说在EvtDestroyCallback中减少引用计数。虽然两者都可以做一些资源释放相关的操作。

标签:pHeader,__,Wdf,FxObject,c1763a40,状态机,NULL,WdfObject,EvtCleanupCallback
From: https://blog.51cto.com/u_13927568/5830870

相关文章

  • 状态机
    1、定义我们先来给出状态机的基本定义。一句话:状态机是有限状态自动机的简称,是现实事物运行规则抽象而成的一个数学模型。先来解释什么是“状态”(State)。现实事物是有......
  • 游戏开发中的状态机模式原理与应用
    该文章总结自人民邮电出版社《游戏编程模式》一书0、开篇状态机,全称有限状态机,其灵感来源于图灵机。将一系列数据输入输入图灵机中,输出数据会随着图灵机内部开关状态改......
  • 状态机
    有限状态机常说的状态机是有限状态机FSM(FiniteStateMachine)。FSM指的是有有限个状态(一般是一个状态变量的值),这个机器同时能够从外部接收信号和信息输入,机器在接收到外部......
  • [答疑]识别员工身份的类图和状态机图
    Alan2021-6-2920:11在这个问题卡住了,@UMLChina潘加宇 和各位同学帮忙看下左耳东2下面写3a?Alan是2bJeff@Alan 如果是用例的话,我建议将2a和2b作为扩展条件来处理,写在主流......
  • QFramework v1.0 使用指南 工具篇:10. FSMKit 状态机
    QFramework内置了一个简易的状态机,基本使用如下:链式usingUnityEngine;namespaceQFramework.Example{publicclassIStateBasicUsageExample:MonoBehaviour......
  • PCIe物理层LTSSM状态机解析
    在PCIe链路可以正常工作之前,需要对PCIe链路进行链路训练,在这个过程中,就会用LTSSM状态机。LTSSM全称是LinkTrainingandStatusStateMachine。这个状态机在哪里呢?它就在P......
  • 开源状态机代码生成 StateSmith 支持C/C++
     StateSmithStateSmithisacrossplatform,free/opensourcetoolforgeneratingstatemachines.Thegeneratedcodeishumanreadable,haszerodependencies......
  • 状态机:给定规则下分类讨论——红黑树(+队列实验-银行模拟)
    状态机:分类讨论,为了递归与美观,把重复的去掉dueto二叉树不保证平衡,herecomesRed-Blacktree——每条路黑高相同,lmax<2lmin类似还有AVLT(1.44lgn,但维护代价大)红黑树......
  • [答疑]EA帮助里的登录状态机图
    七日晴2020-1-1311:26潘老师好,感觉现在做的app的登录功能很混乱,可以用但看代码里的逻辑没有条理,想用状态图画清楚登陆的逻辑,EA帮助里有登录例子,还有登录次数限制条件。您......
  • [答疑]添加新闻的状态机图很诡异
    ​​软件方法(下)分析和设计第8章连载[20210723更新]>>​​Regina(41***58)12:20:44Regina(41***58)12:21:00还有这个状态机图也很诡异呀能是这样吗PYE<pye***q.com>12:20......