Floating point exception masking with Set8087CW, SetMXCSR and TWebBrowser

When I get a floating point to zero exception when using TWebBrowser and TEmbeddedWB from time to time, I find that I need to mask the division by zero of the Set8087CW or SetMXCSR exceptions.

Q1: What would be the best way to do this:

  • to mask such exceptions at an early stage of application launch and never touch them (application is multithreaded)?
  • to use the OnBeforeNavigate and OnDocumentComplete to mask / remove the exception mask? (is there any chance that an exception may occur after loading the document?)

Q2: What would be the best “command” to mask only “division by zero”, and nothing else - if the application is 32-bit, do you also need to mask the exception from 64 bits?

In the application I use, it has TWebBrowser, available all the time to display the contents of the email.

Also, if anyone can clarify, is this a special mistake using Microsoft's TWebBrowser or is it just the difference between Delphi / C ++ Builder and Microsoft tools? What happens if I place TWebBrowser inside a Visual C ++ application, if division by zero error appears - it will not be thrown into the exception, but what then happens - how does Visual C ++ handle the division by zero exception, what?

Oddly enough, Microsoft has not noticed this problem for such a long time - it is also strange that Embarcardero did not notice it. Since masking floating point exceptions effectively also masks your own program exception for that particular purpose.

UPDATE

My final decision after some study:

 SetExceptionMask(GetExceptionMask() << exZeroDivide); 

The default state from GetExceptionMask () returns: TFPUExceptionMask() << exDenormalized << exUnderflow << exPrecision . Obviously, some exceptions are already masked - this simply adds exZeroDivide to the masked exceptions.

As a result, each division by zero now leads to + INF at the floating point instead of an exception. I can live with this - for the production version of the code, it will be masked to avoid errors, and for the debug version it will be exposed to detect floating point division by zero.

+7
exception delphi c ++ builder webbrowser-control twebbrowser
source share
1 answer

Assuming that you do not need floating point exceptions to be exposed in the application code, the far and simplest task is to mask the exceptions at some point in your initialization code.

The best way to do it like this:

 SetExceptionMask(exAllArithmeticExceptions); 

This will set the control word 8087 to 32-bit targets, and MXCSR to 64-bit targets. You will find SetExceptionMask in the Math block.

If you want floating point exceptions to be disabled in your code, this gets complicated. One strategy would be to run your floating point code in a dedicated thread that eliminates exceptions. This may certainly work, but not if you rely on the RTL functions Set8087CW and SetMXCSR . Note that everything in RTL that controls the FP units routes these functions. For example, SetExceptionMask does.

The problem is that Set8087CW and SetMXCSR are not thread safe. It seems hard to believe that Embarcadero can be so inept as to create fundamental routines that work in the context of threads, but cannot be thread safe. But that is what they did.

It is surprisingly difficult to undo the mess that they have left, and this requires quite a bit of code fix. The lack of thread safety depends on the (incorrect) use of the global variables Default8087CW and Default8087CW . If two threads access Set8087CW or SetMXCSR at the same time, then these global variables can have the effect of leaking values ​​from one thread to another.

You can replace Set8087CW and SetMXCSR with versions that did not change the global state, but, unfortunately, this is not so simple. Global status is used elsewhere. This may seem immodest, but if you want to know more about it, read my document attached to this QC report: http://qc.embarcadero.com/wc/qcmain.aspx?d=107411

+8
source share

All Articles