Recent

Author Topic: [SOLVED] Call to a C dll function used to work with old FPC  (Read 2205 times)

avra

  • Hero Member
  • *****
  • Posts: 2547
    • Additional info
[SOLVED] Call to a C dll function used to work with old FPC
« on: August 28, 2020, 10:32:10 am »
I have some very old code that could successfully call a function in C dll, and I have old executable that confirms that compiled application still works on my current system where dll is. However, that application doesn't work when the same project is compiled with FPC 3.2.1 and Lazarus 2.0.11. Well, it works if I do not use just one single function from that dll. Using that single function causes 'External: SIGSEGV' exception at address 655065E2. Both old and new IDE and DLL are 32bit, problem shows also without running code from IDE, clean up and build all did not help, switching off all optimization did not help, current testing OS is Win10x64, and all tested functions from dll wrapper work fine except that one. This is pascal wrapper for the problematic function:

Code: Pascal  [Select][+][-]
  1. function pilg_getconnectedserver(servernamebuf: pchar; var bufsize: longint; var NodeID: longint; var port: longint; seq: longint): longint; stdcall; external 'pilog32.dll';

and this is what it looks in C:
Code: C  [Select][+][-]
  1. EXPORTPIINT32 pilg_getconnectedserver
  2. (
  3.    char PIPTR* lpszServerNameBuf, // server name buffer
  4.    int32 PIPTR* plBufSize, // buffer size - in/out
  5.    int32 PIPTR* plNodeId, // node id
  6.    int32 PIPTR* plPort,   // port number
  7.    int32  lSeq  // sequence GETFIRST, GETNEXT
  8. );
with some more details here: https://techsupport.osisoft.com/Documentation/PI-SDK/PI-API/Functions/pilg_getconnectedserver.htm.

That function worked well when compiled with old FPC SVN 05-07-2013 Rev 25050 and Lazarus SVN 05-07-2013 Rev 42002. It also works well when compiled with even older IDE from 2010.

Since that single function is kind of important detail (there is no other way to get the list of connected servers), I will try to fix the problem since I have to revisit the project. I have some ideas which I do not like too much, so before digging deeper I am asking for your suggestions in a hope to hear something that could help me. All comments are welcome, and at this stage I am open to all ideas.
« Last Edit: August 28, 2020, 03:07:52 pm by avra »
ct2laz - Conversion between Lazarus and CodeTyphon
bithelpers - Bit manipulation for standard types
pasettimino - Siemens S7 PLC lib

440bx

  • Hero Member
  • *****
  • Posts: 5477
Re: Call to a C dll function used to work with old FPC
« Reply #1 on: August 28, 2020, 11:07:31 am »
To solve the problem you describe, I would compile the program that calls the DLL with a previous version of FPC (v3.0.4 for instance) and ask for an assembly listing.  I'd do the same with FPC v3.2.1 and compare the code that is generated by each compiler. 

If it works with one and not the other, there is probably a bug in the compiler and examining the assembly listing (dll function call) will likely indicate what the problem is.

Also, you could trace through the DLL function and find out the instruction that causes SIGSEV and why.  That would very helpful in figuring out what is causing the problem.

HTH.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v4.0rc3) on Windows 7 SP1 64bit.

Thaddy

  • Hero Member
  • *****
  • Posts: 17196
  • Ceterum censeo Trump esse delendam
Re: Call to a C dll function used to work with old FPC
« Reply #2 on: August 28, 2020, 11:07:47 am »
Are you sure it is stdcall? Because portable API's often default to cdecl on all platforms including Windows.
First thing I would do is test with cdecl. I can't find any macro for stdcall.

Another thing that comes to mind is that since 3.2.0 SEH is now default on WIN32, you can try and turn that off.

And the third thing that may influence the interfacing is that the default alignment on Windows has changed(was max 8, now 16).
« Last Edit: August 28, 2020, 11:17:06 am by Thaddy »
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

avra

  • Hero Member
  • *****
  • Posts: 2547
    • Additional info
Re: Call to a C dll function used to work with old FPC
« Reply #3 on: August 28, 2020, 03:07:17 pm »
Thank you all for your valuable input. It helped me to dig deeper. I have finally found the problem and fixed it.

This worked under 2.6.4 but not on newer FPC:
Code: Pascal  [Select][+][-]
  1. var
  2.   strServer: PChar;
  3.   strDummy: PChar = '                                                                                                    ' + #0;
  4.   lngNode, lngPort, lngBsize, lngError: longint;
  5. begin
  6.   lngDummy := 80;
  7.   strServer := strDummy;
  8.   lngError := pilg_getconnectedserver(strServer, lngDummy, lngNode, lngPort, GETFIRST);
  9. end;

It worked on 3.2.1 after this fix:
Code: Pascal  [Select][+][-]
  1. var
  2.   strServer: PChar;
  3.   strDummy: array[0..255] of char;
  4.   lngNode, lngPort, lngBsize, lngError: longint;
  5. begin
  6.   lngDummy := 80;
  7.   strServer := PChar(strDummy);
  8.   lngError := pilg_getconnectedserver(strServer, lngDummy, lngNode, lngPort, GETFIRST);
  9. end;
ct2laz - Conversion between Lazarus and CodeTyphon
bithelpers - Bit manipulation for standard types
pasettimino - Siemens S7 PLC lib

PascalDragon

  • Hero Member
  • *****
  • Posts: 6004
  • Compiler Developer
Re: Call to a C dll function used to work with old FPC
« Reply #4 on: August 28, 2020, 03:16:57 pm »
Thank you all for your valuable input. It helped me to dig deeper. I have finally found the problem and fixed it.

This worked under 2.6.4 but not on newer FPC:
Code: Pascal  [Select][+][-]
  1. var
  2.   strServer: PChar;
  3.   strDummy: PChar = '                                                                                                    ' + #0;
  4.   lngNode, lngPort, lngBsize, lngError: longint;
  5. begin
  6.   lngDummy := 80;
  7.   strServer := strDummy;
  8.   lngError := pilg_getconnectedserver(strServer, lngDummy, lngNode, lngPort, GETFIRST);
  9. end;

String constants are ReadOnly starting with 3.0.0. And according to the documentation the pilg_getconnectedserver functions expects allocated memory so that it can write the server name there. But if the memory that the PChar points to is readonly then this results in an access violation.

It worked on 3.2.1 after this fix:
Code: Pascal  [Select][+][-]
  1. var
  2.   strServer: PChar;
  3.   strDummy: array[0..255] of char;
  4.   lngNode, lngPort, lngBsize, lngError: longint;
  5. begin
  6.   lngDummy := 80;
  7.   strServer := PChar(strDummy);
  8.   lngError := pilg_getconnectedserver(strServer, lngDummy, lngNode, lngPort, GETFIRST);
  9. end;

You can also directly pass PChar(strDummy) instead of using strServer. Please note that lngDummy contains the available space of the string buffer, so if the server name should be larger than 80 you'll only get 80 characters despite the string having enough space left.

avra

  • Hero Member
  • *****
  • Posts: 2547
    • Additional info
Re: Call to a C dll function used to work with old FPC
« Reply #5 on: August 28, 2020, 03:38:33 pm »
String constants are ReadOnly starting with 3.0.0. And according to the documentation the pilg_getconnectedserver functions expects allocated memory so that it can write the server name there. But if the memory that the PChar points to is readonly then this results in an access violation.
Thank you. This explains nicely why code behaved as it did.

You can also directly pass PChar(strDummy) instead of using strServer.
Bits of code were taken from various places and strServer was used later in code, so at the end forum sample was not optimal. Thanks for pointing this out.

Please note that lngDummy contains the available space of the string buffer, so if the server name should be larger than 80 you'll only get 80 characters despite the string having enough space left.
Server name is netbios name and it has max length of 15. I was playing safe with 80.  :D
« Last Edit: August 28, 2020, 03:43:38 pm by avra »
ct2laz - Conversion between Lazarus and CodeTyphon
bithelpers - Bit manipulation for standard types
pasettimino - Siemens S7 PLC lib

 

TinyPortal © 2005-2018