-2

I faced very strange behavior: after some point in the code exceptions stop to work. This is my test function:

procedure vmDbg_TestExceptionsHandling(AMarker: string);
var
  i: integer;
begin
  i := UVmDll.DebugPoint(9002, PChar(AMarker)); // #define dbgpnt_HeapCheck  9002
  if i <> 1 then
    ToAppLogger(ll_ERROR, format('  %s->UVmDll.DebugPoint(9002)->heap integrity failure!', [AMarker]));

  //DBG:
  try
    // when Borland RTL space is somehow broken, it will crash here!
    raise Exception.Create('test exceptions#1 /' + AMarker);
  except
    on e: Exception do begin
      ToAppLogger(ll_ERROR, format('  %s->UVmDll.DebugPoint(99)->%s', [AMarker, ExcErrMsg(e)]));
    end;
  end;

  //DBG:
  try
    // inside ScriptVN.dll there is a special handling for point# 99 - it will throw a C++ exception
    UVmDll.DebugPoint(99, PChar(AMarker));
  except
    on e: Exception do begin
      ToAppLogger(ll_ERROR, format('  %s->UVmDll.DebugPoint(99)->%s', [AMarker, ExcErrMsg(e)]));
    end;
  end;

  //DBG:
  try
    // sometimes it may crash here...
    raise Exception.Create('test exceptions#2 /' + AMarker);
  except
    on e: Exception do begin
      ToAppLogger(ll_ERROR, format('  %s->UVmDll.DebugPoint(99)->%s', [AMarker, ExcErrMsg(e)]));
    end;
  end;
end;

And then use it in my code like this:

procedure vmDll_Jira790TestCase;
var
  n: integer;
  ixf: cpp_IInterface;
  rw, rwx, rwd: TRow;
begin
  isJira790Catch := true; 
  vmDbg_TestExceptionsHandling('Jira790TestCase.0'); //<-- here it works fine

  rwd := TRow.CreateDummy;
  vmDbg_TestExceptionsHandling('Jira790TestCase.1'); //<-- here it works fine

  rw := TRow.Create(true);
  vmDbg_TestExceptionsHandling('Jira790TestCase.2'); //<-- here it works fine

  ixf := UVmDll.DataTree__GetContainerInterface(rw.Engine);
  rwx := TRow.CreateForIxf(ixf); // <-- it crashes on leaving this constructor     
  vmDbg_TestExceptionsHandling('Jira790TestCase.3'); // <-- sometimes it crashes here
end;

The idea of this test function: just to raise exceptions as usual and confirm if try ... except works as expected.

So, the problem is: try ... except statements suddenly stop to work as expected. Instead of catching exceptions the application crashes with a message like this (when running in debugger):

---------------------------
Debugger Fault Notification
---------------------------
Project D:\testApp\testApp.exe faulted with message: 'application-defined exception 
(code 0x0eedfade) at 0x756456e8'. Process Stopped. Use Step or Run to continue.
---------------------------
OK   
---------------------------

When running normally (without debugger) it writes to Windows Events log messages like these:

Faulting application name: testApp.exe, version: 0.0.0.0, time stamp: 0x2a425e19
Faulting module name: KERNELBASE.dll, version: 6.3.9600.19724, time stamp: 0x5ec50c3e
Exception code: 0x0eedfade
Fault offset: 0x000156e8
Faulting process id: 0xb98
Faulting application start time: 0x01d89d1805403f55
Faulting application path: D:\testApp\testApp.exe
Faulting module path: C:\Windows\SYSTEM32\KERNELBASE.dll
Report Id: 43b9a57a-090b-11ed-8140-000c299851c5
Faulting package full name: 
Faulting package-relative application ID: 
  • I stepped through ASM code, validated a lot of stuff, confirmed that VMT of created objects are valid. But now I'm a bit stuck, because I'm not sure how exception handling is implemented in Borland Delphi 5 (or 7). Tried to use Google but it seems that nothing interesting on particular low-level details on how exceptions are implemented in Borland Delphi exists.

Could you please advise documentation materials on this topic? How can I manually track and check correctness of exception handling structures for Borland Delphi? What structures are created for exception handling, where exactly, and so on. I guess it should be somewhere on the stack, but I need a bit more details on it.

  • This is a single threaded simple UI application. Just one form with a button. No additional threads in the background. Also I have not found any problems with heap memory integrity, so that is not broken RAM.

  • Important: crashing only happens on Windows Server. So,

    • it works fine on Windows 7 and 10 (but pls note - on some editions of Windows 10 it also begin to crash, ex: on Win 10 2004 but on next edition - it no crash anymore)
    • but it crashes on Windows Server 2012, 2016, 2019.

    I tried to configure this app to run in different "compatibility modes" but that does not have any effect - it still crashes.

dmitry_bond
  • 378
  • 1
  • 3
  • 15
  • Can you make it a complete program to check for sure you isolated the problem? Nobody knows what `EVmDllTestException` really is - you could have at least written `type EVmDllTestException= Exception;` – AmigoJack Jul 21 '22 at 15:38
  • Ok. I replaced EVmDllTestException with Exception - nothing changed. And you were right - that is defined as type EVmDllTestException= Exception; – dmitry_bond Jul 21 '22 at 15:43
  • Test without the DLL, which seems to raise an exception. See [KernelBase.dll 0x0EEDFADE](https://stackoverflow.com/q/62267856/4299358) and [0x0eedfade in Delphi](https://stackoverflow.com/q/16602756/4299358) and [0x0eedfade in test](https://stackoverflow.com/q/40754343/4299358) and [0x0eedfade](https://stackoverflow.com/q/32073849/4299358) or [use the search](https://stackoverflow.com/search?q=%5Bdelphi%5D+0x0eedfade). – AmigoJack Jul 21 '22 at 20:04
  • 1
    Exceptions raised in a DLL must be handled inside the DLL, not outside in the calling app! – Delphi Coder Jul 21 '22 at 21:02
  • DLL dos and don’ts by Rudy Velthuis: http://rvelthuis.de/articles/articles-dlls.html – Delphi Coder Jul 21 '22 at 21:06
  • @DelphiCoder that is true for plain DLLs. For BPLs, throwing and handling exceptions across the DLL boundary is OK. – Remy Lebeau Jul 21 '22 at 22:56
  • Just FYI - exceptions from C++ DLL are perfectly catch by Delphi 5 and 7 - they are mapped to EExternalException exception class and can be handled normally. Also - this app was working fine on all client Windows OS'es - 2000, XP, Vista, 7, 8, 10... but then suddenly it begins to crash on all Windows Server OS'es - 2008, 2012, 2016, etc. So, this is very old application which was worked fine all these years. – dmitry_bond Jul 22 '22 at 06:31
  • Reminder: your question nowhere explicitly says that exceptions **do occur in a DLL** - the code makes it one possibility. You should write your own C++ DLL wrapping that DLL of interest and at the same time catching all exceptions. Just because it worked on client OSes doesn't make it valid/correct. – AmigoJack Jul 22 '22 at 06:47
  • Yes, correct. I do not tell "that exceptions do occur in a DLL". I tell - maybe something was broken in exceptions handling structures, so I'm trying to figure out - what that could be and fix it. So, I need some documentation on implementation details for exceptions handling in Delphi 5/7 - the rest I can do by myself. Also please note - there were no exceptions inside DLL! All DLL API calls finished with success. Problem is that exe-app no longer able to handle own exceptions normally. – dmitry_bond Jul 22 '22 at 06:57
  • FYI: In KernelBase.dll - it crash in RaiseException API function. So, function address = $756456A0, it crash at $756456E8, which means - it crash at KERNELBASE.RaiseException+$48 location (on mov ecx,[ebp+$54] asm command) – dmitry_bond Jul 22 '22 at 09:10

1 Answers1

0

As discovered there was wrong call-specification for 6 of 300 API functions in VM dll (only 1 of these API functions was frequently used). These functions were compiled with C++ default call-specification - cdecl (instead of stdcall as defined in application code). So, all this was because of broken stack. Seems that is only the reason why exception handlers fail to work as expected...

After I fixed and rebuild our VM dll - all things begin to work. At least I cannot find any crash issues anymore. All exceptions are catch and handled correctly now (both - exceptions inside C++ lib and exceptions in Delphi-compiled application exe).

The strange thing - 1st version of out VM lib was released at July 2003 and since that time this piece of code was not changed. So, all these years dll API function with wrong call-specification was working correctly on all client Windows OS'es. Seems there is some difference on how different Windows OS versions handling application stacks.

dmitry_bond
  • 378
  • 1
  • 3
  • 15