aboutsummaryrefslogtreecommitdiff
path: root/gcc/analyzer/program-state.cc
AgeCommit message (Collapse)AuthorFilesLines
2023-02-21analyzer: stop exploring the path after certain diagnostics [PR108830]David Malcolm1-2/+26
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>
2023-01-16Update copyright years.Jakub Jelinek1-1/+1
2022-11-29analyzer work on issues with flex-generated lexers [PR103546]David Malcolm1-0/+2
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>
2022-11-23analyzer: revamp of heap-allocated regions [PR106473]David Malcolm1-2/+2
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>
2022-11-10analyzer: new warning: -Wanalyzer-deref-before-check [PR99671]David Malcolm1-9/+74
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>
2022-11-03analyzer: use std::unique_ptr for pending_diagnostic/noteDavid Malcolm1-0/+1
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>
2022-10-05analyzer: simplify some includesDavid Malcolm1-6/+0
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>
2022-10-04analyzer: revamp side-effects of call summaries [PR107072]David Malcolm1-0/+48
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>
2022-07-15libcpp: Improve encapsulation of label_textJonathan Wakely1-1/+1
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.
2022-07-07Convert label_text to C++11 move semanticsDavid Malcolm1-1/+0
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>
2022-06-24analyzer: consolidate call_string instancesDavid Malcolm1-5/+6
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>
2022-03-18analyzer: extend state-purging to locals [PR104943]David Malcolm1-35/+94
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>
2022-01-03Update copyright years.Jakub Jelinek1-1/+1
2021-11-19analyzer: fix false leak due to overeager state merging [PR103217]David Malcolm1-3/+6
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>
2021-11-13analyzer: add four new taint-based warningsDavid Malcolm1-2/+24
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>
2021-11-04analyzer: fix ICE in sm_state_map::dump when dumping treesDavid Malcolm1-0/+1
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>
2021-08-30analyzer: support "bifurcation"; reimplement realloc [PR99260]David Malcolm1-2/+4
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-08-18analyzer: detect and analyze calls via function pointerAnkur Saini1-0/+44
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.
2021-07-19analyzer: add svalue::can_have_associated_state_p [PR101503]David Malcolm1-2/+4
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>
2021-07-16analyzer: add region_model::check_region_accessDavid Malcolm1-1/+1
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>
2021-07-16analyzer: add __analyzer_dump_stateDavid Malcolm1-0/+49
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>
2021-07-16analyzer: add svalue::maybe_get_regionDavid Malcolm1-6/+3
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>
2021-07-15analyzer: reimplement -Wanalyzer-use-of-uninitialized-value [PR95006 et al]David Malcolm1-16/+27
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>
2021-06-30analyzer: eliminate enum binding_key [PR95006]David Malcolm1-0/+1
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>
2021-06-15analyzer: track dynamic extents of regionsDavid Malcolm1-2/+11
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>
2021-06-13use range based for loops to iterate over vec<>Trevor Saunders1-3/+1
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.
2021-05-10Remove __cplusplus >= 201103Martin Liska1-2/+0
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.
2021-04-08analyzer: fix leak false +ves due to maybe-clobbered regions [PR99042,PR99774]David Malcolm1-22/+48
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.
2021-04-01analyzer: record per-enode saved_diagnosticsDavid Malcolm1-6/+6
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.
2021-03-24analyzer; reset sm-state for SSA names at def-stmts [PR93695,PR99044,PR99716]David Malcolm1-0/+30
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.
2021-02-17analyzer: fix false leak involving params [PR98969]David Malcolm1-2/+2
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.
2021-01-04Update copyright years.Jakub Jelinek1-1/+1
2020-11-10analyzer: remove dead codeMartin Liska1-11/+11
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.
2020-10-28analyzer: more non-determinism fixesDavid Malcolm1-3/+23
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.
2020-10-28analyzer: fix more pointer-printing in logsDavid Malcolm1-2/+5
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.
2020-10-27analyzer: eliminate non-deterministic behaviorDavid Malcolm1-0/+57
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.
2020-10-27analyzer: eliminate non-determinism in logsDavid Malcolm1-8/+25
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.
2020-09-28analyzer: fix sm_state_map::printDavid Malcolm1-1/+1
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.
2020-09-23analyzer: add -fno-analyzer-feasibilityDavid Malcolm1-1/+1
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.
2020-09-23analyzer: fix member call on null seen with ubsan [PR97178]David Malcolm1-5/+7
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.
2020-09-22analyzer: add -fdump-analyzer-jsonDavid Malcolm1-0/+85
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.
2020-09-09analyzer: use objects for state_machine::state_tDavid Malcolm1-28/+44
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.
2020-08-13analyzer: rewrite of region and value-handlingDavid Malcolm1-781/+490
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.
2020-04-28analyzer: remove -Wanalyzer-use-of-uninitialized-value for GCC 10David Malcolm1-8/+6
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.
2020-04-01analyzer: handle compound assignments [PR94378]David Malcolm1-0/+1
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.
2020-03-27analyzer: fix malloc pointer NULL-nessDavid Malcolm1-1/+1
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.
2020-03-06analyzer: improvements to region_model::get_representative_treeDavid Malcolm1-0/+46
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.
2020-03-06analyzer: improvements to state dumpingDavid Malcolm1-12/+116
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.
2020-02-18analyzer: fix ICE on COMPONENT_REF of ARRAY_TYPE [PR 93778]David Malcolm1-4/+5
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.
2020-02-17analyzer: fix ICEs in region_model::get_lvalue_1 [PR 93388]David Malcolm1-2/+19
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.