Module Name: src Committed By: kre Date: Sun Nov 24 12:33:00 UTC 2024
Modified Files: src/usr.bin/printf: printf.c Log Message: Improve detection and diagnosis of invalid values for conversions. (In particular, integer conversions contain no spaces, and must always contain at least 1 digit, '' is not valid). To generate a diff of this commit: cvs rdiff -u -r1.58 -r1.59 src/usr.bin/printf/printf.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/usr.bin/printf/printf.c diff -u src/usr.bin/printf/printf.c:1.58 src/usr.bin/printf/printf.c:1.59 --- src/usr.bin/printf/printf.c:1.58 Wed Aug 7 15:40:03 2024 +++ src/usr.bin/printf/printf.c Sun Nov 24 12:33:00 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: printf.c,v 1.58 2024/08/07 15:40:03 kre Exp $ */ +/* $NetBSD: printf.c,v 1.59 2024/11/24 12:33:00 kre Exp $ */ /* * Copyright (c) 1989, 1993 @@ -41,7 +41,7 @@ __COPYRIGHT("@(#) Copyright (c) 1989, 19 #if 0 static char sccsid[] = "@(#)printf.c 8.2 (Berkeley) 3/22/95"; #else -__RCSID("$NetBSD: printf.c,v 1.58 2024/08/07 15:40:03 kre Exp $"); +__RCSID("$NetBSD: printf.c,v 1.59 2024/11/24 12:33:00 kre Exp $"); #endif #endif /* not lint */ @@ -84,9 +84,11 @@ static size_t b_length; static char *b_fmt; static int rval; -static char **gargv; +static char ** gargv, ** firstarg; static int long_double; +#define ARGNUM ((int)(gargv - firstarg)) + #ifdef BUILTIN /* csh builtin */ #define main progprintf #endif @@ -124,6 +126,7 @@ static int long_double; #define octtobin(c) ((c) - '0') #define check(c, a) (c) >= (a) && (c) <= (a) + 5 ? (c) - (a) + 10 #define hextobin(c) (check(c, 'a') : check(c, 'A') : (c) - '0') + #ifdef main int main(int, char *[]); #endif @@ -199,7 +202,7 @@ main(int argc, char *argv[]) } format = *argv; /* First remaining arg is the format string */ - gargv = ++argv; /* remaining args are for that to consume */ + firstarg = gargv = ++argv; /* remaining args are for that to consume */ #define SKIP1 "#-+ 0'" #define SKIP2 "0123456789" @@ -217,6 +220,7 @@ main(int argc, char *argv[]) for (fmt = format; (ch = *fmt++) != '\0';) { if (ch == '\\') { char c_ch; + fmt = conv_escape(fmt, &c_ch, 0); putchar(c_ch); continue; @@ -409,14 +413,14 @@ main(int argc, char *argv[]) } } while (gargv != argv && *gargv); - done: + done:; (void)fflush(stdout); if (ferror(stdout)) { clearerr(stdout); err(1, "write error"); } return rval & ~0x100; - out: + out:; warn("print failed"); return 1; } @@ -482,6 +486,7 @@ conv_escape_str(char *str, void (*do_put */ if (ch == '0') { int octnum = 0, i; + for (i = 0; i < 3; i++) { if (!isdigit((unsigned char)*str) || *str > '7') break; @@ -690,6 +695,7 @@ static char * getstr(void) { static char empty[] = ""; + if (!*gargv) return empty; return *gargv++; @@ -708,11 +714,18 @@ getwidth(void) errno = 0; val = strtoul(s, &ep, 0); - check_conversion(s, ep); + if (!isdigit(*(unsigned char *)s)) { + warnx("Arg %d: '%s' value for '*' width/precision" + " must be an unsigned integer", ARGNUM, s); + rval = 1; + val = 0; + } else + check_conversion(s, ep); /* Arbitrarily 'restrict' field widths to 1Mbyte */ if (val > 1 << 20) { - warnx("%s: invalid field width", s); + warnx("Arg %d: %s: invalid field width/precision", ARGNUM, s); + rval = 1; return 0; } @@ -735,7 +748,11 @@ getintmax(void) errno = 0; val = strtoimax(cp, &ep, 0); - check_conversion(cp, ep); + if (*cp != '+' && *cp != '-' && !isdigit(*(unsigned char *)cp)) { + warnx("Arg %d: '%s' numeric value required", ARGNUM, cp); + rval = 1; + } else + check_conversion(cp, ep); return val; } @@ -780,10 +797,11 @@ wide_char(const char *p, int all) (void)mbtowc(NULL, NULL, 0); n = mbtowc(&wch, p + all, (len = strlen(p + all)) + 1); if (n < 0) { - warn("%s", p); - rval = -1; + warn("Arg %d: %s", ARGNUM, p); + rval = 1; } else if (all && (size_t)n != len) { - warnx("%s: not completely converted", p); + warnx("Arg %d: %s: not completely converted", + ARGNUM, p); rval = 1; } @@ -793,14 +811,24 @@ wide_char(const char *p, int all) static void check_conversion(const char *s, const char *ep) { + if (!*s) { + warnx("Arg %d: unexpected empty value ('')", ARGNUM); + rval = 1; + return; + } + if (*ep) { if (ep == s) - warnx("%s: expected numeric value", s); + warnx("Arg %d: %s: numeric value expected", ARGNUM, s); else - warnx("%s: not completely converted", s); + warnx("Arg %d: %s: not completely converted", + ARGNUM, s); rval = 1; - } else if (errno == ERANGE) { - warnx("%s: %s", s, strerror(ERANGE)); + return; + } + + if (errno == ERANGE) { + warnx("Arg %d: %s: %s", ARGNUM, s, strerror(ERANGE)); rval = 1; } }