Recent

Author Topic: [SOLVED] Help with debugging SIGSEGV when calling updated version of library  (Read 3059 times)

Gizmo

  • Hero Member
  • *****
  • Posts: 796
(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/57dfc1f510f08f34eb34452f6679c38185be9472/manuals/libewf.3#L26

Code: Pascal  [Select][+][-]
  1. myunit
  2. {$MODE Delphi}
  3. interface
  4. uses
  5. ...
  6. type
  7.   TLibEWFCheckSig        = function(filename : pansiChar; error:pointer) : integer; cdecl;
  8. ...
  9.   TLibEWF = class(TObject)    
  10.   private
  11.     fLibHandle          : TLibHandle;
  12.     fLibEWFCheckSig     : TLibEWFCheckSig;      
  13.  
  14.   public
  15.   constructor create();        
  16.   function libewf_check_file_signature(const filename : ansistring ) : integer;
  17. ...
  18. const
  19. ...
  20. implementation
  21. ...
  22. begin
  23. constructor TLibEWF.create();
  24. ...
  25. if fLibHandle<>nilhandle then
  26.     begin            
  27.       // _libewf_check_file_signature is from here : https://github.com/libyal/libewf/blob/57dfc1f510f08f34eb34452f6679c38185be9472/manuals/libewf.3#L26
  28.       @fLibEWFCheckSig                   :=GetProcAddress(fLibHandle,'_libewf_check_file_signature');  // Debugger shows OK and loaded
  29.       // lots more loaded
  30.     end;
  31. end;
  32.  
  33. function TLibEWF.libewf_open(const filename : ansistring;flag:byte=$1) : integer;    
  34. begin
  35. ...    
  36. // Filename gets assigned to curFilename with some other code
  37. while FileExists(curFilename) do
  38.       begin
  39.         if libewf_check_file_signature(curFilename)=1 then  // Calls the check_file_signature function below
  40.           begin
  41.             filenames.Add(curFilename)
  42.           end
  43.         else break;
  44.         curFilename:=filenameRoot+'.E'+Format('%.2d',[filenames.Count+1]);
  45.       end;    
  46. ...
  47. end;
  48. function TLibEWF.libewf_check_file_signature(const filename : ansistring) : integer;  // Filename is showing correctly in debugger
  49. var
  50.   err:pointer;
  51. begin
  52.   Result:=0;
  53.   err := nil;
  54.   if fLibHandle<>0 then  // Handle is showing as valid in debugger
  55.   begin
  56.     Result:=fLibEWFCheckSig(pansiChar(filename), @err);  //SIGSEGV raised here. Can't walk into it.
  57.   end;
  58. end;
  59.  


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?
« Last Edit: May 14, 2021, 02:41:56 pm by Gizmo »
Lazarus 2.0.12 and fpc 3.2.0 - Linux Mint 19 LTS, Windows 10 64 and Mac OSX Big Sur
Useful Page to remember : http://wiki.freepascal.org/Cross_compiling#From_Linux_x64_to_Linux_i386

MarkMLl

  • Hero Member
  • *****
  • Posts: 2712
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
Turbo Pascal v1 on CCP/M-86, multitasking with LAN and graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Gizmo

  • Hero Member
  • *****
  • Posts: 796
Thanks for taking a look Mark.

I think this is the full function in original code

https://github.com/libyal/libewf/blob/57dfc1f510f08f34eb34452f6679c38185be9472/libewf/libewf_support.c#L134
« Last Edit: May 14, 2021, 01:45:22 pm by Gizmo »
Lazarus 2.0.12 and fpc 3.2.0 - Linux Mint 19 LTS, Windows 10 64 and Mac OSX Big Sur
Useful Page to remember : http://wiki.freepascal.org/Cross_compiling#From_Linux_x64_to_Linux_i386

MarkMLl

  • Hero Member
  • *****
  • Posts: 2712
Code: C  [Select][+][-]
  1. /* Determines if a file is an EWF file (check for the EWF file signature)
  2.  * Returns 1 if true, 0 if not or -1 on error
  3.  */
  4. #if 0 || defined( HAVE_V2_API )
  5. LIBEWF_EXTERN int libewf_check_file_signature(
  6.                    const char *filename,
  7.                    libewf_error_t **error );
  8. #else
  9. LIBEWF_EXTERN int libewf_check_file_signature(
  10.                    const char *filename );
  11. #endif
  12.  

I think that should be a var libewf_error_t, I think there was a similar thread a couple of weeks ago.

MarkMLl
« Last Edit: May 14, 2021, 02:34:17 pm by MarkMLl »
Turbo Pascal v1 on CCP/M-86, multitasking with LAN and graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Gizmo

  • Hero Member
  • *****
  • Posts: 796
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
Lazarus 2.0.12 and fpc 3.2.0 - Linux Mint 19 LTS, Windows 10 64 and Mac OSX Big Sur
Useful Page to remember : http://wiki.freepascal.org/Cross_compiling#From_Linux_x64_to_Linux_i386

MarkMLl

  • Hero Member
  • *****
  • Posts: 2712
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
Turbo Pascal v1 on CCP/M-86, multitasking with LAN and graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Gizmo

  • Hero Member
  • *****
  • Posts: 796
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?
« Last Edit: May 14, 2021, 03:00:52 pm by Gizmo »
Lazarus 2.0.12 and fpc 3.2.0 - Linux Mint 19 LTS, Windows 10 64 and Mac OSX Big Sur
Useful Page to remember : http://wiki.freepascal.org/Cross_compiling#From_Linux_x64_to_Linux_i386

MarkMLl

  • Hero Member
  • *****
  • Posts: 2712
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][+][-]
  1. procedure TDynamicModule.LoadRoutine(var Routine: Pointer; const Name: string);
  2.  
  3. (* Note that the name of the entry point is case-sensitive.             *)
  4.  
  5. begin
  6.   if Routine = nil then
  7.   begin
  8. {$if defined(CPUX86_64) }
  9.     Assert(PtrUInt(@Routine) mod 8 = 0, 'Internal error: processor-specific stack misalignment for GetProcedureAddress(2) A');
  10.     Assert(PtrUInt(@Name) mod 8 = 0, 'Internal error: processor-specific stack misalignment for GetProcedureAddress(2) B');
  11. {$endif                 }
  12.     Routine := GetProcedureAddress(ModuleHandle, Trim(Name));
  13.     FLastError := GetLoadErrorStr;
  14.     if Routine = nil then
  15.       raise DynamicModuleException.Create(FLastError)
  16.   end
  17. end;
  18.  
  19.  
  20. function TDynamicModule.LoadRoutine(const Name: string): Pointer;
  21.  
  22. (* This is an overloaded addition to Martin's original code. It can     *)
  23. (* result in neater code but is much less efficient since can't check   *)
  24. (* whether it has already been called.                                  *)
  25.  
  26. begin
  27. {$if defined(CPUX86_64) }
  28.   Assert(PtrUInt(@result) mod 8 = 0, 'Internal error: processor-specific stack misalignment for GetProcedureAddress(1) A');
  29.   Assert(PtrUInt(@Name) mod 8 = 0, 'Internal error: processor-specific stack misalignment for GetProcedureAddress(1) B');
  30. {$endif                 }
  31.   RESULT:= GetProcedureAddress(ModuleHandle, Trim(Name));
  32.   FLastError := GetLoadErrorStr;
  33.   if RESULT = nil then
  34.     raise DynamicModuleException.Create(FLastError)
  35. end;
  36.  

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.lazarus.freepascal.org/index.php/topic,53348.msg394506.html#msg394506 etc.

MarkMLl
Turbo Pascal v1 on CCP/M-86, multitasking with LAN and graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Gizmo

  • Hero Member
  • *****
  • Posts: 796
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.
Lazarus 2.0.12 and fpc 3.2.0 - Linux Mint 19 LTS, Windows 10 64 and Mac OSX Big Sur
Useful Page to remember : http://wiki.freepascal.org/Cross_compiling#From_Linux_x64_to_Linux_i386

 

TinyPortal © 2005-2018