我在基于iokit的驱动程序中使用了一些全局变量,即在主类实例之外。然而,由于使用了未初始化的全局变量或试图释放两次,这会在驱动程序启动时导致一些意外的恐慌拆卸时的全局变量。
iokit驱动程序生命周期中全局变量的生命周期是什么?如果我在声明时设置了一个全局变量,
例如,如果我有来自类型lck_grp_t * my_lock_grp
的全局变量。。。
-
当我的iokit驱动程序到达
::start
方法时,我可以假设我的全局变量已经分配好并准备好设置吗?(my_lock_grp = lck_grp_alloc_init("my-locks", my_lock_grp_attr);
( -
当我尝试在iokit
::free
方法上发布全局变量时,我可以假设它仍然有效吗?(lck_grp_free(my_lock_grp)
( -
一般的问题是,与驱动程序实例本身相比,基于iokit的驱动程序中全局变量的生命周期是什么。
生存期肯定与kext的生存期相同。类上的IOKit init/start/stop/free函数将发生在kext start和stop函数之间(您可能没有显式的kext start&stop函数(,全局构造函数在kext启动函数之前运行,全局析构函数同样在kext停止函数之后运行。全局/静态变量的内存分配/释放由动态内核链接器在加载和卸载kext代码本身的同时完成。
我能想到三件事:
-
IOService
start()
和free()
函数不匹配-即使从未调用start()
,也会调用free()
。例如,如果你有一个probe()
函数,它被调用并返回nullptr
,那么start()
永远不会被调用,但free()
肯定会被调用,它试图释放一个从未分配过的锁组。类似地,如果init()
函数返回false,则start()
永远不会运行,但free()
会运行。free()
的等价物是成员函数的init()
族,因此在free()
中仅无条件销毁(无nullptr检查(在所有可能的init…
函数中无条件创建的内容。 -
start()
可以在不同的实例上被调用任意次数,因此,如果您总是在start()
中运行my_lock_grp = lck_grp_alloc_init()
,并且创建了2个实例,my_lock_grp
只会记住最后一个实例,因此如果您的类的两个实例都被释放,那么您最终会尝试两次释放一个锁组,而另一个则根本不释放。这显然是个坏消息。对于初始化/销毁真正的全局状态,我建议使用kext启动和停止函数或全局构造函数/析构函数。 -
否则,我怀疑您可能会遇到这样的情况:运行内核的其他部分在kext已经卸载的点之后仍然有一个悬空引用,例如,如果您创建了一个新的内核线程,而这个线程仍在运行,或者如果您没有注销注册的所有回调,或者回调已被注销,但不能保证已完成所有调用。(kauth听众因后一种情况而臭名昭著(
如果这些听起来都不是问题所在,我建议发布受影响的代码和恐慌日志,如果我们有一些硬数据,也许我们可以更好地了解问题。