]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
sort: fix sort -g infloop again
authorPaul Eggert <eggert@cs.ucla.edu>
Mon, 2 May 2022 05:46:21 +0000 (22:46 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Mon, 2 May 2022 05:53:29 +0000 (22:53 -0700)
Problem reported by Giulio Genovese (Bug#55212).
* src/sort.c (nan_compare): To compare NaNs, simply printf+strcmp.
This avoids the problem of padding bits and unspecified behavior.
Args are now long double instead of char *; caller changed.

NEWS
src/sort.c

diff --git a/NEWS b/NEWS
index 26eb52ca067aabbf321561564d52cf55d2c212a4..3a9148637424e28caeb4b11bc4b124081908356d 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,12 @@ GNU coreutils NEWS                                    -*- outline -*-
   'mv --backup=simple f d/' no longer mistakenly backs up d/f to f~.
   [bug introduced in coreutils-9.1]
 
+  'sort -g' no longer infloops when given multiple NaNs on platforms
+  like x86-64 where 'long double' has padding bits in memory.
+  Although the fix alters sort -g's NaN ordering, that ordering has
+  long been documented to be platform-dependent.
+  [bug introduced 1999-05-02 and only partly fixed in coreutils-8.14]
+
 
 * Noteworthy changes in release 9.1 (2022-04-15) [stable]
 
index 3b775d6bbbd6dbcf6d63e44096ab73bb21b01140..b2a465cf53e42477c9450fe71d6a2f9a64cc6712 100644 (file)
@@ -2003,22 +2003,13 @@ numcompare (char const *a, char const *b)
   return strnumcmp (a, b, decimal_point, thousands_sep);
 }
 
-/* Work around a problem whereby the long double value returned by glibc's
-   strtold ("NaN", ...) contains uninitialized bits: clear all bytes of
-   A and B before calling strtold.  FIXME: remove this function if
-   gnulib guarantees that strtold's result is always well defined.  */
 static int
-nan_compare (char const *sa, char const *sb)
+nan_compare (long double a, long double b)
 {
-  long double a;
-  memset (&a, 0, sizeof a);
-  a = strtold (sa, NULL);
-
-  long double b;
-  memset (&b, 0, sizeof b);
-  b = strtold (sb, NULL);
-
-  return memcmp (&a, &b, sizeof a);
+  char buf[2][sizeof "-nan()" + CHAR_BIT * sizeof a];
+  snprintf (buf[0], sizeof buf[0], "%Lf", a);
+  snprintf (buf[1], sizeof buf[1], "%Lf", b);
+  return strcmp (buf[0], buf[1]);
 }
 
 static int
@@ -2046,7 +2037,7 @@ general_numcompare (char const *sa, char const *sb)
           : a == b ? 0
           : b == b ? -1
           : a == a ? 1
-          : nan_compare (sa, sb));
+          : nan_compare (a, b));
 }
 
 /* Return an integer in 1..12 of the month name MONTH.