From 2f56f5a42033dc6db15d8963e54566f01fa0d61d Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 1 May 2022 22:46:21 -0700 Subject: [PATCH] sort: fix sort -g infloop again 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. Reference:https://github.com/coreutils/coreutils/commit/2f56f5a42033dc6db15d8963e54566f01fa0d61d Conflict: NEWS Context adaptation --- NEWS | 6 ++++++ src/sort.c | 21 ++++++--------------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/NEWS b/NEWS index 3e44c0c..fc8ff16 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,12 @@ GNU coreutils NEWS -*- outline -*- ** Bug fixes + '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] + cp now copies /dev/fd/N correctly on platforms like Solaris where it is a character-special file whose minor device number is N. [bug introduced in fileutils-4.1.6] diff --git a/src/sort.c b/src/sort.c index 8e1533e..5b4342f 100644 --- a/src/sort.c +++ b/src/sort.c @@ -2360,22 +2360,13 @@ numcompare_mb (const char *a, const char *b) } #endif /* HAV_EMBRTOWC */ -/* 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 @@ -2403,7 +2394,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. -- 2.27.0