There was a bad upper limit in diagnostic_manager::prune_path's test for pruning redundant interprocedural pass information, leading to an ICE.
Additional, the test for pruning [..., call, function-entry, return, ...] triples doesn't work for -fanalyzer-verbosity=0, which doesn't generate function-entry events, leading to cases where -fanalyzer-verbosity=0 could be more verbose than higher limits, e.g.: 'test_3': events 1-4 | | NN | free (ptr); | | ^~~~~~~~~~ | | | | | (1) first 'free' here | NN | called_by_test_3 (); | | ~~~~~~~~~~~~~~~~~~~ | | | | | (2) calling 'called_by_test_3' from 'test_3' | | (3) returning to 'test_3' from 'called_by_test_3' | NN | free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */ | | ~~~~~~~~~~ | | | | | (4) second 'free' here; first 'free' was at (1) | where the call/return would be pruned at higher verbosities. This patch fixes the limits, and prunes the case of a [call, return] pair. gcc/ChangeLog: * analyzer/diagnostic-manager.cc (diagnostic_manager::prune_path): When pruning [..., call, function-entry, return, ...] triples, fix the bounds test and move it inside the loop. Also test for [..., call, return, ...] pairs. gcc/testsuite/ChangeLog: * gcc.dg/analyzer/analyzer-verbosity-0.c: Add coverage for pruning a call/return to an empty function. * gcc.dg/analyzer/analyzer-verbosity-1.c: Likewise. * gcc.dg/analyzer/analyzer-verbosity-2.c: Likewise. --- gcc/analyzer/diagnostic-manager.cc | 32 ++++++++++++++++++++-- .../gcc.dg/analyzer/analyzer-verbosity-0.c | 29 ++++++++++++++++++++ .../gcc.dg/analyzer/analyzer-verbosity-1.c | 30 ++++++++++++++++++++ .../gcc.dg/analyzer/analyzer-verbosity-2.c | 30 ++++++++++++++++++++ 4 files changed, 118 insertions(+), 3 deletions(-) diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc index 926900b..8cd4507 100644 --- a/gcc/analyzer/diagnostic-manager.cc +++ b/gcc/analyzer/diagnostic-manager.cc @@ -1076,10 +1076,12 @@ diagnostic_manager::prune_path (checker_path *path, do { changed = false; - int idx = path->m_events.length () - 3; - while (idx >= 0 && idx < (signed)path->m_events.length ()) + int idx = path->m_events.length () - 1; + while (idx >= 0) { - if (path->m_events[idx]->is_call_p () + /* Prune [..., call, function-entry, return, ...] triples. */ + if (idx + 2 < (signed)path->m_events.length () + && path->m_events[idx]->is_call_p () && path->m_events[idx + 1]->is_function_entry_p () && path->m_events[idx + 2]->is_return_p ()) { @@ -1095,7 +1097,31 @@ diagnostic_manager::prune_path (checker_path *path, path->delete_event (idx + 1); path->delete_event (idx); changed = true; + idx--; + continue; } + + /* Prune [..., call, return, ...] pairs + (for -fanalyzer-verbosity=0). */ + if (idx + 1 < (signed)path->m_events.length () + && path->m_events[idx]->is_call_p () + && path->m_events[idx + 1]->is_return_p ()) + { + if (get_logger ()) + { + label_text desc (path->m_events[idx]->get_desc (false)); + log ("filtering events %i-%i:" + " irrelevant call/return: %s", + idx, idx + 1, desc.m_buffer); + desc.maybe_free (); + } + path->delete_event (idx + 1); + path->delete_event (idx); + changed = true; + idx--; + continue; + } + idx--; } diff --git a/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-0.c b/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-0.c index 98200b3..1103cc6 100644 --- a/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-0.c +++ b/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-0.c @@ -131,3 +131,32 @@ void test_2 (void *ptr, int a, int b) // TODO: range cases +/* The call/return to this function shouldn't appear in the path. */ + +void called_by_test_3 (void) +{ +} + +void test_3 (void *ptr) +{ + free (ptr); + called_by_test_3 (); + free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */ +} + +/* { dg-begin-multiline-output "" } + NN | free (ptr); + | ^~~~~~~~~~ + 'test_3': events 1-2 + | + | NN | free (ptr); + | | ^~~~~~~~~~ + | | | + | | (1) first 'free' here + | NN | called_by_test_3 (); + | NN | free (ptr); + | | ~~~~~~~~~~ + | | | + | | (2) second 'free' here; first 'free' was at (1) + | + { dg-end-multiline-output "" } */ diff --git a/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-1.c b/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-1.c index 7e437bb..80039d5 100644 --- a/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-1.c @@ -158,3 +158,33 @@ void test_2 (void *ptr, int a, int b) | | (8) second 'free' here; first 'free' was at (4) | { dg-end-multiline-output "" } */ + +/* The call/return to this function shouldn't appear in the path. */ + +void called_by_test_3 (void) +{ +} + +void test_3 (void *ptr) +{ + free (ptr); + called_by_test_3 (); + free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */ +} + +/* { dg-begin-multiline-output "" } + NN | free (ptr); + | ^~~~~~~~~~ + 'test_3': events 1-2 + | + | NN | free (ptr); + | | ^~~~~~~~~~ + | | | + | | (1) first 'free' here + | NN | called_by_test_3 (); + | NN | free (ptr); + | | ~~~~~~~~~~ + | | | + | | (2) second 'free' here; first 'free' was at (1) + | + { dg-end-multiline-output "" } */ diff --git a/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-2.c b/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-2.c index 2c9e5da..9b87d43 100644 --- a/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-2.c +++ b/gcc/testsuite/gcc.dg/analyzer/analyzer-verbosity-2.c @@ -189,3 +189,33 @@ void test_2 (void *ptr, int a, int b) { dg-end-multiline-output "" } */ // TODO: range cases + +/* The call/return to this function shouldn't appear in the path. */ + +void called_by_test_3 (void) +{ +} + +void test_3 (void *ptr) +{ + free (ptr); + called_by_test_3 (); + free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */ +} + +/* { dg-begin-multiline-output "" } + NN | free (ptr); + | ^~~~~~~~~~ + 'test_3': events 1-2 + | + | NN | free (ptr); + | | ^~~~~~~~~~ + | | | + | | (1) first 'free' here + | NN | called_by_test_3 (); + | NN | free (ptr); + | | ~~~~~~~~~~ + | | | + | | (2) second 'free' here; first 'free' was at (1) + | + { dg-end-multiline-output "" } */ -- 1.8.5.3