From da67acb9b37cf139da014f5bc11e2dbf25a7d597 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Mon, 14 Aug 2017 18:35:13 +0000 Subject: [PATCH] PR c/81117 - Improve buffer overflow checking in strncpy - part 1 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 --- gcc/ChangeLog | 8 +++++ gcc/c-family/ChangeLog | 7 +++++ gcc/c-family/c-format.c | 37 ++++++++++++++++++++++- gcc/c-family/c-format.h | 1 + gcc/c/ChangeLog | 5 +++ gcc/c/c-objc-common.c | 12 +++++++- gcc/cp/ChangeLog | 5 +++ gcc/cp/error.c | 8 ++++- gcc/gimple-pretty-print.c | 19 ++++++++++++ gcc/gimple-pretty-print.h | 1 + gcc/testsuite/ChangeLog | 5 +++ gcc/testsuite/gcc.dg/format/gcc_diag-10.c | 19 +++++++++--- gcc/tree-diagnostic.c | 8 ++++- gcc/tree-pretty-print.c | 14 ++++----- gcc/tree-pretty-print.h | 2 +- 15 files changed, 135 insertions(+), 16 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index feae522a570..9697dd90170 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2017-08-14 Martin Sebor + + 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 PR translation/79998 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 6d33192c5ac..155383de773 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,10 @@ +2017-08-14 Martin Sebor + + 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 * c-opts.c (c_common_post_options): Replace ASM_OUTPUT_DEF with diff --git a/gcc/c-family/c-format.c b/gcc/c-family/c-format.c index 5e5b494383f..7c9095c2a5b 100644 --- a/gcc/c-family/c-format.c +++ b/gcc/c-family/c-format.c @@ -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 ("% 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 37fa3828485..05e9bb73ef1 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/c/ChangeLog b/gcc/c/ChangeLog index cd0c128edc8..3db4189c7d4 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,8 @@ +2017-08-14 Martin Sebor + + PR c/81117 + * c-objc-common.c (c_objc_common_init): Handle 'G'. + 2017-08-11 Marek Polacek PR c/81795 diff --git a/gcc/c/c-objc-common.c b/gcc/c/c-objc-common.c index 05212b2cb8e..8f4d3eb91c5 100644 --- a/gcc/c/c-objc-common.c +++ b/gcc/c/c-objc-common.c @@ -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; } diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a8a3fccdcd1..3fd74bfc196 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2017-08-14 Martin Sebor + + PR c/81117 + * error.c (cp_printer): Handle 'G'. + 2017-08-11 Martin Liska * decl2.c (get_tls_init_fn): Replace ASM_OUTPUT_DEF with diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 31ca8fe1eb2..e4071547091 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -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': diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c index 5727d14777a..ed8e51c1c46 100644 --- a/gcc/gimple-pretty-print.c +++ b/gcc/gimple-pretty-print.c @@ -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); +} diff --git a/gcc/gimple-pretty-print.h b/gcc/gimple-pretty-print.h index 0b74d1b0494..08720f45936 100644 --- a/gcc/gimple-pretty-print.h +++ b/gcc/gimple-pretty-print.h @@ -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 */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c68732f82f9..2bd4fad5153 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2017-08-14 Martin Sebor + + PR c/81117 + * gcc.dg/format/gcc_diag-10.c: Exercise %G. + 2017-08-14 David Edelsohn * gcc.dg/ucnid-5.c: Skip on AIX. diff --git a/gcc/testsuite/gcc.dg/format/gcc_diag-10.c b/gcc/testsuite/gcc.dg/format/gcc_diag-10.c index b3be2773957..9bda73bc628 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 ("%%>"); /* { 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" } */ diff --git a/gcc/tree-diagnostic.c b/gcc/tree-diagnostic.c index 52b7e7f0bb4..023e896a34a 100644 --- a/gcc/tree-diagnostic.c +++ b/gcc/tree-diagnostic.c @@ -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: diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index 4d8177c4a62..c7509af198b 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,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) diff --git a/gcc/tree-pretty-print.h b/gcc/tree-pretty-print.h index 07270b735a7..d17c5a50452 100644 --- a/gcc/tree-pretty-print.h +++ b/gcc/tree-pretty-print.h @@ -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); -- 2.30.2