PR c/81117 - Improve buffer overflow checking in strncpy - part 1
authorMartin Sebor <msebor@redhat.com>
Mon, 14 Aug 2017 18:35:13 +0000 (18:35 +0000)
committerMartin Sebor <msebor@gcc.gnu.org>
Mon, 14 Aug 2017 18:35:13 +0000 (12:35 -0600)
gcc/ChangeLog:

        PR c/81117
* tree-diagnostic.c (default_tree_printer): Handle %G.
* gimple-pretty-print.h (percent_G_format): Declare new function.
* gimple-pretty-print.c (percent_G_format): Define.
* tree-pretty-print.c (percent_K_format): Add argument.

gcc/c/ChangeLog:

PR c/81117
* c-objc-common.c (c_objc_common_init): Handle 'G'.

gcc/c-family/ChangeLog:

PR c/81117
* c-format.h (T89_G): New macro.
* c-format.c (local_gcall_ptr_node): New variable.
(init_dynamic_diag_info): Initialize it.

gcc/cp/ChangeLog:

PR c/81117
* error.c (cp_printer): Handle 'G'.

gcc/testsuite/ChangeLog:

PR c/81117
* gcc.dg/format/gcc_diag-10.c: Exercise %G.

From-SVN: r251098

15 files changed:
gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c-format.c
gcc/c-family/c-format.h
gcc/c/ChangeLog
gcc/c/c-objc-common.c
gcc/cp/ChangeLog
gcc/cp/error.c
gcc/gimple-pretty-print.c
gcc/gimple-pretty-print.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/format/gcc_diag-10.c
gcc/tree-diagnostic.c
gcc/tree-pretty-print.c
gcc/tree-pretty-print.h

index feae522a570e8ec3907cbf4682538ca3fe981e68..9697dd9017024b2d2684805aeb5313718fd5b4b3 100644 (file)
@@ -1,3 +1,11 @@
+2017-08-14  Martin Sebor  <msebor@redhat.com>
+
+       PR c/81117
+       * tree-diagnostic.c (default_tree_printer): Handle %G.
+       * gimple-pretty-print.h (percent_G_format): Declare new function.
+       * gimple-pretty-print.c (percent_G_format): Define.
+       * tree-pretty-print.c (percent_K_format): Add argument.
+
 2017-08-14  Martin Sebor  <msebor@redhat.com>
 
        PR translation/79998
index 6d33192c5ac7a009402a9e68bf79332825eb6d2d..155383de773d2cc0a52d3f855ac13c006f3bd49f 100644 (file)
@@ -1,3 +1,10 @@
+2017-08-14  Martin Sebor  <msebor@redhat.com>
+
+       PR c/81117
+       * c-format.h (T89_G): New macro.
+       * c-format.c (local_gcall_ptr_node): New variable.
+       (init_dynamic_diag_info): Initialize it.
+
 2017-08-11  Martin Liska  <mliska@suse.cz>
 
        * c-opts.c (c_common_post_options): Replace ASM_OUTPUT_DEF with
index 5e5b494383f702e02c22bded63c9ef637eb9a384..7c9095c2a5bab02b6dac1651756676b3d0744dc8 100644 (file)
@@ -56,6 +56,7 @@ struct function_format_info
 
 /* Initialized in init_dynamic_diag_info.  */
 static GTY(()) tree local_tree_type_node;
+static GTY(()) tree local_gcall_ptr_node;
 static GTY(()) tree locus;
 
 static bool decode_format_attr (tree, function_format_info *, int);
@@ -689,7 +690,9 @@ static const format_char_info gcc_diag_char_table[] =
 
   /* Custom conversion specifiers.  */
 
-  /* These will require a "tree" at runtime.  */
+  /* G requires a "gcall*" argument at runtime.  */
+  { "G",   1, STD_C89, { T89_G,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "",    "\"",   NULL },
+  /* K requires a "tree" argument at runtime.  */
   { "K",   1, STD_C89, { T89_T,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "",    "\"",   NULL },
 
   { "r",   1, STD_C89, { T89_C,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "",    "//cR",   NULL },
@@ -718,6 +721,9 @@ static const format_char_info gcc_tdiag_char_table[] =
   { "E", 1, STD_C89, { T89_T,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q+", "",   NULL },
   { "K", 1, STD_C89, { T89_T,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "", "\"",   NULL },
 
+  /* G requires a "gcall*" argument at runtime.  */
+  { "G", 1, STD_C89, { T89_G,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "", "\"",   NULL },
+
   { "v",   0, STD_C89, { T89_I,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q#",  "",   NULL },
 
   { "r",   1, STD_C89, { T89_C,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "",    "/cR",   NULL },
@@ -747,6 +753,9 @@ static const format_char_info gcc_cdiag_char_table[] =
   { "E",   1, STD_C89, { T89_T,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q+", "",   NULL },
   { "K",   1, STD_C89, { T89_T,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "", "\"",   NULL },
 
+  /* G requires a "gcall*" argument at runtime.  */
+  { "G",   1, STD_C89, { T89_G,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "", "\"",   NULL },
+
   { "v",   0, STD_C89, { T89_I,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q#",  "",   NULL },
 
   { "r",   1, STD_C89, { T89_C,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "",    "/cR",   NULL },
@@ -777,6 +786,9 @@ static const format_char_info gcc_cxxdiag_char_table[] =
   { "K", 1, STD_C89,{ T89_T,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "",   "\"",   NULL },
   { "v", 0,STD_C89, { T89_I,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q#",  "",   NULL },
 
+  /* G requires a "gcall*" argument at runtime.  */
+  { "G", 1, STD_C89,{ T89_G,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "",   "\"",   NULL },
+
   /* These accept either an 'int' or an 'enum tree_code' (which is handled as an 'int'.)  */
   { "CLOPQ",0,STD_C89, { T89_I,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "q",  "",   NULL },
 
@@ -3834,6 +3846,29 @@ init_dynamic_diag_info (void)
        local_tree_type_node = void_type_node;
     }
 
+  /* Similar to the above but for gcall*.  */
+  if (!local_gcall_ptr_node
+      || local_gcall_ptr_node == void_type_node)
+    {
+      if ((local_gcall_ptr_node = maybe_get_identifier ("gcall")))
+       {
+         local_gcall_ptr_node
+           = identifier_global_value (local_gcall_ptr_node);
+         if (local_gcall_ptr_node)
+           {
+             if (TREE_CODE (local_gcall_ptr_node) != TYPE_DECL)
+               {
+                 error ("%<gcall%> is not defined as a type");
+                 local_gcall_ptr_node = 0;
+               }
+             else
+               local_gcall_ptr_node = TREE_TYPE (local_gcall_ptr_node);
+           }
+       }
+      else
+       local_gcall_ptr_node = void_type_node;
+    }
+
   static tree hwi;
 
   if (!hwi)
index 37fa3828485a4fe5016a40e8b8278f8f8c83462f..05e9bb73ef1326136adb1e62bfbec5b8ecfa0133 100644 (file)
@@ -298,6 +298,7 @@ struct format_kind_info
 #define T_UC   &unsigned_char_type_node
 #define T99_UC { STD_C99, NULL, T_UC }
 #define T_V    &void_type_node
+#define T89_G   { STD_C89, NULL, &local_gcall_ptr_node }
 #define T89_T   { STD_C89, NULL, &local_tree_type_node }
 #define T89_V  { STD_C89, NULL, T_V }
 #define T_W    &wchar_type_node
index cd0c128edc82c79c300498942e7f9d955ec21aac..3db4189c7d43b509b3b3a67206cc7a213e629a2b 100644 (file)
@@ -1,3 +1,8 @@
+2017-08-14  Martin Sebor  <msebor@redhat.com>
+
+       PR c/81117
+       * c-objc-common.c (c_objc_common_init): Handle 'G'.
+
 2017-08-11  Marek Polacek  <polacek@redhat.com>
 
        PR c/81795
index 05212b2cb8e4c9477daf2cd2f86e3205a66249e4..8f4d3eb91c538538db7f0797fd0b6d7ac6ec8bb4 100644 (file)
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "intl.h"
 #include "c-family/c-pretty-print.h"
 #include "tree-pretty-print.h"
+#include "gimple-pretty-print.h"
 #include "langhooks.h"
 #include "c-objc-common.h"
 
@@ -66,6 +67,8 @@ c_objc_common_init (void)
    %D: a general decl,
    %E: an identifier or expression,
    %F: a function declaration,
+   %G: a Gimple call statement,
+   %K: a CALL_EXPR,
    %T: a type.
    %V: a list of type qualifiers from a tree.
    %v: an explicit list of type qualifiers
@@ -87,9 +90,16 @@ c_tree_printer (pretty_printer *pp, text_info *text, const char *spec,
   if (precision != 0 || wide)
     return false;
 
+  if (*spec == 'G')
+    {
+      percent_G_format (text);
+      return true;
+    }
+
   if (*spec == 'K')
     {
-      percent_K_format (text);
+      t = va_arg (*text->args_ptr, tree);
+      percent_K_format (text, t);
       return true;
     }
 
index a8a3fccdcd1972b5871e10983967c4c2b5521309..3fd74bfc196f535f71724aa832a11c38476e67cc 100644 (file)
@@ -1,3 +1,8 @@
+2017-08-14  Martin Sebor  <msebor@redhat.com>
+
+       PR c/81117
+       * error.c (cp_printer): Handle 'G'.
+
 2017-08-11  Martin Liska  <mliska@suse.cz>
 
        * decl2.c (get_tls_init_fn): Replace ASM_OUTPUT_DEF with
index 31ca8fe1eb2a9a2d7b6e772529bb17361e3d24b9..e4071547091ecaa93bc963c681f15f458155a6b1 100644 (file)
@@ -27,6 +27,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "intl.h"
 #include "cxx-pretty-print.h"
 #include "tree-pretty-print.h"
+#include "gimple-pretty-print.h"
 #include "c-family/c-objc.h"
 #include "ubsan.h"
 #include "internal-fn.h"
@@ -4050,8 +4051,13 @@ cp_printer (pretty_printer *pp, text_info *text, const char *spec,
     case 'V': result = cv_to_string (next_tree, verbose);      break;
     case 'X': result = eh_spec_to_string (next_tree, verbose);  break;
 
+    case 'G':
+      percent_G_format (text);
+      return true;
+
     case 'K':
-      percent_K_format (text);
+      t = va_arg (*text->args_ptr, tree);
+      percent_K_format (text, t);
       return true;
 
     case 'H':
index 5727d14777a234372037006702cfd1cd25ca9460..ed8e51c1c4677735462f88f460db64ee6cb63924 100644 (file)
@@ -2911,3 +2911,22 @@ gimple_dump_bb_for_graph (pretty_printer *pp, basic_block bb)
   pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/true);
 }
 
+
+/* Handle the %G format for TEXT.  Same as %K in handle_K_format in
+   tree-pretty-print.c but with a Gimple call statement as an argument.  */
+
+void
+percent_G_format (text_info *text)
+{
+  gcall *stmt = va_arg (*text->args_ptr, gcall*);
+
+  /* Build a call expression from the Gimple call statement and
+     pass it to the K formatter that knows how to format it.  */
+  tree exp = build_vl_exp (CALL_EXPR, gimple_call_num_args (stmt) + 3);
+  CALL_EXPR_FN (exp) = gimple_call_fn (stmt);
+  TREE_TYPE (exp) = gimple_call_return_type (stmt);
+  CALL_EXPR_STATIC_CHAIN (exp) = gimple_call_chain (stmt);
+  SET_EXPR_LOCATION (exp, gimple_location (stmt));
+
+  percent_K_format (text, exp);
+}
index 0b74d1b0494f87b530f6c3e1aca750c203268481..08720f4593661c7a0a4b929813c2ed840f05b512 100644 (file)
@@ -35,5 +35,6 @@ extern void pp_gimple_stmt_1 (pretty_printer *, gimple *, int, dump_flags_t);
 extern void gimple_dump_bb (FILE *, basic_block, int, dump_flags_t);
 extern void gimple_dump_bb_for_graph (pretty_printer *, basic_block);
 extern void dump_ssaname_info_to_file (FILE *, tree, int);
+extern void percent_G_format (text_info *);
 
 #endif /* ! GCC_GIMPLE_PRETTY_PRINT_H */
index c68732f82f99c2912e91017eae2b299dfaeb079c..2bd4fad515323138957bc83e1777844b429e98e7 100644 (file)
@@ -1,3 +1,8 @@
+2017-08-14  Martin Sebor  <msebor@redhat.com>
+
+       PR c/81117
+       * gcc.dg/format/gcc_diag-10.c: Exercise %G.
+
 2017-08-14  David Edelsohn  <dje.gcc@gmail.com>
 
        * gcc.dg/ucnid-5.c: Skip on AIX.
index b3be27739570b033655762618ae6f22cc373bc61..9bda73bc628bf548eeac29e3240f7192e0a302b2 100644 (file)
@@ -15,6 +15,9 @@ typedef struct location_s
 union tree_node;
 typedef union tree_node *tree;
 
+/* Define gcall as a dummy type.  The typedef must be provided for
+   the C test to find the symbol.  */
+typedef struct gcall gcall;
 
 #define FORMAT(kind) __attribute__ ((format (__gcc_## kind ##__, 1, 2)))
 
@@ -23,12 +26,13 @@ void cdiag (const char*, ...) FORMAT (cdiag);
 void tdiag (const char*, ...) FORMAT (tdiag);
 void cxxdiag (const char*, ...) FORMAT (cxxdiag);
 
-void test_diag (tree t)
+void test_diag (tree t, gcall *gc)
 {
   diag ("%<");   /* { dg-warning "unterminated quoting directive" } */
   diag ("%>");   /* { dg-warning "unmatched quoting directive " } */
   diag ("%<foo%<bar%>%>");   /* { dg-warning "nested quoting directive" } */
 
+  diag ("%G", gc);
   diag ("%K", t);
 
   diag ("%R");       /* { dg-warning "unmatched color reset directive" } */
@@ -38,6 +42,7 @@ void test_diag (tree t)
   diag ("%r%r%R", "", "");
   diag ("%r%R%r%R", "", "");
 
+  diag ("%<%G%>", gc);  /* { dg-warning ".G. conversion used within a quoted sequence" } */
   diag ("%<%K%>", t);   /* { dg-warning ".K. conversion used within a quoted sequence" } */
 
   diag ("%<%R%>");      /* { dg-warning "unmatched color reset directive" } */
@@ -45,7 +50,7 @@ void test_diag (tree t)
   diag ("%<%r%R%>", "");
 }
 
-void test_cdiag (tree t)
+void test_cdiag (tree t, gcall *gc)
 {
   cdiag ("%<");   /* { dg-warning "unterminated quoting directive" } */
   cdiag ("%>");   /* { dg-warning "unmatched quoting directive " } */
@@ -54,6 +59,7 @@ void test_cdiag (tree t)
   cdiag ("%D", t);       /* { dg-warning ".D. conversion used unquoted" } */
   cdiag ("%E", t);
   cdiag ("%F", t);       /* { dg-warning ".F. conversion used unquoted" } */
+  cdiag ("%G", gc);
   cdiag ("%K", t);
 
   cdiag ("%R");       /* { dg-warning "unmatched color reset directive" } */
@@ -69,6 +75,7 @@ void test_cdiag (tree t)
   cdiag ("%<%D%>", t);
   cdiag ("%<%E%>", t);
   cdiag ("%<%F%>", t);
+  cdiag ("%<%G%>", gc);  /* { dg-warning ".G. conversion used within a quoted sequence" } */
   cdiag ("%<%K%>", t);   /* { dg-warning ".K. conversion used within a quoted sequence" } */
 
   cdiag ("%<%R%>");      /* { dg-warning "unmatched color reset directive" } */
@@ -83,7 +90,7 @@ void test_cdiag (tree t)
   cdiag ("%<%qT%>", t);  /* { dg-warning ".q. flag used within a quoted sequence" } */
 }
 
-void test_tdiag (tree t)
+void test_tdiag (tree t, gcall *gc)
 {
   tdiag ("%<");       /* { dg-warning "unterminated quoting directive" } */
   tdiag ("%>");       /* { dg-warning "unmatched quoting directive " } */
@@ -91,6 +98,7 @@ void test_tdiag (tree t)
 
   tdiag ("%D", t);       /* { dg-warning ".D. conversion used unquoted" } */
   tdiag ("%E", t);
+  tdiag ("%G", gc);
   tdiag ("%K", t);
 
   tdiag ("%R");          /* { dg-warning "unmatched color reset directive" } */
@@ -105,6 +113,7 @@ void test_tdiag (tree t)
 
   tdiag ("%<%D%>", t);
   tdiag ("%<%E%>", t);
+  tdiag ("%<%G%>", gc);  /* { dg-warning ".G. conversion used within a quoted sequence" } */
   tdiag ("%<%K%>", t);   /* { dg-warning ".K. conversion used within a quoted sequence" } */
 
   tdiag ("%<%R%>");      /* { dg-warning "unmatched color reset directive" } */
@@ -118,12 +127,14 @@ void test_tdiag (tree t)
   tdiag ("%<%qT%>", t);  /* { dg-warning ".q. flag used within a quoted sequence" } */
 }
 
-void test_cxxdiag (tree t)
+void test_cxxdiag (tree t, gcall *gc)
 {
   cxxdiag ("%A", t);     /* { dg-warning ".A. conversion used unquoted" } */
   cxxdiag ("%D", t);     /* { dg-warning ".D. conversion used unquoted" } */
   cxxdiag ("%E", t);
   cxxdiag ("%F", t);     /* { dg-warning ".F. conversion used unquoted" } */
+  cxxdiag ("%G", gc);
+  cxxdiag ("%K", t);
 
   cxxdiag ("%R");        /* { dg-warning "unmatched color reset directive" } */
   cxxdiag ("%r", "");    /* { dg-warning "unterminated color directive" } */
index 52b7e7f0bb4420b24a317b613596fa7f3407aef6..023e896a34a524dda37c6acd14cda73ed5538e66 100644 (file)
@@ -25,6 +25,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree.h"
 #include "diagnostic.h"
 #include "tree-pretty-print.h"
+#include "gimple-pretty-print.h"
 #include "tree-diagnostic.h"
 #include "langhooks.h"
 #include "intl.h"
@@ -275,8 +276,13 @@ default_tree_printer (pretty_printer *pp, text_info *text, const char *spec,
       t = va_arg (*text->args_ptr, tree);
       break;
 
+    case 'G':
+      percent_G_format (text);
+      return true;
+
     case 'K':
-      percent_K_format (text);
+      t = va_arg (*text->args_ptr, tree);
+      percent_K_format (text, t);
       return true;
 
     default:
index 4d8177c4a6240e80e78cdecc110bda1c7e2bd53f..c7509af198be40add91b5e52bd8cc9eefca7322c 100644 (file)
@@ -33,6 +33,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "dumpfile.h"
 #include "internal-fn.h"
 #include "gomp-constants.h"
+#include "gimple.h"
 
 /* Local functions, macros and variables.  */
 static const char *op_symbol (const_tree);
@@ -3970,18 +3971,17 @@ newline_and_indent (pretty_printer *pp, int spc)
   INDENT (spc);
 }
 
-/* Handle a %K format for TEXT.  Separate from default_tree_printer so
-   it can also be used in front ends.
-   %K: a statement, from which EXPR_LOCATION and TREE_BLOCK will be recorded.
-*/
+/* Handle the %K format for TEXT.  Separate from default_tree_printer
+   so it can also be used in front ends.
+   Argument is a statement from which EXPR_LOCATION and TREE_BLOCK will
+   be recorded.  */
 
 void
-percent_K_format (text_info *text)
+percent_K_format (text_info *text, tree t)
 {
-  tree t = va_arg (*text->args_ptr, tree), block;
   text->set_location (0, EXPR_LOCATION (t), true);
   gcc_assert (pp_ti_abstract_origin (text) != NULL);
-  block = TREE_BLOCK (t);
+  tree block = TREE_BLOCK (t);
   *pp_ti_abstract_origin (text) = NULL;
 
   if (in_lto_p)
index 07270b735a742986d9ac10356f297932cdb05f8e..d17c5a504523d4392de2e1271e54d9815d3c260a 100644 (file)
@@ -45,7 +45,7 @@ extern int op_code_prio (enum tree_code);
 extern int op_prio (const_tree);
 extern const char *op_symbol_code (enum tree_code);
 extern void print_call_name (pretty_printer *, tree, dump_flags_t);
-extern void percent_K_format (text_info *);
+extern void percent_K_format (text_info *, tree);
 extern void pp_tree_identifier (pretty_printer *, tree);
 extern void dump_function_header (FILE *, tree, dump_flags_t);
 extern void pp_double_int (pretty_printer *pp, double_int d, bool uns);