从 D2006 移植到 XE5 后偶尔出现访问冲突,在 XP 兼容模式下不会发生

sda*_*rle 2 delphi access-violation windows-7 delphi-xe5

我们有一个在 Delphi 2006 中运行良好的大型应用程序。我们已将其移至 XE5,并且经常遇到零星的访问冲突。我们正在使用 VCL 表单和许多 DevExpress 和其他第三方组件。我们正在使用带有 Delphi XE Enterprise 版本 19.0.14356.6604 的 Windows 7 Professional。

在移植到 XE5 之后,我们在网上、这里和其他地方查看了有关 A/V 的帖子,但没有发现任何似乎与我们的问题相关的内容。

以下是我们对 A/V 的了解:

  • 它们通常出现在相同的地址:0x50059f27。有时它们发生在 0x5005eb86,通常是在另一个地址触发了 A/V 之后。
  • 它们发生在应用程序中的各种不同位置和操作中。
  • 它们不是 100% 可重复的。有时,项目的重建会消除一个触发因素,但随后其他因素会触发它。它们似乎在构建中保持相当一致的可重现性。
  • 它们通常与打开对话框或激活返回大量记录(1,000+)的查询有关。
  • D2006 版本(我们在 XP 机器或 XP 虚拟机上运行)不会发生这种情况。 - 当我们在 XP-SP3 兼容模式下运行 XE5 应用程序时,它们不会发生。
  • 如果我们在典型的 A/V 之后中断,则指针将在 System.pas 中的第 562 行,在下面的代码部分的{$IFDEF CPUX86}asm 部分procedure Move(const Source; var Dest; Count: NativeInt);中。线路是FILD QWORD PTR [EAX] {Last 8}

我们猜测这个问题与我们的应用程序如何处理 Windows 7 内存管理有关,但我们不知道如何找出哪里出错了。附加了一个示例调用堆栈。

任何人都可以建议我们如何继续解决此问题?是否有第三方调试工具可以提供帮助?我们是否可以使用 Delphi IDE 工具来尝试跟踪此问题?可能有用的文章?

非常感谢您的任何建议。

这是发生 A/V 的 System.pas 代码部分:

    @@LargeForwardMove: {4-Byte Aligned}
    PUSH    EDX
    FILD    QWORD PTR [EAX] {First 8}
    LEA     EAX, [EAX+ECX-8]
    LEA     ECX, [ECX+EDX-8]
    FILD    QWORD PTR [EAX] {Last 8}      // <- Debug break pointer will be here. 
    PUSH    ECX
    NEG     ECX
    AND     EDX, -8 {8-Byte Align Writes}
    LEA     ECX, [ECX+EDX+8]
    POP     EDX
Run Code Online (Sandbox Code Playgroud)

这是来自调用堆栈的示例:

vcl.Vcl.Buttons.TBitBtn.Click
vcl.Vcl.StdCtrls.TCustomButton.CNCommand(???)
vcl.Vcl.Controls.TControl.WndProc((48401, 3186, 724082, 0, 3186, 0, (), 3186, 11, (), 0, 0, ()))
vcl.Vcl.Controls.TWinControl.WndProc((48401, 3186, 724082, 0, 3186, 0, (), 3186, 11, (), 0, 0, ()))
vcl.Vcl.StdCtrls.TButtonControl.WndProc((48401, 3186, 724082, 0, 3186, 0, (), 3186, 11, (), 0, 0, ()))
vcl.Vcl.Controls.TControl.Perform(???,???,724082)
vcl.Vcl.Controls.DoControlMsg(???,(no value))
vcl.Vcl.Controls.TWinControl.WMCommand((273, (), 3186, 0, (), 724082, 0))
vcl.Vcl.Controls.TControl.WndProc((273, 3186, 724082, 0, 3186, 0, (), 3186, 11, (), 0, 0, ()))
vcl.Vcl.Controls.TWinControl.WndProc((273, 3186, 724082, 0, 3186, 0, (), 3186, 11, (), 0, 0, ()))
vcl.Vcl.Controls.TWinControl.MainWndProc(???)
rtl.System.Classes.StdWndProc(987008,273,3186,724082)
:772462fa ; C:\Windows\syswow64\USER32.dll
:77246d3a USER32.GetThreadDesktop + 0xd7
:77246de8 ; C:\Windows\syswow64\USER32.dll
:77246e44 ; C:\Windows\syswow64\USER32.dll
:77ad010a ntdll.KiUserCallbackDispatcher + 0x2e
:772496c5 USER32.SendMessageW + 0x4c
:75184601 ; C:\Windows\WinSxS\x86_microsoft.windows.common-controls_6595b64144ccf1df_6.0.7601.17514_none_41e6975e2bd6f2b2\comctl32.dll
:75184663 ; C:\Windows\WinSxS\x86_microsoft.windows.common-controls_6595b64144ccf1df_6.0.7601.17514_none_41e6975e2bd6f2b2\comctl32.dll
:751844ed ; C:\Windows\WinSxS\x86_microsoft.windows.common-controls_6595b64144ccf1df_6.0.7601.17514_none_41e6975e2bd6f2b2\comctl32.dll
:772462fa ; C:\Windows\syswow64\USER32.dll
:77246d3a USER32.GetThreadDesktop + 0xd7
:77250d27 USER32.GetClientRect + 0xc5
:77250d4d USER32.CallWindowProcW + 0x1b
vcl.Vcl.Controls.TWinControl.DefaultHandler(???)
:5046777f TWinControl.DefaultHandler + $EB
:5046766e TWinControl.WndProc + $5CA
:50487a69 TButtonControl.WndProc + $71
:501749c6 StdWndProc + $E
:772462fa ; C:\Windows\syswow64\USER32.dll
:77246d3a USER32.GetThreadDesktop + 0xd7
:772477c4 ; C:\Windows\syswow64\USER32.dll
:7724788a USER32.DispatchMessageW + 0xf
Run Code Online (Sandbox Code Playgroud)

Dav*_*nan 5

这看起来像是您程序中的一个简单错误。可能在释放后访问内存。或者缓冲区溢出。你需要做的是一些调试。您需要的工具是:

  1. 范围检查编译器选项已启用。这会发现大多数缓冲区溢出。
  2. FastMM 完整版,带有完整的调试设置。这应该查明诸如免费访问之类的错误。
  3. 疯了除外。这将在异常点提供堆栈跟踪。这很重要,因为它可以让您看到如何在代码中达到这一点。这反过来可以帮助您查看正在传递的数据,并且应该为您提供有关您做错了什么的线索。我知道你有一个堆栈跟踪,但它看起来不对。毕竟TBitBtn.ClickMove直接调用。

不要自欺欺人,因为您看不到 XP 上的错误,这意味着责任在于操作系统。或者您需要在不同版本的操作系统中以不同方式处理内存。许多应用程序编程错误在某些系统上是良性的,但在其他系统上却很明显。你的程序到处都被破坏的可能性很高,但你有时会侥幸逃脱。