[fpc-pascal] EControlC instead of EZeroDivide when using SSE instructions

Sven Barth pascaldragon at googlemail.com
Wed Aug 22 16:14:08 CEST 2012


Am 22.08.2012 13:47, schrieb OBones:
> Jonas Maebe wrote:
>>
>> OBones wrote on Wed, 22 Aug 2012:
>>
>>> Olivier SANNIER wrote:
>>>> Does any of you have any suggestion as to explain this behavior, and
>>>> best of
>>>> all, how to fix it?
>>> I went further and changed the code this so that I can get better
>>> details as to where the exception is coming from:
>>
>> EControlC is the translation of run time error 217. The Win32
>> exception handler also sets error code 217 in case of an unknown
>> exception  (the Win64 exception handler does the same, for that
>> matter). Apparently Win32 is not reporting that division-by-zero as
>> either STATUS_INTEGER_DIVIDE_BY_ZERO or STATUS_FLOAT_DIVIDE_BY_ZERO,
>> while Win64 does do this.
>>
>> You can try debugging syswin32_i386_exception_handler in
>> rtl/win32/system.pp to see what exception Win32 reports instead.
> Thanks for the confirmation as I was heading that way when I posted the
> message, without much hope.
> But now that I have put that idea to full length, it became clear that
> the problem is not (entirely) with Win32 but because the exception
> handler does not handle the STATUS_FLOAT_MULTIPLE_FAULTS and
> STATUS_FLOAT_MULTIPLE_TRAPS cases.
> And as you said, when it does not know what to do, it gives 217 that
> gets later translated to Control C, which to me is a bit misleading. I'd
> rather have a 202, External Exception.
> Anyway, I installed my own exception handler using
> SetUnhandledExceptionFilter, saving the return value and I wrote my own
> "overloaded" version of the exception handler that does this:
>
> function GetMXCSR: Cardinal;
> asm
>    stmxcsr Result
> end;
>
> function MyUnhandledExceptionFilter(excep : PExceptionPointers) :
> Longint;stdcall;
> const
>    MXCSR_IE = $01;   // invalid operation
>    MXCSR_DE = $02;   // denormal
>    MXCSR_ZE = $04;   // divide by zero
>    MXCSR_OE = $08;   // overflow
>    MXCSR_UE = $10;   // underflow
>    MXCSR_PE = $20;   // precision
> var
>    MXCSR: Cardinal;
> begin
>    WriteLn('MyUnhandledExceptionFilter: ' + IntToHex(GetMXCSR, 2));
>    WriteLn(IntToHex(excep^.ExceptionRecord^.ExceptionCode, 8));
>    WriteLn(IntToHex(EXCEPTION_FLT_DIVIDE_BY_ZERO, 8));
>    if Assigned(PreviousUnhandledExceptionFilter) then
>    begin
>      if (excep^.ExceptionRecord^.ExceptionCode =
> STATUS_FLOAT_MULTIPLE_FAULTS) or
>        (excep^.ExceptionRecord^.ExceptionCode =
> STATUS_FLOAT_MULTIPLE_TRAPS) then
>      begin
>        MXCSR := GetMXCSR;
>
>        if MXCSR and MXCSR_IE = MXCSR_IE then
>          excep^.ExceptionRecord^.ExceptionCode :=
> STATUS_FLOAT_INVALID_OPERATION
>        else if MXCSR and MXCSR_DE = MXCSR_DE then
>          excep^.ExceptionRecord^.ExceptionCode :=
> STATUS_FLOAT_DENORMAL_OPERAND
>        else if MXCSR and MXCSR_ZE = MXCSR_ZE then
>          excep^.ExceptionRecord^.ExceptionCode :=
> STATUS_FLOAT_DIVIDE_BY_ZERO
>        else if MXCSR and MXCSR_OE = MXCSR_OE then
>          excep^.ExceptionRecord^.ExceptionCode := STATUS_FLOAT_OVERFLOW
>        else if MXCSR and MXCSR_UE = MXCSR_UE then
>          excep^.ExceptionRecord^.ExceptionCode := STATUS_FLOAT_UNDERFLOW
>        else if MXCSR and MXCSR_PE = MXCSR_PE then
>          excep^.ExceptionRecord^.ExceptionCode :=
> STATUS_FLOAT_INEXACT_RESULT;
>      end;
>
>      Result := PreviousUnhandledExceptionFilter(excep);
>    end;
> end;
>
> I know that I hide the case where there might be two errors at once, but
> strangely enough, the MXCSR register only contained one exception bit
> set in my case, so I don't understand why Win32 is giving a "multiple
> traps" error.
>
> So right, now, using this I'm getting the appropriate exception, I'm
> just left wondering if this code (or a similar one) should be added to
> FreePascal so that other people are not having the same issue as I'm
> having.
>
> Note to others: this is only ever useful in Win32 because Win64 does not
> use the handlers set by SetUnhandledExceptionFilter

Win64 (and Win32 systems after Windows XP) do all use 
SetUnhandledExceptionFilter, but we do use AddVectoredExceptionHandler 
on Win64 (at least if not compiled using the new Win64 SEH code in 2.7.1 
;) ) of which the handlers are called before the handler set by 
SetUnhandledExceptionFilter is called.

Regards,
Sven




More information about the fpc-pascal mailing list