【问题标题】:What exactly is the risk when using TerminateProcess?使用 TerminateProcess 的风险究竟是什么?
【发布时间】:2010-11-19 13:25:45
【问题描述】:

我的 Win32 控制台应用程序使用第三方库。退出 WinMain 后,全局对象开始销毁,并且 AV 发生在内部深处。我真的很想写

TerminateProcess( GetCurrentProcess(), 0 );

在 WinMain 结束附近的某个地方。如果我这样做,应用程序就会优雅地结束。

MSDN says 这样做会损害由动态链接库 (DLL) 维护的全局数据的状态,这一点尚不清楚。我知道,如果我有一些全局对象,它的析构函数不会运行,我可能不会完成数据库连接或类似的事情。我的程序中没有类似的东西。

使用 TerminateProcess 的风险究竟是什么?我如何确定是否可以将其用于我的目的?

【问题讨论】:

  • AV = 访问冲突,由于内存访问错误而崩溃
  • 该第三方库的性质是什么?
  • 该库进行光学字符识别。我猜它除了内存不会修改任何东西,但当然不能确定。

标签: windows winapi visual-c++ process


【解决方案1】:

根据相关文档和 ExtiProcess,似乎主要关注的是 DLL 的卸载没有使用标志 DLL_PROCESS_DETACH 调用 DllMain。

我的 2cents:文档是偏执的,你会扰乱在 DllMain + DLL_PROCESS_DETACH 中运行的一些关键操作。任何依赖它来维持关键状态的人都已经受到任务管理器的支配,所以我认为使用这个 API 没有巨大的风险。

【讨论】:

  • +1,但我会反过来说:使用 TerminateProcess() 与通过任务管理器杀死进程一样危险。
【解决方案2】:

通常情况下,与进程之外的对象交互时会发生不好的事情。例如,假设您有一些共享内存被多个进程使用,您的进程将写入这些共享内存,而其他进程将读取和/或写入这些内存。通常使用互斥锁来同步读取和写入。如果您的进程中的线程已获取互斥体,并且在调用 TerminatePorcess 时正在进行更改,则互斥体将被放弃,共享内存可能处于不一致状态。

我怀疑您错过了使用第三方库之一。 DllMain 有点限制,因此库可能具有您应该调用的初始化和取消初始化函数。

【讨论】:

  • 选择了一个很好的例子来说明可能导致问题的案例。在调试了这个问题之后,我发现问题在于库并不总是调用我们的回调函数,该函数会在卸载之前执行正确的取消初始化。在没有取消初始化的情况下,静态全局对象被销毁的顺序导致首先销毁带有对象池的堆,然后尝试释放这些对象。这导致了崩溃,因为对象指针已经指向释放的堆内存。
  • 由于我们的代码中有一个点在应用程序终止期间总是被调用,所以我只是添加了一个与该回调所做的等效的步骤。问题就解决了。
【解决方案3】:

AFAIK,如果您没有做任何“花哨”的事情(包括但不限于:创建线程、锁、数据库连接、使用 COM 对象),那么不会发生任何可怕的事情。但是作为Earwicker says,您不知道 DLL 在操作系统范围内做什么,而且您当然不知道将来是否会改变,因此依赖它是非常脆弱的.

您是否想知道为什么会发生这种访问冲突?这很可能是某些东西在更早之前就被破坏的迹象。请至少确认该错误是由这个 3rd-party 库引起的,例如通过编写一个与库链接但其main() 不执行任何操作的程序,并确认这会导致相同的崩溃。

【讨论】:

    【解决方案4】:

    这取决于您如何解释“全局数据”。如果你把它理解为(像我通常那样)存储在进程地址空间中的数据,那么这个建议毫无意义——我们知道内存会消失,所以谁在乎会发生什么?

    所以它可能指的是 DLL 可能已经完成的操作系统范围的东西,这些东西在任何进程的生命周期之外仍然存在。一个简单的例子是一个可能需要清理的临时文件;让进程崩溃太多次,你会耗尽磁盘空间,所以最好不要养成这样的习惯。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-10-28
      • 2012-08-27
      • 2010-11-12
      • 2011-03-18
      • 2011-01-22
      • 1970-01-01
      相关资源
      最近更新 更多