[yunqa.de] Re: FPU exceptions, Vista, and DISQLite3

  • From: Delphi Inspiration <delphi@xxxxxxxx>
  • To: yunqa@xxxxxxxxxxxxx
  • Date: Thu, 17 Jan 2008 13:43:50 +0100

Michael J. Leaver wrote:

>Hi, I saw on a CodeGear newsgroup that calling Set8087CW($133F) would fail
>on Vista unless the process was run with elevated privileges.

I searched the web but all I could find was some vague mention of the problem 
you describe, with no cause or explanations given, not at Microsoft's either. 
Which posting are you refering to exactly?

However, SQLiteSpy calls Set8087CW($133F); first thing after startup. If the 
claim was true, it should certainly cause problems with Vista, but none have 
yet been reported to me.

>The suggestion was to use the following code instead:
>procedure DisableFPUExceptions;
>  FPUControlWord: Word;
>  FSTCW   FPUControlWord;
>  OR      FPUControlWord, $4 + $1;          // Divide by zero + invalid
>  FLDCW   FPUControlWord;

The above does not work with DISQLite3 as it only disables invalid operation 
($1) and zerodivide ($4) FPU exceptions.

For DISQLite3, you also need to disable at least

 * zerodivide -  $4 
 * overflow   -  $8
 * underflow  - $16

My tests indicate that it is not necessary to suppress invalid operation ($1) 
as well, but it but it should not hurt either.

So here is the corrected versioni for DISQLite3:

procedure DisableFPUExceptions;
  FPUControlWord: Word;
  FSTCW   FPUControlWord;
  { Disable the following FPU exceptions:
     $1 - invalid operation
     $2 - zero divide
     $8 - overflow
    $16 - underflow }
  OR      FPUControlWord, $10 + $8 + $4 + $1;
  FLDCW   FPUControlWord;

To enable the FPU exceptions, call this:

procedure EnableFPUExceptions;
  FPUControlWord: Word;
  FSTCW   FPUControlWord;
  { Enable the following FPU exceptions:
     $1 - invalid operation
     $2 - zero divide
     $8 - overflow
    $16 - underflow }
  AND     FPUControlWord, $FFFF - $1 - $4 - $8 - $10;
  FLDCW   FPUControlWord;

I have not tested if these run fine on Vista in non-admin mode.

>Just to be sure, is there a requirement/reason to disable FPU exceptions
>when using DISQLite3?

Yes. You should disable FPU exceptions if your database handles floating point 
numbers. Here is why:

The SQLite code is generally not prepared to recognize exceptions (FPU or 
others) and does not respond to them as required. If an exception is raised, 
the stack rolls back to the first point the exception is handled. For Delphi, 
this is usually the build-in exception handler.

What is important to SQLite is that, as the stack rolls back, it skips all code 
in SQLite which follows the instruction which raised the exception. This code 
is usually contains commands to free allocated memory and report errors. 
Applications will therefore end up with memory leaks and potentially invalid 
error messages.

In addition, SQLite assumes the FPU to overflow or underflow for certain 
floating point operations. Take these examples, which cause the FPU to store 
INF and -INF to the result:

  SELECT  1e300*1e300;
  SELECT -1e300*1e300;

If FPU exceptions are disabled, the SQL will correctly return INF and -INF, 
because the result is outside the range of a 8-bit floating point number.

With FPU exceptions enabled, the two SQL commands will raise an exception when 
the floating point overflows or underflows. The stack will roll back, SQLite 
can not clean up after itself, and your application will lack memory.


Delphi Inspiration mailing list

Other related posts: