From 66464e61f549e9f2fd35f82567345721798288f9 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sat, 28 Jun 2025 17:29:22 -0700 Subject: [PATCH] od: fix '+N.' bug * src/od.c (parse_old_offset): First arg is now char *, not char const *. If a decimal number, temporarily modify the string so that xstrtoumax does not complain about the '.'. * tests/od/od.pl: Test for the bug. --- NEWS | 3 +++ src/od.c | 31 +++++++++++++++++++++++++++---- tests/od/od.pl | 4 ++++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index 4a958770c7..d0b6e794a7 100644 --- a/NEWS +++ b/NEWS @@ -24,6 +24,9 @@ GNU coreutils NEWS -*- outline -*- Instead, it either outputs correctly or diagnoses a too-large width. [This bug was present in "the beginning".] + od +N. (where N is a decimal number) works again as per POSIX. + [bug introduced on 1995-01-25] + sort with key character offsets of SIZE_MAX, could induce a read of 1 byte before an allocated heap buffer. For example: 'sort +0.18446744073709551615R input' on 64 bit systems. diff --git a/src/od.c b/src/od.c index 8bb463ca8b..fd5fc45bd4 100644 --- a/src/od.c +++ b/src/od.c @@ -1402,7 +1402,7 @@ get_lcm (void) leading '+' return true and set *OFFSET to the offset it denotes. */ static bool -parse_old_offset (char const *s, uintmax_t *offset) +parse_old_offset (char *s, uintmax_t *offset) { int radix; @@ -1414,10 +1414,24 @@ parse_old_offset (char const *s, uintmax_t *offset) ++s; /* Determine the radix we'll use to interpret S. If there is a '.', + optionally followed by 'B' or 'b' and then end of string, it's decimal, otherwise, if the string begins with '0X'or '0x', it's hexadecimal, else octal. */ - if (strchr (s, '.') != nullptr) - radix = 10; + char *dot = strchr (s, '.'); + if (dot) + { + bool b = dot[1] == 'B' || dot[1] == 'b'; + if (dot[b + 1]) + dot = nullptr; + } + + if (dot) + { + /* Temporarily remove the '.' from the decimal string. */ + dot[0] = dot[1]; + dot[1] = '\0'; + radix = 10; + } else { if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) @@ -1426,7 +1440,16 @@ parse_old_offset (char const *s, uintmax_t *offset) radix = 8; } - return xstrtoumax (s, nullptr, radix, offset, "Bb") == LONGINT_OK; + enum strtol_error s_err = xstrtoumax (s, nullptr, radix, offset, "Bb"); + + if (dot) + { + /* Restore the decimal string's original value. */ + dot[1] = dot[0]; + dot[0] = '.'; + } + + return s_err == LONGINT_OK; } /* Read a chunk of size BYTES_PER_BLOCK from the input files, write the diff --git a/tests/od/od.pl b/tests/od/od.pl index 5bb271e607..9688607c6e 100755 --- a/tests/od/od.pl +++ b/tests/od/od.pl @@ -60,6 +60,10 @@ my @Tests = ['j-proc', "-An -c -j $proc_file_byte_count $proc_file", {IN=>{f2=>'e'}}, {OUT=>" e\n"}], + # Check that the traditional form '+N.' works, as per POSIX. + ['trad-dot1', '+1.', {IN_PIPE=>'a'}, {OUT=>"0000001\n"}], + ['trad-dot512', '+1.b', {IN_PIPE => 'a' x 512}, {OUT=>"0001000\n"}], + # Ensure that a large width does not cause trouble. # From coreutils-7.0 through coreutils-8.21, these would print # approximately 128KiB of padding. -- 2.47.3