Skip to content

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