This patch extends the path-printing support to cope with paths for signal-handlers, popping the stack to a new entrypoint, with events outside any function.
gcc/testsuite/ChangeLog: * gcc.dg/plugin/diagnostic-test-paths-4.c: New test. * gcc.dg/plugin/diagnostic_plugin_test_paths.c (example_3): New. (pass_test_show_path::execute): Call it. * gcc.dg/plugin/plugin.exp (plugin_test_list): Add diagnostic-test-paths-4.c. gcc/ChangeLog: * tree-diagnostic-path.cc (path_summary::print): Support NULL_TREE for range->fndecl. Handle disjoint paths in which the stack pops below the start point. --- .../gcc.dg/plugin/diagnostic-test-paths-4.c | 83 +++++++++++++++++++ .../plugin/diagnostic_plugin_test_paths.c | 81 ++++++++++++++++++ gcc/testsuite/gcc.dg/plugin/plugin.exp | 1 + gcc/tree-diagnostic-path.cc | 75 +++++++++-------- 4 files changed, 207 insertions(+), 33 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-4.c diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-4.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-4.c new file mode 100644 index 000000000000..41cbaaaaa976 --- /dev/null +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-4.c @@ -0,0 +1,83 @@ +/* { dg-do compile } */ +/* { dg-options "-fdiagnostics-path-format=inline-events -fdiagnostics-show-caret -fdiagnostics-show-line-numbers -fdiagnostics-nn-line-numbers" } */ + +#include <stdio.h> +#include <signal.h> +#include <stdlib.h> + +extern void body_of_program(void); + +void custom_logger(const char *msg) +{ + fprintf(stderr, "LOG: %s", msg); /* { dg-warning "call to 'fprintf' from within signal handler" } */ +} + +static void int_handler(int signum) +{ + custom_logger("got signal"); +} + +static void register_handler () +{ + signal(SIGINT, int_handler); +} + +void test (void) +{ + register_handler (); + body_of_program(); +} + +/* { dg-begin-multiline-output "" } + NN | fprintf(stderr, "LOG: %s", msg); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 'test': events 1-2 + | + | NN | { + | | ^ + | | | + | | (1) entering 'test' + | NN | register_handler (); + | | ~~~~~~~~~~~~~~~~~~~ + | | | + | | (2) calling 'register_handler' + | + +--> 'register_handler': events 3-4 + | + | NN | { + | | ^ + | | | + | | (3) entering 'register_handler' + | NN | signal(SIGINT, int_handler); + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (4) registering 'int_handler' as signal handler + | + event 5 + | + |cc1: + | (5): later on, when the signal is delivered to the process + | + +--> 'int_handler': events 6-7 + | + | NN | { + | | ^ + | | | + | | (6) entering 'int_handler' + | NN | custom_logger("got signal"); + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (7) calling 'custom_logger' + | + +--> 'custom_logger': events 8-9 + | + | NN | { + | | ^ + | | | + | | (8) entering 'custom_logger' + | NN | fprintf(stderr, "LOG: %s", msg); + | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | | | + | | (9) calling 'fprintf' + | + { dg-end-multiline-output "" } */ diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_paths.c b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_paths.c index 823981550333..cf05ca3a5d32 100644 --- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_paths.c +++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_paths.c @@ -341,11 +341,92 @@ example_2 () } } +/* Example 3: an interprocedural path with a callback. */ + +static void +example_3 () +{ + gimple_stmt_iterator gsi; + basic_block bb; + + event_location_t entry_to_custom_logger; + event_location_t call_to_fprintf; + + event_location_t entry_to_int_handler; + event_location_t call_to_custom_logger; + + event_location_t entry_to_register_handler; + event_location_t call_to_signal; + + event_location_t entry_to_test; + event_location_t call_to_register_handler; + + cgraph_node *node; + FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node) + { + function *fun = node->get_fun (); + FOR_EACH_BB_FN (bb, fun) + { + check_for_named_function (fun, "custom_logger", + &entry_to_custom_logger); + check_for_named_function (fun, "int_handler", + &entry_to_int_handler); + check_for_named_function (fun, "register_handler", + &entry_to_register_handler); + check_for_named_function (fun, "test", + &entry_to_test); + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple *stmt = gsi_stmt (gsi); + if (gcall *call = check_for_named_call (stmt, "fprintf", 3)) + call_to_fprintf.set (call, fun); + if (gcall *call = check_for_named_call (stmt, "custom_logger", 1)) + call_to_custom_logger.set (call, fun); + if (gcall *call = check_for_named_call (stmt, "register_handler", + 0)) + call_to_register_handler.set (call, fun); + if (gcall *call = check_for_named_call (stmt, "signal", 2)) + call_to_signal.set (call, fun); + } + } + } + + if (call_to_fprintf.m_fun) + { + auto_diagnostic_group d; + + gcc_rich_location richloc (call_to_fprintf.m_loc); + test_diagnostic_path path (global_dc->printer); + path.add_entry (entry_to_test, 1, "test"); + path.add_call (call_to_register_handler, 1, + entry_to_register_handler, "register_handler"); + path.add_event (call_to_signal.m_loc, call_to_signal.m_fun->decl, + 2, "registering 'int_handler' as signal handler"); + path.add_event (UNKNOWN_LOCATION, NULL_TREE, 0, + "later on, when the signal is delivered to the process"); + path.add_entry (entry_to_int_handler, 1, "int_handler"); + path.add_call (call_to_custom_logger, 1, + entry_to_custom_logger, "custom_logger"); + path.add_leaf_call (call_to_fprintf, 2, "fprintf"); + + richloc.set_path (&path); + + diagnostic_metadata m; + /* CWE-479: Signal Handler Use of a Non-reentrant Function. */ + m.add_cwe (479); + + warning_at (&richloc, m, 0, + "call to %qs from within signal handler", + "fprintf"); + } +} + unsigned int pass_test_show_path::execute (function *) { example_1 (); example_2 (); + example_3 (); return 0; } diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp b/gcc/testsuite/gcc.dg/plugin/plugin.exp index 4ae30481fb88..6fdb1c67b9e6 100644 --- a/gcc/testsuite/gcc.dg/plugin/plugin.exp +++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp @@ -98,6 +98,7 @@ set plugin_test_list [list \ diagnostic-test-paths-1.c \ diagnostic-test-paths-2.c \ diagnostic-test-paths-3.c \ + diagnostic-test-paths-4.c \ diagnostic-path-format-default.c \ diagnostic-path-format-none.c \ diagnostic-path-format-separate-events.c \ diff --git a/gcc/tree-diagnostic-path.cc b/gcc/tree-diagnostic-path.cc index abb418dd2fa9..a6b51fd9228b 100644 --- a/gcc/tree-diagnostic-path.cc +++ b/gcc/tree-diagnostic-path.cc @@ -339,12 +339,16 @@ path_summary::print (diagnostic_context *dc, bool show_depths) const cur_indent += strlen (push_prefix); } } - print_fndecl (pp, range->m_fndecl, true); + if (range->m_fndecl) + { + print_fndecl (pp, range->m_fndecl, true); + pp_string (pp, ": "); + } if (range->m_start_idx == range->m_end_idx) - pp_printf (pp, ": event %i", + pp_printf (pp, "event %i", range->m_start_idx + 1); else - pp_printf (pp, ": events %i-%i", + pp_printf (pp, "events %i-%i", range->m_start_idx + 1, range->m_end_idx + 1); if (show_depths) pp_printf (pp, " (depth %i)", range->m_stack_depth); @@ -387,36 +391,41 @@ path_summary::print (diagnostic_context *dc, bool show_depths) const if (range->m_stack_depth > next_range->m_stack_depth) { - /* Show returning from stack frame(s), by printing - something like: - " |\n" - " <------------ +\n" - " |\n". */ - - gcc_assert (vbar_column_for_depth.get - (next_range->m_stack_depth)); - - int vbar_for_next_frame - = *vbar_column_for_depth.get (next_range->m_stack_depth); - - int indent_for_next_frame - = vbar_for_next_frame - per_frame_indent; - write_indent (pp, vbar_for_next_frame); - pp_string (pp, start_line_color); - pp_character (pp, '<'); - for (int i = indent_for_next_frame + per_frame_indent; - i < cur_indent + per_frame_indent - 1; i++) - pp_character (pp, '-'); - pp_character (pp, '+'); - pp_string (pp, end_line_color); - pp_newline (pp); - cur_indent = indent_for_next_frame; - - write_indent (pp, vbar_for_next_frame); - pp_string (pp, start_line_color); - pp_printf (pp, "|"); - pp_string (pp, end_line_color); - pp_newline (pp); + if (vbar_column_for_depth.get (next_range->m_stack_depth)) + { + /* Show returning from stack frame(s), by printing + something like: + " |\n" + " <------------ +\n" + " |\n". */ + int vbar_for_next_frame + = *vbar_column_for_depth.get (next_range->m_stack_depth); + + int indent_for_next_frame + = vbar_for_next_frame - per_frame_indent; + write_indent (pp, vbar_for_next_frame); + pp_string (pp, start_line_color); + pp_character (pp, '<'); + for (int i = indent_for_next_frame + per_frame_indent; + i < cur_indent + per_frame_indent - 1; i++) + pp_character (pp, '-'); + pp_character (pp, '+'); + pp_string (pp, end_line_color); + pp_newline (pp); + cur_indent = indent_for_next_frame; + + write_indent (pp, vbar_for_next_frame); + pp_string (pp, start_line_color); + pp_printf (pp, "|"); + pp_string (pp, end_line_color); + pp_newline (pp); + } + else + { + /* Handle disjoint paths (e.g. a callback at some later + time). */ + cur_indent = base_indent; + } } else if (range->m_stack_depth < next_range->m_stack_depth) { -- 2.21.0