]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
maint: avoid signed integer overflows
authorTobias Stoeckmann <tobias@stoeckmann.org>
Sun, 14 Jun 2020 12:47:11 +0000 (14:47 +0200)
committerPádraig Brady <P@draigBrady.com>
Mon, 15 Jun 2020 22:07:03 +0000 (23:07 +0100)
Since -LONG_MIN results in LONG_MIN again, the operation itself is
a signed integer overflow.

This can be observed with the following calls (best if compiled
with -ftrapv or -fsanitize=undefined):

  $ numfmt --padding=-9223372036854775808
  $ seq 1e-9223372036854775808

Technically, the change in seq "reduces" the precision, but a double
or long double that small would be represented as 0 anyway.

* src/numfmt.c: Explicitly disallow --padding=LONG_MIN.
* src/seq.c: Treat 1e$LONG_MIN as 1e-$LONG_MAX.
* tests/misc/numfmt.pl: Add a test case.
* tests/misc/seq-precision.sh: Likewise.

Fixes https://bugs.gnu.org/41850

src/numfmt.c
src/seq.c
tests/misc/numfmt.pl
tests/misc/seq-precision.sh

index 8869791b0f4297418d4ca702f4a9c1317a92ff75..8871a8c01833db4667e50c4b6da4576faf40f509 100644 (file)
@@ -1496,7 +1496,7 @@ main (int argc, char **argv)
 
         case PADDING_OPTION:
           if (xstrtol (optarg, NULL, 10, &padding_width, "") != LONGINT_OK
-              || padding_width == 0)
+              || padding_width == 0 || padding_width < -LONG_MAX)
             die (EXIT_FAILURE, 0, _("invalid padding value %s"),
                  quote (optarg));
           if (padding_width < 0)
index ddb63b642165472a1fb708fd36d8c94ee33fbce4..2ca1e4f7b7970ad6820af74a552d53000b35b85e 100644 (file)
--- a/src/seq.c
+++ b/src/seq.c
@@ -197,7 +197,7 @@ scan_arg (const char *arg)
         e = strchr (arg, 'E');
       if (e)
         {
-          long exponent = strtol (e + 1, NULL, 10);
+          long exponent = MAX (strtol (e + 1, NULL, 10), -LONG_MAX);
           ret.precision += exponent < 0 ? -exponent
                                         : - MIN (ret.precision, exponent);
           /* Don't account for e.... in the width since this is not output.  */
index a78e9c302daa1af2d5359575671e25a4d39c257d..47ff34444ff803f8e07933f039490e0093db5eca 100755 (executable)
@@ -178,6 +178,9 @@ my @Tests =
      ['pad-3.1', '--padding=0 5',
              {ERR => "$prog: invalid padding value '0'\n"},
              {EXIT => '1'}],
+     ['pad-3.2', "--padding=$limits->{LONG_MIN} 0",
+             {ERR => "$prog: invalid padding value '$limits->{LONG_MIN}'\n"},
+             {EXIT => '1'}],
      ['pad-4', '--padding=10 --to=si 50000',             {OUT=>'       50K'}],
      ['pad-5', '--padding=-10 --to=si 50000',            {OUT=>'50K       '}],
 
index b5b167783e63fbcd7878240a5e43ad27ecf83abc..08f9863ed5ca8c720400c29c1fa71926d7d62e7c 100755 (executable)
@@ -18,6 +18,7 @@
 
 . "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
 print_ver_ seq
+getlimits_
 
 # Integer only.  Before v8.24 these would switch output format
 
@@ -76,4 +77,9 @@ seq -w 1.10000e5 1.10000e5 > out || fail=1
 printf "%s\n" 110000 > exp || framework_failure_
 compare exp out || fail=1
 
+# Ensure no undefined behavior which failed with <= 8.32
+# This test would fail with: -fsanitize=undefined
+seq 1e$LONG_MIN 2> err || fail=1
+compare /dev/null err || fail=1
+
 Exit $fail