summaryrefslogtreecommitdiff
path: root/src/sort.c
diff options
context:
space:
mode:
authorJim Meyering <meyering@redhat.com>2011-09-27 16:32:35 +0200
committerJim Meyering <meyering@redhat.com>2011-09-27 16:49:51 +0200
commit57ee5493d996b69a02d367829d579729e8b20eaf (patch)
treed529aabd8f561ba816e3da9f2cef70078eec1eca /src/sort.c
parent1d0a7ed7d58cfcc2f44959fed431e7276bdf1d46 (diff)
downloadcoreutils-57ee5493d996b69a02d367829d579729e8b20eaf.tar.xz
sort: avoid a NaN-induced infloop
These commands would fail to terminate: yes -- -nan | head -156903 | sort -g > /dev/null echo nan > F; sort -m -g F F That can happen with any strtold implementation that includes uninitialized data in its return value. The problem arises in the mergefps function when bubble-sorting the two or more lines, each from one of the input streams being merged: compare(a,b) returns 64, yet compare(b,a) also returns a positive value. With a broken comparison function like that, the bubble sort never terminates. Why do the long-double bit strings corresponding to two identical "nan" strings not compare equal? Because some parts of the result are uninitialized and thus depend on the state of the stack. For more details, see http://bugs.gnu.org/9612. * src/sort.c (nan_compare): New function. (general_numcompare): Use it rather than bare memcmp. Reported by Aaron Denney in http://bugs.debian.org/642557. * NEWS (Bug fixes): Mention it. * tests/misc/sort-NaN-infloop: New file. * tests/Makefile.am (TESTS): Add it.
Diffstat (limited to 'src/sort.c')
-rw-r--r--src/sort.c20
1 files changed, 19 insertions, 1 deletions
diff --git a/src/sort.c b/src/sort.c
index 3d3119d90..3e94a6e79 100644
--- a/src/sort.c
+++ b/src/sort.c
@@ -1910,6 +1910,24 @@ 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 once
+ gnulib guarantees that strtold's result is always well defined. */
+static int
+nan_compare (char const *sa, char const *sb)
+{
+ 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);
+}
+
static int
general_numcompare (char const *sa, char const *sb)
{
@@ -1935,7 +1953,7 @@ general_numcompare (char const *sa, char const *sb)
: a == b ? 0
: b == b ? -1
: a == a ? 1
- : memcmp (&a, &b, sizeof a));
+ : nan_compare (sa, sb));
}
/* Return an integer in 1..12 of the month name MONTH.