1 1.1 mrg /* Classes for saving, deduplicating, and emitting analyzer diagnostics. 2 1.1.1.2 mrg Copyright (C) 2019-2022 Free Software Foundation, Inc. 3 1.1 mrg Contributed by David Malcolm <dmalcolm (at) redhat.com>. 4 1.1 mrg 5 1.1 mrg This file is part of GCC. 6 1.1 mrg 7 1.1 mrg GCC is free software; you can redistribute it and/or modify it 8 1.1 mrg under the terms of the GNU General Public License as published by 9 1.1 mrg the Free Software Foundation; either version 3, or (at your option) 10 1.1 mrg any later version. 11 1.1 mrg 12 1.1 mrg GCC is distributed in the hope that it will be useful, but 13 1.1 mrg WITHOUT ANY WARRANTY; without even the implied warranty of 14 1.1 mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 1.1 mrg General Public License for more details. 16 1.1 mrg 17 1.1 mrg You should have received a copy of the GNU General Public License 18 1.1 mrg along with GCC; see the file COPYING3. If not see 19 1.1 mrg <http://www.gnu.org/licenses/>. */ 20 1.1 mrg 21 1.1 mrg #include "config.h" 22 1.1 mrg #include "system.h" 23 1.1 mrg #include "coretypes.h" 24 1.1 mrg #include "tree.h" 25 1.1 mrg #include "pretty-print.h" 26 1.1 mrg #include "gcc-rich-location.h" 27 1.1 mrg #include "gimple-pretty-print.h" 28 1.1 mrg #include "function.h" 29 1.1 mrg #include "diagnostic-core.h" 30 1.1 mrg #include "diagnostic-event-id.h" 31 1.1 mrg #include "diagnostic-path.h" 32 1.1 mrg #include "alloc-pool.h" 33 1.1 mrg #include "fibonacci_heap.h" 34 1.1 mrg #include "shortest-paths.h" 35 1.1 mrg #include "sbitmap.h" 36 1.1 mrg #include "bitmap.h" 37 1.1 mrg #include "tristate.h" 38 1.1 mrg #include "selftest.h" 39 1.1 mrg #include "ordered-hash-map.h" 40 1.1.1.2 mrg #include "json.h" 41 1.1 mrg #include "analyzer/analyzer.h" 42 1.1 mrg #include "analyzer/analyzer-logging.h" 43 1.1 mrg #include "analyzer/sm.h" 44 1.1 mrg #include "analyzer/pending-diagnostic.h" 45 1.1 mrg #include "analyzer/diagnostic-manager.h" 46 1.1.1.2 mrg #include "analyzer/call-string.h" 47 1.1.1.2 mrg #include "analyzer/program-point.h" 48 1.1.1.2 mrg #include "analyzer/store.h" 49 1.1 mrg #include "analyzer/region-model.h" 50 1.1 mrg #include "analyzer/constraint-manager.h" 51 1.1 mrg #include "cfg.h" 52 1.1 mrg #include "basic-block.h" 53 1.1 mrg #include "gimple.h" 54 1.1 mrg #include "gimple-iterator.h" 55 1.1 mrg #include "cgraph.h" 56 1.1 mrg #include "digraph.h" 57 1.1 mrg #include "analyzer/supergraph.h" 58 1.1 mrg #include "analyzer/program-state.h" 59 1.1 mrg #include "analyzer/exploded-graph.h" 60 1.1.1.2 mrg #include "analyzer/trimmed-graph.h" 61 1.1.1.2 mrg #include "analyzer/feasible-graph.h" 62 1.1 mrg #include "analyzer/checker-path.h" 63 1.1 mrg #include "analyzer/reachability.h" 64 1.1 mrg 65 1.1 mrg #if ENABLE_ANALYZER 66 1.1 mrg 67 1.1 mrg namespace ana { 68 1.1 mrg 69 1.1.1.2 mrg class feasible_worklist; 70 1.1.1.2 mrg 71 1.1.1.2 mrg /* State for finding the shortest feasible exploded_path for a 72 1.1.1.2 mrg saved_diagnostic. 73 1.1.1.2 mrg This is shared between all diagnostics, so that we avoid repeating work. */ 74 1.1.1.2 mrg 75 1.1.1.2 mrg class epath_finder 76 1.1.1.2 mrg { 77 1.1.1.2 mrg public: 78 1.1.1.2 mrg epath_finder (const exploded_graph &eg) 79 1.1.1.2 mrg : m_eg (eg), 80 1.1.1.2 mrg m_sep (NULL) 81 1.1.1.2 mrg { 82 1.1.1.2 mrg /* This is shared by all diagnostics, but only needed if 83 1.1.1.2 mrg !flag_analyzer_feasibility. */ 84 1.1.1.2 mrg if (!flag_analyzer_feasibility) 85 1.1.1.2 mrg m_sep = new shortest_exploded_paths (eg, eg.get_origin (), 86 1.1.1.2 mrg SPS_FROM_GIVEN_ORIGIN); 87 1.1.1.2 mrg } 88 1.1.1.2 mrg 89 1.1.1.2 mrg ~epath_finder () { delete m_sep; } 90 1.1.1.2 mrg 91 1.1.1.2 mrg logger *get_logger () const { return m_eg.get_logger (); } 92 1.1.1.2 mrg 93 1.1.1.2 mrg exploded_path *get_best_epath (const exploded_node *target_enode, 94 1.1.1.2 mrg const char *desc, unsigned diag_idx, 95 1.1.1.2 mrg feasibility_problem **out_problem); 96 1.1.1.2 mrg 97 1.1.1.2 mrg private: 98 1.1.1.2 mrg DISABLE_COPY_AND_ASSIGN(epath_finder); 99 1.1.1.2 mrg 100 1.1.1.2 mrg exploded_path *explore_feasible_paths (const exploded_node *target_enode, 101 1.1.1.2 mrg const char *desc, unsigned diag_idx); 102 1.1.1.2 mrg bool process_worklist_item (feasible_worklist *worklist, 103 1.1.1.2 mrg const trimmed_graph &tg, 104 1.1.1.2 mrg feasible_graph *fg, 105 1.1.1.2 mrg const exploded_node *target_enode, 106 1.1.1.2 mrg unsigned diag_idx, 107 1.1.1.2 mrg exploded_path **out_best_path) const; 108 1.1.1.2 mrg void dump_trimmed_graph (const exploded_node *target_enode, 109 1.1.1.2 mrg const char *desc, unsigned diag_idx, 110 1.1.1.2 mrg const trimmed_graph &tg, 111 1.1.1.2 mrg const shortest_paths<eg_traits, exploded_path> &sep); 112 1.1.1.2 mrg void dump_feasible_graph (const exploded_node *target_enode, 113 1.1.1.2 mrg const char *desc, unsigned diag_idx, 114 1.1.1.2 mrg const feasible_graph &fg); 115 1.1.1.2 mrg void dump_feasible_path (const exploded_node *target_enode, 116 1.1.1.2 mrg unsigned diag_idx, 117 1.1.1.2 mrg const feasible_graph &fg, 118 1.1.1.2 mrg const feasible_node &fnode) const; 119 1.1.1.2 mrg 120 1.1.1.2 mrg const exploded_graph &m_eg; 121 1.1.1.2 mrg shortest_exploded_paths *m_sep; 122 1.1.1.2 mrg }; 123 1.1.1.2 mrg 124 1.1.1.2 mrg /* class epath_finder. */ 125 1.1.1.2 mrg 126 1.1.1.2 mrg /* Get the "best" exploded_path for reaching ENODE from the origin, 127 1.1.1.2 mrg returning ownership of it to the caller. 128 1.1.1.2 mrg 129 1.1.1.2 mrg Ideally we want to report the shortest feasible path. 130 1.1.1.2 mrg Return NULL if we could not find a feasible path 131 1.1.1.2 mrg (when flag_analyzer_feasibility is true). 132 1.1.1.2 mrg 133 1.1.1.2 mrg If flag_analyzer_feasibility is false, then simply return the 134 1.1.1.2 mrg shortest path. 135 1.1.1.2 mrg 136 1.1.1.2 mrg Use DESC and DIAG_IDX when logging. 137 1.1.1.2 mrg 138 1.1.1.2 mrg Write any feasibility_problem to *OUT_PROBLEM. */ 139 1.1.1.2 mrg 140 1.1.1.2 mrg exploded_path * 141 1.1.1.2 mrg epath_finder::get_best_epath (const exploded_node *enode, 142 1.1.1.2 mrg const char *desc, unsigned diag_idx, 143 1.1.1.2 mrg feasibility_problem **out_problem) 144 1.1.1.2 mrg { 145 1.1.1.2 mrg logger *logger = get_logger (); 146 1.1.1.2 mrg LOG_SCOPE (logger); 147 1.1.1.2 mrg 148 1.1.1.2 mrg unsigned snode_idx = enode->get_supernode ()->m_index; 149 1.1.1.2 mrg if (logger) 150 1.1.1.2 mrg logger->log ("considering %qs at EN: %i, SN: %i (sd: %i)", 151 1.1.1.2 mrg desc, enode->m_index, snode_idx, diag_idx); 152 1.1.1.2 mrg 153 1.1.1.2 mrg /* State-merging means that not every path in the egraph corresponds 154 1.1.1.2 mrg to a feasible one w.r.t. states. 155 1.1.1.2 mrg 156 1.1.1.2 mrg We want to find the shortest feasible path from the origin to ENODE 157 1.1.1.2 mrg in the egraph. */ 158 1.1.1.2 mrg 159 1.1.1.2 mrg if (flag_analyzer_feasibility) 160 1.1.1.2 mrg { 161 1.1.1.2 mrg /* Attempt to find the shortest feasible path using feasible_graph. */ 162 1.1.1.2 mrg if (logger) 163 1.1.1.2 mrg logger->log ("trying to find shortest feasible path"); 164 1.1.1.2 mrg if (exploded_path *epath = explore_feasible_paths (enode, desc, diag_idx)) 165 1.1.1.2 mrg { 166 1.1.1.2 mrg if (logger) 167 1.1.1.2 mrg logger->log ("accepting %qs at EN: %i, SN: %i (sd: %i)" 168 1.1.1.2 mrg " with feasible path (length: %i)", 169 1.1.1.2 mrg desc, enode->m_index, snode_idx, diag_idx, 170 1.1.1.2 mrg epath->length ()); 171 1.1.1.2 mrg return epath; 172 1.1.1.2 mrg } 173 1.1.1.2 mrg else 174 1.1.1.2 mrg { 175 1.1.1.2 mrg if (logger) 176 1.1.1.2 mrg logger->log ("rejecting %qs at EN: %i, SN: %i (sd: %i)" 177 1.1.1.2 mrg " due to not finding feasible path", 178 1.1.1.2 mrg desc, enode->m_index, snode_idx, diag_idx); 179 1.1.1.2 mrg return NULL; 180 1.1.1.2 mrg } 181 1.1.1.2 mrg } 182 1.1.1.2 mrg else 183 1.1.1.2 mrg { 184 1.1.1.2 mrg /* As a crude approximation to shortest feasible path, simply find 185 1.1.1.2 mrg the shortest path, and note whether it is feasible. 186 1.1.1.2 mrg There could be longer feasible paths within the egraph, so this 187 1.1.1.2 mrg approach would lead to diagnostics being falsely rejected 188 1.1.1.2 mrg (PR analyzer/96374). */ 189 1.1.1.2 mrg if (logger) 190 1.1.1.2 mrg logger->log ("trying to find shortest path ignoring feasibility"); 191 1.1.1.2 mrg gcc_assert (m_sep); 192 1.1.1.2 mrg exploded_path *epath 193 1.1.1.2 mrg = new exploded_path (m_sep->get_shortest_path (enode)); 194 1.1.1.2 mrg if (epath->feasible_p (logger, out_problem, m_eg.get_engine (), &m_eg)) 195 1.1.1.2 mrg { 196 1.1.1.2 mrg if (logger) 197 1.1.1.2 mrg logger->log ("accepting %qs at EN: %i, SN: %i (sn: %i)" 198 1.1.1.2 mrg " with feasible path (length: %i)", 199 1.1.1.2 mrg desc, enode->m_index, snode_idx, diag_idx, 200 1.1.1.2 mrg epath->length ()); 201 1.1.1.2 mrg } 202 1.1.1.2 mrg else 203 1.1.1.2 mrg { 204 1.1.1.2 mrg if (logger) 205 1.1.1.2 mrg logger->log ("accepting %qs at EN: %i, SN: %i (sn: %i) (length: %i)" 206 1.1.1.2 mrg " despite infeasible path (due to %qs)", 207 1.1.1.2 mrg desc, enode->m_index, snode_idx, diag_idx, 208 1.1.1.2 mrg epath->length (), 209 1.1.1.2 mrg "-fno-analyzer-feasibility"); 210 1.1.1.2 mrg } 211 1.1.1.2 mrg return epath; 212 1.1.1.2 mrg } 213 1.1.1.2 mrg } 214 1.1.1.2 mrg 215 1.1.1.2 mrg /* A class for managing the worklist of feasible_nodes in 216 1.1.1.2 mrg epath_finder::explore_feasible_paths, prioritizing them 217 1.1.1.2 mrg so that shorter paths appear earlier in the queue. */ 218 1.1.1.2 mrg 219 1.1.1.2 mrg class feasible_worklist 220 1.1.1.2 mrg { 221 1.1.1.2 mrg public: 222 1.1.1.2 mrg feasible_worklist (const shortest_paths<eg_traits, exploded_path> &sep) 223 1.1.1.2 mrg : m_queue (key_t (*this, NULL)), 224 1.1.1.2 mrg m_sep (sep) 225 1.1.1.2 mrg { 226 1.1.1.2 mrg } 227 1.1.1.2 mrg 228 1.1.1.2 mrg feasible_node *take_next () { return m_queue.extract_min (); } 229 1.1.1.2 mrg 230 1.1.1.2 mrg void add_node (feasible_node *fnode) 231 1.1.1.2 mrg { 232 1.1.1.2 mrg m_queue.insert (key_t (*this, fnode), fnode); 233 1.1.1.2 mrg } 234 1.1.1.2 mrg 235 1.1.1.2 mrg private: 236 1.1.1.2 mrg struct key_t 237 1.1.1.2 mrg { 238 1.1.1.2 mrg key_t (const feasible_worklist &w, feasible_node *fnode) 239 1.1.1.2 mrg : m_worklist (w), m_fnode (fnode) 240 1.1.1.2 mrg {} 241 1.1.1.2 mrg 242 1.1.1.2 mrg bool operator< (const key_t &other) const 243 1.1.1.2 mrg { 244 1.1.1.2 mrg return cmp (*this, other) < 0; 245 1.1.1.2 mrg } 246 1.1.1.2 mrg 247 1.1.1.2 mrg bool operator== (const key_t &other) const 248 1.1.1.2 mrg { 249 1.1.1.2 mrg return cmp (*this, other) == 0; 250 1.1.1.2 mrg } 251 1.1.1.2 mrg 252 1.1.1.2 mrg bool operator> (const key_t &other) const 253 1.1.1.2 mrg { 254 1.1.1.2 mrg return !(*this == other || *this < other); 255 1.1.1.2 mrg } 256 1.1.1.2 mrg 257 1.1.1.2 mrg private: 258 1.1.1.2 mrg static int cmp (const key_t &ka, const key_t &kb) 259 1.1.1.2 mrg { 260 1.1.1.2 mrg /* Choose the node for which if the remaining path were feasible, 261 1.1.1.2 mrg it would be the shortest path (summing the length of the 262 1.1.1.2 mrg known-feasible path so far with that of the remaining 263 1.1.1.2 mrg possibly-feasible path). */ 264 1.1.1.2 mrg int ca = ka.m_worklist.get_estimated_cost (ka.m_fnode); 265 1.1.1.2 mrg int cb = kb.m_worklist.get_estimated_cost (kb.m_fnode); 266 1.1.1.2 mrg return ca - cb; 267 1.1.1.2 mrg } 268 1.1.1.2 mrg 269 1.1.1.2 mrg const feasible_worklist &m_worklist; 270 1.1.1.2 mrg feasible_node *m_fnode; 271 1.1.1.2 mrg }; 272 1.1.1.2 mrg 273 1.1.1.2 mrg /* Get the estimated length of a path involving FNODE from 274 1.1.1.2 mrg the origin to the target enode. 275 1.1.1.2 mrg Sum the length of the known-feasible path so far with 276 1.1.1.2 mrg that of the remaining possibly-feasible path. */ 277 1.1.1.2 mrg 278 1.1.1.2 mrg int get_estimated_cost (const feasible_node *fnode) const 279 1.1.1.2 mrg { 280 1.1.1.2 mrg unsigned length_so_far = fnode->get_path_length (); 281 1.1.1.2 mrg int shortest_remaining_path 282 1.1.1.2 mrg = m_sep.get_shortest_distance (fnode->get_inner_node ()); 283 1.1.1.2 mrg 284 1.1.1.2 mrg gcc_assert (shortest_remaining_path >= 0); 285 1.1.1.2 mrg /* This should be true since we're only exploring nodes within 286 1.1.1.2 mrg the trimmed graph (and we anticipate it being much smaller 287 1.1.1.2 mrg than this, and thus not overflowing the sum). */ 288 1.1.1.2 mrg gcc_assert (shortest_remaining_path < INT_MAX); 289 1.1.1.2 mrg 290 1.1.1.2 mrg return length_so_far + shortest_remaining_path; 291 1.1.1.2 mrg } 292 1.1.1.2 mrg 293 1.1.1.2 mrg /* Priority queue, backed by a fibonacci_heap. */ 294 1.1.1.2 mrg typedef fibonacci_heap<key_t, feasible_node> queue_t; 295 1.1.1.2 mrg queue_t m_queue; 296 1.1.1.2 mrg const shortest_paths<eg_traits, exploded_path> &m_sep; 297 1.1.1.2 mrg }; 298 1.1.1.2 mrg 299 1.1.1.2 mrg /* When we're building the exploded graph we want to simplify 300 1.1.1.2 mrg overly-complicated symbolic values down to "UNKNOWN" to try to avoid 301 1.1.1.2 mrg state explosions and unbounded chains of exploration. 302 1.1.1.2 mrg 303 1.1.1.2 mrg However, when we're building the feasibility graph for a diagnostic 304 1.1.1.2 mrg (actually a tree), we don't want UNKNOWN values, as conditions on them 305 1.1.1.2 mrg are also unknown: we don't want to have a contradiction such as a path 306 1.1.1.2 mrg where (VAL != 0) and then (VAL == 0) along the same path. 307 1.1.1.2 mrg 308 1.1.1.2 mrg Hence this is an RAII class for temporarily disabling complexity-checking 309 1.1.1.2 mrg in the region_model_manager, for use within 310 1.1.1.2 mrg epath_finder::explore_feasible_paths. 311 1.1.1.2 mrg 312 1.1.1.2 mrg We also disable the creation of unknown_svalue instances during feasibility 313 1.1.1.2 mrg checking, instead creating unique svalues, to avoid paradoxes in paths. */ 314 1.1.1.2 mrg 315 1.1.1.2 mrg class auto_checking_feasibility 316 1.1.1.2 mrg { 317 1.1.1.2 mrg public: 318 1.1.1.2 mrg auto_checking_feasibility (region_model_manager *mgr) : m_mgr (mgr) 319 1.1.1.2 mrg { 320 1.1.1.2 mrg m_mgr->begin_checking_feasibility (); 321 1.1.1.2 mrg } 322 1.1.1.2 mrg ~auto_checking_feasibility () 323 1.1.1.2 mrg { 324 1.1.1.2 mrg m_mgr->end_checking_feasibility (); 325 1.1.1.2 mrg } 326 1.1.1.2 mrg private: 327 1.1.1.2 mrg region_model_manager *m_mgr; 328 1.1.1.2 mrg }; 329 1.1.1.2 mrg 330 1.1.1.2 mrg /* Attempt to find the shortest feasible path from the origin to 331 1.1.1.2 mrg TARGET_ENODE by iteratively building a feasible_graph, in which 332 1.1.1.2 mrg every path to a feasible_node is feasible by construction. 333 1.1.1.2 mrg 334 1.1.1.2 mrg We effectively explore the tree of feasible paths in order of shortest 335 1.1.1.2 mrg path until we either find a feasible path to TARGET_ENODE, or hit 336 1.1.1.2 mrg a limit and give up. 337 1.1.1.2 mrg 338 1.1.1.2 mrg Preliminaries: 339 1.1.1.2 mrg - Find the shortest path from each node to the TARGET_ENODE (without 340 1.1.1.2 mrg checking feasibility), so that we can prioritize our worklist. 341 1.1.1.2 mrg - Construct a trimmed_graph: the subset of nodes/edges that 342 1.1.1.2 mrg are on a path that eventually reaches TARGET_ENODE. We will only need 343 1.1.1.2 mrg to consider these when considering the shortest feasible path. 344 1.1.1.2 mrg 345 1.1.1.2 mrg Build a feasible_graph, in which every path to a feasible_node 346 1.1.1.2 mrg is feasible by construction. 347 1.1.1.2 mrg We use a worklist to flatten the exploration into an iteration. 348 1.1.1.2 mrg Starting at the origin, find feasible out-edges within the trimmed graph. 349 1.1.1.2 mrg At each stage, choose the node for which if the remaining path were feasible, 350 1.1.1.2 mrg it would be the shortest path (summing the length of the known-feasible path 351 1.1.1.2 mrg so far with that of the remaining possibly-feasible path). 352 1.1.1.2 mrg This way, the first feasible path we find to TARGET_ENODE is the shortest. 353 1.1.1.2 mrg We start by trying the shortest possible path, but if that fails, 354 1.1.1.2 mrg we explore progressively longer paths, eventually trying iterations through 355 1.1.1.2 mrg loops. The exploration is captured in the feasible_graph, which can be 356 1.1.1.2 mrg dumped as a .dot file to visualize the exploration. The indices of the 357 1.1.1.2 mrg feasible_nodes show the order in which they were created. 358 1.1.1.2 mrg 359 1.1.1.2 mrg This is something of a brute-force approach, but the trimmed_graph 360 1.1.1.2 mrg hopefully keeps the complexity manageable. 361 1.1.1.2 mrg 362 1.1.1.2 mrg Terminate with failure when the number of infeasible edges exceeds 363 1.1.1.2 mrg a threshold (--param=analyzer-max-infeasible-edges=). 364 1.1.1.2 mrg This is guaranteed to eventually lead to terminatation, as 365 1.1.1.2 mrg we can't keep creating feasible nodes without eventually 366 1.1.1.2 mrg either reaching an infeasible edge, or reaching the 367 1.1.1.2 mrg TARGET_ENODE. Specifically, there can't be a cycle of 368 1.1.1.2 mrg feasible edges that doesn't reach the target_enode without 369 1.1.1.2 mrg an out-edge that either fails feasibility or gets closer 370 1.1.1.2 mrg to the TARGET_ENODE: on each iteration we are either: 371 1.1.1.2 mrg - effectively getting closer to the TARGET_ENODE (which can't 372 1.1.1.2 mrg continue forever without reaching the target), or 373 1.1.1.2 mrg - getting monotonically closer to the termination threshold. */ 374 1.1.1.2 mrg 375 1.1.1.2 mrg exploded_path * 376 1.1.1.2 mrg epath_finder::explore_feasible_paths (const exploded_node *target_enode, 377 1.1.1.2 mrg const char *desc, unsigned diag_idx) 378 1.1.1.2 mrg { 379 1.1.1.2 mrg logger *logger = get_logger (); 380 1.1.1.2 mrg LOG_SCOPE (logger); 381 1.1.1.2 mrg 382 1.1.1.2 mrg region_model_manager *mgr = m_eg.get_engine ()->get_model_manager (); 383 1.1.1.2 mrg 384 1.1.1.2 mrg /* Determine the shortest path to TARGET_ENODE from each node in 385 1.1.1.2 mrg the exploded graph. */ 386 1.1.1.2 mrg shortest_paths<eg_traits, exploded_path> sep 387 1.1.1.2 mrg (m_eg, target_enode, SPS_TO_GIVEN_TARGET); 388 1.1.1.2 mrg 389 1.1.1.2 mrg /* Construct a trimmed_graph: the subset of nodes/edges that 390 1.1.1.2 mrg are on a path that eventually reaches TARGET_ENODE. 391 1.1.1.2 mrg We only need to consider these when considering the shortest 392 1.1.1.2 mrg feasible path. */ 393 1.1.1.2 mrg trimmed_graph tg (m_eg, target_enode); 394 1.1.1.2 mrg 395 1.1.1.2 mrg if (flag_dump_analyzer_feasibility) 396 1.1.1.2 mrg dump_trimmed_graph (target_enode, desc, diag_idx, tg, sep); 397 1.1.1.2 mrg 398 1.1.1.2 mrg feasible_graph fg; 399 1.1.1.2 mrg feasible_worklist worklist (sep); 400 1.1.1.2 mrg 401 1.1.1.2 mrg /* Populate the worklist with the origin node. */ 402 1.1.1.2 mrg { 403 1.1.1.2 mrg feasibility_state init_state (mgr, m_eg.get_supergraph ()); 404 1.1.1.2 mrg feasible_node *origin = fg.add_node (m_eg.get_origin (), init_state, 0); 405 1.1.1.2 mrg worklist.add_node (origin); 406 1.1.1.2 mrg } 407 1.1.1.2 mrg 408 1.1.1.2 mrg /* Iteratively explore the tree of feasible paths in order of shortest 409 1.1.1.2 mrg path until we either find a feasible path to TARGET_ENODE, or hit 410 1.1.1.2 mrg a limit. */ 411 1.1.1.2 mrg 412 1.1.1.2 mrg /* Set this if we find a feasible path to TARGET_ENODE. */ 413 1.1.1.2 mrg exploded_path *best_path = NULL; 414 1.1.1.2 mrg 415 1.1.1.2 mrg { 416 1.1.1.2 mrg auto_checking_feasibility sentinel (mgr); 417 1.1.1.2 mrg 418 1.1.1.2 mrg while (process_worklist_item (&worklist, tg, &fg, target_enode, diag_idx, 419 1.1.1.2 mrg &best_path)) 420 1.1.1.2 mrg { 421 1.1.1.2 mrg /* Empty; the work is done within process_worklist_item. */ 422 1.1.1.2 mrg } 423 1.1.1.2 mrg } 424 1.1.1.2 mrg 425 1.1.1.2 mrg if (logger) 426 1.1.1.2 mrg { 427 1.1.1.2 mrg logger->log ("tg for sd: %i:", diag_idx); 428 1.1.1.2 mrg logger->inc_indent (); 429 1.1.1.2 mrg tg.log_stats (logger); 430 1.1.1.2 mrg logger->dec_indent (); 431 1.1.1.2 mrg 432 1.1.1.2 mrg logger->log ("fg for sd: %i:", diag_idx); 433 1.1.1.2 mrg logger->inc_indent (); 434 1.1.1.2 mrg fg.log_stats (logger); 435 1.1.1.2 mrg logger->dec_indent (); 436 1.1.1.2 mrg } 437 1.1.1.2 mrg 438 1.1.1.2 mrg /* Dump the feasible_graph. */ 439 1.1.1.2 mrg if (flag_dump_analyzer_feasibility) 440 1.1.1.2 mrg dump_feasible_graph (target_enode, desc, diag_idx, fg); 441 1.1.1.2 mrg 442 1.1.1.2 mrg return best_path; 443 1.1.1.2 mrg } 444 1.1.1.2 mrg 445 1.1.1.2 mrg /* Process the next item in WORKLIST, potentially adding new items 446 1.1.1.2 mrg based on feasible out-edges, and extending FG accordingly. 447 1.1.1.2 mrg Use TG to ignore out-edges that don't lead to TARGET_ENODE. 448 1.1.1.2 mrg Return true if the worklist processing should continue. 449 1.1.1.2 mrg Return false if the processing of the worklist should stop 450 1.1.1.2 mrg (either due to reaching TARGET_ENODE, or hitting a limit). 451 1.1.1.2 mrg Write to *OUT_BEST_PATH if stopping due to finding a feasible path 452 1.1.1.2 mrg to TARGET_ENODE. */ 453 1.1.1.2 mrg 454 1.1.1.2 mrg bool 455 1.1.1.2 mrg epath_finder::process_worklist_item (feasible_worklist *worklist, 456 1.1.1.2 mrg const trimmed_graph &tg, 457 1.1.1.2 mrg feasible_graph *fg, 458 1.1.1.2 mrg const exploded_node *target_enode, 459 1.1.1.2 mrg unsigned diag_idx, 460 1.1.1.2 mrg exploded_path **out_best_path) const 461 1.1.1.2 mrg { 462 1.1.1.2 mrg logger *logger = get_logger (); 463 1.1.1.2 mrg 464 1.1.1.2 mrg feasible_node *fnode = worklist->take_next (); 465 1.1.1.2 mrg if (!fnode) 466 1.1.1.2 mrg { 467 1.1.1.2 mrg if (logger) 468 1.1.1.2 mrg logger->log ("drained worklist for sd: %i" 469 1.1.1.2 mrg " without finding feasible path", 470 1.1.1.2 mrg diag_idx); 471 1.1.1.2 mrg return false; 472 1.1.1.2 mrg } 473 1.1.1.2 mrg 474 1.1.1.2 mrg log_scope s (logger, "fg worklist item", 475 1.1.1.2 mrg "considering FN: %i (EN: %i) for sd: %i", 476 1.1.1.2 mrg fnode->get_index (), fnode->get_inner_node ()->m_index, 477 1.1.1.2 mrg diag_idx); 478 1.1.1.2 mrg 479 1.1.1.2 mrg /* Iterate through all out-edges from this item. */ 480 1.1.1.2 mrg unsigned i; 481 1.1.1.2 mrg exploded_edge *succ_eedge; 482 1.1.1.2 mrg FOR_EACH_VEC_ELT (fnode->get_inner_node ()->m_succs, i, succ_eedge) 483 1.1.1.2 mrg { 484 1.1.1.2 mrg log_scope s (logger, "edge", "considering edge: EN:%i -> EN:%i", 485 1.1.1.2 mrg succ_eedge->m_src->m_index, 486 1.1.1.2 mrg succ_eedge->m_dest->m_index); 487 1.1.1.2 mrg /* Reject edges that aren't in the trimmed graph. */ 488 1.1.1.2 mrg if (!tg.contains_p (succ_eedge)) 489 1.1.1.2 mrg { 490 1.1.1.2 mrg if (logger) 491 1.1.1.2 mrg logger->log ("rejecting: not in trimmed graph"); 492 1.1.1.2 mrg continue; 493 1.1.1.2 mrg } 494 1.1.1.2 mrg 495 1.1.1.2 mrg feasibility_state succ_state (fnode->get_state ()); 496 1.1.1.2 mrg rejected_constraint *rc = NULL; 497 1.1.1.2 mrg if (succ_state.maybe_update_for_edge (logger, succ_eedge, &rc)) 498 1.1.1.2 mrg { 499 1.1.1.2 mrg gcc_assert (rc == NULL); 500 1.1.1.2 mrg feasible_node *succ_fnode 501 1.1.1.2 mrg = fg->add_node (succ_eedge->m_dest, 502 1.1.1.2 mrg succ_state, 503 1.1.1.2 mrg fnode->get_path_length () + 1); 504 1.1.1.2 mrg if (logger) 505 1.1.1.2 mrg logger->log ("accepting as FN: %i", succ_fnode->get_index ()); 506 1.1.1.2 mrg fg->add_edge (new feasible_edge (fnode, succ_fnode, succ_eedge)); 507 1.1.1.2 mrg 508 1.1.1.2 mrg /* Have we reached TARGET_ENODE? */ 509 1.1.1.2 mrg if (succ_fnode->get_inner_node () == target_enode) 510 1.1.1.2 mrg { 511 1.1.1.2 mrg if (logger) 512 1.1.1.2 mrg logger->log ("success: got feasible path to EN: %i (sd: %i)" 513 1.1.1.2 mrg " (length: %i)", 514 1.1.1.2 mrg target_enode->m_index, diag_idx, 515 1.1.1.2 mrg succ_fnode->get_path_length ()); 516 1.1.1.2 mrg *out_best_path = fg->make_epath (succ_fnode); 517 1.1.1.2 mrg if (flag_dump_analyzer_feasibility) 518 1.1.1.2 mrg dump_feasible_path (target_enode, diag_idx, *fg, *succ_fnode); 519 1.1.1.2 mrg 520 1.1.1.2 mrg /* Success: stop the worklist iteration. */ 521 1.1.1.2 mrg return false; 522 1.1.1.2 mrg } 523 1.1.1.2 mrg else 524 1.1.1.2 mrg worklist->add_node (succ_fnode); 525 1.1.1.2 mrg } 526 1.1.1.2 mrg else 527 1.1.1.2 mrg { 528 1.1.1.2 mrg if (logger) 529 1.1.1.2 mrg logger->log ("infeasible"); 530 1.1.1.2 mrg gcc_assert (rc); 531 1.1.1.2 mrg fg->add_feasibility_problem (fnode, 532 1.1.1.2 mrg succ_eedge, 533 1.1.1.2 mrg rc); 534 1.1.1.2 mrg 535 1.1.1.2 mrg /* Give up if there have been too many infeasible edges. */ 536 1.1.1.2 mrg if (fg->get_num_infeasible () 537 1.1.1.2 mrg > (unsigned)param_analyzer_max_infeasible_edges) 538 1.1.1.2 mrg { 539 1.1.1.2 mrg if (logger) 540 1.1.1.2 mrg logger->log ("too many infeasible edges (%i); giving up", 541 1.1.1.2 mrg fg->get_num_infeasible ()); 542 1.1.1.2 mrg return false; 543 1.1.1.2 mrg } 544 1.1.1.2 mrg } 545 1.1.1.2 mrg } 546 1.1.1.2 mrg 547 1.1.1.2 mrg /* Continue the worklist iteration. */ 548 1.1.1.2 mrg return true; 549 1.1.1.2 mrg } 550 1.1.1.2 mrg 551 1.1.1.2 mrg /* Helper class for epath_finder::dump_trimmed_graph 552 1.1.1.2 mrg to dump extra per-node information. 553 1.1.1.2 mrg Use SEP to add the length of the shortest path from each 554 1.1.1.2 mrg node to the target node to each node's dump. */ 555 1.1.1.2 mrg 556 1.1.1.2 mrg class dump_eg_with_shortest_path : public eg_traits::dump_args_t 557 1.1.1.2 mrg { 558 1.1.1.2 mrg public: 559 1.1.1.2 mrg dump_eg_with_shortest_path 560 1.1.1.2 mrg (const exploded_graph &eg, 561 1.1.1.2 mrg const shortest_paths<eg_traits, exploded_path> &sep) 562 1.1.1.2 mrg : dump_args_t (eg), 563 1.1.1.2 mrg m_sep (sep) 564 1.1.1.2 mrg { 565 1.1.1.2 mrg } 566 1.1.1.2 mrg 567 1.1.1.2 mrg void dump_extra_info (const exploded_node *enode, 568 1.1.1.2 mrg pretty_printer *pp) const FINAL OVERRIDE 569 1.1.1.2 mrg { 570 1.1.1.2 mrg pp_printf (pp, "sp: %i", m_sep.get_shortest_path (enode).length ()); 571 1.1.1.2 mrg pp_newline (pp); 572 1.1.1.2 mrg } 573 1.1.1.2 mrg 574 1.1.1.2 mrg private: 575 1.1.1.2 mrg const shortest_paths<eg_traits, exploded_path> &m_sep; 576 1.1.1.2 mrg }; 577 1.1.1.2 mrg 578 1.1.1.2 mrg /* Dump TG to "BASE_NAME.DESC.DIAG_IDX.to-enN.tg.dot", 579 1.1.1.2 mrg annotating each node with the length of the shortest path 580 1.1.1.2 mrg from that node to TARGET_ENODE (using SEP). */ 581 1.1.1.2 mrg 582 1.1.1.2 mrg void 583 1.1.1.2 mrg epath_finder:: 584 1.1.1.2 mrg dump_trimmed_graph (const exploded_node *target_enode, 585 1.1.1.2 mrg const char *desc, unsigned diag_idx, 586 1.1.1.2 mrg const trimmed_graph &tg, 587 1.1.1.2 mrg const shortest_paths<eg_traits, exploded_path> &sep) 588 1.1.1.2 mrg { 589 1.1.1.2 mrg auto_timevar tv (TV_ANALYZER_DUMP); 590 1.1.1.2 mrg dump_eg_with_shortest_path inner_args (m_eg, sep); 591 1.1.1.2 mrg trimmed_graph::dump_args_t args (inner_args); 592 1.1.1.2 mrg pretty_printer pp; 593 1.1.1.2 mrg pp_printf (&pp, "%s.%s.%i.to-en%i.tg.dot", 594 1.1.1.2 mrg dump_base_name, desc, diag_idx, target_enode->m_index); 595 1.1.1.2 mrg char *filename = xstrdup (pp_formatted_text (&pp)); 596 1.1.1.2 mrg tg.dump_dot (filename, NULL, args); 597 1.1.1.2 mrg free (filename); 598 1.1.1.2 mrg } 599 1.1.1.2 mrg 600 1.1.1.2 mrg /* Dump FG to "BASE_NAME.DESC.DIAG_IDX.to-enN.fg.dot". */ 601 1.1.1.2 mrg 602 1.1.1.2 mrg void 603 1.1.1.2 mrg epath_finder::dump_feasible_graph (const exploded_node *target_enode, 604 1.1.1.2 mrg const char *desc, unsigned diag_idx, 605 1.1.1.2 mrg const feasible_graph &fg) 606 1.1.1.2 mrg { 607 1.1.1.2 mrg auto_timevar tv (TV_ANALYZER_DUMP); 608 1.1.1.2 mrg exploded_graph::dump_args_t inner_args (m_eg); 609 1.1.1.2 mrg feasible_graph::dump_args_t args (inner_args); 610 1.1.1.2 mrg pretty_printer pp; 611 1.1.1.2 mrg pp_printf (&pp, "%s.%s.%i.to-en%i.fg.dot", 612 1.1.1.2 mrg dump_base_name, desc, diag_idx, target_enode->m_index); 613 1.1.1.2 mrg char *filename = xstrdup (pp_formatted_text (&pp)); 614 1.1.1.2 mrg fg.dump_dot (filename, NULL, args); 615 1.1.1.2 mrg free (filename); 616 1.1.1.2 mrg } 617 1.1.1.2 mrg 618 1.1.1.2 mrg /* Dump the path to FNODE to "BASE_NAME.DIAG_IDX.to-enN.fpath.txt". */ 619 1.1.1.2 mrg 620 1.1.1.2 mrg void 621 1.1.1.2 mrg epath_finder::dump_feasible_path (const exploded_node *target_enode, 622 1.1.1.2 mrg unsigned diag_idx, 623 1.1.1.2 mrg const feasible_graph &fg, 624 1.1.1.2 mrg const feasible_node &fnode) const 625 1.1.1.2 mrg { 626 1.1.1.2 mrg auto_timevar tv (TV_ANALYZER_DUMP); 627 1.1.1.2 mrg pretty_printer pp; 628 1.1.1.2 mrg pp_printf (&pp, "%s.%i.to-en%i.fpath.txt", 629 1.1.1.2 mrg dump_base_name, diag_idx, target_enode->m_index); 630 1.1.1.2 mrg char *filename = xstrdup (pp_formatted_text (&pp)); 631 1.1.1.2 mrg fg.dump_feasible_path (fnode, filename); 632 1.1.1.2 mrg free (filename); 633 1.1.1.2 mrg } 634 1.1.1.2 mrg 635 1.1 mrg /* class saved_diagnostic. */ 636 1.1 mrg 637 1.1 mrg /* saved_diagnostic's ctor. 638 1.1 mrg Take ownership of D and STMT_FINDER. */ 639 1.1 mrg 640 1.1 mrg saved_diagnostic::saved_diagnostic (const state_machine *sm, 641 1.1 mrg const exploded_node *enode, 642 1.1 mrg const supernode *snode, const gimple *stmt, 643 1.1 mrg stmt_finder *stmt_finder, 644 1.1.1.2 mrg tree var, 645 1.1.1.2 mrg const svalue *sval, 646 1.1.1.2 mrg state_machine::state_t state, 647 1.1.1.2 mrg pending_diagnostic *d, 648 1.1.1.2 mrg unsigned idx) 649 1.1 mrg : m_sm (sm), m_enode (enode), m_snode (snode), m_stmt (stmt), 650 1.1 mrg /* stmt_finder could be on-stack; we want our own copy that can 651 1.1 mrg outlive that. */ 652 1.1 mrg m_stmt_finder (stmt_finder ? stmt_finder->clone () : NULL), 653 1.1.1.2 mrg m_var (var), m_sval (sval), m_state (state), 654 1.1 mrg m_d (d), m_trailing_eedge (NULL), 655 1.1.1.2 mrg m_idx (idx), 656 1.1.1.2 mrg m_best_epath (NULL), m_problem (NULL), 657 1.1.1.2 mrg m_notes () 658 1.1 mrg { 659 1.1 mrg gcc_assert (m_stmt || m_stmt_finder); 660 1.1 mrg 661 1.1 mrg /* We must have an enode in order to be able to look for paths 662 1.1 mrg through the exploded_graph to this diagnostic. */ 663 1.1 mrg gcc_assert (m_enode); 664 1.1 mrg } 665 1.1 mrg 666 1.1 mrg /* saved_diagnostic's dtor. */ 667 1.1 mrg 668 1.1 mrg saved_diagnostic::~saved_diagnostic () 669 1.1 mrg { 670 1.1 mrg delete m_stmt_finder; 671 1.1 mrg delete m_d; 672 1.1.1.2 mrg delete m_best_epath; 673 1.1 mrg delete m_problem; 674 1.1 mrg } 675 1.1 mrg 676 1.1 mrg bool 677 1.1 mrg saved_diagnostic::operator== (const saved_diagnostic &other) const 678 1.1 mrg { 679 1.1.1.2 mrg if (m_notes.length () != other.m_notes.length ()) 680 1.1.1.2 mrg return false; 681 1.1.1.2 mrg for (unsigned i = 0; i < m_notes.length (); i++) 682 1.1.1.2 mrg if (!m_notes[i]->equal_p (*other.m_notes[i])) 683 1.1.1.2 mrg return false; 684 1.1 mrg return (m_sm == other.m_sm 685 1.1 mrg /* We don't compare m_enode. */ 686 1.1 mrg && m_snode == other.m_snode 687 1.1 mrg && m_stmt == other.m_stmt 688 1.1 mrg /* We don't compare m_stmt_finder. */ 689 1.1 mrg && pending_diagnostic::same_tree_p (m_var, other.m_var) 690 1.1 mrg && m_state == other.m_state 691 1.1 mrg && m_d->equal_p (*other.m_d) 692 1.1 mrg && m_trailing_eedge == other.m_trailing_eedge); 693 1.1 mrg } 694 1.1 mrg 695 1.1.1.2 mrg /* Add PN to this diagnostic, taking ownership of it. */ 696 1.1.1.2 mrg 697 1.1.1.2 mrg void 698 1.1.1.2 mrg saved_diagnostic::add_note (pending_note *pn) 699 1.1.1.2 mrg { 700 1.1.1.2 mrg gcc_assert (pn); 701 1.1.1.2 mrg m_notes.safe_push (pn); 702 1.1.1.2 mrg } 703 1.1.1.2 mrg 704 1.1.1.2 mrg /* Return a new json::object of the form 705 1.1.1.2 mrg {"sm": optional str, 706 1.1.1.2 mrg "enode": int, 707 1.1.1.2 mrg "snode": int, 708 1.1.1.2 mrg "sval": optional str, 709 1.1.1.2 mrg "state": optional str, 710 1.1.1.2 mrg "path_length": optional int, 711 1.1.1.2 mrg "pending_diagnostic": str, 712 1.1.1.2 mrg "idx": int}. */ 713 1.1.1.2 mrg 714 1.1.1.2 mrg json::object * 715 1.1.1.2 mrg saved_diagnostic::to_json () const 716 1.1.1.2 mrg { 717 1.1.1.2 mrg json::object *sd_obj = new json::object (); 718 1.1.1.2 mrg 719 1.1.1.2 mrg if (m_sm) 720 1.1.1.2 mrg sd_obj->set ("sm", new json::string (m_sm->get_name ())); 721 1.1.1.2 mrg sd_obj->set ("enode", new json::integer_number (m_enode->m_index)); 722 1.1.1.2 mrg sd_obj->set ("snode", new json::integer_number (m_snode->m_index)); 723 1.1.1.2 mrg if (m_sval) 724 1.1.1.2 mrg sd_obj->set ("sval", m_sval->to_json ()); 725 1.1.1.2 mrg if (m_state) 726 1.1.1.2 mrg sd_obj->set ("state", m_state->to_json ()); 727 1.1.1.2 mrg if (m_best_epath) 728 1.1.1.2 mrg sd_obj->set ("path_length", new json::integer_number (get_epath_length ())); 729 1.1.1.2 mrg sd_obj->set ("pending_diagnostic", new json::string (m_d->get_kind ())); 730 1.1.1.2 mrg sd_obj->set ("idx", new json::integer_number (m_idx)); 731 1.1.1.2 mrg 732 1.1.1.2 mrg /* We're not yet JSONifying the following fields: 733 1.1.1.2 mrg const gimple *m_stmt; 734 1.1.1.2 mrg stmt_finder *m_stmt_finder; 735 1.1.1.2 mrg tree m_var; 736 1.1.1.2 mrg exploded_edge *m_trailing_eedge; 737 1.1.1.2 mrg enum status m_status; 738 1.1.1.2 mrg feasibility_problem *m_problem; 739 1.1.1.2 mrg auto_delete_vec <pending_note> m_notes; 740 1.1.1.2 mrg */ 741 1.1.1.2 mrg 742 1.1.1.2 mrg return sd_obj; 743 1.1.1.2 mrg } 744 1.1.1.2 mrg 745 1.1.1.2 mrg /* Dump this to PP in a form suitable for use as an id in .dot output. */ 746 1.1.1.2 mrg 747 1.1.1.2 mrg void 748 1.1.1.2 mrg saved_diagnostic::dump_dot_id (pretty_printer *pp) const 749 1.1.1.2 mrg { 750 1.1.1.2 mrg pp_printf (pp, "sd_%i", m_idx); 751 1.1.1.2 mrg } 752 1.1.1.2 mrg 753 1.1.1.2 mrg /* Dump this to PP in a form suitable for use as a node in .dot output. */ 754 1.1.1.2 mrg 755 1.1.1.2 mrg void 756 1.1.1.2 mrg saved_diagnostic::dump_as_dot_node (pretty_printer *pp) const 757 1.1.1.2 mrg { 758 1.1.1.2 mrg dump_dot_id (pp); 759 1.1.1.2 mrg pp_printf (pp, 760 1.1.1.2 mrg " [shape=none,margin=0,style=filled,fillcolor=\"red\",label=\""); 761 1.1.1.2 mrg pp_write_text_to_stream (pp); 762 1.1.1.2 mrg 763 1.1.1.2 mrg /* Node label. */ 764 1.1.1.2 mrg pp_printf (pp, "DIAGNOSTIC: %s (sd: %i)\n", 765 1.1.1.2 mrg m_d->get_kind (), m_idx); 766 1.1.1.2 mrg if (m_sm) 767 1.1.1.2 mrg { 768 1.1.1.2 mrg pp_printf (pp, "sm: %s", m_sm->get_name ()); 769 1.1.1.2 mrg if (m_state) 770 1.1.1.2 mrg { 771 1.1.1.2 mrg pp_printf (pp, "; state: "); 772 1.1.1.2 mrg m_state->dump_to_pp (pp); 773 1.1.1.2 mrg } 774 1.1.1.2 mrg pp_newline (pp); 775 1.1.1.2 mrg } 776 1.1.1.2 mrg if (m_stmt) 777 1.1.1.2 mrg { 778 1.1.1.2 mrg pp_string (pp, "stmt: "); 779 1.1.1.2 mrg pp_gimple_stmt_1 (pp, m_stmt, 0, (dump_flags_t)0); 780 1.1.1.2 mrg pp_newline (pp); 781 1.1.1.2 mrg } 782 1.1.1.2 mrg if (m_var) 783 1.1.1.2 mrg pp_printf (pp, "var: %qE\n", m_var); 784 1.1.1.2 mrg if (m_sval) 785 1.1.1.2 mrg { 786 1.1.1.2 mrg pp_string (pp, "sval: "); 787 1.1.1.2 mrg m_sval->dump_to_pp (pp, true); 788 1.1.1.2 mrg pp_newline (pp); 789 1.1.1.2 mrg } 790 1.1.1.2 mrg if (m_best_epath) 791 1.1.1.2 mrg pp_printf (pp, "path length: %i\n", get_epath_length ()); 792 1.1.1.2 mrg 793 1.1.1.2 mrg pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/true); 794 1.1.1.2 mrg pp_string (pp, "\"];\n\n"); 795 1.1.1.2 mrg 796 1.1.1.2 mrg /* Show links to duplicates. */ 797 1.1.1.2 mrg for (auto iter : m_duplicates) 798 1.1.1.2 mrg { 799 1.1.1.2 mrg dump_dot_id (pp); 800 1.1.1.2 mrg pp_string (pp, " -> "); 801 1.1.1.2 mrg iter->dump_dot_id (pp); 802 1.1.1.2 mrg pp_string (pp, " [style=\"dotted\" arrowhead=\"none\"];"); 803 1.1.1.2 mrg pp_newline (pp); 804 1.1.1.2 mrg } 805 1.1.1.2 mrg } 806 1.1.1.2 mrg 807 1.1.1.2 mrg /* Use PF to find the best exploded_path for this saved_diagnostic, 808 1.1.1.2 mrg and store it in m_best_epath. 809 1.1.1.2 mrg If m_stmt is still NULL, use m_stmt_finder on the epath to populate 810 1.1.1.2 mrg m_stmt. 811 1.1.1.2 mrg Return true if a best path was found. */ 812 1.1.1.2 mrg 813 1.1.1.2 mrg bool 814 1.1.1.2 mrg saved_diagnostic::calc_best_epath (epath_finder *pf) 815 1.1.1.2 mrg { 816 1.1.1.2 mrg logger *logger = pf->get_logger (); 817 1.1.1.2 mrg LOG_SCOPE (logger); 818 1.1.1.2 mrg delete m_best_epath; 819 1.1.1.2 mrg delete m_problem; 820 1.1.1.2 mrg m_problem = NULL; 821 1.1.1.2 mrg 822 1.1.1.2 mrg m_best_epath = pf->get_best_epath (m_enode, m_d->get_kind (), m_idx, 823 1.1.1.2 mrg &m_problem); 824 1.1.1.2 mrg 825 1.1.1.2 mrg /* Handle failure to find a feasible path. */ 826 1.1.1.2 mrg if (m_best_epath == NULL) 827 1.1.1.2 mrg return false; 828 1.1.1.2 mrg 829 1.1.1.2 mrg gcc_assert (m_best_epath); 830 1.1.1.2 mrg if (m_stmt == NULL) 831 1.1.1.2 mrg { 832 1.1.1.2 mrg gcc_assert (m_stmt_finder); 833 1.1.1.2 mrg m_stmt = m_stmt_finder->find_stmt (*m_best_epath); 834 1.1.1.2 mrg } 835 1.1.1.2 mrg gcc_assert (m_stmt); 836 1.1.1.2 mrg 837 1.1.1.2 mrg return true; 838 1.1.1.2 mrg } 839 1.1.1.2 mrg 840 1.1.1.2 mrg unsigned 841 1.1.1.2 mrg saved_diagnostic::get_epath_length () const 842 1.1.1.2 mrg { 843 1.1.1.2 mrg gcc_assert (m_best_epath); 844 1.1.1.2 mrg return m_best_epath->length (); 845 1.1.1.2 mrg } 846 1.1.1.2 mrg 847 1.1.1.2 mrg /* Record that OTHER (and its duplicates) are duplicates 848 1.1.1.2 mrg of this saved_diagnostic. */ 849 1.1.1.2 mrg 850 1.1.1.2 mrg void 851 1.1.1.2 mrg saved_diagnostic::add_duplicate (saved_diagnostic *other) 852 1.1.1.2 mrg { 853 1.1.1.2 mrg gcc_assert (other); 854 1.1.1.2 mrg m_duplicates.reserve (m_duplicates.length () 855 1.1.1.2 mrg + other->m_duplicates.length () 856 1.1.1.2 mrg + 1); 857 1.1.1.2 mrg m_duplicates.splice (other->m_duplicates); 858 1.1.1.2 mrg other->m_duplicates.truncate (0); 859 1.1.1.2 mrg m_duplicates.safe_push (other); 860 1.1.1.2 mrg } 861 1.1.1.2 mrg 862 1.1.1.2 mrg /* Return true if this diagnostic supercedes OTHER, and that OTHER should 863 1.1.1.2 mrg therefore not be emitted. */ 864 1.1.1.2 mrg 865 1.1.1.2 mrg bool 866 1.1.1.2 mrg saved_diagnostic::supercedes_p (const saved_diagnostic &other) const 867 1.1.1.2 mrg { 868 1.1.1.2 mrg /* They should be at the same stmt. */ 869 1.1.1.2 mrg if (m_stmt != other.m_stmt) 870 1.1.1.2 mrg return false; 871 1.1.1.2 mrg return m_d->supercedes_p (*other.m_d); 872 1.1.1.2 mrg } 873 1.1.1.2 mrg 874 1.1.1.2 mrg /* Emit any pending notes owned by this diagnostic. */ 875 1.1.1.2 mrg 876 1.1.1.2 mrg void 877 1.1.1.2 mrg saved_diagnostic::emit_any_notes () const 878 1.1.1.2 mrg { 879 1.1.1.2 mrg for (auto pn : m_notes) 880 1.1.1.2 mrg pn->emit (); 881 1.1.1.2 mrg } 882 1.1.1.2 mrg 883 1.1 mrg /* State for building a checker_path from a particular exploded_path. 884 1.1 mrg In particular, this precomputes reachability information: the set of 885 1.1 mrg source enodes for which a path be found to the diagnostic enode. */ 886 1.1 mrg 887 1.1 mrg class path_builder 888 1.1 mrg { 889 1.1 mrg public: 890 1.1 mrg path_builder (const exploded_graph &eg, 891 1.1.1.2 mrg const exploded_path &epath, 892 1.1.1.2 mrg const feasibility_problem *problem, 893 1.1.1.2 mrg const saved_diagnostic &sd) 894 1.1 mrg : m_eg (eg), 895 1.1 mrg m_diag_enode (epath.get_final_enode ()), 896 1.1.1.2 mrg m_sd (sd), 897 1.1.1.2 mrg m_reachability (eg, m_diag_enode), 898 1.1.1.2 mrg m_feasibility_problem (problem) 899 1.1 mrg {} 900 1.1 mrg 901 1.1 mrg const exploded_node *get_diag_node () const { return m_diag_enode; } 902 1.1 mrg 903 1.1.1.2 mrg pending_diagnostic *get_pending_diagnostic () const 904 1.1.1.2 mrg { 905 1.1.1.2 mrg return m_sd.m_d; 906 1.1.1.2 mrg } 907 1.1.1.2 mrg 908 1.1 mrg bool reachable_from_p (const exploded_node *src_enode) const 909 1.1 mrg { 910 1.1 mrg return m_reachability.reachable_from_p (src_enode); 911 1.1 mrg } 912 1.1 mrg 913 1.1 mrg const extrinsic_state &get_ext_state () const { return m_eg.get_ext_state (); } 914 1.1 mrg 915 1.1.1.2 mrg const feasibility_problem *get_feasibility_problem () const 916 1.1.1.2 mrg { 917 1.1.1.2 mrg return m_feasibility_problem; 918 1.1.1.2 mrg } 919 1.1.1.2 mrg 920 1.1.1.2 mrg const state_machine *get_sm () const { return m_sd.m_sm; } 921 1.1.1.2 mrg 922 1.1 mrg private: 923 1.1 mrg typedef reachability<eg_traits> enode_reachability; 924 1.1 mrg 925 1.1 mrg const exploded_graph &m_eg; 926 1.1 mrg 927 1.1 mrg /* The enode where the diagnostic occurs. */ 928 1.1 mrg const exploded_node *m_diag_enode; 929 1.1 mrg 930 1.1.1.2 mrg const saved_diagnostic &m_sd; 931 1.1.1.2 mrg 932 1.1 mrg /* Precompute all enodes from which the diagnostic is reachable. */ 933 1.1 mrg enode_reachability m_reachability; 934 1.1.1.2 mrg 935 1.1.1.2 mrg const feasibility_problem *m_feasibility_problem; 936 1.1 mrg }; 937 1.1 mrg 938 1.1.1.2 mrg /* Determine the emission location for PD at STMT in FUN. */ 939 1.1.1.2 mrg 940 1.1.1.2 mrg static location_t 941 1.1.1.2 mrg get_emission_location (const gimple *stmt, function *fun, 942 1.1.1.2 mrg const pending_diagnostic &pd) 943 1.1.1.2 mrg { 944 1.1.1.2 mrg location_t loc = get_stmt_location (stmt, fun); 945 1.1.1.2 mrg 946 1.1.1.2 mrg /* Allow the pending_diagnostic to fix up the location. */ 947 1.1.1.2 mrg loc = pd.fixup_location (loc); 948 1.1.1.2 mrg 949 1.1.1.2 mrg return loc; 950 1.1.1.2 mrg } 951 1.1.1.2 mrg 952 1.1 mrg /* class diagnostic_manager. */ 953 1.1 mrg 954 1.1 mrg /* diagnostic_manager's ctor. */ 955 1.1 mrg 956 1.1.1.2 mrg diagnostic_manager::diagnostic_manager (logger *logger, engine *eng, 957 1.1.1.2 mrg int verbosity) 958 1.1.1.2 mrg : log_user (logger), m_eng (eng), m_verbosity (verbosity), 959 1.1.1.2 mrg m_num_disabled_diagnostics (0) 960 1.1 mrg { 961 1.1 mrg } 962 1.1 mrg 963 1.1.1.2 mrg /* Queue pending_diagnostic D at ENODE for later emission. 964 1.1.1.2 mrg Return true/false signifying if the diagnostic was actually added. 965 1.1.1.2 mrg Take ownership of D (or delete it). */ 966 1.1 mrg 967 1.1.1.2 mrg bool 968 1.1 mrg diagnostic_manager::add_diagnostic (const state_machine *sm, 969 1.1.1.2 mrg exploded_node *enode, 970 1.1 mrg const supernode *snode, const gimple *stmt, 971 1.1 mrg stmt_finder *finder, 972 1.1.1.2 mrg tree var, 973 1.1.1.2 mrg const svalue *sval, 974 1.1.1.2 mrg state_machine::state_t state, 975 1.1 mrg pending_diagnostic *d) 976 1.1 mrg { 977 1.1 mrg LOG_FUNC (get_logger ()); 978 1.1 mrg 979 1.1 mrg /* We must have an enode in order to be able to look for paths 980 1.1 mrg through the exploded_graph to the diagnostic. */ 981 1.1 mrg gcc_assert (enode); 982 1.1 mrg 983 1.1.1.2 mrg /* If this warning is ultimately going to be rejected by a -Wno-analyzer-* 984 1.1.1.2 mrg flag, reject it now. 985 1.1.1.2 mrg We can only do this for diagnostics where we already know the stmt, 986 1.1.1.2 mrg and thus can determine the emission location. */ 987 1.1.1.2 mrg if (stmt) 988 1.1.1.2 mrg { 989 1.1.1.2 mrg location_t loc = get_emission_location (stmt, snode->m_fun, *d); 990 1.1.1.2 mrg int option = d->get_controlling_option (); 991 1.1.1.2 mrg if (!warning_enabled_at (loc, option)) 992 1.1.1.2 mrg { 993 1.1.1.2 mrg if (get_logger ()) 994 1.1.1.2 mrg get_logger ()->log ("rejecting disabled warning %qs", 995 1.1.1.2 mrg d->get_kind ()); 996 1.1.1.2 mrg delete d; 997 1.1.1.2 mrg m_num_disabled_diagnostics++; 998 1.1.1.2 mrg return false; 999 1.1.1.2 mrg } 1000 1.1.1.2 mrg } 1001 1.1.1.2 mrg 1002 1.1 mrg saved_diagnostic *sd 1003 1.1.1.2 mrg = new saved_diagnostic (sm, enode, snode, stmt, finder, var, sval, 1004 1.1.1.2 mrg state, d, m_saved_diagnostics.length ()); 1005 1.1 mrg m_saved_diagnostics.safe_push (sd); 1006 1.1.1.2 mrg enode->add_diagnostic (sd); 1007 1.1 mrg if (get_logger ()) 1008 1.1.1.2 mrg log ("adding saved diagnostic %i at SN %i to EN %i: %qs", 1009 1.1.1.2 mrg sd->get_index (), 1010 1.1.1.2 mrg snode->m_index, enode->m_index, d->get_kind ()); 1011 1.1.1.2 mrg return true; 1012 1.1 mrg } 1013 1.1 mrg 1014 1.1.1.2 mrg /* Queue pending_diagnostic D at ENODE for later emission. 1015 1.1.1.2 mrg Return true/false signifying if the diagnostic was actually added. 1016 1.1.1.2 mrg Take ownership of D (or delete it). */ 1017 1.1 mrg 1018 1.1.1.2 mrg bool 1019 1.1.1.2 mrg diagnostic_manager::add_diagnostic (exploded_node *enode, 1020 1.1 mrg const supernode *snode, const gimple *stmt, 1021 1.1 mrg stmt_finder *finder, 1022 1.1 mrg pending_diagnostic *d) 1023 1.1 mrg { 1024 1.1 mrg gcc_assert (enode); 1025 1.1.1.2 mrg return add_diagnostic (NULL, enode, snode, stmt, finder, NULL_TREE, 1026 1.1.1.2 mrg NULL, 0, d); 1027 1.1.1.2 mrg } 1028 1.1.1.2 mrg 1029 1.1.1.2 mrg /* Add PN to the most recent saved_diagnostic. */ 1030 1.1.1.2 mrg 1031 1.1.1.2 mrg void 1032 1.1.1.2 mrg diagnostic_manager::add_note (pending_note *pn) 1033 1.1.1.2 mrg { 1034 1.1.1.2 mrg LOG_FUNC (get_logger ()); 1035 1.1.1.2 mrg gcc_assert (pn); 1036 1.1.1.2 mrg 1037 1.1.1.2 mrg /* Get most recent saved_diagnostic. */ 1038 1.1.1.2 mrg gcc_assert (m_saved_diagnostics.length () > 0); 1039 1.1.1.2 mrg saved_diagnostic *sd = m_saved_diagnostics[m_saved_diagnostics.length () - 1]; 1040 1.1.1.2 mrg sd->add_note (pn); 1041 1.1.1.2 mrg } 1042 1.1.1.2 mrg 1043 1.1.1.2 mrg /* Return a new json::object of the form 1044 1.1.1.2 mrg {"diagnostics" : [obj for saved_diagnostic]}. */ 1045 1.1.1.2 mrg 1046 1.1.1.2 mrg json::object * 1047 1.1.1.2 mrg diagnostic_manager::to_json () const 1048 1.1.1.2 mrg { 1049 1.1.1.2 mrg json::object *dm_obj = new json::object (); 1050 1.1.1.2 mrg 1051 1.1.1.2 mrg { 1052 1.1.1.2 mrg json::array *sd_arr = new json::array (); 1053 1.1.1.2 mrg int i; 1054 1.1.1.2 mrg saved_diagnostic *sd; 1055 1.1.1.2 mrg FOR_EACH_VEC_ELT (m_saved_diagnostics, i, sd) 1056 1.1.1.2 mrg sd_arr->append (sd->to_json ()); 1057 1.1.1.2 mrg dm_obj->set ("diagnostics", sd_arr); 1058 1.1.1.2 mrg } 1059 1.1.1.2 mrg 1060 1.1.1.2 mrg return dm_obj; 1061 1.1 mrg } 1062 1.1 mrg 1063 1.1 mrg /* A class for identifying sets of duplicated pending_diagnostic. 1064 1.1 mrg 1065 1.1.1.2 mrg We want to find the simplest saved_diagnostic amongst those that share a 1066 1.1 mrg dedupe_key. */ 1067 1.1 mrg 1068 1.1 mrg class dedupe_key 1069 1.1 mrg { 1070 1.1 mrg public: 1071 1.1.1.2 mrg dedupe_key (const saved_diagnostic &sd) 1072 1.1 mrg : m_sd (sd), m_stmt (sd.m_stmt) 1073 1.1 mrg { 1074 1.1 mrg gcc_assert (m_stmt); 1075 1.1 mrg } 1076 1.1 mrg 1077 1.1 mrg hashval_t hash () const 1078 1.1 mrg { 1079 1.1 mrg inchash::hash hstate; 1080 1.1 mrg hstate.add_ptr (m_stmt); 1081 1.1 mrg // TODO: m_sd 1082 1.1 mrg return hstate.end (); 1083 1.1 mrg } 1084 1.1 mrg bool operator== (const dedupe_key &other) const 1085 1.1 mrg { 1086 1.1 mrg return (m_sd == other.m_sd 1087 1.1 mrg && m_stmt == other.m_stmt); 1088 1.1 mrg } 1089 1.1 mrg 1090 1.1 mrg location_t get_location () const 1091 1.1 mrg { 1092 1.1 mrg return m_stmt->location; 1093 1.1 mrg } 1094 1.1 mrg 1095 1.1 mrg /* A qsort comparator for use by dedupe_winners::emit_best 1096 1.1 mrg to sort them into location_t order. */ 1097 1.1 mrg 1098 1.1 mrg static int 1099 1.1 mrg comparator (const void *p1, const void *p2) 1100 1.1 mrg { 1101 1.1 mrg const dedupe_key *pk1 = *(const dedupe_key * const *)p1; 1102 1.1 mrg const dedupe_key *pk2 = *(const dedupe_key * const *)p2; 1103 1.1 mrg 1104 1.1 mrg location_t loc1 = pk1->get_location (); 1105 1.1 mrg location_t loc2 = pk2->get_location (); 1106 1.1 mrg 1107 1.1.1.2 mrg if (int cmp = linemap_compare_locations (line_table, loc2, loc1)) 1108 1.1.1.2 mrg return cmp; 1109 1.1.1.2 mrg if (int cmp = ((int)pk1->m_sd.get_epath_length () 1110 1.1.1.2 mrg - (int)pk2->m_sd.get_epath_length ())) 1111 1.1.1.2 mrg return cmp; 1112 1.1.1.2 mrg if (int cmp = strcmp (pk1->m_sd.m_d->get_kind (), 1113 1.1.1.2 mrg pk2->m_sd.m_d->get_kind ())) 1114 1.1.1.2 mrg return cmp; 1115 1.1.1.2 mrg return 0; 1116 1.1 mrg } 1117 1.1 mrg 1118 1.1 mrg const saved_diagnostic &m_sd; 1119 1.1 mrg const gimple *m_stmt; 1120 1.1 mrg }; 1121 1.1 mrg 1122 1.1 mrg /* Traits for use by dedupe_winners. */ 1123 1.1 mrg 1124 1.1 mrg class dedupe_hash_map_traits 1125 1.1 mrg { 1126 1.1 mrg public: 1127 1.1 mrg typedef const dedupe_key *key_type; 1128 1.1.1.2 mrg typedef saved_diagnostic *value_type; 1129 1.1.1.2 mrg typedef saved_diagnostic *compare_type; 1130 1.1 mrg 1131 1.1 mrg static inline hashval_t hash (const key_type &v) 1132 1.1 mrg { 1133 1.1 mrg return v->hash (); 1134 1.1 mrg } 1135 1.1 mrg static inline bool equal_keys (const key_type &k1, const key_type &k2) 1136 1.1 mrg { 1137 1.1 mrg return *k1 == *k2; 1138 1.1 mrg } 1139 1.1 mrg template <typename T> 1140 1.1 mrg static inline void remove (T &) 1141 1.1 mrg { 1142 1.1 mrg // TODO 1143 1.1 mrg } 1144 1.1 mrg template <typename T> 1145 1.1 mrg static inline void mark_deleted (T &entry) 1146 1.1 mrg { 1147 1.1 mrg entry.m_key = reinterpret_cast<key_type> (1); 1148 1.1 mrg } 1149 1.1 mrg template <typename T> 1150 1.1 mrg static inline void mark_empty (T &entry) 1151 1.1 mrg { 1152 1.1 mrg entry.m_key = NULL; 1153 1.1 mrg } 1154 1.1 mrg template <typename T> 1155 1.1 mrg static inline bool is_deleted (const T &entry) 1156 1.1 mrg { 1157 1.1 mrg return entry.m_key == reinterpret_cast<key_type> (1); 1158 1.1 mrg } 1159 1.1 mrg template <typename T> 1160 1.1 mrg static inline bool is_empty (const T &entry) 1161 1.1 mrg { 1162 1.1 mrg return entry.m_key == NULL; 1163 1.1 mrg } 1164 1.1 mrg static const bool empty_zero_p = true; 1165 1.1 mrg }; 1166 1.1 mrg 1167 1.1 mrg /* A class for deduplicating diagnostics and finding (and emitting) the 1168 1.1.1.2 mrg best saved_diagnostic within each partition. */ 1169 1.1 mrg 1170 1.1 mrg class dedupe_winners 1171 1.1 mrg { 1172 1.1 mrg public: 1173 1.1 mrg ~dedupe_winners () 1174 1.1 mrg { 1175 1.1.1.2 mrg /* Delete all keys, but not the saved_diagnostics. */ 1176 1.1 mrg for (map_t::iterator iter = m_map.begin (); 1177 1.1 mrg iter != m_map.end (); 1178 1.1 mrg ++iter) 1179 1.1.1.2 mrg delete (*iter).first; 1180 1.1 mrg } 1181 1.1 mrg 1182 1.1.1.2 mrg /* Determine an exploded_path for SD using PF and, if it's feasible, 1183 1.1.1.2 mrg determine if SD is the best seen so far for its dedupe_key. 1184 1.1.1.2 mrg Record the winning SD for each dedupe_key. */ 1185 1.1 mrg 1186 1.1 mrg void add (logger *logger, 1187 1.1.1.2 mrg epath_finder *pf, 1188 1.1 mrg saved_diagnostic *sd) 1189 1.1 mrg { 1190 1.1.1.2 mrg /* Determine best epath for SD. */ 1191 1.1.1.2 mrg if (!sd->calc_best_epath (pf)) 1192 1.1.1.2 mrg return; 1193 1.1 mrg 1194 1.1.1.2 mrg dedupe_key *key = new dedupe_key (*sd); 1195 1.1.1.2 mrg if (saved_diagnostic **slot = m_map.get (key)) 1196 1.1 mrg { 1197 1.1 mrg if (logger) 1198 1.1 mrg logger->log ("already have this dedupe_key"); 1199 1.1 mrg 1200 1.1.1.2 mrg saved_diagnostic *cur_best_sd = *slot; 1201 1.1 mrg 1202 1.1.1.2 mrg if (sd->get_epath_length () < cur_best_sd->get_epath_length ()) 1203 1.1 mrg { 1204 1.1 mrg /* We've got a shorter path for the key; replace 1205 1.1.1.2 mrg the current candidate, marking it as a duplicate of SD. */ 1206 1.1 mrg if (logger) 1207 1.1 mrg logger->log ("length %i is better than existing length %i;" 1208 1.1 mrg " taking over this dedupe_key", 1209 1.1.1.2 mrg sd->get_epath_length (), 1210 1.1.1.2 mrg cur_best_sd->get_epath_length ()); 1211 1.1.1.2 mrg sd->add_duplicate (cur_best_sd); 1212 1.1.1.2 mrg *slot = sd; 1213 1.1 mrg } 1214 1.1 mrg else 1215 1.1.1.2 mrg /* We haven't beaten the current best candidate; add SD 1216 1.1.1.2 mrg as a duplicate of it. */ 1217 1.1 mrg { 1218 1.1 mrg if (logger) 1219 1.1 mrg logger->log ("length %i isn't better than existing length %i;" 1220 1.1 mrg " dropping this candidate", 1221 1.1.1.2 mrg sd->get_epath_length (), 1222 1.1.1.2 mrg cur_best_sd->get_epath_length ()); 1223 1.1.1.2 mrg cur_best_sd->add_duplicate (sd); 1224 1.1 mrg } 1225 1.1 mrg delete key; 1226 1.1 mrg } 1227 1.1 mrg else 1228 1.1 mrg { 1229 1.1 mrg /* This is the first candidate for this key. */ 1230 1.1.1.2 mrg m_map.put (key, sd); 1231 1.1 mrg if (logger) 1232 1.1 mrg logger->log ("first candidate for this dedupe_key"); 1233 1.1 mrg } 1234 1.1 mrg } 1235 1.1 mrg 1236 1.1.1.2 mrg /* Handle interactions between the dedupe winners, so that some 1237 1.1.1.2 mrg diagnostics can supercede others (of different kinds). 1238 1.1.1.2 mrg 1239 1.1.1.2 mrg We want use-after-free to supercede use-of-unitialized-value, 1240 1.1.1.2 mrg so that if we have these at the same stmt, we don't emit 1241 1.1.1.2 mrg a use-of-uninitialized, just the use-after-free. */ 1242 1.1.1.2 mrg 1243 1.1.1.2 mrg void handle_interactions (diagnostic_manager *dm) 1244 1.1.1.2 mrg { 1245 1.1.1.2 mrg LOG_SCOPE (dm->get_logger ()); 1246 1.1.1.2 mrg auto_vec<const dedupe_key *> superceded; 1247 1.1.1.2 mrg for (auto outer : m_map) 1248 1.1.1.2 mrg { 1249 1.1.1.2 mrg const saved_diagnostic *outer_sd = outer.second; 1250 1.1.1.2 mrg for (auto inner : m_map) 1251 1.1.1.2 mrg { 1252 1.1.1.2 mrg const saved_diagnostic *inner_sd = inner.second; 1253 1.1.1.2 mrg if (inner_sd->supercedes_p (*outer_sd)) 1254 1.1.1.2 mrg { 1255 1.1.1.2 mrg superceded.safe_push (outer.first); 1256 1.1.1.2 mrg if (dm->get_logger ()) 1257 1.1.1.2 mrg dm->log ("sd[%i] \"%s\" superceded by sd[%i] \"%s\"", 1258 1.1.1.2 mrg outer_sd->get_index (), outer_sd->m_d->get_kind (), 1259 1.1.1.2 mrg inner_sd->get_index (), inner_sd->m_d->get_kind ()); 1260 1.1.1.2 mrg break; 1261 1.1.1.2 mrg } 1262 1.1.1.2 mrg } 1263 1.1.1.2 mrg } 1264 1.1.1.2 mrg for (auto iter : superceded) 1265 1.1.1.2 mrg m_map.remove (iter); 1266 1.1.1.2 mrg } 1267 1.1.1.2 mrg 1268 1.1 mrg /* Emit the simplest diagnostic within each set. */ 1269 1.1 mrg 1270 1.1 mrg void emit_best (diagnostic_manager *dm, 1271 1.1 mrg const exploded_graph &eg) 1272 1.1 mrg { 1273 1.1 mrg LOG_SCOPE (dm->get_logger ()); 1274 1.1 mrg 1275 1.1 mrg /* Get keys into a vec for sorting. */ 1276 1.1 mrg auto_vec<const dedupe_key *> keys (m_map.elements ()); 1277 1.1 mrg for (map_t::iterator iter = m_map.begin (); 1278 1.1 mrg iter != m_map.end (); 1279 1.1 mrg ++iter) 1280 1.1 mrg keys.quick_push ((*iter).first); 1281 1.1 mrg 1282 1.1 mrg dm->log ("# keys after de-duplication: %i", keys.length ()); 1283 1.1 mrg 1284 1.1 mrg /* Sort into a good emission order. */ 1285 1.1 mrg keys.qsort (dedupe_key::comparator); 1286 1.1 mrg 1287 1.1.1.2 mrg /* Emit the best saved_diagnostics for each key. */ 1288 1.1 mrg int i; 1289 1.1 mrg const dedupe_key *key; 1290 1.1 mrg FOR_EACH_VEC_ELT (keys, i, key) 1291 1.1 mrg { 1292 1.1.1.2 mrg saved_diagnostic **slot = m_map.get (key); 1293 1.1 mrg gcc_assert (*slot); 1294 1.1.1.2 mrg const saved_diagnostic *sd = *slot; 1295 1.1.1.2 mrg dm->emit_saved_diagnostic (eg, *sd); 1296 1.1 mrg } 1297 1.1 mrg } 1298 1.1 mrg 1299 1.1 mrg private: 1300 1.1.1.2 mrg /* This maps from each dedupe_key to a current best saved_diagnostic. */ 1301 1.1 mrg 1302 1.1.1.2 mrg typedef hash_map<const dedupe_key *, saved_diagnostic *, 1303 1.1 mrg dedupe_hash_map_traits> map_t; 1304 1.1 mrg map_t m_map; 1305 1.1 mrg }; 1306 1.1 mrg 1307 1.1 mrg /* Emit all saved diagnostics. */ 1308 1.1 mrg 1309 1.1 mrg void 1310 1.1 mrg diagnostic_manager::emit_saved_diagnostics (const exploded_graph &eg) 1311 1.1 mrg { 1312 1.1 mrg LOG_SCOPE (get_logger ()); 1313 1.1 mrg auto_timevar tv (TV_ANALYZER_DIAGNOSTICS); 1314 1.1 mrg log ("# saved diagnostics: %i", m_saved_diagnostics.length ()); 1315 1.1.1.2 mrg log ("# disabled diagnostics: %i", m_num_disabled_diagnostics); 1316 1.1 mrg if (get_logger ()) 1317 1.1 mrg { 1318 1.1 mrg unsigned i; 1319 1.1 mrg saved_diagnostic *sd; 1320 1.1 mrg FOR_EACH_VEC_ELT (m_saved_diagnostics, i, sd) 1321 1.1 mrg log ("[%i] sd: %qs at EN: %i, SN: %i", 1322 1.1 mrg i, sd->m_d->get_kind (), sd->m_enode->m_index, 1323 1.1 mrg sd->m_snode->m_index); 1324 1.1 mrg } 1325 1.1 mrg 1326 1.1 mrg if (m_saved_diagnostics.length () == 0) 1327 1.1 mrg return; 1328 1.1 mrg 1329 1.1 mrg /* Compute the shortest_paths once, sharing it between all diagnostics. */ 1330 1.1.1.2 mrg epath_finder pf (eg); 1331 1.1 mrg 1332 1.1 mrg /* Iterate through all saved diagnostics, adding them to a dedupe_winners 1333 1.1 mrg instance. This partitions the saved diagnostics by dedupe_key, 1334 1.1 mrg generating exploded_paths for them, and retaining the best one in each 1335 1.1 mrg partition. */ 1336 1.1 mrg dedupe_winners best_candidates; 1337 1.1 mrg 1338 1.1 mrg int i; 1339 1.1 mrg saved_diagnostic *sd; 1340 1.1 mrg FOR_EACH_VEC_ELT (m_saved_diagnostics, i, sd) 1341 1.1.1.2 mrg best_candidates.add (get_logger (), &pf, sd); 1342 1.1.1.2 mrg 1343 1.1.1.2 mrg best_candidates.handle_interactions (this); 1344 1.1 mrg 1345 1.1 mrg /* For each dedupe-key, call emit_saved_diagnostic on the "best" 1346 1.1 mrg saved_diagnostic. */ 1347 1.1 mrg best_candidates.emit_best (this, eg); 1348 1.1 mrg } 1349 1.1 mrg 1350 1.1.1.2 mrg /* Given a saved_diagnostic SD with m_best_epath through EG, 1351 1.1 mrg create an checker_path of suitable events and use it to call 1352 1.1 mrg SD's underlying pending_diagnostic "emit" vfunc to emit a diagnostic. */ 1353 1.1 mrg 1354 1.1 mrg void 1355 1.1 mrg diagnostic_manager::emit_saved_diagnostic (const exploded_graph &eg, 1356 1.1.1.2 mrg const saved_diagnostic &sd) 1357 1.1 mrg { 1358 1.1 mrg LOG_SCOPE (get_logger ()); 1359 1.1 mrg log ("sd: %qs at SN: %i", sd.m_d->get_kind (), sd.m_snode->m_index); 1360 1.1.1.2 mrg log ("num dupes: %i", sd.get_num_dupes ()); 1361 1.1 mrg 1362 1.1 mrg pretty_printer *pp = global_dc->printer->clone (); 1363 1.1 mrg 1364 1.1.1.2 mrg const exploded_path *epath = sd.get_best_epath (); 1365 1.1.1.2 mrg gcc_assert (epath); 1366 1.1.1.2 mrg 1367 1.1 mrg /* Precompute all enodes from which the diagnostic is reachable. */ 1368 1.1.1.2 mrg path_builder pb (eg, *epath, sd.get_feasibility_problem (), sd); 1369 1.1 mrg 1370 1.1 mrg /* This is the diagnostic_path subclass that will be built for 1371 1.1 mrg the diagnostic. */ 1372 1.1 mrg checker_path emission_path; 1373 1.1 mrg 1374 1.1 mrg /* Populate emission_path with a full description of EPATH. */ 1375 1.1.1.2 mrg build_emission_path (pb, *epath, &emission_path); 1376 1.1 mrg 1377 1.1 mrg /* Now prune it to just cover the most pertinent events. */ 1378 1.1.1.2 mrg prune_path (&emission_path, sd.m_sm, sd.m_sval, sd.m_state); 1379 1.1 mrg 1380 1.1 mrg /* Add a final event to the path, covering the diagnostic itself. 1381 1.1 mrg We use the final enode from the epath, which might be different from 1382 1.1 mrg the sd.m_enode, as the dedupe code doesn't care about enodes, just 1383 1.1 mrg snodes. */ 1384 1.1.1.2 mrg emission_path.add_final_event (sd.m_sm, epath->get_final_enode (), sd.m_stmt, 1385 1.1 mrg sd.m_var, sd.m_state); 1386 1.1 mrg 1387 1.1 mrg /* The "final" event might not be final; if the saved_diagnostic has a 1388 1.1 mrg trailing eedge stashed, add any events for it. This is for use 1389 1.1 mrg in handling longjmp, to show where a longjmp is rewinding to. */ 1390 1.1 mrg if (sd.m_trailing_eedge) 1391 1.1.1.2 mrg add_events_for_eedge (pb, *sd.m_trailing_eedge, &emission_path, NULL); 1392 1.1 mrg 1393 1.1 mrg emission_path.prepare_for_emission (sd.m_d); 1394 1.1 mrg 1395 1.1.1.2 mrg location_t loc 1396 1.1.1.2 mrg = get_emission_location (sd.m_stmt, sd.m_snode->m_fun, *sd.m_d); 1397 1.1.1.2 mrg 1398 1.1.1.2 mrg /* Allow the pending_diagnostic to fix up the locations of events. */ 1399 1.1.1.2 mrg emission_path.fixup_locations (sd.m_d); 1400 1.1.1.2 mrg 1401 1.1.1.2 mrg gcc_rich_location rich_loc (loc); 1402 1.1 mrg rich_loc.set_path (&emission_path); 1403 1.1 mrg 1404 1.1 mrg auto_diagnostic_group d; 1405 1.1 mrg auto_cfun sentinel (sd.m_snode->m_fun); 1406 1.1 mrg if (sd.m_d->emit (&rich_loc)) 1407 1.1 mrg { 1408 1.1.1.2 mrg sd.emit_any_notes (); 1409 1.1.1.2 mrg 1410 1.1.1.2 mrg unsigned num_dupes = sd.get_num_dupes (); 1411 1.1 mrg if (flag_analyzer_show_duplicate_count && num_dupes > 0) 1412 1.1.1.2 mrg inform_n (loc, num_dupes, 1413 1.1 mrg "%i duplicate", "%i duplicates", 1414 1.1 mrg num_dupes); 1415 1.1.1.2 mrg if (flag_dump_analyzer_exploded_paths) 1416 1.1.1.2 mrg { 1417 1.1.1.2 mrg auto_timevar tv (TV_ANALYZER_DUMP); 1418 1.1.1.2 mrg pretty_printer pp; 1419 1.1.1.2 mrg pp_printf (&pp, "%s.%i.%s.epath.txt", 1420 1.1.1.2 mrg dump_base_name, sd.get_index (), sd.m_d->get_kind ()); 1421 1.1.1.2 mrg char *filename = xstrdup (pp_formatted_text (&pp)); 1422 1.1.1.2 mrg epath->dump_to_file (filename, eg.get_ext_state ()); 1423 1.1.1.2 mrg inform (loc, "exploded path written to %qs", filename); 1424 1.1.1.2 mrg free (filename); 1425 1.1 mrg } 1426 1.1 mrg } 1427 1.1.1.2 mrg delete pp; 1428 1.1 mrg } 1429 1.1 mrg 1430 1.1 mrg /* Emit a "path" of events to EMISSION_PATH describing the exploded path 1431 1.1 mrg EPATH within EG. */ 1432 1.1 mrg 1433 1.1 mrg void 1434 1.1 mrg diagnostic_manager::build_emission_path (const path_builder &pb, 1435 1.1 mrg const exploded_path &epath, 1436 1.1 mrg checker_path *emission_path) const 1437 1.1 mrg { 1438 1.1 mrg LOG_SCOPE (get_logger ()); 1439 1.1.1.2 mrg 1440 1.1.1.2 mrg interesting_t interest; 1441 1.1.1.2 mrg pb.get_pending_diagnostic ()->mark_interesting_stuff (&interest); 1442 1.1.1.2 mrg 1443 1.1.1.2 mrg /* Add region creation events for any globals of interest, at the 1444 1.1.1.2 mrg beginning of the path. */ 1445 1.1.1.2 mrg { 1446 1.1.1.2 mrg for (auto reg : interest.m_region_creation) 1447 1.1.1.2 mrg switch (reg->get_memory_space ()) 1448 1.1.1.2 mrg { 1449 1.1.1.2 mrg default: 1450 1.1.1.2 mrg continue; 1451 1.1.1.2 mrg case MEMSPACE_CODE: 1452 1.1.1.2 mrg case MEMSPACE_GLOBALS: 1453 1.1.1.2 mrg case MEMSPACE_READONLY_DATA: 1454 1.1.1.2 mrg { 1455 1.1.1.2 mrg const region *base_reg = reg->get_base_region (); 1456 1.1.1.2 mrg if (tree decl = base_reg->maybe_get_decl ()) 1457 1.1.1.2 mrg if (DECL_P (decl) 1458 1.1.1.2 mrg && DECL_SOURCE_LOCATION (decl) != UNKNOWN_LOCATION) 1459 1.1.1.2 mrg { 1460 1.1.1.2 mrg emission_path->add_region_creation_event 1461 1.1.1.2 mrg (reg, 1462 1.1.1.2 mrg DECL_SOURCE_LOCATION (decl), 1463 1.1.1.2 mrg NULL_TREE, 1464 1.1.1.2 mrg 0); 1465 1.1.1.2 mrg } 1466 1.1.1.2 mrg } 1467 1.1.1.2 mrg } 1468 1.1.1.2 mrg } 1469 1.1.1.2 mrg 1470 1.1.1.2 mrg /* Walk EPATH, adding events as appropriate. */ 1471 1.1 mrg for (unsigned i = 0; i < epath.m_edges.length (); i++) 1472 1.1 mrg { 1473 1.1 mrg const exploded_edge *eedge = epath.m_edges[i]; 1474 1.1.1.2 mrg add_events_for_eedge (pb, *eedge, emission_path, &interest); 1475 1.1 mrg } 1476 1.1 mrg } 1477 1.1 mrg 1478 1.1 mrg /* Subclass of state_change_visitor that creates state_change_event 1479 1.1 mrg instances. */ 1480 1.1 mrg 1481 1.1 mrg class state_change_event_creator : public state_change_visitor 1482 1.1 mrg { 1483 1.1 mrg public: 1484 1.1.1.2 mrg state_change_event_creator (const path_builder &pb, 1485 1.1.1.2 mrg const exploded_edge &eedge, 1486 1.1 mrg checker_path *emission_path) 1487 1.1.1.2 mrg : m_pb (pb), 1488 1.1.1.2 mrg m_eedge (eedge), 1489 1.1 mrg m_emission_path (emission_path) 1490 1.1 mrg {} 1491 1.1 mrg 1492 1.1 mrg bool on_global_state_change (const state_machine &sm, 1493 1.1 mrg state_machine::state_t src_sm_val, 1494 1.1 mrg state_machine::state_t dst_sm_val) 1495 1.1 mrg FINAL OVERRIDE 1496 1.1 mrg { 1497 1.1.1.2 mrg if (&sm != m_pb.get_sm ()) 1498 1.1.1.2 mrg return false; 1499 1.1 mrg const exploded_node *src_node = m_eedge.m_src; 1500 1.1 mrg const program_point &src_point = src_node->get_point (); 1501 1.1 mrg const int src_stack_depth = src_point.get_stack_depth (); 1502 1.1 mrg const exploded_node *dst_node = m_eedge.m_dest; 1503 1.1 mrg const gimple *stmt = src_point.get_stmt (); 1504 1.1 mrg const supernode *supernode = src_point.get_supernode (); 1505 1.1 mrg const program_state &dst_state = dst_node->get_state (); 1506 1.1 mrg 1507 1.1 mrg int stack_depth = src_stack_depth; 1508 1.1 mrg 1509 1.1 mrg m_emission_path->add_event (new state_change_event (supernode, 1510 1.1 mrg stmt, 1511 1.1 mrg stack_depth, 1512 1.1 mrg sm, 1513 1.1.1.2 mrg NULL, 1514 1.1 mrg src_sm_val, 1515 1.1 mrg dst_sm_val, 1516 1.1.1.2 mrg NULL, 1517 1.1 mrg dst_state)); 1518 1.1 mrg return false; 1519 1.1 mrg } 1520 1.1 mrg 1521 1.1 mrg bool on_state_change (const state_machine &sm, 1522 1.1 mrg state_machine::state_t src_sm_val, 1523 1.1 mrg state_machine::state_t dst_sm_val, 1524 1.1.1.2 mrg const svalue *sval, 1525 1.1.1.2 mrg const svalue *dst_origin_sval) FINAL OVERRIDE 1526 1.1 mrg { 1527 1.1.1.2 mrg if (&sm != m_pb.get_sm ()) 1528 1.1.1.2 mrg return false; 1529 1.1 mrg const exploded_node *src_node = m_eedge.m_src; 1530 1.1 mrg const program_point &src_point = src_node->get_point (); 1531 1.1 mrg const int src_stack_depth = src_point.get_stack_depth (); 1532 1.1 mrg const exploded_node *dst_node = m_eedge.m_dest; 1533 1.1 mrg const gimple *stmt = src_point.get_stmt (); 1534 1.1 mrg const supernode *supernode = src_point.get_supernode (); 1535 1.1 mrg const program_state &dst_state = dst_node->get_state (); 1536 1.1 mrg 1537 1.1 mrg int stack_depth = src_stack_depth; 1538 1.1 mrg 1539 1.1 mrg if (m_eedge.m_sedge 1540 1.1 mrg && m_eedge.m_sedge->m_kind == SUPEREDGE_CFG_EDGE) 1541 1.1 mrg { 1542 1.1 mrg supernode = src_point.get_supernode (); 1543 1.1 mrg stmt = supernode->get_last_stmt (); 1544 1.1 mrg stack_depth = src_stack_depth; 1545 1.1 mrg } 1546 1.1 mrg 1547 1.1 mrg /* Bulletproofing for state changes at calls/returns; 1548 1.1 mrg TODO: is there a better way? */ 1549 1.1 mrg if (!stmt) 1550 1.1 mrg return false; 1551 1.1 mrg 1552 1.1 mrg m_emission_path->add_event (new state_change_event (supernode, 1553 1.1 mrg stmt, 1554 1.1 mrg stack_depth, 1555 1.1 mrg sm, 1556 1.1.1.2 mrg sval, 1557 1.1 mrg src_sm_val, 1558 1.1 mrg dst_sm_val, 1559 1.1.1.2 mrg dst_origin_sval, 1560 1.1 mrg dst_state)); 1561 1.1 mrg return false; 1562 1.1 mrg } 1563 1.1 mrg 1564 1.1.1.2 mrg const path_builder &m_pb; 1565 1.1 mrg const exploded_edge &m_eedge; 1566 1.1 mrg checker_path *m_emission_path; 1567 1.1 mrg }; 1568 1.1 mrg 1569 1.1 mrg /* Compare SRC_STATE and DST_STATE (which use EXT_STATE), and call 1570 1.1 mrg VISITOR's on_state_change for every sm-state change that occurs 1571 1.1 mrg to a tree, and on_global_state_change for every global state change 1572 1.1 mrg that occurs. 1573 1.1 mrg 1574 1.1 mrg This determines the state changes that ought to be reported to 1575 1.1 mrg the user: a combination of the effects of changes to sm_state_map 1576 1.1 mrg (which maps svalues to sm-states), and of region_model changes 1577 1.1 mrg (which map trees to svalues). 1578 1.1 mrg 1579 1.1 mrg Bail out early and return true if any call to on_global_state_change 1580 1.1 mrg or on_state_change returns true, otherwise return false. 1581 1.1 mrg 1582 1.1 mrg This is split out to make it easier to experiment with changes to 1583 1.1 mrg exploded_node granularity (so that we can observe what state changes 1584 1.1 mrg lead to state_change_events being emitted). */ 1585 1.1 mrg 1586 1.1 mrg bool 1587 1.1 mrg for_each_state_change (const program_state &src_state, 1588 1.1 mrg const program_state &dst_state, 1589 1.1 mrg const extrinsic_state &ext_state, 1590 1.1 mrg state_change_visitor *visitor) 1591 1.1 mrg { 1592 1.1 mrg gcc_assert (src_state.m_checker_states.length () 1593 1.1 mrg == ext_state.get_num_checkers ()); 1594 1.1 mrg gcc_assert (dst_state.m_checker_states.length () 1595 1.1 mrg == ext_state.get_num_checkers ()); 1596 1.1 mrg for (unsigned i = 0; i < ext_state.get_num_checkers (); i++) 1597 1.1 mrg { 1598 1.1 mrg const state_machine &sm = ext_state.get_sm (i); 1599 1.1 mrg const sm_state_map &src_smap = *src_state.m_checker_states[i]; 1600 1.1 mrg const sm_state_map &dst_smap = *dst_state.m_checker_states[i]; 1601 1.1 mrg 1602 1.1 mrg /* Add events for any global state changes. */ 1603 1.1 mrg if (src_smap.get_global_state () != dst_smap.get_global_state ()) 1604 1.1 mrg if (visitor->on_global_state_change (sm, 1605 1.1 mrg src_smap.get_global_state (), 1606 1.1 mrg dst_smap.get_global_state ())) 1607 1.1 mrg return true; 1608 1.1 mrg 1609 1.1 mrg /* Add events for per-svalue state changes. */ 1610 1.1 mrg for (sm_state_map::iterator_t iter = dst_smap.begin (); 1611 1.1 mrg iter != dst_smap.end (); 1612 1.1 mrg ++iter) 1613 1.1 mrg { 1614 1.1.1.2 mrg const svalue *sval = (*iter).first; 1615 1.1 mrg state_machine::state_t dst_sm_val = (*iter).second.m_state; 1616 1.1.1.2 mrg state_machine::state_t src_sm_val 1617 1.1.1.2 mrg = src_smap.get_state (sval, ext_state); 1618 1.1.1.2 mrg if (dst_sm_val != src_sm_val) 1619 1.1 mrg { 1620 1.1.1.2 mrg const svalue *origin_sval = (*iter).second.m_origin; 1621 1.1.1.2 mrg if (visitor->on_state_change (sm, src_sm_val, dst_sm_val, 1622 1.1.1.2 mrg sval, origin_sval)) 1623 1.1.1.2 mrg return true; 1624 1.1 mrg } 1625 1.1 mrg } 1626 1.1 mrg } 1627 1.1 mrg return false; 1628 1.1 mrg } 1629 1.1 mrg 1630 1.1.1.2 mrg /* An sm_context for adding state_change_event on assignments to NULL, 1631 1.1.1.2 mrg where the default state isn't m_start. Storing such state in the 1632 1.1.1.2 mrg sm_state_map would lead to bloat of the exploded_graph, so we want 1633 1.1.1.2 mrg to leave it as a default state, and inject state change events here 1634 1.1.1.2 mrg when we have a diagnostic. 1635 1.1.1.2 mrg Find transitions of constants, for handling on_zero_assignment. */ 1636 1.1.1.2 mrg 1637 1.1.1.2 mrg struct null_assignment_sm_context : public sm_context 1638 1.1.1.2 mrg { 1639 1.1.1.2 mrg null_assignment_sm_context (int sm_idx, 1640 1.1.1.2 mrg const state_machine &sm, 1641 1.1.1.2 mrg const program_state *old_state, 1642 1.1.1.2 mrg const program_state *new_state, 1643 1.1.1.2 mrg const gimple *stmt, 1644 1.1.1.2 mrg const program_point *point, 1645 1.1.1.2 mrg checker_path *emission_path, 1646 1.1.1.2 mrg const extrinsic_state &ext_state) 1647 1.1.1.2 mrg : sm_context (sm_idx, sm), m_old_state (old_state), m_new_state (new_state), 1648 1.1.1.2 mrg m_stmt (stmt), m_point (point), m_emission_path (emission_path), 1649 1.1.1.2 mrg m_ext_state (ext_state) 1650 1.1.1.2 mrg { 1651 1.1.1.2 mrg } 1652 1.1.1.2 mrg 1653 1.1.1.2 mrg tree get_fndecl_for_call (const gcall */*call*/) FINAL OVERRIDE 1654 1.1.1.2 mrg { 1655 1.1.1.2 mrg return NULL_TREE; 1656 1.1.1.2 mrg } 1657 1.1.1.2 mrg 1658 1.1.1.2 mrg state_machine::state_t get_state (const gimple *stmt ATTRIBUTE_UNUSED, 1659 1.1.1.2 mrg tree var) FINAL OVERRIDE 1660 1.1.1.2 mrg { 1661 1.1.1.2 mrg const svalue *var_old_sval 1662 1.1.1.2 mrg = m_old_state->m_region_model->get_rvalue (var, NULL); 1663 1.1.1.2 mrg const sm_state_map *old_smap = m_old_state->m_checker_states[m_sm_idx]; 1664 1.1.1.2 mrg 1665 1.1.1.2 mrg state_machine::state_t current 1666 1.1.1.2 mrg = old_smap->get_state (var_old_sval, m_ext_state); 1667 1.1.1.2 mrg 1668 1.1.1.2 mrg return current; 1669 1.1.1.2 mrg } 1670 1.1.1.2 mrg 1671 1.1.1.2 mrg state_machine::state_t get_state (const gimple *stmt ATTRIBUTE_UNUSED, 1672 1.1.1.2 mrg const svalue *sval) FINAL OVERRIDE 1673 1.1.1.2 mrg { 1674 1.1.1.2 mrg const sm_state_map *old_smap = m_old_state->m_checker_states[m_sm_idx]; 1675 1.1.1.2 mrg state_machine::state_t current = old_smap->get_state (sval, m_ext_state); 1676 1.1.1.2 mrg return current; 1677 1.1.1.2 mrg } 1678 1.1.1.2 mrg 1679 1.1.1.2 mrg void set_next_state (const gimple *stmt, 1680 1.1.1.2 mrg tree var, 1681 1.1.1.2 mrg state_machine::state_t to, 1682 1.1.1.2 mrg tree origin ATTRIBUTE_UNUSED) FINAL OVERRIDE 1683 1.1.1.2 mrg { 1684 1.1.1.2 mrg state_machine::state_t from = get_state (stmt, var); 1685 1.1.1.2 mrg if (from != m_sm.get_start_state ()) 1686 1.1.1.2 mrg return; 1687 1.1.1.2 mrg 1688 1.1.1.2 mrg const svalue *var_new_sval 1689 1.1.1.2 mrg = m_new_state->m_region_model->get_rvalue (var, NULL); 1690 1.1.1.2 mrg const supernode *supernode = m_point->get_supernode (); 1691 1.1.1.2 mrg int stack_depth = m_point->get_stack_depth (); 1692 1.1.1.2 mrg 1693 1.1.1.2 mrg m_emission_path->add_event (new state_change_event (supernode, 1694 1.1.1.2 mrg m_stmt, 1695 1.1.1.2 mrg stack_depth, 1696 1.1.1.2 mrg m_sm, 1697 1.1.1.2 mrg var_new_sval, 1698 1.1.1.2 mrg from, to, 1699 1.1.1.2 mrg NULL, 1700 1.1.1.2 mrg *m_new_state)); 1701 1.1.1.2 mrg } 1702 1.1.1.2 mrg 1703 1.1.1.2 mrg void set_next_state (const gimple *stmt, 1704 1.1.1.2 mrg const svalue *sval, 1705 1.1.1.2 mrg state_machine::state_t to, 1706 1.1.1.2 mrg tree origin ATTRIBUTE_UNUSED) FINAL OVERRIDE 1707 1.1.1.2 mrg { 1708 1.1.1.2 mrg state_machine::state_t from = get_state (stmt, sval); 1709 1.1.1.2 mrg if (from != m_sm.get_start_state ()) 1710 1.1.1.2 mrg return; 1711 1.1.1.2 mrg 1712 1.1.1.2 mrg const supernode *supernode = m_point->get_supernode (); 1713 1.1.1.2 mrg int stack_depth = m_point->get_stack_depth (); 1714 1.1.1.2 mrg 1715 1.1.1.2 mrg m_emission_path->add_event (new state_change_event (supernode, 1716 1.1.1.2 mrg m_stmt, 1717 1.1.1.2 mrg stack_depth, 1718 1.1.1.2 mrg m_sm, 1719 1.1.1.2 mrg sval, 1720 1.1.1.2 mrg from, to, 1721 1.1.1.2 mrg NULL, 1722 1.1.1.2 mrg *m_new_state)); 1723 1.1.1.2 mrg } 1724 1.1.1.2 mrg 1725 1.1.1.2 mrg void warn (const supernode *, const gimple *, 1726 1.1.1.2 mrg tree, pending_diagnostic *d) FINAL OVERRIDE 1727 1.1.1.2 mrg { 1728 1.1.1.2 mrg delete d; 1729 1.1.1.2 mrg } 1730 1.1.1.2 mrg 1731 1.1.1.2 mrg tree get_diagnostic_tree (tree expr) FINAL OVERRIDE 1732 1.1.1.2 mrg { 1733 1.1.1.2 mrg return expr; 1734 1.1.1.2 mrg } 1735 1.1.1.2 mrg 1736 1.1.1.2 mrg tree get_diagnostic_tree (const svalue *sval) FINAL OVERRIDE 1737 1.1.1.2 mrg { 1738 1.1.1.2 mrg return m_new_state->m_region_model->get_representative_tree (sval); 1739 1.1.1.2 mrg } 1740 1.1.1.2 mrg 1741 1.1.1.2 mrg state_machine::state_t get_global_state () const FINAL OVERRIDE 1742 1.1.1.2 mrg { 1743 1.1.1.2 mrg return 0; 1744 1.1.1.2 mrg } 1745 1.1.1.2 mrg 1746 1.1.1.2 mrg void set_global_state (state_machine::state_t) FINAL OVERRIDE 1747 1.1.1.2 mrg { 1748 1.1.1.2 mrg /* No-op. */ 1749 1.1.1.2 mrg } 1750 1.1.1.2 mrg 1751 1.1.1.2 mrg void on_custom_transition (custom_transition *) FINAL OVERRIDE 1752 1.1.1.2 mrg { 1753 1.1.1.2 mrg } 1754 1.1.1.2 mrg 1755 1.1.1.2 mrg tree is_zero_assignment (const gimple *stmt) FINAL OVERRIDE 1756 1.1.1.2 mrg { 1757 1.1.1.2 mrg const gassign *assign_stmt = dyn_cast <const gassign *> (stmt); 1758 1.1.1.2 mrg if (!assign_stmt) 1759 1.1.1.2 mrg return NULL_TREE; 1760 1.1.1.2 mrg if (const svalue *sval 1761 1.1.1.2 mrg = m_new_state->m_region_model->get_gassign_result (assign_stmt, NULL)) 1762 1.1.1.2 mrg if (tree cst = sval->maybe_get_constant ()) 1763 1.1.1.2 mrg if (::zerop(cst)) 1764 1.1.1.2 mrg return gimple_assign_lhs (assign_stmt); 1765 1.1.1.2 mrg return NULL_TREE; 1766 1.1.1.2 mrg } 1767 1.1.1.2 mrg 1768 1.1.1.2 mrg const program_state *get_old_program_state () const FINAL OVERRIDE 1769 1.1.1.2 mrg { 1770 1.1.1.2 mrg return m_old_state; 1771 1.1.1.2 mrg } 1772 1.1.1.2 mrg 1773 1.1.1.2 mrg const program_state *m_old_state; 1774 1.1.1.2 mrg const program_state *m_new_state; 1775 1.1.1.2 mrg const gimple *m_stmt; 1776 1.1.1.2 mrg const program_point *m_point; 1777 1.1.1.2 mrg checker_path *m_emission_path; 1778 1.1.1.2 mrg const extrinsic_state &m_ext_state; 1779 1.1.1.2 mrg }; 1780 1.1.1.2 mrg 1781 1.1 mrg /* Subroutine of diagnostic_manager::build_emission_path. 1782 1.1 mrg Add any events for EEDGE to EMISSION_PATH. */ 1783 1.1 mrg 1784 1.1 mrg void 1785 1.1 mrg diagnostic_manager::add_events_for_eedge (const path_builder &pb, 1786 1.1 mrg const exploded_edge &eedge, 1787 1.1.1.2 mrg checker_path *emission_path, 1788 1.1.1.2 mrg interesting_t *interest) const 1789 1.1 mrg { 1790 1.1 mrg const exploded_node *src_node = eedge.m_src; 1791 1.1 mrg const program_point &src_point = src_node->get_point (); 1792 1.1.1.2 mrg const int src_stack_depth = src_point.get_stack_depth (); 1793 1.1 mrg const exploded_node *dst_node = eedge.m_dest; 1794 1.1 mrg const program_point &dst_point = dst_node->get_point (); 1795 1.1 mrg const int dst_stack_depth = dst_point.get_stack_depth (); 1796 1.1 mrg if (get_logger ()) 1797 1.1 mrg { 1798 1.1 mrg get_logger ()->start_log_line (); 1799 1.1 mrg pretty_printer *pp = get_logger ()->get_printer (); 1800 1.1 mrg pp_printf (pp, "EN %i -> EN %i: ", 1801 1.1 mrg eedge.m_src->m_index, 1802 1.1 mrg eedge.m_dest->m_index); 1803 1.1 mrg src_point.print (pp, format (false)); 1804 1.1 mrg pp_string (pp, "-> "); 1805 1.1 mrg dst_point.print (pp, format (false)); 1806 1.1 mrg get_logger ()->end_log_line (); 1807 1.1 mrg } 1808 1.1 mrg const program_state &src_state = src_node->get_state (); 1809 1.1 mrg const program_state &dst_state = dst_node->get_state (); 1810 1.1 mrg 1811 1.1 mrg /* Add state change events for the states that have changed. 1812 1.1 mrg We add these before events for superedges, so that if we have a 1813 1.1 mrg state_change_event due to following an edge, we'll get this sequence 1814 1.1 mrg of events: 1815 1.1 mrg 1816 1.1 mrg | if (!ptr) 1817 1.1 mrg | ~ 1818 1.1 mrg | | 1819 1.1 mrg | (1) assuming 'ptr' is non-NULL (state_change_event) 1820 1.1 mrg | (2) following 'false' branch... (start_cfg_edge_event) 1821 1.1 mrg ... 1822 1.1 mrg | do_something (ptr); 1823 1.1 mrg | ~~~~~~~~~~~~~^~~~~ 1824 1.1 mrg | | 1825 1.1 mrg | (3) ...to here (end_cfg_edge_event). */ 1826 1.1.1.2 mrg state_change_event_creator visitor (pb, eedge, emission_path); 1827 1.1 mrg for_each_state_change (src_state, dst_state, pb.get_ext_state (), 1828 1.1 mrg &visitor); 1829 1.1 mrg 1830 1.1 mrg /* Allow non-standard edges to add events, e.g. when rewinding from 1831 1.1 mrg longjmp to a setjmp. */ 1832 1.1 mrg if (eedge.m_custom_info) 1833 1.1 mrg eedge.m_custom_info->add_events_to_path (emission_path, eedge); 1834 1.1 mrg 1835 1.1 mrg /* Add events for superedges, function entries, and for statements. */ 1836 1.1 mrg switch (dst_point.get_kind ()) 1837 1.1 mrg { 1838 1.1 mrg default: 1839 1.1 mrg break; 1840 1.1 mrg case PK_BEFORE_SUPERNODE: 1841 1.1 mrg if (src_point.get_kind () == PK_AFTER_SUPERNODE) 1842 1.1 mrg { 1843 1.1 mrg if (eedge.m_sedge) 1844 1.1 mrg add_events_for_superedge (pb, eedge, emission_path); 1845 1.1 mrg } 1846 1.1 mrg /* Add function entry events. */ 1847 1.1 mrg if (dst_point.get_supernode ()->entry_p ()) 1848 1.1 mrg { 1849 1.1 mrg emission_path->add_event 1850 1.1 mrg (new function_entry_event 1851 1.1 mrg (dst_point.get_supernode ()->get_start_location (), 1852 1.1 mrg dst_point.get_fndecl (), 1853 1.1 mrg dst_stack_depth)); 1854 1.1.1.2 mrg /* Create region_creation_events for on-stack regions within 1855 1.1.1.2 mrg this frame. */ 1856 1.1.1.2 mrg if (interest) 1857 1.1.1.2 mrg { 1858 1.1.1.2 mrg unsigned i; 1859 1.1.1.2 mrg const region *reg; 1860 1.1.1.2 mrg FOR_EACH_VEC_ELT (interest->m_region_creation, i, reg) 1861 1.1.1.2 mrg if (const frame_region *frame = reg->maybe_get_frame_region ()) 1862 1.1.1.2 mrg if (frame->get_fndecl () == dst_point.get_fndecl ()) 1863 1.1.1.2 mrg { 1864 1.1.1.2 mrg const region *base_reg = reg->get_base_region (); 1865 1.1.1.2 mrg if (tree decl = base_reg->maybe_get_decl ()) 1866 1.1.1.2 mrg if (DECL_P (decl) 1867 1.1.1.2 mrg && DECL_SOURCE_LOCATION (decl) != UNKNOWN_LOCATION) 1868 1.1.1.2 mrg { 1869 1.1.1.2 mrg emission_path->add_region_creation_event 1870 1.1.1.2 mrg (reg, 1871 1.1.1.2 mrg DECL_SOURCE_LOCATION (decl), 1872 1.1.1.2 mrg dst_point.get_fndecl (), 1873 1.1.1.2 mrg dst_stack_depth); 1874 1.1.1.2 mrg } 1875 1.1.1.2 mrg } 1876 1.1.1.2 mrg } 1877 1.1 mrg } 1878 1.1 mrg break; 1879 1.1 mrg case PK_BEFORE_STMT: 1880 1.1 mrg { 1881 1.1 mrg const gimple *stmt = dst_point.get_stmt (); 1882 1.1 mrg const gcall *call = dyn_cast <const gcall *> (stmt); 1883 1.1 mrg if (call && is_setjmp_call_p (call)) 1884 1.1 mrg emission_path->add_event 1885 1.1 mrg (new setjmp_event (stmt->location, 1886 1.1 mrg dst_node, 1887 1.1 mrg dst_point.get_fndecl (), 1888 1.1 mrg dst_stack_depth, 1889 1.1 mrg call)); 1890 1.1 mrg else 1891 1.1 mrg emission_path->add_event 1892 1.1 mrg (new statement_event (stmt, 1893 1.1 mrg dst_point.get_fndecl (), 1894 1.1 mrg dst_stack_depth, dst_state)); 1895 1.1.1.2 mrg 1896 1.1.1.2 mrg /* Create state change events for assignment to NULL. 1897 1.1.1.2 mrg Iterate through the stmts in dst_enode, adding state change 1898 1.1.1.2 mrg events for them. */ 1899 1.1.1.2 mrg if (dst_state.m_region_model) 1900 1.1.1.2 mrg { 1901 1.1.1.2 mrg program_state iter_state (dst_state); 1902 1.1.1.2 mrg program_point iter_point (dst_point); 1903 1.1.1.2 mrg while (1) 1904 1.1.1.2 mrg { 1905 1.1.1.2 mrg const gimple *stmt = iter_point.get_stmt (); 1906 1.1.1.2 mrg if (const gassign *assign = dyn_cast<const gassign *> (stmt)) 1907 1.1.1.2 mrg { 1908 1.1.1.2 mrg const extrinsic_state &ext_state = pb.get_ext_state (); 1909 1.1.1.2 mrg program_state old_state (iter_state); 1910 1.1.1.2 mrg iter_state.m_region_model->on_assignment (assign, NULL); 1911 1.1.1.2 mrg for (unsigned i = 0; i < ext_state.get_num_checkers (); i++) 1912 1.1.1.2 mrg { 1913 1.1.1.2 mrg const state_machine &sm = ext_state.get_sm (i); 1914 1.1.1.2 mrg null_assignment_sm_context sm_ctxt (i, sm, 1915 1.1.1.2 mrg &old_state, 1916 1.1.1.2 mrg &iter_state, 1917 1.1.1.2 mrg stmt, 1918 1.1.1.2 mrg &iter_point, 1919 1.1.1.2 mrg emission_path, 1920 1.1.1.2 mrg pb.get_ext_state ()); 1921 1.1.1.2 mrg sm.on_stmt (&sm_ctxt, dst_point.get_supernode (), stmt); 1922 1.1.1.2 mrg // TODO: what about phi nodes? 1923 1.1.1.2 mrg } 1924 1.1.1.2 mrg } 1925 1.1.1.2 mrg iter_point.next_stmt (); 1926 1.1.1.2 mrg if (iter_point.get_kind () == PK_AFTER_SUPERNODE 1927 1.1.1.2 mrg || (dst_node->m_succs.length () > 1 1928 1.1.1.2 mrg && (iter_point 1929 1.1.1.2 mrg == dst_node->m_succs[0]->m_dest->get_point ()))) 1930 1.1.1.2 mrg break; 1931 1.1.1.2 mrg } 1932 1.1.1.2 mrg 1933 1.1.1.2 mrg } 1934 1.1 mrg } 1935 1.1 mrg break; 1936 1.1 mrg } 1937 1.1.1.2 mrg 1938 1.1.1.2 mrg /* Look for changes in dynamic extents, which will identify 1939 1.1.1.2 mrg the creation of heap-based regions and alloca regions. */ 1940 1.1.1.2 mrg if (interest) 1941 1.1.1.2 mrg { 1942 1.1.1.2 mrg const region_model *src_model = src_state.m_region_model; 1943 1.1.1.2 mrg const region_model *dst_model = dst_state.m_region_model; 1944 1.1.1.2 mrg if (src_model->get_dynamic_extents () 1945 1.1.1.2 mrg != dst_model->get_dynamic_extents ()) 1946 1.1.1.2 mrg { 1947 1.1.1.2 mrg unsigned i; 1948 1.1.1.2 mrg const region *reg; 1949 1.1.1.2 mrg FOR_EACH_VEC_ELT (interest->m_region_creation, i, reg) 1950 1.1.1.2 mrg { 1951 1.1.1.2 mrg const region *base_reg = reg->get_base_region (); 1952 1.1.1.2 mrg const svalue *old_extents 1953 1.1.1.2 mrg = src_model->get_dynamic_extents (base_reg); 1954 1.1.1.2 mrg const svalue *new_extents 1955 1.1.1.2 mrg = dst_model->get_dynamic_extents (base_reg); 1956 1.1.1.2 mrg if (old_extents == NULL && new_extents != NULL) 1957 1.1.1.2 mrg switch (base_reg->get_kind ()) 1958 1.1.1.2 mrg { 1959 1.1.1.2 mrg default: 1960 1.1.1.2 mrg break; 1961 1.1.1.2 mrg case RK_HEAP_ALLOCATED: 1962 1.1.1.2 mrg case RK_ALLOCA: 1963 1.1.1.2 mrg emission_path->add_region_creation_event 1964 1.1.1.2 mrg (reg, 1965 1.1.1.2 mrg src_point.get_location (), 1966 1.1.1.2 mrg src_point.get_fndecl (), 1967 1.1.1.2 mrg src_stack_depth); 1968 1.1.1.2 mrg break; 1969 1.1.1.2 mrg } 1970 1.1.1.2 mrg } 1971 1.1.1.2 mrg } 1972 1.1.1.2 mrg } 1973 1.1.1.2 mrg 1974 1.1.1.2 mrg if (pb.get_feasibility_problem () 1975 1.1.1.2 mrg && &pb.get_feasibility_problem ()->m_eedge == &eedge) 1976 1.1.1.2 mrg { 1977 1.1.1.2 mrg pretty_printer pp; 1978 1.1.1.2 mrg pp_format_decoder (&pp) = default_tree_printer; 1979 1.1.1.2 mrg pp_string (&pp, 1980 1.1.1.2 mrg "this path would have been rejected as infeasible" 1981 1.1.1.2 mrg " at this edge: "); 1982 1.1.1.2 mrg pb.get_feasibility_problem ()->dump_to_pp (&pp); 1983 1.1.1.2 mrg emission_path->add_event (new precanned_custom_event 1984 1.1.1.2 mrg (dst_point.get_location (), 1985 1.1.1.2 mrg dst_point.get_fndecl (), 1986 1.1.1.2 mrg dst_stack_depth, 1987 1.1.1.2 mrg pp_formatted_text (&pp))); 1988 1.1.1.2 mrg } 1989 1.1 mrg } 1990 1.1 mrg 1991 1.1 mrg /* Return true if EEDGE is a significant edge in the path to the diagnostic 1992 1.1 mrg for PB. 1993 1.1 mrg 1994 1.1 mrg Consider all of the sibling out-eedges from the same source enode 1995 1.1 mrg as EEDGE. 1996 1.1 mrg If there's no path from the destinations of those eedges to the 1997 1.1 mrg diagnostic enode, then we have to take this eedge and thus it's 1998 1.1 mrg significant. 1999 1.1 mrg 2000 1.1 mrg Conversely if there is a path from the destination of any other sibling 2001 1.1 mrg eedge to the diagnostic enode, then this edge is insignificant. 2002 1.1 mrg 2003 1.1 mrg Example 1: redundant if-else: 2004 1.1 mrg 2005 1.1 mrg (A) if (...) A 2006 1.1 mrg (B) ... / \ 2007 1.1 mrg else B C 2008 1.1 mrg (C) ... \ / 2009 1.1 mrg (D) [DIAGNOSTIC] D 2010 1.1 mrg 2011 1.1 mrg D is reachable by either B or C, so neither of these edges 2012 1.1 mrg are significant. 2013 1.1 mrg 2014 1.1 mrg Example 2: pertinent if-else: 2015 1.1 mrg 2016 1.1 mrg (A) if (...) A 2017 1.1 mrg (B) ... / \ 2018 1.1 mrg else B C 2019 1.1 mrg (C) [NECESSARY CONDITION] | | 2020 1.1 mrg (D) [POSSIBLE DIAGNOSTIC] D1 D2 2021 1.1 mrg 2022 1.1 mrg D becomes D1 and D2 in the exploded graph, where the diagnostic occurs 2023 1.1 mrg at D2. D2 is only reachable via C, so the A -> C edge is significant. 2024 1.1 mrg 2025 1.1 mrg Example 3: redundant loop: 2026 1.1 mrg 2027 1.1 mrg (A) while (...) +-->A 2028 1.1 mrg (B) ... | / \ 2029 1.1 mrg (C) ... +-B C 2030 1.1 mrg (D) [DIAGNOSTIC] | 2031 1.1 mrg D 2032 1.1 mrg 2033 1.1 mrg D is reachable from both B and C, so the A->C edge is not significant. */ 2034 1.1 mrg 2035 1.1 mrg bool 2036 1.1 mrg diagnostic_manager::significant_edge_p (const path_builder &pb, 2037 1.1 mrg const exploded_edge &eedge) const 2038 1.1 mrg { 2039 1.1 mrg int i; 2040 1.1 mrg exploded_edge *sibling; 2041 1.1 mrg FOR_EACH_VEC_ELT (eedge.m_src->m_succs, i, sibling) 2042 1.1 mrg { 2043 1.1 mrg if (sibling == &eedge) 2044 1.1 mrg continue; 2045 1.1 mrg if (pb.reachable_from_p (sibling->m_dest)) 2046 1.1 mrg { 2047 1.1 mrg if (get_logger ()) 2048 1.1 mrg get_logger ()->log (" edge EN: %i -> EN: %i is insignificant as" 2049 1.1 mrg " EN: %i is also reachable via" 2050 1.1 mrg " EN: %i -> EN: %i", 2051 1.1 mrg eedge.m_src->m_index, eedge.m_dest->m_index, 2052 1.1 mrg pb.get_diag_node ()->m_index, 2053 1.1 mrg sibling->m_src->m_index, 2054 1.1 mrg sibling->m_dest->m_index); 2055 1.1 mrg return false; 2056 1.1 mrg } 2057 1.1 mrg } 2058 1.1 mrg 2059 1.1 mrg return true; 2060 1.1 mrg } 2061 1.1 mrg 2062 1.1 mrg /* Subroutine of diagnostic_manager::add_events_for_eedge 2063 1.1 mrg where EEDGE has an underlying superedge i.e. a CFG edge, 2064 1.1 mrg or an interprocedural call/return. 2065 1.1 mrg Add any events for the superedge to EMISSION_PATH. */ 2066 1.1 mrg 2067 1.1 mrg void 2068 1.1 mrg diagnostic_manager::add_events_for_superedge (const path_builder &pb, 2069 1.1 mrg const exploded_edge &eedge, 2070 1.1 mrg checker_path *emission_path) 2071 1.1 mrg const 2072 1.1 mrg { 2073 1.1 mrg gcc_assert (eedge.m_sedge); 2074 1.1 mrg 2075 1.1.1.2 mrg /* Give diagnostics an opportunity to override this function. */ 2076 1.1.1.2 mrg pending_diagnostic *pd = pb.get_pending_diagnostic (); 2077 1.1.1.2 mrg if (pd->maybe_add_custom_events_for_superedge (eedge, emission_path)) 2078 1.1.1.2 mrg return; 2079 1.1.1.2 mrg 2080 1.1 mrg /* Don't add events for insignificant edges at verbosity levels below 3. */ 2081 1.1 mrg if (m_verbosity < 3) 2082 1.1 mrg if (!significant_edge_p (pb, eedge)) 2083 1.1 mrg return; 2084 1.1 mrg 2085 1.1 mrg const exploded_node *src_node = eedge.m_src; 2086 1.1 mrg const program_point &src_point = src_node->get_point (); 2087 1.1 mrg const exploded_node *dst_node = eedge.m_dest; 2088 1.1 mrg const program_point &dst_point = dst_node->get_point (); 2089 1.1 mrg const int src_stack_depth = src_point.get_stack_depth (); 2090 1.1 mrg const int dst_stack_depth = dst_point.get_stack_depth (); 2091 1.1 mrg const gimple *last_stmt = src_point.get_supernode ()->get_last_stmt (); 2092 1.1 mrg 2093 1.1 mrg switch (eedge.m_sedge->m_kind) 2094 1.1 mrg { 2095 1.1 mrg case SUPEREDGE_CFG_EDGE: 2096 1.1 mrg { 2097 1.1 mrg emission_path->add_event 2098 1.1 mrg (new start_cfg_edge_event (eedge, 2099 1.1 mrg (last_stmt 2100 1.1 mrg ? last_stmt->location 2101 1.1 mrg : UNKNOWN_LOCATION), 2102 1.1 mrg src_point.get_fndecl (), 2103 1.1 mrg src_stack_depth)); 2104 1.1 mrg emission_path->add_event 2105 1.1 mrg (new end_cfg_edge_event (eedge, 2106 1.1 mrg dst_point.get_supernode ()->get_start_location (), 2107 1.1 mrg dst_point.get_fndecl (), 2108 1.1 mrg dst_stack_depth)); 2109 1.1 mrg } 2110 1.1 mrg break; 2111 1.1 mrg 2112 1.1 mrg case SUPEREDGE_CALL: 2113 1.1 mrg { 2114 1.1 mrg emission_path->add_event 2115 1.1 mrg (new call_event (eedge, 2116 1.1 mrg (last_stmt 2117 1.1 mrg ? last_stmt->location 2118 1.1 mrg : UNKNOWN_LOCATION), 2119 1.1 mrg src_point.get_fndecl (), 2120 1.1 mrg src_stack_depth)); 2121 1.1 mrg } 2122 1.1 mrg break; 2123 1.1 mrg 2124 1.1 mrg case SUPEREDGE_INTRAPROCEDURAL_CALL: 2125 1.1 mrg { 2126 1.1 mrg /* TODO: add a subclass for this, or generate events for the 2127 1.1 mrg summary. */ 2128 1.1 mrg emission_path->add_event 2129 1.1 mrg (new debug_event ((last_stmt 2130 1.1 mrg ? last_stmt->location 2131 1.1 mrg : UNKNOWN_LOCATION), 2132 1.1 mrg src_point.get_fndecl (), 2133 1.1 mrg src_stack_depth, 2134 1.1 mrg "call summary")); 2135 1.1 mrg } 2136 1.1 mrg break; 2137 1.1 mrg 2138 1.1 mrg case SUPEREDGE_RETURN: 2139 1.1 mrg { 2140 1.1 mrg const return_superedge *return_edge 2141 1.1 mrg = as_a <const return_superedge *> (eedge.m_sedge); 2142 1.1 mrg 2143 1.1 mrg const gcall *call_stmt = return_edge->get_call_stmt (); 2144 1.1 mrg emission_path->add_event 2145 1.1 mrg (new return_event (eedge, 2146 1.1 mrg (call_stmt 2147 1.1 mrg ? call_stmt->location 2148 1.1 mrg : UNKNOWN_LOCATION), 2149 1.1 mrg dst_point.get_fndecl (), 2150 1.1 mrg dst_stack_depth)); 2151 1.1 mrg } 2152 1.1 mrg break; 2153 1.1 mrg } 2154 1.1 mrg } 2155 1.1 mrg 2156 1.1 mrg /* Prune PATH, based on the verbosity level, to the most pertinent 2157 1.1 mrg events for a diagnostic that involves VAR ending in state STATE 2158 1.1 mrg (for state machine SM). 2159 1.1 mrg 2160 1.1 mrg PATH is updated in place, and the redundant checker_events are deleted. 2161 1.1 mrg 2162 1.1 mrg As well as deleting events, call record_critical_state on events in 2163 1.1 mrg which state critical to the pending_diagnostic is being handled; see 2164 1.1 mrg the comment for diagnostic_manager::prune_for_sm_diagnostic. */ 2165 1.1 mrg 2166 1.1 mrg void 2167 1.1 mrg diagnostic_manager::prune_path (checker_path *path, 2168 1.1 mrg const state_machine *sm, 2169 1.1.1.2 mrg const svalue *sval, 2170 1.1 mrg state_machine::state_t state) const 2171 1.1 mrg { 2172 1.1 mrg LOG_FUNC (get_logger ()); 2173 1.1 mrg path->maybe_log (get_logger (), "path"); 2174 1.1.1.2 mrg prune_for_sm_diagnostic (path, sm, sval, state); 2175 1.1 mrg prune_interproc_events (path); 2176 1.1.1.2 mrg consolidate_conditions (path); 2177 1.1 mrg finish_pruning (path); 2178 1.1 mrg path->maybe_log (get_logger (), "pruned"); 2179 1.1 mrg } 2180 1.1 mrg 2181 1.1 mrg /* A cheap test to determine if EXPR can be the expression of interest in 2182 1.1 mrg an sm-diagnostic, so that we can reject cases where we have a non-lvalue. 2183 1.1 mrg We don't have always have a model when calling this, so we can't use 2184 1.1 mrg tentative_region_model_context, so there can be false positives. */ 2185 1.1 mrg 2186 1.1 mrg static bool 2187 1.1 mrg can_be_expr_of_interest_p (tree expr) 2188 1.1 mrg { 2189 1.1 mrg if (!expr) 2190 1.1 mrg return false; 2191 1.1 mrg 2192 1.1 mrg /* Reject constants. */ 2193 1.1 mrg if (CONSTANT_CLASS_P (expr)) 2194 1.1 mrg return false; 2195 1.1 mrg 2196 1.1 mrg /* Otherwise assume that it can be an lvalue. */ 2197 1.1 mrg return true; 2198 1.1 mrg } 2199 1.1 mrg 2200 1.1 mrg /* First pass of diagnostic_manager::prune_path: apply verbosity level, 2201 1.1 mrg pruning unrelated state change events. 2202 1.1 mrg 2203 1.1 mrg Iterate backwards through PATH, skipping state change events that aren't 2204 1.1 mrg VAR but update the pertinent VAR when state-copying occurs. 2205 1.1 mrg 2206 1.1 mrg As well as deleting events, call record_critical_state on events in 2207 1.1 mrg which state critical to the pending_diagnostic is being handled, so 2208 1.1 mrg that the event's get_desc vfunc can potentially supply a more precise 2209 1.1 mrg description of the event to the user. 2210 1.1 mrg e.g. improving 2211 1.1 mrg "calling 'foo' from 'bar'" 2212 1.1 mrg to 2213 1.1 mrg "passing possibly-NULL pointer 'ptr' to 'foo' from 'bar' as param 1" 2214 1.1 mrg when the diagnostic relates to later dereferencing 'ptr'. */ 2215 1.1 mrg 2216 1.1 mrg void 2217 1.1 mrg diagnostic_manager::prune_for_sm_diagnostic (checker_path *path, 2218 1.1 mrg const state_machine *sm, 2219 1.1.1.2 mrg const svalue *sval, 2220 1.1 mrg state_machine::state_t state) const 2221 1.1 mrg { 2222 1.1 mrg int idx = path->num_events () - 1; 2223 1.1 mrg while (idx >= 0 && idx < (signed)path->num_events ()) 2224 1.1 mrg { 2225 1.1 mrg checker_event *base_event = path->get_checker_event (idx); 2226 1.1 mrg if (get_logger ()) 2227 1.1 mrg { 2228 1.1 mrg if (sm) 2229 1.1 mrg { 2230 1.1.1.2 mrg if (sval) 2231 1.1.1.2 mrg { 2232 1.1.1.2 mrg label_text sval_desc = sval->get_desc (); 2233 1.1.1.2 mrg log ("considering event %i (%s), with sval: %qs, state: %qs", 2234 1.1.1.2 mrg idx, event_kind_to_string (base_event->m_kind), 2235 1.1.1.2 mrg sval_desc.m_buffer, state->get_name ()); 2236 1.1.1.2 mrg sval_desc.maybe_free (); 2237 1.1.1.2 mrg } 2238 1.1 mrg else 2239 1.1.1.2 mrg log ("considering event %i (%s), with global state: %qs", 2240 1.1.1.2 mrg idx, event_kind_to_string (base_event->m_kind), 2241 1.1.1.2 mrg state->get_name ()); 2242 1.1 mrg } 2243 1.1 mrg else 2244 1.1 mrg log ("considering event %i", idx); 2245 1.1 mrg } 2246 1.1.1.2 mrg 2247 1.1 mrg switch (base_event->m_kind) 2248 1.1 mrg { 2249 1.1 mrg default: 2250 1.1 mrg gcc_unreachable (); 2251 1.1 mrg 2252 1.1 mrg case EK_DEBUG: 2253 1.1 mrg if (m_verbosity < 4) 2254 1.1 mrg { 2255 1.1 mrg log ("filtering event %i: debug event", idx); 2256 1.1 mrg path->delete_event (idx); 2257 1.1 mrg } 2258 1.1 mrg break; 2259 1.1 mrg 2260 1.1 mrg case EK_CUSTOM: 2261 1.1 mrg /* Don't filter custom events. */ 2262 1.1 mrg break; 2263 1.1 mrg 2264 1.1 mrg case EK_STMT: 2265 1.1 mrg { 2266 1.1 mrg if (m_verbosity < 4) 2267 1.1 mrg { 2268 1.1 mrg log ("filtering event %i: statement event", idx); 2269 1.1 mrg path->delete_event (idx); 2270 1.1 mrg } 2271 1.1 mrg } 2272 1.1 mrg break; 2273 1.1 mrg 2274 1.1.1.2 mrg case EK_REGION_CREATION: 2275 1.1.1.2 mrg /* Don't filter these. */ 2276 1.1.1.2 mrg break; 2277 1.1.1.2 mrg 2278 1.1 mrg case EK_FUNCTION_ENTRY: 2279 1.1 mrg if (m_verbosity < 1) 2280 1.1 mrg { 2281 1.1 mrg log ("filtering event %i: function entry", idx); 2282 1.1 mrg path->delete_event (idx); 2283 1.1 mrg } 2284 1.1 mrg break; 2285 1.1 mrg 2286 1.1 mrg case EK_STATE_CHANGE: 2287 1.1 mrg { 2288 1.1 mrg state_change_event *state_change = (state_change_event *)base_event; 2289 1.1.1.2 mrg gcc_assert (state_change->m_dst_state.m_region_model); 2290 1.1.1.2 mrg 2291 1.1.1.2 mrg if (state_change->m_sval == sval) 2292 1.1 mrg { 2293 1.1 mrg if (state_change->m_origin) 2294 1.1 mrg { 2295 1.1.1.2 mrg if (get_logger ()) 2296 1.1.1.2 mrg { 2297 1.1.1.2 mrg label_text sval_desc = sval->get_desc (); 2298 1.1.1.2 mrg label_text origin_sval_desc 2299 1.1.1.2 mrg = state_change->m_origin->get_desc (); 2300 1.1.1.2 mrg log ("event %i:" 2301 1.1.1.2 mrg " switching var of interest from %qs to %qs", 2302 1.1.1.2 mrg idx, sval_desc.m_buffer, 2303 1.1.1.2 mrg origin_sval_desc.m_buffer); 2304 1.1.1.2 mrg sval_desc.maybe_free (); 2305 1.1.1.2 mrg origin_sval_desc.maybe_free (); 2306 1.1.1.2 mrg } 2307 1.1.1.2 mrg sval = state_change->m_origin; 2308 1.1 mrg } 2309 1.1 mrg log ("event %i: switching state of interest from %qs to %qs", 2310 1.1.1.2 mrg idx, state_change->m_to->get_name (), 2311 1.1.1.2 mrg state_change->m_from->get_name ()); 2312 1.1 mrg state = state_change->m_from; 2313 1.1 mrg } 2314 1.1 mrg else if (m_verbosity < 4) 2315 1.1 mrg { 2316 1.1.1.2 mrg if (get_logger ()) 2317 1.1.1.2 mrg { 2318 1.1.1.2 mrg if (state_change->m_sval) 2319 1.1.1.2 mrg { 2320 1.1.1.2 mrg label_text change_sval_desc 2321 1.1.1.2 mrg = state_change->m_sval->get_desc (); 2322 1.1.1.2 mrg if (sval) 2323 1.1.1.2 mrg { 2324 1.1.1.2 mrg label_text sval_desc = sval->get_desc (); 2325 1.1.1.2 mrg log ("filtering event %i:" 2326 1.1.1.2 mrg " state change to %qs unrelated to %qs", 2327 1.1.1.2 mrg idx, change_sval_desc.m_buffer, 2328 1.1.1.2 mrg sval_desc.m_buffer); 2329 1.1.1.2 mrg } 2330 1.1.1.2 mrg else 2331 1.1.1.2 mrg log ("filtering event %i: state change to %qs", 2332 1.1.1.2 mrg idx, change_sval_desc.m_buffer); 2333 1.1.1.2 mrg change_sval_desc.maybe_free (); 2334 1.1.1.2 mrg } 2335 1.1.1.2 mrg else 2336 1.1.1.2 mrg log ("filtering event %i: global state change", idx); 2337 1.1.1.2 mrg } 2338 1.1 mrg path->delete_event (idx); 2339 1.1 mrg } 2340 1.1 mrg } 2341 1.1 mrg break; 2342 1.1 mrg 2343 1.1 mrg case EK_START_CFG_EDGE: 2344 1.1 mrg { 2345 1.1 mrg cfg_edge_event *event = (cfg_edge_event *)base_event; 2346 1.1 mrg 2347 1.1 mrg /* TODO: is this edge significant to var? 2348 1.1 mrg See if var can be in other states in the dest, but not 2349 1.1 mrg in other states in the src? 2350 1.1 mrg Must have multiple sibling edges. */ 2351 1.1 mrg 2352 1.1 mrg if (event->should_filter_p (m_verbosity)) 2353 1.1 mrg { 2354 1.1.1.2 mrg log ("filtering events %i and %i: CFG edge", idx, idx + 1); 2355 1.1 mrg path->delete_event (idx); 2356 1.1 mrg /* Also delete the corresponding EK_END_CFG_EDGE. */ 2357 1.1 mrg gcc_assert (path->get_checker_event (idx)->m_kind 2358 1.1 mrg == EK_END_CFG_EDGE); 2359 1.1 mrg path->delete_event (idx); 2360 1.1 mrg } 2361 1.1 mrg } 2362 1.1 mrg break; 2363 1.1 mrg 2364 1.1 mrg case EK_END_CFG_EDGE: 2365 1.1 mrg /* These come in pairs with EK_START_CFG_EDGE events and are 2366 1.1 mrg filtered when their start event is filtered. */ 2367 1.1 mrg break; 2368 1.1 mrg 2369 1.1 mrg case EK_CALL_EDGE: 2370 1.1 mrg { 2371 1.1 mrg call_event *event = (call_event *)base_event; 2372 1.1.1.2 mrg const region_model *callee_model 2373 1.1.1.2 mrg = event->m_eedge.m_dest->get_state ().m_region_model; 2374 1.1.1.2 mrg const region_model *caller_model 2375 1.1.1.2 mrg = event->m_eedge.m_src->get_state ().m_region_model; 2376 1.1.1.2 mrg tree callee_var = callee_model->get_representative_tree (sval); 2377 1.1 mrg callsite_expr expr; 2378 1.1.1.2 mrg 2379 1.1.1.2 mrg tree caller_var; 2380 1.1.1.2 mrg if(event->m_sedge) 2381 1.1.1.2 mrg { 2382 1.1.1.2 mrg const callgraph_superedge& cg_superedge 2383 1.1.1.2 mrg = event->get_callgraph_superedge (); 2384 1.1.1.2 mrg if (cg_superedge.m_cedge) 2385 1.1.1.2 mrg caller_var 2386 1.1.1.2 mrg = cg_superedge.map_expr_from_callee_to_caller (callee_var, 2387 1.1.1.2 mrg &expr); 2388 1.1.1.2 mrg else 2389 1.1.1.2 mrg caller_var = caller_model->get_representative_tree (sval); 2390 1.1.1.2 mrg } 2391 1.1.1.2 mrg else 2392 1.1.1.2 mrg caller_var = caller_model->get_representative_tree (sval); 2393 1.1.1.2 mrg 2394 1.1 mrg if (caller_var) 2395 1.1 mrg { 2396 1.1.1.2 mrg if (get_logger ()) 2397 1.1.1.2 mrg { 2398 1.1.1.2 mrg label_text sval_desc = sval->get_desc (); 2399 1.1.1.2 mrg log ("event %i:" 2400 1.1.1.2 mrg " recording critical state for %qs at call" 2401 1.1.1.2 mrg " from %qE in callee to %qE in caller", 2402 1.1.1.2 mrg idx, sval_desc.m_buffer, callee_var, caller_var); 2403 1.1.1.2 mrg sval_desc.maybe_free (); 2404 1.1.1.2 mrg } 2405 1.1 mrg if (expr.param_p ()) 2406 1.1.1.2 mrg event->record_critical_state (caller_var, state); 2407 1.1 mrg } 2408 1.1 mrg } 2409 1.1 mrg break; 2410 1.1 mrg 2411 1.1 mrg case EK_RETURN_EDGE: 2412 1.1 mrg { 2413 1.1.1.2 mrg if (sval) 2414 1.1 mrg { 2415 1.1 mrg return_event *event = (return_event *)base_event; 2416 1.1.1.2 mrg const region_model *caller_model 2417 1.1.1.2 mrg = event->m_eedge.m_dest->get_state ().m_region_model; 2418 1.1.1.2 mrg tree caller_var = caller_model->get_representative_tree (sval); 2419 1.1.1.2 mrg const region_model *callee_model 2420 1.1.1.2 mrg = event->m_eedge.m_src->get_state ().m_region_model; 2421 1.1 mrg callsite_expr expr; 2422 1.1.1.2 mrg 2423 1.1.1.2 mrg tree callee_var; 2424 1.1.1.2 mrg if (event->m_sedge) 2425 1.1.1.2 mrg { 2426 1.1.1.2 mrg const callgraph_superedge& cg_superedge 2427 1.1.1.2 mrg = event->get_callgraph_superedge (); 2428 1.1.1.2 mrg if (cg_superedge.m_cedge) 2429 1.1.1.2 mrg callee_var 2430 1.1.1.2 mrg = cg_superedge.map_expr_from_caller_to_callee (caller_var, 2431 1.1.1.2 mrg &expr); 2432 1.1.1.2 mrg else 2433 1.1.1.2 mrg callee_var = callee_model->get_representative_tree (sval); 2434 1.1.1.2 mrg } 2435 1.1.1.2 mrg else 2436 1.1.1.2 mrg callee_var = callee_model->get_representative_tree (sval); 2437 1.1.1.2 mrg 2438 1.1 mrg if (callee_var) 2439 1.1 mrg { 2440 1.1.1.2 mrg if (get_logger ()) 2441 1.1.1.2 mrg { 2442 1.1.1.2 mrg label_text sval_desc = sval->get_desc (); 2443 1.1.1.2 mrg log ("event %i:" 2444 1.1.1.2 mrg " recording critical state for %qs at return" 2445 1.1.1.2 mrg " from %qE in caller to %qE in callee", 2446 1.1.1.2 mrg idx, sval_desc.m_buffer, callee_var, callee_var); 2447 1.1.1.2 mrg sval_desc.maybe_free (); 2448 1.1.1.2 mrg } 2449 1.1 mrg if (expr.return_value_p ()) 2450 1.1.1.2 mrg event->record_critical_state (callee_var, state); 2451 1.1 mrg } 2452 1.1 mrg } 2453 1.1 mrg } 2454 1.1 mrg break; 2455 1.1 mrg 2456 1.1 mrg case EK_SETJMP: 2457 1.1 mrg /* TODO: only show setjmp_events that matter i.e. those for which 2458 1.1 mrg there is a later rewind event using them. */ 2459 1.1 mrg case EK_REWIND_FROM_LONGJMP: 2460 1.1 mrg case EK_REWIND_TO_SETJMP: 2461 1.1 mrg break; 2462 1.1 mrg 2463 1.1 mrg case EK_WARNING: 2464 1.1 mrg /* Always show the final "warning" event in the path. */ 2465 1.1 mrg break; 2466 1.1 mrg } 2467 1.1 mrg idx--; 2468 1.1 mrg } 2469 1.1 mrg } 2470 1.1 mrg 2471 1.1 mrg /* Subroutine of diagnostic_manager::prune_for_sm_diagnostic. 2472 1.1 mrg If *EXPR is not suitable to be the expression of interest in 2473 1.1 mrg an sm-diagnostic, set *EXPR to NULL and log. */ 2474 1.1 mrg 2475 1.1 mrg void 2476 1.1 mrg diagnostic_manager::update_for_unsuitable_sm_exprs (tree *expr) const 2477 1.1 mrg { 2478 1.1 mrg gcc_assert (expr); 2479 1.1 mrg if (*expr && !can_be_expr_of_interest_p (*expr)) 2480 1.1 mrg { 2481 1.1 mrg log ("new var %qE is unsuitable; setting var to NULL", *expr); 2482 1.1 mrg *expr = NULL_TREE; 2483 1.1 mrg } 2484 1.1 mrg } 2485 1.1 mrg 2486 1.1 mrg /* Second pass of diagnostic_manager::prune_path: remove redundant 2487 1.1 mrg interprocedural information. 2488 1.1 mrg 2489 1.1 mrg For example, given: 2490 1.1 mrg (1)- calling "f2" from "f1" 2491 1.1 mrg (2)--- entry to "f2" 2492 1.1 mrg (3)--- calling "f3" from "f2" 2493 1.1 mrg (4)----- entry to "f3" 2494 1.1 mrg (5)--- returning to "f2" to "f3" 2495 1.1 mrg (6)- returning to "f1" to "f2" 2496 1.1 mrg with no other intervening events, then none of these events are 2497 1.1 mrg likely to be interesting to the user. 2498 1.1 mrg 2499 1.1 mrg Prune [..., call, function-entry, return, ...] triples repeatedly 2500 1.1 mrg until nothing has changed. For the example above, this would 2501 1.1 mrg remove events (3, 4, 5), and then remove events (1, 2, 6). */ 2502 1.1 mrg 2503 1.1 mrg void 2504 1.1 mrg diagnostic_manager::prune_interproc_events (checker_path *path) const 2505 1.1 mrg { 2506 1.1 mrg bool changed = false; 2507 1.1 mrg do 2508 1.1 mrg { 2509 1.1 mrg changed = false; 2510 1.1.1.2 mrg int idx = (signed)path->num_events () - 1; 2511 1.1 mrg while (idx >= 0) 2512 1.1 mrg { 2513 1.1 mrg /* Prune [..., call, function-entry, return, ...] triples. */ 2514 1.1 mrg if (idx + 2 < (signed)path->num_events () 2515 1.1 mrg && path->get_checker_event (idx)->is_call_p () 2516 1.1 mrg && path->get_checker_event (idx + 1)->is_function_entry_p () 2517 1.1 mrg && path->get_checker_event (idx + 2)->is_return_p ()) 2518 1.1 mrg { 2519 1.1 mrg if (get_logger ()) 2520 1.1 mrg { 2521 1.1 mrg label_text desc 2522 1.1 mrg (path->get_checker_event (idx)->get_desc (false)); 2523 1.1 mrg log ("filtering events %i-%i:" 2524 1.1 mrg " irrelevant call/entry/return: %s", 2525 1.1 mrg idx, idx + 2, desc.m_buffer); 2526 1.1 mrg desc.maybe_free (); 2527 1.1 mrg } 2528 1.1 mrg path->delete_event (idx + 2); 2529 1.1 mrg path->delete_event (idx + 1); 2530 1.1 mrg path->delete_event (idx); 2531 1.1 mrg changed = true; 2532 1.1 mrg idx--; 2533 1.1 mrg continue; 2534 1.1 mrg } 2535 1.1 mrg 2536 1.1 mrg /* Prune [..., call, return, ...] pairs 2537 1.1 mrg (for -fanalyzer-verbosity=0). */ 2538 1.1 mrg if (idx + 1 < (signed)path->num_events () 2539 1.1 mrg && path->get_checker_event (idx)->is_call_p () 2540 1.1 mrg && path->get_checker_event (idx + 1)->is_return_p ()) 2541 1.1 mrg { 2542 1.1 mrg if (get_logger ()) 2543 1.1 mrg { 2544 1.1 mrg label_text desc 2545 1.1 mrg (path->get_checker_event (idx)->get_desc (false)); 2546 1.1 mrg log ("filtering events %i-%i:" 2547 1.1 mrg " irrelevant call/return: %s", 2548 1.1 mrg idx, idx + 1, desc.m_buffer); 2549 1.1 mrg desc.maybe_free (); 2550 1.1 mrg } 2551 1.1 mrg path->delete_event (idx + 1); 2552 1.1 mrg path->delete_event (idx); 2553 1.1 mrg changed = true; 2554 1.1 mrg idx--; 2555 1.1 mrg continue; 2556 1.1 mrg } 2557 1.1 mrg 2558 1.1 mrg idx--; 2559 1.1 mrg } 2560 1.1 mrg 2561 1.1 mrg } 2562 1.1 mrg while (changed); 2563 1.1 mrg } 2564 1.1 mrg 2565 1.1.1.2 mrg /* Return true iff event IDX within PATH is on the same line as REF_EXP_LOC. */ 2566 1.1.1.2 mrg 2567 1.1.1.2 mrg static bool 2568 1.1.1.2 mrg same_line_as_p (const expanded_location &ref_exp_loc, 2569 1.1.1.2 mrg checker_path *path, unsigned idx) 2570 1.1.1.2 mrg { 2571 1.1.1.2 mrg const checker_event *ev = path->get_checker_event (idx); 2572 1.1.1.2 mrg expanded_location idx_exp_loc = expand_location (ev->get_location ()); 2573 1.1.1.2 mrg gcc_assert (ref_exp_loc.file); 2574 1.1.1.2 mrg if (idx_exp_loc.file == NULL) 2575 1.1.1.2 mrg return false; 2576 1.1.1.2 mrg if (strcmp (ref_exp_loc.file, idx_exp_loc.file)) 2577 1.1.1.2 mrg return false; 2578 1.1.1.2 mrg return ref_exp_loc.line == idx_exp_loc.line; 2579 1.1.1.2 mrg } 2580 1.1.1.2 mrg 2581 1.1.1.2 mrg /* This path-readability optimization reduces the verbosity of compound 2582 1.1.1.2 mrg conditional statements (without needing to reconstruct the AST, which 2583 1.1.1.2 mrg has already been lost). 2584 1.1.1.2 mrg 2585 1.1.1.2 mrg For example, it converts: 2586 1.1.1.2 mrg 2587 1.1.1.2 mrg | 61 | if (cp[0] != '\0' && cp[0] != '#') 2588 1.1.1.2 mrg | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2589 1.1.1.2 mrg | | | | | 2590 1.1.1.2 mrg | | | | (6) ...to here 2591 1.1.1.2 mrg | | | (7) following true branch... 2592 1.1.1.2 mrg | | (5) following true branch... 2593 1.1.1.2 mrg | 62 | { 2594 1.1.1.2 mrg | 63 | alias = cp++; 2595 1.1.1.2 mrg | | ~~~~ 2596 1.1.1.2 mrg | | | 2597 1.1.1.2 mrg | | (8) ...to here 2598 1.1.1.2 mrg 2599 1.1.1.2 mrg into: 2600 1.1.1.2 mrg 2601 1.1.1.2 mrg | 61 | if (cp[0] != '\0' && cp[0] != '#') 2602 1.1.1.2 mrg | | ~ 2603 1.1.1.2 mrg | | | 2604 1.1.1.2 mrg | | (5) following true branch... 2605 1.1.1.2 mrg | 62 | { 2606 1.1.1.2 mrg | 63 | alias = cp++; 2607 1.1.1.2 mrg | | ~~~~ 2608 1.1.1.2 mrg | | | 2609 1.1.1.2 mrg | | (6) ...to here 2610 1.1.1.2 mrg 2611 1.1.1.2 mrg by combining events 5-8 into new events 5-6. 2612 1.1.1.2 mrg 2613 1.1.1.2 mrg Find runs of consecutive (start_cfg_edge_event, end_cfg_edge_event) pairs 2614 1.1.1.2 mrg in which all events apart from the final end_cfg_edge_event are on the same 2615 1.1.1.2 mrg line, and for which either all the CFG edges are TRUE edges, or all are 2616 1.1.1.2 mrg FALSE edges. 2617 1.1.1.2 mrg 2618 1.1.1.2 mrg Consolidate each such run into a 2619 1.1.1.2 mrg (start_consolidated_cfg_edges_event, end_consolidated_cfg_edges_event) 2620 1.1.1.2 mrg pair. */ 2621 1.1.1.2 mrg 2622 1.1.1.2 mrg void 2623 1.1.1.2 mrg diagnostic_manager::consolidate_conditions (checker_path *path) const 2624 1.1.1.2 mrg { 2625 1.1.1.2 mrg /* Don't simplify edges if we're debugging them. */ 2626 1.1.1.2 mrg if (flag_analyzer_verbose_edges) 2627 1.1.1.2 mrg return; 2628 1.1.1.2 mrg 2629 1.1.1.2 mrg for (int start_idx = 0; 2630 1.1.1.2 mrg start_idx < (signed)path->num_events () - 1; 2631 1.1.1.2 mrg start_idx++) 2632 1.1.1.2 mrg { 2633 1.1.1.2 mrg if (path->cfg_edge_pair_at_p (start_idx)) 2634 1.1.1.2 mrg { 2635 1.1.1.2 mrg const checker_event *old_start_ev 2636 1.1.1.2 mrg = path->get_checker_event (start_idx); 2637 1.1.1.2 mrg expanded_location start_exp_loc 2638 1.1.1.2 mrg = expand_location (old_start_ev->get_location ()); 2639 1.1.1.2 mrg if (start_exp_loc.file == NULL) 2640 1.1.1.2 mrg continue; 2641 1.1.1.2 mrg if (!same_line_as_p (start_exp_loc, path, start_idx + 1)) 2642 1.1.1.2 mrg continue; 2643 1.1.1.2 mrg 2644 1.1.1.2 mrg /* Are we looking for a run of all TRUE edges, or all FALSE edges? */ 2645 1.1.1.2 mrg gcc_assert (old_start_ev->m_kind == EK_START_CFG_EDGE); 2646 1.1.1.2 mrg const start_cfg_edge_event *old_start_cfg_ev 2647 1.1.1.2 mrg = (const start_cfg_edge_event *)old_start_ev; 2648 1.1.1.2 mrg const cfg_superedge& first_cfg_sedge 2649 1.1.1.2 mrg = old_start_cfg_ev->get_cfg_superedge (); 2650 1.1.1.2 mrg bool edge_sense; 2651 1.1.1.2 mrg if (first_cfg_sedge.true_value_p ()) 2652 1.1.1.2 mrg edge_sense = true; 2653 1.1.1.2 mrg else if (first_cfg_sedge.false_value_p ()) 2654 1.1.1.2 mrg edge_sense = false; 2655 1.1.1.2 mrg else 2656 1.1.1.2 mrg continue; 2657 1.1.1.2 mrg 2658 1.1.1.2 mrg /* Find a run of CFG start/end event pairs from 2659 1.1.1.2 mrg [start_idx, next_idx) 2660 1.1.1.2 mrg where all apart from the final event are on the same line, 2661 1.1.1.2 mrg and all are either TRUE or FALSE edges, matching the initial. */ 2662 1.1.1.2 mrg int next_idx = start_idx + 2; 2663 1.1.1.2 mrg while (path->cfg_edge_pair_at_p (next_idx) 2664 1.1.1.2 mrg && same_line_as_p (start_exp_loc, path, next_idx)) 2665 1.1.1.2 mrg { 2666 1.1.1.2 mrg const checker_event *iter_ev 2667 1.1.1.2 mrg = path->get_checker_event (next_idx); 2668 1.1.1.2 mrg gcc_assert (iter_ev->m_kind == EK_START_CFG_EDGE); 2669 1.1.1.2 mrg const start_cfg_edge_event *iter_cfg_ev 2670 1.1.1.2 mrg = (const start_cfg_edge_event *)iter_ev; 2671 1.1.1.2 mrg const cfg_superedge& iter_cfg_sedge 2672 1.1.1.2 mrg = iter_cfg_ev->get_cfg_superedge (); 2673 1.1.1.2 mrg if (edge_sense) 2674 1.1.1.2 mrg { 2675 1.1.1.2 mrg if (!iter_cfg_sedge.true_value_p ()) 2676 1.1.1.2 mrg break; 2677 1.1.1.2 mrg } 2678 1.1.1.2 mrg else 2679 1.1.1.2 mrg { 2680 1.1.1.2 mrg if (!iter_cfg_sedge.false_value_p ()) 2681 1.1.1.2 mrg break; 2682 1.1.1.2 mrg } 2683 1.1.1.2 mrg next_idx += 2; 2684 1.1.1.2 mrg } 2685 1.1.1.2 mrg 2686 1.1.1.2 mrg /* If we have more than one pair in the run, consolidate. */ 2687 1.1.1.2 mrg if (next_idx > start_idx + 2) 2688 1.1.1.2 mrg { 2689 1.1.1.2 mrg const checker_event *old_end_ev 2690 1.1.1.2 mrg = path->get_checker_event (next_idx - 1); 2691 1.1.1.2 mrg log ("consolidating CFG edge events %i-%i into %i-%i", 2692 1.1.1.2 mrg start_idx, next_idx - 1, start_idx, start_idx +1); 2693 1.1.1.2 mrg start_consolidated_cfg_edges_event *new_start_ev 2694 1.1.1.2 mrg = new start_consolidated_cfg_edges_event 2695 1.1.1.2 mrg (old_start_ev->get_location (), 2696 1.1.1.2 mrg old_start_ev->get_fndecl (), 2697 1.1.1.2 mrg old_start_ev->get_stack_depth (), 2698 1.1.1.2 mrg edge_sense); 2699 1.1.1.2 mrg checker_event *new_end_ev 2700 1.1.1.2 mrg = new end_consolidated_cfg_edges_event 2701 1.1.1.2 mrg (old_end_ev->get_location (), 2702 1.1.1.2 mrg old_end_ev->get_fndecl (), 2703 1.1.1.2 mrg old_end_ev->get_stack_depth ()); 2704 1.1.1.2 mrg path->replace_event (start_idx, new_start_ev); 2705 1.1.1.2 mrg path->replace_event (start_idx + 1, new_end_ev); 2706 1.1.1.2 mrg path->delete_events (start_idx + 2, next_idx - (start_idx + 2)); 2707 1.1.1.2 mrg } 2708 1.1.1.2 mrg } 2709 1.1.1.2 mrg } 2710 1.1.1.2 mrg } 2711 1.1.1.2 mrg 2712 1.1 mrg /* Final pass of diagnostic_manager::prune_path. 2713 1.1 mrg 2714 1.1 mrg If all we're left with is in one function, then filter function entry 2715 1.1 mrg events. */ 2716 1.1 mrg 2717 1.1 mrg void 2718 1.1 mrg diagnostic_manager::finish_pruning (checker_path *path) const 2719 1.1 mrg { 2720 1.1 mrg if (!path->interprocedural_p ()) 2721 1.1 mrg { 2722 1.1 mrg int idx = path->num_events () - 1; 2723 1.1 mrg while (idx >= 0 && idx < (signed)path->num_events ()) 2724 1.1 mrg { 2725 1.1 mrg checker_event *base_event = path->get_checker_event (idx); 2726 1.1 mrg if (base_event->m_kind == EK_FUNCTION_ENTRY) 2727 1.1 mrg { 2728 1.1 mrg log ("filtering event %i:" 2729 1.1 mrg " function entry for purely intraprocedural path", idx); 2730 1.1 mrg path->delete_event (idx); 2731 1.1 mrg } 2732 1.1 mrg idx--; 2733 1.1 mrg } 2734 1.1 mrg } 2735 1.1 mrg } 2736 1.1 mrg 2737 1.1 mrg } // namespace ana 2738 1.1 mrg 2739 1.1 mrg #endif /* #if ENABLE_ANALYZER */ 2740