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:
parent
98a98ed10e
commit
a2b1df94ad
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user