linux-mips
[Top] [All Lists]

endless recursive loop in pow()

To: linux-mips@oss.sgi.com
Subject: endless recursive loop in pow()
From: Atsushi Nemoto <nemoto@toshiba-tops.co.jp>
Date: Tue, 05 Feb 2002 17:43:20 +0900 (JST)
Cc: ralf@oss.sgi.com
In-reply-to: <200202040953.g149rrA17976@oss.sgi.com>
Organization: TOSHIBA Personal Computer System Corporation
References: <200202040953.g149rrA17976@oss.sgi.com>
Sender: owner-linux-mips@oss.sgi.com
I found that pow() of glibc 2.2.4 causes stack overflow on some
testcase with NaN operand.  Try this simple (and dirty) test program
(for little endian).

main()
{
        double x, y, z;
        *(int*)(&x) = 0x00000000;
        *((int*)(&x) + 1) = 0xfff00001;
        *(int*)(&y) = 0x80000000;
        *((int*)(&y) + 1) = 0xcff00000;
        z = pow(x, y);
        printf("%x %x\n", *((int*)&z + 1), *(int*)&z);
        return 0;
}

This program fall into endless recursive call at line 128 in
sysdeps/ieee754/dbl-64/e_pow.c.

128:     return (k==1)?__ieee754_pow(-x,y):-__ieee754_pow(-x,y); /* if y even 
or odd */


The problem occur if sign-bit of a NaN and negation of the NaN is
same.  I saw this problem only if the neg.d instruction was
interpreted by kernel fp emulation.

The patch below is a fix for kernel fp emulation.  Is this a right
fix?  Or glibc should be fixed?

---
Atsushi Nemoto
diff -u linux-sgi-cvs/arch/mips/math-emu/dp_simple.c 
linux.new/arch/mips/math-emu/dp_simple.c
--- linux-sgi-cvs/arch/mips/math-emu/dp_simple.c        Mon Oct 22 10:29:56 2001
+++ linux.new/arch/mips/math-emu/dp_simple.c    Tue Feb  5 17:36:29 2002
@@ -48,16 +48,18 @@
        CLEARCX;
        FLUSHXDP;
 
+       /* quick fix up */
+       DPSIGN(x) ^= 1;
+
        if (xc == IEEE754_CLASS_SNAN) {
+               ieee754dp y = ieee754dp_indef();
                SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754dp_nanxcpt(ieee754dp_indef(), "neg");
+               DPSIGN(y) = DPSIGN(x);
+               return ieee754dp_nanxcpt(y, "neg");
        }
 
        if (ieee754dp_isnan(x)) /* but not infinity */
                return ieee754dp_nanxcpt(x, "neg", x);
-
-       /* quick fix up */
-       DPSIGN(x) ^= 1;
        return x;
 }
 
diff -u linux-sgi-cvs/arch/mips/math-emu/sp_simple.c 
linux.new/arch/mips/math-emu/sp_simple.c
--- linux-sgi-cvs/arch/mips/math-emu/sp_simple.c        Mon Oct 22 10:29:56 2001
+++ linux.new/arch/mips/math-emu/sp_simple.c    Tue Feb  5 17:36:29 2002
@@ -48,16 +48,18 @@
        CLEARCX;
        FLUSHXSP;
 
+       /* quick fix up */
+       SPSIGN(x) ^= 1;
+
        if (xc == IEEE754_CLASS_SNAN) {
+               ieee754sp y = ieee754sp_indef();
                SETCX(IEEE754_INVALID_OPERATION);
-               return ieee754sp_nanxcpt(ieee754sp_indef(), "neg");
+               SPSIGN(y) = SPSIGN(x);
+               return ieee754sp_nanxcpt(y, "neg");
        }
 
        if (ieee754sp_isnan(x)) /* but not infinity */
                return ieee754sp_nanxcpt(x, "neg", x);
-
-       /* quick fix up */
-       SPSIGN(x) ^= 1;
        return x;
 }
 
<Prev in Thread] Current Thread [Next in Thread>