Age | Commit message (Collapse) | Author | Files | Lines |
|
This patch extends -Wanalyzer-out-of-bounds so that, where possible, it
will emit a text art diagram visualizing the spatial relationship between
(a) the memory region that the analyzer predicts would be accessed, versus
(b) the range of memory that is valid to access - whether they overlap,
are touching, are close or far apart; which one is before or after in
memory, the relative sizes involved, the direction of the access (read vs
write), and, in some cases, the values of data involved. This diagram
can be suppressed using -fdiagnostics-text-art-charset=none.
For example, given:
int32_t arr[10];
int32_t int_arr_read_element_before_start_far(void)
{
return arr[-100];
}
it emits:
demo-1.c: In function ‘int_arr_read_element_before_start_far’:
demo-1.c:7:13: warning: buffer under-read [CWE-127] [-Wanalyzer-out-of-bounds]
7 | return arr[-100];
| ~~~^~~~~~
‘int_arr_read_element_before_start_far’: event 1
|
| 7 | return arr[-100];
| | ~~~^~~~~~
| | |
| | (1) out-of-bounds read from byte -400 till byte -397 but ‘arr’ starts at byte 0
|
demo-1.c:7:13: note: valid subscripts for ‘arr’ are ‘[0]’ to ‘[9]’
┌───────────────────────────┐
│read of ‘int32_t’ (4 bytes)│
└───────────────────────────┘
^
│
│
┌───────────────────────────┐ ┌────────┬────────┬─────────┐
│ │ │ [0] │ ... │ [9] │
│ before valid range │ ├────────┴────────┴─────────┤
│ │ │‘arr’ (type: ‘int32_t[10]’)│
└───────────────────────────┘ └───────────────────────────┘
├─────────────┬─────────────┤├─────┬──────┤├─────────────┬─────────────┤
│ │ │
╭────────────┴───────────╮ ╭────┴────╮ ╭───────┴──────╮
│⚠️ under-read of 4 bytes│ │396 bytes│ │size: 40 bytes│
╰────────────────────────╯ ╰─────────╯ ╰──────────────╯
and given:
#include <string.h>
void
test_non_ascii ()
{
char buf[5];
strcpy (buf, "文字化け");
}
it emits:
demo-2.c: In function ‘test_non_ascii’:
demo-2.c:7:3: warning: stack-based buffer overflow [CWE-121] [-Wanalyzer-out-of-bounds]
7 | strcpy (buf, "文字化け");
| ^~~~~~~~~~~~~~~~~~~~~~~~
‘test_non_ascii’: events 1-2
|
| 6 | char buf[5];
| | ^~~
| | |
| | (1) capacity: 5 bytes
| 7 | strcpy (buf, "文字化け");
| | ~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (2) out-of-bounds write from byte 5 till byte 12 but ‘buf’ ends at byte 5
|
demo-2.c:7:3: note: write of 8 bytes to beyond the end of ‘buf’
7 | strcpy (buf, "文字化け");
| ^~~~~~~~~~~~~~~~~~~~~~~~
demo-2.c:7:3: note: valid subscripts for ‘buf’ are ‘[0]’ to ‘[4]’
┌─────┬─────┬─────┬────┬────┐┌────┬────┬────┬────┬────┬────┬────┬──────┐
│ [0] │ [1] │ [2] │[3] │[4] ││[5] │[6] │[7] │[8] │[9] │[10]│[11]│ [12] │
├─────┼─────┼─────┼────┼────┤├────┼────┼────┼────┼────┼────┼────┼──────┤
│0xe6 │0x96 │0x87 │0xe5│0xad││0x97│0xe5│0x8c│0x96│0xe3│0x81│0x91│ 0x00 │
├─────┴─────┴─────┼────┴────┴┴────┼────┴────┴────┼────┴────┴────┼──────┤
│ U+6587 │ U+5b57 │ U+5316 │ U+3051 │U+0000│
├─────────────────┼───────────────┼──────────────┼──────────────┼──────┤
│ 文 │ 字 │ 化 │ け │ NUL │
├─────────────────┴───────────────┴──────────────┴──────────────┴──────┤
│ string literal (type: ‘char[13]’) │
└──────────────────────────────────────────────────────────────────────┘
│ │ │ │ │ │ │ │ │ │ │ │ │
│ │ │ │ │ │ │ │ │ │ │ │ │
v v v v v v v v v v v v v
┌─────┬────────────────┬────┐┌─────────────────────────────────────────┐
│ [0] │ ... │[4] ││ │
├─────┴────────────────┴────┤│ after valid range │
│ ‘buf’ (type: ‘char[5]’) ││ │
└───────────────────────────┘└─────────────────────────────────────────┘
├─────────────┬─────────────┤├────────────────────┬────────────────────┤
│ │
╭────────┴────────╮ ╭───────────┴──────────╮
│capacity: 5 bytes│ │⚠️ overflow of 8 bytes│
╰─────────────────╯ ╰──────────────────────╯
showing that the overflow occurs partway through the UTF-8 encoding of
the U+5b57 code point.
There are lots more examples in the test suite.
It doesn't show up in this email, but the above diagrams are colorized
to constrast the valid and invalid access ranges.
gcc/ChangeLog:
PR analyzer/106626
* Makefile.in (ANALYZER_OBJS): Add analyzer/access-diagram.o.
* doc/invoke.texi (Wanalyzer-out-of-bounds): Add description of
text art.
(fanalyzer-debug-text-art): New.
gcc/analyzer/ChangeLog:
PR analyzer/106626
* access-diagram.cc: New file.
* access-diagram.h: New file.
* analyzer.h (class region_offset): Add default ctor.
(region_offset::make_byte_offset): New decl.
(region_offset::concrete_p): New.
(region_offset::get_concrete_byte_offset): New.
(region_offset::calc_symbolic_bit_offset): New decl.
(region_offset::calc_symbolic_byte_offset): New decl.
(region_offset::dump_to_pp): New decl.
(region_offset::dump): New decl.
(operator<, operator<=, operator>, operator>=): New decls for
region_offset.
* analyzer.opt
(-param=analyzer-text-art-string-ellipsis-threshold=): New.
(-param=analyzer-text-art-string-ellipsis-head-len=): New.
(-param=analyzer-text-art-string-ellipsis-tail-len=): New.
(-param=analyzer-text-art-ideal-canvas-width=): New.
(fanalyzer-debug-text-art): New.
* bounds-checking.cc: Include "intl.h", "diagnostic-diagram.h",
and "analyzer/access-diagram.h".
(class out_of_bounds::oob_region_creation_event_capacity): New.
(out_of_bounds::out_of_bounds): Add "model" and "sval_hint"
params.
(out_of_bounds::mark_interesting_stuff): Use the base region.
(out_of_bounds::add_region_creation_events): Use
oob_region_creation_event_capacity.
(out_of_bounds::get_dir): New pure vfunc.
(out_of_bounds::maybe_show_notes): New.
(out_of_bounds::maybe_show_diagram): New.
(out_of_bounds::make_access_diagram): New.
(out_of_bounds::m_model): New field.
(out_of_bounds::m_sval_hint): New field.
(out_of_bounds::m_region_creation_event_id): New field.
(concrete_out_of_bounds::concrete_out_of_bounds): Update for new
fields.
(concrete_past_the_end::concrete_past_the_end): Likewise.
(concrete_past_the_end::add_region_creation_events): Use
oob_region_creation_event_capacity.
(concrete_buffer_overflow::concrete_buffer_overflow): Update for
new fields.
(concrete_buffer_overflow::emit): Replace call to
maybe_describe_array_bounds with maybe_show_notes.
(concrete_buffer_overflow::get_dir): New.
(concrete_buffer_over_read::concrete_buffer_over_read): Update for
new fields.
(concrete_buffer_over_read::emit): Replace call to
maybe_describe_array_bounds with maybe_show_notes.
(concrete_buffer_overflow::get_dir): New.
(concrete_buffer_underwrite::concrete_buffer_underwrite): Update
for new fields.
(concrete_buffer_underwrite::emit): Replace call to
maybe_describe_array_bounds with maybe_show_notes.
(concrete_buffer_underwrite::get_dir): New.
(concrete_buffer_under_read::concrete_buffer_under_read): Update
for new fields.
(concrete_buffer_under_read::emit): Replace call to
maybe_describe_array_bounds with maybe_show_notes.
(concrete_buffer_under_read::get_dir): New.
(symbolic_past_the_end::symbolic_past_the_end): Update for new
fields.
(symbolic_buffer_overflow::symbolic_buffer_overflow): Likewise.
(symbolic_buffer_overflow::emit): Call maybe_show_notes.
(symbolic_buffer_overflow::get_dir): New.
(symbolic_buffer_over_read::symbolic_buffer_over_read): Update for
new fields.
(symbolic_buffer_over_read::emit): Call maybe_show_notes.
(symbolic_buffer_over_read::get_dir): New.
(region_model::check_symbolic_bounds): Add "sval_hint" param. Pass
it and sized_offset_reg to diagnostics.
(region_model::check_region_bounds): Add "sval_hint" param, passing
it to diagnostics.
* diagnostic-manager.cc
(diagnostic_manager::emit_saved_diagnostic): Pass logger to
pending_diagnostic::emit.
* engine.cc: Add logger param to pending_diagnostic::emit
implementations.
* infinite-recursion.cc: Likewise.
* kf-analyzer.cc: Likewise.
* kf.cc: Likewise. Add nullptr for new param of
check_region_for_write.
* pending-diagnostic.h: Likewise in decl.
* region-model-manager.cc
(region_model_manager::get_or_create_int_cst): Convert param from
poly_int64 to const poly_wide_int_ref &.
(region_model_manager::maybe_fold_binop): Support type being NULL
when checking for floating-point types.
Check for (X + Y) - X => Y. Be less strict about types when folding
associative ops. Check for (X + Y) * CST => (X * CST) + (Y * CST).
* region-model-manager.h
(region_model_manager::get_or_create_int_cst): Convert param from
poly_int64 to const poly_wide_int_ref &.
* region-model.cc: Add logger param to pending_diagnostic::emit
implementations.
(region_model::check_external_function_for_access_attr): Update
for new param of check_region_for_write.
(region_model::deref_rvalue): Use nullptr rather than NULL.
(region_model::get_capacity): Handle RK_STRING.
(region_model::check_region_access): Add "sval_hint" param; pass it to
check_region_bounds.
(region_model::check_region_for_write): Add "sval_hint" param;
pass it to check_region_access.
(region_model::check_region_for_read): Add NULL for new param to
check_region_access.
(region_model::set_value): Pass rhs_sval to
check_region_for_write.
(region_model::get_representative_path_var_1): Handle SK_CONSTANT
in the check for infinite recursion.
* region-model.h (region_model::check_region_for_write): Add
"sval_hint" param.
(region_model::check_region_access): Likewise.
(region_model::check_symbolic_bounds): Likewise.
(region_model::check_region_bounds): Likewise.
* region.cc (region_offset::make_byte_offset): New.
(region_offset::calc_symbolic_bit_offset): New.
(region_offset::calc_symbolic_byte_offset): New.
(region_offset::dump_to_pp): New.
(region_offset::dump): New.
(struct linear_op): New.
(operator<, operator<=, operator>, operator>=): New, for
region_offset.
(region::get_next_offset): New.
(region::get_relative_symbolic_offset): Use ptrdiff_type_node.
(field_region::get_relative_symbolic_offset): Likewise.
(element_region::get_relative_symbolic_offset): Likewise.
(bit_range_region::get_relative_symbolic_offset): Likewise.
* region.h (region::get_next_offset): New decl.
* sm-fd.cc: Add logger param to pending_diagnostic::emit
implementations.
* sm-file.cc: Likewise.
* sm-malloc.cc: Likewise.
* sm-pattern-test.cc: Likewise.
* sm-sensitive.cc: Likewise.
* sm-signal.cc: Likewise.
* sm-taint.cc: Likewise.
* store.cc (bit_range::contains_p): Allow "out" to be null.
* store.h (byte_range::get_start_bit_offset): New.
(byte_range::get_next_bit_offset): New.
* varargs.cc: Add logger param to pending_diagnostic::emit
implementations.
gcc/testsuite/ChangeLog:
PR analyzer/106626
* gcc.dg/analyzer/data-model-1.c (test_16): Update for
out-of-bounds working.
* gcc.dg/analyzer/out-of-bounds-diagram-1-ascii.c: New test.
* gcc.dg/analyzer/out-of-bounds-diagram-1-debug.c: New test.
* gcc.dg/analyzer/out-of-bounds-diagram-1-emoji.c: New test.
* gcc.dg/analyzer/out-of-bounds-diagram-1-json.c: New test.
* gcc.dg/analyzer/out-of-bounds-diagram-1-sarif.c: New test.
* gcc.dg/analyzer/out-of-bounds-diagram-1-unicode.c: New test.
* gcc.dg/analyzer/out-of-bounds-diagram-10.c: New test.
* gcc.dg/analyzer/out-of-bounds-diagram-11.c: New test.
* gcc.dg/analyzer/out-of-bounds-diagram-12.c: New test.
* gcc.dg/analyzer/out-of-bounds-diagram-13.c: New test.
* gcc.dg/analyzer/out-of-bounds-diagram-14.c: New test.
* gcc.dg/analyzer/out-of-bounds-diagram-15.c: New test.
* gcc.dg/analyzer/out-of-bounds-diagram-2.c: New test.
* gcc.dg/analyzer/out-of-bounds-diagram-3.c: New test.
* gcc.dg/analyzer/out-of-bounds-diagram-4.c: New test.
* gcc.dg/analyzer/out-of-bounds-diagram-5-ascii.c: New test.
* gcc.dg/analyzer/out-of-bounds-diagram-5-unicode.c: New test.
* gcc.dg/analyzer/out-of-bounds-diagram-6.c: New test.
* gcc.dg/analyzer/out-of-bounds-diagram-7.c: New test.
* gcc.dg/analyzer/out-of-bounds-diagram-8.c: New test.
* gcc.dg/analyzer/out-of-bounds-diagram-9.c: New test.
* gcc.dg/analyzer/pattern-test-2.c: Update expected results.
* gcc.dg/analyzer/pr101962.c: Update expected results.
* gcc.dg/plugin/analyzer_gil_plugin.c: Add logger param to
pending_diagnostic::emit implementations.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
gcc/analyzer/ChangeLog:
PR analyzer/108935
* infinite-recursion.cc (contains_unknown_p): New.
(sufficiently_different_region_binding_p): New function, splitting
out inner loop from...
(sufficiently_different_p): ...here. Extend detection of unknown
svalues to also include svalues that contain unknown. Treat
changes in frames below the entry to the recursion as being
sufficiently different to reject being an infinite recursion.
gcc/testsuite/ChangeLog:
PR analyzer/108935
* gcc.dg/analyzer/infinite-recursion-pr108935-1.c: New test.
* gcc.dg/analyzer/infinite-recursion-pr108935-1a.c: New test.
* gcc.dg/analyzer/infinite-recursion-pr108935-2.c: New test.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
This patch updates poisoned_value_diagnostic so that, where possible,
it checks to see if the value is still poisoned along the execution
path seen during feasibility analysis, rather than just that seen
in the exploded graph.
Integration testing shows this reduction in the number of
false positives:
-Wanalyzer-use-of-uninitialized-value: 191 -> 153 (-38)
where the changes happen in:
coreutils-9.1: 34 -> 20 (-14)
qemu-7.2.0: 78 -> 54 (-24)
gcc/analyzer/ChangeLog:
PR analyzer/108664
PR analyzer/108666
PR analyzer/108725
* diagnostic-manager.cc (epath_finder::get_best_epath): Add
"target_stmt" param.
(epath_finder::explore_feasible_paths): Likewise.
(epath_finder::process_worklist_item): Likewise.
(saved_diagnostic::calc_best_epath): Pass m_stmt to
epath_finder::get_best_epath.
* engine.cc (feasibility_state::maybe_update_for_edge): Move
per-stmt logic to...
(feasibility_state::update_for_stmt): ...this new function.
* exploded-graph.h (feasibility_state::update_for_stmt): New decl.
* feasible-graph.cc (feasible_node::get_state_at_stmt): New.
* feasible-graph.h: Include "analyzer/exploded-graph.h".
(feasible_node::get_state_at_stmt): New decl.
* infinite-recursion.cc
(infinite_recursion_diagnostic::check_valid_fpath_p): Update for
vfunc signature change.
* pending-diagnostic.h (pending_diagnostic::check_valid_fpath_p):
Convert first param to a reference. Add stmt param.
* region-model.cc: Include "analyzer/feasible-graph.h".
(poisoned_value_diagnostic::poisoned_value_diagnostic): Add
"check_expr" param.
(poisoned_value_diagnostic::check_valid_fpath_p): New.
(poisoned_value_diagnostic::m_check_expr): New field.
(region_model::check_for_poison): Attempt to supply a check_expr
to the diagnostic
(region_model::deref_rvalue): Add NULL for new check_expr param
of poisoned_value_diagnostic.
(region_model::get_or_create_region_for_heap_alloc): Don't reuse
regions that are marked as TOUCHED.
gcc/testsuite/ChangeLog:
PR analyzer/108664
PR analyzer/108666
PR analyzer/108725
* gcc.dg/analyzer/coreutils-cksum-pr108664.c: New test.
* gcc.dg/analyzer/coreutils-sum-pr108666.c: New test.
* gcc.dg/analyzer/torture/uninit-pr108725.c: New test.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
Reject -Wanalyzer-infinite-recursion diagnostics in which control flow
has been affected by conjured_svalues between the initial call to a
function and the subsequent entry to that function. This prevents false
positives such as in qemu's recursive JSON parser where function calls are
changing state in the rest of the program (e.g. consuming tokens), despite
the modelled state being effectively identical at both nested entrypoints.
gcc/analyzer/ChangeLog:
PR analyzer/108524
* analyzer.h (class feasible_node): New forward decl.
* diagnostic-manager.cc (epath_finder::get_best_epath): Add "pd"
param.
(epath_finder::explore_feasible_paths): Likewise.
(epath_finder::process_worklist_item): Likewise. Use it to call
pending_diagnostic::check_valid_fpath_p on the final fpath to
give pending_diagnostic a way to add additional restrictions on
feasibility.
(saved_diagnostic::calc_best_epath): Pass pending_diagnostic to
epath_finder::get_best_epath.
* infinite-recursion.cc: Include "analyzer/feasible-graph.h".
(infinite_recursion_diagnostic::check_valid_fpath_p): New.
(infinite_recursion_diagnostic::fedge_uses_conjured_svalue_p): New.
(infinite_recursion_diagnostic::expr_uses_conjured_svalue_p): New.
* pending-diagnostic.h (pending_diagnostic::check_valid_fpath_p):
New vfunc.
gcc/testsuite/ChangeLog:
PR analyzer/108524
* gcc.dg/analyzer/infinite-recursion-pr108524-1.c: New test.
* gcc.dg/analyzer/infinite-recursion-pr108524-2.c: New test.
* gcc.dg/analyzer/infinite-recursion-pr108524-qobject-json-parser.c:
New test.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
My integration testing [1] of -fanalyzer in GCC 13 is showing a lot of
diagnostics from the new -Wanalyzer-deref-before-check warning on
real-world C projects, and most of these seem to be false positives.
This patch updates the warning to make it much less likely to fire:
- only intraprocedural cases are now reported
- reject cases in which there are control flow paths to the check
that didn't come through the dereference, by looking at BB dominator
information. This fixes a false positive seen in git-2.39.0's
pack-revindex.c: load_revindex_from_disk (PR analyzer/108455), in
which a shared "cleanup:" section checks "data" for NULL, and
depending on how much of the function is executed "data" might or
might not have already been dereferenced.
The counts of -Wanalyzer-deref-before-check diagnostics in [1]
before/after this patch show this improvement:
Known false positives: 6 -> 0 (-6)
Known true positives: 1 -> 1
Unclassified positives: 123 -> 63 (-60)
[1] https://github.com/davidmalcolm/gcc-analyzer-integration-tests
gcc/analyzer/ChangeLog:
PR analyzer/108455
* analyzer.h (class checker_event): New forward decl.
(class state_change_event): Indent.
(class warning_event): New forward decl.
* checker-event.cc (state_change_event::state_change_event): Add
"enode" param.
(warning_event::get_desc): Update for new param of
evdesc::final_event ctor.
* checker-event.h (state_change_event::state_change_event): Add
"enode" param.
(state_change_event::get_exploded_node): New accessor.
(state_change_event::m_enode): New field.
(warning_event::warning_event): New "enode" param.
(warning_event::get_exploded_node): New accessor.
(warning_event::m_enode): New field.
* diagnostic-manager.cc
(state_change_event_creator::on_global_state_change): Pass
src_node to state_change_event ctor.
(state_change_event_creator::on_state_change): Likewise.
(null_assignment_sm_context::set_next_state): Pass NULL for
new param of state_change_event ctor.
* infinite-recursion.cc
(infinite_recursion_diagnostic::add_final_event): Update for new
param of warning_event ctor.
* pending-diagnostic.cc (pending_diagnostic::add_final_event):
Pass enode to warning_event ctor.
* pending-diagnostic.h (evdesc::final_event): Add reference to
warning_event.
* sm-malloc.cc: Include "analyzer/checker-event.h" and
"analyzer/exploded-graph.h".
(deref_before_check::deref_before_check): Initialize new fields.
(deref_before_check::emit): Reject warnings in which we were
unable to determine the enodes of the dereference and the check.
Reject warnings interprocedural warnings. Reject warnings in which
the dereference doesn't dominate the check.
(deref_before_check::describe_state_change): Set m_deref_enode.
(deref_before_check::describe_final_event): Set m_check_enode.
(deref_before_check::m_deref_enode): New field.
(deref_before_check::m_check_enode): New field.
gcc/testsuite/ChangeLog:
PR analyzer/108455
* gcc.dg/analyzer/deref-before-check-1.c: Add test coverage
involving dominance.
* gcc.dg/analyzer/deref-before-check-pr108455-1.c: New test.
* gcc.dg/analyzer/deref-before-check-pr108455-git-pack-revindex.c:
New test.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
|
|
gcc/analyzer/ChangeLog:
* analyzer.h (struct event_loc_info): New forward decl.
* bounds-checking.cc: Use event_loc_info throughout to bundle the
loc, fndecl, depth triples.
* call-info.cc: Likewise.
* checker-event.cc: Likewise.
* checker-event.h (struct event_loc_info): New decl. Use it
throughout to bundle the loc, fndecl, depth triples.
* checker-path.cc: Likewise.
* checker-path.h: Likewise.
* diagnostic-manager.cc: Likewise.
* engine.cc: Likewise.
* infinite-recursion.cc: Likewise.
* pending-diagnostic.cc: Likewise.
* pending-diagnostic.h: Likewise.
* region-model.cc: Likewise.
* sm-signal.cc: Likewise.
* varargs.cc: Likewise.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
This patch adds a new -Wanalyzer-infinite-recursion warning to
-fanalyzer, which complains about certain cases of infinite recursion.
Specifically, when it detects recursion during its symbolic execution
of the user's code, it compares the state of memory to that at the
previous level of recursion, and if nothing appears to have effectively
changed, it issues a warning.
Unlike the middle-end warning -Winfinite-recursion (added by Martin
Sebor in GCC 12; r12-5483-g30ba058f77eedf), the analyzer warning
complains if there exists an interprocedural path in which recursion
occurs in which memory has not changed, whereas -Winfinite-recursion
complains if *every* intraprocedural path through the function leads to
a self-call.
Hence the warnings complement each other: there's some overlap, but each
also catches issues that the other misses.
For example, the new warning complains about a guarded recursion in
which the guard is passed unchanged:
void test_guarded (int flag)
{
if (flag)
test_guarded (flag);
}
t.c: In function 'test_guarded':
t.c:4:5: warning: infinite recursion [CWE-674] [-Wanalyzer-infinite-recursion]
4 | test_guarded (flag);
| ^~~~~~~~~~~~~~~~~~~
'test_guarded': events 1-4
|
| 1 | void test_guarded (int flag)
| | ^~~~~~~~~~~~
| | |
| | (1) initial entry to 'test_guarded'
| 2 | {
| 3 | if (flag)
| | ~
| | |
| | (2) following 'true' branch (when 'flag != 0')...
| 4 | test_guarded (flag);
| | ~~~~~~~~~~~~~~~~~~~
| | |
| | (3) ...to here
| | (4) calling 'test_guarded' from 'test_guarded'
|
+--> 'test_guarded': events 5-6
|
| 1 | void test_guarded (int flag)
| | ^~~~~~~~~~~~
| | |
| | (5) recursive entry to 'test_guarded'; previously entered at (1)
| | (6) apparently infinite recursion
|
whereas the existing warning doesn't complain, since when "flag" is
false the function doesn't recurse.
The new warning doesn't trigger for e.g.:
void test_param_variant (int depth)
{
if (depth > 0)
test_param_variant (depth - 1);
}
on the grounds that "depth" is changing, and appears to be a variant
that enforces termination of the recursion.
gcc/ChangeLog:
PR analyzer/106147
* Makefile.in (ANALYZER_OBJS): Add analyzer/infinite-recursion.o.
gcc/analyzer/ChangeLog:
PR analyzer/106147
* analyzer.opt (Wanalyzer-infinite-recursion): New.
* call-string.cc (call_string::count_occurrences_of_function):
New.
* call-string.h (call_string::count_occurrences_of_function): New
decl.
* checker-path.cc (function_entry_event::function_entry_event):
New ctor.
(checker_path::add_final_event): Delete.
* checker-path.h (function_entry_event::function_entry_event): New
ctor.
(function_entry_event::get_desc): Drop "final".
(checker_path::add_final_event): Delete.
* diagnostic-manager.cc
(diagnostic_manager::emit_saved_diagnostic): Create the final
event via a new pending_diagnostic::add_final_event vfunc, rather
than checker_path::add_final_event.
(diagnostic_manager::add_events_for_eedge): Create function entry
events via a new pending_diagnostic::add_function_entry_event
vfunc.
* engine.cc (exploded_graph::process_node): When creating a new
PK_BEFORE_SUPERNODE node, call
exploded_graph::detect_infinite_recursion on it after adding the
in-edge.
* exploded-graph.h (exploded_graph::detect_infinite_recursion):
New decl.
(exploded_graph::find_previous_entry_to): New decl.
* infinite-recursion.cc: New file.
* pending-diagnostic.cc
(pending_diagnostic::add_function_entry_event): New.
(pending_diagnostic::add_final_event): New.
* pending-diagnostic.h
(pending_diagnostic::add_function_entry_event): New vfunc.
(pending_diagnostic::add_final_event): New vfunc.
gcc/ChangeLog:
PR analyzer/106147
* doc/gcc/gcc-command-options/options-that-control-static-analysis.rst:
Add -Wanalyzer-infinite-recursion.
* doc/gcc/gcc-command-options/options-to-request-or-suppress-warnings.rst
(-Winfinite-recursion): Mention -Wanalyzer-infinite-recursion.
gcc/testsuite/ChangeLog:
PR analyzer/106147
* g++.dg/analyzer/infinite-recursion-1.C: New test.
* g++.dg/analyzer/infinite-recursion-2.C: New test, copied from
g++.dg/warn/Winfinite-recursion-2.C.
* g++.dg/analyzer/infinite-recursion-3.C: New test, adapted from
g++.dg/warn/Winfinite-recursion-3.C.
* gcc.dg/analyzer/infinite-recursion-2.c: New test.
* gcc.dg/analyzer/infinite-recursion-3.c: New test.
* gcc.dg/analyzer/infinite-recursion-4-limited-buggy.c: New test.
* gcc.dg/analyzer/infinite-recursion-4-limited.c: New test.
* gcc.dg/analyzer/infinite-recursion-4-unlimited-buggy.c: New test.
* gcc.dg/analyzer/infinite-recursion-4-unlimited.c: New test.
* gcc.dg/analyzer/infinite-recursion-5.c: New test, adapted from
gcc.dg/Winfinite-recursion.c.
* gcc.dg/analyzer/infinite-recursion-alloca.c: New test.
* gcc.dg/analyzer/infinite-recursion-inlining.c: New test.
* gcc.dg/analyzer/infinite-recursion-multiline-1.c: New test.
* gcc.dg/analyzer/infinite-recursion-multiline-2.c: New test.
* gcc.dg/analyzer/infinite-recursion-variadic.c: New test.
* gcc.dg/analyzer/infinite-recursion.c: Add dg-warning directives
where infinite recursions occur.
* gcc.dg/analyzer/malloc-ipa-12.c: Likewise.
* gcc.dg/analyzer/pr105365.c: Likewise.
* gcc.dg/analyzer/pr105366.c: Likewise.
* gcc.dg/analyzer/pr97029.c: Likewise.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|