【发布时间】:2017-12-24 12:51:58
【问题描述】:
我们遇到了一个案例,将FreeLibrary 调用放入DllMain / DLL_PROCESS_DETACH 是我们的最佳解决方案。
当然,你must not do that:
从 DllMain 调用 FreeLibrary 是不安全的。
用例是我们有这样的情况:
(unknown client dll or exe) links dynamically or statically to ->
-> DLL_1, loads dynamically -> DLL_x
DLL_1 应该以透明方式加载 DLL_x。到它的客户端代码,它应该动态加载 DLL_x。现在,可以延迟加载,这样LoadLibrary 调用就不必驻留在DLL_1 的DLL_PROCESS_ATTACH 部分。
但是一旦客户端完成了 DLL_1,当 DLL_1 从进程中卸载时/之前,它也应该卸载 (== FreeLibrary) DLL_x。
如果没有必须由客户端调用的显式 DLL_1/Uninitialize 函数,有什么方法可以做到这一点?
我会注意的:
-
DllMain,因此也不能使用任何 C++ 全局静态析构函数。 - 在 kernel32/ntdll 或共享的 MS CRT 中是否有任何其他回调机制来实现这一点?
- 还有其他模式可以使这个用例发挥作用吗?
【问题讨论】:
-
It is not safe to call FreeLibrary from DllMain- 需要了解为什么。仅因为这可能导致在系统执行其终止代码后使用 DLL。 - 如果您确切知道您和其他人不再使用此 DLL(在调用FreeLibrary之后),这是来自 DllMain 的安全和正常呼叫FreeLibrary -
@RbMm - 没有。它是不安全的,因为它被记录为不安全。加载器不支持它。我接受它在某些情况下可能会起作用,但在某些极端情况下它仍然可能会爆炸。 For example.
-
LoadLibrary的示例。这里的问题不在LoadLibrary调用中,而是在刚加载的DLL 的调用函数中。LoadLibrary不保证(当它在加载器路径中递归调用时)DLL 入口点将在LoadLibrary返回之前被调用。这是所有错误的根源 - 在初始化之前使用 DLL。但是FreeLibrary的情况不是对称的。直到最后一个FreeLibrary才会调用 DLL 取消初始化。如果您有已加载 DLL 的句柄 - 您有 100% 的保证在您自己调用FreeLibrary显式之前不会调用它的未初始化代码。 -
即使您从加载器路径 (
DllMain) 调用FreeLibrary,我们也可以确定DLL_X尚未(也不能)处于卸载过程中,因为它保留了您的参考。所以在调用FreeLibrary之前调用任何来自dll 的函数,因为这个dll 是安全的。而且我看不到即使从DllMain调用FreeLibrary也会导致问题。如果您能准确地举出这个例子 - 看起来会很有趣。 -
@RbMm - 我不怀疑它在实践中经常起作用。我将引用another answer: ""并不是加载器锁做任何事情来阻止 DllMain 调用 LoadLibrary,甚至加载器锁本身使这样的调用不安全。相反,通过保留加载程序锁,NTDLL 信任 DllMain 不会调用 LoadLibrary。""
标签: windows visual-c++ dll loadlibrary dllmain