[PATCH v2] math: Set errno to ERANGE for logb (+-0) [BZ #6793]

Shamil Abdulaev ashamil435@gmail.com
Fri Sep 4 18:13:47 GMT 2026


logb (+-0) is a pole error: it returns -Inf and raises the
divide-by-zero exception, but it never set errno, even though glibc
defines math_errhandling to include MATH_ERRNO.

Set errno in the zero branch that already exists in every logb
implementation, instead of adding a w_logb wrapper; the
USE_LOGB*_BUILTIN paths have no such branch, so add one there.  The
double and float versions use __math_divzero and __math_divzerof.
There is no long double equivalent, so those keep the explicit
division and use math_opt_barrier to stop the compiler from folding
it away.

The i386 fxtract implementations of logb and logbf cannot set errno,
and adding the error handling to the assembly is not worthwhile, so
they are removed in favour of the generic C ones.  s_logbl.c moves to
sysdeps/x86/fpu, replacing the x86_64 copy that only included it.

The manual described logb (0) as returning +Inf without signalling,
which was wrong in both respects.

Tested on x86_64-linux-gnu.

Signed-off-by: Shamil Abdulaev <ashamil435@gmail.com>
---
Changes since v1:

  - Use __math_divzero / __math_divzerof in the double and float
    implementations instead of open-coding the errno setting.
  - Use math_opt_barrier on the numerator in the long double and
    powerpc implementations, where no such helper exists, so that the
    division by zero is not folded at compile time.
  - Move sysdeps/i386/fpu/s_logbl.c to sysdeps/x86/fpu and drop
    sysdeps/x86_64/fpu/s_logbl.c, which only included it.
  - Drop the claim that the i386 assembly is removed for the same
    reason as ilogb in commit 7c00a20397; that removal was a
    performance change.

 manual/math.texi                      |  3 ++-
 math/libm-test-logb.inc               |  6 ++----
 sysdeps/i386/fpu/s_logb.S             | 16 ----------------
 sysdeps/i386/fpu/s_logbf.S            | 16 ----------------
 sysdeps/ieee754/dbl-64/s_logb.c       |  7 ++++++-
 sysdeps/ieee754/flt-32/s_logbf.c      |  7 ++++++-
 sysdeps/ieee754/ldbl-128/s_logbl.c    | 14 +++++++++++++-
 sysdeps/ieee754/ldbl-128ibm/s_logbl.c |  8 +++++++-
 sysdeps/m68k/m680x0/fpu/s_logbl.c     |  8 +++++++-
 sysdeps/powerpc/fpu/s_logb.c          |  9 +++++++--
 sysdeps/powerpc/fpu/s_logbf.c         |  9 +++++++--
 sysdeps/powerpc/fpu/s_logbl.c         |  9 +++++++--
 sysdeps/{i386 => x86}/fpu/s_logbl.c   | 10 ++++++++++
 sysdeps/x86_64/fpu/s_logbl.c          |  1 -
 14 files changed, 74 insertions(+), 49 deletions(-)
 delete mode 100644 sysdeps/i386/fpu/s_logb.S
 delete mode 100644 sysdeps/i386/fpu/s_logbf.S
 rename sysdeps/{i386 => x86}/fpu/s_logbl.c (50%)
 delete mode 100644 sysdeps/x86_64/fpu/s_logbl.c

diff --git a/manual/math.texi b/manual/math.texi
index cf57937943..945b48d9fc 100644
--- a/manual/math.texi
+++ b/manual/math.texi
@@ -669,7 +669,8 @@ due to intermediate rounding.
 If @var{x} is de-normalized, @code{logb} returns the exponent @var{x}
 would have if it were normalized.  If @var{x} is infinity (positive or
 negative), @code{logb} returns @math{@infinity{}}.  If @var{x} is zero,
-@code{logb} returns @math{@infinity{}}.  It does not signal.
+a pole error occurs: @code{logb} raises the divide-by-zero exception,
+sets @code{errno} to @code{ERANGE} and returns @math{-@infinity{}}.
 @end deftypefun
 
 @deftypefun int ilogb (double @var{x})
diff --git a/math/libm-test-logb.inc b/math/libm-test-logb.inc
index 8399f52031..df8642bf21 100644
--- a/math/libm-test-logb.inc
+++ b/math/libm-test-logb.inc
@@ -23,10 +23,8 @@ static const struct test_f_f_data logb_test_data[] =
     TEST_f_f (logb, plus_infty, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
     TEST_f_f (logb, minus_infty, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
 
-    /* Bug 6793: errno setting may be missing.  */
-    TEST_f_f (logb, 0, minus_infty, NO_INEXACT_EXCEPTION|DIVIDE_BY_ZERO_EXCEPTION),
-
-    TEST_f_f (logb, minus_zero, minus_infty, NO_INEXACT_EXCEPTION|DIVIDE_BY_ZERO_EXCEPTION),
+    TEST_f_f (logb, 0, minus_infty, NO_INEXACT_EXCEPTION|DIVIDE_BY_ZERO_EXCEPTION|ERRNO_ERANGE),
+    TEST_f_f (logb, minus_zero, minus_infty, NO_INEXACT_EXCEPTION|DIVIDE_BY_ZERO_EXCEPTION|ERRNO_ERANGE),
     TEST_f_f (logb, qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
     TEST_f_f (logb, -qnan_value, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
     TEST_f_f (logb, snan_value, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION),
diff --git a/sysdeps/i386/fpu/s_logb.S b/sysdeps/i386/fpu/s_logb.S
deleted file mode 100644
index d1c7129248..0000000000
--- a/sysdeps/i386/fpu/s_logb.S
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Public domain.
- */
-
-#include <machine/asm.h>
-#include <libm-alias-double.h>
-
-RCSID("$NetBSD: s_logb.S,v 1.4 1995/05/09 00:14:30 jtc Exp $")
-
-ENTRY(__logb)
-	fldl	4(%esp)
-	fxtract
-	fstp	%st
-	ret
-END (__logb)
-libm_alias_double (__logb, logb)
diff --git a/sysdeps/i386/fpu/s_logbf.S b/sysdeps/i386/fpu/s_logbf.S
deleted file mode 100644
index 0d5e55d34f..0000000000
--- a/sysdeps/i386/fpu/s_logbf.S
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Public domain.
- */
-
-#include <machine/asm.h>
-#include <libm-alias-float.h>
-
-RCSID("$NetBSD: s_logbf.S,v 1.3 1995/05/09 00:15:12 jtc Exp $")
-
-ENTRY(__logbf)
-	flds	4(%esp)
-	fxtract
-	fstp	%st
-	ret
-END (__logbf)
-libm_alias_float (__logb, logb)
diff --git a/sysdeps/ieee754/dbl-64/s_logb.c b/sysdeps/ieee754/dbl-64/s_logb.c
index 49b88d2c8d..af4d56a2e7 100644
--- a/sysdeps/ieee754/dbl-64/s_logb.c
+++ b/sysdeps/ieee754/dbl-64/s_logb.c
@@ -20,11 +20,15 @@
 #include <math_private.h>
 #include <libm-alias-double.h>
 #include <fix-int-fp-convert-zero.h>
+#include "math_config.h"
 
 double
 __logb (double x)
 {
 #if USE_LOGB_BUILTIN
+  if (__glibc_unlikely (x == 0))
+    /* Pole error: logb (+-0).  */
+    return __math_divzero (1);
   return __builtin_logb (x);
 #else
   int64_t ix, ex;
@@ -32,7 +36,8 @@ __logb (double x)
   EXTRACT_WORDS64 (ix, x);
   ix &= UINT64_C(0x7fffffffffffffff);
   if (ix == 0)
-    return -1.0 / fabs (x);
+    /* Pole error: logb (+-0).  */
+    return __math_divzero (1);
   ex = ix >> 52;
   if (ex == 0x7ff)
     return x * x;
diff --git a/sysdeps/ieee754/flt-32/s_logbf.c b/sysdeps/ieee754/flt-32/s_logbf.c
index 29316e5787..f21a5b4123 100644
--- a/sysdeps/ieee754/flt-32/s_logbf.c
+++ b/sysdeps/ieee754/flt-32/s_logbf.c
@@ -16,11 +16,15 @@
 #include <math_private.h>
 #include <libm-alias-float.h>
 #include <fix-int-fp-convert-zero.h>
+#include "math_config.h"
 
 float
 __logbf (float x)
 {
 #if USE_LOGBF_BUILTIN
+  if (__glibc_unlikely (x == 0))
+    /* Pole error: logbf (+-0).  */
+    return __math_divzerof (1);
   return __builtin_logbf (x);
 #else
   int32_t ix, rix;
@@ -28,7 +32,8 @@ __logbf (float x)
   GET_FLOAT_WORD (ix, x);
   ix &= 0x7fffffff;		/* high |x| */
   if (ix == 0)
-    return (float) -1.0 / fabsf (x);
+    /* Pole error: logbf (+-0).  */
+    return __math_divzerof (1);
   if (ix >= 0x7f800000)
     return x * x;
   if (__glibc_unlikely ((rix = ix >> 23) == 0))
diff --git a/sysdeps/ieee754/ldbl-128/s_logbl.c b/sysdeps/ieee754/ldbl-128/s_logbl.c
index 7927155cac..2151a04117 100644
--- a/sysdeps/ieee754/ldbl-128/s_logbl.c
+++ b/sysdeps/ieee754/ldbl-128/s_logbl.c
@@ -23,6 +23,8 @@ static char rcsid[] = "$NetBSD: $";
  */
 
 #include <math.h>
+#include <errno.h>
+#include <math-barriers.h>
 #include <math_private.h>
 #include <libm-alias-ldouble.h>
 
@@ -30,6 +32,12 @@ _Float128
 __logbl (_Float128 x)
 {
 #if USE_LOGBL_BUILTIN
+  if (__glibc_unlikely (x == 0))
+    {
+      /* Pole error: logbl (+-0).  */
+      __set_errno (ERANGE);
+      return math_opt_barrier (-1.0) / fabsl (x);
+    }
   return __builtin_logbl (x);
 #else
   /* Use generic implementation.  */
@@ -38,7 +46,11 @@ __logbl (_Float128 x)
   GET_LDOUBLE_WORDS64 (hx, lx, x);
   hx &= 0x7fffffffffffffffLL;	/* high |x| */
   if ((hx | lx) == 0)
-    return -1.0 / fabsl (x);
+    {
+      /* Pole error: logbl (+-0).  */
+      __set_errno (ERANGE);
+      return math_opt_barrier (-1.0) / fabsl (x);
+    }
   if (hx >= 0x7fff000000000000LL)
     return x * x;
   if ((ex = hx >> 48) == 0)	/* IEEE 754 logb */
diff --git a/sysdeps/ieee754/ldbl-128ibm/s_logbl.c b/sysdeps/ieee754/ldbl-128ibm/s_logbl.c
index 37ef47b6a4..cea7c14d8b 100644
--- a/sysdeps/ieee754/ldbl-128ibm/s_logbl.c
+++ b/sysdeps/ieee754/ldbl-128ibm/s_logbl.c
@@ -19,6 +19,8 @@
  */
 
 #include <math.h>
+#include <errno.h>
+#include <math-barriers.h>
 #include <math_private.h>
 #include <math_ldbl_opt.h>
 #include <fix-int-fp-convert-zero.h>
@@ -34,7 +36,11 @@ __logbl (long double x)
   hxs = hx;
   hx &= 0x7fffffffffffffffLL;	/* high |x| */
   if (hx == 0)
-    return -1.0 / fabs (x);
+    {
+      /* Pole error: logbl (+-0).  */
+      __set_errno (ERANGE);
+      return math_opt_barrier (-1.0) / fabs (x);
+    }
   if (hx >= 0x7ff0000000000000LL)
     return x * x;
   if (__glibc_unlikely ((rhx = hx >> 52) == 0))
diff --git a/sysdeps/m68k/m680x0/fpu/s_logbl.c b/sysdeps/m68k/m680x0/fpu/s_logbl.c
index 8cd2326bf8..ec2448aebe 100644
--- a/sysdeps/m68k/m680x0/fpu/s_logbl.c
+++ b/sysdeps/m68k/m680x0/fpu/s_logbl.c
@@ -19,6 +19,8 @@
  */
 
 #include <math.h>
+#include <errno.h>
+#include <math-barriers.h>
 #include <math_private.h>
 
 long double
@@ -29,7 +31,11 @@ __logbl (long double x)
   GET_LDOUBLE_WORDS (es, ix, lx, x);
   es &= 0x7fff;			/* exponent */
   if ((es | ix | lx) == 0)
-    return -1.0 / fabsl (x);
+    {
+      /* Pole error: logbl (+-0).  */
+      __set_errno (ERANGE);
+      return math_opt_barrier (-1.0) / fabsl (x);
+    }
   if (es == 0x7fff)
     return x * x;
   if (es == 0)			/* IEEE 754 logb */
diff --git a/sysdeps/powerpc/fpu/s_logb.c b/sysdeps/powerpc/fpu/s_logb.c
index 880e48e0f5..bcda752bed 100644
--- a/sysdeps/powerpc/fpu/s_logb.c
+++ b/sysdeps/powerpc/fpu/s_logb.c
@@ -22,6 +22,8 @@
 # include <sysdeps/ieee754/dbl-64/s_logb.c>
 #else
 # include <math.h>
+# include <errno.h>
+# include <math-barriers.h>
 # include <math_private.h>
 # include <math_ldbl_opt.h>
 # include <libm-alias-double.h>
@@ -34,8 +36,11 @@ __logb (double x)
   double ret;
 
   if (__glibc_unlikely (x == 0.0))
-    /* Raise FE_DIVBYZERO and return -HUGE_VAL[LF].  */
-    return -1.0 / fabs (x);
+    {
+      /* Pole error: raise FE_DIVBYZERO, set errno and return -HUGE_VAL.  */
+      __set_errno (ERANGE);
+      return math_opt_barrier (-1.0) / fabs (x);
+    }
 
   /* Mask to extract the exponent.  */
   asm ("xxland %x0,%x1,%x2\n"
diff --git a/sysdeps/powerpc/fpu/s_logbf.c b/sysdeps/powerpc/fpu/s_logbf.c
index c640aa88bc..beeecf9c20 100644
--- a/sysdeps/powerpc/fpu/s_logbf.c
+++ b/sysdeps/powerpc/fpu/s_logbf.c
@@ -22,6 +22,8 @@
 # include <sysdeps/ieee754/flt-32/s_logbf.c>
 #else
 # include <math.h>
+# include <errno.h>
+# include <math-barriers.h>
 # include <libm-alias-float.h>
 /* This implementation avoids FP to INT conversions by using VSX
    bitwise instructions over FP values.  */
@@ -32,8 +34,11 @@ __logbf (float x)
   double ret;
 
   if (__glibc_unlikely (x == 0.0))
-    /* Raise FE_DIVBYZERO and return -HUGE_VAL[LF].  */
-    return -1.0 / fabs (x);
+    {
+      /* Pole error: raise FE_DIVBYZERO, set errno and return -HUGE_VALF.  */
+      __set_errno (ERANGE);
+      return math_opt_barrier (-1.0) / fabs (x);
+    }
 
   /* mask to extract the exponent.  */
   asm ("xxland %x0,%x1,%x2\n"
diff --git a/sysdeps/powerpc/fpu/s_logbl.c b/sysdeps/powerpc/fpu/s_logbl.c
index 51edd8ebde..4111fb221c 100644
--- a/sysdeps/powerpc/fpu/s_logbl.c
+++ b/sysdeps/powerpc/fpu/s_logbl.c
@@ -22,6 +22,8 @@
 # include <./sysdeps/ieee754/ldbl-128ibm/s_logbl.c>
 #else
 # include <math.h>
+# include <errno.h>
+# include <math-barriers.h>
 # include <math_private.h>
 # include <math_ldbl_opt.h>
 
@@ -35,8 +37,11 @@ __logbl (long double x)
   int64_t hx;
 
   if (__glibc_unlikely (x == 0.0))
-    /* Raise FE_DIVBYZERO and return -HUGE_VAL[LF].  */
-    return -1.0L / __builtin_fabsl (x);
+    {
+      /* Pole error: raise FE_DIVBYZERO, set errno and return -HUGE_VALL.  */
+      __set_errno (ERANGE);
+      return math_opt_barrier (-1.0L) / __builtin_fabsl (x);
+    }
 
   ldbl_unpack (x, &xh, &xl);
   EXTRACT_WORDS64 (hx, xh);
diff --git a/sysdeps/i386/fpu/s_logbl.c b/sysdeps/x86/fpu/s_logbl.c
similarity index 50%
rename from sysdeps/i386/fpu/s_logbl.c
rename to sysdeps/x86/fpu/s_logbl.c
index ec867de010..91056e1b06 100644
--- a/sysdeps/i386/fpu/s_logbl.c
+++ b/sysdeps/x86/fpu/s_logbl.c
@@ -2,6 +2,9 @@
  * Public domain.
  */
 
+#include <math.h>
+#include <errno.h>
+#include <math-barriers.h>
 #include <libm-alias-ldouble.h>
 
 long double
@@ -9,6 +12,13 @@ __logbl (long double x)
 {
   long double res;
 
+  if (__glibc_unlikely (x == 0))
+    {
+      /* Pole error: logbl (+-0).  */
+      __set_errno (ERANGE);
+      return math_opt_barrier (-1.0L) / 0.0L;
+    }
+
   asm ("fxtract\n"
        "fstp	%%st" : "=t" (res) : "0" (x));
   return res;
diff --git a/sysdeps/x86_64/fpu/s_logbl.c b/sysdeps/x86_64/fpu/s_logbl.c
deleted file mode 100644
index 4791ba64e8..0000000000
--- a/sysdeps/x86_64/fpu/s_logbl.c
+++ /dev/null
@@ -1 +0,0 @@
-#include <sysdeps/i386/fpu/s_logbl.c>
-- 
2.55.0



More information about the Libc-alpha mailing list