From a2b1df94ad3af9d024aee5d5312d143cfbd269d3 Mon Sep 17 00:00:00 2001 From: sheldonh Date: Thu, 22 Jul 1999 17:11:59 +0000 Subject: [PATCH] Improve printf(3) conversion specifier parsing so that silly formats aren't allowed and the right casts can be used for printf() statements. Document the conversion specifier limitations and the fact that arithmetic overflow causes a fatal error. PR: 12611 Reported by: Frode Vatvedt Fjeld Reviewed by: bde --- usr.bin/jot/jot.1 | 16 +++++++- usr.bin/jot/jot.c | 100 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 97 insertions(+), 19 deletions(-) diff --git a/usr.bin/jot/jot.1 b/usr.bin/jot/jot.1 index da3928322dc9..d0f0ce457fc2 100644 --- a/usr.bin/jot/jot.1 +++ b/usr.bin/jot/jot.1 @@ -30,7 +30,7 @@ .\" SUCH DAMAGE. .\" .\" @(#)jot.1 8.1 (Berkeley) 6/6/93 -.\" $Id$ +.\" $Id: jot.1,v 1.5 1999/07/12 20:23:37 nik Exp $ .\" .Dd June 6, 1993 .Dt JOT 1 @@ -191,3 +191,17 @@ and to print all lines 80 characters or longer, .Xr yes 1 , .Xr printf 3 , .Xr random 3 +.Sh BUGS +Conversion format specifiers for +.Xr printf 3 +are limited to those of the form +.Dl %[#][ ][{+,-}][0-9]*[.[0-9]*]? +where +.Dq ? +must be one of +.Dl [l]{d,i,o,u,x} +or +.Dl {c,e,f,g,D,E,G,O,U,X} +.Pp +No bounds-checking is performed on numeric values, so arithmetic overflow +will cause a fatal error. diff --git a/usr.bin/jot/jot.c b/usr.bin/jot/jot.c index 5b67862e7998..7dd4261bb12e 100644 --- a/usr.bin/jot/jot.c +++ b/usr.bin/jot/jot.c @@ -42,7 +42,7 @@ static const char copyright[] = static char sccsid[] = "@(#)jot.c 8.1 (Berkeley) 6/6/93"; #endif static const char rcsid[] = - "$Id: jot.c,v 1.8 1997/11/03 07:45:33 charnier Exp $"; + "$Id: jot.c,v 1.9 1999/05/13 12:18:24 kris Exp $"; #endif /* not lint */ /* @@ -75,8 +75,9 @@ int randomize; int infinity; int boring; int prec; -int dox; +int intdata; int chardata; +int nosign; int nofinalnl; char *sepstring = "\n"; char format[BUFSIZ]; @@ -105,8 +106,7 @@ main(argc, argv) *y = (double) arc4random() / ULONG_MAX; putdata(*y * *x + begin, reps - *i); } - } - else + } else for (*i = 1, *x = begin; *i <= reps || infinity; (*i)++, *x += s) putdata(*x, reps - *i); if (!nofinalnl) @@ -310,13 +310,15 @@ putdata(x, notlast) double x; long notlast; { - long d = x; - register long *dp = &d; if (boring) /* repeated word */ printf(format); - else if (dox) /* scalar */ - printf(format, *dp); + else if (chardata) /* character representation */ + printf(format, (int)x); + else if (intdata && nosign) /* scalar */ + printf(format, (unsigned long)x); + else if (intdata) + printf(format, (long)x); else /* real */ printf(format, x); if (notlast != 0) @@ -354,6 +356,8 @@ void getformat() { register char *p; + int dot, hash, space, sign, numbers, islong = 0; + char *s; if (boring) /* no need to bother */ return; @@ -364,24 +368,84 @@ getformat() sprintf(p, "%%.%df", prec); else if (!*p && chardata) { strcpy(p, "%c"); - dox = 1; - } - else if (!*(p+1)) + intdata = 1; + } else if (!*(p+1)) strcat(format, "%"); /* cannot end in single '%' */ else { - while (!isalpha(*p)) - p++; + /* + * Allow conversion format specifiers of the form + * %[#][ ][{+,-}][0-9]*[.[0-9]*]? where ? must be one of + * [l]{d,i,o,u,x} or {f,e,g,E,G,d,o,x,D,O,U,X,c,u} + */ + s = p++; + dot = hash = space = sign = numbers = 0; + while (!isalpha(*p)) { + if (isdigit(*p)) { + numbers++; + p++; + } else if ((*p == '#' && !(numbers|dot|sign|space| + hash++)) || + (*p == ' ' && !(numbers|dot|space++)) || + ((*p == '+' || *p == '-') && !(numbers|dot|sign++)) + || (*p == '.' && !(dot++))) + p++; + else if (*p == '$' || *p == '*') + errx(1, "unsupported format character %c", *p); + else if (*p == '\0') + errx(1, "missing format character"); + else + errx(1, "illegal format character %c", *p); + } switch (*p) { - case 'f': case 'e': case 'g': case '%': + case 'l': + islong = 1; + p++; + /* FALLTHROUGH */ + case 'o': case 'u': case 'x': case 'X': + intdata = nosign = 1; break; + case 'd': case 'i': + intdata = 1; + break; + case 'D': + if (!islong) { + intdata = 1; + break; + } + case 'O': case 'U': + if (!islong) { + intdata = nosign = 1; + break; + } + case 'c': + if (!(intdata | islong)) { + chardata = 1; + break; + } case 's': errx(1, "cannot convert numeric data to strings"); break; - /* case 'd': case 'o': case 'x': case 'D': case 'O': case 'X': - case 'c': case 'u': */ + case 'h': case 'n': case 'p': case 'q': case 'L': + case '$': case '*': + errx(1, "unsupported format character %c", *p); + /* NOTREACHED */ + case 'f': case 'e': case 'g': case 'E': case 'G': + if (!islong) + break; + /* FALLTHROUGH */ default: - dox = 1; - break; + *++p = '\0'; + errx(1, "illegal or unsupported format '%s'", s); + /* NOTREACHED */ } + while (*++p) + if (*p == '%' && *(p+1) && *(p+1) != '%') + errx(1, "too many conversions"); + else if (*p == '%' && *(p+1) == '%') + p++; + else if (*p == '%' && !*(p+1)) { + strcat(format, "%"); + break; + } } }