From 3df6da258c338e4fd165a2850bb8d4b0f39b6e9b Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Fri, 21 Mar 2025 13:15:55 +0100 Subject: [PATCH] parse-duration: Work around an strtoul() misfeature. * lib/parse-duration.c (str_const_to_ul): Reject a + or - sign between the optional whitespace and the digits. * tests/test-parse-duration.sh: Add some tests with expected failure. * tests/test-parse-duration.c (main): Fix usage message. --- ChangeLog | 8 ++++++++ lib/parse-duration.c | 18 ++++++++++++++++-- tests/test-parse-duration.c | 2 +- tests/test-parse-duration.sh | 24 ++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8111c9df7c..78fc19c93e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2025-03-21 Bruno Haible + + parse-duration: Work around an strtoul() misfeature. + * lib/parse-duration.c (str_const_to_ul): Reject a + or - sign between + the optional whitespace and the digits. + * tests/test-parse-duration.sh: Add some tests with expected failure. + * tests/test-parse-duration.c (main): Fix usage message. + 2025-03-21 Bruno Haible mountlist: Add specification comment in .h file. diff --git a/lib/parse-duration.c b/lib/parse-duration.c index 6c5d7e0251..1fe3f845b3 100644 --- a/lib/parse-duration.c +++ b/lib/parse-duration.c @@ -56,11 +56,25 @@ typedef enum { #undef MAX_DURATION #define MAX_DURATION TYPE_MAXIMUM(time_t) -/* Wrapper around strtoul that does not require a cast. */ +/* Wrapper around strtoul that does not allow a sign. */ static unsigned long str_const_to_ul (cch_t * str, cch_t ** ppz, int base) { - return strtoul (str, (char **)ppz, base); + cch_t * orig_str = str; + while (isspace ((unsigned char) *str)) + str++; + if (isdigit ((unsigned char) *str)) + { + unsigned long ret = strtoul (str, (char **)ppz, base); + if (*ppz == str) + *ppz = orig_str; + return ret; + } + else + { + *ppz = orig_str; + return 0; + } } /* Wrapper around strtol that does not require a cast. */ diff --git a/tests/test-parse-duration.c b/tests/test-parse-duration.c index 36c000856f..29ac7732ea 100644 --- a/tests/test-parse-duration.c +++ b/tests/test-parse-duration.c @@ -30,7 +30,7 @@ main (int argc, char *argv[]) { if (--argc <= 0) { - fprintf (stderr, "USAGE: %s [...]", argv[0]); + fprintf (stderr, "USAGE: %s [...]\n", argv[0]); return 1; } diff --git a/tests/test-parse-duration.sh b/tests/test-parse-duration.sh index cf45913261..5b4e01bb21 100755 --- a/tests/test-parse-duration.sh +++ b/tests/test-parse-duration.sh @@ -47,6 +47,7 @@ func_tmpdir trap 'rm -rf "${tmp}"' EXIT tmpf="${tmp}/tests.txt" +# Tests where we expect success. cat > "${tmpf}" <<- _EOF_ 1 Y 2 M 3 W 4 d 5 h 6 m 7 s P 00010225 T 05:06:07 @@ -65,3 +66,26 @@ do test $v -eq 38898367 || die $v is not 38898367 done exec 3>&- + +# Tests where we expect failure. +cat > "${tmpf}" <<- _EOF_ + T-00302 + T-0:3:2 + T-0 H 3 M 2 S + P+04 Y 03 M 02 D + P04 Y +03 M 02 D + P04 Y 03 M +02 D + _EOF_ + +fail=0 +exec 3< "${tmpf}" +while read line <&3 +do + if ${CHECKER} ${exe} "${line}"; then + echo "Succeeded: ${exe} '${line}'" 1>&2 + fail=1 + fi +done +exec 3>&- + +exit $fail -- 2.39.5