]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/analyzer/checker-path.h
analyzer: fix up paths for inlining (PR analyzer/105962)
[thirdparty/gcc.git] / gcc / analyzer / checker-path.h
1 /* Subclasses of diagnostic_path and diagnostic_event for analyzer diagnostics.
2 Copyright (C) 2019-2022 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
20
21 #ifndef GCC_ANALYZER_CHECKER_PATH_H
22 #define GCC_ANALYZER_CHECKER_PATH_H
23
24 #include "tree-logical-location.h"
25
26 namespace ana {
27
28 /* An enum for discriminating between the concrete subclasses of
29 checker_event. */
30
31 enum event_kind
32 {
33 EK_DEBUG,
34 EK_CUSTOM,
35 EK_STMT,
36 EK_REGION_CREATION,
37 EK_FUNCTION_ENTRY,
38 EK_STATE_CHANGE,
39 EK_START_CFG_EDGE,
40 EK_END_CFG_EDGE,
41 EK_CALL_EDGE,
42 EK_RETURN_EDGE,
43 EK_START_CONSOLIDATED_CFG_EDGES,
44 EK_END_CONSOLIDATED_CFG_EDGES,
45 EK_INLINED_CALL,
46 EK_SETJMP,
47 EK_REWIND_FROM_LONGJMP,
48 EK_REWIND_TO_SETJMP,
49 EK_WARNING
50 };
51
52 extern const char *event_kind_to_string (enum event_kind ek);
53
54 /* Event subclasses.
55
56 The class hierarchy looks like this (using indentation to show
57 inheritance, and with event_kinds shown for the concrete subclasses):
58
59 diagnostic_event
60 checker_event
61 debug_event (EK_DEBUG)
62 custom_event (EK_CUSTOM)
63 precanned_custom_event
64 statement_event (EK_STMT)
65 region_creation_event (EK_REGION_CREATION)
66 function_entry_event (EK_FUNCTION_ENTRY)
67 state_change_event (EK_STATE_CHANGE)
68 superedge_event
69 cfg_edge_event
70 start_cfg_edge_event (EK_START_CFG_EDGE)
71 end_cfg_edge_event (EK_END_CFG_EDGE)
72 call_event (EK_CALL_EDGE)
73 return_edge (EK_RETURN_EDGE)
74 start_consolidated_cfg_edges_event (EK_START_CONSOLIDATED_CFG_EDGES)
75 end_consolidated_cfg_edges_event (EK_END_CONSOLIDATED_CFG_EDGES)
76 inlined_call_event (EK_INLINED_CALL)
77 setjmp_event (EK_SETJMP)
78 rewind_event
79 rewind_from_longjmp_event (EK_REWIND_FROM_LONGJMP)
80 rewind_to_setjmp_event (EK_REWIND_TO_SETJMP)
81 warning_event (EK_WARNING). */
82
83 /* Abstract subclass of diagnostic_event; the base class for use in
84 checker_path (the analyzer's diagnostic_path subclass). */
85
86 class checker_event : public diagnostic_event
87 {
88 public:
89 /* Implementation of diagnostic_event. */
90
91 location_t get_location () const final override { return m_loc; }
92 tree get_fndecl () const final override { return m_effective_fndecl; }
93 int get_stack_depth () const final override { return m_effective_depth; }
94 const logical_location *get_logical_location () const final override
95 {
96 if (m_effective_fndecl)
97 return &m_logical_loc;
98 else
99 return NULL;
100 }
101 meaning get_meaning () const override;
102
103 /* Additional functionality. */
104
105 int get_original_stack_depth () const { return m_original_depth; }
106
107 virtual void prepare_for_emission (checker_path *,
108 pending_diagnostic *pd,
109 diagnostic_event_id_t emission_id);
110 virtual bool is_call_p () const { return false; }
111 virtual bool is_function_entry_p () const { return false; }
112 virtual bool is_return_p () const { return false; }
113
114 /* For use with %@. */
115 const diagnostic_event_id_t *get_id_ptr () const
116 {
117 return &m_emission_id;
118 }
119
120 void dump (pretty_printer *pp) const;
121
122 void set_location (location_t loc) { m_loc = loc; }
123
124 protected:
125 checker_event (enum event_kind kind,
126 location_t loc, tree fndecl, int depth);
127
128 public:
129 const enum event_kind m_kind;
130 protected:
131 location_t m_loc;
132 tree m_original_fndecl;
133 tree m_effective_fndecl;
134 int m_original_depth;
135 int m_effective_depth;
136 pending_diagnostic *m_pending_diagnostic;
137 diagnostic_event_id_t m_emission_id; // only set once all pruning has occurred
138 tree_logical_location m_logical_loc;
139 };
140
141 /* A concrete event subclass for a purely textual event, for use in
142 debugging path creation and filtering. */
143
144 class debug_event : public checker_event
145 {
146 public:
147 debug_event (location_t loc, tree fndecl, int depth,
148 const char *desc)
149 : checker_event (EK_DEBUG, loc, fndecl, depth),
150 m_desc (xstrdup (desc))
151 {
152 }
153 ~debug_event ()
154 {
155 free (m_desc);
156 }
157
158 label_text get_desc (bool) const final override;
159
160 private:
161 char *m_desc;
162 };
163
164 /* An abstract event subclass for custom events. These are not filtered,
165 as they are likely to be pertinent to the diagnostic. */
166
167 class custom_event : public checker_event
168 {
169 protected:
170 custom_event (location_t loc, tree fndecl, int depth)
171 : checker_event (EK_CUSTOM, loc, fndecl, depth)
172 {
173 }
174 };
175
176 /* A concrete custom_event subclass with a precanned message. */
177
178 class precanned_custom_event : public custom_event
179 {
180 public:
181 precanned_custom_event (location_t loc, tree fndecl, int depth,
182 const char *desc)
183 : custom_event (loc, fndecl, depth),
184 m_desc (xstrdup (desc))
185 {
186 }
187 ~precanned_custom_event ()
188 {
189 free (m_desc);
190 }
191
192 label_text get_desc (bool) const final override;
193
194 private:
195 char *m_desc;
196 };
197
198 /* A concrete event subclass describing the execution of a gimple statement,
199 for use at high verbosity levels when debugging paths. */
200
201 class statement_event : public checker_event
202 {
203 public:
204 statement_event (const gimple *stmt, tree fndecl, int depth,
205 const program_state &dst_state);
206
207 label_text get_desc (bool) const final override;
208
209 const gimple * const m_stmt;
210 const program_state m_dst_state;
211 };
212
213 /* A concrete event subclass describing the creation of a region that
214 is significant for a diagnostic e.g. "region created on stack here". */
215
216 class region_creation_event : public checker_event
217 {
218 public:
219 region_creation_event (const region *reg,
220 location_t loc, tree fndecl, int depth);
221
222 label_text get_desc (bool) const final override;
223
224 private:
225 const region *m_reg;
226 };
227
228 /* An event subclass describing the entry to a function. */
229
230 class function_entry_event : public checker_event
231 {
232 public:
233 function_entry_event (location_t loc, tree fndecl, int depth)
234 : checker_event (EK_FUNCTION_ENTRY, loc, fndecl, depth)
235 {
236 }
237
238 label_text get_desc (bool can_colorize) const final override;
239 meaning get_meaning () const override;
240
241 bool is_function_entry_p () const final override { return true; }
242 };
243
244 /* Subclass of checker_event describing a state change. */
245
246 class state_change_event : public checker_event
247 {
248 public:
249 state_change_event (const supernode *node, const gimple *stmt,
250 int stack_depth,
251 const state_machine &sm,
252 const svalue *sval,
253 state_machine::state_t from,
254 state_machine::state_t to,
255 const svalue *origin,
256 const program_state &dst_state);
257
258 label_text get_desc (bool can_colorize) const final override;
259 meaning get_meaning () const override;
260
261 function *get_dest_function () const
262 {
263 return m_dst_state.get_current_function ();
264 }
265
266 const supernode *m_node;
267 const gimple *m_stmt;
268 const state_machine &m_sm;
269 const svalue *m_sval;
270 state_machine::state_t m_from;
271 state_machine::state_t m_to;
272 const svalue *m_origin;
273 program_state m_dst_state;
274 };
275
276 /* Subclass of checker_event; parent class for subclasses that relate to
277 a superedge. */
278
279 class superedge_event : public checker_event
280 {
281 public:
282 /* Mark this edge event as being either an interprocedural call or
283 return in which VAR is in STATE, and that this is critical to the
284 diagnostic (so that get_desc can attempt to get a better description
285 from any pending_diagnostic). */
286 void record_critical_state (tree var, state_machine::state_t state)
287 {
288 m_var = var;
289 m_critical_state = state;
290 }
291
292 const callgraph_superedge& get_callgraph_superedge () const;
293
294 bool should_filter_p (int verbosity) const;
295
296 protected:
297 superedge_event (enum event_kind kind, const exploded_edge &eedge,
298 location_t loc, tree fndecl, int depth);
299
300 public:
301 const exploded_edge &m_eedge;
302 const superedge *m_sedge;
303 tree m_var;
304 state_machine::state_t m_critical_state;
305 };
306
307 /* An abstract event subclass for when a CFG edge is followed; it has two
308 subclasses, representing the start of the edge and the end of the
309 edge, which come in pairs. */
310
311 class cfg_edge_event : public superedge_event
312 {
313 public:
314 meaning get_meaning () const override;
315
316 const cfg_superedge& get_cfg_superedge () const;
317
318 protected:
319 cfg_edge_event (enum event_kind kind, const exploded_edge &eedge,
320 location_t loc, tree fndecl, int depth);
321 };
322
323 /* A concrete event subclass for the start of a CFG edge
324 e.g. "following 'false' branch...'. */
325
326 class start_cfg_edge_event : public cfg_edge_event
327 {
328 public:
329 start_cfg_edge_event (const exploded_edge &eedge,
330 location_t loc, tree fndecl, int depth)
331 : cfg_edge_event (EK_START_CFG_EDGE, eedge, loc, fndecl, depth)
332 {
333 }
334
335 label_text get_desc (bool can_colorize) const final override;
336
337 private:
338 label_text maybe_describe_condition (bool can_colorize) const;
339
340 static label_text maybe_describe_condition (bool can_colorize,
341 tree lhs,
342 enum tree_code op,
343 tree rhs);
344 static bool should_print_expr_p (tree);
345 };
346
347 /* A concrete event subclass for the end of a CFG edge
348 e.g. "...to here'. */
349
350 class end_cfg_edge_event : public cfg_edge_event
351 {
352 public:
353 end_cfg_edge_event (const exploded_edge &eedge,
354 location_t loc, tree fndecl, int depth)
355 : cfg_edge_event (EK_END_CFG_EDGE, eedge, loc, fndecl, depth)
356 {
357 }
358
359 label_text get_desc (bool /*can_colorize*/) const final override
360 {
361 return label_text::borrow ("...to here");
362 }
363 };
364
365 /* A concrete event subclass for an interprocedural call. */
366
367 class call_event : public superedge_event
368 {
369 public:
370 call_event (const exploded_edge &eedge,
371 location_t loc, tree fndecl, int depth);
372
373 label_text get_desc (bool can_colorize) const override;
374 meaning get_meaning () const override;
375
376 bool is_call_p () const final override;
377
378 protected:
379 tree get_caller_fndecl () const;
380 tree get_callee_fndecl () const;
381
382 const supernode *m_src_snode;
383 const supernode *m_dest_snode;
384 };
385
386 /* A concrete event subclass for an interprocedural return. */
387
388 class return_event : public superedge_event
389 {
390 public:
391 return_event (const exploded_edge &eedge,
392 location_t loc, tree fndecl, int depth);
393
394 label_text get_desc (bool can_colorize) const final override;
395 meaning get_meaning () const override;
396
397 bool is_return_p () const final override;
398
399 const supernode *m_src_snode;
400 const supernode *m_dest_snode;
401 };
402
403 /* A concrete event subclass for the start of a consolidated run of CFG
404 edges all either TRUE or FALSE e.g. "following 'false' branch...'. */
405
406 class start_consolidated_cfg_edges_event : public checker_event
407 {
408 public:
409 start_consolidated_cfg_edges_event (location_t loc, tree fndecl, int depth,
410 bool edge_sense)
411 : checker_event (EK_START_CONSOLIDATED_CFG_EDGES, loc, fndecl, depth),
412 m_edge_sense (edge_sense)
413 {
414 }
415
416 label_text get_desc (bool can_colorize) const final override;
417 meaning get_meaning () const override;
418
419 private:
420 bool m_edge_sense;
421 };
422
423 /* A concrete event subclass for the end of a consolidated run of
424 CFG edges e.g. "...to here'. */
425
426 class end_consolidated_cfg_edges_event : public checker_event
427 {
428 public:
429 end_consolidated_cfg_edges_event (location_t loc, tree fndecl, int depth)
430 : checker_event (EK_END_CONSOLIDATED_CFG_EDGES, loc, fndecl, depth)
431 {
432 }
433
434 label_text get_desc (bool /*can_colorize*/) const final override
435 {
436 return label_text::borrow ("...to here");
437 }
438 };
439
440 /* A concrete event subclass for describing an inlined call event
441 e.g. "inlined call to 'callee' from 'caller'". */
442
443 class inlined_call_event : public checker_event
444 {
445 public:
446 inlined_call_event (location_t loc,
447 tree apparent_callee_fndecl,
448 tree apparent_caller_fndecl,
449 int actual_depth,
450 int stack_depth_adjustment)
451 : checker_event (EK_INLINED_CALL, loc,
452 apparent_caller_fndecl,
453 actual_depth + stack_depth_adjustment),
454 m_apparent_callee_fndecl (apparent_callee_fndecl),
455 m_apparent_caller_fndecl (apparent_caller_fndecl)
456 {
457 gcc_assert (LOCATION_BLOCK (loc) == NULL);
458 }
459
460 label_text get_desc (bool /*can_colorize*/) const final override;
461 meaning get_meaning () const override;
462
463 private:
464 tree m_apparent_callee_fndecl;
465 tree m_apparent_caller_fndecl;
466 };
467
468 /* A concrete event subclass for a setjmp or sigsetjmp call. */
469
470 class setjmp_event : public checker_event
471 {
472 public:
473 setjmp_event (location_t loc, const exploded_node *enode,
474 tree fndecl, int depth, const gcall *setjmp_call)
475 : checker_event (EK_SETJMP, loc, fndecl, depth),
476 m_enode (enode), m_setjmp_call (setjmp_call)
477 {
478 }
479
480 label_text get_desc (bool can_colorize) const final override;
481
482 void prepare_for_emission (checker_path *path,
483 pending_diagnostic *pd,
484 diagnostic_event_id_t emission_id) final override;
485
486 private:
487 const exploded_node *m_enode;
488 const gcall *m_setjmp_call;
489 };
490
491 /* An abstract event subclass for rewinding from a longjmp to a setjmp
492 (or siglongjmp to sigsetjmp).
493
494 Base class for two from/to subclasses, showing the two halves of the
495 rewind. */
496
497 class rewind_event : public checker_event
498 {
499 public:
500 tree get_longjmp_caller () const;
501 tree get_setjmp_caller () const;
502 const exploded_edge *get_eedge () const { return m_eedge; }
503
504 protected:
505 rewind_event (const exploded_edge *eedge,
506 enum event_kind kind,
507 location_t loc, tree fndecl, int depth,
508 const rewind_info_t *rewind_info);
509 const rewind_info_t *m_rewind_info;
510
511 private:
512 const exploded_edge *m_eedge;
513 };
514
515 /* A concrete event subclass for rewinding from a longjmp to a setjmp,
516 showing the longjmp (or siglongjmp). */
517
518 class rewind_from_longjmp_event : public rewind_event
519 {
520 public:
521 rewind_from_longjmp_event (const exploded_edge *eedge,
522 location_t loc, tree fndecl, int depth,
523 const rewind_info_t *rewind_info)
524 : rewind_event (eedge, EK_REWIND_FROM_LONGJMP, loc, fndecl, depth,
525 rewind_info)
526 {
527 }
528
529 label_text get_desc (bool can_colorize) const final override;
530 };
531
532 /* A concrete event subclass for rewinding from a longjmp to a setjmp,
533 showing the setjmp (or sigsetjmp). */
534
535 class rewind_to_setjmp_event : public rewind_event
536 {
537 public:
538 rewind_to_setjmp_event (const exploded_edge *eedge,
539 location_t loc, tree fndecl, int depth,
540 const rewind_info_t *rewind_info)
541 : rewind_event (eedge, EK_REWIND_TO_SETJMP, loc, fndecl, depth,
542 rewind_info)
543 {
544 }
545
546 label_text get_desc (bool can_colorize) const final override;
547
548 void prepare_for_emission (checker_path *path,
549 pending_diagnostic *pd,
550 diagnostic_event_id_t emission_id) final override;
551
552 private:
553 diagnostic_event_id_t m_original_setjmp_event_id;
554 };
555
556 /* Concrete subclass of checker_event for use at the end of a path:
557 a repeat of the warning message at the end of the path (perhaps with
558 references to pertinent events that occurred on the way), at the point
559 where the problem occurs. */
560
561 class warning_event : public checker_event
562 {
563 public:
564 warning_event (location_t loc, tree fndecl, int depth,
565 const state_machine *sm,
566 tree var, state_machine::state_t state)
567 : checker_event (EK_WARNING, loc, fndecl, depth),
568 m_sm (sm), m_var (var), m_state (state)
569 {
570 }
571
572 label_text get_desc (bool can_colorize) const final override;
573 meaning get_meaning () const override;
574
575 private:
576 const state_machine *m_sm;
577 tree m_var;
578 state_machine::state_t m_state;
579 };
580
581 /* Subclass of diagnostic_path for analyzer diagnostics. */
582
583 class checker_path : public diagnostic_path
584 {
585 public:
586 checker_path () : diagnostic_path () {}
587
588 /* Implementation of diagnostic_path vfuncs. */
589
590 unsigned num_events () const final override
591 {
592 return m_events.length ();
593 }
594
595 const diagnostic_event & get_event (int idx) const final override
596 {
597 return *m_events[idx];
598 }
599
600 checker_event *get_checker_event (int idx)
601 {
602 return m_events[idx];
603 }
604
605 void dump (pretty_printer *pp) const;
606 void debug () const;
607
608 void maybe_log (logger *logger, const char *desc) const;
609
610 void add_event (checker_event *event)
611 {
612 m_events.safe_push (event);
613 }
614
615 void delete_event (int idx)
616 {
617 checker_event *event = m_events[idx];
618 m_events.ordered_remove (idx);
619 delete event;
620 }
621
622 void delete_events (unsigned start_idx, unsigned len)
623 {
624 for (unsigned i = start_idx; i < start_idx + len; i++)
625 delete m_events[i];
626 m_events.block_remove (start_idx, len);
627 }
628
629 void replace_event (unsigned idx, checker_event *new_event)
630 {
631 delete m_events[idx];
632 m_events[idx] = new_event;
633 }
634
635 void add_region_creation_event (const region *reg,
636 location_t loc,
637 tree fndecl, int depth);
638
639 void add_final_event (const state_machine *sm,
640 const exploded_node *enode, const gimple *stmt,
641 tree var, state_machine::state_t state);
642
643 /* After all event-pruning, a hook for notifying each event what
644 its ID will be. The events are notified in order, allowing
645 for later events to refer to the IDs of earlier events in
646 their descriptions. */
647 void prepare_for_emission (pending_diagnostic *pd)
648 {
649 checker_event *e;
650 int i;
651 FOR_EACH_VEC_ELT (m_events, i, e)
652 e->prepare_for_emission (this, pd, diagnostic_event_id_t (i));
653 }
654
655 void fixup_locations (pending_diagnostic *pd);
656
657 void record_setjmp_event (const exploded_node *enode,
658 diagnostic_event_id_t setjmp_emission_id)
659 {
660 m_setjmp_event_ids.put (enode, setjmp_emission_id);
661 }
662
663 bool get_setjmp_event (const exploded_node *enode,
664 diagnostic_event_id_t *out_emission_id)
665 {
666 if (diagnostic_event_id_t *emission_id = m_setjmp_event_ids.get (enode))
667 {
668 *out_emission_id = *emission_id;
669 return true;
670 }
671 return false;
672 }
673
674 bool cfg_edge_pair_at_p (unsigned idx) const;
675
676 void inject_any_inlined_call_events (logger *logger);
677
678 private:
679 DISABLE_COPY_AND_ASSIGN(checker_path);
680
681 /* The events that have occurred along this path. */
682 auto_delete_vec<checker_event> m_events;
683
684 /* During prepare_for_emission (and after), the setjmp_event for each
685 exploded_node *, so that rewind events can refer to them in their
686 descriptions. */
687 hash_map <const exploded_node *, diagnostic_event_id_t> m_setjmp_event_ids;
688 };
689
690 } // namespace ana
691
692 #endif /* GCC_ANALYZER_CHECKER_PATH_H */