public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Martin Sebor <msebor@gmail.com>
To: Jeff Law <law@redhat.com>, Gcc Patch List <gcc-patches@gcc.gnu.org>
Subject: [PATCH 1/4] enhance overflow and truncation detection in strncpy and strncat (PR 81117)
Date: Sun, 06 Aug 2017 20:07:00 -0000	[thread overview]
Message-ID: <33a2ba18-274d-8229-06b4-c4983f0d3e2f@gmail.com> (raw)
In-Reply-To: <a0069a6d-d4a8-67df-e2f3-902dc7704ab2@redhat.com>

[-- Attachment #1: Type: text/plain, Size: 292 bytes --]

The attached patch adds support for a new GCC format specifier,
G, that behaves like %K but accepts a gcall* argument.  This
makes it possible to provide inlining context for "artificial"
inline functions like strncpy (with _FORTIFY_SOURCE) in
diagnostics issued from the middle end.

Martin

[-- Attachment #2: gcc-81117-1.diff --]
[-- Type: text/x-patch, Size: 14293 bytes --]

PR c/81117 - Improve buffer overflow checking in strncpy

gcc/ChangeLog:

	PR c/81117
	* tree-diagnostic.c (default_tree_printer): Handle %G.
	* tree-pretty-print.h (percent_G_format): Declare new function.
	* tree-pretty-print.c (percent_K_format): Define a static overload.
	(percent_G_format): New function.

gcc/c/ChangeLog:

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

gcc/c-family/ChangeLog:

	* 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.

diff --git a/gcc/tree-diagnostic.c b/gcc/tree-diagnostic.c
index 52b7e7f..ad58b69 100644
--- a/gcc/tree-diagnostic.c
+++ b/gcc/tree-diagnostic.c
@@ -275,6 +275,10 @@ 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);
       return true;
diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
index 4d8177c..7c4c805 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -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,15 +3971,15 @@ 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 and %G 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)
+static void
+percent_K_format (text_info *text, tree t)
 {
-  tree t = va_arg (*text->args_ptr, tree), block;
+  tree block;
   text->set_location (0, EXPR_LOCATION (t), true);
   gcc_assert (pp_ti_abstract_origin (text) != NULL);
   block = TREE_BLOCK (t);
@@ -4022,6 +4023,34 @@ percent_K_format (text_info *text)
     }
 }
 
+/* Handle the %K format for TEXT.  */
+
+void
+percent_K_format (text_info *text)
+{
+  tree t = va_arg (*text->args_ptr, tree);
+  percent_K_format (text, t);
+}
+
+/* Handle the %G format for TEXT.  Same as %K 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);
+}
+
 /* Print the identifier ID to PRETTY-PRINTER.  */
 
 void
diff --git a/gcc/tree-pretty-print.h b/gcc/tree-pretty-print.h
index 07270b7..213841e 100644
--- a/gcc/tree-pretty-print.h
+++ b/gcc/tree-pretty-print.h
@@ -45,6 +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_G_format (text_info *);
 extern void percent_K_format (text_info *);
 extern void pp_tree_identifier (pretty_printer *, tree);
 extern void dump_function_header (FILE *, tree, dump_flags_t);
diff --git a/gcc/c/c-objc-common.c b/gcc/c/c-objc-common.c
index 05212b2..9dd5718 100644
--- a/gcc/c/c-objc-common.c
+++ b/gcc/c/c-objc-common.c
@@ -66,6 +66,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,6 +89,12 @@ 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);
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 2497c7f..483d3b5 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -4048,6 +4048,10 @@ 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);
       return true;
diff --git a/gcc/c-family/c-format.c b/gcc/c-family/c-format.c
index 0a5cc03..0ff9446 100644
--- a/gcc/c-family/c-format.c
+++ b/gcc/c-family/c-format.c
@@ -55,6 +55,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)
diff --git a/gcc/c-family/c-format.h b/gcc/c-family/c-format.h
index 37fa382..05e9bb7 100644
--- a/gcc/c-family/c-format.h
+++ b/gcc/c-family/c-format.h
@@ -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
diff --git a/gcc/testsuite/gcc.dg/format/gcc_diag-10.c b/gcc/testsuite/gcc.dg/format/gcc_diag-10.c
index b3be277..9bda73b 100644
--- a/gcc/testsuite/gcc.dg/format/gcc_diag-10.c
+++ b/gcc/testsuite/gcc.dg/format/gcc_diag-10.c
@@ -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" } */

  reply	other threads:[~2017-08-06 20:07 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-07-08 20:45 [PATCH] " Martin Sebor
2017-07-18  2:51 ` [PING] " Martin Sebor
2017-07-25  3:10   ` [PING #2] " Martin Sebor
2017-07-31 17:29 ` Jeff Law
2017-07-31 19:42   ` Martin Sebor
2017-08-02 16:59     ` Jeff Law
2017-08-06 20:07       ` Martin Sebor [this message]
2017-08-10  5:02         ` [PATCH 1/4] " Jeff Law
2017-08-14 19:21           ` Martin Sebor
2017-08-06 20:07       ` [PATCH] " Martin Sebor
2017-08-09 19:21         ` Jeff Law
2017-08-06 20:07       ` [PATCH 3/4] " Martin Sebor
2017-08-10  7:17         ` Jeff Law
2017-08-10  7:39           ` Richard Biener
2017-08-10 20:21           ` Martin Sebor
2017-08-15  3:06             ` Martin Sebor
2017-08-23 21:11               ` [PING] " Martin Sebor
2017-08-29  5:07                 ` [PING 2] " Martin Sebor
2017-09-19 15:44                   ` [PING 3] " Martin Sebor
2017-09-26  2:27                     ` [PING 4] " Martin Sebor
2017-10-02 22:15             ` Jeff Law
2017-10-21  0:26               ` Martin Sebor
2017-11-04  3:49                 ` Jeff Law
2017-11-10  0:17                   ` Martin Sebor
2017-11-10  0:31                     ` Jeff Law
2017-11-14  9:24         ` [testsuite, committed] Require alloca for c-c++-common/Wstringop-truncation.c Tom de Vries
2017-11-15 15:30         ` [testsuite, committed] Compile strncpy-fix-1.c with -Wno-stringop-truncation Tom de Vries
2017-11-15 15:58           ` Martin Sebor
2017-08-06 20:07       ` [PATCH 2/4] enhance overflow and truncation detection in strncpy and strncat (PR 81117) Martin Sebor
2017-08-10  6:39         ` Jeff Law
2017-08-14 18:04           ` Martin Sebor
2017-08-14 18:29             ` Joseph Myers
2017-08-14 19:26               ` Martin Sebor
2017-08-14 20:41                 ` Joseph Myers
2017-08-14 20:44                   ` Martin Sebor
2017-08-15  3:03                     ` Joseph Myers
2017-11-10 23:03         ` Marc Glisse
2017-11-11 21:10           ` Martin Sebor
2017-08-06 20:07       ` [PATCH 4/4] " Martin Sebor

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=33a2ba18-274d-8229-06b4-c4983f0d3e2f@gmail.com \
    --to=msebor@gmail.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=law@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).