[fpc-pascal] EControlC instead of EZeroDivide when using SSE instructions
OBones
obones at free.fr
Wed Aug 22 13:47:58 CEST 2012
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
Regards
Olivier
More information about the fpc-pascal
mailing list