[SOLVED] Help with debugging SIGSEGV when calling updated version of library lazarus / 62-General ---------------------------------------------------------------------- Gizmo · 2021-05-14 08:52 (Meant to post in General board,!not freepascal —> General, sorry) I struggle often with the correct placement of code, and I have a suspicion my latest problem relates to this. I am using a more updated library that I recently managed to compile as a new DLL and code that I wrote to use the library from about 5 years ago (when FPC was probably v2 or early v3). The function I am having a problem with is called the same in the DLL as it was 5 years ago, except there is now an additional error buffer in the function call. So I have updated the call structure in my code, accordingly. But, with the new DLL call, I get a seemingly undebuggable SIGSEGV error now, which, in my experience, usually means you are trying to access something that either does not exist (perhaps not created) or cannot be reached. The asembler window just show ??? everywhere Would one of you mind looking at this stripped down version of the code from my library call, and see if you can see why or where the error is forming? I haven't included all the code because it is enormous and I suspect I have something in the wrong place. But I've tried to make sure the bits that matter are included. Note, however, that this code structure is largely unchanged from when I used it with the DLL compiled from the same (older) library of 5 years ago, and the only thing that is new that I can see is the use of @err in fLibEWFCheckSig which was added because the new library states that the C syntax is no longer just the filename, but also an error buffer (2 parameters, not 1): .Ft int .Fn libewf_check_file_signature "const char *filename" "libewf_error_t **error" https://github.com/libyal/libewf/blob/57dfc1f510f08f34eb34452f6679c381 85be9472/manuals/libewf.3#L26 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 myunit {$MODE Delphi} interfaceuses...type  TLibEWFCheckSig        = function(filename : pansiChar; error:pointer) : integer; cdecl;...   TLibEWF = class(TObject)      private    fLibHandle          : TLibHandle;    fLibEWFCheckSig     : TLibEWFCheckSig;          public  constructor create();           function libewf_check_file_signature(const filename : ansistring ) : integer;...const...implementation...beginconstructor TLibEWF.create(); ...if fLibHandle<>nilhandle then    begin                   // _libewf_check_file_signature is from here : https://github.com/libyal/ libewf/blob/57dfc1f510f08f34eb34452f6679c38185be9472/manuals/libewf.3# L26      @fLibEWFCheckSig                   :=GetProcAddress(fLibHandle,'_libewf_check_file_signature');  // Debugger shows OK and loaded      // lots more loaded    end;end; function TLibEWF.libewf_open(const filename : ansistring;flag:byte=$1) : integer;     begin...    // Filename gets assigned to curFilename with some other codewhile FileExists(curFilename) do      begin        if libewf_check_file_signature(curFilename)=1 then  // Calls the check_file_signature function below          begin            filenames.Add(curFilename)          end        else break;        curFilename:=filenameRoot+'.E'+Format('%.2d',[filenames.Count+1]);    end;     ...end;function TLibEWF.libewf_check_file_signature(const filename : ansistring) : integer;  // Filename is showing correctly in debuggervar  err:pointer;begin  Result:=0;  err := nil;  if fLibHandle<>0 then  // Handle is showing as valid in debugger  begin  Result:=fLibEWFCheckSig(pansiChar(filename), @err);  //SIGSEGV raised here. Can't walk into it.   end;end;   I do wonder if the **error and my equivlanet FPC syntax of @err is correct? ** in C means "pointer to pointer" I think? So err : pointer declares "the pointer", and so "@err" means "pointer to the err pointer", which is equivalent of "**err" in C? ---------------------------------------------------------------------- MarkMLl · 2021-05-14 11:18 I'm not a Windows programmer and that documentation isn't very good for online reference, but is the function call expecting a pointer that it initialises to refer to an error message, or a pointer to a valid area of memory into which it copies an error message? I suggest that you give us the relevant function declaration. MarkMLl ---------------------------------------------------------------------- Gizmo · 2021-05-14 11:24 Thanks for taking a look Mark. I think this is the full function in original code https://github.com/libyal/libewf/blob/57dfc1f510f08f34eb34452f6679c381 85be9472/libewf/libewf_support.c#L134 ---------------------------------------------------------------------- MarkMLl · 2021-05-14 12:26 Code: C  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i /* Determines if a file is an EWF file (check for the EWF file signature) * Returns 1 if true, 0 if not or -1 on error */#if 0 || defined( HAVE_V2_API )LIBEWF_EXTERN int libewf_check_file_signature(                 const char *filename,                   libewf_error_t **error );#elseLIBEWF_EXTERN int libewf_check_file_signature(                 const char *filename );#endif  I think that should be a var libewf_error_t, I think there was a similar thread a couple of weeks ago. MarkMLl ---------------------------------------------------------------------- Gizmo · 2021-05-14 12:41 I will check that, but, I have solved it. It was the underscore declarations in the GetProcAddress statements. i.e. @fLibEWFCheckSig                   :=GetProcAddress(fLibHandle,'_libewf_check_file_signature');  should be @fLibEWFCheckSig                   :=GetProcAddress(fLibHandle,'libewf_check_file_signature');  !! I only realised after opening the DLL with DLL Explorer, and I noticed the function names had no underscore prefixing them. So when I changed them all, all of my library calls completed OK! How bizarre. I assume something must have changes when compiling using MSYS2 that it no longer puts _ before function names? Anyway, solved. Thanks all for looking ---------------------------------------------------------------------- MarkMLl · 2021-05-14 12:46 Presumably that means that you're loading the library dynamically rather than leaving the entire job to the OS. You should /really/ be checking that entry points resolve properly before trying to use them. MarkMLl ---------------------------------------------------------------------- Gizmo · 2021-05-14 12:51 Good point. So you're saying the way I have it now, it's only checking the function calls are "valid" when called? If so, then what do these assignments do in the constructor Create routine? : @SomeCall                   :=GetProcAddress(fLibHandle,'somefunction');  I thought that WAS saying "Using the library you've just loaded, get the address of somefunction and allocate it to SomeCall". I assume there is a better way to do it? If so, could you direct me so I can avoid these kinds of issues going forward? ---------------------------------------------------------------------- MarkMLl · 2021-05-14 13:47 https://www.freepascal.org/docs- html/current/rtl/system/getprocedureaddress.html "provides the same functionality as GetProcedureAddress" hence -> https://www.freepascal.org/docs- html/current/rtl/system/getprocedureaddress.html "If the symbol cannot be found or the handle is invalid, Nil is returned." For dynamic loads, you HAVE to check that yourself, hence e.g. 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 procedure TDynamicModule.LoadRoutine(var Routine: Pointer; const Name: string); (* Note that the name of the entry point is case-sensitive.           *) begin  if Routine = nil then  begin{$if defined(CPUX86_64) }    Assert(PtrUInt(@Routine) mod 8 = 0, 'Internal error: processor-specific stack misalignment for GetProcedureAddress(2) A');    Assert(PtrUInt(@Name) mod 8 = 0, 'Internal error: processor-specific stack misalignment for GetProcedureAddress(2) B');{$endif                 }    Routine := GetProcedureAddress(ModuleHandle, Trim(Name));    FLastError := GetLoadErrorStr;    if Routine = nil then      raise DynamicModuleException.Create(FLastError)  endend;  function TDynamicModule.LoadRoutine(const Name: string): Pointer; (* This is an overloaded addition to Martin's original code. It can     *)(* result in neater code but is much less efficient since can't check   *)(* whether it has already been called.                                  *) begin{$if defined(CPUX86_64) }  Assert(PtrUInt(@result) mod 8 = 0, 'Internal error: processor-specific stack misalignment for GetProcedureAddress(1) A');  Assert(PtrUInt(@Name) mod 8 = 0, 'Internal error: processor-specific stack misalignment for GetProcedureAddress(1) B');{$endif                 }  RESULT:= GetProcedureAddress(ModuleHandle, Trim(Name));  FLastError := GetLoadErrorStr;  if RESULT = nil then    raise DynamicModuleException.Create(FLastError)end;  I was given that in Delphi-1 days, it might originally have come out of NAG. There's an example of how I do it at https://github.com/MarkMLl/asound which is part of an ongoing project: basically, I have a methodology that allows me to put the declarations into a .inc file which can then be used either statically or dynamically, hence also https://forum.laz arus.freepascal.org/index.php/topic,53348.msg394506.html#msg394506 etc. MarkMLl ---------------------------------------------------------------------- Gizmo · 2021-05-20 15:01 Mark...I've not got round to looking at this more fully yet. But I will. Wanted to let you know I appreciate the details though and will get round to it.