Exceptional lazarus / 12-Debugger ---------------------------------------------------------------------- christian1987 · 2015-11-04 15:58 When I raise an Exception from inside FreePascal DLL, the Delphi EXE just says: Stack Overflow. Is there a reason why? raise Exception.create('guava'); ---------------------------------------------------------------------- balazsszekely · 2015-11-04 17:39 It's not safe to raise exceptions across the DLL boundary because of  the different memory management. To be more precise, it is possible if you use a shared memory manager like: ShareMem, SimpleShareMem, etc... ---------------------------------------------------------------------- balazsszekely · 2015-11-04 18:54 What about raising exception with a callback function, cross platform way? 1 Library Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i library Test; {$mode objfpc}{$H+} uses  Classes,  SysUtils; type  PError = ^TError;  TError = record    FErrorCode: Integer;    FErrorMessage: String;    //you can add other fields here, even managed types  end;  TOnRaiseError = procedure(Error: PError); cdecl; var  OnRaiseError: TOnRaiseError = nil;  Error: PError; //this is the procedure where the exception is happeningprocedure Dummy;begin  try  //some unsafe codde  except    on E: Exception do    begin      Error^.FErrorCode := GetLastOSError;      Error^.FErrorMessage := E.Message;      if Assigned(OnRaiseError) then        OnRaiseError(Error);    end;  end;end; procedure InitRaiseError(AOnRaiseError: TOnRaiseError; AError: PError); cdecl;begin  OnRaiseError := AOnRaiseError;  Error := AError;end; exports  InitRaiseError; beginend.                   2. Application Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  //...implementation uses dynlibs,  LCLType; type  PError = ^TError;  TError = record    FErrorCode: Integer;    FErrorMessage: String;    //you can add other fields here, even managed types  end;   TOnRaiseError = procedure(Error: PError); cdecl; var  Error: PError;  LibHandle: TLibHandle = NilHandle; { TfMain } //this will display the actual error received from the dllprocedure CallbackRaiseError(Error: PError); cdecl;begin  ShowMessage('Error raised from the dll:' + sLineBreak +              'ErrorCode:    ' + IntToStr(Error^.FErrorCode) + sLineBreak +              'ErrorMessage: ' + Error^.FErrorMessage);end; procedure TfMain.FormCreate(Sender: TObject);type  TInitRaiseError = procedure(AOnRaiseError: TOnRaiseError; AError: PError); cdecl;var  LibName: string;  FarProc: TFarProc;  InitRaiseError: TInitRaiseError;begin  New(Error);  LibName := ExtractFilePath(ParamStr(0)) + 'Test.' + SharedSuffix;   LibHandle := LoadLibrary(LibName);  if LibHandle <> NilHandle then  begin    FarProc := GetProcedureAddress(LibHandle, 'InitRaiseError');    if FarProc <> nil then    begin      InitRaiseError := TInitRaiseError(FarProc);      InitRaiseError(@CallbackRaiseError, Error);    end;  end;end; procedure TfMain.FormDestroy(Sender: TObject);begin  Dispose(Error);  if LibHandle <> NilHandle then  begin    UnloadLibrary(LibHandle);    LibHandle := NilHandle;  end;end; end. ---------------------------------------------------------------------- z505 · 2017-05-12 09:18 Quote from: GetMem on November 04, 2015, 06:39:21 pmIt's not safe to raise exceptions across the DLL boundary because of  the different memory management. To be more precise, it is possible if you use a shared memory manager like: ShareMem, SimpleShareMem, etc... Or the cmem unit (c memory manager), but I'm not sure delphi and fpc's exception mechanisms are the same (compatible). It would be theoretically better if you had a fpc dll, and and fpc exe, if you were going to try this, not a delphi exe with an fpc dll, or vice versa. And as for the alternative solution: catch all the exceptions in the DLL itself (not the exe) and make the DLL return error codes, instead of throwing exceptions that the exe will catch. This is obnoxious and tedious, but seems to be the only safe solution for throwing exceptions in a dll. Simply catch them all and return an error code that the exe can deal with. Annoying, I know. Sorry, standard thread necromancer apology applies. ---------------------------------------------------------------------- Thaddy · 2017-05-12 09:27 Quote from: z505 on May 12, 2017, 11:18:20 amOr the cmem unit (c memory manager), but I'm not sure delphi and fpc's exception mechanisms are the same (compatible). For win64 they are. For win32 you may have to enable it: compile the compiler and the rtl with OPT=-dTEST_WIN32_SEH Still, raising exceptions inside a dll is a bit of nonsense unless you also handle them inside the dll. Better to return error codes. It also shows a thorough misunderstanding of how a library should be architected, but that's a different story. (Know of any C libraries that throw exceptions into main?, of course not! Unless the main programmer screwed up) ---------------------------------------------------------------------- Thaddy · 2017-05-12 10:34 Quote from: GetMem on November 04, 2015, 07:54:04 pmWhat about raising exception with a callback function, cross platform way? The exception frames would get lost, defeating the use of structured exception handling. Unless all frames trigger an individual callback. (E.g. something like the heaptrc behavior on Lazarus/windows looks similar) On the plus side: it has good communication under most but not all circumstances. I wonder if such a system would be stable. using SEH on win32 just about helps very little. Bottom line: handle the exception inside the dll and return an error code if you can't recover. Exception to the exceptions: COM will allow - almost - all exceptions to propagate to the main program apart from hardware failure and out- of -memory and provided a com memory manager is used besides SEH.. ---------------------------------------------------------------------- Thaddy · 2017-05-12 13:08 Also note z505 remarks about cmem is not correct. cmem is simply a basic heap memory manager w/o any optimizations. It does not help with exception handling in any way. A COM memory manager does that, because of COM marshaling. Therefor it is - very - slow as I found out during the memory manager shoot-out a couple of years ago. OTOH: it is the simplest replacement for sharemem under Windows. ---------------------------------------------------------------------- marcov · 2017-05-12 13:21 Quote from: Thaddy on May 12, 2017, 11:27:12 amQuote from: z505 on May 12, 2017, 11:18:20 amOr the cmem unit (c memory manager), but I'm not sure delphi and fpc's exception mechanisms are the same (compatible). For win64 they are. For win32 you may have to enable it: compile the compiler and the rtl with OPT=-dTEST_WIN32_SEH Still, raising exceptions inside a dll is a bit of nonsense unless you also handle them inside the dll. Better to return error codes. Note that while this allows one (e.g. Delphi) to clean up exceptions generated by the other (e.g. FPC), I'm not sure if allows one to read information stored in the exception by the other.