From d9291d09b86228afd547d845460ba5b91577645f Mon Sep 17 00:00:00 2001 From: Jouke Witteveen Date: Fri, 16 Jul 2021 14:04:33 +0200 Subject: [PATCH] Use strtol() instead of atoi() strtol() is part of C89 and a fallback is provided by gnulib. * src/function.c (func_word, func_wordlist): Change atoi to strtol. * test/scripts/functions/word: Add out-of-range verification testing. --- bootstrap.conf | 1 + src/function.c | 51 ++++++++++++++++++------------------ tests/scripts/functions/word | 12 ++++++--- 3 files changed, 35 insertions(+), 29 deletions(-) diff --git a/bootstrap.conf b/bootstrap.conf index bd37f1b9..69058aa0 100644 --- a/bootstrap.conf +++ b/bootstrap.conf @@ -51,4 +51,5 @@ getloadavg host-cpu-c-abi mempcpy strerror +strtol make-glob" diff --git a/src/function.c b/src/function.c index 5a7ad3a5..b870cbff 100644 --- a/src/function.c +++ b/src/function.c @@ -765,35 +765,36 @@ strip_whitespace (const char **begpp, const char **endpp) return (char *)*begpp; } -static void -check_numeric (const char *s, const char *msg) +static long +parse_numeric (const char *s, const char *msg) { - const char *end = s + strlen (s) - 1; const char *beg = s; - strip_whitespace (&s, &end); + const char *end = s + strlen (s) - 1; + char *endp; + long num; + strip_whitespace (&beg, &end); - for (; s <= end; ++s) - if (!ISDIGIT (*s)) /* ISDIGIT only evals its arg once: see makeint.h. */ - break; + errno = 0; + num = strtol (beg, &endp, 10); + if (errno == ERANGE) + OSS (fatal, *expanding_var, "%s: '%s'", strerror (errno), s); + else if (endp == beg || endp <= end) + /* Empty or non-numeric input */ + OSS (fatal, *expanding_var, "%s: '%s'", msg, s); - if (s <= end || end - beg < 0) - OSS (fatal, *expanding_var, "%s: '%s'", msg, beg); + return num; } - - static char * func_word (char *o, char **argv, const char *funcname UNUSED) { const char *end_p; const char *p; - int i; + long i; - /* Check the first argument. */ - check_numeric (argv[0], _("non-numeric first argument to 'word' function")); - i = atoi (argv[0]); - - if (i == 0) + i = parse_numeric (argv[0], + _("non-numeric first argument to 'word' function")); + if (i <= 0) O (fatal, *expanding_var, _("first argument to 'word' function must be greater than 0")); @@ -811,20 +812,18 @@ func_word (char *o, char **argv, const char *funcname UNUSED) static char * func_wordlist (char *o, char **argv, const char *funcname UNUSED) { - int start, count; + long start, stop, count; - /* Check the arguments. */ - check_numeric (argv[0], - _("non-numeric first argument to 'wordlist' function")); - check_numeric (argv[1], - _("non-numeric second argument to 'wordlist' function")); + start = parse_numeric (argv[0], + _("non-numeric first argument to 'wordlist' function")); + stop = parse_numeric (argv[1], + _("non-numeric second argument to 'wordlist' function")); - start = atoi (argv[0]); if (start < 1) ON (fatal, *expanding_var, - "invalid first argument to 'wordlist' function: '%d'", start); + "invalid first argument to 'wordlist' function: '%ld'", start); - count = atoi (argv[1]) - start + 1; + count = stop - start + 1; if (count > 0) { diff --git a/tests/scripts/functions/word b/tests/scripts/functions/word index 4dcc9406..044bc947 100644 --- a/tests/scripts/functions/word +++ b/tests/scripts/functions/word @@ -51,6 +51,7 @@ run_make_test('FOO = foo bar biz baz word-e1: ; @echo $(word ,$(FOO)) word-e2: ; @echo $(word abc ,$(FOO)) word-e3: ; @echo $(word 1a,$(FOO)) +word-e4: ; @echo $(word 9999999999999999999,$(FOO)) wordlist-e1: ; @echo $(wordlist ,,$(FOO)) wordlist-e2: ; @echo $(wordlist abc ,,$(FOO)) @@ -69,19 +70,24 @@ run_make_test(undef, "#MAKEFILE#:5: *** non-numeric first argument to 'word' function: '1a'. Stop.", 512); +run_make_test(undef, + 'word-e4', + "#MAKEFILE#:6: *** Numerical result out of range: '9999999999999999999'. Stop.", + 512); + run_make_test(undef, 'wordlist-e1', - "#MAKEFILE#:7: *** non-numeric first argument to 'wordlist' function: ''. Stop.", + "#MAKEFILE#:8: *** non-numeric first argument to 'wordlist' function: ''. Stop.", 512); run_make_test(undef, 'wordlist-e2', - "#MAKEFILE#:8: *** non-numeric first argument to 'wordlist' function: 'abc '. Stop.", + "#MAKEFILE#:9: *** non-numeric first argument to 'wordlist' function: 'abc '. Stop.", 512); run_make_test(undef, 'wordlist-e3', - "#MAKEFILE#:9: *** non-numeric second argument to 'wordlist' function: ' 12a '. Stop.", + "#MAKEFILE#:10: *** non-numeric second argument to 'wordlist' function: ' 12a '. Stop.", 512); # Test error conditions again, but this time in a variable reference