1 /* Modeling API uses and misuses via state machines. 2 Copyright (C) 2019-2020 Free Software Foundation, Inc. 3 Contributed by David Malcolm <dmalcolm@redhat.com>. 4 5 This file is part of GCC. 6 7 GCC is free software; you can redistribute it and/or modify it 8 under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3, or (at your option) 10 any later version. 11 12 GCC is distributed in the hope that it will be useful, but 13 WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with GCC; see the file COPYING3. If not see 19 <http://www.gnu.org/licenses/>. */ 20 21 #include "config.h" 22 #include "system.h" 23 #include "coretypes.h" 24 #include "tree.h" 25 #include "function.h" 26 #include "basic-block.h" 27 #include "gimple.h" 28 #include "options.h" 29 #include "function.h" 30 #include "diagnostic-core.h" 31 #include "pretty-print.h" 32 #include "analyzer/analyzer.h" 33 #include "analyzer/analyzer-logging.h" 34 #include "analyzer/sm.h" 35 36 #if ENABLE_ANALYZER 37 38 /* If STMT is an assignment from zero, return the LHS. */ 39 40 tree 41 is_zero_assignment (const gimple *stmt) 42 { 43 const gassign *assign_stmt = dyn_cast <const gassign *> (stmt); 44 if (!assign_stmt) 45 return NULL_TREE; 46 47 enum tree_code op = gimple_assign_rhs_code (assign_stmt); 48 if (TREE_CODE_CLASS (op) != tcc_constant) 49 return NULL_TREE; 50 51 if (!zerop (gimple_assign_rhs1 (assign_stmt))) 52 return NULL_TREE; 53 54 return gimple_assign_lhs (assign_stmt); 55 } 56 57 /* Return true if VAR has pointer or reference type. */ 58 59 bool 60 any_pointer_p (tree var) 61 { 62 return POINTER_TYPE_P (TREE_TYPE (var)); 63 } 64 65 namespace ana { 66 67 /* Add a state with name NAME to this state_machine. 68 The string is required to outlive the state_machine. 69 70 Return the state_t for the new state. */ 71 72 state_machine::state_t 73 state_machine::add_state (const char *name) 74 { 75 m_state_names.safe_push (name); 76 return m_state_names.length () - 1; 77 } 78 79 /* Get the name of state S within this state_machine. */ 80 81 const char * 82 state_machine::get_state_name (state_t s) const 83 { 84 return m_state_names[s]; 85 } 86 87 /* Get the state with name NAME, which must exist. 88 This is purely intended for use in selftests. */ 89 90 state_machine::state_t 91 state_machine::get_state_by_name (const char *name) 92 { 93 unsigned i; 94 const char *iter_name; 95 FOR_EACH_VEC_ELT (m_state_names, i, iter_name) 96 if (!strcmp (name, iter_name)) 97 return i; 98 /* Name not found. */ 99 gcc_unreachable (); 100 } 101 102 /* Assert that S is a valid state for this state_machine. */ 103 104 void 105 state_machine::validate (state_t s) const 106 { 107 gcc_assert (s < m_state_names.length ()); 108 } 109 110 /* Dump a multiline representation of this state machine to PP. */ 111 112 void 113 state_machine::dump_to_pp (pretty_printer *pp) const 114 { 115 unsigned i; 116 const char *name; 117 FOR_EACH_VEC_ELT (m_state_names, i, name) 118 pp_printf (pp, " state %i: %qs\n", i, name); 119 } 120 121 /* Create instances of the various state machines, each using LOGGER, 122 and populate OUT with them. */ 123 124 void 125 make_checkers (auto_delete_vec <state_machine> &out, logger *logger) 126 { 127 out.safe_push (make_malloc_state_machine (logger)); 128 out.safe_push (make_fileptr_state_machine (logger)); 129 /* The "taint" checker must be explicitly enabled (as it currently 130 leads to state explosions that stop the other checkers working). */ 131 if (flag_analyzer_checker) 132 out.safe_push (make_taint_state_machine (logger)); 133 out.safe_push (make_sensitive_state_machine (logger)); 134 out.safe_push (make_signal_state_machine (logger)); 135 136 /* We only attempt to run the pattern tests if it might have been manually 137 enabled (for DejaGnu purposes). */ 138 if (flag_analyzer_checker) 139 out.safe_push (make_pattern_test_state_machine (logger)); 140 141 if (flag_analyzer_checker) 142 { 143 unsigned read_index, write_index; 144 state_machine **sm; 145 146 /* TODO: this leaks the machines 147 Would be nice to log the things that were removed. */ 148 VEC_ORDERED_REMOVE_IF (out, read_index, write_index, sm, 149 0 != strcmp (flag_analyzer_checker, 150 (*sm)->get_name ())); 151 } 152 } 153 154 } // namespace ana 155 156 #endif /* #if ENABLE_ANALYZER */ 157