aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2024-11-18 13:46:33 -0800
committerPaul Eggert <eggert@cs.ucla.edu>2024-11-19 08:41:34 -0800
commita665aa4f6df54806d0e16e3a950791b9a63142cb (patch)
tree8c22036fb589ef151656f4b19263a6120e7e890a
parentprintf: refactor macros to function (diff)
downloadcoreutils-a665aa4f6df54806d0e16e3a950791b9a63142cb.tar.gz
coreutils-a665aa4f6df54806d0e16e3a950791b9a63142cb.zip
printf: do n$ overflow checking by hand
* src/printf.c (get_curr_arg): Mark as pure to pacify GCC 14. Do overflow checking by hand rather than relying on strspn and strtoimax.
-rw-r--r--src/printf.c30
1 files changed, 20 insertions, 10 deletions
diff --git a/src/printf.c b/src/printf.c
index 61b8bc614..488e8e006 100644
--- a/src/printf.c
+++ b/src/printf.c
@@ -452,21 +452,31 @@ struct arg_cursor
int end_arg; /* End arg processed. */
int direc_arg; /* Arg for main directive. */
};
-static struct arg_cursor
+ATTRIBUTE_PURE static struct arg_cursor
get_curr_arg (int pos, struct arg_cursor ac)
{
- intmax_t arg = 0;
- size_t argl;
- /* Check with strspn() first to avoid spaces etc.
- This also avoids any locale ambiguities,
- and simplifies strtoimax errno checking. */
- if (pos < 3 && (argl = strspn (ac.f, "0123456789")) && ac.f[argl] == '$')
- arg = MIN (strtoimax (ac.f, nullptr, 10), INT_MAX);
- if (1 <= arg && arg <= INT_MAX)
+ /* Convert sequences like "123$" by hand to avoid problems with strtol,
+ which might treat "$" as part of the number in some locales. */
+ int arg = 0;
+ char const *f = ac.f;
+ if (pos < 3 && c_isdigit (*f))
+ {
+ bool v = false;
+ int a = *f++ - '0';
+ for (; c_isdigit (*f); f++)
+ {
+ v |= ckd_mul (&a, a, 10);
+ v |= ckd_add (&a, a, *f - '0');
+ }
+ if (*f == '$')
+ arg = v ? INT_MAX : a;
+ }
+
+ if (0 < arg)
{
/* Process indexed %i$ format. */
arg--;
- ac.f += argl + 1;
+ ac.f = f + 1;
if (pos == 0)
ac.direc_arg = arg;
}