Borland Delphi 5 and 7: exceptions stop to work

304 Views Asked by At

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.

1

There are 1 best solutions below

1
dmitry_bond On

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.