* 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:
parent
37a105a123
commit
46e9880c62
4 changed files with 184 additions and 48 deletions
|
@ -1,3 +1,17 @@
|
||||||
|
2006-02-01 Daniel Jacobowitz <dan@codesourcery.com>
|
||||||
|
|
||||||
|
* 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.
|
||||||
|
|
||||||
2006-02-01 Daniel Jacobowitz <dan@codesourcery.com>
|
2006-02-01 Daniel Jacobowitz <dan@codesourcery.com>
|
||||||
|
|
||||||
* Makefile.in (remote.o): Update.
|
* Makefile.in (remote.o): Update.
|
||||||
|
|
|
@ -132,6 +132,8 @@ WERROR_CFLAGS = @WERROR_CFLAGS@
|
||||||
GDB_WARN_CFLAGS = $(WARN_CFLAGS)
|
GDB_WARN_CFLAGS = $(WARN_CFLAGS)
|
||||||
GDB_WERROR_CFLAGS = $(WERROR_CFLAGS)
|
GDB_WERROR_CFLAGS = $(WERROR_CFLAGS)
|
||||||
|
|
||||||
|
GDB_WARN_CFLAGS_NO_FORMAT = `echo " $(GDB_WARN_CFLAGS) " | sed "s/ -Wformat-nonliteral / /g"`
|
||||||
|
|
||||||
# Where is the INTL library? Typically in ../intl.
|
# Where is the INTL library? Typically in ../intl.
|
||||||
INTL_DIR = ../intl
|
INTL_DIR = ../intl
|
||||||
INTL = @INTLLIBS@
|
INTL = @INTLLIBS@
|
||||||
|
@ -344,12 +346,12 @@ CFLAGS = @CFLAGS@
|
||||||
CXXFLAGS = -g -O
|
CXXFLAGS = -g -O
|
||||||
|
|
||||||
# INTERNAL_CFLAGS is the aggregate of all other *CFLAGS macros.
|
# INTERNAL_CFLAGS is the aggregate of all other *CFLAGS macros.
|
||||||
INTERNAL_WARN_CFLAGS = \
|
INTERNAL_CFLAGS_BASE = \
|
||||||
$(CFLAGS) $(GLOBAL_CFLAGS) $(PROFILE_CFLAGS) \
|
$(CFLAGS) $(GLOBAL_CFLAGS) $(PROFILE_CFLAGS) \
|
||||||
$(GDB_CFLAGS) $(OPCODES_CFLAGS) $(READLINE_CFLAGS) \
|
$(GDB_CFLAGS) $(OPCODES_CFLAGS) $(READLINE_CFLAGS) \
|
||||||
$(BFD_CFLAGS) $(INCLUDE_CFLAGS) \
|
$(BFD_CFLAGS) $(INCLUDE_CFLAGS) \
|
||||||
$(INTL_CFLAGS) $(ENABLE_CFLAGS) \
|
$(INTL_CFLAGS) $(ENABLE_CFLAGS)
|
||||||
$(GDB_WARN_CFLAGS)
|
INTERNAL_WARN_CFLAGS = $(INTERNAL_CFLAGS_BASE) $(GDB_WARN_CFLAGS)
|
||||||
INTERNAL_CFLAGS = $(INTERNAL_WARN_CFLAGS) $(GDB_WERROR_CFLAGS)
|
INTERNAL_CFLAGS = $(INTERNAL_WARN_CFLAGS) $(GDB_WERROR_CFLAGS)
|
||||||
|
|
||||||
# LDFLAGS is specifically reserved for setting from the command line
|
# LDFLAGS is specifically reserved for setting from the command line
|
||||||
|
@ -1479,8 +1481,7 @@ main.o: main.c
|
||||||
# return types - "enum gnu_v3_dtor_kinds" vs "enum ctor_kinds" -
|
# return types - "enum gnu_v3_dtor_kinds" vs "enum ctor_kinds" -
|
||||||
# conflict.
|
# conflict.
|
||||||
gnu-v3-abi.o: $(srcdir)/gnu-v3-abi.c
|
gnu-v3-abi.o: $(srcdir)/gnu-v3-abi.c
|
||||||
$(CC) -c $(INTERNAL_WARN_CFLAGS) $(NO_WERROR_CFLAGS) \
|
$(CC) -c $(INTERNAL_WARN_CFLAGS) $(srcdir)/gnu-v3-abi.c
|
||||||
$(srcdir)/gnu-v3-abi.c
|
|
||||||
|
|
||||||
# FIXME: cagney/2003-08-10: "monitor.c" gets -Wformat-nonliteral
|
# FIXME: cagney/2003-08-10: "monitor.c" gets -Wformat-nonliteral
|
||||||
# errors. It turns out that that is the least of monitor.c's
|
# errors. It turns out that that is the least of monitor.c's
|
||||||
|
@ -1489,25 +1490,23 @@ gnu-v3-abi.o: $(srcdir)/gnu-v3-abi.c
|
||||||
# definitly will not work. "monitor.c" needs to be rewritten so that
|
# definitly will not work. "monitor.c" needs to be rewritten so that
|
||||||
# it doesn't use format strings and instead uses callbacks.
|
# it doesn't use format strings and instead uses callbacks.
|
||||||
monitor.o: $(srcdir)/monitor.c
|
monitor.o: $(srcdir)/monitor.c
|
||||||
$(CC) -c $(INTERNAL_WARN_CFLAGS) $(NO_WERROR_CFLAGS) $(srcdir)/monitor.c
|
$(CC) -c $(INTERNAL_WARN_CFLAGS) $(srcdir)/monitor.c
|
||||||
|
|
||||||
# FIXME: cagney/2003-08-10: Do not try to build "printcmd.c" with
|
# Do not try to build "printcmd.c" with -Wformat-nonliteral. It manually
|
||||||
# -Wformat-nonliteral. It needs to be overhauled so that it doesn't
|
# checks format strings.
|
||||||
# pass user input strings as the format parameter to host printf
|
|
||||||
# function calls.
|
|
||||||
printcmd.o: $(srcdir)/printcmd.c
|
printcmd.o: $(srcdir)/printcmd.c
|
||||||
$(CC) -c $(INTERNAL_WARN_CFLAGS) $(NO_WERROR_CFLAGS) $(srcdir)/printcmd.c
|
$(CC) -c $(INTERNAL_CFLAGS_BASE) $(GDB_WARN_CFLAGS_NO_FORMAT) \
|
||||||
|
$(GDB_WERROR_CFLAGS) $(srcdir)/printcmd.c
|
||||||
|
|
||||||
# FIXME: Procfs.o gets -Wformat errors because things like pid_t don't
|
# FIXME: Procfs.o gets -Wformat errors because things like pid_t don't
|
||||||
# match output format strings.
|
# match output format strings.
|
||||||
procfs.o: $(srcdir)/procfs.c
|
procfs.o: $(srcdir)/procfs.c
|
||||||
$(CC) -c $(INTERNAL_WARN_CFLAGS) $(NO_WERROR_CFLAGS) $(srcdir)/procfs.c
|
$(CC) -c $(INTERNAL_WARN_CFLAGS) $(srcdir)/procfs.c
|
||||||
|
|
||||||
# FIXME: Thread-db.o gets warnings because the definitions of the register
|
# FIXME: Thread-db.o gets warnings because the definitions of the register
|
||||||
# sets are different from kernel to kernel.
|
# sets are different from kernel to kernel.
|
||||||
linux-thread-db.o: $(srcdir)/linux-thread-db.c
|
linux-thread-db.o: $(srcdir)/linux-thread-db.c
|
||||||
$(CC) -c $(INTERNAL_WARN_CFLAGS) $(NO_WERROR_CFLAGS) \
|
$(CC) -c $(INTERNAL_WARN_CFLAGS) $(srcdir)/linux-thread-db.c
|
||||||
$(srcdir)/linux-thread-db.c
|
|
||||||
|
|
||||||
v850ice.o: $(srcdir)/v850ice.c
|
v850ice.o: $(srcdir)/v850ice.c
|
||||||
$(CC) -c $(INTERNAL_CFLAGS) $(IDE_CFLAGS) $(ITCL_CFLAGS) \
|
$(CC) -c $(INTERNAL_CFLAGS) $(IDE_CFLAGS) $(ITCL_CFLAGS) \
|
||||||
|
|
161
gdb/printcmd.c
161
gdb/printcmd.c
|
@ -1836,13 +1836,13 @@ printf_command (char *arg, int from_tty)
|
||||||
|
|
||||||
enum argclass
|
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 *argclass;
|
||||||
enum argclass this_argclass;
|
enum argclass this_argclass;
|
||||||
char *last_arg;
|
char *last_arg;
|
||||||
int nargs_wanted;
|
int nargs_wanted;
|
||||||
int lcount;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
argclass = (enum argclass *) alloca (strlen (s) * sizeof *argclass);
|
argclass = (enum argclass *) alloca (strlen (s) * sizeof *argclass);
|
||||||
|
@ -1852,23 +1852,136 @@ printf_command (char *arg, int from_tty)
|
||||||
while (*f)
|
while (*f)
|
||||||
if (*f++ == '%')
|
if (*f++ == '%')
|
||||||
{
|
{
|
||||||
lcount = 0;
|
int seen_hash = 0, seen_zero = 0, lcount = 0, seen_prec = 0;
|
||||||
while (strchr ("0123456789.hlL-+ #", *f))
|
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')
|
f++;
|
||||||
lcount++;
|
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++;
|
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)
|
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':
|
case 's':
|
||||||
this_argclass = string_arg;
|
this_argclass = string_arg;
|
||||||
|
if (lcount || seen_h || seen_big_l)
|
||||||
|
bad = 1;
|
||||||
|
if (seen_zero || seen_space || seen_plus)
|
||||||
|
bad = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'e':
|
case 'e':
|
||||||
case 'f':
|
case 'f':
|
||||||
case 'g':
|
case 'g':
|
||||||
|
case 'E':
|
||||||
|
case 'G':
|
||||||
|
if (seen_big_l)
|
||||||
|
this_argclass = long_double_arg;
|
||||||
|
else
|
||||||
this_argclass = double_arg;
|
this_argclass = double_arg;
|
||||||
|
|
||||||
|
if (lcount || seen_h)
|
||||||
|
bad = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '*':
|
case '*':
|
||||||
|
@ -1877,27 +1990,24 @@ printf_command (char *arg, int from_tty)
|
||||||
case 'n':
|
case 'n':
|
||||||
error (_("Format specifier `n' not supported in printf"));
|
error (_("Format specifier `n' not supported in printf"));
|
||||||
|
|
||||||
case '%':
|
case '\0':
|
||||||
this_argclass = no_arg;
|
error (_("Incomplete format specifier at end of format string"));
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (lcount > 1)
|
error (_("Unrecognized format specifier '%c' in printf"), *f);
|
||||||
this_argclass = long_long_arg;
|
|
||||||
else
|
|
||||||
this_argclass = int_arg;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bad)
|
||||||
|
error (_("Inappropriate modifiers to format specifier '%c' in printf"),
|
||||||
|
*f);
|
||||||
|
|
||||||
f++;
|
f++;
|
||||||
if (this_argclass != no_arg)
|
|
||||||
{
|
|
||||||
strncpy (current_substring, last_arg, f - last_arg);
|
strncpy (current_substring, last_arg, f - last_arg);
|
||||||
current_substring += f - last_arg;
|
current_substring += f - last_arg;
|
||||||
*current_substring++ = '\0';
|
*current_substring++ = '\0';
|
||||||
last_arg = f;
|
last_arg = f;
|
||||||
argclass[nargs_wanted++] = this_argclass;
|
argclass[nargs_wanted++] = this_argclass;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Now, parse all arguments and evaluate them.
|
/* Now, parse all arguments and evaluate them.
|
||||||
Store the VALUEs in VAL_ARGS. */
|
Store the VALUEs in VAL_ARGS. */
|
||||||
|
@ -1970,6 +2080,16 @@ printf_command (char *arg, int from_tty)
|
||||||
printf_filtered (current_substring, val);
|
printf_filtered (current_substring, val);
|
||||||
break;
|
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:
|
case long_long_arg:
|
||||||
#if defined (CC_HAS_LONG_LONG) && defined (PRINTF_HAS_LONG_LONG)
|
#if defined (CC_HAS_LONG_LONG) && defined (PRINTF_HAS_LONG_LONG)
|
||||||
{
|
{
|
||||||
|
@ -1982,7 +2102,12 @@ printf_command (char *arg, int from_tty)
|
||||||
#endif
|
#endif
|
||||||
case int_arg:
|
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]);
|
long val = value_as_long (val_args[i]);
|
||||||
printf_filtered (current_substring, val);
|
printf_filtered (current_substring, val);
|
||||||
break;
|
break;
|
||||||
|
|
18
gdb/utils.c
18
gdb/utils.c
|
@ -1,8 +1,8 @@
|
||||||
/* General utility routines for GDB, the GNU debugger.
|
/* General utility routines for GDB, the GNU debugger.
|
||||||
|
|
||||||
Copyright (C) 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
|
Copyright (C) 1986, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
|
||||||
1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free
|
1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
|
||||||
Software Foundation, Inc.
|
Free Software Foundation, Inc.
|
||||||
|
|
||||||
This file is part of GDB.
|
This file is part of GDB.
|
||||||
|
|
||||||
|
@ -1069,14 +1069,12 @@ xstrvprintf (const char *format, va_list ap)
|
||||||
{
|
{
|
||||||
char *ret = NULL;
|
char *ret = NULL;
|
||||||
int status = vasprintf (&ret, format, ap);
|
int status = vasprintf (&ret, format, ap);
|
||||||
/* NULL is returned when there was a memory allocation problem. */
|
/* NULL is returned when there was a memory allocation problem, or
|
||||||
if (ret == NULL)
|
any other error (for instance, a bad format string). A negative
|
||||||
nomem (0);
|
status (the printed length) with a non-NULL buffer should never
|
||||||
/* A negative status (the printed length) with a non-NULL buffer
|
happen, but just to be sure. */
|
||||||
should never happen, but just to be sure. */
|
if (ret == NULL || status < 0)
|
||||||
if (status < 0)
|
internal_error (__FILE__, __LINE__, _("vasprintf call failed"));
|
||||||
internal_error (__FILE__, __LINE__,
|
|
||||||
_("vasprintf call failed (errno %d)"), errno);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue