]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/analyzer/checker-path.h
analyzer: implement trust boundaries via a plugin for Linux kernel
[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 /* There are too many combinations to express region creation in one message,
214 so we emit multiple region_creation_event instances when each pertinent
215 region is created.
216
217 This enum distinguishes between the different messages. */
218
219 enum rce_kind
220 {
221 /* Generate a message based on the memory space of the region
222 e.g. "region created on stack here". */
223 RCE_MEM_SPACE,
224
225 /* Generate a message based on the capacity of the region
226 e.g. "capacity: 100 bytes". */
227 RCE_CAPACITY,
228
229 /* Generate a debug message. */
230 RCE_DEBUG
231 };
232
233 /* A concrete event subclass describing the creation of a region that
234 is significant for a diagnostic. */
235
236 class region_creation_event : public checker_event
237 {
238 public:
239 region_creation_event (const region *reg,
240 tree capacity,
241 enum rce_kind kind,
242 location_t loc, tree fndecl, int depth);
243
244 label_text get_desc (bool can_colorize) const final override;
245
246 private:
247 const region *m_reg;
248 tree m_capacity;
249 enum rce_kind m_rce_kind;
250 };
251
252 /* An event subclass describing the entry to a function. */
253
254 class function_entry_event : public checker_event
255 {
256 public:
257 function_entry_event (location_t loc, tree fndecl, int depth)
258 : checker_event (EK_FUNCTION_ENTRY, loc, fndecl, depth)
259 {
260 }
261
262 label_text get_desc (bool can_colorize) const final override;
263 meaning get_meaning () const override;
264
265 bool is_function_entry_p () const final override { return true; }
266 };
267
268 /* Subclass of checker_event describing a state change. */
269
270 class state_change_event : public checker_event
271 {
272 public:
273 state_change_event (const supernode *node, const gimple *stmt,
274 int stack_depth,
275 const state_machine &sm,
276 const svalue *sval,
277 state_machine::state_t from,
278 state_machine::state_t to,
279 const svalue *origin,
280 const program_state &dst_state);
281
282 label_text get_desc (bool can_colorize) const final override;
283 meaning get_meaning () const override;
284
285 function *get_dest_function () const
286 {
287 return m_dst_state.get_current_function ();
288 }
289
290 const supernode *m_node;
291 const gimple *m_stmt;
292 const state_machine &m_sm;
293 const svalue *m_sval;
294 state_machine::state_t m_from;
295 state_machine::state_t m_to;
296 const svalue *m_origin;
297 program_state m_dst_state;
298 };
299
300 /* Subclass of checker_event; parent class for subclasses that relate to
301 a superedge. */
302
303 class superedge_event : public checker_event
304 {
305 public:
306 /* Mark this edge event as being either an interprocedural call or
307 return in which VAR is in STATE, and that this is critical to the
308 diagnostic (so that get_desc can attempt to get a better description
309 from any pending_diagnostic). */
310 void record_critical_state (tree var, state_machine::state_t state)
311 {
312 m_var = var;
313 m_critical_state = state;
314 }
315
316 const callgraph_superedge& get_callgraph_superedge () const;
317
318 bool should_filter_p (int verbosity) const;
319
320 protected:
321 superedge_event (enum event_kind kind, const exploded_edge &eedge,
322 location_t loc, tree fndecl, int depth);
323
324 public:
325 const exploded_edge &m_eedge;
326 const superedge *m_sedge;
327 tree m_var;
328 state_machine::state_t m_critical_state;
329 };
330
331 /* An abstract event subclass for when a CFG edge is followed; it has two
332 subclasses, representing the start of the edge and the end of the
333 edge, which come in pairs. */
334
335 class cfg_edge_event : public superedge_event
336 {
337 public:
338 meaning get_meaning () const override;
339
340 const cfg_superedge& get_cfg_superedge () const;
341
342 protected:
343 cfg_edge_event (enum event_kind kind, const exploded_edge &eedge,
344 location_t loc, tree fndecl, int depth);
345 };
346
347 /* A concrete event subclass for the start of a CFG edge
348 e.g. "following 'false' branch...'. */
349
350 class start_cfg_edge_event : public cfg_edge_event
351 {
352 public:
353 start_cfg_edge_event (const exploded_edge &eedge,
354 location_t loc, tree fndecl, int depth)
355 : cfg_edge_event (EK_START_CFG_EDGE, eedge, loc, fndecl, depth)
356 {
357 }
358
359 label_text get_desc (bool can_colorize) const final override;
360
361 private:
362 label_text maybe_describe_condition (bool can_colorize) const;
363
364 static label_text maybe_describe_condition (bool can_colorize,
365 tree lhs,
366 enum tree_code op,
367 tree rhs);
368 static bool should_print_expr_p (tree);
369 };
370
371 /* A concrete event subclass for the end of a CFG edge
372 e.g. "...to here'. */
373
374 class end_cfg_edge_event : public cfg_edge_event
375 {
376 public:
377 end_cfg_edge_event (const exploded_edge &eedge,
378 location_t loc, tree fndecl, int depth)
379 : cfg_edge_event (EK_END_CFG_EDGE, eedge, loc, fndecl, depth)
380 {
381 }
382
383 label_text get_desc (bool /*can_colorize*/) const final override
384 {
385 return label_text::borrow ("...to here");
386 }
387 };
388
389 /* A concrete event subclass for an interprocedural call. */
390
391 class call_event : public superedge_event
392 {
393 public:
394 call_event (const exploded_edge &eedge,
395 location_t loc, tree fndecl, int depth);
396
397 label_text get_desc (bool can_colorize) const override;
398 meaning get_meaning () const override;
399
400 bool is_call_p () const final override;
401
402 protected:
403 tree get_caller_fndecl () const;
404 tree get_callee_fndecl () const;
405
406 const supernode *m_src_snode;
407 const supernode *m_dest_snode;
408 };
409
410 /* A concrete event subclass for an interprocedural return. */
411
412 class return_event : public superedge_event
413 {
414 public:
415 return_event (const exploded_edge &eedge,
416 location_t loc, tree fndecl, int depth);
417
418 label_text get_desc (bool can_colorize) const final override;
419 meaning get_meaning () const override;
420
421 bool is_return_p () const final override;
422
423 const supernode *m_src_snode;
424 const supernode *m_dest_snode;
425 };
426
427 /* A concrete event subclass for the start of a consolidated run of CFG
428 edges all either TRUE or FALSE e.g. "following 'false' branch...'. */
429
430 class start_consolidated_cfg_edges_event : public checker_event
431 {
432 public:
433 start_consolidated_cfg_edges_event (location_t loc, tree fndecl, int depth,
434 bool edge_sense)
435 : checker_event (EK_START_CONSOLIDATED_CFG_EDGES, loc, fndecl, depth),
436 m_edge_sense (edge_sense)
437 {
438 }
439
440 label_text get_desc (bool can_colorize) const final override;
441 meaning get_meaning () const override;
442
443 private:
444 bool m_edge_sense;
445 };
446
447 /* A concrete event subclass for the end of a consolidated run of
448 CFG edges e.g. "...to here'. */
449
450 class end_consolidated_cfg_edges_event : public checker_event
451 {
452 public:
453 end_consolidated_cfg_edges_event (location_t loc, tree fndecl, int depth)
454 : checker_event (EK_END_CONSOLIDATED_CFG_EDGES, loc, fndecl, depth)
455 {
456 }
457
458 label_text get_desc (bool /*can_colorize*/) const final override
459 {
460 return label_text::borrow ("...to here");
461 }
462 };
463
464 /* A concrete event subclass for describing an inlined call event
465 e.g. "inlined call to 'callee' from 'caller'". */
466
467 class inlined_call_event : public checker_event
468 {
469 public:
470 inlined_call_event (location_t loc,
471 tree apparent_callee_fndecl,
472 tree apparent_caller_fndecl,
473 int actual_depth,
474 int stack_depth_adjustment)
475 : checker_event (EK_INLINED_CALL, loc,
476 apparent_caller_fndecl,
477 actual_depth + stack_depth_adjustment),
478 m_apparent_callee_fndecl (apparent_callee_fndecl),
479 m_apparent_caller_fndecl (apparent_caller_fndecl)
480 {
481 gcc_assert (LOCATION_BLOCK (loc) == NULL);
482 }
483
484 label_text get_desc (bool /*can_colorize*/) const final override;
485 meaning get_meaning () const override;
486
487 private:
488 tree m_apparent_callee_fndecl;
489 tree m_apparent_caller_fndecl;
490 };
491
492 /* A concrete event subclass for a setjmp or sigsetjmp call. */
493
494 class setjmp_event : public checker_event
495 {
496 public:
497 setjmp_event (location_t loc, const exploded_node *enode,
498 tree fndecl, int depth, const gcall *setjmp_call)
499 : checker_event (EK_SETJMP, loc, fndecl, depth),
500 m_enode (enode), m_setjmp_call (setjmp_call)
501 {
502 }
503
504 label_text get_desc (bool can_colorize) const final override;
505
506 void prepare_for_emission (checker_path *path,
507 pending_diagnostic *pd,
508 diagnostic_event_id_t emission_id) final override;
509
510 private:
511 const exploded_node *m_enode;
512 const gcall *m_setjmp_call;
513 };
514
515 /* An abstract event subclass for rewinding from a longjmp to a setjmp
516 (or siglongjmp to sigsetjmp).
517
518 Base class for two from/to subclasses, showing the two halves of the
519 rewind. */
520
521 class rewind_event : public checker_event
522 {
523 public:
524 tree get_longjmp_caller () const;
525 tree get_setjmp_caller () const;
526 const exploded_edge *get_eedge () const { return m_eedge; }
527
528 protected:
529 rewind_event (const exploded_edge *eedge,
530 enum event_kind kind,
531 location_t loc, tree fndecl, int depth,
532 const rewind_info_t *rewind_info);
533 const rewind_info_t *m_rewind_info;
534
535 private:
536 const exploded_edge *m_eedge;
537 };
538
539 /* A concrete event subclass for rewinding from a longjmp to a setjmp,
540 showing the longjmp (or siglongjmp). */
541
542 class rewind_from_longjmp_event : public rewind_event
543 {
544 public:
545 rewind_from_longjmp_event (const exploded_edge *eedge,
546 location_t loc, tree fndecl, int depth,
547 const rewind_info_t *rewind_info)
548 : rewind_event (eedge, EK_REWIND_FROM_LONGJMP, loc, fndecl, depth,
549 rewind_info)
550 {
551 }
552
553 label_text get_desc (bool can_colorize) const final override;
554 };
555
556 /* A concrete event subclass for rewinding from a longjmp to a setjmp,
557 showing the setjmp (or sigsetjmp). */
558
559 class rewind_to_setjmp_event : public rewind_event
560 {
561 public:
562 rewind_to_setjmp_event (const exploded_edge *eedge,
563 location_t loc, tree fndecl, int depth,
564 const rewind_info_t *rewind_info)
565 : rewind_event (eedge, EK_REWIND_TO_SETJMP, loc, fndecl, depth,
566 rewind_info)
567 {
568 }
569
570 label_text get_desc (bool can_colorize) const final override;
571
572 void prepare_for_emission (checker_path *path,
573 pending_diagnostic *pd,
574 diagnostic_event_id_t emission_id) final override;
575
576 private:
577 diagnostic_event_id_t m_original_setjmp_event_id;
578 };
579
580 /* Concrete subclass of checker_event for use at the end of a path:
581 a repeat of the warning message at the end of the path (perhaps with
582 references to pertinent events that occurred on the way), at the point
583 where the problem occurs. */
584
585 class warning_event : public checker_event
586 {
587 public:
588 warning_event (location_t loc, tree fndecl, int depth,
589 const state_machine *sm,
590 tree var, state_machine::state_t state)
591 : checker_event (EK_WARNING, loc, fndecl, depth),
592 m_sm (sm), m_var (var), m_state (state)
593 {
594 }
595
596 label_text get_desc (bool can_colorize) const final override;
597 meaning get_meaning () const override;
598
599 private:
600 const state_machine *m_sm;
601 tree m_var;
602 state_machine::state_t m_state;
603 };
604
605 /* Subclass of diagnostic_path for analyzer diagnostics. */
606
607 class checker_path : public diagnostic_path
608 {
609 public:
610 checker_path () : diagnostic_path () {}
611
612 /* Implementation of diagnostic_path vfuncs. */
613
614 unsigned num_events () const final override
615 {
616 return m_events.length ();
617 }
618
619 const diagnostic_event & get_event (int idx) const final override
620 {
621 return *m_events[idx];
622 }
623
624 checker_event *get_checker_event (int idx)
625 {
626 return m_events[idx];
627 }
628
629 void dump (pretty_printer *pp) const;
630 void debug () const;
631
632 void maybe_log (logger *logger, const char *desc) const;
633
634 void add_event (checker_event *event)
635 {
636 m_events.safe_push (event);
637 }
638
639 void delete_event (int idx)
640 {
641 checker_event *event = m_events[idx];
642 m_events.ordered_remove (idx);
643 delete event;
644 }
645
646 void delete_events (unsigned start_idx, unsigned len)
647 {
648 for (unsigned i = start_idx; i < start_idx + len; i++)
649 delete m_events[i];
650 m_events.block_remove (start_idx, len);
651 }
652
653 void replace_event (unsigned idx, checker_event *new_event)
654 {
655 delete m_events[idx];
656 m_events[idx] = new_event;
657 }
658
659 void add_region_creation_events (const region *reg,
660 const region_model *model,
661 location_t loc,
662 tree fndecl, int depth,
663 bool debug);
664
665 void add_final_event (const state_machine *sm,
666 const exploded_node *enode, const gimple *stmt,
667 tree var, state_machine::state_t state);
668
669 /* After all event-pruning, a hook for notifying each event what
670 its ID will be. The events are notified in order, allowing
671 for later events to refer to the IDs of earlier events in
672 their descriptions. */
673 void prepare_for_emission (pending_diagnostic *pd)
674 {
675 checker_event *e;
676 int i;
677 FOR_EACH_VEC_ELT (m_events, i, e)
678 e->prepare_for_emission (this, pd, diagnostic_event_id_t (i));
679 }
680
681 void fixup_locations (pending_diagnostic *pd);
682
683 void record_setjmp_event (const exploded_node *enode,
684 diagnostic_event_id_t setjmp_emission_id)
685 {
686 m_setjmp_event_ids.put (enode, setjmp_emission_id);
687 }
688
689 bool get_setjmp_event (const exploded_node *enode,
690 diagnostic_event_id_t *out_emission_id)
691 {
692 if (diagnostic_event_id_t *emission_id = m_setjmp_event_ids.get (enode))
693 {
694 *out_emission_id = *emission_id;
695 return true;
696 }
697 return false;
698 }
699
700 bool cfg_edge_pair_at_p (unsigned idx) const;
701
702 void inject_any_inlined_call_events (logger *logger);
703
704 private:
705 DISABLE_COPY_AND_ASSIGN(checker_path);
706
707 /* The events that have occurred along this path. */
708 auto_delete_vec<checker_event> m_events;
709
710 /* During prepare_for_emission (and after), the setjmp_event for each
711 exploded_node *, so that rewind events can refer to them in their
712 descriptions. */
713 hash_map <const exploded_node *, diagnostic_event_id_t> m_setjmp_event_ids;
714 };
715
716 } // namespace ana
717
718 #endif /* GCC_ANALYZER_CHECKER_PATH_H */