Robbie Matthews
Robbie Matthews

Reputation: 1580

Dlls crashing in Delphi 10.2 but only in debug mode

I have recently upgraded from Delphi 2010 to Delphi 10.2 Tokyo A number of 3rd party libraries have started throwing exceptions in debug mode, and only in debug mode. The most common error is a $C0000005 general protection fault. These are libraries I have been using for years, and well established.

These are 3rd party libs, I do not have access to the source code.

This includes things like jvm.dll and msxml

Any clues? Workarounds? The issues are consistent and persistent, and the apps in question run quite cheerfully when NOT in debug.

In every case I've seen it happen the libraries are dynamically linked rather than statically. I have a suspicion the issue relates to different permissions when in debug mode.

Edit: I traced a DLL call, and it turns out it was trying to write to the DLLs local memory DATA or BSS. In Delphi 2010 it allows this quite cheerfully. In Tokyo it throws the $C0000005 error. I'm assuming this is a bug or setup issue with the latest Delphi debugger.

Edit 2: I have managed to pull out a minimal app to reproduce the issue. https://www.dropbox.com/s/uy8e9rw0qjxspie/testdll.zip?dl=0 The download contains a minimal 32 bit executable (testdll). It is statically linked to a 3rd party dll mirixafind.dll. It is an old dll and I don't have access to the source. If you run testdll standalone or without debugging, hitting the 'Mirixa' button prints some lines to the screen and stops. If you run WITH debugging it will fall over with a $C0000005 error, attempting to write a string to a section of memory that appears to be part of the dll's DATA (or possible BSS) segment. A colleague has duplicated it on a separate installation. It does not happen in Delphi 2010.

Edit 3: Stack trace:

: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)

Tdump of dll gives the following info:

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

As far as I can tell, in this case 0x00974409 should be an entirely legitimate address.

Upvotes: 2

Views: 2167

Answers (3)

Robbie Matthews
Robbie Matthews

Reputation: 1580

As it turns out, what I was seeing was the debugger catching an exception that was being handled in the dll.

Tools-->Options-->Debugger Optionss-->Embarcadero Debuggers-->Native OS Exceptions-->32-bit windows OS Exceptions-->Access Violation ($C0000005) was set to "Handled by Debugger"

In prior versions of Delphi this defaulted to "User Program" (as did all the other Native OS Exceptions)

It looked worse than it was, because it was occurring in the middle of a loop, so it kept being thrown continuously... but if I'd just told Delphi to ignore the exception it would have gone away. (Headdesk)

Upvotes: 3

Neil
Neil

Reputation: 11919

Posting as an answer so the code is formatted correctly.

So, from the stack trace it looks like the code is enumerating all the windows to get the window text (possibly the title of each window?). It's hard to fathom out, but if you could dump the assembly at 0x0068fbbf you will see the parameters being passed to GetWindowText. The prototype (below) is fairly hard to get wrong.

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

My guess would be lpString is null.

Just read the documentation on GetWindowText:

Copies the text of the specified window's title bar (if it has one) into a buffer. If the specified window is a control, the text of the control is copied. However, GetWindowText cannot retrieve the text of a control in another application.

I wonder if you are trying to enumerate Windows on an application this isn't yours?

Upvotes: 0

Neil
Neil

Reputation: 11919

Error 5 is access denied.

This could either be an attempt to write to null (or anywhere within the first 64k of data), or (as you surmise) it's calling a Win32 API function that it doesn't have the correct security settings.

I presume you have tried running your app under an administrator account, to see if it is related to that?

Upvotes: 0

Related Questions