Subject: Re: bug#7877: sleep takes undocumented hex args

From: Jim Meyering <[email-masked]>
Date: Fri, 21 Jan 2011 10:24:36 +0100

[email-masked] wrote:
> The documentation doesn't say that one can also use hex args:
> $ time /bin/sleep 0x10
> real    0m16.007s
> However not octal args:
> $ time /bin/sleep 010
> real    0m10.003s

Interesting.  Thanks for the report.
That's an artifact of GNU sleep using strtod, which means "inf" and
"INFINITY" are also accepted:

    $ timeout 1 sleep inf
    [Exit 124]

My first reflex was to make sleep reject args like 0x... and inf.
However, that would mean duplicating the parsing that strtod does,
in order to detect-and-skip leading isspace and/or "+".

No one likes duplication, but in this case it's not so bad, and seems
better than documenting the "extension", so I wrote the patch:

>From 2bf8d9172cf653b31c202f327b3cc6240acec867 Mon Sep 17 00:00:00 2001
From: Jim Meyering <[email-masked]>
Date: Fri, 21 Jan 2011 09:56:15 +0100
Subject: [PATCH] sleep: do not accept "inf" or hexadecimal numbers like 0x10

* src/sleep.c (strtod_pre_filter): New function.
(main): Use it.
* tests/misc/sleep-hex: New file.  Test for the above change.
* tests/Makefile.am (TESTS): Add it.
Reported by Dan Jacobson in http://debbugs.gnu.org/7877
---
 src/sleep.c          |   20 +++++++++++++++++++-
 tests/Makefile.am    |    1 +
 tests/misc/sleep-hex |   37 +++++++++++++++++++++++++++++++++++++
 3 files changed, 57 insertions(+), 1 deletions(-)
 create mode 100755 tests/misc/sleep-hex

diff --git a/src/sleep.c b/src/sleep.c
index d32daa4..36ee271 100644
--- a/src/sleep.c
+++ b/src/sleep.c
@@ -96,6 +96,23 @@ apply_suffix (double *x, char suffix_char)
   return true;
 }

+/* strtod accepts strings like "INF" and "infinity" as well as
+   hexadecimal representations, but we'd rather not extend sleep
+   to accept such inputs, so reject them here.  Return false for
+   such otherwise-valid inputs to strtod and true otherwise.  */
+static bool
+strtod_pre_filter (char const *s)
+{
+  char const *p = s;
+  while (isspace (*p))
+    ++p;
+  if (*p == '+')
+    ++p;
+  if (*p == '0' && (p[1] == 'x' || p[1] == 'X'))
+    return false;
+  return ISDIGIT (*p) || *p == '.';
+}
+
 int
 main (int argc, char **argv)
 {
@@ -126,7 +143,8 @@ main (int argc, char **argv)
     {
       double s;
       const char *p;
-      if (! xstrtod (argv[i], &p, &s, c_strtod)
+      if (! strtod_pre_filter (argv[i])
+          || ! xstrtod (argv[i], &p, &s, c_strtod)
           /* Nonnegative interval.  */
           || ! (0 <= s)
           /* No extra chars after the number and an optional s,m,h,d char.  */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 1e4e300..3d08a73 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -225,6 +225,7 @@ TESTS =						\
   misc/shred-passes				\
   misc/shred-remove				\
   misc/shuf					\
+  misc/sleep-hex				\
   misc/sort					\
   misc/sort-benchmark-random			\
   misc/sort-compress				\
diff --git a/tests/misc/sleep-hex b/tests/misc/sleep-hex
new file mode 100755
index 0000000..a60a009
--- /dev/null
+++ b/tests/misc/sleep-hex
@@ -0,0 +1,37 @@
+#!/bin/sh
+# Ensure that sleep rejects "inf", 0x10 etc.
+
+# Copyright (C) 2011 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/init.sh"; path_prepend_ ../src
+print_ver_ sleep
+
+sleep 0		|| fail=1
+sleep +0	|| fail=1
+sleep +.001	|| fail=1
+sleep 0.001	|| fail=1
+sleep 1e-4	|| fail=1
+sleep +1E-4	|| fail=1
+
+# The following were all accepted by coreutils-8.9 and earlier.
+# Now, such arguments are rejected.
+sleep +0x10	&& fail=1
+sleep 0x10	&& fail=1
+sleep INF	&& fail=1
+sleep +INF	&& fail=1
+sleep infinity	&& fail=1
+
+Exit $fail
--
1.7.3.5