【问题标题】:Why CreateProcess must not be called from a DllMain function?为什么不能从 DllMain 函数调用 CreateProcess?
【发布时间】:2014-11-05 09:50:36
【问题描述】:

我在几个来源中读到过,CreateProcess 不能从 DllMain 函数中调用。

CreateProcess :

不要从 DllMain 函数调用 CreateProcess。这会导致应用程序停止响应。

Dynamic-Link Library Best Practices:

您不应该在 DllMain 中执行以下任务: 调用 CreateProcess。创建一个进程可以加载另一个 DLL。

问题

这是为什么呢?它声明它导致应用程序停止响应,但这只是一个症状。真正的原因是什么?

我问的原因是我尝试从 DllMain 函数创建一个进程,它看起来工作得很好。

【问题讨论】:

  • 因为它可能会造成死锁,但它不是必须的——它不保证能正常工作。您的尝试成功,其他尝试失败/锁定。
  • 好的。但这是我无法控制的还是我可以以不可能出现死锁的方式进行编码?
  • 这完全不在您的控制范围内。即使您确保用于创建新进程的可执行映像没有任何需要解决的依赖关系,系统也可以配置为在您背后加载模块(AppInit_DLL、全局挂钩等)。注意警告,您对此无能为力。

标签: winapi createprocess dllmain


【解决方案1】:

DllMain 在保持加载程序锁定时执行。正如您引用的文档所解释的,CreateProcess 可能会导致加载 DLL。这可能导致加载程序锁死锁。发生死锁是因为加载程序锁已被持有。

文档很清楚。不要从DllMain 拨打CreateProcess。从DllMain 完成工作的标准方法是创建一个线程来完成工作。尽管您不能在该线程上等待,因为这会导致完全相同的死锁。

【讨论】:

  • 如果线程得到一个指向定义在DllMain作用域内的函数的指针,并且线程在DllMain退出后执行,会不会导致线程寻址到无效的内存地址?
  • 你为什么要那样做。不要那样做。
  • 如果 CreateThread 在DllMain 的范围内被调用,那么它必须获得一个指向该范围内函数的指针。我迷路了吗?
  • 没有。传递指向具有扩展范围的内存的指针。例如堆分配的内存。这对 DllMain 来说并不特殊。这就是将参数传递给线程的工作原理。
  • 嗯,如果返回 false 表示 DLL 已加载,然后继续工作,那将是一个明显的错误。尽管如此,我想你的问题现在已经得到了回答。
【解决方案2】:

MSDNsays:

因此,入口点函数可以调用 Kernel32.dll 中不加载其他 DLL 的函数。 [...] 不幸的是,Kernel32.dll 中没有安全函数的完整列表。

然后它扩展了声明,解释更复杂的 API(包括 CreateProcess)可能涉及 usafe API 调用:

调用需要 Kernel32.dll 以外的 DLL 的函数可能会导致难以诊断的问题。例如,调用 User、Shell 和 COM 函数可能会导致访问冲突错误,因为某些函数会加载其他系统组件。相反,在终止期间调用此类函数可能会导致访问冲突错误,因为相应的组件可能已经被卸载或未初始化。

这就是最佳实践建议不要调用 CreateProcess 的原因。 CreateProcess 是否会加载其他 DLL 是您无法控制的。在你的控制是避免不安全的 API 调用和稍后创建进程。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-04-19
    • 2021-04-23
    • 2014-09-21
    • 1970-01-01
    • 1970-01-01
    • 2019-09-10
    • 2017-12-25
    • 1970-01-01
    相关资源
    最近更新 更多