Recent

Author Topic: Multiple floating point traps when using external DLL  (Read 4147 times)

alpine

  • Hero Member
  • *****
  • Posts: 1038
Multiple floating point traps when using external DLL
« on: January 25, 2022, 05:42:55 pm »
I'm trying to "merge" an existing MSVC project with Lazarus by converting it to a DLL and then calling some of its entry points from the Lazarus App. Everything is OK until some FP operation used (in this case the _ftol2_pentium4() ) and the exception  0xC00002B5: Multiple floating point traps raises.

I've searched in GitLab issues, found a couple of issues with FP and DLLs:
https://gitlab.com/freepascal.org/fpc/source/-/issues/16801
https://gitlab.com/freepascal.org/fpc/source/-/issues/16263, but those are >10yrs old.

Is there some recipe how to accomplish such kind of a merger? Is it possible?
Should I start preparing myself to divide in separate processes and use IPC for that? 

Suggestions welcome
Thanks in advance!
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

Thaddy

  • Hero Member
  • *****
  • Posts: 14205
  • Probably until I exterminate Putin.
Re: Multiple floating point traps when using external DLL
« Reply #1 on: January 25, 2022, 06:07:57 pm »
If it is msvc (that does not play nice with floats since IONS!, it is not IEEE compliant) and is 32 bits windows you simply -partially - disable floating point exceptions through Set8087CW if you access a msvc compiled dll.
I have an example, but not at hand.
See this discussion:
https://forum.lazarus.freepascal.org/index.php/topic,46014.msg326495.html#msg326495
BTW, since 3.2.0 you may want to use winapi instead of stdcall. That will also cover 64 bit issues, including other platforms than windows.

If you are not compiling for 32 bit i386 Windows, I need a small example.
If you are, I will post that example.
« Last Edit: January 25, 2022, 06:21:44 pm by Thaddy »
Specialize a type, not a var.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: Multiple floating point traps when using external DLL
« Reply #2 on: January 26, 2022, 09:36:01 am »
I'm trying to "merge" an existing MSVC project with Lazarus by converting it to a DLL and then calling some of its entry points from the Lazarus App. Everything is OK until some FP operation used (in this case the _ftol2_pentium4() ) and the exception  0xC00002B5: Multiple floating point traps raises.

C code doesn't usually expect the floating point exceptions that FPC enables. Use SetExceptionMask to disable the corresponding exceptions (especially overflow and underflow).

If it is msvc (that does not play nice with floats since IONS!, it is not IEEE compliant) and is 32 bits windows you simply -partially - disable floating point exceptions through Set8087CW if you access a msvc compiled dll.
I have an example, but not at hand.
See this discussion:
https://forum.lazarus.freepascal.org/index.php/topic,46014.msg326495.html#msg326495

Set8087CW only sets the control word for the x87 FPU, but in case of x86_64 Windows only SSE is used, thus the corresponding SSE exceptions wouldn't be disabled. And on ARM64 it doesn't exist at all. So the correct solution is SetExceptionMask (which handles both the x87 and SSE) and not Set8087CW directly.

AlexTP

  • Hero Member
  • *****
  • Posts: 2386
    • UVviewsoft
Re: Multiple floating point traps when using external DLL
« Reply #3 on: January 26, 2022, 12:59:05 pm »
I just stored this answer to https://wiki.freepascal.org/SetExceptionMask .

Thaddy

  • Hero Member
  • *****
  • Posts: 14205
  • Probably until I exterminate Putin.
Re: Multiple floating point traps when using external DLL
« Reply #4 on: January 26, 2022, 02:54:29 pm »
That is correct, in so far that afaik there is an option to enable 8087() in x86_32-win64.
That sounds funny, is hidden, but Florian did that. I forgot the option. Intel/AMD only.
Specialize a type, not a var.

alpine

  • Hero Member
  • *****
  • Posts: 1038
Re: Multiple floating point traps when using external DLL
« Reply #5 on: January 27, 2022, 09:41:40 am »
Thank you all for the suggestions.

At this point I've (only) changed the MSVC compiler floating point model option from /fp:precise to /fp:strict and that one muted the exceptions. Not sure the problem is solved - it is a lot of code and it needs exhaustive testing. I suspect I can hit the curbs at many other places, not only the fp. That fp issue just popped-up instantly.

*snip*
If you are not compiling for 32 bit i386 Windows, I need a small example.
If you are, I will post that example.
Oops, sorry for not giving more details about.
It is a 32 bit application.
The MSVC compiler is rather old: Microsoft Visual C++ 2008.
Lazarus 1.9.0 r63034 FPC 3.1.1 i386-win32-win32/win64.
The original application was built using C++Builder 5.0 Build 12.34. C++Builder capacity was outgrown long time ago.
Now I desperately need a new means of handling the GUI and I'm putting the non-gui part into a DLL.

What about compiling the DLL with TDM-GCC32 for example? Will it be better?
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: Multiple floating point traps when using external DLL
« Reply #6 on: January 27, 2022, 09:52:54 am »
That is correct, in so far that afaik there is an option to enable 8087() in x86_32-win64.
That sounds funny, is hidden, but Florian did that. I forgot the option. Intel/AMD only.

We do not advertise that option by default and do not suggest to use it.

Also even then the problem would still be there, because Set8087CW still only sets the control word of the x87 and if the C code uses SSE instead of x87 (which MSVC generated code for x64 always does) then there'd still be exceptions, because SetSSECW wasn't used. So, in short, always use SetExceptionMask and at best forget about Set8087CW except if you have very specific use cases (changing rounding mode has specific functions that handles both x87 and SSE at once as well).

Thaddy

  • Hero Member
  • *****
  • Posts: 14205
  • Probably until I exterminate Putin.
Re: Multiple floating point traps when using external DLL
« Reply #7 on: January 27, 2022, 10:04:35 am »
Well, SetExceptionMask is the way to go then. Glad that I forgot that option I mentioned  ;D

There's a good chance that this example from the wiki is sufficient:
Code: Pascal  [Select][+][-]
  1. uses Math;
  2. //...
  3. begin
  4.   SetExceptionMask(GetExceptionMask + [exOverflow,exZeroDivide,exInvalidOp]);
« Last Edit: January 27, 2022, 10:07:05 am by Thaddy »
Specialize a type, not a var.

alpine

  • Hero Member
  • *****
  • Posts: 1038
Re: Multiple floating point traps when using external DLL
« Reply #8 on: January 27, 2022, 02:13:04 pm »
Well, SetExceptionMask is the way to go then. Glad that I forgot that option I mentioned  ;D

There's a good chance that this example from the wiki is sufficient:
Code: Pascal  [Select][+][-]
  1. uses Math;
  2. //...
  3. begin
  4.   SetExceptionMask(GetExceptionMask + [exOverflow,exZeroDivide,exInvalidOp]);

Follow-up:
Using SetExceptionMask also worked by muting the exceptions. I'll use both ways together with the MSVC option /fp:strict to be more certain

 
*snip*
What about compiling the DLL with TDM-GCC32 for example? Will it be better?
Does anybody have opinion on that?
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

Thaddy

  • Hero Member
  • *****
  • Posts: 14205
  • Probably until I exterminate Putin.
Re: Multiple floating point traps when using external DLL
« Reply #9 on: January 27, 2022, 02:57:27 pm »
Does anybody have opinion on that?
Well, Both GNU compilers and the Borland/Embarcadero compilers adhere to the IEEE standards for floating point handling and MSVC does not...
So yes, that may be worth a try to build with a different compiler..
Specialize a type, not a var.

alpine

  • Hero Member
  • *****
  • Posts: 1038
Re: Multiple floating point traps when using external DLL
« Reply #10 on: February 01, 2022, 07:38:25 pm »
Follow-up:
It seems the FP exceptions were just the tip of the iceberg. Since then, I have encountered lots of issues with exceptions and/or variants - depending on where try/finally (FPC) and try/catch (MSVC) used, with or without using local variant variables, the code gives erratic SIGSEGV exceptions, even sometimes SIGILL (?!).

Debugging such a hybrid is a very tedious and time consuming for me, I'm giving up on this. Going now for separate processes with messages on stdin/stdout pipes.

Thanks again to anyone participating.     
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

 

TinyPortal © 2005-2018