Infinite loop in frexp

Summary

There is an error, or at least an oversight, in one of the generic mathematical functions, namely frexp on line 351 of rtl/inc/genmath.inc.

    procedure frexp(X: Real; out Mantissa: Real; out Exponent: longint);
    {*  frexp() extracts the exponent from x.  It returns an integer     *}
    {*  power of two to expnt and the significand between 0.5 and 1      *}
    {*  to y.  Thus  x = y * 2**expn.                                    *}
    begin
      exponent:=0;
      if (abs(x)<0.5) then
       While (abs(x)<0.5) do
       begin
         x := x*2;
         Dec(exponent);
       end
      else
       While (abs(x)>1) do
       begin
         x := x/2;
         Inc(exponent);
       end;
      Mantissa := x;
    end;

This gets used in the generic fpc_sqrt_real function (if a platform-specific square root instruction isn't supported). The bug is that if X is infinity, it lives up to its name as the function enters an infinite loop, because all operations upon X keep it set to infinity. NaNs should logically exit very quickly with the exponent set to zero because all of the conditions will evaluate to false.

System Information

  • Processor architecture: Cross-platform (no native SQRT)
  • Compiler version: Trunk

Steps to reproduce

On any system without a native floating-point square root (FPC_SYSTEM_HAS_SQRT is not defined), call Sqrt(1.0/0.0) and note that the program never makes progress beyond this point.

Possible fixes

Since the format of the floating-point number cannot be guaranteed to be of a IEEE 754 standard, the input of frexp must explicitly check against ±∞, likely via if Abs(X)=1.0/0.0 then.

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information