【问题标题】:Dlls crashing in Delphi 10.2 but only in debug modeDll 在 Delphi 10.2 中崩溃,但仅在调试模式下
【发布时间】:2017-10-07 05:58:56
【问题描述】:

我最近从 Delphi 2010 升级到 Delphi 10.2 Tokyo 许多第 3 方库已开始在调试模式下抛出异常,并且仅在调试模式下。 最常见的错误是 $C0000005 一般保护故障。 这些是我多年来一直使用的库,并且非常完善。

这些是第 3 方库,我无权访问源代码。

这包括 jvm.dll 和 msxml 之类的东西

有什么线索吗?解决方法?这些问题是一致且持久的,并且有问题的应用程序在未调试时运行得非常愉快。

在我见过的每种情况下,库都是动态链接的,而不是静态链接的。我怀疑这个问题与调试模式下的不同权限有关。

编辑:我跟踪了一个 DLL 调用,结果它试图写入 DLL 的本地内存 DATA 或 BSS。在 Delphi 2010 中,它非常愉快地允许这样做。在东京,它会抛出 $C0000005 错误。我假设这是最新的 Delphi 调试器的错误或设置问题。

编辑 2:我已经设法提取了一个最小的应用程序来重现该问题。 https://www.dropbox.com/s/uy8e9rw0qjxspie/testdll.zip?dl=0 下载包含一个最小的 32 位可执行文件 (testdll)。它静态链接到第 3 方 dll mirixafind.dll。这是一个旧的 dll,我无权访问源代码。 如果您单独运行 testdll 或不进行调试,点击“Mirixa”按钮会在屏幕上打印一些行并停止。 如果您运行 WITH 调试,它将因 $C0000005 错误而失败,试图将字符串写入似乎是 dll 的 DATA(或可能的 BSS)段的一部分的内存部分。 一位同事在单独的安装中复制了它。在 Delphi 2010 中不会发生这种情况。

编辑 3: 堆栈跟踪:

:757db78d user32.GetWindowTextA + 0x1d
:0068fbbf ; C:\Users\Robbie\Documents\Embarcadero\Studio\Projects\Win32\Debug\mirixafind.dll
:757e9275 ; C:\WINDOWS\SysWOW64\user32.dll
:757e757a user32.EnumWindows + 0x1a
:0068fca5 ; C:\Users\Robbie\Documents\Embarcadero\Studio\Projects\Win32\Debug\mirixafind.dll
:00691afa ; C:\Users\Robbie\Documents\Embarcadero\Studio\Projects\Win32\Debug\mirixafind.dll
:00690bcd ; C:\Users\Robbie\Documents\Embarcadero\Studio\Projects\Win32\Debug\mirixafind.dll
testdll1.TForm1.Button2Click($234B380)
Vcl.Controls.TControl.Click
Vcl.StdCtrls.TCustomButton.Click
Vcl.StdCtrls.TCustomButton.CNCommand(???)
Vcl.Controls.TControl.WndProc((48401, 3796, 1117908, 0, 3796, 0, (), 3796, 17, (), 0, 0, ()))
Vcl.Controls.TWinControl.WndProc((48401, 3796, 1117908, 0, 3796, 0, (), 3796, 17, (), 0, 0, ()))
Vcl.StdCtrls.TButtonControl.WndProc((48401, 3796, 1117908, 0, 3796, 0, (), 3796, 17, (), 0, 0, ()))
Vcl.Controls.TControl.Perform(???,???,1117908)
Vcl.Controls.DoControlMsg(???,(no value))
Vcl.Controls.TWinControl.WMCommand((273, (), 3796, 0, (), 1117908, 0))
Vcl.Controls.TControl.WndProc((273, 3796, 1117908, 0, 3796, 0, (), 3796, 17, (), 0, 0, ()))
Vcl.Controls.TWinControl.WndProc((273, 3796, 1117908, 0, 3796, 0, (), 3796, 17, (), 0, 0, ()))
Vcl.Controls.TWinControl.MainWndProc(???)
System.Classes.StdWndProc(1575384,273,3796,1117908)
:757ed2b3 user32.SetManipulationInputTarget + 0x53
:757ce88a ; C:\WINDOWS\SysWOW64\user32.dll
:757f764b ; C:\WINDOWS\SysWOW64\user32.dll
:757d0c00 ; C:\WINDOWS\SysWOW64\user32.dll
:6ccdd36f ; C:\WINDOWS\WinSxS\x86_microsoft.windows.common-controls_6595b64144ccf1df_6.0.14393.953_none_89c2555adb023171\comctl32.dll
:6cced065 ; C:\WINDOWS\WinSxS\x86_microsoft.windows.common-controls_6595b64144ccf1df_6.0.14393.953_none_89c2555adb023171\comctl32.dll
:757ed2b3 user32.SetManipulationInputTarget + 0x53
:757ce88a ; C:\WINDOWS\SysWOW64\user32.dll
:757cdf17 user32.CallWindowProcW + 0x97
Vcl.Controls.TWinControl.DefaultHandler(???)
:00521b5b TWinControl.DefaultHandler + $EB
:00521a4a TWinControl.WndProc + $5EE
:00536559 TButtonControl.WndProc + $71
:004c2b5a StdWndProc + $16
:757ed2b3 user32.SetManipulationInputTarget + 0x53
:757ce88a ; C:\WINDOWS\SysWOW64\user32.dll
:757ce1e4 ; C:\WINDOWS\SysWOW64\user32.dll
:757cdfa0 user32.DispatchMessageW + 0x10

First chance exception at $757DB78D. Exception class $C0000005 with message 'access violation at 0x757db78d: write of address 0x00974409'. Process testdll.exe (26036)

Module Load: MirixaFind.dll. No Debug Info. Base Address: $00970000. Process testdll.exe (26036)

dll 的 Tdump 提供以下信息:

Object table:
#   Name              VirtSize    RVA     PhysSize  Phys off  Flags   
--  --------          --------  --------  --------  --------  --------
01  CODE              00052714  00001000  00052800  00000400  60000020 [CER]
02  DATA              000013D8  00054000  00001400  00052C00  C0000040 [IRW]
03  BSS               00000B7D  00056000  00000000  00054000  C0000000 [RW]
04  .idata            00001F86  00057000  00002000  00054000  C0000040 [IRW]
05  .edata            0000139F  00059000  00001400  00056000  50000040 [IRS]
06  .reloc            0000588C  0005B000  00005A00  00057400  50000040 [IRS]
07  .rsrc             00004800  00061000  00004800  0005CE00  50000040 [IRS]

Key to section flags:
  C - contains code
  E - executable
  I - contains initialized data
  R - readable
  S - shareable
  W - writeable

据我所知,在这种情况下,0x00974409 应该是一个完全合法的地址。

【问题讨论】:

  • 有一些迹象表明堆栈正在变得混乱。
  • 事实并非如此。这绝对是一个写权限的事情。
  • 如果你在调试器中运行,你会有一个堆栈跟踪,不是吗?您能否将问题的堆栈跟踪提供给您控制的代码?
  • 提供了堆栈跟踪。

标签: delphi debugging exception delphi-10.2-tokyo


【解决方案1】:

错误 5 是拒绝访问。

这可能是尝试写入 null(或前 64k 数据中的任何位置),或者(如您所料)它正在调用一个没有正确安全设置的 Win32 API 函数。

我想您已经尝试在管理员帐户下运行您的应用程序,看看是否与此有关?

【讨论】:

  • 好主意,但是不...以管理员身份运行 Delphi 并没有什么不同。 (注意问题出现在调试模式)
【解决方案2】:

作为答案发布,以便代码格式正确。

因此,从堆栈跟踪看来,代码正在枚举所有窗口以获取窗口文本(可能是每个窗口的标题?)。很难理解,但是如果您可以在 0x0068fbbf 处转储程序集,您将看到传递给 GetWindowText 的参数。原型(下图)很难出错。

int WINAPI GetWindowText(_In_ HWND hWnd, _Out_ LPTSTR lpString, _In_ int nMaxCount);

我的猜测是 lpString 为空。

只需阅读 GetWindowText 上的文档:

复制指定窗口标题栏的文本(如果有的话) 进入缓冲区。如果指定的窗口是一个控件,则 控制被复制。 但是,GetWindowText 无法检索 另一个应用程序中的控件

我想知道您是否尝试在不属于您的应用程序上枚举 Windows?

【讨论】:

  • 我已经完成了所有这些。 lpString 的位置似乎是 dll 的数据(或 BSS,很难分辨)段的一部分。在 Delphi 2010 中,它是一个完全合法的地址并且工作正常。在东京,仍然应该是一个完全合法的地址,但它会引发 GP 错误。除非在调试器中运行,否则它不会抛出错误。
  • nMaxCount 呢?可能是仅在调试内存管理器中出现的缓冲区溢出。
【解决方案3】:

事实证明,我看到的是调试器捕获了一个正在 dll 中处理的异常。

Tools-->Options-->Debugger Optionss-->Embarcadero Debuggers-->Native OS Exceptions-->32-bit windows OS Exceptions-->Access Violation ($C0000005) 设置为“Handled by Debugger”

在 Delphi 的早期版本中,默认为“用户程序”(与所有其他本机操作系统异常一样)

它看起来比实际更糟,因为它发生在循环的中间,所以它不断被抛出......但如果我只是告诉 Delphi 忽略这个异常,它就会消失。 (总台)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-19
    • 1970-01-01
    • 1970-01-01
    • 2012-08-20
    • 2011-01-21
    • 2017-08-25
    • 1970-01-01
    相关资源
    最近更新 更多