From: Paul Eggert Date: Mon, 18 Nov 2024 21:46:33 +0000 (-0800) Subject: printf: do n$ overflow checking by hand X-Git-Tag: v9.6~68 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a665aa4f6df54806d0e16e3a950791b9a63142cb;p=thirdparty%2Fcoreutils.git 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. --- diff --git a/src/printf.c b/src/printf.c index 61b8bc614d..488e8e006a 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; }