Patch: format checking const arrays

Joseph S. Myers jsm28@cam.ac.uk
Thu Oct 19 14:04:00 GMT 2000


On Wed, 18 Oct 2000, Mark Mitchell wrote:

>     Joseph> After moving the tests of pedantic to the uses of
>     Joseph> decl_constant_value (which is still a misuse of pedantic,
> 
> It's probably actually better to make a wrapper function, and call
> that.

I rather feel a wrapper function would in essence if not in name be
broken_bug_compatible_decl_constant_value and that the relevant tests
belong where they are (brokenly) used.

This updated patch for format checking arrays uses decl_constant_value
by moving the pedantic and BLKmode checks to the places in c-typeck.c
where it is used (still not a proper use of pedantic, but doesn't
change the compiler's behaviour and makes it clear at each affected
place that whether pedantic should be checked and how must be
considered there).  The purpose of this work isn't to get into
changing optimizations, misguided though some of them may be.  That's
best done by someone who understands the pessimization the BLKmode
tests address and has appropriate benchmarks to test any such changes.
I suspect that the proper solution for the pedantic tests might
involve separating the semantic analysis of code and production of
warnings required by the standard (which should refer to pedantic, and
carry out constant folding of actual constants but not const
variables) from the tree-based optimization involving replacing uses
of these variables by their values (which if appropriate might apply
the BLKmode tests).

Bootstrapped with no regressions on i686-pc-linux-gnu.  OK to commit?

gcc/ChangeLog:
2000-10-19  Joseph S. Myers  <jsm28@cam.ac.uk>

	* 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.
	(default_conversion, convert_for_assignment, digest_init): Check
	them here instead at calls to decl_constant_value.

gcc/testsuite/ChangeLog:
2000-10-19  Joseph S. Myers  <jsm28@cam.ac.uk>

	* gcc.dg/format-array-1.c: New test.

--- c-common.c.orig	Wed Oct 18 21:27:38 2000
+++ c-common.c	Wed Oct 18 21:52:49 2000
@@ -2344,6 +2344,8 @@ check_format_info_recurse (status, res, 
 {
   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, 
       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, 
     }
   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++;
--- c-typeck.c.orig	Wed Oct 18 21:26:45 2000
+++ c-typeck.c	Wed Oct 18 21:53:45 2000
@@ -844,7 +844,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,8 +853,7 @@ 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;
 }
@@ -879,8 +877,10 @@ default_conversion (exp)
   /* Replace a nonvolatile const static variable with its value unless
      it is an array, in which case we must be sure that taking the
      address of the array produces consistent results.  */
-  else if (optimize && TREE_CODE (exp) == VAR_DECL && code != ARRAY_TYPE)
+  else if (optimize && TREE_CODE (exp) == VAR_DECL && code != ARRAY_TYPE
+	   && ! pedantic && DECL_MODE (exp) != BLKmode)
     {
+      /* FIXME: this is an inappropriate use of pedantic.  */
       exp = decl_constant_value (exp);
       type = TREE_TYPE (exp);
     }
@@ -4018,8 +4018,10 @@ convert_for_assignment (type, rhs, errty
   if (TREE_CODE (TREE_TYPE (rhs)) == ARRAY_TYPE
       || TREE_CODE (TREE_TYPE (rhs)) == FUNCTION_TYPE)
     rhs = default_conversion (rhs);
-  else if (optimize && TREE_CODE (rhs) == VAR_DECL)
+  else if (optimize && TREE_CODE (rhs) == VAR_DECL && ! pedantic
+	   && DECL_MODE (rhs) != BLKmode)
     rhs = decl_constant_value (rhs);
+  /* FIXME: this is an inappropriate use of pedantic.  */
 
   rhstype = TREE_TYPE (rhs);
   coder = TREE_CODE (rhstype);
@@ -4694,8 +4696,10 @@ digest_init (type, init, require_constan
 	  return error_mark_node;
 	}
 
-      if (optimize && TREE_CODE (inside_init) == VAR_DECL)
+      if (optimize && TREE_CODE (inside_init) == VAR_DECL && ! pedantic
+	  && DECL_MODE (inside_init) != BLKmode)
 	inside_init = decl_constant_value (inside_init);
+      /* FIXME: this is an inappropriate use of pedantic.  */
 
       /* Compound expressions can only occur here if -pedantic or
 	 -pedantic-errors is specified.  In the later case, we always want
--- testsuite/gcc.dg/format-array-1.c.orig	Fri Sep 11 11:31:59 1998
+++ testsuite/gcc.dg/format-array-1.c	Tue Oct 17 18:34:24 2000
@@ -0,0 +1,39 @@
+/* Test for format checking of constant arrays.  */
+/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
+/* { 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" } */
+}

-- 
Joseph S. Myers
jsm28@cam.ac.uk



More information about the Gcc-patches mailing list