* printcmd.c (printf_command): Make format string checking

stricter.  Add separate cases for long_arg, ptr_arg, and
	long_double_arg.
	* utils.c (xstrvprintf): Improve the error message issued
	for a bad format string.
	* Makefile.in (GDB_WARN_CFLAGS_NO_FORMAT, INTERNAL_CFLAGS_BASE):
	New variables.
	(gnu-v3-abi.o, monitor.o, procfs.o, linux-thread-db.o): Remove
	$(NO_WERROR_CFLAGS).
	(printcmd.o): Likewise.  Use $(GDB_WARN_CFLAGS_NO_FORMAT) and
	enable -Werror.
This commit is contained in:
Daniel Jacobowitz 2006-02-02 02:26:48 +00:00
parent 37a105a123
commit 46e9880c62
4 changed files with 184 additions and 48 deletions

View file

@ -1836,13 +1836,13 @@ printf_command (char *arg, int from_tty)
enum argclass
{
no_arg, int_arg, string_arg, double_arg, long_long_arg
int_arg, long_arg, long_long_arg, ptr_arg, string_arg,
double_arg, long_double_arg
};
enum argclass *argclass;
enum argclass this_argclass;
char *last_arg;
int nargs_wanted;
int lcount;
int i;
argclass = (enum argclass *) alloca (strlen (s) * sizeof *argclass);
@ -1852,23 +1852,136 @@ printf_command (char *arg, int from_tty)
while (*f)
if (*f++ == '%')
{
lcount = 0;
while (strchr ("0123456789.hlL-+ #", *f))
int seen_hash = 0, seen_zero = 0, lcount = 0, seen_prec = 0;
int seen_space = 0, seen_plus = 0;
int seen_big_l = 0, seen_h = 0;
int bad = 0;
/* Check the validity of the format specifier, and work
out what argument it expects. We only accept C89
format strings, with the exception of long long (which
we autoconf for). */
/* Skip over "%%". */
if (*f == '%')
{
if (*f == 'l' || *f == 'L')
lcount++;
f++;
continue;
}
/* The first part of a format specifier is a set of flag
characters. */
while (strchr ("0-+ #", *f))
{
if (*f == '#')
seen_hash = 1;
else if (*f == '0')
seen_zero = 1;
else if (*f == ' ')
seen_space = 1;
else if (*f == '+')
seen_plus = 1;
f++;
}
/* The next part of a format specifier is a width. */
while (strchr ("0123456789", *f))
f++;
/* The next part of a format specifier is a precision. */
if (*f == '.')
{
seen_prec = 1;
f++;
while (strchr ("0123456789", *f))
f++;
}
/* The next part of a format specifier is a length modifier. */
if (*f == 'h')
{
seen_h = 1;
f++;
}
else if (*f == 'l')
{
f++;
lcount++;
if (*f == 'l')
{
f++;
lcount++;
}
}
else if (*f == 'L')
{
seen_big_l = 1;
f++;
}
switch (*f)
{
case 'u':
if (seen_hash)
bad = 1;
/* FALLTHROUGH */
case 'o':
case 'x':
case 'X':
if (seen_space || seen_plus)
bad = 1;
/* FALLTHROUGH */
case 'd':
case 'i':
if (lcount == 0)
this_argclass = int_arg;
else if (lcount == 1)
this_argclass = long_arg;
else
this_argclass = long_long_arg;
if (seen_big_l)
bad = 1;
break;
case 'c':
this_argclass = int_arg;
if (lcount || seen_h || seen_big_l)
bad = 1;
if (seen_prec || seen_zero || seen_space || seen_plus)
bad = 1;
break;
case 'p':
this_argclass = ptr_arg;
if (lcount || seen_h || seen_big_l)
bad = 1;
if (seen_prec || seen_zero || seen_space || seen_plus)
bad = 1;
break;
case 's':
this_argclass = string_arg;
if (lcount || seen_h || seen_big_l)
bad = 1;
if (seen_zero || seen_space || seen_plus)
bad = 1;
break;
case 'e':
case 'f':
case 'g':
this_argclass = double_arg;
case 'E':
case 'G':
if (seen_big_l)
this_argclass = long_double_arg;
else
this_argclass = double_arg;
if (lcount || seen_h)
bad = 1;
break;
case '*':
@ -1877,26 +1990,23 @@ printf_command (char *arg, int from_tty)
case 'n':
error (_("Format specifier `n' not supported in printf"));
case '%':
this_argclass = no_arg;
break;
case '\0':
error (_("Incomplete format specifier at end of format string"));
default:
if (lcount > 1)
this_argclass = long_long_arg;
else
this_argclass = int_arg;
break;
error (_("Unrecognized format specifier '%c' in printf"), *f);
}
if (bad)
error (_("Inappropriate modifiers to format specifier '%c' in printf"),
*f);
f++;
if (this_argclass != no_arg)
{
strncpy (current_substring, last_arg, f - last_arg);
current_substring += f - last_arg;
*current_substring++ = '\0';
last_arg = f;
argclass[nargs_wanted++] = this_argclass;
}
strncpy (current_substring, last_arg, f - last_arg);
current_substring += f - last_arg;
*current_substring++ = '\0';
last_arg = f;
argclass[nargs_wanted++] = this_argclass;
}
/* Now, parse all arguments and evaluate them.
@ -1970,6 +2080,16 @@ printf_command (char *arg, int from_tty)
printf_filtered (current_substring, val);
break;
}
case long_double_arg:
#ifdef HAVE_LONG_DOUBLE
{
long double val = value_as_double (val_args[i]);
printf_filtered (current_substring, val);
break;
}
#else
error (_("long double not supported in printf"));
#endif
case long_long_arg:
#if defined (CC_HAS_LONG_LONG) && defined (PRINTF_HAS_LONG_LONG)
{
@ -1982,7 +2102,12 @@ printf_command (char *arg, int from_tty)
#endif
case int_arg:
{
/* FIXME: there should be separate int_arg and long_arg. */
int val = value_as_long (val_args[i]);
printf_filtered (current_substring, val);
break;
}
case long_arg:
{
long val = value_as_long (val_args[i]);
printf_filtered (current_substring, val);
break;