1
0
mirror of https://git.FreeBSD.org/ports.git synced 2024-12-28 05:29:48 +00:00

Add "-Wnon-const-format" which checks for non-constant format strings for

auditing purposes.

Submitted by:	kris
Obtained from:	NetBSD
This commit is contained in:
David E. O'Brien 2000-11-27 01:12:33 +00:00
parent 55612f9987
commit 339e20ffc2
Notes: svn2git 2021-03-31 03:12:20 +00:00
svn path=/head/; revision=35457
7 changed files with 410 additions and 50 deletions

View File

@ -1,15 +1,15 @@
--- gcc/c-common.c.orig Mon Feb 15 16:40:05 1999
+++ gcc/c-common.c Tue Mar 30 03:35:22 1999
@@ -61,7 +61,7 @@
--- gcc/c-common.c.orig Tue Sep 7 01:11:16 1999
+++ gcc/c-common.c Sun Nov 26 15:35:38 2000
@@ -64,7 +64,7 @@
int, int, int));
static void init_attributes PROTO((void));
static void record_function_format PROTO((tree, tree, enum format_type,
- int, int));
+ int, int, int));
static void record_international_format PROTO((tree, tree, int));
/* Keep a stack of if statements. We record the number of compound
@@ -669,6 +669,7 @@
static tree c_find_base_decl PROTO((tree));
static int default_valid_lang_attribute PROTO ((tree, tree, tree, tree));
@@ -715,6 +715,7 @@
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
int format_num;
int first_arg_num;
@ -17,7 +17,7 @@
enum format_type format_type;
tree argument;
int arg_num;
@@ -682,7 +683,7 @@
@@ -728,7 +729,7 @@
if (TREE_CODE (format_type_id) != IDENTIFIER_NODE)
{
@ -26,8 +26,8 @@
continue;
}
else
@@ -690,12 +691,26 @@
char *p = IDENTIFIER_POINTER (format_type_id);
@@ -736,12 +737,26 @@
const char *p = IDENTIFIER_POINTER (format_type_id);
if (!strcmp (p, "printf") || !strcmp (p, "__printf__"))
+ {
@ -52,8 +52,8 @@
+ }
else
{
error ("`%s' is an unrecognized format function type", p);
@@ -766,7 +781,8 @@
warning ("`%s' is an unrecognized format function type", p);
@@ -812,7 +827,8 @@
record_function_format (DECL_NAME (decl),
DECL_ASSEMBLER_NAME (decl),
@ -63,7 +63,7 @@
break;
}
@@ -1010,6 +1026,11 @@
@@ -1090,6 +1106,11 @@
} format_char_info;
static format_char_info print_char_table[] = {
@ -75,7 +75,7 @@
{ "di", 0, T_I, T_I, T_I, T_L, T_LL, T_LL, T_ST, "-wp0 +" },
{ "oxX", 0, T_UI, T_UI, T_UI, T_UL, T_ULL, T_ULL, T_ST, "-wp0#" },
{ "u", 0, T_UI, T_UI, T_UI, T_UL, T_ULL, T_ULL, T_ST, "-wp0" },
@@ -1070,6 +1091,7 @@
@@ -1150,6 +1171,7 @@
tree name; /* identifier such as "printf" */
tree assembler_name; /* optional mangled identifier (for C++) */
enum format_type format_type; /* type of format (printf, scanf, etc.) */
@ -83,7 +83,7 @@
int format_num; /* number of format argument */
int first_arg_num; /* number of first arg (zero for varargs) */
} function_format_info;
@@ -1102,25 +1124,25 @@
@@ -1182,25 +1204,25 @@
init_function_format_info ()
{
record_function_format (get_identifier ("printf"), NULL_TREE,
@ -119,7 +119,7 @@
record_international_format (get_identifier ("gettext"), NULL_TREE, 1);
record_international_format (get_identifier ("dgettext"), NULL_TREE, 2);
@@ -1137,11 +1159,12 @@
@@ -1217,11 +1239,12 @@
(e.g. for varargs such as vfprintf). */
static void
@ -133,7 +133,7 @@
int format_num;
int first_arg_num;
{
@@ -1165,6 +1188,7 @@
@@ -1245,6 +1268,7 @@
}
info->format_type = format_type;
@ -141,17 +141,150 @@
info->format_num = format_num;
info->first_arg_num = first_arg_num;
}
@@ -1314,7 +1338,8 @@
@@ -1292,6 +1316,21 @@
warning ("too few arguments for format");
}
+static function_format_info *
+find_function_format (name, assembler_name)
+ tree name;
+ tree assembler_name;
+{
+ function_format_info *info;
+
+ for (info = function_format_list; info; info = info->next)
+ if (info->assembler_name
+ ? (info->assembler_name == assembler_name)
+ : (info->name == name))
+ return info;
+ return 0;
+}
+
/* Check the argument list of a call to printf, scanf, etc.
NAME is the function identifier.
ASSEMBLER_NAME is the function's assembler identifier.
@@ -1307,17 +1346,10 @@
function_format_info *info;
/* See if this function is a format function. */
- for (info = function_format_list; info; info = info->next)
- {
- if (info->assembler_name
- ? (info->assembler_name == assembler_name)
- : (info->name == name))
- {
- /* Yup; check it. */
- check_format_info (info, params);
- break;
- }
- }
+ info = find_function_format (name, assembler_name);
+
+ if (info)
+ check_format_info (info, params);
}
/* Check the argument list of a call to printf, scanf, etc.
@@ -1361,6 +1393,7 @@
return;
/* We can only check the format if it's a string constant. */
+ again:
while (TREE_CODE (format_tree) == NOP_EXPR)
format_tree = TREE_OPERAND (format_tree, 0); /* strip coercion */
@@ -1396,16 +1429,73 @@
}
}
+ if (TREE_CODE (format_tree) == COND_EXPR)
+ {
+ format_tree = TREE_OPERAND(format_tree, 1);
+ goto again;
+ }
+
if (integer_zerop (format_tree))
{
- warning ("null format string");
+ if (!info->null_format_ok)
+ warning ("null format string");
+ return;
+ }
+ if (TREE_CODE (format_tree) != ADDR_EXPR)
+ {
+ if ((info->first_arg_num == 0) &&
+ (TREE_CODE(format_tree) == PARM_DECL))
+ {
+ function_format_info *i2;
+ tree p;
+ int n;
+
+ /* Now, we need to determine if the current function is printf-like,
+ and, if so, if the parameter we have here is as a parameter of
+ the current function and is in the argument slot declared to
+ contain the format argument. */
+
+ p = current_function_decl;
+
+ i2 = find_function_format (p->decl.name, p->decl.assembler_name);
+
+ if (i2 == NULL)
+ {
+ if (warn_format > 1)
+ warning("non-constant format parameter");
+ }
+ else
+ {
+ for (n = 1, p = current_function_decl->decl.arguments;
+ (n < i2->format_num) && (p != NULL);
+ n++, p = TREE_CHAIN(p))
+ ;
+ if ((p == NULL) || (n != i2->format_num))
+ warning("can't find format arg for current format function");
+ else if (p != format_tree)
+ warning("format argument passed here is not declared as format argument");
+ }
+ }
+ else if ((info->format_type != strftime_format_type) &&
+ (warn_format > 1))
+ warning("non-constant format parameter");
return;
}
if (TREE_CODE (format_tree) != ADDR_EXPR)
@@ -1485,12 +1510,13 @@
- if (TREE_CODE (format_tree) != ADDR_EXPR)
- return;
format_tree = TREE_OPERAND (format_tree, 0);
- if (TREE_CODE (format_tree) != STRING_CST)
- return;
+ if (warn_format > 1 &&
+ (TREE_CODE (format_tree) == VAR_DECL) &&
+ TREE_READONLY(format_tree) &&
+ (DECL_INITIAL(format_tree) != NULL) &&
+ TREE_CODE(DECL_INITIAL(format_tree)) == STRING_CST)
+ format_tree = DECL_INITIAL(format_tree);
+
+ if (TREE_CODE (format_tree) != STRING_CST)
+ {
+ if ((info->format_type != strftime_format_type) &&
+ (warn_format > 1))
+ warning("non-constant format parameter");
+ return;
+ }
format_chars = TREE_STRING_POINTER (format_tree);
format_length = TREE_STRING_LENGTH (format_tree);
if (format_length <= 1)
@@ -1433,7 +1523,10 @@
if (format_chars - TREE_STRING_POINTER (format_tree) != format_length)
warning ("embedded `\\0' in format");
if (info->first_arg_num != 0 && params != 0 && ! has_operand_number)
- warning ("too many arguments for format");
+ {
+ if (warn_format_extra_args)
+ warning ("too many arguments for format");
+ }
return;
}
if (*format_chars++ != '%')
@@ -1569,12 +1662,13 @@
It will work on most machines, because size_t and int
have the same mode. But might as well warn anyway,
since it will fail on other machines. */
@ -166,7 +299,7 @@
}
}
else
@@ -1535,6 +1561,53 @@
@@ -1619,6 +1713,53 @@
}
}
}
@ -220,7 +353,7 @@
aflag = 0;
@@ -1604,7 +1677,8 @@
@@ -1688,7 +1829,8 @@
switch (info->format_type)
{
case printf_format_type:
@ -230,3 +363,11 @@
break;
case scanf_format_type:
fci = scan_char_table;
@@ -1787,7 +1929,6 @@
warning ("use of `%c' length character with `%c' type character",
length_char, format_char);
- /* Finally. . .check type of argument against desired type! */
if (info->first_arg_num == 0)
continue;
if (fci->pointer_count == 0 && wanted_type == void_type_node)

View File

@ -1,6 +1,6 @@
--- gcc/toplev.c.orig Mon Mar 22 15:23:26 1999
+++ gcc/toplev.c Tue Mar 30 13:13:44 1999
@@ -754,6 +754,9 @@
--- gcc/toplev.c.orig Thu Oct 21 00:01:37 1999
+++ gcc/toplev.c Sun Nov 26 15:25:45 2000
@@ -771,6 +771,9 @@
int flag_no_ident = 0;
@ -10,7 +10,7 @@
/* Table of supported debugging formats. */
static struct
{
@@ -954,6 +957,8 @@
@@ -971,6 +974,8 @@
"Generate code to check every memory access" },
{"prefix-function-name", &flag_prefix_function_name, 1,
"Add a prefix to all function names" },
@ -19,3 +19,13 @@
{"dump-unnumbered", &flag_dump_unnumbered, 1,
"Suppress output of instruction numbers and line number notes in debugging dumps"},
{"instrument-functions", &flag_instrument_function_entry_exit, 1,
@@ -1051,7 +1056,9 @@
{ "-Wconversion", "Warn about possibly confusing type conversions" },
{ "-Wno-conversion", "" },
{ "-Wformat", "Warn about printf format anomalies" },
+ { "-Wnon-const-format", "Warn about printf-like format strings" },
{ "-Wno-format", "" },
+ { "-Wno-format-extra-args", "" },
{ "-Wimplicit-function-declaration",
"Warn about implicit function declarations" },
{ "-Wno-implicit-function-declaration", "" },

View File

@ -0,0 +1,38 @@
--- gcc/c-decl.c.orig Mon Apr 12 07:05:29 1999
+++ gcc/c-decl.c Sun Nov 26 15:24:45 2000
@@ -557,6 +557,7 @@
/* Warn about *printf or *scanf format/argument anomalies. */
int warn_format;
+int warn_format_extra_args;
/* Warn about a subscript that has type char. */
@@ -808,10 +809,17 @@
warn_traditional = 1;
else if (!strcmp (p, "-Wno-traditional"))
warn_traditional = 0;
+ else if (!strcmp (p, "-Wnon-const-format"))
+ warn_format = MAX(warn_format, 2);
else if (!strcmp (p, "-Wformat"))
- warn_format = 1;
+ {
+ warn_format_extra_args = 1;
+ warn_format = MAX(warn_format, 1);
+ }
else if (!strcmp (p, "-Wno-format"))
warn_format = 0;
+ else if (!strcmp (p, "-Wno-format-extra-args"))
+ warn_format_extra_args = 0;
else if (!strcmp (p, "-Wchar-subscripts"))
warn_char_subscripts = 1;
else if (!strcmp (p, "-Wno-char-subscripts"))
@@ -882,7 +890,7 @@
warn_return_type = 1;
warn_unused = 1;
warn_switch = 1;
- warn_format = 1;
+ warn_format = MAX(warn_format, 1);
warn_char_subscripts = 1;
warn_parentheses = 1;
warn_missing_braces = 1;

View File

@ -0,0 +1,10 @@
--- gcc/c-tree.h.orig Thu Feb 18 12:38:43 1999
+++ gcc/c-tree.h Sun Nov 26 15:21:36 2000
@@ -495,6 +495,7 @@
/* Warn about *printf or *scanf format/argument anomalies. */
extern int warn_format;
+extern int warn_format_extra_args;
/* Warn about a subscript that has type char. */

View File

@ -0,0 +1,10 @@
--- gcc/cp/decl2.c.orig Thu Aug 19 16:29:45 1999
+++ gcc/cp/decl2.c Sun Nov 26 15:21:44 2000
@@ -281,6 +281,7 @@
/* Warn about *printf or *scanf format/argument anomalies. */
int warn_format;
+int warn_format_extra_args = 1;
/* Warn about a subscript that has type char. */

View File

@ -1,15 +1,15 @@
--- gcc/c-common.c.orig Mon Feb 15 16:40:05 1999
+++ gcc/c-common.c Tue Mar 30 03:35:22 1999
@@ -61,7 +61,7 @@
--- gcc/c-common.c.orig Tue Sep 7 01:11:16 1999
+++ gcc/c-common.c Sun Nov 26 15:35:38 2000
@@ -64,7 +64,7 @@
int, int, int));
static void init_attributes PROTO((void));
static void record_function_format PROTO((tree, tree, enum format_type,
- int, int));
+ int, int, int));
static void record_international_format PROTO((tree, tree, int));
/* Keep a stack of if statements. We record the number of compound
@@ -669,6 +669,7 @@
static tree c_find_base_decl PROTO((tree));
static int default_valid_lang_attribute PROTO ((tree, tree, tree, tree));
@@ -715,6 +715,7 @@
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
int format_num;
int first_arg_num;
@ -17,7 +17,7 @@
enum format_type format_type;
tree argument;
int arg_num;
@@ -682,7 +683,7 @@
@@ -728,7 +729,7 @@
if (TREE_CODE (format_type_id) != IDENTIFIER_NODE)
{
@ -26,8 +26,8 @@
continue;
}
else
@@ -690,12 +691,26 @@
char *p = IDENTIFIER_POINTER (format_type_id);
@@ -736,12 +737,26 @@
const char *p = IDENTIFIER_POINTER (format_type_id);
if (!strcmp (p, "printf") || !strcmp (p, "__printf__"))
+ {
@ -52,8 +52,8 @@
+ }
else
{
error ("`%s' is an unrecognized format function type", p);
@@ -766,7 +781,8 @@
warning ("`%s' is an unrecognized format function type", p);
@@ -812,7 +827,8 @@
record_function_format (DECL_NAME (decl),
DECL_ASSEMBLER_NAME (decl),
@ -63,7 +63,7 @@
break;
}
@@ -1010,6 +1026,11 @@
@@ -1090,6 +1106,11 @@
} format_char_info;
static format_char_info print_char_table[] = {
@ -75,7 +75,7 @@
{ "di", 0, T_I, T_I, T_I, T_L, T_LL, T_LL, T_ST, "-wp0 +" },
{ "oxX", 0, T_UI, T_UI, T_UI, T_UL, T_ULL, T_ULL, T_ST, "-wp0#" },
{ "u", 0, T_UI, T_UI, T_UI, T_UL, T_ULL, T_ULL, T_ST, "-wp0" },
@@ -1070,6 +1091,7 @@
@@ -1150,6 +1171,7 @@
tree name; /* identifier such as "printf" */
tree assembler_name; /* optional mangled identifier (for C++) */
enum format_type format_type; /* type of format (printf, scanf, etc.) */
@ -83,7 +83,7 @@
int format_num; /* number of format argument */
int first_arg_num; /* number of first arg (zero for varargs) */
} function_format_info;
@@ -1102,25 +1124,25 @@
@@ -1182,25 +1204,25 @@
init_function_format_info ()
{
record_function_format (get_identifier ("printf"), NULL_TREE,
@ -119,7 +119,7 @@
record_international_format (get_identifier ("gettext"), NULL_TREE, 1);
record_international_format (get_identifier ("dgettext"), NULL_TREE, 2);
@@ -1137,11 +1159,12 @@
@@ -1217,11 +1239,12 @@
(e.g. for varargs such as vfprintf). */
static void
@ -133,7 +133,7 @@
int format_num;
int first_arg_num;
{
@@ -1165,6 +1188,7 @@
@@ -1245,6 +1268,7 @@
}
info->format_type = format_type;
@ -141,17 +141,150 @@
info->format_num = format_num;
info->first_arg_num = first_arg_num;
}
@@ -1314,7 +1338,8 @@
@@ -1292,6 +1316,21 @@
warning ("too few arguments for format");
}
+static function_format_info *
+find_function_format (name, assembler_name)
+ tree name;
+ tree assembler_name;
+{
+ function_format_info *info;
+
+ for (info = function_format_list; info; info = info->next)
+ if (info->assembler_name
+ ? (info->assembler_name == assembler_name)
+ : (info->name == name))
+ return info;
+ return 0;
+}
+
/* Check the argument list of a call to printf, scanf, etc.
NAME is the function identifier.
ASSEMBLER_NAME is the function's assembler identifier.
@@ -1307,17 +1346,10 @@
function_format_info *info;
/* See if this function is a format function. */
- for (info = function_format_list; info; info = info->next)
- {
- if (info->assembler_name
- ? (info->assembler_name == assembler_name)
- : (info->name == name))
- {
- /* Yup; check it. */
- check_format_info (info, params);
- break;
- }
- }
+ info = find_function_format (name, assembler_name);
+
+ if (info)
+ check_format_info (info, params);
}
/* Check the argument list of a call to printf, scanf, etc.
@@ -1361,6 +1393,7 @@
return;
/* We can only check the format if it's a string constant. */
+ again:
while (TREE_CODE (format_tree) == NOP_EXPR)
format_tree = TREE_OPERAND (format_tree, 0); /* strip coercion */
@@ -1396,16 +1429,73 @@
}
}
+ if (TREE_CODE (format_tree) == COND_EXPR)
+ {
+ format_tree = TREE_OPERAND(format_tree, 1);
+ goto again;
+ }
+
if (integer_zerop (format_tree))
{
- warning ("null format string");
+ if (!info->null_format_ok)
+ warning ("null format string");
+ return;
+ }
+ if (TREE_CODE (format_tree) != ADDR_EXPR)
+ {
+ if ((info->first_arg_num == 0) &&
+ (TREE_CODE(format_tree) == PARM_DECL))
+ {
+ function_format_info *i2;
+ tree p;
+ int n;
+
+ /* Now, we need to determine if the current function is printf-like,
+ and, if so, if the parameter we have here is as a parameter of
+ the current function and is in the argument slot declared to
+ contain the format argument. */
+
+ p = current_function_decl;
+
+ i2 = find_function_format (p->decl.name, p->decl.assembler_name);
+
+ if (i2 == NULL)
+ {
+ if (warn_format > 1)
+ warning("non-constant format parameter");
+ }
+ else
+ {
+ for (n = 1, p = current_function_decl->decl.arguments;
+ (n < i2->format_num) && (p != NULL);
+ n++, p = TREE_CHAIN(p))
+ ;
+ if ((p == NULL) || (n != i2->format_num))
+ warning("can't find format arg for current format function");
+ else if (p != format_tree)
+ warning("format argument passed here is not declared as format argument");
+ }
+ }
+ else if ((info->format_type != strftime_format_type) &&
+ (warn_format > 1))
+ warning("non-constant format parameter");
return;
}
if (TREE_CODE (format_tree) != ADDR_EXPR)
@@ -1485,12 +1510,13 @@
- if (TREE_CODE (format_tree) != ADDR_EXPR)
- return;
format_tree = TREE_OPERAND (format_tree, 0);
- if (TREE_CODE (format_tree) != STRING_CST)
- return;
+ if (warn_format > 1 &&
+ (TREE_CODE (format_tree) == VAR_DECL) &&
+ TREE_READONLY(format_tree) &&
+ (DECL_INITIAL(format_tree) != NULL) &&
+ TREE_CODE(DECL_INITIAL(format_tree)) == STRING_CST)
+ format_tree = DECL_INITIAL(format_tree);
+
+ if (TREE_CODE (format_tree) != STRING_CST)
+ {
+ if ((info->format_type != strftime_format_type) &&
+ (warn_format > 1))
+ warning("non-constant format parameter");
+ return;
+ }
format_chars = TREE_STRING_POINTER (format_tree);
format_length = TREE_STRING_LENGTH (format_tree);
if (format_length <= 1)
@@ -1433,7 +1523,10 @@
if (format_chars - TREE_STRING_POINTER (format_tree) != format_length)
warning ("embedded `\\0' in format");
if (info->first_arg_num != 0 && params != 0 && ! has_operand_number)
- warning ("too many arguments for format");
+ {
+ if (warn_format_extra_args)
+ warning ("too many arguments for format");
+ }
return;
}
if (*format_chars++ != '%')
@@ -1569,12 +1662,13 @@
It will work on most machines, because size_t and int
have the same mode. But might as well warn anyway,
since it will fail on other machines. */
@ -166,7 +299,7 @@
}
}
else
@@ -1535,6 +1561,53 @@
@@ -1619,6 +1713,53 @@
}
}
}
@ -220,7 +353,7 @@
aflag = 0;
@@ -1604,7 +1677,8 @@
@@ -1688,7 +1829,8 @@
switch (info->format_type)
{
case printf_format_type:
@ -230,3 +363,11 @@
break;
case scanf_format_type:
fci = scan_char_table;
@@ -1787,7 +1929,6 @@
warning ("use of `%c' length character with `%c' type character",
length_char, format_char);
- /* Finally. . .check type of argument against desired type! */
if (info->first_arg_num == 0)
continue;
if (fci->pointer_count == 0 && wanted_type == void_type_node)

View File

@ -1,6 +1,6 @@
--- gcc/toplev.c.orig Mon Mar 22 15:23:26 1999
+++ gcc/toplev.c Tue Mar 30 13:13:44 1999
@@ -754,6 +754,9 @@
--- gcc/toplev.c.orig Thu Oct 21 00:01:37 1999
+++ gcc/toplev.c Sun Nov 26 15:25:45 2000
@@ -771,6 +771,9 @@
int flag_no_ident = 0;
@ -10,7 +10,7 @@
/* Table of supported debugging formats. */
static struct
{
@@ -954,6 +957,8 @@
@@ -971,6 +974,8 @@
"Generate code to check every memory access" },
{"prefix-function-name", &flag_prefix_function_name, 1,
"Add a prefix to all function names" },
@ -19,3 +19,13 @@
{"dump-unnumbered", &flag_dump_unnumbered, 1,
"Suppress output of instruction numbers and line number notes in debugging dumps"},
{"instrument-functions", &flag_instrument_function_entry_exit, 1,
@@ -1051,7 +1056,9 @@
{ "-Wconversion", "Warn about possibly confusing type conversions" },
{ "-Wno-conversion", "" },
{ "-Wformat", "Warn about printf format anomalies" },
+ { "-Wnon-const-format", "Warn about printf-like format strings" },
{ "-Wno-format", "" },
+ { "-Wno-format-extra-args", "" },
{ "-Wimplicit-function-declaration",
"Warn about implicit function declarations" },
{ "-Wno-implicit-function-declaration", "" },