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 <frodef@acm.org>
Reviewed by:	bde
This commit is contained in:
sheldonh 1999-07-22 17:11:59 +00:00
parent 98a98ed10e
commit a2b1df94ad
2 changed files with 97 additions and 19 deletions

View File

@ -30,7 +30,7 @@
.\" SUCH DAMAGE. .\" SUCH DAMAGE.
.\" .\"
.\" @(#)jot.1 8.1 (Berkeley) 6/6/93 .\" @(#)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 .Dd June 6, 1993
.Dt JOT 1 .Dt JOT 1
@ -191,3 +191,17 @@ and to print all lines 80 characters or longer,
.Xr yes 1 , .Xr yes 1 ,
.Xr printf 3 , .Xr printf 3 ,
.Xr random 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.

View File

@ -42,7 +42,7 @@ static const char copyright[] =
static char sccsid[] = "@(#)jot.c 8.1 (Berkeley) 6/6/93"; static char sccsid[] = "@(#)jot.c 8.1 (Berkeley) 6/6/93";
#endif #endif
static const char rcsid[] = 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 */ #endif /* not lint */
/* /*
@ -75,8 +75,9 @@ int randomize;
int infinity; int infinity;
int boring; int boring;
int prec; int prec;
int dox; int intdata;
int chardata; int chardata;
int nosign;
int nofinalnl; int nofinalnl;
char *sepstring = "\n"; char *sepstring = "\n";
char format[BUFSIZ]; char format[BUFSIZ];
@ -105,8 +106,7 @@ main(argc, argv)
*y = (double) arc4random() / ULONG_MAX; *y = (double) arc4random() / ULONG_MAX;
putdata(*y * *x + begin, reps - *i); putdata(*y * *x + begin, reps - *i);
} }
} } else
else
for (*i = 1, *x = begin; *i <= reps || infinity; (*i)++, *x += s) for (*i = 1, *x = begin; *i <= reps || infinity; (*i)++, *x += s)
putdata(*x, reps - *i); putdata(*x, reps - *i);
if (!nofinalnl) if (!nofinalnl)
@ -310,13 +310,15 @@ putdata(x, notlast)
double x; double x;
long notlast; long notlast;
{ {
long d = x;
register long *dp = &d;
if (boring) /* repeated word */ if (boring) /* repeated word */
printf(format); printf(format);
else if (dox) /* scalar */ else if (chardata) /* character representation */
printf(format, *dp); printf(format, (int)x);
else if (intdata && nosign) /* scalar */
printf(format, (unsigned long)x);
else if (intdata)
printf(format, (long)x);
else /* real */ else /* real */
printf(format, x); printf(format, x);
if (notlast != 0) if (notlast != 0)
@ -354,6 +356,8 @@ void
getformat() getformat()
{ {
register char *p; register char *p;
int dot, hash, space, sign, numbers, islong = 0;
char *s;
if (boring) /* no need to bother */ if (boring) /* no need to bother */
return; return;
@ -364,23 +368,83 @@ getformat()
sprintf(p, "%%.%df", prec); sprintf(p, "%%.%df", prec);
else if (!*p && chardata) { else if (!*p && chardata) {
strcpy(p, "%c"); strcpy(p, "%c");
dox = 1; intdata = 1;
} } else if (!*(p+1))
else if (!*(p+1))
strcat(format, "%"); /* cannot end in single '%' */ strcat(format, "%"); /* cannot end in single '%' */
else { else {
while (!isalpha(*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++; 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) { 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; 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': case 's':
errx(1, "cannot convert numeric data to strings"); errx(1, "cannot convert numeric data to strings");
break; break;
/* case 'd': case 'o': case 'x': case 'D': case 'O': case 'X': case 'h': case 'n': case 'p': case 'q': case 'L':
case 'c': case 'u': */ 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: default:
dox = 1; *++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; break;
} }
} }