bug-make
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 1/2] Use strtol instead of atoi


From: Jouke Witteveen
Subject: [PATCH 1/2] Use strtol instead of atoi
Date: Mon, 8 Jun 2020 22:20:39 +0200

strtol is part of C89 and a fallback is provided by gnulib

* src/function.c (func_word, func_wordlist): Use strtol instead of atoi
* test/scripts/functions/word: Add out-of-range verification testing
---

Here is a proposal to start a more thorough support of numerical values.
While earlier discussion indicated that at least 64bit of range is
required, only long integers (guaranteed to have at least 32bit of range)
are part of C89. To keep things simple and compatible, I therefore chose
to use long. Note that on systems where large files (>4GB) may be
encountered, it is not unlikely for long to support 64bit of range.

In the code below, I have added a strtol line to bootstrap.conf. I am
completely unsure whether this is needed or even supported. My thought was
that gnulib provides a fallback strtol implementation for systems with
incomplete C89 support. Someone more knowledgable of gnulib should verify
this.

One change that these changes bring about is that a sign (+ or -) in front
of a numerical value is now supported.

 bootstrap.conf               |  1 +
 src/function.c               | 49 ++++++++++++++++++------------------
 tests/scripts/functions/word | 12 ++++++---
 3 files changed, 35 insertions(+), 27 deletions(-)

diff --git a/bootstrap.conf b/bootstrap.conf
index 7c4c9ab..c9c3668 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -50,4 +50,5 @@ findprog-in
 getloadavg
 host-cpu-c-abi
 strerror
+strtol
 make-glob"
diff --git a/src/function.c b/src/function.c
index 0917e0c..ccad300 100644
--- a/src/function.c
+++ b/src/function.c
@@ -766,19 +766,24 @@ 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);
-
-  for (; s <= end; ++s)
-    if (!ISDIGIT (*s))  /* ISDIGIT only evals its arg once: see makeint.h.  */
-      break;
+  const char *end = s + strlen (s) - 1;
+  char *endp;
+  long num;
+  strip_whitespace (&beg, &end);
 
-  if (s <= end || end - beg < 0)
-    OSS (fatal, *expanding_var, "%s: '%s'", msg, beg);
+  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);
+
+  return num;
 }
 
 
@@ -788,13 +793,11 @@ 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"));
 
@@ -812,20 +815,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);
 
-  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 4dcc940..044bc94 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
-- 
2.27.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]