Recent

Author Topic: cannot use a certain dll under freepascal, but works with delphi- cdecl problem?  (Read 822 times)

JernejL

  • Jr. Member
  • **
  • Posts: 64
i've compiled libsquish to a 32 bit dll a long time ago, the dll is rather simple and works well in delphi 7
 
It is a very simple and quality library, which compresses raw graphics to DXT compression and back.
 
however i get the same code and dll to crash under freepascal,
 
Quote
[Window Title]
Error

[Content]
Project TexWorkshop raised exception class 'External: ?'.

 At address 72D1117A

[OK]



Code: Pascal  [Select]
  1.  
  2. {
  3. http://code.google.com/p/libsquish/source/browse/trunk/squish.h
  4.  
  5. void CompressImage( u8 const* rgba, int width, int height, void* blocks, int flags, float* metric = 0 );
  6. void DecompressImage( u8* rgba, int width, int height, void const* blocks, int flags );
  7. int GetStorageRequirements( int width, int height, int flags );
  8. }
  9.  
  10. const
  11.  
  12.         //! Use DXT1 compression.
  13.         kDxt1 = 1 shl 0;
  14.         //! Use DXT3 compression.
  15.         kDxt3 = ( 1 shl 1 );
  16.         //! Use DXT5 compression.
  17.         kDxt5 = ( 1 shl 2 );
  18.         //! Use a very slow but very high quality colour compressor.
  19.         kColourIterativeClusterFit = ( 1 shl 8 );
  20.         //! Use a slow but high quality colour compressor (the default).
  21.         kColourClusterFit = ( 1 shl 3 );
  22.         //! Use a fast but low quality colour compressor.
  23.         kColourRangeFit = ( 1 shl 4 );
  24.         //! Use a perceptual metric for colour error (the default).
  25.         kColourMetricPerceptual = ( 1 shl 5 );
  26.         //! Use a uniform metric for colour error.
  27.         kColourMetricUniform = ( 1 shl 6 );
  28.         //! Weight the colour by alpha during cluster fit (disabled by default).
  29.         kWeightColourByAlpha = ( 1 shl 7 );
  30.  
  31. procedure CompressImage( rgba: Pu8; width, height: integer; blocks: pointer; flags: integer; metric: psingle ); cdecl; external 'libsquish.dll';
  32. procedure DecompressImage( rgba: pointer; width, height: integer; blocks: pointer; flags: integer ); cdecl; external 'libsquish.dll';
  33. function GetStorageRequirements( width, height, flags: integer): integer; cdecl; external 'libsquish.dll';
  34.  
  35.  

Whole call stack is following:
 
Code: Pascal  [Select]
  1. #0 ?? at :0
  2. #1 squish!CompressImage at :0
  3. #2 squish!CompressImage at :0
  4. #3 squish!DecompressImage at :0
  5. #4 squish!CompressImage at :0
  6. #5 COMPRESSDXTIMAGE(true, 3, 0x26c4b80, 0x26d67c0) at u_workshop.pas:1653
  7. #6 BTN_PROPERTIESCLICK(0x26ed678, 0x26efc08) at u_workshop.pas:1305
  8. #7 CONTROLS$_$TCONTROL_$__$$_DBLCLICK at :0
  9. #8 CONTROLS$_$TCONTROL_$__$$_WMLBUTTONDBLCLK$TLMMOUSE at :0
  10. #9 SYSTEM$_$TOBJECT_$__$$_DISPATCH$formal at :0
  11. #10 VMT_$CONTROLS_$$_TCONTROL at :0
  12. #11 ?? at :0
  13. #12 ?? at :0
  14. #13 ?? at :0
  15. #14 CONTROLS$_$TWINCONTROL_$__$$_WNDPROC$TMESSAGE at :0
  16. #15 LCLMESSAGEGLUE_$$_DELIVERMESSAGE$TOBJECT$formal$$LONGINT at :0
  17. #16 WIN32INT$_$TWINDOWPROCHELPER_$__$$_DOWINDOWPROC$$LONGINT at :0
  18. #17 WIN32INT_$$_WINDOWPROC$LONGWORD$LONGWORD$LONGINT$LONGINT$$LONGINT at :0
  19. #18 WIN32WSSTDCTRLS_$$_LISTBOXWINDOWPROC$LONGWORD$LONGWORD$LONGINT$LONGINT$$LONGINT at :0
  20. #19 USER32!AddClipboardFormatListener at :0
  21. #20 USER32!CallWindowProcW at :0
  22. #21 USER32!DispatchMessageW at :0
  23. #22 USER32!DispatchMessageW at :0
  24. #23 WIN32INT$_$TWIN32WIDGETSET_$__$$_APPPROCESSMESSAGES at :0
  25. #24 FORMS$_$TAPPLICATION_$__$$_HANDLEMESSAGE at :0
  26. #25 FORMS$_$TAPPLICATION_$__$$_RUNLOOP at :0
  27. #26 INTERFACEBASE$_$TWIDGETSET_$__$$_APPRUN$TAPPLICATIONMAINLOOP at :0
  28. #27 FORMS$_$TAPPLICATION_$__$$_RUN at :0
  29. #28 main at TexWorkshop.dpr:24
  30.  

There is not much to analyse, as the whole thing makes no sense - a c++ dll with cdecl calls should behave identically in both cases? Does anybody know what could cause this?
 

440bx

  • Hero Member
  • *****
  • Posts: 1199
I don't know if the following may be applicable to your case but, just in case, check the following thread https://forum.lazarus.freepascal.org/index.php?topic=6225.0
using FPC v3.0.4 and Lazarus 1.8.2 on Windows 7 64bit.

Thaddy

  • Hero Member
  • *****
  • Posts: 9183
Try 3.2.0 because it has structured exception handling as default for win32.
also related to equus asinus.

julkas

  • Sr. Member
  • ****
  • Posts: 412
  • KISS principle / Lazarus 2.0.0 / FPC 3.0.4
Give more info about OS, FPC / Lazarus. Attach library.
Are you using mode Delphi?
procedure mulu64(a, b: QWORD; out clo, chi: QWORD); assembler;
asm
  mov rax, a
  mov rdx, b
  mul rdx
  mov [clo], rax
  mov [chi], rdx
end;

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 7503
Try 3.2.0 because it has structured exception handling as default for win32.

Not yet. It needs a define to activate. But yes, this could be the cause.

JernejL

  • Jr. Member
  • **
  • Posts: 64
I've attached the dll, i use fpc 3.0.4 with lazarus 2.0.0 - compiled on windows for win32 api.
Regarding the debugger, crash happens also when ran without debugger.
 
The squish dll is simple - just point the source and dest to a large enough buffers, the input can be garbage too, for example call compress on random memory stream data (each pixel is 4 bytes), and have output same size buffer.
 
Here is an example call, with the dll i attached:
 
Code: Pascal  [Select]
  1.  
  2. procedure Twnd_workshop.btn1Click(Sender: TObject);
  3. const
  4.         iwidth = 128;
  5.         iheight = 128;
  6. var
  7.         inimage: Tmemorystream;
  8.         datastream: Tmemorystream;
  9.         gsr: integer;
  10. begin
  11.  
  12.  
  13.         inimage:= TMemoryStream.Create();
  14.         inimage.Size:= (iwidth * iheight) * 4;
  15.        
  16.         gsr:= GetStorageRequirements(iwidth, iheight, kDxt3 or kColourIterativeClusterFit);
  17.  
  18.         datastream:= TMemoryStream.Create(); // output stream
  19.         datastream.Size:= gsr;
  20.  
  21.         CompressImage(inimage.memory, iwidth, iheight, datastream.Memory, kDxt3 or kColourIterativeClusterFit, nil);
  22.        
  23. end;
  24.  
  25.  

This will work perfectly in delphi 7, but crash very strangely if compiled with freepascal.
 
« Last Edit: November 08, 2019, 08:54:15 am by JernejL »

Thaddy

  • Hero Member
  • *****
  • Posts: 9183
Can you test as per my suggestion and Marco's remark?
Otherwise I need full sources that replicate the issue.
also related to equus asinus.

JernejL

  • Jr. Member
  • **
  • Posts: 64
Can you test as per my suggestion and Marco's remark?
Otherwise I need full sources that replicate the issue.

 
You need only the dll i attached in zip file and the example code i posted - compile with win32 and it will crash on compress line.
 
Regarding SEH, it could be - i would need to custom compile the compile, can someone first check if SEH is the issue?
 
I don't think this is SEH fault tho - there is no exception at all under delphi.
 

julkas

  • Sr. Member
  • ****
  • Posts: 412
  • KISS principle / Lazarus 2.0.0 / FPC 3.0.4
Can you test as per my suggestion and Marco's remark?
Otherwise I need full sources that replicate the issue.

 
You need only the dll i attached in zip file and the example code i posted - compile with win32 and it will crash on compress line.
 
Regarding SEH, it could be - i would need to custom compile the compile, can someone first check if SEH is the issue?
 
I don't think this is SEH fault tho - there is no exception at all under delphi.

Try attached project. It works for me (Win8 64bit, FPC 3.0.4 / Lazarus 2.0.0) compiled for Win32.
procedure mulu64(a, b: QWORD; out clo, chi: QWORD); assembler;
asm
  mov rax, a
  mov rdx, b
  mul rdx
  mov [clo], rax
  mov [chi], rdx
end;

JernejL

  • Jr. Member
  • **
  • Posts: 64
I found something - i ran the tool in visual studio and got a better exception message:
 
Quote
Unhandled exception at 0x6D0C4815 (squish.dll) in TexWorkshop.exe: 0xC00002B5:  Multiple floating point traps (parameters: 0x00000000, 0x00001921).

I've added a call to Math.SetExceptionMask and exceptions disappeared.. i'm not aware that delphi 7 version of the app changed this in any way, but it happened somehow?! it's possible that i had something else included in some way that messed with this in delphi 7 version..
 
Oh well - at least i can say that libsquish works well in fpc and i've ported my last game tool to 100% lazarus + FPC development
 

Thaddy

  • Hero Member
  • *****
  • Posts: 9183

I don't think this is SEH fault tho - there is no exception at all under delphi.
Delphi doesn't know anything else, so that is why that is important.
And yes, specifically ms compilers mess with the float settings.(and are not in any way compliant to standards)
Glad it is now solved.
also related to equus asinus.

440bx

  • Hero Member
  • *****
  • Posts: 1199
i ran the tool in visual studio and got a better exception message:
It's nice to see that alternate way of debugging is used and useful :)
using FPC v3.0.4 and Lazarus 1.8.2 on Windows 7 64bit.

JernejL

  • Jr. Member
  • **
  • Posts: 64
i ran the tool in visual studio and got a better exception message:
It's nice to see that alternate way of debugging is used and useful :)

I actually do this regularly because i link to a bunch of c++ libraries in my game.
 
I compile program with dwarf debug symbols and use https://github.com/rainers/cv2pdb that converts the debug sybols to PDB file.
Then i run program and attach debugger in visual studio 2013 - it can then debug all used c++ dlls and main program loaded easily, it also shows pascal files in editor - breakpoints, call stack, function names and even profiling - it all works.
 

PascalDragon

  • Hero Member
  • *****
  • Posts: 673
  • Compiler Developer

I don't think this is SEH fault tho - there is no exception at all under delphi.
Delphi doesn't know anything else, so that is why that is important.
And yes, specifically ms compilers mess with the float settings.(and are not in any way compliant to standards)
Glad it is now solved.
That has nothing to do with MS compilers. It would be similar with GCC: C/C++ programs normally don't expect floating point exceptions (floating point exceptions are not part of the standard). FPC (and Delphi) by default set the exception mask to something different, so it is rather common that one has to change the exception mask when working with such libraries.

Thaddy

  • Hero Member
  • *****
  • Posts: 9183

I don't think this is SEH fault tho - there is no exception at all under delphi.
Delphi doesn't know anything else, so that is why that is important.
And yes, specifically ms compilers mess with the float settings.(and are not in any way compliant to standards)
Glad it is now solved.
That has nothing to do with MS compilers. It would be similar with GCC: C/C++ programs normally don't expect floating point exceptions (floating point exceptions are not part of the standard). FPC (and Delphi) by default set the exception mask to something different, so it is rather common that one has to change the exception mask when working with such libraries.
It is actually that the Borland 32 bit compilers - including C++ builder - adhere to the IEEE 754 described standards for floating point handling, whereas msvc does not adhere. if other compilers follow msvc they are also not standards compliant.
But indeed the issue exists for many years and up until now I only have to solve it for ms compiled code, or recompile for C++ builder (which I do not recommend for 32 bit since it optimizes not as good as msvc.) Danny Thorpe wrote a lengthy blog about this many moons ago. I'll see if I can find it.
« Last Edit: November 09, 2019, 11:35:00 am by Thaddy »
also related to equus asinus.