Age | Commit message (Collapse) | Author | Files | Lines |
|
PR analyzer/108830 reports a situation in which there are lots of
followup -Wanalyzer-null-dereference warnings after the first access of
a NULL pointer, leading to very noisy output from -fanalyzer.
The analyzer's logic for stopping emitting multiple warnings from a
state machine doesn't quite work for NULL pointers: it attempts to
transition the malloc state machine's NULL pointer to the "stop" state,
which doesn't seem to make much sense in retrospect, and seems to get
confused over types.
Similarly, poisoned_value_diagnostic can be very noisy for uninit
variables, emitting a warning for every access to an uninitialized
variable. In theory, region_model::check_for_poison makes some attempts
to suppress followups, but only for the symbolic value itself; if the
user's code keeps accessing the same region, we would get a warning on
each one. For example, this showed up in Doom's s_sound.c where there
were 7 followup uninit warnings after the first uninit warning in
"S_ChangeMusic".
This patch adds an extra mechanism, giving pending diagnostics the
option of stopping the analysis of an execution path if they're saved
for emission on it, and turning this on for these warnings:
-Wanalyzer-null-dereference
-Wanalyzer-null-argument
-Wanalyzer-use-after-free
-Wanalyzer-use-of-pointer-in-stale-stack-frame
-Wanalyzer-use-of-uninitialized-value
Doing so should hopefully reduce the cascades of diagnostics that
-fanalyzer can sometimes emit.
I added a -fno-analyzer-suppress-followups for the cases where you
really want the followup warnings (e.g. in some DejaGnu tests, and
for microbenchmarks of UB detection, such as PR analyzer/104224).
Integration testing shows this patch reduces the number of probable
false positives reported by 94, and finds one more true positive:
Comparison: 9.34% -> 10.91%
GOOD: 66 -> 67 (+1)
BAD: 641 -> 547 (-94)
where the affected warnings/projects are:
-Wanalyzer-null-dereference: 0.00% GOOD: 0 BAD: 269 -> 239 (-30)
Unclassified: 257 -> 228 (-29)
apr-1.7.0: 12 -> 5 (-7)
doom: 1 -> 0 (-1)
haproxy-2.7.1: 47 -> 41 (-6)
ImageMagick-7.1.0-57: 13 -> 9 (-4)
qemu-7.2.0: 165 -> 154 (-11)
Known false: 7 -> 6 (-1)
xz-5.4.0: 4 -> 3 (-1)
-Wanalyzer-use-of-uninitialized-value: 0.00% GOOD: 0 BAD: 143 -> 80 (-63)
Known false: 47 -> 16 (-31)
doom: 42 -> 11 (-31)
Unclassified: 96 -> 64 (-32)
coreutils-9.1: 14 -> 10 (-4)
haproxy-2.7.1: 29 -> 23 (-6)
qemu-7.2.0: 48 -> 26 (-22)
-Wanalyzer-null-argument: 0.00% -> 2.33% GOOD: 0 -> 1 (+1) BAD: 43 -> 42 (-1)
Unclassified: 39 -> 38 (-1)
due to coreutils-9.1: 9 -> 8 (-1)
True positive: 0 -> 1 (+1)
(in haproxy-2.7.1)
gcc/analyzer/ChangeLog:
PR analyzer/108830
* analyzer.opt (fanalyzer-suppress-followups): New option.
* engine.cc (impl_region_model_context::warn): Terminate the path
if the diagnostic's terminate_path_p vfunc returns true and
-fanalyzer-suppress-followups is true (the default).
(impl_sm_context::warn): Likewise, for both overloads.
* pending-diagnostic.h (pending_diagnostic::terminate_path_p): New
vfunc.
* program-state.cc (program_state::on_edge): Terminate the path if
the ctxt requests it during updating the edge.
* region-model.cc (poisoned_value_diagnostic::terminate_path_p):
New vfunc.
* sm-malloc.cc (null_deref::terminate_path_p): New vfunc.
(null_arg::terminate_path_p): New vfunc.
gcc/ChangeLog:
PR analyzer/108830
* doc/invoke.texi: Document -fno-analyzer-suppress-followups.
gcc/testsuite/ChangeLog:
PR analyzer/108830
* gcc.dg/analyzer/attribute-nonnull.c: Update for
-Wanalyzer-use-of-uninitialized-value terminating analysis along
a path.
* gcc.dg/analyzer/call-summaries-2.c: Likewise.
* gcc.dg/analyzer/data-model-1.c: Likewise.
* gcc.dg/analyzer/data-model-5.c: Likewise.
* gcc.dg/analyzer/doom-s_sound-pr108867.c: New test.
* gcc.dg/analyzer/memset-CVE-2017-18549-1.c: Add
-fno-analyzer-suppress-followups.
* gcc.dg/analyzer/null-deref-pr108830.c: New test.
* gcc.dg/analyzer/pipe-1.c: Add -fno-analyzer-suppress-followups.
* gcc.dg/analyzer/pipe-void-return.c: Likewise.
* gcc.dg/analyzer/pipe2-1.c: Likewise.
* gcc.dg/analyzer/pr101547.c: Update for
-Wanalyzer-use-of-uninitialized-value terminating analysis along
a path.
* gcc.dg/analyzer/pr101875.c: Likewise.
* gcc.dg/analyzer/pr104224-split.c: New test, based on...
* gcc.dg/analyzer/pr104224.c: Add
-fno-analyzer-suppress-followups.
* gcc.dg/analyzer/realloc-2.c: Add
-fno-analyzer-suppress-followups.
* gcc.dg/analyzer/realloc-3.c: Likewise.
* gcc.dg/analyzer/realloc-5.c: Likewise.
* gcc.dg/analyzer/stdarg-1-ms_abi.c: Likewise.
* gcc.dg/analyzer/stdarg-1-sysv_abi.c: Likewise.
* gcc.dg/analyzer/stdarg-1.c: Likewise.
* gcc.dg/analyzer/symbolic-1.c: Likewise.
* gcc.dg/analyzer/symbolic-7.c: Update for
-Wanalyzer-use-of-uninitialized-value terminating analysis along a
path.
* gcc.dg/analyzer/uninit-4.c: Likewise.
* gcc.dg/analyzer/uninit-8.c: New test.
* gcc.dg/analyzer/uninit-pr94713.c: Update for
-Wanalyzer-use-of-uninitialized-value terminating analysis along a
path.
* gcc.dg/analyzer/zlib-6a.c: Add -fno-analyzer-suppress-followups.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
|
|
PR analyzer/103546 tracks various false positives seen on
flex-generated lexers.
Whilst investigating them, I noticed an ICE with
-fanalyzer-call-summaries due to attempting to store sm-state
for an UNKNOWN svalue, which this patch fixes.
This patch also provides known_function implementations of all of the
external functions called by the lexer, reducing the number of false
positives.
The patch doesn't eliminate all false positives, but adds integration
tests to try to establish a baseline from which the remaining false
positives can be fixed.
gcc/analyzer/ChangeLog:
PR analyzer/103546
* analyzer.h (register_known_file_functions): New decl.
* program-state.cc (sm_state_map::replay_call_summary): Rejct
attempts to store sm-state for caller_sval that can't have
associated state.
* region-model-impl-calls.cc (register_known_functions): Call
register_known_file_functions.
* sm-fd.cc (class kf_isatty): New.
(register_known_fd_functions): Register it.
* sm-file.cc (class kf_ferror): New.
(class kf_fileno): New.
(class kf_getc): New.
(register_known_file_functions): New.
gcc/ChangeLog:
PR analyzer/103546
* doc/invoke.texi (Static Analyzer Options): Add isatty, ferror,
fileno, and getc to the list of functions known to the analyzer.
gcc/testsuite/ChangeLog:
PR analyzer/103546
* gcc.dg/analyzer/ferror-1.c: New test.
* gcc.dg/analyzer/fileno-1.c: New test.
* gcc.dg/analyzer/flex-with-call-summaries.c: New test.
* gcc.dg/analyzer/flex-without-call-summaries.c: New test.
* gcc.dg/analyzer/getc-1.c: New test.
* gcc.dg/analyzer/isatty-1.c: New test.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
PR analyzer/106473 reports a false positive from -Wanalyzer-malloc-leak
on:
void foo(char **args[], int *argc) {
*argc = 1;
(*args)[0] = __builtin_malloc(42);
}
The issue is that at the write to *argc we don't know if argc could
point within *args, and so we conservatiely set *args to be unknown.
At the write "(*args)[0] = __builtin_malloc(42)" we have the result of
the allocation written through an unknown pointer, so we mark the
heap_allocated_region as having escaped.
Unfortunately, within store::canonicalize we overzealously purge the
heap allocated region, losing the information that it has escaped, and
thus errnoeously report a leak.
The first part of the fix is to update store::canonicalize so that it
doesn't purge heap_allocated_regions that are marked as escaping.
Doing so fixes the leak false positive, but leads to various state
explosions relating to anywhere we have a malloc/free pair in a loop,
where the analysis of the iteration appears to only have been reaching
a fixed state due to a bug in the state merger code that was erroneously
merging state about the region allocated in one iteration with that
of another. On touching that, the analyzer fails to reach a fixed state
on any loops containing a malloc/free pair, since each analysis of a
malloc was creating a new heap_allocated_region instance.
Hence the second part of the fix is to revamp how heap_allocated_regions
are managed within the analyzer. Rather than create a new one at each
analysis of a malloc call, instead we reuse them across the analysis,
only creating a new one if the current path's state is referencing all
of the existing ones. Hence the heap_allocated_region instances get
used in a fixed order along every analysis path, so e.g. at:
if (flag)
p = malloc (4096);
else
p = malloc (1024);
both paths now use the same heap_allocated_region for their malloc
calls - but we still end up with two enodes after the CFG merger, by
rejecting merger of states with non-equal dynamic extents.
gcc/analyzer/ChangeLog:
PR analyzer/106473
* call-summary.cc
(call_summary_replay::convert_region_from_summary_1): Update for
change to creation of heap-allocated regions.
* program-state.cc (test_program_state_1): Likewise.
(test_program_state_merging): Likewise.
* region-model-impl-calls.cc (kf_calloc::impl_call_pre): Likewise.
(kf_malloc::impl_call_pre): Likewise.
(kf_operator_new::impl_call_pre): Likewise.
(kf_realloc::impl_call_postsuccess_with_move::update_model): Likewise.
* region-model-manager.cc
(region_model_manager::create_region_for_heap_alloc): Convert
to...
(region_model_manager::get_or_create_region_for_heap_alloc):
...this, reusing an existing region if it's unreferenced in the
client state.
* region-model-manager.h (region_model_manager::get_num_regions): New.
(region_model_manager::create_region_for_heap_alloc): Convert to...
(region_model_manager::get_or_create_region_for_heap_alloc): ...this.
* region-model.cc (region_to_value_map::can_merge_with_p): Reject
merger when the values are different.
(region_model::create_region_for_heap_alloc): Convert to...
(region_model::get_or_create_region_for_heap_alloc): ...this.
(region_model::get_referenced_base_regions): New.
(selftest::test_state_merging): Update for change to creation of
heap-allocated regions.
(selftest::test_malloc_constraints): Likewise.
(selftest::test_malloc): Likewise.
* region-model.h: Include "sbitmap.h".
(region_model::create_region_for_heap_alloc): Convert to...
(region_model::get_or_create_region_for_heap_alloc): ...this.
(region_model::get_referenced_base_regions): New decl.
* store.cc (store::canonicalize): Don't purge a heap-allocated region
that's been marked as escaping.
gcc/testsuite/ChangeLog:
PR analyzer/106473
* gcc.dg/analyzer/aliasing-pr106473.c: New test.
* gcc.dg/analyzer/allocation-size-2.c: Add
-fanalyzer-fine-grained".
* gcc.dg/analyzer/allocation-size-3.c: Likewise.
* gcc.dg/analyzer/explode-1.c: Mark leak with XFAIL.
* gcc.dg/analyzer/explode-3.c: New test.
* gcc.dg/analyzer/malloc-reuse.c: New test.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
This patch implements a new -Wanalyzer-deref-before-check within
-fanalyzer. It complains about code paths in which a pointer is checked
for NULL after it has already been dereferenced.
For example, for the testcase in PR 77432 the diagnostic emits:
deref-before-check-1.c: In function 'test_from_pr77432':
deref-before-check-1.c:6:8: warning: check of 'a' for NULL after already dereferencing it [-Wanalyzer-deref-before-check]
6 | if (a)
| ^
'test_from_pr77432': events 1-2
|
| 5 | int b = *a;
| | ^
| | |
| | (1) pointer 'a' is dereferenced here
| 6 | if (a)
| | ~
| | |
| | (2) pointer 'a' is checked for NULL here but it was already dereferenced at (1)
|
and in PR 77425 we had an instance of this hidden behind a
macro, which the diagnostic complains about as follows:
deref-before-check-pr77425.c: In function 'get_odr_type':
deref-before-check-pr77425.c:35:10: warning: check of 'odr_types_ptr' for NULL after already dereferencing it [-Wanalyzer-deref-before-check]
35 | if (odr_types_ptr)
| ^
'get_odr_type': events 1-3
|
| 27 | if (cond)
| | ^
| | |
| | (1) following 'false' branch...
|......
| 31 | else if (other_cond)
| | ~~~~~~~~~~~
| | ||
| | |(2) ...to here
| | (3) following 'true' branch...
|
'get_odr_type': event 4
|
| 11 | #define odr_types (*odr_types_ptr)
| | ~^~~~~~~~~~~~~~~
| | |
| | (4) ...to here
deref-before-check-pr77425.c:33:7: note: in expansion of macro 'odr_types'
| 33 | odr_types[val->id] = 0;
| | ^~~~~~~~~
|
'get_odr_type': event 5
|
| 11 | #define odr_types (*odr_types_ptr)
| | ~^~~~~~~~~~~~~~~
| | |
| | (5) pointer 'odr_types_ptr' is dereferenced here
deref-before-check-pr77425.c:33:7: note: in expansion of macro 'odr_types'
| 33 | odr_types[val->id] = 0;
| | ^~~~~~~~~
|
'get_odr_type': event 6
|
| 35 | if (odr_types_ptr)
| | ^
| | |
| | (6) pointer 'odr_types_ptr' is checked for NULL here but it was already dereferenced at (5)
|
gcc/analyzer/ChangeLog:
PR analyzer/99671
* analyzer.opt (Wanalyzer-deref-before-check): New warning.
* diagnostic-manager.cc
(null_assignment_sm_context::set_next_state): Only add state
change events for transition to "null" state.
(null_assignment_sm_context::is_transition_to_null): New.
* engine.cc (impl_region_model_context::on_pop_frame): New.
* exploded-graph.h (impl_region_model_context::on_pop_frame): New
decl.
* program-state.cc (sm_state_map::clear_any_state): New.
(sm_state_map::can_merge_with_p): New.
(program_state::can_merge_with_p): Replace requirement that
sm-states be equal in favor of an attempt to merge them.
* program-state.h (sm_state_map::clear_any_state): New decl.
(sm_state_map::can_merge_with_p): New decl.
* region-model.cc (region_model::eval_condition): Make const.
(region_model::pop_frame): Call ctxt->on_pop_frame.
* region-model.h (region_model::eval_condition): Make const.
(region_model_context::on_pop_frame): New vfunc.
(noop_region_model_context::on_pop_frame): New.
(region_model_context_decorator::on_pop_frame): New.
* sm-malloc.cc (enum resource_state): Add RS_ASSUMED_NON_NULL.
(allocation_state::dump_to_pp): Drop "final".
(struct assumed_non_null_state): New subclass.
(malloc_state_machine::m_assumed_non_null): New.
(assumed_non_null_p): New.
(class deref_before_check): New.
(assumed_non_null_state::dump_to_pp): New.
(malloc_state_machine::get_or_create_assumed_non_null_state_for_frame):
New.
(malloc_state_machine::maybe_assume_non_null): New.
(malloc_state_machine::on_stmt): Transition from start state to
"assumed-non-null" state for pointers passed to
__attribute__((nonnull)) arguments, and for pointers explicitly
dereferenced. Call maybe_complain_about_deref_before_check for
pointers explicitly compared against NULL.
(malloc_state_machine::maybe_complain_about_deref_before_check):
New.
(malloc_state_machine::on_deallocator_call): Also transition
"assumed-non-null" states to "freed".
(malloc_state_machine::on_pop_frame): New.
(malloc_state_machine::maybe_get_merged_states_nonequal): New.
* sm-malloc.dot: Update for changes to sm-malloc.cc.
* sm.h (state_machine::on_pop_frame): New.
(state_machine::maybe_get_merged_state): New.
(state_machine::maybe_get_merged_states_nonequal): New.
gcc/ChangeLog:
* doc/gcc/gcc-command-options/options-that-control-static-analysis.rst:
Add -Wanalyzer-deref-before-check.
gcc/testsuite/ChangeLog:
* gcc.dg/analyzer/deref-before-check-1.c: New test.
* gcc.dg/analyzer/deref-before-check-2.c: New test.
* gcc.dg/analyzer/deref-before-check-pr77425.c: New test.
* gcc.dg/analyzer/malloc-1.c (test_51): New test.
gcc/ChangeLog:
PR analyzer/99671
* tristate.h (tristate::is_unknown): New.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
gcc/analyzer/ChangeLog:
* call-info.cc: Add define of INCLUDE_MEMORY.
* call-summary.cc: Likewise.
* checker-path.cc: Likewise.
* constraint-manager.cc: Likewise.
* diagnostic-manager.cc: Likewise.
(saved_diagnostic::saved_diagnostic): Use std::unique_ptr for
param d and field m_d.
(saved_diagnostic::~saved_diagnostic): Remove explicit delete of m_d.
(saved_diagnostic::add_note): Use std::unique_ptr for
param pn.
(saved_diagnostic::get_pending_diagnostic): Update for conversion
of m_sd.m_d to unique_ptr.
(diagnostic_manager::add_diagnostic): Use std::unique_ptr for
param d. Remove explicit deletion.
(diagnostic_manager::add_note): Use std::unique_ptr for param pn.
(diagnostic_manager::emit_saved_diagnostic): Update for conversion
of m_sd.m_d to unique_ptr.
(null_assignment_sm_context::warn): Use std::unique_ptr for
param d. Remove explicit deletion.
* diagnostic-manager.h (saved_diagnostic::saved_diagnostic): Use
std::unique_ptr for param d.
(saved_diagnostic::add_note): Likewise for param pn.
(saved_diagnostic::m_d): Likewise.
(diagnostic_manager::add_diagnostic): Use std::unique_ptr for
param d.
(diagnostic_manager::add_note): Use std::unique_ptr for param pn.
* engine.cc: Include "make-unique.h".
(impl_region_model_context::warn): Update to use std::unique_ptr
for param, removing explicit deletion.
(impl_region_model_context::add_note): Likewise.
(impl_sm_context::warn): Update to use std::unique_ptr
for param.
(impl_region_model_context::on_state_leak): Likewise for result of
on_leak.
(exploded_node::on_longjmp): Use make_unique when creating
pending_diagnostic.
(exploded_graph::process_node): Likewise.
* exploded-graph.h (impl_region_model_context::warn): Update to
use std::unique_ptr for param.
(impl_region_model_context::add_note): Likewise.
* feasible-graph.cc: Add define of INCLUDE_MEMORY.
* pending-diagnostic.cc: Likewise.
* pending-diagnostic.h: Include analyzer.sm.h"
* program-point.cc: Add define of INCLUDE_MEMORY.
* program-state.cc: Likewise.
* region-model-asm.cc: Likewise.
* region-model-impl-calls.cc: Likewise. Include "make-unique.h".
(region_model::impl_call_putenv): Use make_unique when creating
pending_diagnostic.
* region-model-manager.cc: Add define of INCLUDE_MEMORY.
* region-model-reachability.cc: Likewise.
* region-model.cc: Likewise. Include "make-unique.h".
(region_model::get_gassign_result): Use make_unique when creating
pending_diagnostic.
(region_model::check_for_poison): Likewise.
(region_model::on_stmt_pre): Likewise.
(region_model::check_symbolic_bounds): Likewise.
(region_model::check_region_bounds): Likewise.
(annotating_ctxt: make_note): Use std::unique_ptr for result.
(region_model::deref_rvalue): Use make_unique when creating
pending_diagnostic.
(region_model::check_for_writable_region): Likewise.
(region_model::check_region_size): Likewise.
(region_model::check_dynamic_size_for_floats): Likewise.
(region_model::maybe_complain_about_infoleak): Likewise.
(noop_region_model_context::add_note): Use std::unique_ptr for
param. Remove explicit deletion.
* region-model.h: Include "analyzer/pending-diagnostic.h".
(region_model_context::warn): Convert param to std::unique_ptr.
(region_model_context::add_note): Likewise.
(noop_region_model_context::warn): Likewise.
(noop_region_model_context::add_note): Likewise.
(region_model_context_decorator::warn): Likewise.
(region_model_context_decorator::add_note): Likewise.
(note_adding_context::warn): Likewise.
(note_adding_context::make_note): Likewise for return type.
(test_region_model_context::warn): Convert param to
std::unique_ptr.
* region.cc: Add define of INCLUDE_MEMORY.
* sm-fd.cc: Likewise. Include "make-unique.h".
(fd_state_machine::check_for_fd_attrs): Use make_unique when
creating pending_diagnostics.
(fd_state_machine::on_open): Likewise.
(fd_state_machine::on_creat): Likewise.
(fd_state_machine::check_for_dup): Likewise.
(fd_state_machine::on_close): Likewise.
(fd_state_machine::check_for_open_fd): Likewise.
(fd_state_machine::on_leak): Likewise, converting return type to
std::unique_ptr.
* sm-file.cc: Add define of INCLUDE_MEMORY. Include
"make-unique.h".
(fileptr_state_machine::on_stmt): Use make_unique when creating
pending_diagnostic.
(fileptr_state_machine::on_leak): Likewise, converting return type
to std::unique_ptr.
* sm-malloc.cc: Add define of INCLUDE_MEMORY. Include
"make-unique.h".
(malloc_state_machine::on_stmt): Use make_unique when creating
pending_diagnostic.
(malloc_state_machine::handle_free_of_non_heap): Likewise.
(malloc_state_machine::on_deallocator_call): Likewise.
(malloc_state_machine::on_realloc_call): Likewise.
(malloc_state_machine::on_leak): Likewise, converting return type
to std::unique_ptr.
* sm-pattern-test.cc: Add define of INCLUDE_MEMORY. Include
"make-unique.h".
(pattern_test_state_machine::on_condition): Use make_unique when
creating pending_diagnostic.
* sm-sensitive.cc: Add define of INCLUDE_MEMORY. Include
"make-unique.h".
(sensitive_state_machine::warn_for_any_exposure): Use make_unique
when creating pending_diagnostic.
* sm-signal.cc: Add define of INCLUDE_MEMORY. Include
"make-unique.h".
(signal_state_machine::on_stmt): Use make_unique when creating
pending_diagnostic.
* sm-taint.cc: Add define of INCLUDE_MEMORY. Include
"make-unique.h".
(taint_state_machine::check_for_tainted_size_arg): Use make_unique
when creating pending_diagnostic.
(taint_state_machine::check_for_tainted_divisor): Likewise.
(region_model::check_region_for_taint): Likewise.
(region_model::check_dynamic_size_for_taint): Likewise.
* sm.cc: Add define of INCLUDE_MEMORY. Include
"analyzer/pending-diagnostic.h".
(state_machine::on_leak): Move here from sm.h, changing return
type to std::unique_ptr.
* sm.h (state_machine::on_leak): Change return type to
std::unique_ptr. Move defn of base impl to sm.cc
(sm_context::warn): Convert param d to std_unique_ptr.
* state-purge.cc: Add define of INCLUDE_MEMORY.
* store.cc: Likewise.
* svalue.cc: Likewise.
* trimmed-graph.cc: Likewise.
* varargs.cc: Likewise. Include "make-unique.h".
(va_list_state_machine::check_for_ended_va_list): Use make_unique
when creating pending_diagnostic.
(va_list_state_machine::on_leak): Likewise, converting return type
to std::unique_ptr.
(region_model::impl_call_va_arg): Use make_unique when creating
pending_diagnostic.
gcc/testsuite/ChangeLog:
* gcc.dg/plugin/analyzer_gil_plugin.c: Add define of
INCLUDE_MEMORY. Include "make-unique.h".
(gil_state_machine::check_for_pyobject_in_call): Use make_unique
when creating pending_diagnostic.
(gil_state_machine::on_stmt): Likewise.
(gil_state_machine::check_for_pyobject_usage_without_gil): Likewise.
* gcc.dg/plugin/analyzer_kernel_plugin.c: : Add define of
INCLUDE_MEMORY.
* gcc.dg/plugin/analyzer_known_fns_plugin.c: Likewise.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
gcc/analyzer/ChangeLog:
* analysis-plan.cc: Simplify includes.
* analyzer-pass.cc: Likewise.
* analyzer-selftests.cc: Likewise.
* analyzer.cc: Likewise.
* analyzer.h: Add includes of "json.h" and "tristate.h".
* call-info.cc: Simplify includes.
* call-string.cc: Likewise.
* call-summary.cc: Likewise.
* checker-path.cc: Likewise.
* complexity.cc: Likewise.
* constraint-manager.cc: Likewise.
* diagnostic-manager.cc: Likewise.
* engine.cc: Likewise.
* feasible-graph.cc: Likewise.
* known-function-manager.cc: Likewise.
* pending-diagnostic.cc: Likewise.
* program-point.cc: Likewise.
* program-state.cc: Likewise.
* region-model-asm.cc: Likewise.
* region-model-impl-calls.cc: Likewise.
* region-model-manager.cc: Likewise.
* region-model-reachability.cc: Likewise.
* region-model.cc: Likewise.
* region-model.h: Include "selftest.h".
* region.cc: Simplify includes.
* sm-fd.cc: Likewise.
* 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.
* sm.cc: Likewise.
* state-purge.cc: Likewise.
* store.cc: Likewise.
* store.h: Likewise.
* supergraph.cc: Likewise.
* svalue.cc: Likewise.
* svalue.h: Likewise.
* trimmed-graph.cc: Likewise.
* varargs.cc: Likewise.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
With -fanalyzer-call-summaries the analyzer canl attempt to summarize
the effects of some function calls at their call site, rather than
simulate the call directly, which can avoid big slowdowns during
analysis.
Previously, this summarization was extremely simplistic: no attempt
was made to update sm-state, and region_model::update_for_call_summary
would simply set the return value of the function to UNKNOWN, and assume
the function had no side effects.
This patch implements less simplistic summarizations: it tracks each
possible return enode from the called function, and attempts to generate
a successor enode from the callsite for each that have compatible
conditions, mapping state changes in the summary to state changes
at the callsite. It also implements the beginnings of heuristics for
generating user-facing descriptions of a summary e.g.
"when 'foo' returns NULL"
versus:
"when 'foo' returns a heap-allocated buffer"
This still has some bugs, but much more accurately tracks the effects
of a call, and so is an improvement; it should only have an effect
when -fanalyzer-call-summaries is enabled.
As before, -fanalyzer-call-summaries is disabled by default in
analyzer.opt (but enabled by default in the test suite).
gcc/ChangeLog:
PR analyzer/107072
* Makefile.in (ANALYZER_OBJS): Add analyzer/call-summary.o.
gcc/analyzer/ChangeLog:
PR analyzer/107072
* analyzer-logging.h: Include "diagnostic-core.h".
* analyzer.h: Include "function.h".
(class call_summary): New forward decl.
(class call_summary_replay): New forward decl.
(struct per_function_data): New forward decl.
(struct interesting_t): New forward decl.
(custom_edge_info::update_state): New vfunc.
* call-info.cc (custom_edge_info::update_state): New.
* call-summary.cc: New file.
* call-summary.h: New file.
* constraint-manager.cc: Include "analyzer/call-summary.h".
(class replay_fact_visitor): New.
(constraint_manager::replay_call_summary): New.
* constraint-manager.h (constraint_manager::replay_call_summary):
New.
* engine.cc: Include "analyzer/call-summary.h".
(exploded_node::on_stmt): Handle call summaries.
(class call_summary_edge_info): New.
(exploded_node::replay_call_summaries): New.
(exploded_node::replay_call_summary): New.
(per_function_data::~per_function_data): New.
(per_function_data::add_call_summary): Move here from header and
reimplement.
(exploded_graph::process_node): Call update_state rather than
update_model when handling bifurcation
(viz_callgraph_node::dump_dot): Use a regular label rather
than an HTML table; add summaries to dump.
* exploded-graph.h: Include "alloc-pool.h", "fibonacci_heap.h",
"supergraph.h", "sbitmap.h", "shortest-paths.h", "analyzer/sm.h",
"analyzer/program-state.h", and "analyzer/diagnostic-manager.h".
(exploded_node::replay_call_summaries): New decl.
(exploded_node::replay_call_summary): New decl.
(per_function_data::~per_function_data): New decl.
(per_function_data::add_call_summary): Move implemention from
header.
(per_function_data::m_summaries): Update type of element.
* known-function-manager.h: Include "analyzer/analyzer-logging.h".
* program-point.h: Include "pretty-print.h" and
"analyzer/call-string.h".
* program-state.cc: Include "analyzer/call-summary.h".
(sm_state_map::replay_call_summary): New.
(program_state::replay_call_summary): New.
* program-state.h (sm_state_map::replay_call_summary): New decl.
(program_state::replay_call_summary): New decl.
* region-model-manager.cc
(region_model_manager::get_or_create_asm_output_svalue): New
overload.
* region-model-manager.h
(region_model_manager::get_or_create_asm_output_svalue): New
overload decl.
* region-model.cc: Include "analyzer/call-summary.h".
(region_model::maybe_update_for_edge): Remove call to
region_model::update_for_call_summary on
SUPEREDGE_INTRAPROCEDURAL_CALL.
(region_model::update_for_call_summary): Delete.
(region_model::replay_call_summary): New.
* region-model.h (region_model::replay_call_summary): New decl.
(region_model::update_for_call_summary): Delete decl.
* store.cc: Include "analyzer/call-summary.h".
(store::replay_call_summary): New.
(store::replay_call_summary_cluster): New.
* store.h: Include "tristate.h".
(is_a_helper <const ana::concrete_binding *>::test): New.
(store::replay_call_summary): New decl.
(store::replay_call_summary_cluster): New decl.
* supergraph.cc (get_ultimate_function_for_cgraph_edge): Remove
"static" from decl.
(supergraph_call_edge): Make stmt param const.
* supergraph.h: Include "ordered-hash-map.h", "cfg.h",
"basic-block.h", "gimple.h", "gimple-iterator.h", and "digraph.h".
(supergraph_call_edge): Make stmt param const.
(get_ultimate_function_for_cgraph_edge): New decl.
* svalue.cc (compound_svalue::compound_svalue): Assert that we're
not nesting compound_svalues.
* svalue.h: Include "json.h", "analyzer/store.h", and
"analyzer/program-point.h".
(asm_output_svalue::get_num_outputs): New accessor.
gcc/testsuite/ChangeLog:
PR analyzer/107072
* gcc.dg/analyzer/call-summaries-2.c: New test.
* gcc.dg/analyzer/call-summaries-3.c: New test.
* gcc.dg/analyzer/call-summaries-asm-x86.c: New test.
* gcc.dg/analyzer/call-summaries-malloc.c: New test.
* gcc.dg/analyzer/call-summaries-pr107072.c: New test.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
This adjusts the API of label_text so that the data members are private
and cannot be modified by callers. Add accessors for them instead, and
make the accessors const-correct. Also rename moved_from () to the more
idiomatic release (). Also remove the unused take_or_copy () member
function which has confusing ownership semantics.
gcc/analyzer/ChangeLog:
* call-info.cc (call_info::print): Adjust to new label_text API.
* checker-path.cc (checker_event::dump): Likewise.
(region_creation_event::get_desc): Likewise.
(state_change_event::get_desc): Likewise.
(superedge_event::should_filter_p): Likewise.
(start_cfg_edge_event::get_desc): Likewise.
(call_event::get_desc): Likewise.
(return_event::get_desc): Likewise.
(warning_event::get_desc): Likewise.
(checker_path::dump): Likewise.
(checker_path::debug): Likewise.
* diagnostic-manager.cc (diagnostic_manager::prune_for_sm_diagnostic):
Likewise.
(diagnostic_manager::prune_interproc_events): Likewise.
* engine.cc (feasibility_state::maybe_update_for_edge):
Likewise.
* program-state.cc (sm_state_map::to_json): Likewise.
* region-model-impl-calls.cc (region_model::impl_call_analyzer_describe): Likewise.
(region_model::impl_call_analyzer_dump_capacity): Likewise.
* region.cc (region::to_json): Likewise.
* sm-malloc.cc (inform_nonnull_attribute): Likewise.
* store.cc (binding_map::to_json): Likewise.
(store::to_json): Likewise.
* supergraph.cc (superedge::dump): Likewise.
* svalue.cc (svalue::to_json): Likewise.
gcc/c-family/ChangeLog:
* c-format.cc (class range_label_for_format_type_mismatch):
Adjust to new label_text API.
gcc/ChangeLog:
* diagnostic-format-json.cc (json_from_location_range): Adjust
to new label_text API.
* diagnostic-format-sarif.cc (sarif_builder::make_location_object):
Likewise.
* diagnostic-show-locus.cc (struct pod_label_text): Likewise.
(layout::print_any_labels): Likewise.
* tree-diagnostic-path.cc (class path_label): Likewise.
(struct event_range): Likewise.
(default_tree_diagnostic_path_printer): Likewise.
(default_tree_make_json_for_path): Likewise.
libcpp/ChangeLog:
* include/line-map.h (label_text::take_or_copy): Remove.
(label_text::moved_from): Rename to release.
(label_text::m_buffer, label_text::m_owned): Make private.
(label_text::get, label_text::is_owned): New accessors.
|
|
libcpp's class label_text stores a char * for a string and a flag saying
whether it owns the buffer. I added this class before we could use
C++11, and so to avoid lots of copying it required an explicit call
to label_text::maybe_free to potentially free the buffer.
Now that we can use C++11, this patch removes label_text::maybe_free in
favor of doing the cleanup in the destructor, and using C++ move
semantics to avoid any copying. This allows lots of messy cleanup code
to be eliminated in favor of implicit destruction (mostly in the
analyzer).
No functional change intended.
gcc/analyzer/ChangeLog:
* call-info.cc (call_info::print): Update for removal of
label_text::maybe_free in favor of automatic memory management.
* checker-path.cc (checker_event::dump): Likewise.
(checker_event::prepare_for_emission): Likewise.
(state_change_event::get_desc): Likewise.
(superedge_event::should_filter_p): Likewise.
(start_cfg_edge_event::get_desc): Likewise.
(warning_event::get_desc): Likewise.
(checker_path::dump): Likewise.
(checker_path::debug): Likewise.
* diagnostic-manager.cc
(diagnostic_manager::prune_for_sm_diagnostic): Likewise.
(diagnostic_manager::prune_interproc_events): Likewise.
* program-state.cc (sm_state_map::to_json): Likewise.
* region.cc (region::to_json): Likewise.
* sm-malloc.cc (inform_nonnull_attribute): Likewise.
* store.cc (binding_map::to_json): Likewise.
(store::to_json): Likewise.
* svalue.cc (svalue::to_json): Likewise.
gcc/c-family/ChangeLog:
* c-format.cc (range_label_for_format_type_mismatch::get_text):
Update for removal of label_text::maybe_free in favor of automatic
memory management.
gcc/ChangeLog:
* diagnostic-format-json.cc (json_from_location_range): Update for
removal of label_text::maybe_free in favor of automatic memory
management.
* diagnostic-format-sarif.cc
(sarif_builder::make_location_object): Likewise.
* diagnostic-show-locus.cc (struct pod_label_text): New.
(class line_label): Convert m_text from label_text to pod_label_text.
(layout::print_any_labels): Move "text" to the line_label.
* tree-diagnostic-path.cc (path_label::get_text): Update for
removal of label_text::maybe_free in favor of automatic memory
management.
(event_range::print): Likewise.
(default_tree_diagnostic_path_printer): Likewise.
(default_tree_make_json_for_path): Likewise.
libcpp/ChangeLog:
* include/line-map.h: Include <utility>.
(class label_text): Delete maybe_free method in favor of a
destructor. Add move ctor and assignment operator. Add deletion
of the copy ctor and copy-assignment operator. Rename field
m_caller_owned to m_owned. Add std::move where necessary; add
moved_from member function.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
ana::call_string is a wrapper around an auto_vec of callsites, leading
to non-trivial copying when copying around call_string instances, e.g.
in ana::program_point.
This patch consolidates call_string instances within the
region_model_manager: it now owns the root/empty call_string, and
each call_string instance tracks its children, lazily creating them on
demand, so that the call_string instances form a tree-like hierarchy in
memory. Doing this requires passing the region_model_manager to the
various program_point factory methods, so that they can get at the root
call_string.
Instances of call_string become immutable (apart from their internal
cache for looking up their children); operations that previously
modified them now return the call_string for the result of the
operation.
I wasn't able to observe any performance impact of this, but it
simplifies call_string and program_point management, and thus I hope
will make it easier to improve call summarization. In particular,
region_model_manager::log_stats will now print a hierarchical dump of
all the call_string instances used in the analysis (in -fdump-analyzer
and -fdump-analyzer-stderr).
gcc/analyzer/ChangeLog:
* call-string.cc: Add includes of "analyzer/analyzer.h"
and "analyzer/analyzer-logging.h".
(call_string::call_string): Delete copy ctor.
(call_string::operator=): Delete.
(call_string::operator==): Delete.
(call_string::hash): Delete.
(call_string::push_call): Make const, returning the resulting
call_string.
(call_string::pop): Delete.
(call_string::cmp_ptr_ptr): New.
(call_string::validate): Assert that m_parent is non-NULL, or
m_elements is empty.
(call_string::call_string): Move default ctor here from
call-string.h and reimplement. Add ctor taking a parent
and an element.
(call_string::~call_string): New.
(call_string::recursive_log): New.
* call-string.h (call_string::call_string): Move default ctor's
defn to call-string.cc. Delete copy ctor. Add ctor taking a
parent and an element.
(call_string::operator=): Delete.
(call_string::operator==): Delete.
(call_string::hash): Delete.
(call_string::push_call): Make const, returning the resulting
call_string.
(call_string::pop): Delete decl.
(call_string::get_parent): New.
(call_string::cmp_ptr_ptr): New decl.
(call_string::get_top_of_stack): New.
(struct call_string::hashmap_traits_t): New.
(class call_string): Add friend class region_model_manager. Add
DISABLE_COPY_AND_ASSIGN.
(call_string::~call_string): New decl.
(call_string::recursive_log): New decl.
(call_string::m_parent): New field.
(call_string::m_children): New field.
* constraint-manager.cc (selftest::test_many_constants): Pass
model manager to program_point::origin.
* engine.cc (exploded_graph::exploded_graph): Likewise.
(exploded_graph::add_function_entry): Likewise for
program_point::from_function_entry.
(add_tainted_args_callback): Likewise.
(exploded_graph::maybe_process_run_of_before_supernode_enodes):
Update for change to program_point.get_call_string.
(exploded_graph::process_node): Likewise.
(class function_call_string_cluster): Convert m_cs from a
call_string to a const call_string &.
(struct function_call_string): Likewise.
(pod_hash_traits<function_call_string>::hash): Use pointer_hash
for m_cs.
(pod_hash_traits<function_call_string>::equal): Update for change
to m_cs.
(root_cluster::add_node): Update for change to
function_call_string.
(viz_callgraph_node::dump_dot): Update for change to call_string.
* exploded-graph.h (per_call_string_data::m_key): Convert to a
reference.
(struct eg_call_string_hash_map_traits): Delete.
(exploded_graph::call_string_data_map_t): Remove traits class.
* program-point.cc: Move include of "analyzer/call-string.h" to
after "analyzer/analyzer-logging.h".
(program_point::print): Update for conversion of m_call_string to
a pointer.
(program_point::to_json): Likewise.
(program_point::push_to_call_stack): Update for immutability of
call strings.
(program_point::pop_from_call_stack): Likewise.
(program_point::hash): Use pointer hashing for m_call_string.
(program_point::get_function_at_depth): Update for change to
m_call_string.
(program_point::validate): Update for changes to call_string.
(program_point::on_edge): Likewise.
(program_point::origin): Move here from call-string.h. Add
region_model_manager param and use it to get empty call string.
(program_point::from_function_entry): Likewise.
(selftest::test_function_point_ordering): Likewise.
(selftest::test_function_point_ordering): Likewise.
* program-point.h (program_point::program_point): Update for
change to m_call_string.
(program_point::get_call_string): Likewise.
(program_point::get_stack_depth): Likewise.
(program_point::origin): Add region_model_manager param, and move
defn to call-string.cc.
(program_point::from_function_entry): Likewise.
(program_point::empty): Drop call_string.
(program_point::deleted): Likewise.
(program_point::program_point): New private ctor.
(program_point::m_call_string): Convert from call_string to const
call_string *.
* program-state.cc (selftest::test_program_state_merging): Update
for call_string changes.
(selftest::test_program_state_merging_2): Likewise.
* region-model-manager.cc
(region_model_manager::region_model_manager): Construct
m_empty_call_string.
(region_model_manager::log_stats): Log the call strings.
* region-model.cc (assert_region_models_merge): Pass the
region_model_manager when creating program_point instances.
(selftest::test_state_merging): Likewise.
(selftest::test_constraint_merging): Likewise.
(selftest::test_widening_constraints): Likewise.
(selftest::test_iteration_1): Likewise.
* region-model.h (region_model_manager::get_empty_call_string):
New.
(region_model_manager::m_empty_call_string): New.
* sm-signal.cc (register_signal_handler::impl_transition): Update
for changes to call_string.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
The existing analyzer code attempts to purge the state of SSA names
where it can in order to minimize the size of program_state instances,
and to increase the chances of being able to reuse exploded_node
instances whilst exploring the user's code.
PR analyzer/104943 identifies that we fail to purge state of local
variables, based on behavior seen in PR analyzer/104954 when attempting
to profile slow performance of -fanalyzer on a particular file in the
Linux kernel, where that testcase has many temporary "boxed" values of
structs containing ints, which are never cleaned up, leading to bloat
of the program_state instances (specifically, of the store objects).
This patch generalizes the state purging from just being on SSA names
to also work on local variables. Doing so requires that we detect where
addresses to a local variable (or within them) are taken; we assume that
once a pointer has been taken, it's not longer safe to purge the value
of that decl at any successor point within the function.
Doing so speeds up the PR analyzer/104954 Linux kernel analyzer testcase
from taking 254 seconds to "just" 186 seconds (and I have a followup
patch in development that seems to further reduce this to 37 seconds).
The patch may also help with scaling up taint-detection so that it can
eventually be turned on by default, but we're not quite there (this
is PR analyzer/103533).
gcc/analyzer/ChangeLog:
PR analyzer/104943
PR analyzer/104954
PR analyzer/103533
* analyzer.h (class state_purge_per_decl): New forward decl.
* engine.cc (impl_run_checkers): Pass region_model_manager to
state_purge_map ctor.
* program-point.cc (function_point::final_stmt_p): New.
(function_point::get_next): New.
* program-point.h (function_point::final_stmt_p): New decl.
(function_point::get_next): New decl.
* program-state.cc (program_state::prune_for_point): Generalize to
purge local decls as well as SSA names.
(program_state::can_purge_base_region_p): New.
* program-state.h (program_state::can_purge_base_region_p): New
decl.
* region-model.cc (struct append_ssa_names_cb_data): Rename to...
(struct append_regions_cb_data): ...this.
(region_model::get_ssa_name_regions_for_current_frame): Rename
to...
(region_model::get_regions_for_current_frame): ...this, updating
for other renamings.
(region_model::append_ssa_names_cb): Rename to...
(region_model::append_regions_cb): ...this, and drop the requirement
that the subregion be a SSA name.
* region-model.h (struct append_ssa_names_cb_data): Rename decl
to...
(struct append_regions_cb_data): ...this.
(region_model::get_ssa_name_regions_for_current_frame): Rename
decl to...
(region_model::get_regions_for_current_frame): ...this.
(region_model::append_ssa_names_cb): Rename decl to...
(region_model::append_regions_cb): ...this.
* state-purge.cc: Include "tristate.h", "selftest.h",
"analyzer/store.h", "analyzer/region-model.h", and
"gimple-walk.h".
(get_candidate_for_purging): New.
(class gimple_op_visitor): New.
(my_load_cb): New.
(my_store_cb): New.
(my_addr_cb): New.
(state_purge_map::state_purge_map): Add "mgr" param. Update for
renamings. Find uses of local variables.
(state_purge_map::~state_purge_map): Update for renaming of m_map
to m_ssa_map. Clean up m_decl_map.
(state_purge_map::get_or_create_data_for_decl): New.
(state_purge_per_ssa_name::state_purge_per_ssa_name): Update for
inheriting from state_purge_per_tree.
(state_purge_per_ssa_name::add_to_worklist): Likewise.
(state_purge_per_decl::state_purge_per_decl): New.
(state_purge_per_decl::add_needed_at): New.
(state_purge_per_decl::add_pointed_to_at): New.
(state_purge_per_decl::process_worklists): New.
(state_purge_per_decl::add_to_worklist): New.
(same_binding_p): New.
(fully_overwrites_p): New.
(state_purge_per_decl::process_point_backwards): New.
(state_purge_per_decl::process_point_forwards): New.
(state_purge_per_decl::needed_at_point_p): New.
(state_purge_annotator::print_needed): Generalize to print local
decls as well as SSA names.
* state-purge.h (class state_purge_map): Update leading comment.
(state_purge_map::map_t): Rename to...
(state_purge_map::ssa_map_t): ...this.
(state_purge_map::iterator): Rename to...
(state_purge_map::ssa_iterator): ...this.
(state_purge_map::decl_map_t): New typedef.
(state_purge_map::decl_iterator): New typedef.
(state_purge_map::state_purge_map): Add "mgr" param.
(state_purge_map::get_data_for_ssa_name): Update for renaming.
(state_purge_map::get_any_data_for_decl): New.
(state_purge_map::get_or_create_data_for_decl): New decl.
(state_purge_map::begin): Rename to...
(state_purge_map::begin_ssas): ...this.
(state_purge_map::end): Rename to...
(state_purge_map::end_ssa): ...this.
(state_purge_map::begin_decls): New.
(state_purge_map::end_decls): New.
(state_purge_map::m_map): Rename to...
(state_purge_map::m_ssa_map): ...this.
(state_purge_map::m_decl_map): New field.
(class state_purge_per_tree): New class.
(class state_purge_per_ssa_name): Inherit from state_purge_per_tree.
(state_purge_per_ssa_name::get_function): Move to base class.
(state_purge_per_ssa_name::point_set_t): Likewise.
(state_purge_per_ssa_name::m_fun): Likewise.
(class state_purge_per_decl): New.
gcc/testsuite/ChangeLog:
PR analyzer/104943
PR analyzer/104954
PR analyzer/103533
* gcc.dg/analyzer/torture/boxed-ptr-1.c: Update expected number
of exploded nodes to reflect improvements in state purging.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
|
|
PR analyzer/103217 reports a false positive from -Wanalyzer-malloc-leak.
The root cause is due to overzealous state merger, where the
state-merging code decided to merge these two states by merging
the stores:
state A:
clusters within frame: ‘main’@1
cluster for: one_3: CONJURED(val_4 = strdup (src_2(D));, val_4)
cluster for: two_4: UNKNOWN(char *)
cluster for: one_21: CONJURED(val_4 = strdup (src_2(D));, val_4)
state B:
clusters within frame: ‘main’@1
cluster for: one_3: UNKNOWN(char *)
cluster for: two_4: CONJURED(val_4 = strdup (src_2(D));, val_4)
cluster for: two_18: CONJURED(val_4 = strdup (src_2(D));, val_4)
into:
clusters within frame: ‘main’@1
cluster for: one_3: UNKNOWN(char *)
cluster for: two_4: UNKNOWN(char *)
cluster for: one_21: UNKNOWN(char *)
cluster for: two_18: UNKNOWN(char *)
despite "CONJURED(val_4 = strdup (src_2(D));, val_4)" having sm-state,
in this case malloc:nonnull ({free}), thus leading to both references
to the conjured svalue being lost at merger.
This patch tweaks the state merger code so that it will not consider
merging two different svalues for the value of a region if either svalue
has non-purgable sm-state (in the above example, malloc:nonnull). This
fixes the false leak report above.
Doing so uncovered an issue with explode-2a.c in which the warnings
moved from the correct location to the "while" stmt. This turned out
to be a missing call to detect_leaks in phi-handling, which the patch
also fixes (in the PK_BEFORE_SUPERNODE case in
exploded_graph::process_node). Doing this fixed the regression in
explode-2a.c and also fixed the location of the leak warning in
explode-1.c.
The other side effect of the change is that pr94858-1.c now emits
a -Wanalyzer-too-complex warning, since pertinent state is no longer
being thrown away. There doesn't seem to be a good way of avoiding
this, so the patch also adds -Wno-analyzer-too-complex to that test
case (restoring the default).
gcc/analyzer/ChangeLog:
PR analyzer/103217
* engine.cc (exploded_graph::get_or_create_node): Pass in
m_ext_state to program_state::can_merge_with_p.
(exploded_graph::process_worklist): Likewise.
(exploded_graph::maybe_process_run_of_before_supernode_enodes):
Likewise.
(exploded_graph::process_node): Add missing call to detect_leaks
when handling phi nodes.
* program-state.cc (program_state::can_merge_with_p): Add
"ext_state" param. Pass it and state ptrs to
region_model::can_merge_with_p.
(selftest::test_program_state_merging): Update for new ext_state
param of program_state::can_merge_with_p.
(selftest::test_program_state_merging_2): Likewise.
* program-state.h (program_state::can_purge_p): Make const.
(program_state::can_merge_with_p): Add "ext_state" param.
* region-model.cc: Include "analyzer/program-state.h".
(region_model::can_merge_with_p): Add params "ext_state",
"state_a", and "state_b", use them when creating model_merger
object.
(model_merger::mergeable_svalue_p): New.
* region-model.h (region_model::can_merge_with_p): Add params
"ext_state", "state_a", and "state_b".
(model_merger::model_merger) Likewise, initializing new fields.
(model_merger::mergeable_svalue_p): New decl.
(model_merger::m_ext_state): New field.
(model_merger::m_state_a): New field.
(model_merger::m_state_b): New field.
* svalue.cc (svalue::can_merge_p): Call
model_merger::mergeable_svalue_p on both states and reject the
merger accordingly.
gcc/testsuite/ChangeLog:
PR analyzer/103217
* gcc.dg/analyzer/explode-1.c: Update for improvement to location
of leak warning.
* gcc.dg/analyzer/pr103217.c: New test.
* gcc.dg/analyzer/pr94858-1.c: Add -Wno-analyzer-too-complex.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
The initial commit of the analyzer in GCC 10 had a single warning,
-Wanalyzer-tainted-array-index
and required manually enabling the taint checker with
-fanalyzer-checker=taint (due to scaling issues).
This patch extends the taint detection to add four new taint-based
warnings:
-Wanalyzer-tainted-allocation-size
for e.g. attacker-controlled malloc/alloca
-Wanalyzer-tainted-divisor
for detecting where an attacker can inject a divide-by-zero
-Wanalyzer-tainted-offset
for attacker-controlled pointer offsets
-Wanalyzer-tainted-size
for e.g. attacker-controlled memset
and rewords all the warnings to talk about "attacker-controlled" values
rather than "tainted" values.
Unfortunately I haven't yet addressed the scaling issues, so all of
these still require -fanalyzer-checker=taint (in addition to -fanalyzer).
gcc/analyzer/ChangeLog:
* analyzer.opt (Wanalyzer-tainted-allocation-size): New.
(Wanalyzer-tainted-divisor): New.
(Wanalyzer-tainted-offset): New.
(Wanalyzer-tainted-size): New.
* engine.cc (impl_region_model_context::get_taint_map): New.
* exploded-graph.h (impl_region_model_context::get_taint_map):
New decl.
* program-state.cc (sm_state_map::get_state): Call
alt_get_inherited_state.
(sm_state_map::impl_set_state): Modify states within
compound svalues.
(program_state::impl_call_analyzer_dump_state): Undo casts.
(selftest::test_program_state_1): Update for new context param of
create_region_for_heap_alloc.
(selftest::test_program_state_merging): Likewise.
* region-model-impl-calls.cc (region_model::impl_call_alloca):
Likewise.
(region_model::impl_call_calloc): Likewise.
(region_model::impl_call_malloc): Likewise.
(region_model::impl_call_operator_new): Likewise.
(region_model::impl_call_realloc): Likewise.
* region-model.cc (region_model::check_region_access): Call
check_region_for_taint.
(region_model::get_representative_path_var_1): Handle binops.
(region_model::create_region_for_heap_alloc): Add "ctxt" param and
pass it to set_dynamic_extents.
(region_model::create_region_for_alloca): Likewise.
(region_model::set_dynamic_extents): Add "ctxt" param and use it
to call check_dynamic_size_for_taint.
(selftest::test_state_merging): Update for new context param of
create_region_for_heap_alloc.
(selftest::test_malloc_constraints): Likewise.
(selftest::test_malloc): Likewise.
(selftest::test_alloca): Likewise for create_region_for_alloca.
* region-model.h (region_model::create_region_for_heap_alloc): Add
"ctxt" param.
(region_model::create_region_for_alloca): Likewise.
(region_model::set_dynamic_extents): Likewise.
(region_model::check_dynamic_size_for_taint): New decl.
(region_model::check_region_for_taint): New decl.
(region_model_context::get_taint_map): New vfunc.
(noop_region_model_context::get_taint_map): New.
* sm-taint.cc: Remove include of "diagnostic-event-id.h"; add
includes of "gimple-iterator.h", "tristate.h", "selftest.h",
"ordered-hash-map.h", "cgraph.h", "cfg.h", "digraph.h",
"analyzer/supergraph.h", "analyzer/call-string.h",
"analyzer/program-point.h", "analyzer/store.h",
"analyzer/region-model.h", and "analyzer/program-state.h".
(enum bounds): Move to top of file.
(class taint_diagnostic): New.
(class tainted_array_index): Convert to subclass of taint_diagnostic.
(tainted_array_index::emit): Add CWE-129. Reword warning to use
"attacker-controlled" rather than "tainted".
(tainted_array_index::describe_state_change): Move to
taint_diagnostic::describe_state_change.
(tainted_array_index::describe_final_event): Reword to use
"attacker-controlled" rather than "tainted".
(class tainted_offset): New.
(class tainted_size): New.
(class tainted_divisor): New.
(class tainted_allocation_size): New.
(taint_state_machine::alt_get_inherited_state): New.
(taint_state_machine::on_stmt): In assignment handling, remove
ARRAY_REF handling in favor of check_region_for_taint. Add
detection of tainted divisors.
(taint_state_machine::get_taint): New.
(taint_state_machine::combine_states): New.
(region_model::check_region_for_taint): New.
(region_model::check_dynamic_size_for_taint): New.
* sm.h (state_machine::alt_get_inherited_state): New.
gcc/ChangeLog:
* doc/invoke.texi (Static Analyzer Options): Add
-Wno-analyzer-tainted-allocation-size,
-Wno-analyzer-tainted-divisor, -Wno-analyzer-tainted-offset, and
-Wno-analyzer-tainted-size to list. Add
-Wanalyzer-tainted-allocation-size, -Wanalyzer-tainted-divisor,
-Wanalyzer-tainted-offset, and -Wanalyzer-tainted-size to list
of options effectively enabled by -fanalyzer.
(-Wanalyzer-tainted-allocation-size): New.
(-Wanalyzer-tainted-array-index): Tweak wording; add link to CWE.
(-Wanalyzer-tainted-divisor): New.
(-Wanalyzer-tainted-offset): New.
(-Wanalyzer-tainted-size): New.
gcc/testsuite/ChangeLog:
* gcc.dg/analyzer/pr93382.c: Tweak expected wording.
* gcc.dg/analyzer/taint-alloc-1.c: New test.
* gcc.dg/analyzer/taint-alloc-2.c: New test.
* gcc.dg/analyzer/taint-divisor-1.c: New test.
* gcc.dg/analyzer/taint-1.c: Rename to...
* gcc.dg/analyzer/taint-read-index-1.c: ...this. Tweak expected
wording. Mark some events as xfail.
* gcc.dg/analyzer/taint-read-offset-1.c: New test.
* gcc.dg/analyzer/taint-size-1.c: New test.
* gcc.dg/analyzer/taint-write-index-1.c: New test.
* gcc.dg/analyzer/taint-write-offset-1.c: New test.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
gcc/analyzer/ChangeLog:
* program-state.cc (sm_state_map::dump): Use default_tree_printer
as format decoder.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
Most of the state-management code in the analyzer involves
modifying state objects in-place, which implies a single outcome.
(I originally implemented in-place modification because I wanted
to avoid having to create copies of state objects, and it's now
very difficult to change this aspect of the analyzer's design)
However, there are various special-cases such as "realloc" for which
it's best to split the state into multiple outcomes.
This patch adds a mechanism for "bifurcating" the analysis in places
where there isn't a split in the CFG, and uses it to implement realloc,
in this case treating it as having 3 possible outcomes:
- failure, returning NULL
- success, growing the buffer in-place without moving it
- success, allocating a new buffer, copying the content of the old
buffer to it, and freeing the old buffer.
gcc/ChangeLog:
PR analyzer/99260
* Makefile.in (ANALYZER_OBJS): Add analyzer/call-info.o.
gcc/analyzer/ChangeLog:
PR analyzer/99260
* analyzer.h (class custom_edge_info): New class, adapted from
exploded_edge::custom_info_t. Make member functions const.
Make update_model return bool, converting edge param from
reference to a pointer, and adding a ctxt param.
(class path_context): New class.
* call-info.cc: New file.
* call-info.h: New file.
* engine.cc: Include "analyzer/call-info.h" and <memory>.
(impl_region_model_context::impl_region_model_context): Update for
new m_path_ctxt field.
(impl_region_model_context::bifurcate): New.
(impl_region_model_context::terminate_path): New.
(impl_region_model_context::get_malloc_map): New.
(impl_sm_context::impl_sm_context): Update for new m_path_ctxt
field.
(impl_sm_context::get_fndecl_for_call): Likewise.
(impl_sm_context::set_next_state): Likewise.
(impl_sm_context::warn): Likewise.
(impl_sm_context::is_zero_assignment): Likewise.
(impl_sm_context::get_path_context): New.
(impl_sm_context::m_path_ctxt): New.
(impl_region_model_context::on_condition): Update for new
path_ctxt param. Handle m_enode_for_diag being NULL.
(impl_region_model_context::on_phi): Update for new path_ctxt
param.
(exploded_node::on_stmt): Add path_ctxt param, updating ctor calls
to use it as necessary. Use it to bail out after sm-handling,
if needed.
(exploded_node::detect_leaks): Update for new path_ctxt param.
(dynamic_call_info_t::update_model): Update for conversion of
exploded_edge::custom_info_t to custom_edge_info.
(dynamic_call_info_t::add_events_to_path): Likewise.
(rewind_info_t::update_model): Likewise.
(rewind_info_t::add_events_to_path): Likewise.
(exploded_edge::exploded_edge): Likewise.
(exploded_graph::add_edge): Likewise.
(exploded_graph::maybe_process_run_of_before_supernode_enodes):
Update for new path_ctxt param.
(class impl_path_context): New.
(exploded_graph::process_node): Update for new path_ctxt param.
Create an impl_path_context and pass it to exploded_node::on_stmt.
Use it to terminate iterating stmts if terminate_path is called
on it. After processing a run of stmts, query path_ctxt to
potentially terminate the analysis path, and/or to "bifurcate" the
analysis into multiple additional paths.
(feasibility_state::maybe_update_for_edge): Update for new
update_model ctxt param.
* exploded-graph.h
(impl_region_model_context::impl_region_model_context): Add
path_ctxt param.
(impl_region_model_context::bifurcate): New.
(impl_region_model_context::terminate_path): New
(impl_region_model_context::get_ext_state): New.
(impl_region_model_context::get_malloc_map): New.
(impl_region_model_context::m_path_ctxt): New field.
(exploded_node::on_stmt): Add path_ctxt param.
(class exploded_edge::custom_info_t): Move to analyzer.h, renaming
to custom_edge_info, and making the changes as noted in analyzer.h
above.
(exploded_edge::exploded_edge): Update for these changes to
exploded_edge::custom_info_t.
(exploded_edge::m_custom_info): Likewise.
(class dynamic_call_info_t): Likewise.
(class rewind_info_t): Likewise.
(exploded_graph::add_edge): Likewise.
* program-state.cc (program_state::on_edge): Update for new
path_ctxt param.
(program_state::push_call): Likewise.
(program_state::returning_call): Likewise.
(program_state::prune_for_point): Likewise.
* region-model-impl-calls.cc: Include "analyzer/call-info.h".
(call_details::get_fndecl_for_call): New.
(region_model::impl_call_realloc): Reimplement.
* region-model.cc (region_model::on_call_pre): Move call to
impl_call_realloc to...
(region_model::on_call_post): ...here. Consolidate creation
of call_details instance.
(noop_region_model_context::bifurcate): New.
(noop_region_model_context::terminate_path): New.
* region-model.h (call_details::get_call_stmt): New.
(call_details::get_fndecl_for_call): New.
(region_model::on_realloc_with_move): New.
(region_model_context::bifurcate): New.
(region_model_context::terminate_path): New.
(region_model_context::get_ext_state): New.
(region_model_context::get_malloc_map): New.
(noop_region_model_context::bifurcate): New.
(noop_region_model_context::terminate_path): New.
(noop_region_model_context::get_ext_state): New.
(noop_region_model_context::get_malloc_map): New.
* sm-malloc.cc: Include "analyzer/program-state.h".
(malloc_state_machine::on_realloc_call): Reimplement.
(malloc_state_machine::on_realloc_with_move): New.
(region_model::on_realloc_with_move): New.
* sm-signal.cc (class signal_delivery_edge_info_t): Update for
conversion from exploded_edge::custom_info_t to custom_edge_info.
* sm.h (sm_context::get_path_context): New.
* svalue.cc (svalue::maybe_get_constant): Call
unwrap_any_unmergeable.
gcc/testsuite/ChangeLog:
PR analyzer/99260
* gcc.dg/analyzer/capacity-2.c: Update for changes to realloc
analysis.
* gcc.dg/analyzer/pr99193-1.c: Likewise.
* gcc.dg/analyzer/pr99193-3.c: Likewise.
* gcc.dg/analyzer/realloc-1.c: Likewise. Add test coverage for
realloc of non-heap pointer, realloc from mismatching allocator,
and realloc on a freed pointer.
* gcc.dg/analyzer/realloc-2.c: New test.
|
|
2021-07-29 Ankur Saini <arsenic@sourceware.org>
gcc/analyzer/ChangeLog:
PR analyzer/100546
* analysis-plan.cc (analysis_plan::use_summary_p): Don't use call
summaries if there is no callgraph edge
* checker-path.cc (call_event::call_event): Handle calls events that
are not represented by a supergraph call edge
(return_event::return_event): Likewise.
(call_event::get_desc): Work with new call_event structure.
(return_event::get_desc): Likeise.
* checker-path.h (call_event::m_src_snode): New field.
(call_event::m_dest_snode): New field.
(return_event::m_src_snode): New field.
(return_event::m_dest_snode): New field.
* diagnostic-manager.cc
(diagnostic_manager::prune_for_sm_diagnostic)<case EK_CALL_EDGE>:
Refactor to work with edges without callgraph edge.
(diagnostic_manager::prune_for_sm_diagnostic)<case EK_RETURN_EDGE>:
Likewise.
* engine.cc (dynamic_call_info_t::update_model): New function.
(dynamic_call_info_t::add_events_to_path): New function.
(exploded_graph::create_dynamic_call): New function.
(exploded_graph::process_node): Work with dynamically discovered calls.
* exploded-graph.h (class dynamic_call_info_t): New class.
(exploded_graph::create_dynamic_call): New decl.
* program-point.cc (program_point::push_to_call_stack): New function.
(program_point::pop_from_call_stack): New function.
* program-point.h (program_point::push_to_call_stack): New decl.
(program_point::pop_from_call_stack): New decl.
* program-state.cc (program_state::push_call): New function.
(program_state::returning_call): New function.
* program-state.h (program_state::push_call): New decl.
(program_state::returning_call): New decl.
* region-model.cc (region_model::update_for_gcall) New function.
(region_model::update_for_return_gcall): New function.
(egion_model::update_for_call_superedge): Get the underlying gcall and
update for gcall.
(region_model::update_for_return_superedge): Likewise.
* region-model.h (region_model::update_for_gcall): New decl.
(region_model::update_for_return_gcall): New decl.
* state-purge.cc (state_purge_per_ssa_name::process_point): Update to
work with calls without underlying cgraph edge.
* supergraph.cc (supergraph::supergraph) Split snodes at every callsite.
* supergraph.h (supernode::get_returning_call) New accessor.
gcc/testsuite/ChangeLog:
PR analyzer/100546
* gcc.dg/analyzer/function-ptr-4.c: New test.
* gcc.dg/analyzer/pr100546.c: New test.
|
|
PR analyzer/101503 reports an assertion failure due to an unexpected
"UNKNOWN" value (due to using --param analyzer-max-svalue-depth=0).
This patch fixes this by rejecting attempts to purge state involving
unknown/poisoned svalues (in region_model::purge_state_involving),
as these svalues should not have state associated with them - they
are singletons w.r.t each type.
To be more systematic about this, the patch also introduces a new
svalue::can_have_associated_state_p which returns false for
unknown/poisoned svalues, so that we can reject adding constraints
or sm-state on them, or building various kinds of svalue in terms
of them (e.g. unary ops, binary ops, etc).
gcc/analyzer/ChangeLog:
PR analyzer/101503
* constraint-manager.cc (constraint_manager::add_constraint): Use
can_have_associated_state_p rather than testing for unknown.
(constraint_manager::get_or_add_equiv_class): Likewise.
* program-state.cc (sm_state_map::set_state): Likewise.
(sm_state_map::impl_set_state): Add assertion.
* region-model-manager.cc
(region_model_manager::maybe_fold_unaryop): Handle poisoned
values.
(region_model_manager::maybe_fold_binop): Move handling of unknown
values...
(region_model_manager::get_or_create_binop): ...to here, and
generalize to use can_have_associated_state_p.
(region_model_manager::maybe_fold_sub_svalue): Use
can_have_associated_state_p rather than testing for unknown.
(region_model_manager::maybe_fold_repeated_svalue): Use unknown
when the size or repeated value is "unknown"/"poisoned".
* region-model.cc (region_model::purge_state_involving): Reject
attempts to purge unknown/poisoned svalues, as these svalues
should not have state associated with them.
* svalue.cc (sub_svalue::sub_svalue): Assert that we're building
on top of an svalue with can_have_associated_state_p.
(repeated_svalue::repeated_svalue): Likewise.
(bits_within_svalue::bits_within_svalue): Likewise.
* svalue.h (svalue::can_have_associated_state_p): New.
(unknown_svalue::can_have_associated_state_p): New.
(poisoned_svalue::can_have_associated_state_p): New.
(unaryop_svalue::unaryop_svalue): Assert that we're building on
top of an svalue with can_have_associated_state_p.
(binop_svalue::binop_svalue): Likewise.
(widening_svalue::widening_svalue): Likewise.
gcc/testsuite/ChangeLog:
PR analyzer/101503
* gcc.dg/analyzer/pr101503.c: New test.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
I've been experimenting with various new diagnostics that
require a common place for the analyzer to check the validity
of reads or writes to memory (e.g. buffer overflow).
As preliminary work, this patch adds new
region_model::check_region_for_{read|write} functions
which are called anywhere that the analyzer "sees" memory being
read from or written to (via region_model::get_store_value and
region_model::set_value).
This takes over the hardcoded calls to check_for_writable_region
(allowing for other kinds of checks on writes); checking reads is
currently a no-op.
gcc/analyzer/ChangeLog:
* analyzer.h (enum access_direction): New.
* engine.cc (exploded_node::on_longjmp): Update for new param of
get_store_value.
* program-state.cc (program_state::prune_for_point): Likewise.
* region-model-impl-calls.cc (region_model::impl_call_memcpy):
Replace call to check_for_writable_region with call to
check_region_for_write.
(region_model::impl_call_memset): Likewise.
(region_model::impl_call_strcpy): Likewise.
* region-model-reachability.cc (reachable_regions::add): Update
for new param of get_store_value.
* region-model.cc (region_model::get_rvalue_1): Likewise, also for
get_rvalue_for_bits.
(region_model::get_store_value): Add ctxt param and use it to call
check_region_for_read.
(region_model::get_rvalue_for_bits): Add ctxt param and use it to
call get_store_value.
(region_model::check_region_access): New.
(region_model::check_region_for_write): New.
(region_model::check_region_for_read): New.
(region_model::set_value): Update comment. Replace call to
check_for_writable_region with call to check_region_for_write.
* region-model.h (region_model::get_rvalue_for_bits): Add ctxt
param.
(region_model::get_store_value): Add ctxt param.
(region_model::check_region_access): New decl.
(region_model::check_region_for_write): New decl.
(region_model::check_region_for_read): New decl.
* region.cc (region_model::copy_region): Update call to
get_store_value.
* svalue.cc (initial_svalue::implicitly_live_p): Likewise.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
gcc/analyzer/ChangeLog:
* engine.cc (exploded_node::on_stmt_pre): Handle
__analyzer_dump_state.
* program-state.cc (extrinsic_state::get_sm_idx_by_name): New.
(program_state::impl_call_analyzer_dump_state): New.
* program-state.h (extrinsic_state::get_sm_idx_by_name): New decl.
(program_state::impl_call_analyzer_dump_state): New decl.
* region-model-impl-calls.cc
(call_details::get_arg_string_literal): New.
* region-model.h (call_details::get_arg_string_literal): New decl.
gcc/ChangeLog:
* doc/analyzer.texi: Add __analyzer_dump_state.
gcc/testsuite/ChangeLog:
* gcc.dg/analyzer/analyzer-decls.h (__analyzer_dump_state): New.
* gcc.dg/analyzer/dump-state.c: New test.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
gcc/analyzer/ChangeLog:
* program-state.cc (program_state::detect_leaks): Simplify using
svalue::maybe_get_region.
* region-model-impl-calls.cc (region_model::impl_call_fgets): Likewise.
(region_model::impl_call_fread): Likewise.
(region_model::impl_call_free): Likewise.
(region_model::impl_call_operator_delete): Likewise.
* region-model.cc (selftest::test_stack_frames): Likewise.
(selftest::test_state_merging): Likewise.
* svalue.cc (svalue::maybe_get_region): New.
* svalue.h (svalue::maybe_get_region): New decl.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
The initial gcc 10 era commit of the analyzer (in
757bf1dff5e8cee34c0a75d06140ca972bfecfa7) had an implementation of
-Wanalyzer-use-of-uninitialized-value, but was sufficiently buggy
that I removed it in 78b9783774bfd3540f38f5b1e3c7fc9f719653d7 before
the release of gcc 10.1
This patch reintroduces the warning, heavily rewritten, with (I hope)
a less buggy implementation this time, for GCC 12.
gcc/analyzer/ChangeLog:
PR analyzer/95006
PR analyzer/94713
PR analyzer/94714
* analyzer.cc (maybe_reconstruct_from_def_stmt): Split out
GIMPLE_ASSIGN case into...
(get_diagnostic_tree_for_gassign_1): New.
(get_diagnostic_tree_for_gassign): New.
* analyzer.h (get_diagnostic_tree_for_gassign): New decl.
* analyzer.opt (Wanalyzer-write-to-string-literal): New.
* constraint-manager.cc (class svalue_purger): New.
(constraint_manager::purge_state_involving): New.
* constraint-manager.h
(constraint_manager::purge_state_involving): New.
* diagnostic-manager.cc (saved_diagnostic::supercedes_p): New.
(dedupe_winners::handle_interactions): New.
(diagnostic_manager::emit_saved_diagnostics): Call it.
* diagnostic-manager.h (saved_diagnostic::supercedes_p): New decl.
* engine.cc (impl_region_model_context::warn): Convert return type
to bool. Return false if the diagnostic isn't saved.
(impl_region_model_context::purge_state_involving): New.
(impl_sm_context::get_state): Use NULL ctxt when querying old
rvalue.
(impl_sm_context::set_next_state): Use new sval when querying old
state.
(class dump_path_diagnostic): Move to region-model.cc
(exploded_node::on_stmt): Move to on_stmt_pre and on_stmt_post.
Remove call to purge_state_involving.
(exploded_node::on_stmt_pre): New, based on the above. Move most
of it to region_model::on_stmt_pre.
(exploded_node::on_stmt_post): Likewise, moving to
region_model::on_stmt_post.
(class stale_jmp_buf): Fix parent class to use curiously recurring
template pattern.
(feasibility_state::maybe_update_for_edge): Call on_call_pre and
on_call_post on gcalls.
* exploded-graph.h (impl_region_model_context::warn): Return bool.
(impl_region_model_context::purge_state_involving): New decl.
(exploded_node::on_stmt_pre): New decl.
(exploded_node::on_stmt_post): New decl.
* pending-diagnostic.h (pending_diagnostic::use_of_uninit_p): New.
(pending_diagnostic::supercedes_p): New.
* program-state.cc (sm_state_map::get_state): Inherit state for
conjured_svalue as well as initial_svalue.
(sm_state_map::purge_state_involving): Also support SK_CONJURED.
* region-model-impl-calls.cc (call_details::get_uncertainty):
Handle m_ctxt being NULL.
(call_details::get_or_create_conjured_svalue): New.
(region_model::impl_call_fgets): New.
(region_model::impl_call_fread): New.
* region-model-manager.cc
(region_model_manager::get_or_create_initial_value): Return an
uninitialized poisoned value for regions that can't have initial
values.
* region-model-reachability.cc
(reachable_regions::mark_escaped_clusters): Handle ctxt being
NULL.
* region-model.cc (region_to_value_map::purge_state_involving): New.
(poisoned_value_diagnostic::use_of_uninit_p): New.
(poisoned_value_diagnostic::emit): Handle POISON_KIND_UNINIT.
(poisoned_value_diagnostic::describe_final_event): Likewise.
(region_model::check_for_poison): New.
(region_model::on_assignment): Call it.
(class dump_path_diagnostic): Move here from engine.cc.
(region_model::on_stmt_pre): New, based on exploded_node::on_stmt.
(region_model::on_call_pre): Move the setting of the LHS to a
conjured svalue to before the checks for specific functions.
Handle "fgets", "fgets_unlocked", and "fread".
(region_model::purge_state_involving): New.
(region_model::handle_unrecognized_call): Handle ctxt being NULL.
(region_model::get_rvalue): Call check_for_poison.
(selftest::test_stack_frames): Use NULL for context when getting
uninitialized rvalue.
(selftest::test_alloca): Likewise.
* region-model.h (region_to_value_map::purge_state_involving): New
decl.
(call_details::get_or_create_conjured_svalue): New decl.
(region_model::on_stmt_pre): New decl.
(region_model::purge_state_involving): New decl.
(region_model::impl_call_fgets): New decl.
(region_model::impl_call_fread): New decl.
(region_model::check_for_poison): New decl.
(region_model_context::warn): Return bool.
(region_model_context::purge_state_involving): New.
(noop_region_model_context::warn): Return bool.
(noop_region_model_context::purge_state_involving): New.
(test_region_model_context:: warn): Return bool.
* region.cc (region::get_memory_space): New.
(region::can_have_initial_svalue_p): New.
(region::involves_p): New.
* region.h (enum memory_space): New.
(region::get_memory_space): New decl.
(region::can_have_initial_svalue_p): New decl.
(region::involves_p): New decl.
* sm-malloc.cc (use_after_free::supercedes_p): New.
* store.cc (binding_cluster::purge_state_involving): New.
(store::purge_state_involving): New.
* store.h (class symbolic_binding): New forward decl.
(binding_key::dyn_cast_symbolic_binding): New.
(symbolic_binding::dyn_cast_symbolic_binding): New.
(binding_cluster::purge_state_involving): New.
(store::purge_state_involving): New.
* svalue.cc (svalue::can_merge_p): Reject attempts to merge
poisoned svalues with other svalues, so that we identify
paths in which a variable is conditionally uninitialized.
(involvement_visitor::visit_conjured_svalue): New.
(svalue::involves_p): Also handle SK_CONJURED.
(poison_kind_to_str): Handle POISON_KIND_UNINIT.
(poisoned_svalue::maybe_fold_bits_within): New.
* svalue.h (enum poison_kind): Add POISON_KIND_UNINIT.
(poisoned_svalue::maybe_fold_bits_within): New decl.
gcc/ChangeLog:
PR analyzer/95006
PR analyzer/94713
PR analyzer/94714
* doc/invoke.texi: Add -Wanalyzer-use-of-uninitialized-value.
gcc/testsuite/ChangeLog:
PR analyzer/95006
PR analyzer/94713
PR analyzer/94714
* g++.dg/analyzer/pr93212.C: Update location of warning.
* g++.dg/analyzer/pr94011.C: Add
-Wno-analyzer-use-of-uninitialized-value.
* g++.dg/analyzer/pr94503.C: Likewise.
* gcc.dg/analyzer/clobbers-1.c: Convert "f" from a local to a
param to avoid uninitialized warning.
* gcc.dg/analyzer/data-model-1.c (test_12): Add test for
uninitialized value on result of alloca.
(test_12a): Add expected warning.
(test_12c): Likewise.
(test_19): Likewise.
(test_29b): Likewise.
(test_29c): Likewise.
(test_37): Remove xfail.
(test_37a): Likewise.
* gcc.dg/analyzer/data-model-20.c: Add warning about leak.
* gcc.dg/analyzer/explode-2.c: Remove params; add
-Wno-analyzer-too-complex, -Wno-analyzer-malloc-leak, and xfails.
Initialize the locals.
* gcc.dg/analyzer/explode-2a.c: Initialize the locals. Add
expected leak.
* gcc.dg/analyzer/fgets-1.c: New test.
* gcc.dg/analyzer/fread-1.c: New test.
* gcc.dg/analyzer/malloc-1.c (test_16): Add expected warning.
(test_40): Likewise.
* gcc.dg/analyzer/memset-CVE-2017-18549-1.c: Check for
uninitialized padding.
* gcc.dg/analyzer/pr93355-localealias-feasibility.c (fread): New
decl.
(read_alias_file): Call it.
* gcc.dg/analyzer/pr94047.c: Add expected warnings.
* gcc.dg/analyzer/pr94851-2.c: Likewise.
* gcc.dg/analyzer/pr96841.c: Convert local to a param.
* gcc.dg/analyzer/pr98628.c: Likewise.
* gcc.dg/analyzer/pr99042.c: Updated expected location of leak
diagnostics.
* gcc.dg/analyzer/symbolic-1.c: Add expected warnings.
* gcc.dg/analyzer/symbolic-7.c: Likewise.
* gcc.dg/analyzer/torture/pr93649.c: Add expected warning. Skip
with -fno-fat-lto-objects.
* gcc.dg/analyzer/uninit-1.c: New test.
* gcc.dg/analyzer/uninit-2.c: New test.
* gcc.dg/analyzer/uninit-3.c: New test.
* gcc.dg/analyzer/uninit-4.c: New test.
* gcc.dg/analyzer/uninit-pr94713.c: New test.
* gcc.dg/analyzer/uninit-pr94714.c: New test.
* gcc.dg/analyzer/use-after-free-2.c: New test.
* gcc.dg/analyzer/use-after-free-3.c: New test.
* gcc.dg/analyzer/zlib-3.c: Add expected warning.
* gcc.dg/analyzer/zlib-6.c: Convert locals to params to avoid
uninitialized warnings. Remove xfail.
* gcc.dg/analyzer/zlib-6a.c: New test, based on the old version
of the above.
* gfortran.dg/analyzer/pr97668.f: Add
-Wno-analyzer-use-of-uninitialized-value and
-Wno-analyzer-too-complex.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
I rewrote the way the analyzer's region_model tracks the state of memory
in GCC 11 (in 808f4dfeb3a95f50f15e71148e5c1067f90a126d), which
introduced a store with a binding_map class, mapping binding keys to
symbolic values.
The GCC 11 implementation of binding keys has an enum binding_kind,
which can be "default" vs "direct"; the idea being that direct
bindings take priority over default bindings, where the latter could
be used to represent e.g. a zero-fill of a buffer, and the former
expresses those subregions that have since been touched.
This doesn't work well: it doesn't express the idea of filling
different subregions with different values, or a memset that only
touches part of a buffer, leading to numerous XFAILs in the memset
test cases (and elsewhere).
As preparatory work towards tracking uninitialized values, this patch
eliminates the enum binding_kind, so that all bindings have
equal weight; the order in which they happen is all that matters.
If a write happens which partially overwrites an existing binding,
the new code can partially overwrite a binding, potentially punching a
hole so that an existing binding is split into two parts.
The patch adds some new classes:
- a new "bits_within_svalue" symbolic value to support extracting
parts of an existing value when its binding is partially clobbered
- a new "repeated_svalue" symbolic value to better express filling
a region with repeated copies of a symbolic value (e.g. constant
zero)
- a new "sized_region" region to express accessing a subregion
with a symbolic size in bytes
and it rewrites e.g. how memset is implemented, so that we can precisely
track which bits in a region have not been touched.
That said, the patch doesn't actually implement "uninitialized" values;
I'm saving that for a followup.
gcc/analyzer/ChangeLog:
PR analyzer/95006
* analyzer.h (class repeated_svalue): New forward decl.
(class bits_within_svalue): New forward decl.
(class sized_region): New forward decl.
(get_field_at_bit_offset): New forward decl.
* engine.cc (exploded_graph::get_or_create_node): Validate the
merged state.
(exploded_graph::maybe_process_run_of_before_supernode_enodes):
Validate the states at each stage.
* program-state.cc (program_state::validate): Validate
m_region_model.
* region-model-impl-calls.cc (region_model::impl_call_memset):
Replace special-case logic for handling constant sizes with
a call to fill_region of a sized_region with the given fill value.
* region-model-manager.cc (maybe_undo_optimize_bit_field_compare):
Drop DK_direct.
(region_model_manager::maybe_fold_sub_svalue): Fold element-based
subregions of an initial value into initial values of an element.
Fold subvalues of repeated svalues.
(region_model_manager::maybe_fold_repeated_svalue): New.
(region_model_manager::get_or_create_repeated_svalue): New.
(get_bit_range_for_field): New.
(get_byte_range_for_field): New.
(get_field_at_byte_range): New.
(region_model_manager::maybe_fold_bits_within_svalue): New.
(region_model_manager::get_or_create_bits_within): New.
(region_model_manager::get_sized_region): New.
(region_model_manager::log_stats): Update for addition of
m_repeated_values_map, m_bits_within_values_map, and
m_sized_regions.
* region-model.cc (region_model::validate): New.
(region_model::on_assignment): Drop enum binding_kind.
(region_model::get_initial_value_for_global): Likewise.
(region_model::get_rvalue_for_bits): Replace body with call to
get_or_create_bits_within.
(region_model::get_capacity): Handle RK_SIZED.
(region_model::set_value): Drop enum binding_kind.
(region_model::fill_region): New.
(region_model::get_representative_path_var_1): Handle RK_SIZED.
* region-model.h (visitor::visit_repeated_svalue): New.
(visitor::visit_bits_within_svalue): New.
(region_model_manager::get_or_create_repeated_svalue): New decl.
(region_model_manager::get_or_create_bits_within): New decl.
(region_model_manager::get_sized_region): New decl.
(region_model_manager::maybe_fold_repeated_svalue): New decl.
(region_model_manager::maybe_fold_bits_within_svalue): New decl.
(region_model_manager::repeated_values_map_t): New typedef.
(region_model_manager::m_repeated_values_map): New field.
(region_model_manager::bits_within_values_map_t): New typedef.
(region_model_manager::m_bits_within_values_map): New field.
(region_model_manager::m_sized_regions): New field.
(region_model::fill_region): New decl.
* region.cc (region::get_base_region): Handle RK_SIZED.
(region::base_region_p): Likewise.
(region::get_byte_size_sval): New.
(get_field_at_bit_offset): Make non-static.
(region::calc_offset): Move implementation of cases to
get_relative_concrete_offset vfunc implementations. Handle
RK_SIZED.
(region::get_relative_concrete_offset): New.
(decl_region::get_svalue_for_initializer): Drop enum binding_kind.
(field_region::get_relative_concrete_offset): New, from
region::calc_offset.
(element_region::get_relative_concrete_offset): Likewise.
(offset_region::get_relative_concrete_offset): Likewise.
(sized_region::accept): New.
(sized_region::dump_to_pp): New.
(sized_region::get_byte_size): New.
(sized_region::get_bit_size): New.
* region.h (enum region_kind): Add RK_SIZED.
(region::dyn_cast_sized_region): New.
(region::get_byte_size): Make virtual.
(region::get_bit_size): Likewise.
(region::get_byte_size_sval): New decl.
(region::get_relative_concrete_offset): New decl.
(field_region::get_relative_concrete_offset): New decl.
(element_region::get_relative_concrete_offset): Likewise.
(offset_region::get_relative_concrete_offset): Likewise.
(class sized_region): New.
* store.cc (binding_kind_to_string): Delete.
(binding_key::make): Drop enum binding_kind.
(binding_key::dump_to_pp): Delete.
(binding_key::cmp_ptrs): Drop enum binding_kind.
(bit_range::contains_p): New.
(byte_range::dump): New.
(byte_range::contains_p): New.
(byte_range::cmp): New.
(concrete_binding::dump_to_pp): Drop enum binding_kind.
(concrete_binding::cmp_ptr_ptr): Likewise.
(symbolic_binding::dump_to_pp): Likewise.
(symbolic_binding::cmp_ptr_ptr): Likewise.
(binding_map::apply_ctor_val_to_range): Likewise.
(binding_map::apply_ctor_pair_to_child_region): Likewise.
(binding_map::get_overlapping_bindings): New.
(binding_map::remove_overlapping_bindings): New.
(binding_cluster::validate): New.
(binding_cluster::bind): Drop enum binding_kind.
(binding_cluster::bind_compound_sval): Likewise.
(binding_cluster::purge_region): Likewise.
(binding_cluster::zero_fill_region): Reimplement in terms of...
(binding_cluster::fill_region): New.
(binding_cluster::mark_region_as_unknown): Drop enum binding_kind.
(binding_cluster::get_binding): Likewise.
(binding_cluster::get_binding_recursive): Likewise.
(binding_cluster::get_any_binding): Likewise.
(binding_cluster::maybe_get_compound_binding): Reimplement.
(binding_cluster::get_overlapping_bindings): Delete.
(binding_cluster::remove_overlapping_bindings): Reimplement in
terms of binding_map::remove_overlapping_bindings.
(binding_cluster::can_merge_p): Update for removal of
enum binding_kind.
(binding_cluster::on_unknown_fncall): Drop enum binding_kind.
(binding_cluster::maybe_get_simple_value): Likewise.
(store_manager::get_concrete_binding): Likewise.
(store_manager::get_symbolic_binding): Likewise.
(store::validate): New.
(store::set_value): Drop enum binding_kind.
(store::zero_fill_region): Reimplement in terms of...
(store::fill_region): New.
(selftest::test_binding_key_overlap): Drop enum binding_kind.
* store.h (enum binding_kind): Delete.
(binding_kind_to_string): Delete decl.
(binding_key::make): Drop enum binding_kind.
(binding_key::dump_to_pp): Make pure virtual.
(binding_key::get_kind): Delete.
(binding_key::mark_deleted): Delete.
(binding_key::mark_empty): Delete.
(binding_key::is_deleted): Delete.
(binding_key::is_empty): Delete.
(binding_key::binding_key): Delete.
(binding_key::impl_hash): Delete.
(binding_key::impl_eq): Delete.
(binding_key::m_kind): Delete.
(bit_range::get_last_bit_offset): New.
(bit_range::contains_p): New.
(byte_range::contains_p): New.
(byte_range::operator==): New.
(byte_range::get_start_byte_offset): New.
(byte_range::get_next_byte_offset): New.
(byte_range::get_last_byte_offset): New.
(byte_range::as_bit_range): New.
(byte_range::cmp): New.
(concrete_binding::concrete_binding): Drop enum binding_kind.
(concrete_binding::hash): Likewise.
(concrete_binding::operator==): Likewise.
(concrete_binding::mark_deleted): New.
(concrete_binding::mark_empty): New.
(concrete_binding::is_deleted): New.
(concrete_binding::is_empty): New.
(default_hash_traits<ana::concrete_binding>::empty_zero_p): Make false.
(symbolic_binding::symbolic_binding): Drop enum binding_kind.
(symbolic_binding::hash): Likewise.
(symbolic_binding::operator==): Likewise.
(symbolic_binding::mark_deleted): New.
(symbolic_binding::mark_empty): New.
(symbolic_binding::is_deleted): New.
(symbolic_binding::is_empty): New.
(binding_map::remove_overlapping_bindings): New decl.
(binding_map::get_overlapping_bindings): New decl.
(binding_cluster::validate): New decl.
(binding_cluster::bind): Drop enum binding_kind.
(binding_cluster::fill_region): New decl.
(binding_cluster::get_binding): Drop enum binding_kind.
(binding_cluster::get_binding_recursive): Likewise.
(binding_cluster::get_overlapping_bindings): Delete.
(store::validate): New decl.
(store::set_value): Drop enum binding_kind.
(store::fill_region): New decl.
(store_manager::get_concrete_binding): Drop enum binding_kind.
(store_manager::get_symbolic_binding): Likewise.
* svalue.cc (svalue::cmp_ptr): Handle SK_REPEATED and
SK_BITS_WITHIN.
(svalue::extract_bit_range): New.
(svalue::maybe_fold_bits_within): New.
(constant_svalue::maybe_fold_bits_within): New.
(unknown_svalue::maybe_fold_bits_within): New.
(unaryop_svalue::maybe_fold_bits_within): New.
(repeated_svalue::repeated_svalue): New.
(repeated_svalue::dump_to_pp): New.
(repeated_svalue::accept): New.
(repeated_svalue::all_zeroes_p): New.
(repeated_svalue::maybe_fold_bits_within): New.
(bits_within_svalue::bits_within_svalue): New.
(bits_within_svalue::dump_to_pp): New.
(bits_within_svalue::maybe_fold_bits_within): New.
(bits_within_svalue::accept): New.
(bits_within_svalue::implicitly_live_p): New.
(compound_svalue::maybe_fold_bits_within): New.
* svalue.h (enum svalue_kind): Add SK_REPEATED and SK_BITS_WITHIN.
(svalue::dyn_cast_repeated_svalue): New.
(svalue::dyn_cast_bits_within_svalue): New.
(svalue::extract_bit_range): New decl.
(svalue::maybe_fold_bits_within): New vfunc decl.
(region_svalue::key_t::mark_empty): Use 2 rather than NULL_TREE.
(region_svalue::key_t::is_empty): Likewise.
(default_hash_traits<region_svalue::key_t>::empty_zero_p): Make false.
(constant_svalue::maybe_fold_bits_within): New.
(unknown_svalue::maybe_fold_bits_within): New.
(poisoned_svalue::key_t::mark_empty): Use 2 rather than NULL_TREE.
(poisoned_svalue::key_t::is_empty): Likewise.
(default_hash_traits<poisoned_svalue::key_t>::empty_zero_p): Make
false.
(setjmp_svalue::key_t::mark_empty): Use 2 rather than NULL_TREE.
(setjmp_svalue::key_t::is_empty): Likewise.
(default_hash_traits<setjmp_svalue::key_t>::empty_zero_p): Make
false.
(unaryop_svalue::key_t::mark_empty): Use 2 rather than NULL_TREE.
(unaryop_svalue::key_t::is_empty): Likewise.
(unaryop_svalue::maybe_fold_bits_within): New.
(default_hash_traits<unaryop_svalue::key_t>::empty_zero_p): Make
false.
(binop_svalue::key_t::mark_empty): Use 2 rather than NULL_TREE.
(binop_svalue::key_t::is_empty): Likewise.
(default_hash_traits<binop_svalue::key_t>::empty_zero_p): Make
false.
(sub_svalue::key_t::mark_empty): Use 2 rather than NULL_TREE.
(sub_svalue::key_t::is_empty): Likewise.
(default_hash_traits<sub_svalue::key_t>::empty_zero_p): Make
false.
(class repeated_svalue): New.
(is_a_helper <const repeated_svalue *>::test): New.
(struct default_hash_traits<repeated_svalue::key_t>): New.
(class bits_within_svalue): New.
(is_a_helper <const bits_within_svalue *>::test): New.
(struct default_hash_traits<bits_within_svalue::key_t>): New.
(widening_svalue::key_t::mark_empty): Use 2 rather than NULL_TREE.
(widening_svalue::key_t::is_empty): Likewise.
(default_hash_traits<widening_svalue::key_t>::empty_zero_p): Make
false.
(compound_svalue::key_t::mark_empty): Use 2 rather than NULL_TREE.
(compound_svalue::key_t::is_empty): Likewise.
(compound_svalue::maybe_fold_bits_within): New.
(default_hash_traits<compound_svalue::key_t>::empty_zero_p): Make
false.
gcc/testsuite/ChangeLog:
PR analyzer/95006
* gcc.dg/analyzer/clobbers-1.c: New test.
* gcc.dg/analyzer/clobbers-2.c: New test.
* gcc.dg/analyzer/data-model-1.c (test_26): Mark xfail as fixed.
(test_28): Likewise.
(test_52): Likewise. Add coverage for end of buffer.
* gcc.dg/analyzer/explode-1.c: Add leak warning.
* gcc.dg/analyzer/memset-1.c (test_3): Mark xfail as fixed.
(test_4): Use char. Mark xfail as fixed.
(test_6b): New.
(test_7): Mark xfail as fixed. Add coverage for start of buffer.
(test_8): New.
(test_9): New.
* gcc.dg/analyzer/memset-CVE-2017-18549-1.c: New test.
* gcc.dg/analyzer/symbolic-8.c: New test.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
This patch extends region_model to add tracking of the sizes of
dynamically-allocated regions, both on the heap (via malloc etc) and
stack (via alloca). It adds enough purging of this state to avoid
blowing up any existing analyzer test cases.
The state can be queried via a new "__analyzer_dump_capacity" for use
in DejaGnu tests but other than that doesn't do anything - I have
various followup experiments that make use of this.
gcc/analyzer/ChangeLog:
* engine.cc (exploded_node::on_stmt): Handle __analyzer_dump_capacity.
(exploded_node::on_stmt): Drop m_sm_changes from on_stmt_flags.
(state_change_requires_new_enode_p): New function...
(exploded_graph::process_node): Call it, rather than querying
flags.m_sm_changes, so that dynamic-extent differences can also
trigger the splitting of nodes.
* exploded-graph.h (struct on_stmt_flags): Drop field m_sm_changes.
* program-state.cc (program_state::detect_leaks): Purge dead
heap-allocated regions from dynamic extents.
(selftest::test_program_state_1): Fix type of "size_in_bytes".
(selftest::test_program_state_merging): Likewise.
* region-model-impl-calls.cc
(region_model::impl_call_analyzer_dump_capacity): New.
(region_model::impl_call_free): Remove dynamic extents from the
freed region.
* region-model-reachability.h
(reachable_regions::begin_mutable_base_regs): New.
(reachable_regions::end_mutable_base_regs): New.
* region-model.cc: Include "tree-object-size.h".
(region_model::region_model): Support new field m_dynamic_extents.
(region_model::operator=): Likewise.
(region_model::operator==): Likewise.
(region_model::dump_to_pp): Dump sizes of dynamic regions.
(region_model::handle_unrecognized_call): Purge dynamic extents
from any regions that have escaped mutably:.
(region_model::get_capacity): New function.
(region_model::add_constraint): Unset dynamic extents when a
heap-allocated region's address is NULL.
(region_model::unbind_region_and_descendents): Purge dynamic
extents of unbound regions.
(region_model::can_merge_with_p): Call
m_dynamic_extents.can_merge_with_p.
(region_model::create_region_for_heap_alloc): Assert that
size_in_bytes's type is compatible with size_type_node. Update
for renaming of record_dynamic_extents to set_dynamic_extents.
(region_model::create_region_for_alloca): Likewise.
(region_model::record_dynamic_extents): Rename to...
(region_model::set_dynamic_extents): ...this. Assert that
size_in_bytes's type is compatible with size_type_node. Add it
to the m_dynamic_extents map.
(region_model::get_dynamic_extents): New.
(region_model::unset_dynamic_extents): New.
(selftest::test_state_merging): Fix type of "size".
(selftest::test_malloc_constraints): Likewise.
(selftest::test_malloc): Verify dynamic extents.
(selftest::test_alloca): Likewise.
* region-model.h (region_to_value_map::is_empty): New.
(region_model::dynamic_extents_t): New typedef.
(region_model::impl_call_analyzer_dump_capacity): New decl.
(region_model::get_dynamic_extents): New function.
(region_model::get_dynamic_extents): New decl.
(region_model::set_dynamic_extents): New decl.
(region_model::unset_dynamic_extents): New decl.
(region_model::get_capacity): New decl.
(region_model::record_dynamic_extents): Rename to set_dynamic_extents.
(region_model::m_dynamic_extents): New field.
gcc/ChangeLog:
* doc/analyzer.texi
(Special Functions for Debugging the Analyzer): Add
__analyzer_dump_capacity.
gcc/testsuite/ChangeLog:
* gcc.dg/analyzer/analyzer-decls.h (__analyzer_dump_capacity): New decl.
* gcc.dg/analyzer/capacity-1.c: New test.
* gcc.dg/analyzer/capacity-2.c: New test.
* gcc.dg/analyzer/capacity-3.c: New test.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
|
|
This changes users of FOR_EACH_VEC_ELT to use range based for loops,
where the index variables are otherwise unused. As such the index
variables are all deleted, producing shorter and simpler code.
Signed-off-by: Trevor Saunders <tbsaunde@tbsaunde.org>
gcc/analyzer/ChangeLog:
* call-string.cc (call_string::call_string): Use range based for
to iterate over vec<>.
(call_string::to_json): Likewise.
(call_string::hash): Likewise.
(call_string::calc_recursion_depth): Likewise.
* checker-path.cc (checker_path::fixup_locations): Likewise.
* constraint-manager.cc (equiv_class::equiv_class): Likewise.
(equiv_class::to_json): Likewise.
(equiv_class::hash): Likewise.
(constraint_manager::to_json): Likewise.
* engine.cc (impl_region_model_context::on_svalue_leak):
Likewise.
(on_liveness_change): Likewise.
(impl_region_model_context::on_unknown_change): Likewise.
* program-state.cc (sm_state_map::set_state): Likewise.
* region-model.cc (test_canonicalization_4): Likewise.
gcc/ChangeLog:
* attribs.c (find_attribute_namespace): Iterate over vec<> with
range based for.
* auto-profile.c (afdo_find_equiv_class): Likewise.
* gcc.c (do_specs_vec): Likewise.
(do_spec_1): Likewise.
(driver::set_up_specs): Likewise.
* gimple-loop-jam.c (any_access_function_variant_p): Likewise.
* gimple-ssa-store-merging.c (compatible_load_p): Likewise.
(imm_store_chain_info::try_coalesce_bswap): Likewise.
(imm_store_chain_info::coalesce_immediate_stores): Likewise.
(get_location_for_stmts): Likewise.
* graphite-poly.c (print_iteration_domains): Likewise.
(free_poly_bb): Likewise.
(remove_gbbs_in_scop): Likewise.
(free_scop): Likewise.
(dump_gbb_cases): Likewise.
(dump_gbb_conditions): Likewise.
(print_pdrs): Likewise.
(print_scop): Likewise.
* ifcvt.c (cond_move_process_if_block): Likewise.
* lower-subreg.c (decompose_multiword_subregs): Likewise.
* regcprop.c (pass_cprop_hardreg::execute): Likewise.
* sanopt.c (sanitize_rewrite_addressable_params): Likewise.
* sel-sched-dump.c (dump_insn_vector): Likewise.
* store-motion.c (store_ops_ok): Likewise.
(store_killed_in_insn): Likewise.
* timevar.c (timer::named_items::print): Likewise.
* tree-cfgcleanup.c (cleanup_control_flow_pre): Likewise.
(cleanup_tree_cfg_noloop): Likewise.
* tree-data-ref.c (dump_data_references): Likewise.
(print_dir_vectors): Likewise.
(print_dist_vectors): Likewise.
(dump_data_dependence_relations): Likewise.
(dump_dist_dir_vectors): Likewise.
(dump_ddrs): Likewise.
(create_runtime_alias_checks): Likewise.
(free_subscripts): Likewise.
(save_dist_v): Likewise.
(save_dir_v): Likewise.
(invariant_access_functions): Likewise.
(same_access_functions): Likewise.
(access_functions_are_affine_or_constant_p): Likewise.
(find_data_references_in_stmt): Likewise.
(graphite_find_data_references_in_stmt): Likewise.
(free_dependence_relations): Likewise.
(free_data_refs): Likewise.
* tree-inline.c (copy_debug_stmts): Likewise.
* tree-into-ssa.c (dump_currdefs): Likewise.
(rewrite_update_phi_arguments): Likewise.
* tree-ssa-propagate.c (clean_up_loop_closed_phi): Likewise.
* tree-vect-data-refs.c (vect_analyze_possibly_independent_ddr):
Likewise.
(vect_slp_analyze_node_dependences): Likewise.
(vect_slp_analyze_instance_dependence): Likewise.
(vect_record_base_alignments): Likewise.
(vect_get_peeling_costs_all_drs): Likewise.
(vect_peeling_supportable): Likewise.
* tree-vectorizer.c (vec_info::~vec_info): Likewise.
(vec_info::free_stmt_vec_infos): Likewise.
gcc/cp/ChangeLog:
* constexpr.c (cxx_eval_call_expression): Iterate over vec<>
with range based for.
(cxx_eval_store_expression): Likewise.
(cxx_eval_loop_expr): Likewise.
* decl.c (wrapup_namespace_globals): Likewise.
(cp_finish_decl): Likewise.
(cxx_simulate_enum_decl): Likewise.
* parser.c (cp_parser_postfix_expression): Likewise.
|
|
Right now, we require a C++11 compiler, so the check is not needed any
longer.
gcc/analyzer/ChangeLog:
* program-state.cc (program_state::operator=): Remove
__cplusplus >= 201103.
(program_state::program_state): Likewise.
* program-state.h: Likewise.
* region-model.h (class region_model): Remove dead code.
gcc/ChangeLog:
* bitmap.h (class auto_bitmap): Remove
__cplusplus >= 201103.
* config/aarch64/aarch64.c: Likewise.
* gimple-ssa-store-merging.c (store_immediate_info::store_immediate_info):
Likewise.
* sbitmap.h: Likewise.
|
|
Prior to this patch, program_state::detect_leaks worked by finding all
live svalues in the old state and in the new state, and calling
on_svalue_leak for each svalue that has changed from being live to
not being live.
PR analyzer/99042 and PR analyzer/99774 both describe false leak
diagnostics from -fanalyzer (a false FILE * leak in git, and a false
malloc leak in qemu, respectively).
In both cases the root cause of the false leak diagnostic relates to
svalues no longer being explicitly bound in the store due to regions
being conservatively clobbered, due to an unknown function being
called, or due to a write through a pointer that could alias the
region, respectively.
We have a transition from an svalue being explicitly live to not
being explicitly live - but only because the store is being
conservative, clobbering the binding. The leak detection is looking
for transitions from "definitely live" to "not definitely live",
when it should be looking for transitions from "definitely live"
to "definitely not live".
This patch introduces a new class to temporarily capture information
about svalues that were explicitly live, but for which a region bound
to them got clobbered for conservative reasons. This new
"uncertainty_t" class is passed around to capture the data long enough
for use in program_state::detect_leaks, where it is used to only
complain about svalues that were definitely live and are now both
not definitely live *or* possibly-live i.e. definitely not-live.
The class also captures for which svalues we can't meaningfully track
sm-state anymore, and resets the svalues back to the "start" state.
Together, these changes fix the false leak reports.
gcc/analyzer/ChangeLog:
PR analyzer/99042
PR analyzer/99774
* engine.cc
(impl_region_model_context::impl_region_model_context): Add
uncertainty param and use it to initialize m_uncertainty.
(impl_region_model_context::get_uncertainty): New.
(impl_sm_context::get_fndecl_for_call): Add NULL for new
uncertainty param when constructing impl_region_model_context.
(impl_sm_context::get_state): Likewise.
(impl_sm_context::set_next_state): Likewise.
(impl_sm_context::warn): Likewise.
(exploded_node::on_stmt): Add uncertainty param
and use it when constructing impl_region_model_context.
(exploded_node::on_edge): Add uncertainty param and pass
to on_edge call.
(exploded_node::detect_leaks): Create uncertainty_t and pass to
impl_region_model_context.
(exploded_graph::get_or_create_node): Create uncertainty_t and
pass to prune_for_point.
(maybe_process_run_of_before_supernode_enodes): Create
uncertainty_t and pass to impl_region_model_context.
(exploded_graph::process_node): Create uncertainty_t instances and
pass around as needed.
* exploded-graph.h
(impl_region_model_context::impl_region_model_context): Add
uncertainty param.
(impl_region_model_context::get_uncertainty): New decl.
(impl_region_model_context::m_uncertainty): New field.
(exploded_node::on_stmt): Add uncertainty param.
(exploded_node::on_edge): Likewise.
* program-state.cc (sm_state_map::on_liveness_change): Get
uncertainty from context and use it to unset sm-state from
svalues as appropriate.
(program_state::on_edge): Add uncertainty param and use it when
constructing impl_region_model_context. Fix indentation.
(program_state::prune_for_point): Add uncertainty param and use it
when constructing impl_region_model_context.
(program_state::detect_leaks): Get any uncertainty from ctxt and
use it to get maybe-live svalues for dest_state, rather than
definitely-live ones; use this when determining which svalues
have leaked.
(selftest::test_program_state_merging): Create uncertainty_t and
pass to impl_region_model_context.
* program-state.h (program_state::on_edge): Add uncertainty param.
(program_state::prune_for_point): Likewise.
* region-model-impl-calls.cc (call_details::get_uncertainty): New.
(region_model::impl_call_memcpy): Pass uncertainty to
mark_region_as_unknown call.
(region_model::impl_call_memset): Likewise.
(region_model::impl_call_strcpy): Likewise.
* region-model-reachability.cc (reachable_regions::handle_sval):
Also add sval to m_mutable_svals.
* region-model.cc (region_model::on_assignment): Pass any
uncertainty from ctxt to the store::set_value call.
(region_model::handle_unrecognized_call): Get any uncertainty from
ctxt and use it to record mutable svalues at the unknown call.
(region_model::get_reachable_svalues): Add uncertainty param and
use it to mark any maybe-bound svalues as being reachable.
(region_model::set_value): Pass any uncertainty from ctxt to the
store::set_value call.
(region_model::mark_region_as_unknown): Add uncertainty param and
pass it on to the store::mark_region_as_unknown call.
(region_model::update_for_call_summary): Add uncertainty param and
pass it on to the region_model::mark_region_as_unknown call.
* region-model.h (call_details::get_uncertainty): New decl.
(region_model::get_reachable_svalues): Add uncertainty param.
(region_model::mark_region_as_unknown): Add uncertainty param.
(region_model_context::get_uncertainty): New vfunc.
(noop_region_model_context::get_uncertainty): New vfunc
implementation.
* store.cc (dump_svalue_set): New.
(uncertainty_t::dump_to_pp): New.
(uncertainty_t::dump): New.
(binding_cluster::clobber_region): Pass NULL for uncertainty to
remove_overlapping_bindings.
(binding_cluster::mark_region_as_unknown): Add uncertainty param
and pass it to remove_overlapping_bindings.
(binding_cluster::remove_overlapping_bindings): Add uncertainty param.
Use it to record any svalues that were in clobbered bindings.
(store::set_value): Add uncertainty param. Pass it to
binding_cluster::mark_region_as_unknown when handling symbolic
regions.
(store::mark_region_as_unknown): Add uncertainty param and pass it
to binding_cluster::mark_region_as_unknown.
(store::remove_overlapping_bindings): Add uncertainty param and
pass it to binding_cluster::remove_overlapping_bindings.
* store.h (binding_cluster::mark_region_as_unknown): Add
uncertainty param.
(binding_cluster::remove_overlapping_bindings): Likewise.
(store::set_value): Likewise.
(store::mark_region_as_unknown): Likewise.
gcc/testsuite/ChangeLog:
PR analyzer/99042
PR analyzer/99774
* gcc.dg/analyzer/pr99042.c: New test.
* gcc.dg/analyzer/pr99774-1.c: New test.
* gcc.dg/analyzer/pr99774-2.c: New test.
|
|
Various places iterate through all of the saved_diagnostics to find
just the ones that are at a given enode. This patch adds a per-enode
record of the diagnostics that are at each node, to save iterating
through all of the diagnostics each time.
gcc/analyzer/ChangeLog:
* diagnostic-manager.cc (diagnostic_manager::add_diagnostic): Make
enode param non-constant, and call add_diagnostic on it. Add
enode index to log message.
(diagnostic_manager::add_diagnostic): Make enode param
non-constant.
* diagnostic-manager.h (diagnostic_manager::add_diagnostic):
Likewise for both decls.
* engine.cc
(impl_region_model_context::impl_region_model_context): Likewise
for enode_for_diag.
(impl_sm_context::impl_sm_context): Likewise.
(impl_sm_context::m_enode_for_diag): Likewise.
(exploded_node::dump_dot): Don't pass the diagnostic manager
to dump_saved_diagnostics.
(exploded_node::dump_saved_diagnostics): Drop param. Iterate
directly through all saved diagnostics for the enode, rather
than all saved diagnostics in the diagnostic_manager and
filtering.
(exploded_node::on_stmt): Make non-const.
(exploded_node::on_edge): Likewise.
(exploded_node::on_longjmp): Likewise.
(exploded_node::detect_leaks): Likewise.
(exploded_graph::get_or_create_node): Make enode_for_diag param
non-const.
(exploded_graph_annotator::print_enode): Iterate
directly through all saved diagnostics for the enode, rather
than all saved diagnostics in the diagnostic_manager and
filtering.
* exploded-graph.h
(impl_region_model_context::impl_region_model_context): Make
enode_for_diag param non-constant.
(impl_region_model_context::m_enode_for_diag): Likewise.
(exploded_node::dump_saved_diagnostics): Drop param.
(exploded_node::on_stmt): Make non-const.
(exploded_node::on_edge): Likewise.
(exploded_node::on_longjmp): Likewise.
(exploded_node::detect_leaks): Likewise.
(exploded_node::add_diagnostic): New.
(exploded_node::get_num_diagnostics): New.
(exploded_node::get_saved_diagnostic): New.
(exploded_node::m_saved_diagnostics): New.
(exploded_graph::get_or_create_node): Make enode_for_diag param
non-constant.
* feasible-graph.cc (feasible_node::dump_dot): Drop
diagnostic_manager from call to dump_saved_diagnostics.
* program-state.cc (program_state::on_edge): Convert enode param
to non-const pointer.
(program_state::prune_for_point): Likewise for enode_for_diag
param.
* program-state.h (program_state::on_edge): Convert enode param
to non-const pointer.
(program_state::prune_for_point): Likewise for enode_for_diag
param.
|
|
Various false positives from -fanalyzer involve SSA names in loops,
where sm-state associated with an SSA name from one iteration is
erroneously reused in a subsequent iteration.
For example, PR analyzer/99716 describes a false
"double 'fclose' of FILE 'fp'"
on:
for (i = 0; i < 2; ++i) {
FILE *fp = fopen ("/tmp/test", "w");
fprintf (fp, "hello");
fclose (fp);
}
where the gimple of the loop body is:
fp_7 = fopen ("/tmp/test", "w");
__builtin_fwrite ("hello", 1, 5, fp_7);
fclose (fp_7);
i_10 = i_1 + 1;
where fp_7 transitions to "closed" at the fclose, but is not
reset at the subsequent fopen, leading to the false positive
when the fclose is re-reached.
The fix is to reset sm-state for svalues that involve an SSA name
at the SSA name's def-stmt, since the def-stmt effectively changes
the meaning of those related svalues.
gcc/analyzer/ChangeLog:
PR analyzer/93695
PR analyzer/99044
PR analyzer/99716
* engine.cc (exploded_node::on_stmt): Clear sm-state involving
an SSA name at the def-stmt of that SSA name.
* program-state.cc (sm_state_map::purge_state_involving): New.
* program-state.h (sm_state_map::purge_state_involving): New decl.
* region-model.cc (selftest::test_involves_p): New.
(selftest::analyzer_region_model_cc_tests): Call it.
* svalue.cc (class involvement_visitor): New class
(svalue::involves_p): New.
* svalue.h (svalue::involves_p): New decl.
gcc/testsuite/ChangeLog:
PR analyzer/93695
PR analyzer/99044
PR analyzer/99716
* gcc.dg/analyzer/attr-malloc-CVE-2019-19078-usb-leak.c: Remove
xfail.
* gcc.dg/analyzer/pr93695-1.c: New test.
* gcc.dg/analyzer/pr99044-1.c: New test.
* gcc.dg/analyzer/pr99044-2.c: New test.
* gcc.dg/analyzer/pr99716-1.c: New test.
* gcc.dg/analyzer/pr99716-2.c: New test.
* gcc.dg/analyzer/pr99716-3.c: New test.
|
|
This patch updates the svalue liveness code so that the initial value
of parameters at top-level functions to the analysis are treated as
live (since the values are presumably still live within the
outside-of-the-analysis calling code).
This fixes the false leak in PR analyzer/98969 seen on:
void
test (long int i)
{
struct foo *f = (struct foo *)i;
f->expr = __builtin_malloc (1024);
}
since the calling code can presumably still access the allocated
buffer via:
((struct foo *)i)->expr
The patch also removes the expected leak warnings from
g++.dg/analyzer/pr99064.C and gcc.dg/analyzer/pr96841.c, which now
appear to me to be false positives.
gcc/analyzer/ChangeLog:
PR analyzer/98969
* constraint-manager.cc (dead_svalue_purger::should_purge_p):
Update for change to svalue::live_p.
* program-state.cc (sm_state_map::on_liveness_change): Likewise.
(program_state::detect_leaks): Likewise.
* region-model-reachability.cc (reachable_regions::init_cluster):
When dealing with a symbolic region, if the underlying pointer is
implicitly live, add the region to the reachable regions.
* region-model.cc (region_model::compare_initial_and_pointer):
Move logic for detecting initial values of params to
initial_svalue::initial_value_of_param_p.
* svalue.cc (svalue::live_p): Convert "live_svalues" from a
reference to a pointer; support it being NULL.
(svalue::implicitly_live_p): Convert first param from a
refererence to a pointer.
(region_svalue::implicitly_live_p): Likewise.
(constant_svalue::implicitly_live_p): Likewise.
(initial_svalue::implicitly_live_p): Likewise. Treat the initial
values of params for the top level frame as still live.
(initial_svalue::initial_value_of_param_p): New function, taken
from a test in region_model::compare_initial_and_pointer.
(unaryop_svalue::implicitly_live_p): Convert first param from a
refererence to a pointer.
(binop_svalue::implicitly_live_p): Likewise.
(sub_svalue::implicitly_live_p): Likewise.
(unmergeable_svalue::implicitly_live_p): Likewise.
* svalue.h (svalue::live_p): Likewise.
(svalue::implicitly_live_p): Likewise.
(region_svalue::implicitly_live_p): Likewise.
(constant_svalue::implicitly_live_p): Likewise.
(initial_svalue::implicitly_live_p): Likewise.
(initial_svalue::initial_value_of_param_p): New decl.
(unaryop_svalue::implicitly_live_p): Convert first param from a
refererence to a pointer.
(binop_svalue::implicitly_live_p): Likewise.
(sub_svalue::implicitly_live_p): Likewise.
(unmergeable_svalue::implicitly_live_p): Likewise.
gcc/testsuite/ChangeLog:
PR analyzer/98969
* g++.dg/analyzer/pr99064.C: Convert dg-bogus to dg-warning.
* gcc.dg/analyzer/pr96841.c: Add -Wno-analyzer-too-complex to
options. Remove false leak directive.
* gcc.dg/analyzer/pr98969.c (test_1): Remove xfail from leak
false positive.
(test_3): New.
|
|
|
|
gcc/analyzer/ChangeLog:
* constraint-manager.cc (constraint_manager::merge): Remove
unused code.
* constraint-manager.h: Likewise.
* program-state.cc (sm_state_map::sm_state_map): Likewise.
(program_state::program_state): Likewise.
(test_sm_state_map): Likewise.
* program-state.h: Likewise.
* region-model-reachability.cc (reachable_regions::reachable_regions): Likewise.
* region-model-reachability.h: Likewise.
* region-model.cc (region_model::handle_unrecognized_call): Likewise.
(region_model::get_reachable_svalues): Likewise.
(region_model::can_merge_with_p): Likewise.
|
|
gcc/analyzer/ChangeLog:
* program-state.cc (sm_state_map::on_liveness_change): Sort the
leaking svalues before calling on_state_leak.
(program_state::detect_leaks): Likewise when calling
on_svalue_leak.
* region-model-reachability.cc
(reachable_regions::mark_escaped_clusters): Likewise when
calling on_escaped_function.
|
|
gcc/analyzer/ChangeLog:
* program-state.cc (sm_state_map::print): Guard the printing of
the origin pointer with !flag_dump_noaddr.
* region.cc (string_region::dump_to_pp): Likewise for
m_string_cst.
|
|
This patch is a followup to the previous one, eliminating
non-determinism in the behavior of the analyzer (rather than just in
the logs), by sorting whenever the result previously depended on
pointer values. Tested as per the previous patch.
gcc/analyzer/ChangeLog:
* constraint-manager.cc (svalue_cmp_by_ptr): Delete.
(equiv_class::canonicalize): Use svalue::cmp_ptr_ptr instead.
(equiv_class_cmp): Eliminate pointer comparison.
* diagnostic-manager.cc (dedupe_key::comparator): If they are at
the same location, also compare epath ength and pending_diagnostic
kind.
* engine.cc (readability_comparator): If two path_vars have the
same readability, then impose an arbitrary ordering on them.
(worklist::key_t::cmp): If two points have the same plan ordering,
continue the comparison. Call sm_state_map::cmp rather than
comparing hash values.
* program-state.cc (sm_state_map::entry_t::cmp): New.
(sm_state_map::cmp): New.
* program-state.h (sm_state_map::entry_t::cmp): New decl.
(sm_state_map::elements): New.
(sm_state_map::cmp): New.
|
|
This patch and the followup eliminate various forms of non-determinism
in the analyzer due to changing pointer values.
This patch fixes churn seen when diffing analyzer logs. The patch
avoids embedding pointers in various places, and adds sorting when
dumping hash_set and hash_map for various analyzer types. Doing so
requires implementing a way to sort svalue instances, and assigning UIDs
to gimple statements.
Tested both patches together via a script that runs a testcase 100 times,
and then using diff and md5sum to verify that the results are consistent
in the face of address space randomization:
FILENAME=$1
rm $FILENAME.*
for i in `seq 1 100`; do
echo "iteration: $i"
./xgcc -B. -fanalyzer -c ../../src/gcc/testsuite/gcc.dg/analyzer/$FILENAME \
--Wanalyzer-too-complex \
-fdump-analyzer-supergraph \
-fdump-analyzer-exploded-graph \
-fdump-analyzer \
-fdump-noaddr \
-fdump-analyzer-exploded-nodes-2
mv $FILENAME.supergraph.dot $FILENAME.$i.supergraph.dot
mv $FILENAME.analyzer.txt $FILENAME.$i.analyzer.txt
mv $FILENAME.supergraph-eg.dot $FILENAME.$i.supergraph-eg.dot
mv $FILENAME.eg.txt $FILENAME.$i.eg.txt
mv $FILENAME.eg.dot $FILENAME.$i.eg.dot
done
gcc/analyzer/ChangeLog:
* engine.cc (setjmp_record::cmp): New.
(supernode_cluster::dump_dot): Avoid embedding pointer in cluster
name.
(supernode_cluster::cmp_ptr_ptr): New.
(function_call_string_cluster::dump_dot): Avoid embedding pointer
in cluster name. Sort m_map when dumping child clusters.
(function_call_string_cluster::cmp_ptr_ptr): New.
(root_cluster::dump_dot): Sort m_map when dumping child clusters.
* program-point.cc (function_point::cmp): New.
(function_point::cmp_ptr): New.
* program-point.h (function_point::cmp): New decl.
(function_point::cmp_ptr): New decl.
* program-state.cc (sm_state_map::print): Sort the values. Guard
the printing of pointers with !flag_dump_noaddr.
(program_state::prune_for_point): Sort the regions.
(log_set_of_svalues): Sort the values. Guard the printing of
pointers with !flag_dump_noaddr.
* region-model-manager.cc (log_uniq_map): Sort the values.
* region-model-reachability.cc (dump_set): New function template.
(reachable_regions::dump_to_pp): Use it.
* region-model.h (svalue::cmp_ptr): New decl.
(svalue::cmp_ptr_ptr): New decl.
(setjmp_record::cmp): New decl.
(placeholder_svalue::get_name): New accessor.
(widening_svalue::get_point): New accessor.
(compound_svalue::get_map): New accessor.
(conjured_svalue::get_stmt): New accessor.
(conjured_svalue::get_id_region): New accessor.
(region::cmp_ptrs): Rename to...
(region::cmp_ptr_ptr): ...this.
* region.cc (region::cmp_ptrs): Rename to...
(region::cmp_ptr_ptr): ...this.
* state-purge.cc
(state_purge_per_ssa_name::state_purge_per_ssa_name): Sort
m_points_needing_name when dumping.
* store.cc (concrete_binding::cmp_ptr_ptr): New.
(symbolic_binding::cmp_ptr_ptr): New.
(binding_map::cmp): New.
(get_sorted_parent_regions): Update for renaming of
region::cmp_ptrs to region::cmp_ptr_ptr.
(store::dump_to_pp): Likewise.
(store::to_json): Likewise.
(store::can_merge_p): Sort the base regions before considering
them.
* store.h (concrete_binding::cmp_ptr_ptr): New decl.
(symbolic_binding::cmp_ptr_ptr): New decl.
(binding_map::cmp): New decl.
* supergraph.cc (supergraph::supergraph): Assign UIDs to the
gimple stmts.
* svalue.cc (cmp_cst): New.
(svalue::cmp_ptr): New.
(svalue::cmp_ptr_ptr): New.
|
|
In 10fc42a8396072912e9d9d940fba25950b3fdfc5 I converted state_t from
unsigned to const state *, but missed this comparison against 0.
gcc/analyzer/ChangeLog:
* program-state.cc (sm_state_map::print): Update check
for m_global_state being the start state.
|
|
This patch provides a new option "-fno-analyzer-feasibility" as a way
to disable feasibility-checking of the constraints along the control
flow paths for -fanalyzer diagnostics. I'm adding this in the hope of
making it easier to debug issues involving the feasibility-checking
logic.
The patch adds a new rejected_constraint object which is captured if
exploded_path::feasible_p fails, and adds logic that uses this to emit
an additional custom_event within the checker_path for the diagnostic,
showing where in the control flow path the diagnostic would have been
rejected, and giving details of why.
gcc/analyzer/ChangeLog:
* analyzer.h (struct rejected_constraint): New decl.
* analyzer.opt (fanalyzer-feasibility): New option.
* diagnostic-manager.cc (path_builder::path_builder): Add
"problem" param and use it to initialize new field.
(path_builder::get_feasibility_problem): New accessor.
(path_builder::m_feasibility_problem): New field.
(dedupe_winners::add): Remove inversion of logic in "if" clause,
swapping if/else suites. In the !feasible_p suite, inspect
flag_analyzer_feasibility and add code to handle when this
is off, accepting the infeasible path, but recording the
feasibility_problem.
(diagnostic_manager::emit_saved_diagnostic): Pass the
feasibility_problem to the path_builder.
(diagnostic_manager::add_events_for_eedge): If we have
a feasibility_problem at this edge, use it to add a custom event.
* engine.cc (exploded_path::feasible_p): Pass a
rejected_constraint ** to model.maybe_update_for_edge and transfer
ownership of any created instance to any feasibility_problem.
(feasibility_problem::dump_to_pp): New.
* exploded-graph.h (feasibility_problem::feasibility_problem):
Drop "model" param; add rejected_constraint * param.
(feasibility_problem::~feasibility_problem): New.
(feasibility_problem::dump_to_pp): New decl.
(feasibility_problem::m_model): Drop field.
(feasibility_problem::m_rc): New field.
* program-point.cc (function_point::get_location): Handle
PK_BEFORE_SUPERNODE and PK_AFTER_SUPERNODE.
* program-state.cc (program_state::on_edge): Pass NULL to new
param of region_model::maybe_update_for_edge.
* region-model.cc (region_model::add_constraint): New overload
adding a rejected_constraint ** param.
(region_model::maybe_update_for_edge): Add rejected_constraint **
param and pass it to the various apply_constraints_for_ calls.
(region_model::apply_constraints_for_gcond): Add
rejected_constraint ** param and pass it to add_constraint calls.
(region_model::apply_constraints_for_gswitch): Likewise.
(region_model::apply_constraints_for_exception): Likewise.
(rejected_constraint::dump_to_pp): New.
* region-model.h (region_model::maybe_update_for_edge):
Add rejected_constraint ** param.
(region_model::add_constraint): New overload adding a
rejected_constraint ** param.
(region_model::apply_constraints_for_gcond): Add
rejected_constraint ** param.
(region_model::apply_constraints_for_gswitch): Likewise.
(region_model::apply_constraints_for_exception): Likewise.
(struct rejected_constraint): New.
gcc/ChangeLog:
* doc/analyzer.texi (Analyzer Paths): Add note about
-fno-analyzer-feasibility.
* doc/invoke.texi (Static Analyzer Options): Add
-fno-analyzer-feasibility.
gcc/testsuite/ChangeLog:
* gcc.dg/analyzer/feasibility-2.c: New test.
|
|
gcc/analyzer/ChangeLog:
PR analyzer/97178
* engine.cc (impl_run_checkers): Update for change to ext_state
ctor.
* program-state.cc (selftest::test_sm_state_map): Pass an engine
instance to ext_state ctor.
(selftest::test_program_state_1): Likewise.
(selftest::test_program_state_2): Likewise.
(selftest::test_program_state_merging): Likewise.
(selftest::test_program_state_merging_2): Likewise.
* program-state.h (extrinsic_state::extrinsic_state): Remove NULL
default value for "eng" param.
|
|
I've found this useful for debugging state explosions in the analyzer.
gcc/analyzer/ChangeLog:
* analysis-plan.cc: Include "json.h".
* analyzer.opt (fdump-analyzer-json): New.
* call-string.cc: Include "json.h".
(call_string::to_json): New.
* call-string.h (call_string::to_json): New decl.
* checker-path.cc: Include "json.h".
* constraint-manager.cc: Include "json.h".
(equiv_class::to_json): New.
(constraint::to_json): New.
(constraint_manager::to_json): New.
* constraint-manager.h (equiv_class::to_json): New decl.
(constraint::to_json): New decl.
(constraint_manager::to_json): New decl.
* diagnostic-manager.cc: Include "json.h".
(saved_diagnostic::to_json): New.
(diagnostic_manager::to_json): New.
* diagnostic-manager.h (saved_diagnostic::to_json): New decl.
(diagnostic_manager::to_json): New decl.
* engine.cc: Include "json.h", <zlib.h>.
(exploded_node::status_to_str): New.
(exploded_node::to_json): New.
(exploded_edge::to_json): New.
(exploded_graph::to_json): New.
(dump_analyzer_json): New.
(impl_run_checkers): Call it.
* exploded-graph.h (exploded_node::status_to_str): New decl.
(exploded_node::to_json): New.
(exploded_edge::to_json): New.
(exploded_graph::to_json): New.
* pending-diagnostic.cc: Include "json.h".
* program-point.cc: Include "json.h".
(program_point::to_json): New.
* program-point.h (program_point::to_json): New decl.
* program-state.cc: Include "json.h".
(extrinsic_state::to_json): New.
(sm_state_map::to_json): New.
(program_state::to_json): New.
* program-state.h (extrinsic_state::to_json): New decl.
(sm_state_map::to_json): New decl.
(program_state::to_json): New decl.
* region-model-impl-calls.cc: Include "json.h".
* region-model-manager.cc: Include "json.h".
* region-model-reachability.cc: Include "json.h".
* region-model.cc: Include "json.h".
* region-model.h (svalue::to_json): New decl.
(region::to_json): New decl.
* region.cc: Include "json.h".
(region::to_json: New.
* sm-file.cc: Include "json.h".
* sm-malloc.cc: Include "json.h".
* sm-pattern-test.cc: Include "json.h".
* sm-sensitive.cc: Include "json.h".
* sm-signal.cc: Include "json.h".
(signal_delivery_edge_info_t::to_json): New.
* sm-taint.cc: Include "json.h".
* sm.cc: Include "diagnostic.h", "tree-diagnostic.h", and
"json.h".
(state_machine::state::to_json): New.
(state_machine::to_json): New.
* sm.h (state_machine::state::to_json): New.
(state_machine::to_json): New.
* state-purge.cc: Include "json.h".
* store.cc: Include "json.h".
(binding_key::get_desc): New.
(binding_map::to_json): New.
(binding_cluster::to_json): New.
(store::to_json): New.
* store.h (binding_key::get_desc): New decl.
(binding_map::to_json): New decl.
(binding_cluster::to_json): New decl.
(store::to_json): New decl.
* supergraph.cc: Include "json.h".
(supergraph::to_json): New.
(supernode::to_json): New.
(superedge::to_json): New.
* supergraph.h (supergraph::to_json): New decl.
(supernode::to_json): New decl.
(superedge::to_json): New decl.
* svalue.cc: Include "json.h".
(svalue::to_json): New.
gcc/ChangeLog:
* doc/analyzer.texi (Other Debugging Techniques): Mention
-fdump-analyzer-json.
* doc/invoke.texi (Static Analyzer Options): Add
-fdump-analyzer-json.
|
|
This patch is preliminary work towards generalizing sm-malloc.cc so that
it can check APIs other than just malloc/free (and e.g. detect
mismatching alloc/dealloc pairs).
Generalize states in state machines so that, rather than state_t being
just an "unsigned", it becomes a "const state *", where the underlying
state objects are immutable objects managed by the state machine in
question, and can e.g. have vfuncs and extra fields. The start state
m_start becomes a member of the state_machine base_class.
gcc/analyzer/ChangeLog:
* checker-path.cc (state_change_event::get_desc): Update
state_machine::get_state_name calls to state::get_name.
(warning_event::get_desc): Likewise.
* diagnostic-manager.cc
(null_assignment_sm_context::on_transition): Update comparison
against 0 with comparison with m_sm.get_start_state.
(diagnostic_manager::prune_for_sm_diagnostic): Update
state_machine::get_state_name calls to state::get_name.
* engine.cc (impl_sm_context::on_transition): Likewise.
(exploded_node::get_dot_fillcolor): Use get_id when summing
the sm states.
* program-state.cc (sm_state_map::sm_state_map): Don't hardcode
0 as the start state when initializing m_global_state.
(sm_state_map::print): Use dump_to_pp rather than get_state_name
when dumping states.
(sm_state_map::is_empty_p): Don't hardcode 0 as the start state
when examining m_global_state.
(sm_state_map::hash): Use get_id when hashing states.
(selftest::test_sm_state_map): Use state objects rather than
arbitrary hardcoded integers.
(selftest::test_program_state_merging): Likewise.
(selftest::test_program_state_merging_2): Likewise.
* sm-file.cc (fileptr_state_machine::m_start): Move to base class.
(file_diagnostic::describe_state_change): Use get_start_state.
(fileptr_state_machine::fileptr_state_machine): Drop m_start
initialization.
* sm-malloc.cc (malloc_state_machine::m_start): Move to base
class.
(malloc_diagnostic::describe_state_change): Use get_start_state.
(possible_null::describe_state_change): Likewise.
(malloc_state_machine::malloc_state_machine): Drop m_start
initialization.
* sm-pattern-test.cc (pattern_test_state_machine::m_start): Move
to base class.
(pattern_test_state_machine::pattern_test_state_machine): Drop
m_start initialization.
* sm-sensitive.cc (sensitive_state_machine::m_start): Move to base
class.
(sensitive_state_machine::sensitive_state_machine): Drop m_start
initialization.
* sm-signal.cc (signal_state_machine::m_start): Move to base
class.
(signal_state_machine::signal_state_machine): Drop m_start
initialization.
* sm-taint.cc (taint_state_machine::m_start): Move to base class.
(taint_state_machine::taint_state_machine): Drop m_start
initialization.
* sm.cc (state_machine::state::dump_to_pp): New.
(state_machine::state_machine): Move here from sm.h. Initialize
m_next_state_id and m_start.
(state_machine::add_state): Reimplement in terms of state objects.
(state_machine::get_state_name): Delete.
(state_machine::get_state_by_name): Reimplement in terms of state
objects. Make const.
(state_machine::validate): Delete.
(state_machine::dump_to_pp): Reimplement in terms of state
objects.
* sm.h (state_machine::state): New class.
(state_machine::state_t): Convert typedef from "unsigned" to
"const state_machine::state *".
(state_machine::state_machine): Move to sm.cc.
(state_machine::get_default_state): Use m_start rather than
hardcoding 0.
(state_machine::get_state_name): Delete.
(state_machine::get_state_by_name): Make const.
(state_machine::get_start_state): New accessor.
(state_machine::alloc_state_id): New.
(state_machine::m_state_names): Drop in favor of...
(state_machine::m_states): New field
(state_machine::m_start): New field
(start_start_p): Delete.
|
|
This large patch reimplements how the analyzer tracks regions and
values.
Elimination of region_id and svalue_id
**************************************
The patch eliminates region_id and svalue_id in favor of simply
using pointers. I'd hoped that the ID classes would make it easier
to compare states, avoiding having to compare long hexadecimal addresses
in favor of small integers. Unfortunately it added lots of complexity,
with the need to remap IDs when comparing or purging states, and the
need to "canonicalize" when comparing states.
Various "state explosion" bugs in the old implementation were due to
failures in canonicalization, where two states that ought to be equal
were non-equal due to differences in ID ordering. I spent a lot of
time trying to fix canonicalization bugs, and there always seemed to
be one more bug. By eliminating IDs in this new implementation, lots
of tricky canonicalization goes away and no ID remapping should be
needed; almost all of the old validation code becomes redundant.
There's still some canonicalization in the new implementation, mostly
in constraint_manager, but much less than before.
Ownership of regions and svalues
********************************
In the old implementation, each region_model had its own copies of
regions and svalues, so there was heap bloat and churn as lots of
little objects were cloned when copying program_state instances. In the
new implementation the regions and svalues are immutable and are shared
thoughout the analysis, rather than being per region_model. They are
owned by a manager class, and are effectively singletons. Region and
svalue instances can now be compared by pointer rather than by comparing
their fields (the manager class takes care of uniqueness).
This is a huge simplification, and (I hope) will avoid lots
of heap churn as states are copied; all mutable state from regions and
svalues is now stored in a "store" class in the region_model.
Changes to the meaning of a "region"
************************************
Region subclasses no longer represent internal structure, but instead
represent how the regions are reached. So e.g. a global "struct coord
c;" is now a decl_region, rather than a struct_region.
In the old implementation, the values for each region were stored in the
region instances, but in the new implementation the regions are immutable.
Memory is now modeled in a new "store" class: a mapping from keys to
svalues, where the keys are both concrete bit-offsets from the start of
a "base region", and "symbolic" keys (thus hopefully making unions,
casts, aliasing etc easier to deal with). So e.g. for assignments to
the fields of a struct, it records the mapping from bit-offsets of e.g.
field to the values; if that memory is cast to another type and written
to, the appropriate clobbering of the bound values can happen.
The concept of "what the current stack is" moves from the regions to
being a field within the region_model ("m_current_frame").
Bugs fixed by this patch
************************
PR analyzer/93032 (missing leak diagnostic for zlib/contrib/minizip/mztools.c)
PR analyzer/93938 (ICE in analyzer)
PR analyzer/94011 (ICE in analyzer)
PR analyzer/94099 (ICE in analyzer)
PR analyzer/94399 (leak false positive with __attribute__((cleanup())))
PR analyzer/94458 (leak false positive)
PR analyzer/94503 (ICE on C++ return-value-optimization)
PR analyzer/94640 (leak false positive)
PR analyzer/94688 (ICE in analyzer)
PR analyzer/94689 ("arrays of functions are not meaningful" error)
PR analyzer/94839 (leak false positive)
PR analyzer/95026 (leak false positive)
PR analyzer/95042 (ICE merging const and non-const C++ object instances)
PR analyzer/95240 (leak false positive)
gcc/ChangeLog:
* Makefile.in (ANALYZER_OBJS): Add analyzer/region.o,
analyzer/region-model-impl-calls.o,
analyzer/region-model-manager.o,
analyzer/region-model-reachability.o, analyzer/store.o, and
analyzer/svalue.o.
* doc/analyzer.texi: Update for changes to analyzer
implementation.
* tristate.h (tristate::get_value): New accessor.
gcc/analyzer/ChangeLog:
* analyzer-logging.cc: Ignore "-Wformat-diag".
(logger::enter_scope): Use inc_indent in both overloads.
(logger::exit_scope): Use dec_indent.
* analyzer-logging.h (logger::inc_indent): New.
(logger::dec_indent): New.
* analyzer-selftests.cc (run_analyzer_selftests): Call
analyzer_store_cc_tests.
* analyzer-selftests.h (analyzer_store_cc_tests): New decl.
* analyzer.cc (get_stmt_location): New function.
* analyzer.h (class initial_svalue): New forward decl.
(class unaryop_svalue): New forward decl.
(class binop_svalue): New forward decl.
(class sub_svalue): New forward decl.
(class unmergeable_svalue): New forward decl.
(class placeholder_svalue): New forward decl.
(class widening_svalue): New forward decl.
(class compound_svalue): New forward decl.
(class conjured_svalue): New forward decl.
(svalue_set): New typedef.
(class map_region): Delete.
(class array_region): Delete.
(class frame_region): New forward decl.
(class function_region): New forward decl.
(class label_region): New forward decl.
(class decl_region): New forward decl.
(class element_region): New forward decl.
(class offset_region): New forward decl.
(class cast_region): New forward decl.
(class field_region): New forward decl.
(class string_region): New forward decl.
(class region_model_manager): New forward decl.
(class store_manager): New forward decl.
(class store): New forward decl.
(class call_details): New forward decl.
(struct svalue_id_merger_mapping): Delete.
(struct canonicalization): Delete.
(class function_point): New forward decl.
(class engine): New forward decl.
(dump_tree): New function decl.
(print_quoted_type): New function decl.
(readability_comparator): New function decl.
(tree_cmp): New function decl.
(class path_var): Move here from region-model.h
(bit_offset_t, bit_size_t, byte_size_t): New typedefs.
(class region_offset): New class.
(get_stmt_location): New decl.
(struct member_function_hash_traits): New struct.
(class consolidation_map): New class.
Ignore "-Wformat-diag".
* analyzer.opt (-param=analyzer-max-svalue-depth=): New param.
(-param=analyzer-max-enodes-for-full-dump=): New param.
* call-string.cc: Ignore -Wformat-diag.
* checker-path.cc: Move includes of "analyzer/call-string.h" and
"analyzer/program-point.h" to before "analyzer/region-model.h",
and also include "analyzer/store.h" before it.
(state_change_event::state_change_event): Replace "tree var" param
with "const svalue *sval". Convert "origin" param from tree to
"const svalue *".
(state_change_event::get_desc): Call get_representative_tree to
convert the var and origin from const svalue * to tree. Use
svalue::get_desc rather than %qE when describing state changes.
(checker_path::add_final_event): Use get_stmt_location.
* checker-path.h (state_change_event::state_change_event): Port
from tree to const svalue *.
(state_change_event::get_lvalue): Delete.
(state_change_event::get_dest_function): New.
(state_change_event::m_var): Replace with...
(state_change_event::m_sval): ...this.
(state_change_event::m_origin): Convert from tree to
const svalue *.
* constraint-manager.cc: Include "analyzer/call-string.h",
"analyzer/program-point.h", and "analyzer/store.h" before
"analyzer/region-model.h".
(struct bound, struct range): Move to constraint-manager.h.
(compare_constants): New function.
(range::dump): Rename to...
(range::dump_to_pp): ...this. Support NULL constants.
(range::dump): Reintroduce for dumping to stderr.
(range::constrained_to_single_element): Return result, rather than
writing to *OUT.
(range::eval_condition): New.
(range::below_lower_bound): New.
(range::above_upper_bound): New.
(equiv_class::equiv_class): Port from svalue_id to const svalue *.
(equiv_class::print): Likewise.
(equiv_class::hash): Likewise.
(equiv_class::operator==): Port from svalue_id to const svalue *.
(equiv_class::add): Port from svalue_id to const svalue *. Drop
"cm" param.
(equiv_class::del): Port from svalue_id to const svalue *.
(equiv_class::get_representative): Likewise.
(equiv_class::remap_svalue_ids): Delete.
(svalue_id_cmp_by_id): Rename to...
(svalue_cmp_by_ptr): ...this, porting from svalue_id to
const svalue *.
(equiv_class::canonicalize): Update qsort comparator.
(constraint::implied_by): New.
(constraint_manager::constraint_manager): Copy m_mgr in copy ctor.
(constraint_manager::dump_to_pp): Add "multiline" param
(constraint_manager::dump): Pass "true" for "multiline".
(constraint_manager::add_constraint): Port from svalue_id to
const svalue *. Split out second part into...
(constraint_manager::add_unknown_constraint): ...this new
function. Remove self-constraints when merging equivalence
classes.
(constraint_manager::add_constraint_internal): Remove constraints
that would be implied by the new constraint. Port from svalue_id
to const svalue *.
(constraint_manager::get_equiv_class_by_sid): Rename to...
(constraint_manager::get_equiv_class_by_svalue): ...this, porting
from svalue_id to const svalue *.
(constraint_manager::get_or_add_equiv_class): Port from svalue_id
to const svalue *.
(constraint_manager::eval_condition): Make const. Call
compare_constants and return early if it provides a known result.
(constraint_manager::get_ec_bounds): New.
(constraint_manager::eval_condition): New overloads. Make
existing one const, and use compare_constants.
(constraint_manager::purge): Convert "p" param to a template
rather that an abstract base class. Port from svalue_id to
const svalue *.
(class dead_svalue_purger): New class.
(constraint_manager::remap_svalue_ids): Delete.
(constraint_manager::on_liveness_change): New.
(equiv_class_cmp): Port from svalue_id to const svalue *.
(constraint_manager::canonicalize): Likewise. Combine with
purging of redundant equivalence classes and constraints.
(class cleaned_constraint_manager): Delete.
(class merger_fact_visitor): Make "m_cm_b" const. Add "m_merger"
field.
(merger_fact_visitor::fact): Port from svalue_id to const svalue *.
Add special case for widening.
(constraint_manager::merge): Port from svalue_id to const svalue *.
(constraint_manager::clean_merger_input): Delete.
(constraint_manager::for_each_fact): Port from svalue_id to
const svalue *.
(constraint_manager::validate): Likewise.
(selftest::test_constraint_conditions): Provide a
region_model_manager when creating region_model instances.
Add test for self-equality not creating equivalence classes.
(selftest::test_transitivity): Provide a region_model_manager when
creating region_model instances. Verify that EC-merging happens
when constraints are implied.
(selftest::test_constant_comparisons): Provide a
region_model_manager when creating region_model instances.
(selftest::test_constraint_impl): Likewise. Remove over-specified
assertions.
(selftest::test_equality): Provide a region_model_manager when
creating region_model instances.
(selftest::test_many_constants): Likewise. Provide a
program_point when testing merging.
(selftest::run_constraint_manager_tests): Move call to
test_constant_comparisons to outside the transitivity guard.
* constraint-manager.h (struct bound): Move here from
constraint-manager.cc.
(struct range): Likewise.
(struct::eval_condition): New decl.
(struct::below_lower_bound): New decl.
(struct::above_upper_bound): New decl.
(equiv_class::add): Port from svalue_id to const svalue *.
(equiv_class::del): Likewise.
(equiv_class::get_representative): Likewise.
(equiv_class::remap_svalue_ids): Drop.
(equiv_class::m_cst_sid): Convert to..
(equiv_class::m_cst_sval): ...this.
(equiv_class::m_vars): Port from svalue_id to const svalue *.
(constraint::bool implied_by): New decl.
(fact_visitor::on_fact): Port from svalue_id to const svalue *.
(constraint_manager::constraint_manager): Add mgr param.
(constraint_manager::clone): Delete.
(constraint_manager::maybe_get_constant): Delete.
(constraint_manager::get_sid_for_constant): Delete.
(constraint_manager::get_num_svalues): Delete.
(constraint_manager::dump_to_pp): Add "multiline" param.
(constraint_manager::get_equiv_class): Port from svalue_id to
const svalue *.
(constraint_manager::add_constraint): Likewise.
(constraint_manager::get_equiv_class_by_sid): Rename to...
(constraint_manager::get_equiv_class_by_svalue): ...this, porting
from svalue_id to const svalue *.
(constraint_manager::add_unknown_constraint): New decl.
(constraint_manager::get_or_add_equiv_class): Port from svalue_id
to const svalue *.
(constraint_manager::eval_condition): Likewise. Add overloads.
(constraint_manager::get_ec_bounds): New decl.
(constraint_manager::purge): Convert to template.
(constraint_manager::remap_svalue_ids): Delete.
(constraint_manager::on_liveness_change): New decl.
(constraint_manager::canonicalize): Drop param.
(constraint_manager::clean_merger_input): Delete.
(constraint_manager::m_mgr): New field.
* diagnostic-manager.cc: Move includes of
"analyzer/call-string.h" and "analyzer/program-point.h" to before
"analyzer/region-model.h", and also include "analyzer/store.h"
before it.
(saved_diagnostic::saved_diagnostic): Add "sval" param.
(diagnostic_manager::diagnostic_manager): Add engine param.
(diagnostic_manager::add_diagnostic): Add "sval" param, passing it
to saved_diagnostic ctor. Update overload to pass NULL for it.
(dedupe_winners::dedupe_winners): Add engine param.
(dedupe_winners::add): Add "eg" param. Pass m_engine to
feasible_p.
(dedupe_winner::m_engine): New field.
(diagnostic_manager::emit_saved_diagnostics): Pass engine to
dedupe_winners. Pass &eg when adding candidates. Pass svalue
rather than tree to prune_path. Use get_stmt_location to get
primary location of diagnostic.
(diagnostic_manager::emit_saved_diagnostic): Likewise.
(get_any_origin): Drop.
(state_change_event_creator::on_global_state_change): Pass NULL
const svalue * rather than NULL_TREE trees to state_change_event
ctor.
(state_change_event_creator::on_state_change): Port from tree and
svalue_id to const svalue *.
(for_each_state_change): Port from svalue_id to const svalue *.
(struct null_assignment_sm_context): New.
(diagnostic_manager::add_events_for_eedge): Add state change
events for assignment to NULL.
(diagnostic_manager::prune_path): Update param from tree to
const svalue *.
(diagnostic_manager::prune_for_sm_diagnostic): Port from tracking
by tree to by const svalue *.
* diagnostic-manager.h (saved_diagnostic::saved_diagnostic): Add sval
param.
(saved_diagnostic::m_sval): New field.
(diagnostic_manager::diagnostic_manager): Add engine param.
(diagnostic_manager::get_engine): New.
(diagnostic_manager::add_diagnostic): Add "sval" param.
(diagnostic_manager::prune_path): Likewise.
(diagnostic_manager::prune_for_sm_diagnostic): New overload.
(diagnostic_manager::m_eng): New field.
* engine.cc: Move includes of "analyzer/call-string.h" and
"analyzer/program-point.h" to before "analyzer/region-model.h",
and also include "analyzer/store.h" before it.
(impl_region_model_context::impl_region_model_context): Update for
removal of m_change field.
(impl_region_model_context::remap_svalue_ids): Delete.
(impl_region_model_context::on_svalue_leak): New.
(impl_region_model_context::on_svalue_purge): Delete.
(impl_region_model_context::on_liveness_change): New.
(impl_region_model_context::on_unknown_change): Update param
from svalue_id to const svalue *. Add is_mutable param.
(setjmp_svalue::compare_fields): Delete.
(setjmp_svalue::accept): New.
(setjmp_svalue::add_to_hash): Delete.
(setjmp_svalue::dump_to_pp): New.
(setjmp_svalue::print_details): Delete.
(impl_sm_context::impl_sm_context): Drop "change" param.
(impl_sm_context::get_fndecl_for_call): Drop "m_change".
(impl_sm_context::on_transition): Drop ATTRIBUTE_UNUSED from
"stmt" param. Drop m_change. Port from svalue_id to
const svalue *.
(impl_sm_context::warn_for_state): Drop m_change. Port from
svalue_id to const svalue *.
(impl_sm_context::get_readable_tree): Rename to...
(impl_sm_context::get_diagnostic_tree): ...this. Port from
svalue_id to const svalue *.
(impl_sm_context::is_zero_assignment): New.
(impl_sm_context::m_change): Delete field.
(leak_stmt_finder::find_stmt): Handle m_var being NULL.
(readability): Increase penalty for MEM_REF. For SSA_NAMEs,
slightly favor the underlying var over the SSA name. Heavily
penalize temporaries. Handle RESULT_DECL.
(readability_comparator): Make non-static. Consider stack depths.
(impl_region_model_context::on_state_leak): Convert from svalue_id
to const svalue *, updating for region_model changes. Use
id_equal.
(impl_region_model_context::on_inherited_svalue): Delete.
(impl_region_model_context::on_cast): Delete.
(impl_region_model_context::on_condition): Drop m_change.
(impl_region_model_context::on_phi): Likewise.
(impl_region_model_context::on_unexpected_tree_code): Handle t
being NULL.
(point_and_state::validate): Update stack checking for
region_model changes.
(eg_traits::dump_args_t::show_enode_details_p): New.
(exploded_node::exploded_node): Initialize m_num_processed_stmts.
(exploded_node::get_processed_stmt): New function.
(exploded_node::get_dot_fillcolor): Add more colors.
(exploded_node::dump_dot): Guard the printing of the point and
state with show_enode_details_p. Print the processed stmts for
this enode after the initial state.
(exploded_node::dump_to_pp): Pass true for new multiline param
of program_state::dump_to_pp.
(exploded_node::on_stmt): Drop "change" param. Log the stmt.
Set input_location. Implement __analyzer_describe. Update
implementation of __analyzer_dump and __analyzer_eval.
Remove purging of sm-state for unknown fncalls from here.
(exploded_node::on_edge): Drop "change" param.
(exploded_node::on_longjmp): Port from region_id/svalue_id to
const region */const svalue *. Call program_state::detect_leaks.
Drop state_change.
(exploded_node::detect_leaks): Update for changes to region_model.
Call program_state::detect_leaks.
(exploded_edge::exploded_edge): Drop ext_state and change params.
(exploded_edge::dump_dot): "args" is no longer used. Drop dumping
of m_change.
(exploded_graph::exploded_graph): Pass engine to
m_diagnostic_manager ctor. Use program_point::origin.
(exploded_graph::add_function_entry): Drop ctxt. Use
program_state::push_frame. Drop state_change.
(exploded_graph::get_or_create_node): Drop "change" param. Add
"enode_for_diag" param. Update dumping calls for API changes.
Pass point to can_merge_with_p. Show enode indices
within -Wanalyzer-too-complex diagnostic for hitting the per-point
limit.
(exploded_graph::add_edge): Drop "change" param. Log which nodes
are being connected. Update for changes to exploded_edge ctor.
(exploded_graph::get_per_program_point_data): New.
(exploded_graph::process_worklist): Pass point to
can_merge_with_p. Drop state_change. Update dumping call for API
change.
(exploded_graph::process_node): Drop state_change. Split the
node in-place if an sm-state-change occurs. Update
m_num_processed_stmts. Update dumping calls for API change.
(exploded_graph::log_stats): Call engine::log_stats.
(exploded_graph::dump_states_for_supernode): Update dumping
call.
(exploded_path::feasible_p): Add "eng" and "eg" params.
Rename "i" to "end_idx". Pass the manager to the region_model
ctor. Update for every processed stmt in the enode, not just the
first. Keep track of which snodes have been visited, and call
loop_replay_fixup when revisiting one.
(enode_label::get_text): Update dump call for new param.
(exploded_graph::dump_exploded_nodes): Likewise.
(exploded_graph::get_node_by_index): New.
(impl_run_checkers): Create engine instance and pass its address
to extrinsic_state ctor.
* exploded-graph.h
(impl_region_model_context::impl_region_model_context): Drop
"change" params.
(impl_region_model_context::void remap_svalue_ids): Delete.
(impl_region_model_context::on_svalue_purge): Delete.
(impl_region_model_context::on_svalue_leak): New.
(impl_region_model_context::on_liveness_change): New.
(impl_region_model_context::on_state_leak): Update signature.
(impl_region_model_context::on_inherited_svalue): Delete.
(impl_region_model_context::on_cast): Delete.
(impl_region_model_context::on_unknown_change): Update signature.
(impl_region_model_context::m_change): Delete.
(eg_traits::dump_args_t::show_enode_details_p): New.
(exploded_node::on_stmt): Drop "change" param.
(exploded_node::on_edge): Likewise.
(exploded_node::get_processed_stmt): New decl.
(exploded_node::m_num_processed_stmts): New field.
(exploded_edge::exploded_edge): Drop ext_state and change params.
(exploded_edge::m_change): Delete.
(exploded_graph::get_engine): New accessor.
(exploded_graph::get_or_create_node): Drop "change" param. Add
"enode_for_diag" param.
(exploded_graph::add_edge): Drop "change" param.
(exploded_graph::get_per_program_point_data): New decl.
(exploded_graph::get_node_by_index): New decl.
(exploded_path::feasible_p): Add "eng" and "eg" params.
* program-point.cc: Include "analyzer/store.h" before including
"analyzer/region-model.h".
(function_point::function_point): Move here from
program-point.h.
(function_point::get_function): Likewise.
(function_point::from_function_entry): Likewise.
(function_point::before_supernode): Likewise.
(function_point::next_stmt): New function.
* program-point.h (function_point::function_point): Move
implementation from here to program-point.cc.
(function_point::get_function): Likewise.
(function_point::from_function_entry): Likewise.
(function_point::before_supernode): Likewise.
(function_point::next_stmt): New decl.
(program_point::operator!=): New.
(program_point::origin): New.
(program_point::next_stmt): New.
(program_point::m_function_point): Make non-const.
* program-state.cc: Move includes of "analyzer/call-string.h" and
"analyzer/program-point.h" to before "analyzer/region-model.h",
and also include "analyzer/store.h" before it.
(extrinsic_state::get_model_manager): New.
(sm_state_map::sm_state_map): Pass in sm and sm_idx to ctor,
rather than pass the around.
(sm_state_map::clone_with_remapping): Delete.
(sm_state_map::print): Remove "sm" param in favor of "m_sm". Add
"simple" and "multiline" params and support multiline vs single
line dumping.
(sm_state_map::dump): Remove "sm" param in favor of "m_sm". Add
"simple" param.
(sm_state_map::hash): Port from svalue_id to const svalue *.
(sm_state_map::operator==): Likewise.
(sm_state_map::get_state): Likewise. Call canonicalize_svalue on
input. Handle inheritance of sm-state. Call get_default_state.
(sm_state_map::get_origin): Port from svalue_id to const svalue *.
(sm_state_map::set_state): Likewise. Pass in ext_state. Reject
attempts to set state on UNKNOWN.
(sm_state_map::impl_set_state): Port from svalue_id to
const svalue *. Pass in ext_state. Call canonicalize_svalue on
input.
(sm_state_map::purge_for_unknown_fncall): Delete.
(sm_state_map::on_svalue_leak): New.
(sm_state_map::remap_svalue_ids): Delete.
(sm_state_map::on_liveness_change): New.
(sm_state_map::on_unknown_change): Reimplement.
(sm_state_map::on_svalue_purge): Delete.
(sm_state_map::on_inherited_svalue): Delete.
(sm_state_map::on_cast): Delete.
(sm_state_map::validate): Delete.
(sm_state_map::canonicalize_svalue): New.
(program_state::program_state): Update to pass manager to
region_model's ctor. Constify num_states and pass state machine
and index to sm_state_map ctor.
(program_state::print): Update for changes to dump API.
(program_state::dump_to_pp): Ignore the summarize param. Add
"multiline" param.
(program_state::dump_to_file): Add "multiline" param.
(program_state::dump): Pass "true" for new "multiline" param.
(program_state::push_frame): New.
(program_state::on_edge): Drop "change" param. Call
program_state::detect_leaks.
(program_state::prune_for_point): Add enode_for_diag param.
Reimplement based on store class. Call detect_leaks
(program_state::remap_svalue_ids): Delete.
(program_state::get_representative_tree): Port from svalue_id to
const svalue *.
(program_state::can_merge_with_p): Add "point" param. Add early
reject for sm-differences. Drop id remapping.
(program_state::validate): Drop region model and sm_state_map
validation.
(state_change::sm_change::dump): Delete.
(state_change::sm_change::remap_svalue_ids): Delete.
(state_change::sm_change::on_svalue_purge): Delete.
(log_set_of_svalues): New.
(state_change::sm_change::validate): Delete.
(state_change::state_change): Delete.
(state_change::add_sm_change): Delete.
(state_change::affects_p): Delete.
(state_change::dump): Delete.
(state_change::remap_svalue_ids): Delete.
(state_change::on_svalue_purge): Delete.
(state_change::validate): Delete.
(selftest::assert_dump_eq): Delete.
(ASSERT_DUMP_EQ): Delete.
(selftest::test_sm_state_map): Update for changes to region_model
and sm_state_map, porting from svalue_id to const svalue *.
(selftest::test_program_state_dumping): Likewise. Drop test of
dumping, renaming to...
(selftest::test_program_state_1): ...this.
(selftest::test_program_state_dumping_2): Likewise, renaming to...
(selftest::test_program_state_2): ...this.
(selftest::test_program_state_merging): Update for changes to
region_model.
(selftest::test_program_state_merging_2): Likewise.
(selftest::analyzer_program_state_cc_tests): Update for renamed
tests.
* program-state.h (extrinsic_state::extrinsic_state): Add logger
and engine params.
(extrinsic_state::get_logger): New accessor.
(extrinsic_state::get_engine): New accessor.
(extrinsic_state::get_model_manager): New accessor.
(extrinsic_state::m_logger): New field.
(extrinsic_state::m_engine): New field.
(struct default_hash_traits<svalue_id>): Delete.
(pod_hash_traits<svalue_id>::hash): Delete.
(pod_hash_traits<svalue_id>::equal): Delete.
(pod_hash_traits<svalue_id>::mark_deleted): Delete.
(pod_hash_traits<svalue_id>::mark_empty): Delete.
(pod_hash_traits<svalue_id>::is_deleted): Delete.
(pod_hash_traits<svalue_id>::is_empty): Delete.
(sm_state_map::entry_t::entry_t): Port from svalue_id to
const svalue *.
(sm_state_map::entry_t::m_origin): Likewise.
(sm_state_map::map_t): Likewise.
(sm_state_map::sm_state_map): Add state_machine and index params.
(sm_state_map::clone_with_remapping): Delete.
(sm_state_map::print): Drop sm param; add simple and multiline
params.
(sm_state_map::dump): Drop sm param; add simple param.
(sm_state_map::get_state): Port from svalue_id to const svalue *.
Add ext_state param.
(sm_state_map::get_origin): Likewise.
(sm_state_map::set_state): Likewise.
(sm_state_map::impl_set_state): Likewise.
(sm_state_map::purge_for_unknown_fncall): Delete.
(sm_state_map::remap_svalue_ids): Delete.
(sm_state_map::on_svalue_purge): Delete.
(sm_state_map::on_svalue_leak): New.
(sm_state_map::on_liveness_change): New.
(sm_state_map::on_inherited_svalue): Delete.
(sm_state_map::on_cast): Delete.
(sm_state_map::validate): Delete.
(sm_state_map::on_unknown_change): Port from svalue_id to
const svalue *. Add is_mutable and ext_state params.
(sm_state_map::canonicalize_svalue): New.
(sm_state_map::m_sm): New field.
(sm_state_map::m_sm_idx): New field.
(program_state::operator=): Delete.
(program_state::dump_to_pp): Drop "summarize" param, adding
"simple" and "multiline".
(program_state::dump_to_file): Likewise.
(program_state::dump): Rename "summarize" to "simple".
(program_state::push_frame): New.
(program_state::get_current_function): New.
(program_state::on_edge): Drop "change" param.
(program_state::prune_for_point): Likewise. Add enode_for_diag
param.
(program_state::remap_svalue_ids): Delete.
(program_state::get_representative_tree): Port from svalue_id to
const svalue *.
(program_state::can_purge_p): Likewise. Pass ext_state to get_state.
(program_state::can_merge_with_p): Add point param.
(program_state::detect_leaks): New.
(state_change_visitor::on_state_change): Port from tree and
svalue_id to a pair of const svalue *.
(class state_change): Delete.
* region.cc: New file.
* region-model-impl-calls.cc: New file.
* region-model-manager.cc: New file.
* region-model-reachability.cc: New file.
* region-model-reachability.h: New file.
* region-model.cc: Include "analyzer/call-string.h",
"analyzer/program-point.h", and "analyzer/store.h" before
"analyzer/region-model.h". Include
"analyzer/region-model-reachability.h".
(dump_tree): Make non-static.
(dump_quoted_tree): Make non-static.
(print_quoted_type): Make non-static.
(path_var::dump): Delete.
(dump_separator): Delete.
(class impl_constraint_manager): Delete.
(svalue_id::print): Delete.
(svalue_id::dump_node_name_to_pp): Delete.
(svalue_id::validate): Delete.
(region_id::print): Delete.
(region_id::dump_node_name_to_pp): Delete.
(region_id::validate): Delete.
(region_id_set::region_id_set): Delete.
(svalue_id_set::svalue_id_set): Delete.
(svalue::operator==): Delete.
(svalue::hash): Delete.
(svalue::print): Delete.
(svalue::dump_dot_to_pp): Delete.
(svalue::remap_region_ids): Delete.
(svalue::walk_for_canonicalization): Delete.
(svalue::get_child_sid): Delete.
(svalue::maybe_get_constant): Delete.
(region_svalue::compare_fields): Delete.
(region_svalue::add_to_hash): Delete.
(region_svalue::print_details): Delete.
(region_svalue::dump_dot_to_pp): Delete.
(region_svalue::remap_region_ids): Delete.
(region_svalue::merge_values): Delete.
(region_svalue::walk_for_canonicalization): Delete.
(region_svalue::eval_condition): Delete.
(constant_svalue::compare_fields): Delete.
(constant_svalue::add_to_hash): Delete.
(constant_svalue::merge_values): Delete.
(constant_svalue::eval_condition): Move to svalue.cc.
(constant_svalue::print_details): Delete.
(constant_svalue::get_child_sid): Delete.
(unknown_svalue::compare_fields): Delete.
(unknown_svalue::add_to_hash): Delete.
(unknown_svalue::print_details): Delete.
(poison_kind_to_str): Move to svalue.cc.
(poisoned_svalue::compare_fields): Delete.
(poisoned_svalue::add_to_hash): Delete.
(poisoned_svalue::print_details): Delete.
(region_kind_to_str): Move to region.cc and reimplement.
(region::operator==): Delete.
(region::get_parent_region): Delete.
(region::set_value): Delete.
(region::become_active_view): Delete.
(region::deactivate_any_active_view): Delete.
(region::deactivate_view): Delete.
(region::get_value): Delete.
(region::get_inherited_child_sid): Delete.
(region_model::copy_region): Delete.
(region_model::copy_struct_region): Delete.
(region_model::copy_union_region): Delete.
(region_model::copy_array_region): Delete.
(region::hash): Delete.
(region::print): Delete.
(region::dump_dot_to_pp): Delete.
(region::dump_to_pp): Delete.
(region::dump_child_label): Delete.
(region::validate): Delete.
(region::remap_svalue_ids): Delete.
(region::remap_region_ids): Delete.
(region::add_view): Delete.
(region::get_view): Delete.
(region::region): Move to region.cc.
(region::add_to_hash): Delete.
(region::print_fields): Delete.
(region::non_null_p): Delete.
(primitive_region::clone): Delete.
(primitive_region::walk_for_canonicalization): Delete.
(map_region::map_region): Delete.
(map_region::compare_fields): Delete.
(map_region::print_fields): Delete.
(map_region::validate): Delete.
(map_region::dump_dot_to_pp): Delete.
(map_region::dump_child_label): Delete.
(map_region::get_or_create): Delete.
(map_region::get): Delete.
(map_region::add_to_hash): Delete.
(map_region::remap_region_ids): Delete.
(map_region::unbind): Delete.
(map_region::get_tree_for_child_region): Delete.
(map_region::get_tree_for_child_region): Delete.
(tree_cmp): Move to region.cc.
(map_region::can_merge_p): Delete.
(map_region::walk_for_canonicalization): Delete.
(map_region::get_value_by_name): Delete.
(struct_or_union_region::valid_key_p): Delete.
(struct_or_union_region::compare_fields): Delete.
(struct_region::clone): Delete.
(struct_region::compare_fields): Delete.
(union_region::clone): Delete.
(union_region::compare_fields): Delete.
(frame_region::compare_fields): Delete.
(frame_region::clone): Delete.
(frame_region::valid_key_p): Delete.
(frame_region::print_fields): Delete.
(frame_region::add_to_hash): Delete.
(globals_region::compare_fields): Delete.
(globals_region::clone): Delete.
(globals_region::valid_key_p): Delete.
(code_region::compare_fields): Delete.
(code_region::clone): Delete.
(code_region::valid_key_p): Delete.
(array_region::array_region): Delete.
(array_region::get_element): Delete.
(array_region::clone): Delete.
(array_region::compare_fields): Delete.
(array_region::print_fields): Delete.
(array_region::validate): Delete.
(array_region::dump_dot_to_pp): Delete.
(array_region::dump_child_label): Delete.
(array_region::get_or_create): Delete.
(array_region::get): Delete.
(array_region::add_to_hash): Delete.
(array_region::remap_region_ids): Delete.
(array_region::get_key_for_child_region): Delete.
(array_region::key_cmp): Delete.
(array_region::walk_for_canonicalization): Delete.
(array_region::key_from_constant): Delete.
(array_region::constant_from_key): Delete.
(function_region::compare_fields): Delete.
(function_region::clone): Delete.
(function_region::valid_key_p): Delete.
(stack_region::stack_region): Delete.
(stack_region::compare_fields): Delete.
(stack_region::clone): Delete.
(stack_region::print_fields): Delete.
(stack_region::dump_child_label): Delete.
(stack_region::validate): Delete.
(stack_region::push_frame): Delete.
(stack_region::get_current_frame_id): Delete.
(stack_region::pop_frame): Delete.
(stack_region::add_to_hash): Delete.
(stack_region::remap_region_ids): Delete.
(stack_region::can_merge_p): Delete.
(stack_region::walk_for_canonicalization): Delete.
(stack_region::get_value_by_name): Delete.
(heap_region::heap_region): Delete.
(heap_region::compare_fields): Delete.
(heap_region::clone): Delete.
(heap_region::walk_for_canonicalization): Delete.
(root_region::root_region): Delete.
(root_region::compare_fields): Delete.
(root_region::clone): Delete.
(root_region::print_fields): Delete.
(root_region::validate): Delete.
(root_region::dump_child_label): Delete.
(root_region::push_frame): Delete.
(root_region::get_current_frame_id): Delete.
(root_region::pop_frame): Delete.
(root_region::ensure_stack_region): Delete.
(root_region::get_stack_region): Delete.
(root_region::ensure_globals_region): Delete.
(root_region::get_code_region): Delete.
(root_region::ensure_code_region): Delete.
(root_region::get_globals_region): Delete.
(root_region::ensure_heap_region): Delete.
(root_region::get_heap_region): Delete.
(root_region::remap_region_ids): Delete.
(root_region::can_merge_p): Delete.
(root_region::add_to_hash): Delete.
(root_region::walk_for_canonicalization): Delete.
(root_region::get_value_by_name): Delete.
(symbolic_region::symbolic_region): Delete.
(symbolic_region::compare_fields): Delete.
(symbolic_region::clone): Delete.
(symbolic_region::walk_for_canonicalization): Delete.
(symbolic_region::print_fields): Delete.
(region_model::region_model): Add region_model_manager * param.
Reimplement in terms of store, dropping impl_constraint_manager
subclass.
(region_model::operator=): Reimplement in terms of store
(region_model::operator==): Likewise.
(region_model::hash): Likewise.
(region_model::print): Delete.
(region_model::print_svalue): Delete.
(region_model::dump_dot_to_pp): Delete.
(region_model::dump_dot_to_file): Delete.
(region_model::dump_dot): Delete.
(region_model::dump_to_pp): Replace "summarize" param with
"simple" and "multiline". Port to store-based implementation.
(region_model::dump): Replace "summarize" param with "simple" and
"multiline".
(dump_vec_of_tree): Delete.
(region_model::dump_summary_of_rep_path_vars): Delete.
(region_model::validate): Delete.
(svalue_id_cmp_by_constant_svalue_model): Delete.
(svalue_id_cmp_by_constant_svalue): Delete.
(region_model::canonicalize): Drop "ctxt" param. Reimplement in
terms of store and constraints.
(region_model::canonicalized_p): Remove NULL arg to canonicalize.
(region_model::loop_replay_fixup): New.
(poisoned_value_diagnostic::emit): Tweak wording of warnings.
(region_model::check_for_poison): Delete.
(region_model::get_gassign_result): New.
(region_model::on_assignment): Port to store-based implementation.
(region_model::on_call_pre): Delete calls to check_for_poison.
Move implementations to region-model-impl-calls.c and port to
store-based implementation.
(region_model::on_call_post): Likewise.
(class reachable_regions): Move to region-model-reachability.h/cc
and port to store-based implementation.
(region_model::handle_unrecognized_call): Port to store-based
implementation.
(region_model::get_reachable_svalues): New.
(region_model::on_setjmp): Port to store-based implementation.
(region_model::on_longjmp): Likewise.
(region_model::handle_phi): Drop is_back_edge param and the logic
using it.
(region_model::get_lvalue_1): Port from region_id to const region *.
(region_model::make_region_for_unexpected_tree_code): Delete.
(assert_compat_types): If the check fails, use internal_error to
show the types.
(region_model::get_lvalue): Port from region_id to const region *.
(region_model::get_rvalue_1): Port from svalue_id to const svalue *.
(region_model::get_rvalue): Likewise.
(region_model::get_or_create_ptr_svalue): Delete.
(region_model::get_or_create_constant_svalue): Delete.
(region_model::get_svalue_for_fndecl): Delete.
(region_model::get_region_for_fndecl): Delete.
(region_model::get_svalue_for_label): Delete.
(region_model::get_region_for_label): Delete.
(build_cast): Delete.
(region_model::maybe_cast_1): Delete.
(region_model::maybe_cast): Delete.
(region_model::get_field_region): Delete.
(region_model::get_store_value): New.
(region_model::region_exists_p): New.
(region_model::deref_rvalue): Port from svalue_id to const svalue *.
(region_model::set_value): Likewise.
(region_model::clobber_region): New.
(region_model::purge_region): New.
(region_model::zero_fill_region): New.
(region_model::mark_region_as_unknown): New.
(region_model::eval_condition): Port from svalue_id to
const svalue *.
(region_model::eval_condition_without_cm): Likewise.
(region_model::compare_initial_and_pointer): New.
(region_model::add_constraint): Port from svalue_id to
const svalue *.
(region_model::maybe_get_constant): Delete.
(region_model::get_representative_path_var): New.
(region_model::add_new_malloc_region): Delete.
(region_model::get_representative_tree): Port to const svalue *.
(region_model::get_representative_path_var): Port to
const region *.
(region_model::get_path_vars_for_svalue): Delete.
(region_model::set_to_new_unknown_value): Delete.
(region_model::update_for_phis): Don't pass is_back_edge to handle_phi.
(region_model::update_for_call_superedge): Port from svalue_id to
const svalue *.
(region_model::update_for_return_superedge): Port to store-based
implementation.
(region_model::update_for_call_summary): Replace
set_to_new_unknown_value with mark_region_as_unknown.
(region_model::get_root_region): Delete.
(region_model::get_stack_region_id): Delete.
(region_model::push_frame): Delete.
(region_model::get_current_frame_id): Delete.
(region_model::get_current_function): Delete.
(region_model::pop_frame): Delete.
(region_model::on_top_level_param): New.
(region_model::get_stack_depth): Delete.
(region_model::get_function_at_depth): Delete.
(region_model::get_globals_region_id): Delete.
(region_model::add_svalue): Delete.
(region_model::replace_svalue): Delete.
(region_model::add_region): Delete.
(region_model::get_svalue): Delete.
(region_model::get_region): Delete.
(make_region_for_type): Delete.
(region_model::add_region_for_type): Delete.
(region_model::on_top_level_param): New.
(class restrict_to_used_svalues): Delete.
(region_model::purge_unused_svalues): Delete.
(region_model::push_frame): New.
(region_model::remap_svalue_ids): Delete.
(region_model::remap_region_ids): Delete.
(region_model::purge_regions): Delete.
(region_model::get_descendents): Delete.
(region_model::delete_region_and_descendents): Delete.
(region_model::poison_any_pointers_to_bad_regions): Delete.
(region_model::can_merge_with_p): Delete.
(region_model::get_current_function): New.
(region_model::get_value_by_name): Delete.
(region_model::convert_byte_offset_to_array_index): Delete.
(region_model::pop_frame): New.
(region_model::get_or_create_mem_ref): Delete.
(region_model::get_stack_depth): New.
(region_model::get_frame_at_index): New.
(region_model::unbind_region_and_descendents): New.
(struct bad_pointer_finder): New.
(region_model::get_or_create_pointer_plus_expr): Delete.
(region_model::poison_any_pointers_to_descendents): New.
(region_model::get_or_create_view): Delete.
(region_model::can_merge_with_p): New.
(region_model::get_fndecl_for_call): Port from svalue_id to
const svalue *.
(struct append_ssa_names_cb_data): New.
(get_ssa_name_regions_for_current_frame): New.
(region_model::append_ssa_names_cb): New.
(model_merger::dump_to_pp): Add "simple" param. Drop dumping of
remappings.
(model_merger::dump): Add "simple" param to both overloads.
(model_merger::can_merge_values_p): Delete.
(model_merger::record_regions): Delete.
(model_merger::record_svalues): Delete.
(svalue_id_merger_mapping::svalue_id_merger_mapping): Delete.
(svalue_id_merger_mapping::dump_to_pp): Delete.
(svalue_id_merger_mapping::dump): Delete.
(region_model::create_region_for_heap_alloc): New.
(region_model::create_region_for_alloca): New.
(region_model::record_dynamic_extents): New.
(canonicalization::canonicalization): Delete.
(canonicalization::walk_rid): Delete.
(canonicalization::walk_sid): Delete.
(canonicalization::dump_to_pp): Delete.
(canonicalization::dump): Delete.
(inchash::add): Delete overloads for svalue_id and region_id.
(engine::log_stats): New.
(assert_condition): Add overload comparing svalues.
(assert_dump_eq): Pass "true" for multiline.
(selftest::test_dump): Update for rewrite of region_model.
(selftest::test_dump_2): Rename to...
(selftest::test_struct): ...this. Provide a region_model_manager
when creating region_model instance. Remove dump test. Add
checks for get_offset.
(selftest::test_dump_3): Rename to...
(selftest::test_array_1): ...this. Provide a region_model_manager
when creating region_model instance. Remove dump test.
(selftest::test_get_representative_tree): Port from svalue_id to
new API. Add test coverage for various expressions.
(selftest::test_unique_constants): Provide a region_model_manager
for the region_model. Add test coverage for comparing const vs
non-const.
(selftest::test_svalue_equality): Delete.
(selftest::test_region_equality): Delete.
(selftest::test_unique_unknowns): New.
(class purge_all_svalue_ids): Delete.
(class purge_one_svalue_id): Delete.
(selftest::test_purging_by_criteria): Delete.
(selftest::test_initial_svalue_folding): New.
(selftest::test_unaryop_svalue_folding): New.
(selftest::test_binop_svalue_folding): New.
(selftest::test_sub_svalue_folding): New.
(selftest::test_purge_unused_svalues): Delete.
(selftest::test_descendent_of_p): New.
(selftest::test_assignment): Provide a region_model_manager for
the region_model. Drop the dump test.
(selftest::test_compound_assignment): Likewise.
(selftest::test_stack_frames): Port to new implementation.
(selftest::test_get_representative_path_var): Likewise.
(selftest::test_canonicalization_1): Rename to...
(selftest::test_equality_1): ...this. Port to new API, and add
(selftest::test_canonicalization_2): Provide a
region_model_manager when creating region_model instances.
Remove redundant canicalization.
(selftest::test_canonicalization_3): Provide a
region_model_manager when creating region_model instances.
Remove param from calls to region_model::canonicalize.
(selftest::test_canonicalization_4): Likewise.
(selftest::assert_region_models_merge): Constify
out_merged_svalue. Port to new API.
(selftest::test_state_merging): Provide a
region_model_manager when creating region_model instances.
Provide a program_point point when merging them. Replace
set_to_new_unknown_value with usage of placeholder_svalues.
Drop get_value_by_name. Port from svalue_id to const svalue *.
Add test of heap allocation.
(selftest::test_constraint_merging): Provide a
region_model_manager when creating region_model instances.
Provide a program_point point when merging them. Eliminate use
of set_to_new_unknown_value.
(selftest::test_widening_constraints): New.
(selftest::test_iteration_1): New.
(selftest::test_malloc_constraints): Port to store-based
implementation.
(selftest::test_var): New test.
(selftest::test_array_2): New test.
(selftest::test_mem_ref): New test.
(selftest::test_POINTER_PLUS_EXPR_then_MEM_REF): New.
(selftest::test_malloc): New.
(selftest::test_alloca): New.
(selftest::analyzer_region_model_cc_tests): Update for renamings.
Call new functions.
* region-model.h (class path_var): Move to analyzer.h.
(class svalue_id): Delete.
(class region_id): Delete.
(class id_map): Delete.
(svalue_id_map): Delete.
(region_id_map): Delete.
(id_map<T>::id_map): Delete.
(id_map<T>::put): Delete.
(id_map<T>::get_dst_for_src): Delete.
(id_map<T>::get_src_for_dst): Delete.
(id_map<T>::dump_to_pp): Delete.
(id_map<T>::dump): Delete.
(id_map<T>::update): Delete.
(one_way_svalue_id_map): Delete.
(one_way_region_id_map): Delete.
(class region_id_set): Delete.
(class svalue_id_set): Delete.
(struct complexity): New.
(class visitor): New.
(enum svalue_kind): Add SK_SETJMP, SK_INITIAL, SK_UNARYOP,
SK_BINOP, SK_SUB,SK_UNMERGEABLE, SK_PLACEHOLDER, SK_WIDENING,
SK_COMPOUND, and SK_CONJURED.
(svalue::operator==): Delete.
(svalue::operator!=): Delete.
(svalue::clone): Delete.
(svalue::hash): Delete.
(svalue::dump_dot_to_pp): Delete.
(svalue::dump_to_pp): New.
(svalue::dump): New.
(svalue::get_desc): New.
(svalue::dyn_cast_initial_svalue): New.
(svalue::dyn_cast_unaryop_svalue): New.
(svalue::dyn_cast_binop_svalue): New.
(svalue::dyn_cast_sub_svalue): New.
(svalue::dyn_cast_unmergeable_svalue): New.
(svalue::dyn_cast_widening_svalue): New.
(svalue::dyn_cast_compound_svalue): New.
(svalue::dyn_cast_conjured_svalue): New.
(svalue::maybe_undo_cast): New.
(svalue::unwrap_any_unmergeable): New.
(svalue::remap_region_ids): Delete
(svalue::can_merge_p): New.
(svalue::walk_for_canonicalization): Delete
(svalue::get_complexity): New.
(svalue::get_child_sid): Delete
(svalue::accept): New.
(svalue::live_p): New.
(svalue::implicitly_live_p): New.
(svalue::svalue): Add complexity param.
(svalue::add_to_hash): Delete
(svalue::print_details): Delete
(svalue::m_complexity): New field.
(region_svalue::key_t): New struct.
(region_svalue::region_svalue): Port from region_id to
const region_id *. Add complexity.
(region_svalue::compare_fields): Delete.
(region_svalue::clone): Delete.
(region_svalue::dump_dot_to_pp): Delete.
(region_svalue::get_pointee): Port from region_id to
const region_id *.
(region_svalue::remap_region_ids): Delete.
(region_svalue::merge_values): Delete.
(region_svalue::dump_to_pp): New.
(region_svalue::accept): New.
(region_svalue::walk_for_canonicalization): Delete.
(region_svalue::eval_condition): Make params const.
(region_svalue::add_to_hash): Delete.
(region_svalue::print_details): Delete.
(region_svalue::m_rid): Replace with...
(region_svalue::m_reg): ...this.
(is_a_helper <region_svalue *>::test): Convert to...
(is_a_helper <const region_svalue *>::test): ...this.
(template <> struct default_hash_traits<region_svalue::key_t>):
New.
(constant_svalue::constant_svalue): Add complexity.
(constant_svalue::compare_fields): Delete.
(constant_svalue::clone): Delete.
(constant_svalue::add_to_hash): Delete.
(constant_svalue::dump_to_pp): New.
(constant_svalue::accept): New.
(constant_svalue::implicitly_live_p): New.
(constant_svalue::merge_values): Delete.
(constant_svalue::eval_condition): Make params const.
(constant_svalue::get_child_sid): Delete.
(constant_svalue::print_details): Delete.
(is_a_helper <constant_svalue *>::test): Convert to...
(is_a_helper <const constant_svalue *>::test): ...this.
(class unknown_svalue): Update leading comment.
(unknown_svalue::unknown_svalue): Add complexity.
(unknown_svalue::compare_fields): Delete.
(unknown_svalue::add_to_hash): Delete.
(unknown_svalue::dyn_cast_unknown_svalue): Delete.
(unknown_svalue::print_details): Delete.
(unknown_svalue::dump_to_pp): New.
(unknown_svalue::accept): New.
(poisoned_svalue::key_t): New struct.
(poisoned_svalue::poisoned_svalue): Add complexity.
(poisoned_svalue::compare_fields): Delete.
(poisoned_svalue::clone): Delete.
(poisoned_svalue::add_to_hash): Delete.
(poisoned_svalue::dump_to_pp): New.
(poisoned_svalue::accept): New.
(poisoned_svalue::print_details): Delete.
(is_a_helper <poisoned_svalue *>::test): Convert to...
(is_a_helper <const poisoned_svalue *>::test): ...this.
(template <> struct default_hash_traits<poisoned_svalue::key_t>):
New.
(setjmp_record::add_to_hash): New.
(setjmp_svalue::key_t): New struct.
(setjmp_svalue::compare_fields): Delete.
(setjmp_svalue::clone): Delete.
(setjmp_svalue::add_to_hash): Delete.
(setjmp_svalue::setjmp_svalue): Add complexity.
(setjmp_svalue::dump_to_pp): New.
(setjmp_svalue::accept): New.
(setjmp_svalue::void print_details): Delete.
(is_a_helper <const setjmp_svalue *>::test): New.
(template <> struct default_hash_traits<setjmp_svalue::key_t>): New.
(class initial_svalue : public svalue): New.
(is_a_helper <const initial_svalue *>::test): New.
(class unaryop_svalue): New.
(is_a_helper <const unaryop_svalue *>::test): New.
(template <> struct default_hash_traits<unaryop_svalue::key_t>): New.
(class binop_svalue): New.
(is_a_helper <const binop_svalue *>::test): New.
(template <> struct default_hash_traits<binop_svalue::key_t>): New.
(class sub_svalue): New.
(is_a_helper <const sub_svalue *>::test): New.
(template <> struct default_hash_traits<sub_svalue::key_t>): New.
(class unmergeable_svalue): New.
(is_a_helper <const unmergeable_svalue *>::test): New.
(class placeholder_svalue): New.
(is_a_helper <placeholder_svalue *>::test): New.
(class widening_svalue): New.
(is_a_helper <widening_svalue *>::test): New.
(template <> struct default_hash_traits<widening_svalue::key_t>): New.
(class compound_svalue): New.
(is_a_helper <compound_svalue *>::test): New.
(template <> struct default_hash_traits<compound_svalue::key_t>): New.
(class conjured_svalue): New.
(is_a_helper <conjured_svalue *>::test): New.
(template <> struct default_hash_traits<conjured_svalue::key_t>): New.
(enum region_kind): Delete RK_PRIMITIVE, RK_STRUCT, RK_UNION, and
RK_ARRAY. Add RK_LABEL, RK_DECL, RK_FIELD, RK_ELEMENT, RK_OFFSET,
RK_CAST, RK_HEAP_ALLOCATED, RK_ALLOCA, RK_STRING, and RK_UNKNOWN.
(region_kind_to_str): Delete.
(region::~region): Move implementation to region.cc.
(region::operator==): Delete.
(region::operator!=): Delete.
(region::clone): Delete.
(region::get_id): New.
(region::cmp_ids): New.
(region::dyn_cast_map_region): Delete.
(region::dyn_cast_array_region): Delete.
(region::region_id get_parent): Delete.
(region::get_parent_region): Convert to a simple accessor.
(region::void set_value): Delete.
(region::svalue_id get_value): Delete.
(region::svalue_id get_value_direct): Delete.
(region::svalue_id get_inherited_child_sid): Delete.
(region::dyn_cast_frame_region): New.
(region::dyn_cast_function_region): New.
(region::dyn_cast_decl_region): New.
(region::dyn_cast_field_region): New.
(region::dyn_cast_element_region): New.
(region::dyn_cast_offset_region): New.
(region::dyn_cast_cast_region): New.
(region::dyn_cast_string_region): New.
(region::accept): New.
(region::get_base_region): New.
(region::base_region_p): New.
(region::descendent_of_p): New.
(region::maybe_get_frame_region): New.
(region::maybe_get_decl): New.
(region::hash): Delete.
(region::rint): Delete.
(region::dump_dot_to_pp): Delete.
(region::get_desc): New.
(region::dump_to_pp): Convert to vfunc, changing signature.
(region::dump_child_label): Delete.
(region::remap_svalue_ids): Delete.
(region::remap_region_ids): Delete.
(region::dump): New.
(region::walk_for_canonicalization): Delete.
(region::non_null_p): Drop region_model param.
(region::add_view): Delete.
(region::get_view): Delete.
(region::get_active_view): Delete.
(region::is_view_p): Delete.
(region::cmp_ptrs): New.
(region::validate): Delete.
(region::get_offset): New.
(region::get_byte_size): New.
(region::get_bit_size): New.
(region::get_subregions_for_binding): New.
(region::region): Add complexity param. Convert parent from
region_id to const region *. Drop svalue_id. Drop copy ctor.
(region::symbolic_for_unknown_ptr_p): New.
(region::add_to_hash): Delete.
(region::print_fields): Delete.
(region::get_complexity): New accessor.
(region::become_active_view): Delete.
(region::deactivate_any_active_view): Delete.
(region::deactivate_view): Delete.
(region::calc_offset): New.
(region::m_parent_rid): Delete.
(region::m_sval_id): Delete.
(region::m_complexity): New.
(region::m_id): New.
(region::m_parent): New.
(region::m_view_rids): Delete.
(region::m_is_view): Delete.
(region::m_active_view_rid): Delete.
(region::m_cached_offset): New.
(is_a_helper <region *>::test): Convert to...
(is_a_helper <const region *>::test): ... this.
(class primitive_region): Delete.
(class space_region): New.
(class map_region): Delete.
(is_a_helper <map_region *>::test): Delete.
(class frame_region): Reimplement.
(template <> struct default_hash_traits<frame_region::key_t>):
New.
(class globals_region): Reimplement.
(is_a_helper <globals_region *>::test): Convert to...
(is_a_helper <const globals_region *>::test): ...this.
(class struct_or_union_region): Delete.
(is_a_helper <struct_or_union_region *>::test): Delete.
(class code_region): Reimplement.
(is_a_helper <const code_region *>::test): New.
(class struct_region): Delete.
(is_a_helper <struct_region *>::test): Delete.
(class function_region): Reimplement.
(is_a_helper <function_region *>::test): Convert to...
(is_a_helper <const function_region *>::test): ...this.
(class union_region): Delete.
(is_a_helper <union_region *>::test): Delete.
(class label_region): New.
(is_a_helper <const label_region *>::test): New.
(class scope_region): Delete.
(class stack_region): Reimplement.
(is_a_helper <stack_region *>::test): Convert to...
(is_a_helper <const stack_region *>::test): ...this.
(class heap_region): Reimplement.
(is_a_helper <heap_region *>::test): Convert to...
(is_a_helper <const heap_region *>::test): ...this.
(class root_region): Reimplement.
(is_a_helper <root_region *>::test): Convert to...
(is_a_helper <const root_region *>::test): ...this.
(class symbolic_region): Reimplement.
(is_a_helper <const symbolic_region *>::test): New.
(template <> struct default_hash_traits<symbolic_region::key_t>):
New.
(class decl_region): New.
(is_a_helper <const decl_region *>::test): New.
(class field_region): New.
(template <> struct default_hash_traits<field_region::key_t>): New.
(class array_region): Delete.
(class element_region): New.
(is_a_helper <array_region *>::test): Delete.
(is_a_helper <const element_region *>::test): New.
(template <> struct default_hash_traits<element_region::key_t>):
New.
(class offset_region): New.
(is_a_helper <const offset_region *>::test): New.
(template <> struct default_hash_traits<offset_region::key_t>):
New.
(class cast_region): New.
(is_a_helper <const cast_region *>::test): New.
(template <> struct default_hash_traits<cast_region::key_t>): New.
(class heap_allocated_region): New.
(class alloca_region): New.
(class string_region): New.
(is_a_helper <const string_region *>::test): New.
(class unknown_region): New.
(class region_model_manager): New.
(struct append_ssa_names_cb_data): New.
(class call_details): New.
(region_model::region_model): Add region_model_manager param.
(region_model::print_svalue): Delete.
(region_model::dump_dot_to_pp): Delete.
(region_model::dump_dot_to_file): Delete.
(region_model::dump_dot): Delete.
(region_model::dump_to_pp): Drop summarize param in favor of
simple and multiline.
(region_model::dump): Likewise.
(region_model::summarize_to_pp): Delete.
(region_model::summarize): Delete.
(region_model::void canonicalize): Drop ctxt param.
(region_model::void check_for_poison): Delete.
(region_model::get_gassign_result): New.
(region_model::impl_call_alloca): New.
(region_model::impl_call_analyzer_describe): New.
(region_model::impl_call_analyzer_eval): New.
(region_model::impl_call_builtin_expect): New.
(region_model::impl_call_calloc): New.
(region_model::impl_call_free): New.
(region_model::impl_call_malloc): New.
(region_model::impl_call_memset): New.
(region_model::impl_call_strlen): New.
(region_model::get_reachable_svalues): New.
(region_model::handle_phi): Drop is_back_edge param.
(region_model::region_id get_root_rid): Delete.
(region_model::root_region *get_root_region): Delete.
(region_model::region_id get_stack_region_id): Delete.
(region_model::push_frame): Convert from region_id and svalue_id
to const region * and const svalue *.
(region_model::get_current_frame_id): Replace with...
(region_model::get_current_frame): ...this.
(region_model::pop_frame): Convert from region_id to
const region *. Drop purge and stats param. Add out_result.
(region_model::function *get_function_at_depth): Delete.
(region_model::get_globals_region_id): Delete.
(region_model::add_svalue): Delete.
(region_model::replace_svalue): Delete.
(region_model::add_region): Delete.
(region_model::add_region_for_type): Delete.
(region_model::get_svalue): Delete.
(region_model::get_region): Delete.
(region_model::get_lvalue): Convert from region_id to
const region *.
(region_model::get_rvalue): Convert from svalue_id to
const svalue *.
(region_model::get_or_create_ptr_svalue): Delete.
(region_model::get_or_create_constant_svalue): Delete.
(region_model::get_svalue_for_fndecl): Delete.
(region_model::get_svalue_for_label): Delete.
(region_model::get_region_for_fndecl): Delete.
(region_model::get_region_for_label): Delete.
(region_model::get_frame_at_index (int index) const;): New.
(region_model::maybe_cast): Delete.
(region_model::maybe_cast_1): Delete.
(region_model::get_field_region): Delete.
(region_model::id deref_rvalue): Convert from region_id and
svalue_id to const region * and const svalue *. Drop overload,
passing in both a tree and an svalue.
(region_model::set_value): Convert from region_id and svalue_id to
const region * and const svalue *.
(region_model::set_to_new_unknown_value): Delete.
(region_model::clobber_region (const region *reg);): New.
(region_model::purge_region (const region *reg);): New.
(region_model::zero_fill_region (const region *reg);): New.
(region_model::mark_region_as_unknown (const region *reg);): New.
(region_model::copy_region): Convert from region_id to
const region *.
(region_model::eval_condition): Convert from svalue_id to
const svalue *.
(region_model::eval_condition_without_cm): Likewise.
(region_model::compare_initial_and_pointer): New.
(region_model:maybe_get_constant): Delete.
(region_model::add_new_malloc_region): Delete.
(region_model::get_representative_tree): Convert from svalue_id to
const svalue *.
(region_model::get_representative_path_var): Delete decl taking a
region_id in favor of two decls, for svalue vs region, with an
svalue_set to ensure termination.
(region_model::get_path_vars_for_svalue): Delete.
(region_model::create_region_for_heap_alloc): New.
(region_model::create_region_for_alloca): New.
(region_model::purge_unused_svalues): Delete.
(region_model::remap_svalue_ids): Delete.
(region_model::remap_region_ids): Delete.
(region_model::purge_regions): Delete.
(region_model::get_num_svalues): Delete.
(region_model::get_num_regions): Delete.
(region_model::get_descendents): Delete.
(region_model::get_store): New.
(region_model::delete_region_and_descendents): Delete.
(region_model::get_manager): New.
(region_model::unbind_region_and_descendents): New.
(region_model::can_merge_with_p): Add point param. Drop
svalue_id_merger_mapping.
(region_model::get_value_by_name): Delete.
(region_model::convert_byte_offset_to_array_index): Delete.
(region_model::get_or_create_mem_ref): Delete.
(region_model::get_or_create_pointer_plus_expr): Delete.
(region_model::get_or_create_view): Delete.
(region_model::get_lvalue_1): Convert from region_id to
const region *.
(region_model::get_rvalue_1): Convert from svalue_id to
const svalue *.
(region_model::get_ssa_name_regions_for_current_frame): New.
(region_model::append_ssa_names_cb): New.
(region_model::get_store_value): New.
(region_model::copy_struct_region): Delete.
(region_model::copy_union_region): Delete.
(region_model::copy_array_region): Delete.
(region_model::region_exists_p): New.
(region_model::make_region_for_unexpected_tree_code): Delete.
(region_model::loop_replay_fixup): New.
(region_model::poison_any_pointers_to_bad_regions): Delete.
(region_model::poison_any_pointers_to_descendents): New.
(region_model::dump_summary_of_rep_path_vars): Delete.
(region_model::on_top_level_param): New.
(region_model::record_dynamic_extents): New.
(region_model::m_mgr;): New.
(region_model::m_store;): New.
(region_model::m_svalues;): Delete.
(region_model::m_regions;): Delete.
(region_model::m_root_rid;): Delete.
(region_model::m_current_frame;): New.
(region_model_context::remap_svalue_ids): Delete.
(region_model_context::can_purge_p): Delete.
(region_model_context::on_svalue_leak): New.
(region_model_context::on_svalue_purge): Delete.
(region_model_context::on_liveness_change): New.
(region_model_context::on_inherited_svalue): Delete.
(region_model_context::on_cast): Delete.
(region_model_context::on_unknown_change): Convert from svalue_id to
const svalue * and add is_mutable.
(class noop_region_model_context): Update for region_model_context
changes.
(model_merger::model_merger): Add program_point. Drop
svalue_id_merger_mapping.
(model_merger::dump_to_pp): Add "simple" param.
(model_merger::dump): Likewise.
(model_merger::get_region_a): Delete.
(model_merger::get_region_b): Delete.
(model_merger::can_merge_values_p): Delete.
(model_merger::record_regions): Delete.
(model_merger::record_svalues): Delete.
(model_merger::m_point): New field.
(model_merger::m_map_regions_from_a_to_m): Delete.
(model_merger::m_map_regions_from_b_to_m): Delete.
(model_merger::m_sid_mapping): Delete.
(struct svalue_id_merger_mapping): Delete.
(class engine): New.
(struct canonicalization): Delete.
(inchash::add): Delete decls for hashing svalue_id and region_id.
(test_region_model_context::on_unexpected_tree_code): Require t to
be non-NULL.
(selftest::assert_condition): Add overload comparing a pair of
const svalue *.
* sm-file.cc: Include "tristate.h", "selftest.h",
"analyzer/call-string.h", "analyzer/program-point.h",
"analyzer/store.h", and "analyzer/region-model.h".
(fileptr_state_machine::get_default_state): New.
(fileptr_state_machine::on_stmt): Remove calls to
get_readable_tree in favor of get_diagnostic_tree.
* sm-malloc.cc: Include "tristate.h", "selftest.h",
"analyzer/call-string.h", "analyzer/program-point.h",
"analyzer/store.h", and "analyzer/region-model.h".
(malloc_state_machine::get_default_state): New.
(malloc_state_machine::reset_when_passed_to_unknown_fn_p): New.
(malloc_diagnostic::describe_state_change): Handle change.m_expr
being NULL.
(null_arg::emit): Avoid printing "NULL '0'".
(null_arg::describe_final_event): Avoid printing "(0) NULL".
(malloc_leak::emit): Handle m_arg being NULL.
(malloc_leak::describe_final_event): Handle ev.m_expr being NULL.
(malloc_state_machine::on_stmt): Don't call get_readable_tree.
Call get_diagnostic_tree when creating pending diagnostics.
Update for is_zero_assignment becoming a member function of
sm_ctxt.
Don't transition to m_non_heap for ADDR_EXPR(MEM_REF()).
(malloc_state_machine::reset_when_passed_to_unknown_fn_p): New
vfunc implementation.
* sm-sensitive.cc (sensitive_state_machine::warn_for_any_exposure): Call
get_diagnostic_tree and pass the result to warn_for_state.
* sm-signal.cc: Move includes of "analyzer/call-string.h" and
"analyzer/program-point.h" to before "analyzer/region-model.h",
and also include "analyzer/store.h" before it.
(signal_unsafe_call::describe_state_change): Use
get_dest_function to get handler.
(update_model_for_signal_handler): Pass manager to region_model
ctor.
(register_signal_handler::impl_transition): Update for changes to
get_or_create_node and add_edge.
* sm-taint.cc (taint_state_machine::on_stmt): Remove calls to
get_readable_tree, replacing them when calling warn_for_state with
calls to get_diagnostic_tree.
* sm.cc (is_zero_assignment): Delete.
(any_pointer_p): Move to within namespace ana.
* sm.h (is_zero_assignment): Remove decl.
(any_pointer_p): Move decl to within namespace ana.
(state_machine::get_default_state): New vfunc.
(state_machine::reset_when_passed_to_unknown_fn_p): New vfunc.
(sm_context::get_readable_tree): Rename to...
(sm_context::get_diagnostic_tree): ...this.
(sm_context::is_zero_assignment): New vfunc.
* store.cc: New file.
* store.h: New file.
* svalue.cc: New file.
gcc/testsuite/ChangeLog:
PR analyzer/93032
PR analyzer/93938
PR analyzer/94011
PR analyzer/94099
PR analyzer/94399
PR analyzer/94458
PR analyzer/94503
PR analyzer/94640
PR analyzer/94688
PR analyzer/94689
PR analyzer/94839
PR analyzer/95026
PR analyzer/95042
PR analyzer/95240
* g++.dg/analyzer/pr93212.C: Add dg-warning for dangling
reference.
* g++.dg/analyzer/pr93950.C: Remove xfail.
* g++.dg/analyzer/pr94011.C: New test.
* g++.dg/analyzer/pr94028.C: Remove leak false positives; mark as
failing on C++98.
* g++.dg/analyzer/pr94503.C: New test.
* g++.dg/analyzer/pr95042.C: New test.
* gcc.dg/analyzer/CVE-2005-1689-dedupe-issue-2.c: New test.
* gcc.dg/analyzer/CVE-2005-1689-dedupe-issue.c: Add xfail.
* gcc.dg/analyzer/CVE-2005-1689-minimal.c:
Include "analyzer-decls.h".
(test_4, test_5, test_6, test_7, test_8): New tests.
* gcc.dg/analyzer/abs-1.c: New test.
* gcc.dg/analyzer/aliasing-1.c: New test.
* gcc.dg/analyzer/aliasing-2.c: New test.
* gcc.dg/analyzer/analyzer-decls.h (__analyzer_describe): New
decl.
(__analyzer_dump_num_heap_regions): Remove.
* gcc.dg/analyzer/attribute-nonnull.c: Add dg-warnings for cases
where NULL is directly used as an argument.
* gcc.dg/analyzer/bzero-1.c: New test.
* gcc.dg/analyzer/casts-1.c: New test.
* gcc.dg/analyzer/casts-2.c: New test.
* gcc.dg/analyzer/compound-assignment-1.c
(test_4): Remove xfail from leak false positive.
(called_by_test_5a): Add "allocated here" expected message.
(called_by_test_5b): Make expected leak message more precise.
* gcc.dg/analyzer/compound-assignment-3.c: Update expected leak
message.
* gcc.dg/analyzer/compound-assignment-4.c: New test.
* gcc.dg/analyzer/compound-assignment-5.c: New test.
* gcc.dg/analyzer/conditionals-notrans.c: Remove xfails.
* gcc.dg/analyzer/data-model-1.c (test_12d): Update expected
results.
(test_13): Remove xfail.
(test_14): Remove xfail.
(test_15): Remove xfail.
(test_16): Remove xfails. Add out-of-bounds access.
(test_16_alt): Remove xfails.
(test_23): Remove xfail.
(test_24): Remove xfail.
(test_25): Remove xfail.
(test_26): Update expected result. Remove xfail. Add xfail.
(test_27): Remove xfails.
(test_29): Add __analyzer_eval pointer comparisons.
(test_41): Generalize expected output for u.ptr comparison with
NULL for targets where this could be known to be false.
(test_42): Remove xfail.
(test_51): Remove xfails.
* gcc.dg/analyzer/data-model-13.c: Update for improvements to
source location and wording of leak message.
* gcc.dg/analyzer/data-model-14.c: Remove -fanalyzer-fine-grained.
(test_1): Update for improvement to expected message.
(test_2): Remove xfail.
* gcc.dg/analyzer/data-model-18.c: Remove xfail.
* gcc.dg/analyzer/data-model-20.c: New test.
* gcc.dg/analyzer/data-model-5.c: Add dg-warning for deref of
NULL. Add xfailing false leak.
* gcc.dg/analyzer/data-model-5b.c: Add xfailing false leak.
* gcc.dg/analyzer/data-model-5c.c: Update xfailing false leak.
* gcc.dg/analyzer/data-model-5d.c: Reimplement.
* gcc.dg/analyzer/data-model-6.c: Delete test.
* gcc.dg/analyzer/data-model-8.c: Remove xfail.
* gcc.dg/analyzer/describe-1.c: New test.
* gcc.dg/analyzer/dot-output.c: Remove xfail.
* gcc.dg/analyzer/explode-1.c: Add expected leak warning.
* gcc.dg/analyzer/explode-2.c: Add expected leak warnings. Mark
double-free warnings as xfail for now.
* gcc.dg/analyzer/feasibility-1.c: New test.
* gcc.dg/analyzer/first-field-1.c: New test.
* gcc.dg/analyzer/first-field-2.c: New test.
* gcc.dg/analyzer/init.c: New test.
* gcc.dg/analyzer/leak-2.c: New test.
* gcc.dg/analyzer/loop-0-up-to-n-by-1-with-iter-obj.c: New test.
* gcc.dg/analyzer/loop-0-up-to-n-by-1.c: New test.
* gcc.dg/analyzer/loop-2a.c: Update expected behavior.
* gcc.dg/analyzer/loop-3.c: Mark use-after-free as xfail. Add
expected warning about deref of unchecked pointer.
* gcc.dg/analyzer/loop-4.c: Remove -fno-analyzer-state-purge.
Update expected behavior.
* gcc.dg/analyzer/loop-n-down-to-1-by-1.c: New test.
* gcc.dg/analyzer/loop-start-down-to-end-by-1.c: New test.
* gcc.dg/analyzer/loop-start-down-to-end-by-step.c: New test.
* gcc.dg/analyzer/loop-start-to-end-by-step.c: New test.
* gcc.dg/analyzer/loop-start-up-to-end-by-1.c: New test.
* gcc.dg/analyzer/loop.c: Remove -fno-analyzer-state-purge.
Update expected behavior.
* gcc.dg/analyzer/malloc-1.c: Remove xfails from leak false
positives. Update expected wording of global_link.m_ptr leak.
(test_49): New test.
* gcc.dg/analyzer/malloc-4.c: Remove leak false positive. Update
expected wording of leak warning.
* gcc.dg/analyzer/malloc-in-loop.c: New test.
* gcc.dg/analyzer/malloc-ipa-8-double-free.c: Update expected path
to show call to wrapped_malloc.
* gcc.dg/analyzer/malloc-ipa-8-unchecked.c: Remove
-fanalyzer-verbose-state-changes.
* gcc.dg/analyzer/malloc-paths-9.c: Remove comment about duplicate
warnings. Remove duplicate use-after-free paths.
* gcc.dg/analyzer/malloc-vs-local-1a.c: Add dg-warning for deref
of unchecked pointer. Update expected number of enodes.
* gcc.dg/analyzer/malloc-vs-local-2.c: Likewise.
* gcc.dg/analyzer/malloc-vs-local-3.c: Add dg-warning for deref of
unchecked pointer. Update expected number of enodes. Avoid
overspecifying the leak message.
* gcc.dg/analyzer/memset-1.c: New test.
* gcc.dg/analyzer/paths-3.c: Update expected number of enodes.
* gcc.dg/analyzer/paths-4.c: Likewise.
* gcc.dg/analyzer/paths-6.c: Likewise.
* gcc.dg/analyzer/paths-7.c: Likewise.
* gcc.dg/analyzer/pr93032-mztools-simplified.c: New test.
* gcc.dg/analyzer/pr93032-mztools.c: New test.
* gcc.dg/analyzer/pr93382.c: Mark taint tests as failing.
* gcc.dg/analyzer/pr93938.c: New test.
* gcc.dg/analyzer/pr94099.c: Replace uninit dg-warning with
dg-warning for NULL dereference.
* gcc.dg/analyzer/pr94399.c: New test.
* gcc.dg/analyzer/pr94447.c: Add dg-warning for NULL dereference.
* gcc.dg/analyzer/pr94458.c: New test.
* gcc.dg/analyzer/pr94640.c: New test.
* gcc.dg/analyzer/pr94688.c: New test.
* gcc.dg/analyzer/pr94689.c: New test.
* gcc.dg/analyzer/pr94839.c: New test.
* gcc.dg/analyzer/pr95026.c: New test.
* gcc.dg/analyzer/pr95240.c: New test.
* gcc.dg/analyzer/refcounting-1.c: New test.
* gcc.dg/analyzer/single-field.c: New test.
* gcc.dg/analyzer/stale-frame-1.c: New test.
* gcc.dg/analyzer/symbolic-1.c: New test.
* gcc.dg/analyzer/symbolic-2.c: New test.
* gcc.dg/analyzer/symbolic-3.c: New test.
* gcc.dg/analyzer/symbolic-4.c: New test.
* gcc.dg/analyzer/symbolic-5.c: New test.
* gcc.dg/analyzer/symbolic-6.c: New test.
* gcc.dg/analyzer/taint-1.c: Mark the "gets unchecked value"
events as failing for now. Update dg-message directives to avoid
relying on numbering.
* gcc.dg/analyzer/torture/loop-inc-ptr-1.c: New test.
* gcc.dg/analyzer/torture/loop-inc-ptr-2.c: New test.
* gcc.dg/analyzer/torture/loop-inc-ptr-3.c: New test.
* gcc.dg/analyzer/unknown-fns-2.c: New test.
* gcc.dg/analyzer/unknown-fns-3.c: New test.
* gcc.dg/analyzer/unknown-fns-4.c: New test.
* gcc.dg/analyzer/unknown-fns.c: Update dg-warning to reflect fixed
source location for leak diagnostic.
* gcc.dg/analyzer/use-after-free.c: New test.
* gcc.dg/analyzer/vla-1.c: New test.
* gcc.dg/analyzer/zlib-4.c: Rewrite to avoid "exit" calls. Add
expected leak warnings.
* gfortran.dg/analyzer/pr93993.f90: Remove leak of tm warning,
which seems to have been a false positive.
|
|
From what I can tell -Wanalyzer-use-of-uninitialized-value has not
yet found a true diagnostic in real-world code, and seems to be
particularly susceptible to false positives. These relate to bugs in
the region_model code.
For GCC 10 it seems best to remove this warning, which this patch does.
Internally it also removes POISON_KIND_UNINIT.
I'm working on a rewrite of the region_model code for GCC 11 that I
hope will fix these issues, and allow this warning to be reintroduced.
gcc/analyzer/ChangeLog:
PR analyzer/94447
PR analyzer/94639
PR analyzer/94732
PR analyzer/94754
* analyzer.opt (Wanalyzer-use-of-uninitialized-value): Delete.
* program-state.cc (selftest::test_program_state_dumping): Update
expected dump result for removal of "uninit".
* region-model.cc (poison_kind_to_str): Delete POISON_KIND_UNINIT
case.
(root_region::ensure_stack_region): Initialize stack with null
svalue_id rather than with a typeless POISON_KIND_UNINIT value.
(root_region::ensure_heap_region): Likewise for the heap.
(region_model::dump_summary_of_rep_path_vars): Remove
summarization of uninit values.
(region_model::validate): Remove check that the stack has a
POISON_KIND_UNINIT value.
(poisoned_value_diagnostic::emit): Remove POISON_KIND_UNINIT
case.
(poisoned_value_diagnostic::describe_final_event): Likewise.
(selftest::test_dump): Update expected dump result for removal of
"uninit".
(selftest::test_svalue_equality): Remove "uninit" and "freed".
* region-model.h (enum poison_kind): Remove POISON_KIND_UNINIT.
gcc/ChangeLog:
PR analyzer/94447
PR analyzer/94639
PR analyzer/94732
PR analyzer/94754
* doc/invoke.texi (Static Analyzer Options): Remove
-Wanalyzer-use-of-uninitialized-value.
(-Wno-analyzer-use-of-uninitialized-value): Remove item.
gcc/testsuite/ChangeLog:
PR analyzer/94447
PR analyzer/94639
PR analyzer/94732
PR analyzer/94754
* gcc.dg/analyzer/data-model-1.c: Mark "use of uninitialized
value" warnings as xfail for now.
* gcc.dg/analyzer/data-model-5b.c: Remove uninitialized warning.
* gcc.dg/analyzer/pr94099.c: Mark "uninitialized" warning as xfail
for now.
* gcc.dg/analyzer/pr94447.c: New test.
* gcc.dg/analyzer/pr94639.c: New test.
* gcc.dg/analyzer/pr94732.c: New test.
* gcc.dg/analyzer/pr94754.c: New test.
* gcc.dg/analyzer/zlib-6.c: Mark "uninitialized" warning as xfail
for now.
|
|
PR analyzer/94378 reports a false -Wanalyzer-malloc-leak
when returning a struct containing a malloc-ed pointer.
The issue is that the assignment code was not handling
compound copies, only copying top-level values from region to region,
and not copying child values.
This patch introduces a region_model::copy_region function, using
it for assignments and when analyzing function return values.
It recursively copies nested values within structs, unions, and
arrays, fixing the bug.
gcc/analyzer/ChangeLog:
PR analyzer/94378
* checker-path.cc: Include "bitmap.h".
* constraint-manager.cc: Likewise.
* diagnostic-manager.cc: Likewise.
* engine.cc: Likewise.
(exploded_node::detect_leaks): Pass null region_id to pop_frame.
* program-point.cc: Include "bitmap.h".
* program-state.cc: Likewise.
* region-model.cc (id_set<region_id>::id_set): Convert to...
(region_id_set::region_id_set): ...this.
(svalue_id_set::svalue_id_set): New ctor.
(region_model::copy_region): New function.
(region_model::copy_struct_region): New function.
(region_model::copy_union_region): New function.
(region_model::copy_array_region): New function.
(stack_region::pop_frame): Drop return value. Add
"result_dst_rid" param; if it is non-null, use copy_region to copy
the result to it. Rather than capture and pass a single "known
used" return value to be used by purge_unused_values, instead
gather and pass a set of known used return values.
(root_region::pop_frame): Drop return value. Add "result_dst_rid"
param.
(region_model::on_assignment): Use copy_region.
(region_model::on_return): Likewise for the result.
(region_model::on_longjmp): Pass null for pop_frame's
result_dst_rid.
(region_model::update_for_return_superedge): Pass the region for the
return value of the call, if any, to pop_frame, rather than setting
the lvalue for the lhs of the result.
(region_model::pop_frame): Drop return value. Add
"result_dst_rid" param.
(region_model::purge_unused_svalues): Convert third param from an
svalue_id * to an svalue_id_set *, updating the initial populating
of the "used" bitmap accordingly. Don't remap it when done.
(struct selftest::coord_test): New selftest fixture, extracted from...
(selftest::test_dump_2): ...here.
(selftest::test_compound_assignment): New selftest.
(selftest::test_stack_frames): Pass null to new param of pop_frame.
(selftest::analyzer_region_model_cc_tests): Call the new selftest.
* region-model.h (class id_set): Delete template.
(class region_id_set): Reimplement, using old id_set implementation.
(class svalue_id_set): Likewise. Convert from auto_sbitmap to
auto_bitmap.
(region::get_active_view): New accessor.
(stack_region::pop_frame): Drop return value. Add
"result_dst_rid" param.
(root_region::pop_frame): Likewise.
(region_model::pop_frame): Likewise.
(region_model::copy_region): New decl.
(region_model::purge_unused_svalues): Convert third param from an
svalue_id * to an svalue_id_set *.
(region_model::copy_struct_region): New decl.
(region_model::copy_union_region): New decl.
(region_model::copy_array_region): New decl.
gcc/testsuite/ChangeLog:
PR analyzer/94378
* gcc.dg/analyzer/compound-assignment-1.c: New test.
* gcc.dg/analyzer/compound-assignment-2.c: New test.
* gcc.dg/analyzer/compound-assignment-3.c: New test.
|
|
Fixes to exploded_path::feasible_p exposed a pre-existing bug
with pointer NULL-ness for pointers to symbolic_region.
symbolic_region has an "m_possibly_null" flag which if set means
that a region_svalue pointing to that region is treated as possibly
NULL. Adding a constraint of "!= NULL" on an edge records that
the pointer is non-NULL, but doesn't affect other pointers (e.g.
if the first if a void *, but the other pointers are cast to other
pointer types). This showed up in the tests
gcc.dg/analyzer/data-model-5b.c and -5c.c, which malloc a buffer
and test for NULL, but then cast that to a struct * and later test
that struct *: a path for the first test being non-NULL and the
second being NULL was erroneously found to be feasible.
This patch clears the m_possibly_null flag when a "!= NULL" constraint
is added, fixing that erroneous path (but not yet fixing the false
positive in the above tests, which seems to go on to hit a different
issue). It also adds the field to dumps.
gcc/analyzer/ChangeLog:
* program-state.cc (selftest::test_program_state_dumping): Update
expected dump to include symbolic_region's possibly_null field.
* region-model.cc (symbolic_region::print_fields): New vfunc
implementation.
(region_model::add_constraint): Clear m_possibly_null from
symbolic_regions now known to be non-NULL.
(selftest::test_malloc_constraints): New selftest.
(selftest::analyzer_region_model_cc_tests): Call it.
* region-model.h (region::dyn_cast_symbolic_region): Add non-const
overload.
(symbolic_region::dyn_cast_symbolic_region): Implement it.
(symbolic_region::print_fields): New vfunc override decl.
gcc/testsuite/ChangeLog:
* gcc.dg/analyzer/data-model-5b.c: Add xfail for new false
positive leak.
* gcc.dg/analyzer/data-model-5c.c: Likewise.
* gcc.dg/analyzer/malloc-5.c: New test.
|
|
This patch extends region_model::get_representative_tree so that dumps
are able to refer to string literals, which I've found useful in
investigating a state-bloat issue.
Doing so uncovered a bug in the handling of views I introduced in
r10-7024-ge516294a1acb28aaaad44cfd583cc6a80354044e where the code was
erroneously using TREE_TYPE on the view region's type, rather than just
using its type, which the patch also fixes.
gcc/analyzer/ChangeLog:
* analyzer.h (class array_region): New forward decl.
* program-state.cc (selftest::test_program_state_dumping_2): New.
(selftest::analyzer_program_state_cc_tests): Call it.
* region-model.cc (array_region::constant_from_key): New.
(region_model::get_representative_tree): Handle region_svalue by
generating an ADDR_EXPR.
(region_model::get_representative_path_var): In view handling,
remove erroneous TREE_TYPE when determining the type of the tree.
Handle array regions and STRING_CST.
(selftest::assert_dump_tree_eq): New.
(ASSERT_DUMP_TREE_EQ): New macro.
(selftest::test_get_representative_tree): New selftest.
(selftest::analyzer_region_model_cc_tests): Call it.
* region-model.h (region::dyn_cast_array_region): New vfunc.
(array_region::dyn_cast_array_region): New vfunc implementation.
(array_region::constant_from_key): New decl.
gcc/testsuite/ChangeLog:
* gcc.dg/analyzer/malloc-4.c: Update expected output of leak to
reflect fix to region_model::get_representative_path_var, adding
the missing "*" from the cast.
|
|
This patch fixes a bug in which summarized state dumps involving a
non-NULL pointer to a region for which get_representative_path_var
returned NULL were erroneously dumped as "NULL".
It also extends sm-state dumps so that they show representative tree
values, where available.
Finally, it adds some selftest coverage for such dumps. Doing so
requires replacing some %qE with a dump_quoted_tree, to avoid
C vs C++ differences between "make selftest-c" and "make selftest-c++".
gcc/analyzer/ChangeLog:
* analyzer.h (dump_quoted_tree): New decl.
* engine.cc (exploded_node::dump_dot): Pass region model to
sm_state_map::print.
* program-state.cc: Include diagnostic-core.h.
(sm_state_map::print): Add "model" param and use it to print
representative trees. Only print origin information if non-null.
(sm_state_map::dump): Pass NULL for model to print call.
(program_state::print): Pass region model to sm_state_map::print.
(program_state::dump_to_pp): Use spaces rather than newlines when
summarizing. Pass region_model to sm_state_map::print.
(ana::selftest::assert_dump_eq): New function.
(ASSERT_DUMP_EQ): New macro.
(ana::selftest::test_program_state_dumping): New function.
(ana::selftest::analyzer_program_state_cc_tests): Call it.
* program-state.h (program_state::print): Add model param.
* region-model.cc (dump_quoted_tree): New function.
(map_region::print_fields): Use dump_quoted_tree rather than
%qE to avoid lang-dependent output.
(map_region::dump_child_label): Likewise.
(region_model::dump_summary_of_map): For SK_REGION, when
get_representative_path_var fails, print the region id rather than
erroneously printing NULL.
* sm.cc (state_machine::get_state_by_name): New function.
* sm.h (state_machine::get_state_by_name): New decl.
|
|
PR analyzer/93778 reports an ICE with -fanalyzer on a gfortran test case
at this gimple stmt:
_gfortran_st_set_nml_var (&dt_parm.0, &ro.xi.jq, &"ro%xi%jq"[1]{lb: 1 sz: 1}, 4, 0, D.3913);
where ro.xi.jq is a COMPONENT_REF, but ro.xi is of type "struct bl[3]".
The analyzer's handling of COMPONENT_REF assumes that the type of the
1st argument is a RECORD_TYPE or UNION_TYPE, whereas in this case it's
an ARRAY_TYPE, leading to a failed as_a inside
region_model::get_field_region.
This patch fixes the ICE by generalizing the "give up on this tree code"
logic from r10-6667-gf76a88ebf089871dcce215aa0cb1956ccc060895 for
PR analyzer/93388, so that the analyzer gives up when it needs to get an
lvalue for a COMPONENT_REF on something other than a RECORD_TYPE or
UNION_TYPE.
gcc/analyzer/ChangeLog:
PR analyzer/93778
* engine.cc (impl_region_model_context::on_unknown_tree_code):
Rename to...
(impl_region_model_context::on_unexpected_tree_code): ...this and
convert first argument from path_var to tree.
(exploded_node::on_stmt): Pass ctxt to purge_for_unknown_fncall.
* exploded-graph.h (region_model_context::on_unknown_tree_code):
Rename to...
(region_model_context::on_unexpected_tree_code): ...this and
convert first argument from path_var to tree.
* program-state.cc (sm_state_map::purge_for_unknown_fncall): Add
ctxt param and pass on to calls to get_rvalue.
* program-state.h (sm_state_map::purge_for_unknown_fncall): Add
ctxt param.
* region-model.cc (region_model::handle_unrecognized_call): Pass
ctxt on to call to get_rvalue.
(region_model::get_lvalue_1): Move body of default case to
region_model::make_region_for_unexpected_tree_code and call it.
Within COMPONENT_REF case, reject attempts to handle types other
than RECORD_TYPE and UNION_TYPE.
(region_model::make_region_for_unexpected_tree_code): New
function, based on default case of region_model::get_lvalue_1.
* region-model.h
(region_model::make_region_for_unexpected_tree_code): New decl.
(region_model::on_unknown_tree_code): Rename to...
(region_model::on_unexpected_tree_code): ...this and convert first
argument from path_var to tree.
(class test_region_model_context): Update vfunc implementation for
above change.
gcc/testsuite/ChangeLog:
PR analyzer/93778
* gfortran.dg/analyzer/pr93778.f90: New test.
|
|
There have been various ICEs with -fanalyzer involving unhandled tree
codes in region_model::get_lvalue_1; PR analyzer/93388 reports various
others e.g. for IMAGPART_EXPR, REALPART_EXPR, and VIEW_CONVERT_EXPR seen
when running the testsuite with -fanalyzer forcibly enabled.
Whilst we could implement lvalue-handling in the region model for every
tree code, for some of these we're straying far from my primary goal for
GCC 10 of implementing a double-free checker for C.
This patch implements a fallback for unimplemented tree codes: create a
dummy region, but mark the new state as being invalid, and stop
exploring state along this path. It also implements VIEW_CONVERT_EXPR.
Doing so fixes the ICEs, whilst effectively turning off the analyzer
along code paths that use such tree codes. Hopefully this compromise
is sensible for GCC 10.
gcc/analyzer/ChangeLog:
PR analyzer/93388
* engine.cc (impl_region_model_context::on_unknown_tree_code):
New.
(exploded_graph::get_or_create_node): Reject invalid states.
* exploded-graph.h
(impl_region_model_context::on_unknown_tree_code): New decl.
(point_and_state::point_and_state): Assert that the state is
valid.
* program-state.cc (program_state::program_state): Initialize
m_valid to true.
(program_state::operator=): Copy m_valid.
(program_state::program_state): Likewise for move constructor.
(program_state::print): Print m_valid.
(program_state::dump_to_pp): Likewise.
* program-state.h (program_state::m_valid): New field.
* region-model.cc (region_model::get_lvalue_1): Implement the
default case by returning a new symbolic region and calling
the context's on_unknown_tree_code, rather than issuing an
internal_error. Implement VIEW_CONVERT_EXPR.
* region-model.h (region_model_context::on_unknown_tree_code): New
vfunc.
(test_region_model_context::on_unknown_tree_code): New.
gcc/testsuite/ChangeLog:
PR analyzer/93388
* gcc.dg/analyzer/torture/20060625-1.c: New test.
* gcc.dg/analyzer/torture/pr51628-30.c: New test.
* gcc.dg/analyzer/torture/pr59037.c: New test.
|