diff options
author | David Malcolm <dmalcolm@redhat.com> | 2019-09-27 09:23:16 -0400 |
---|---|---|
committer | David Malcolm <dmalcolm@redhat.com> | 2020-01-14 15:34:24 -0500 |
commit | 757bf1dff5e8cee34c0a75d06140ca972bfecfa7 (patch) | |
tree | cca8a96a39f87c90df46a389d1777854f97017d3 /gcc/analyzer/program-point.h | |
parent | 08c8c973c082457a7d6192673e87475f1fdfdbef (diff) | |
download | gcc-757bf1dff5e8cee34c0a75d06140ca972bfecfa7.zip gcc-757bf1dff5e8cee34c0a75d06140ca972bfecfa7.tar.gz gcc-757bf1dff5e8cee34c0a75d06140ca972bfecfa7.tar.bz2 |
Initial commit of analyzer
This patch adds a static analysis pass to the middle-end, focusing
for this release on C code, and malloc/free issues in particular.
See:
https://gcc.gnu.org/wiki/DavidMalcolm/StaticAnalyzer
gcc/ChangeLog:
* Makefile.in (lang_opt_files): Add analyzer.opt.
(ANALYZER_OBJS): New.
(OBJS): Add digraph.o, graphviz.o, ordered-hash-map-tests.o,
tristate.o and ANALYZER_OBJS.
(TEXI_GCCINT_FILES): Add analyzer.texi.
* common.opt (-fanalyzer): New driver option.
* config.in: Regenerate.
* configure: Regenerate.
* configure.ac (--disable-analyzer, ENABLE_ANALYZER): New option.
(gccdepdir): Also create depdir for "analyzer" subdir.
* digraph.cc: New file.
* digraph.h: New file.
* doc/analyzer.texi: New file.
* doc/gccint.texi ("Static Analyzer") New menu item.
(analyzer.texi): Include it.
* doc/invoke.texi ("Static Analyzer Options"): New list and new section.
("Warning Options"): Add static analysis warnings to the list.
(-Wno-analyzer-double-fclose): New option.
(-Wno-analyzer-double-free): New option.
(-Wno-analyzer-exposure-through-output-file): New option.
(-Wno-analyzer-file-leak): New option.
(-Wno-analyzer-free-of-non-heap): New option.
(-Wno-analyzer-malloc-leak): New option.
(-Wno-analyzer-possible-null-argument): New option.
(-Wno-analyzer-possible-null-dereference): New option.
(-Wno-analyzer-null-argument): New option.
(-Wno-analyzer-null-dereference): New option.
(-Wno-analyzer-stale-setjmp-buffer): New option.
(-Wno-analyzer-tainted-array-index): New option.
(-Wno-analyzer-use-after-free): New option.
(-Wno-analyzer-use-of-pointer-in-stale-stack-frame): New option.
(-Wno-analyzer-use-of-uninitialized-value): New option.
(-Wanalyzer-too-complex): New option.
(-fanalyzer-call-summaries): New warning.
(-fanalyzer-checker=): New warning.
(-fanalyzer-fine-grained): New warning.
(-fno-analyzer-state-merge): New warning.
(-fno-analyzer-state-purge): New warning.
(-fanalyzer-transitivity): New warning.
(-fanalyzer-verbose-edges): New warning.
(-fanalyzer-verbose-state-changes): New warning.
(-fanalyzer-verbosity=): New warning.
(-fdump-analyzer): New warning.
(-fdump-analyzer-callgraph): New warning.
(-fdump-analyzer-exploded-graph): New warning.
(-fdump-analyzer-exploded-nodes): New warning.
(-fdump-analyzer-exploded-nodes-2): New warning.
(-fdump-analyzer-exploded-nodes-3): New warning.
(-fdump-analyzer-supergraph): New warning.
* doc/sourcebuild.texi (dg-require-dot): New.
(dg-check-dot): New.
* gdbinit.in (break-on-saved-diagnostic): New command.
* graphviz.cc: New file.
* graphviz.h: New file.
* ordered-hash-map-tests.cc: New file.
* ordered-hash-map.h: New file.
* passes.def (pass_analyzer): Add before
pass_ipa_whole_program_visibility.
* selftest-run-tests.c (selftest::run_tests): Call
selftest::ordered_hash_map_tests_cc_tests.
* selftest.h (selftest::ordered_hash_map_tests_cc_tests): New
decl.
* shortest-paths.h: New file.
* timevar.def (TV_ANALYZER): New timevar.
(TV_ANALYZER_SUPERGRAPH): Likewise.
(TV_ANALYZER_STATE_PURGE): Likewise.
(TV_ANALYZER_PLAN): Likewise.
(TV_ANALYZER_SCC): Likewise.
(TV_ANALYZER_WORKLIST): Likewise.
(TV_ANALYZER_DUMP): Likewise.
(TV_ANALYZER_DIAGNOSTICS): Likewise.
(TV_ANALYZER_SHORTEST_PATHS): Likewise.
* tree-pass.h (make_pass_analyzer): New decl.
* tristate.cc: New file.
* tristate.h: New file.
gcc/analyzer/ChangeLog:
* ChangeLog: New file.
* analyzer-selftests.cc: New file.
* analyzer-selftests.h: New file.
* analyzer.opt: New file.
* analysis-plan.cc: New file.
* analysis-plan.h: New file.
* analyzer-logging.cc: New file.
* analyzer-logging.h: New file.
* analyzer-pass.cc: New file.
* analyzer.cc: New file.
* analyzer.h: New file.
* call-string.cc: New file.
* call-string.h: New file.
* checker-path.cc: New file.
* checker-path.h: New file.
* constraint-manager.cc: New file.
* constraint-manager.h: New file.
* diagnostic-manager.cc: New file.
* diagnostic-manager.h: New file.
* engine.cc: New file.
* engine.h: New file.
* exploded-graph.h: New file.
* pending-diagnostic.cc: New file.
* pending-diagnostic.h: New file.
* program-point.cc: New file.
* program-point.h: New file.
* program-state.cc: New file.
* program-state.h: New file.
* region-model.cc: New file.
* region-model.h: New file.
* sm-file.cc: New file.
* sm-malloc.cc: New file.
* sm-malloc.dot: New file.
* sm-pattern-test.cc: New file.
* sm-sensitive.cc: New file.
* sm-signal.cc: New file.
* sm-taint.cc: New file.
* sm.cc: New file.
* sm.h: New file.
* state-purge.cc: New file.
* state-purge.h: New file.
* supergraph.cc: New file.
* supergraph.h: New file.
gcc/testsuite/ChangeLog:
* gcc.dg/analyzer/CVE-2005-1689-minimal.c: New test.
* gcc.dg/analyzer/abort.c: New test.
* gcc.dg/analyzer/alloca-leak.c: New test.
* gcc.dg/analyzer/analyzer-decls.h: New header.
* gcc.dg/analyzer/analyzer-verbosity-0.c: New test.
* gcc.dg/analyzer/analyzer-verbosity-1.c: New test.
* gcc.dg/analyzer/analyzer-verbosity-2.c: New test.
* gcc.dg/analyzer/analyzer.exp: New suite.
* gcc.dg/analyzer/attribute-nonnull.c: New test.
* gcc.dg/analyzer/call-summaries-1.c: New test.
* gcc.dg/analyzer/conditionals-2.c: New test.
* gcc.dg/analyzer/conditionals-3.c: New test.
* gcc.dg/analyzer/conditionals-notrans.c: New test.
* gcc.dg/analyzer/conditionals-trans.c: New test.
* gcc.dg/analyzer/data-model-1.c: New test.
* gcc.dg/analyzer/data-model-2.c: New test.
* gcc.dg/analyzer/data-model-3.c: New test.
* gcc.dg/analyzer/data-model-4.c: New test.
* gcc.dg/analyzer/data-model-5.c: New test.
* gcc.dg/analyzer/data-model-5b.c: New test.
* gcc.dg/analyzer/data-model-5c.c: New test.
* gcc.dg/analyzer/data-model-5d.c: New test.
* gcc.dg/analyzer/data-model-6.c: New test.
* gcc.dg/analyzer/data-model-7.c: New test.
* gcc.dg/analyzer/data-model-8.c: New test.
* gcc.dg/analyzer/data-model-9.c: New test.
* gcc.dg/analyzer/data-model-11.c: New test.
* gcc.dg/analyzer/data-model-12.c: New test.
* gcc.dg/analyzer/data-model-13.c: New test.
* gcc.dg/analyzer/data-model-14.c: New test.
* gcc.dg/analyzer/data-model-15.c: New test.
* gcc.dg/analyzer/data-model-16.c: New test.
* gcc.dg/analyzer/data-model-17.c: New test.
* gcc.dg/analyzer/data-model-18.c: New test.
* gcc.dg/analyzer/data-model-19.c: New test.
* gcc.dg/analyzer/data-model-path-1.c: New test.
* gcc.dg/analyzer/disabling.c: New test.
* gcc.dg/analyzer/dot-output.c: New test.
* gcc.dg/analyzer/double-free-lto-1-a.c: New test.
* gcc.dg/analyzer/double-free-lto-1-b.c: New test.
* gcc.dg/analyzer/double-free-lto-1.h: New header.
* gcc.dg/analyzer/equivalence.c: New test.
* gcc.dg/analyzer/explode-1.c: New test.
* gcc.dg/analyzer/explode-2.c: New test.
* gcc.dg/analyzer/factorial.c: New test.
* gcc.dg/analyzer/fibonacci.c: New test.
* gcc.dg/analyzer/fields.c: New test.
* gcc.dg/analyzer/file-1.c: New test.
* gcc.dg/analyzer/file-2.c: New test.
* gcc.dg/analyzer/function-ptr-1.c: New test.
* gcc.dg/analyzer/function-ptr-2.c: New test.
* gcc.dg/analyzer/function-ptr-3.c: New test.
* gcc.dg/analyzer/gzio-2.c: New test.
* gcc.dg/analyzer/gzio-3.c: New test.
* gcc.dg/analyzer/gzio-3a.c: New test.
* gcc.dg/analyzer/gzio.c: New test.
* gcc.dg/analyzer/infinite-recursion.c: New test.
* gcc.dg/analyzer/loop-2.c: New test.
* gcc.dg/analyzer/loop-2a.c: New test.
* gcc.dg/analyzer/loop-3.c: New test.
* gcc.dg/analyzer/loop-4.c: New test.
* gcc.dg/analyzer/loop.c: New test.
* gcc.dg/analyzer/malloc-1.c: New test.
* gcc.dg/analyzer/malloc-2.c: New test.
* gcc.dg/analyzer/malloc-3.c: New test.
* gcc.dg/analyzer/malloc-callbacks.c: New test.
* gcc.dg/analyzer/malloc-dce.c: New test.
* gcc.dg/analyzer/malloc-dedupe-1.c: New test.
* gcc.dg/analyzer/malloc-ipa-1.c: New test.
* gcc.dg/analyzer/malloc-ipa-10.c: New test.
* gcc.dg/analyzer/malloc-ipa-11.c: New test.
* gcc.dg/analyzer/malloc-ipa-12.c: New test.
* gcc.dg/analyzer/malloc-ipa-13.c: New test.
* gcc.dg/analyzer/malloc-ipa-2.c: New test.
* gcc.dg/analyzer/malloc-ipa-3.c: New test.
* gcc.dg/analyzer/malloc-ipa-4.c: New test.
* gcc.dg/analyzer/malloc-ipa-5.c: New test.
* gcc.dg/analyzer/malloc-ipa-6.c: New test.
* gcc.dg/analyzer/malloc-ipa-7.c: New test.
* gcc.dg/analyzer/malloc-ipa-8-double-free.c: New test.
* gcc.dg/analyzer/malloc-ipa-8-lto-a.c: New test.
* gcc.dg/analyzer/malloc-ipa-8-lto-b.c: New test.
* gcc.dg/analyzer/malloc-ipa-8-lto-c.c: New test.
* gcc.dg/analyzer/malloc-ipa-8-lto.h: New test.
* gcc.dg/analyzer/malloc-ipa-8-unchecked.c: New test.
* gcc.dg/analyzer/malloc-ipa-9.c: New test.
* gcc.dg/analyzer/malloc-macro-inline-events.c: New test.
* gcc.dg/analyzer/malloc-macro-separate-events.c: New test.
* gcc.dg/analyzer/malloc-macro.h: New header.
* gcc.dg/analyzer/malloc-many-paths-1.c: New test.
* gcc.dg/analyzer/malloc-many-paths-2.c: New test.
* gcc.dg/analyzer/malloc-many-paths-3.c: New test.
* gcc.dg/analyzer/malloc-paths-1.c: New test.
* gcc.dg/analyzer/malloc-paths-10.c: New test.
* gcc.dg/analyzer/malloc-paths-2.c: New test.
* gcc.dg/analyzer/malloc-paths-3.c: New test.
* gcc.dg/analyzer/malloc-paths-4.c: New test.
* gcc.dg/analyzer/malloc-paths-5.c: New test.
* gcc.dg/analyzer/malloc-paths-6.c: New test.
* gcc.dg/analyzer/malloc-paths-7.c: New test.
* gcc.dg/analyzer/malloc-paths-8.c: New test.
* gcc.dg/analyzer/malloc-paths-9.c: New test.
* gcc.dg/analyzer/malloc-vs-local-1a.c: New test.
* gcc.dg/analyzer/malloc-vs-local-1b.c: New test.
* gcc.dg/analyzer/malloc-vs-local-2.c: New test.
* gcc.dg/analyzer/malloc-vs-local-3.c: New test.
* gcc.dg/analyzer/malloc-vs-local-4.c: New test.
* gcc.dg/analyzer/operations.c: New test.
* gcc.dg/analyzer/params-2.c: New test.
* gcc.dg/analyzer/params.c: New test.
* gcc.dg/analyzer/paths-1.c: New test.
* gcc.dg/analyzer/paths-1a.c: New test.
* gcc.dg/analyzer/paths-2.c: New test.
* gcc.dg/analyzer/paths-3.c: New test.
* gcc.dg/analyzer/paths-4.c: New test.
* gcc.dg/analyzer/paths-5.c: New test.
* gcc.dg/analyzer/paths-6.c: New test.
* gcc.dg/analyzer/paths-7.c: New test.
* gcc.dg/analyzer/pattern-test-1.c: New test.
* gcc.dg/analyzer/pattern-test-2.c: New test.
* gcc.dg/analyzer/pointer-merging.c: New test.
* gcc.dg/analyzer/pr61861.c: New test.
* gcc.dg/analyzer/pragma-1.c: New test.
* gcc.dg/analyzer/scope-1.c: New test.
* gcc.dg/analyzer/sensitive-1.c: New test.
* gcc.dg/analyzer/setjmp-1.c: New test.
* gcc.dg/analyzer/setjmp-2.c: New test.
* gcc.dg/analyzer/setjmp-3.c: New test.
* gcc.dg/analyzer/setjmp-4.c: New test.
* gcc.dg/analyzer/setjmp-5.c: New test.
* gcc.dg/analyzer/setjmp-6.c: New test.
* gcc.dg/analyzer/setjmp-7.c: New test.
* gcc.dg/analyzer/setjmp-7a.c: New test.
* gcc.dg/analyzer/setjmp-8.c: New test.
* gcc.dg/analyzer/setjmp-9.c: New test.
* gcc.dg/analyzer/signal-1.c: New test.
* gcc.dg/analyzer/signal-2.c: New test.
* gcc.dg/analyzer/signal-3.c: New test.
* gcc.dg/analyzer/signal-4a.c: New test.
* gcc.dg/analyzer/signal-4b.c: New test.
* gcc.dg/analyzer/strcmp-1.c: New test.
* gcc.dg/analyzer/switch.c: New test.
* gcc.dg/analyzer/taint-1.c: New test.
* gcc.dg/analyzer/zlib-1.c: New test.
* gcc.dg/analyzer/zlib-2.c: New test.
* gcc.dg/analyzer/zlib-3.c: New test.
* gcc.dg/analyzer/zlib-4.c: New test.
* gcc.dg/analyzer/zlib-5.c: New test.
* gcc.dg/analyzer/zlib-6.c: New test.
* lib/gcc-defs.exp (dg-check-dot): New procedure.
* lib/target-supports.exp (check_dot_available): New procedure.
(check_effective_target_analyzer): New.
* lib/target-supports-dg.exp (dg-require-dot): New procedure.
Diffstat (limited to 'gcc/analyzer/program-point.h')
-rw-r--r-- | gcc/analyzer/program-point.h | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/gcc/analyzer/program-point.h b/gcc/analyzer/program-point.h new file mode 100644 index 0000000..b9fe548 --- /dev/null +++ b/gcc/analyzer/program-point.h @@ -0,0 +1,310 @@ +/* Classes for representing locations within the program. + Copyright (C) 2019-2020 Free Software Foundation, Inc. + Contributed by David Malcolm <dmalcolm@redhat.com>. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#ifndef GCC_ANALYZER_PROGRAM_POINT_H +#define GCC_ANALYZER_PROGRAM_POINT_H + +class exploded_graph; + +/* An enum for distinguishing the various kinds of program_point. */ + +enum point_kind { + /* A "fake" node which has edges to all entrypoints. */ + PK_ORIGIN, + + PK_BEFORE_SUPERNODE, + PK_BEFORE_STMT, + PK_AFTER_SUPERNODE, + + /* Special values used for hash_map: */ + PK_EMPTY, + PK_DELETED, + + NUM_POINT_KINDS +}; + +extern const char *point_kind_to_string (enum point_kind pk); + +class format +{ +public: + format (bool newlines) : m_newlines (newlines) {} + + void spacer (pretty_printer *pp) const + { + if (m_newlines) + pp_newline (pp); + else + pp_space (pp); + } + + bool m_newlines; +}; + +/* A class for representing a location within the program, without + interprocedural information. + + This represents a fine-grained location within the supergraph (or + within one of its nodes). */ + +class function_point +{ +public: + function_point (const supernode *supernode, + const superedge *from_edge, + unsigned stmt_idx, + enum point_kind kind) + : m_supernode (supernode), m_from_edge (from_edge), + m_stmt_idx (stmt_idx), m_kind (kind) + { + if (from_edge) + { + gcc_checking_assert (m_kind == PK_BEFORE_SUPERNODE); + gcc_checking_assert (from_edge->get_kind () == SUPEREDGE_CFG_EDGE); + } + if (stmt_idx) + gcc_checking_assert (m_kind == PK_BEFORE_STMT); + } + + void print (pretty_printer *pp, const format &f) const; + void print_source_line (pretty_printer *pp) const; + void dump () const; + + hashval_t hash () const; + bool operator== (const function_point &other) const + { + return (m_supernode == other.m_supernode + && m_from_edge == other.m_from_edge + && m_stmt_idx == other.m_stmt_idx + && m_kind == other.m_kind); + } + + /* Accessors. */ + + const supernode *get_supernode () const { return m_supernode; } + function *get_function () const + { + if (m_supernode) + return m_supernode->m_fun; + else + return NULL; + } + const gimple *get_stmt () const; + location_t get_location () const; + enum point_kind get_kind () const { return m_kind; } + const superedge *get_from_edge () const + { + return m_from_edge; + } + unsigned get_stmt_idx () const + { + gcc_assert (m_kind == PK_BEFORE_STMT); + return m_stmt_idx; + } + + /* Factory functions for making various kinds of program_point. */ + + static function_point from_function_entry (const supergraph &sg, + function *fun) + { + return before_supernode (sg.get_node_for_function_entry (fun), + NULL); + } + + static function_point before_supernode (const supernode *supernode, + const superedge *from_edge) + { + if (from_edge && from_edge->get_kind () != SUPEREDGE_CFG_EDGE) + from_edge = NULL; + return function_point (supernode, from_edge, 0, PK_BEFORE_SUPERNODE); + } + + static function_point before_stmt (const supernode *supernode, + unsigned stmt_idx) + { + return function_point (supernode, NULL, stmt_idx, PK_BEFORE_STMT); + } + + static function_point after_supernode (const supernode *supernode) + { + return function_point (supernode, NULL, 0, PK_AFTER_SUPERNODE); + } + + /* Support for hash_map. */ + + static function_point empty () + { + return function_point (NULL, NULL, 0, PK_EMPTY); + } + static function_point deleted () + { + return function_point (NULL, NULL, 0, PK_DELETED); + } + + static int cmp_within_supernode_1 (const function_point &point_a, + const function_point &point_b); + static int cmp_within_supernode (const function_point &point_a, + const function_point &point_b); + + private: + const supernode *m_supernode; + + /* For PK_BEFORE_SUPERNODE, and only for CFG edges. */ + const superedge *m_from_edge; + + /* Only for PK_BEFORE_STMT. */ + unsigned m_stmt_idx; + + enum point_kind m_kind; +}; + +/* A class for representing a location within the program, including + interprocedural information. + + This represents a fine-grained location within the supergraph (or + within one of its nodes), along with a call string giving the + interprocedural context. */ + +class program_point +{ +public: + program_point (const function_point &fn_point, + const call_string &call_string) + : m_function_point (fn_point), + m_call_string (call_string) + { + } + + void print (pretty_printer *pp, const format &f) const; + void print_source_line (pretty_printer *pp) const; + void dump () const; + + hashval_t hash () const; + bool operator== (const program_point &other) const + { + return (m_function_point == other.m_function_point + && m_call_string == other.m_call_string); + } + + /* Accessors. */ + + const function_point &get_function_point () const { return m_function_point; } + const call_string &get_call_string () const { return m_call_string; } + + const supernode *get_supernode () const + { + return m_function_point.get_supernode (); + } + function *get_function () const + { + return m_function_point.get_function (); + } + function *get_function_at_depth (unsigned depth) const; + tree get_fndecl () const + { + gcc_assert (get_kind () != PK_ORIGIN); + return get_function ()->decl; + } + const gimple *get_stmt () const + { + return m_function_point.get_stmt (); + } + location_t get_location () const + { + return m_function_point.get_location (); + } + enum point_kind get_kind () const + { + return m_function_point.get_kind (); + } + const superedge *get_from_edge () const + { + return m_function_point.get_from_edge (); + } + unsigned get_stmt_idx () const + { + return m_function_point.get_stmt_idx (); + } + + /* Get the number of frames we expect at this program point. + This will be one more than the length of the call_string + (which stores the parent callsites), apart from the origin + node, which doesn't have any frames. */ + int get_stack_depth () const + { + if (get_kind () == PK_ORIGIN) + return 0; + return m_call_string.length () + 1; + } + + /* Factory functions for making various kinds of program_point. */ + + static program_point from_function_entry (const supergraph &sg, + function *fun) + { + return program_point (function_point::from_function_entry (sg, fun), + call_string ()); + } + + static program_point before_supernode (const supernode *supernode, + const superedge *from_edge, + const call_string &call_string) + { + return program_point (function_point::before_supernode (supernode, + from_edge), + call_string); + } + + static program_point before_stmt (const supernode *supernode, + unsigned stmt_idx, + const call_string &call_string) + { + return program_point (function_point::before_stmt (supernode, stmt_idx), + call_string); + } + + static program_point after_supernode (const supernode *supernode, + const call_string &call_string) + { + return program_point (function_point::after_supernode (supernode), + call_string); + } + + /* Support for hash_map. */ + + static program_point empty () + { + return program_point (function_point::empty (), call_string ()); + } + static program_point deleted () + { + return program_point (function_point::deleted (), call_string ()); + } + + bool on_edge (exploded_graph &eg, const superedge *succ); + + void validate () const; + + private: + const function_point m_function_point; + call_string m_call_string; +}; + +#endif /* GCC_ANALYZER_PROGRAM_POINT_H */ |