From: Joseph Myers Date: Fri, 20 Oct 2000 15:59:07 +0000 (+0100) Subject: c-common.c (check_format_info_recurse): Extract string constant initializers from... X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=2f74f7e928e72c7382cc5a72a7440657175fc2d2;p=gcc.git c-common.c (check_format_info_recurse): Extract string constant initializers from non-volatile constant arrays and... * c-common.c (check_format_info_recurse): Extract string constant initializers from non-volatile constant arrays and check them as formats. * c-typeck.c (decl_constant_value): Don't check pedantic or check for DECL_MODE (decl) != BLKmode. (decl_constant_value_for_broken_optimization): New function which includes these checks. (default_conversion, convert_for_assignment, digest_init): Use decl_constant_value_for_broken_optimization instead of decl_constant_value. testsuite: * gcc.dg/format-array-1.c: New test. From-SVN: r36965 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b9f58c10a3c..5a71796a0b5 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2000-10-20 Joseph S. Myers + + * c-common.c (check_format_info_recurse): Extract string constant + initializers from non-volatile constant arrays and check them as + formats. + * c-typeck.c (decl_constant_value): Don't check pedantic or check + for DECL_MODE (decl) != BLKmode. + (decl_constant_value_for_broken_optimization): New function which + includes these checks. + (default_conversion, convert_for_assignment, digest_init): Use + decl_constant_value_for_broken_optimization instead of + decl_constant_value. + 2000-10-20 Mark Mitchell * tree.h (DECL_ALIGN_UNIT): New macro. diff --git a/gcc/c-common.c b/gcc/c-common.c index 086177f5860..e9ce259901a 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -2344,6 +2344,8 @@ check_format_info_recurse (status, res, info, format_tree, params, arg_num) { int format_length; const char *format_chars; + tree array_size = 0; + tree array_init; if (TREE_CODE (format_tree) == NOP_EXPR) { @@ -2436,6 +2438,17 @@ check_format_info_recurse (status, res, info, format_tree, params, arg_num) return; } format_tree = TREE_OPERAND (format_tree, 0); + if (TREE_CODE (format_tree) == VAR_DECL + && TREE_CODE (TREE_TYPE (format_tree)) == ARRAY_TYPE + && (array_init = decl_constant_value (format_tree)) != format_tree + && TREE_CODE (array_init) == STRING_CST) + { + /* Extract the string constant initializer. Note that this may include + a trailing NUL character that is not in the array (e.g. + const char a[3] = "foo";). */ + array_size = DECL_SIZE_UNIT (format_tree); + format_tree = array_init; + } if (TREE_CODE (format_tree) != STRING_CST) { res->number_non_literal++; @@ -2448,6 +2461,20 @@ check_format_info_recurse (status, res, info, format_tree, params, arg_num) } format_chars = TREE_STRING_POINTER (format_tree); format_length = TREE_STRING_LENGTH (format_tree); + if (array_size != 0) + { + /* Variable length arrays can't be initialized. */ + if (TREE_CODE (array_size) != INTEGER_CST) + abort (); + if (host_integerp (array_size, 0)) + { + HOST_WIDE_INT array_size_value = TREE_INT_CST_LOW (array_size); + if (array_size_value > 0 + && array_size_value == (int) array_size_value + && format_length > array_size_value) + format_length = array_size_value; + } + } if (format_length < 1) { res->number_unterminated++; diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index 0d2209e501a..e055e988beb 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -54,6 +54,7 @@ static tree qualify_type PARAMS ((tree, tree)); static int comp_target_types PARAMS ((tree, tree)); static int function_types_compatible_p PARAMS ((tree, tree)); static int type_lists_compatible_p PARAMS ((tree, tree)); +static tree decl_constant_value_for_broken_optimization PARAMS ((tree)); static tree lookup_field PARAMS ((tree, tree, tree *)); static tree convert_arguments PARAMS ((tree, tree, tree, tree)); static tree pointer_int_sum PARAMS ((enum tree_code, tree, tree)); @@ -844,7 +845,6 @@ decl_constant_value (decl) if (/* Don't change a variable array bound or initial value to a constant in a place where a variable is invalid. */ current_function_decl != 0 - && ! pedantic && ! TREE_THIS_VOLATILE (decl) && TREE_READONLY (decl) && DECL_INITIAL (decl) != 0 @@ -854,12 +854,29 @@ decl_constant_value (decl) or a variable, then re-evaluating it could give different results. */ && TREE_CONSTANT (DECL_INITIAL (decl)) /* Check for cases where this is sub-optimal, even though valid. */ - && TREE_CODE (DECL_INITIAL (decl)) != CONSTRUCTOR - && DECL_MODE (decl) != BLKmode) + && TREE_CODE (DECL_INITIAL (decl)) != CONSTRUCTOR) return DECL_INITIAL (decl); return decl; } +/* Return either DECL or its known constant value (if it has one), but + return DECL if pedantic or DECL has mode BLKmode. This is for + bug-compatibility with the old behavior of decl_constant_value + (before GCC 3.0); every use of this function is a bug and it should + be removed before GCC 3.1. It is not appropriate to use pedantic + in a way that affects optimization, and BLKmode is probably not the + right test for avoiding misoptimizations either. */ + +static tree +decl_constant_value_for_broken_optimization (decl) + tree decl; +{ + if (pedantic || DECL_MODE (decl) == BLKmode) + return decl; + else + return decl_constant_value (decl); +} + /* Perform default promotions for C data used in expressions. Arrays and functions are converted to pointers; enumeral types or short or char, to int. @@ -881,7 +898,7 @@ default_conversion (exp) address of the array produces consistent results. */ else if (optimize && TREE_CODE (exp) == VAR_DECL && code != ARRAY_TYPE) { - exp = decl_constant_value (exp); + exp = decl_constant_value_for_broken_optimization (exp); type = TREE_TYPE (exp); } @@ -4019,7 +4036,7 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum) || TREE_CODE (TREE_TYPE (rhs)) == FUNCTION_TYPE) rhs = default_conversion (rhs); else if (optimize && TREE_CODE (rhs) == VAR_DECL) - rhs = decl_constant_value (rhs); + rhs = decl_constant_value_for_broken_optimization (rhs); rhstype = TREE_TYPE (rhs); coder = TREE_CODE (rhstype); @@ -4695,7 +4712,7 @@ digest_init (type, init, require_constant, constructor_constant) } if (optimize && TREE_CODE (inside_init) == VAR_DECL) - inside_init = decl_constant_value (inside_init); + inside_init = decl_constant_value_for_broken_optimization (inside_init); /* Compound expressions can only occur here if -pedantic or -pedantic-errors is specified. In the later case, we always want diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 679b4edf630..ebaa50f34db 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2000-10-20 Joseph S. Myers + + * gcc.dg/format-array-1.c: New test. + 2000-10-18 Joseph S. Myers * gcc.dg/c90-printf-1.c, gcc.dg/c90-scanf-1.c: Add tests for diff --git a/gcc/testsuite/gcc.dg/format-array-1.c b/gcc/testsuite/gcc.dg/format-array-1.c new file mode 100644 index 00000000000..8d632a7f914 --- /dev/null +++ b/gcc/testsuite/gcc.dg/format-array-1.c @@ -0,0 +1,39 @@ +/* Test for format checking of constant arrays. */ +/* Origin: Joseph Myers */ +/* { dg-do compile } */ +/* { dg-options "-std=gnu99 -Wformat=2" } */ + +extern int printf (const char *, ...); + +const char a1[] = "foo"; +const char a2[] = "foo%d"; +const char b[3] = "foo"; +static const char c1[] = "foo"; +static const char c2[] = "foo%d"; +char d[] = "foo"; +volatile const char e[] = "foo"; + +void +foo (int i, long l) +{ + const char p1[] = "bar"; + const char p2[] = "bar%d"; + static const char q1[] = "bar"; + static const char q2[] = "bar%d"; + printf (a1); + printf (a2, i); + printf (a2, l); /* { dg-warning "format" "wrong type with array" } */ + printf (b); /* { dg-warning "unterminated" "unterminated array" } */ + printf (c1); + printf (c2, i); + printf (c2, l); /* { dg-warning "format" "wrong type with array" } */ + printf (p1); + printf (p2, i); + printf (p2, l); /* { dg-warning "format" "wrong type with array" } */ + printf (q1); + printf (q2, i); + printf (q2, l); /* { dg-warning "format" "wrong type with array" } */ + /* Volatile or non-constant arrays must not be checked. */ + printf (d); /* { dg-warning "not a string literal" "non-const" } */ + printf ((const char *)e); /* { dg-warning "not a string literal" "volatile" } */ +}