delphi - TMonitor.Destroy 中的无效指针操作

标签 delphi delphi-2010 tmonitor

我目前正在致力于将现有的 Delphi 5 应用程序移植到 Delphi 2010。

它是一个加载到 Outlook 中的多线程 DLL(其中线程由 Outlook 生成)。当通过 Delphi 2010 进行编译时,每当我关闭表单时,我都会在 TMonitor.Destroy 中遇到“无效指针操作”...即 system.pas 中的操作。

由于这是一个现有的且有点复杂的应用程序,我有很多的方向需要研究,而delphi帮助甚至没有记录几乎没有记录这个特定的内容首先是 TMonitor 类(我将其追溯到一些带有附加信息的 Allen Bauer 帖子)...所以我想我首先会询问周围是否有人遇到过此问题或对可能导致此问题的原因有任何建议。 郑重声明:我没有在代码中明确使用 TMonitor 功能,我们在这里讨论的是 Delphi 5 代码的直接移植。

编辑问题发生时的调用堆栈:

System.TMonitor.Destroy
System.TObject.Free
Forms.TCustomForm.CMRelease(???)
Controls.TControl.WndProc(???)
Controls.TWinControl.WndProc((45089, 0, 0, 0, 0, 0, 0, 0, 0, 0))
Forms.TCustomForm.WndProc(???)
Controls.TWinControl.MainWndProc(???)
Classes.StdWndProc(15992630,45089,0,0)
Forms.TApplication.ProcessMessage(???)

最佳答案

指向每个对象的System.Monitor实例的指针存储在所有数据字段之后。如果向对象的最后一个字段写入太多数据,则可能会向监视器的地址写入虚假值,当对象的析构函数尝试销毁虚假监视器时,这很可能会导致崩溃。您可以在表单的 BeforeDestruction 方法中检查此地址是否为 nil,对于直接的 Delphi 5 端口,不应分配任何监视器。类似的东西

procedure TForm1.BeforeDestruction;
var
  MonitorPtr: PPMonitor;
begin
  MonitorPtr := PPMonitor(Integer(Self) + InstanceSize - hfFieldSize + hfMonitorOffset);
  Assert(MonitorPtr^ = nil);
  inherited;
end;

如果这是您原始代码中的问题,您应该能够通过使用 FastMM4 内存管理器并激活所有检查,在 Delphi 5 版本的 DLL 中检测到它。 OTOH 这也可能是由于 Unicode 构建中字符数据大小的增加造成的,在这种情况下,它只会在使用 Delphi 2009 或 2010 的 DLL 构建中体现出来。使用最新的 FastMM4 进行所有检查仍然是一个好主意。

编辑:

从堆栈跟踪来看,监视器确实已分配。为了找出为什么我会使用数据断点。我无法让它们与 Delphi 2009 一起工作,但您可以使用 WinDbg 轻松完成。

在表单的 OnCreate 处理程序中输入以下内容:

var
  MonitorPtr: PPMonitor;
begin
  MonitorPtr := PPMonitor(Integer(Self) + InstanceSize - hfFieldSize + hfMonitorOffset);
  MessageDlg(Format('MonitorPtr: %p', [pointer(MonitorPtr)]), mtInformation,
    [mbOK], 0);
  DebugBreak;
  // ...

现在加载 WinDbg 并打开并运行调用 DLL 的进程。创建表单后,消息框将显示监视器实例的地址。记下地址,然后单击“确定”。调试器将出现,并且您可以在对该指针的写访问上设置断点,如下所示:

ba w4 A32D00

A32D00 替换为消息框中的正确地址。继续执行,当监视器被分配时,调试器应该命中断点。使用各种调试器 View (模块、线程、堆栈),您可以获得有关写入该地址的代码的重要信息。

关于delphi - TMonitor.Destroy 中的无效指针操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2064315/

相关文章:

delphi - delphi中的记事本问题

delphi - 如何从包含 D2007 的异常 block 中使用 Halt(n) 返回错误代码?

mysql - Delphi中从SQL表接收数据

delphi - Delphi 和 C++ WinAPI 函数的地址在不应该不同的情况下不同

delphi - 从 OleVariant 获取 IStream

delphi - Delphi系统单元中的TMonitor有什么用?

delphi - 从 Delphi 应用程序将文本样式写入 DXF

delphi - 未修改数据类型上没有RTTI

multithreading - 在Delphi中,System.TMonitor.Pulse和TMonitor.PulseAll实际上做了什么

multithreading - TMonitor 同步/Application.ProcessMessages