Line data Source code
1 : /* Subclasses of diagnostics::paths::event for analyzer diagnostics.
2 : Copyright (C) 2019-2026 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_EVENT_H
22 : #define GCC_ANALYZER_CHECKER_EVENT_H
23 :
24 : #include "tree-logical-location.h"
25 : #include "analyzer/program-state.h"
26 : #include "analyzer/event-loc-info.h"
27 : #include "diagnostics/digraphs.h"
28 :
29 : namespace ana {
30 :
31 : /* An enum for discriminating between the concrete subclasses of
32 : checker_event. */
33 :
34 : enum class event_kind
35 : {
36 : debug,
37 : custom,
38 : stmt,
39 : region_creation,
40 : state_transition,
41 : function_entry,
42 : state_change,
43 : start_cfg_edge,
44 : end_cfg_edge,
45 : catch_,
46 : call_,
47 : return_,
48 : start_consolidated_cfg_edges,
49 : end_consolidated_cfg_edges,
50 : inlined_call,
51 : setjmp_,
52 : rewind_from_longjmp,
53 : rewind_to_setjmp,
54 : throw_,
55 : unwind,
56 : warning
57 : };
58 :
59 : extern const char *event_kind_to_string (enum event_kind ek);
60 :
61 : /* Event subclasses.
62 :
63 : The class hierarchy looks like this (using indentation to show
64 : inheritance, and with event_kinds shown for the concrete subclasses):
65 :
66 : diagnostics::paths::event
67 : checker_event
68 : debug_event (event_kind::debug)
69 : custom_event (event_kind::custom)
70 : precanned_custom_event
71 : statement_event (event_kind::stmt)
72 : state_transition_event (event_kind::data_flow)
73 : region_creation_event (event_kind::region_creation)
74 : function_entry_event (event_kind::function_entry)
75 : state_change_event (event_kind::state_change)
76 : superedge_event
77 : cfg_edge_event
78 : start_cfg_edge_event (event_kind::start_cfg_edge)
79 : end_cfg_edge_event (event_kind::end_cfg_edge)
80 : catch_cfg_edge_event (event_kind::catch_cfg_edge)
81 : call_event (event_kind::call_)
82 : return_event (event_kind::return_)
83 : start_consolidated_cfg_edges_event (event_kind::start_consolidated_cfg_edges)
84 : end_consolidated_cfg_edges_event (event_kind::end_consolidated_cfg_edges)
85 : inlined_call_event (event_kind::inlined_call)
86 : setjmp_event (event_kind::setjmp_)
87 : rewind_event
88 : rewind_from_longjmp_event (event_kind::rewind_from_longjmp)
89 : rewind_to_setjmp_event (event_kind::rewind_to_setjmp)
90 : throw_event (event_kind:throw_)
91 : explicit_throw_event
92 : throw_from_call_to_external_fn_event
93 : unwind_event (event_kind::unwind)
94 : warning_event (event_kind::warning). */
95 :
96 : /* Abstract subclass of diagnostics::paths::event; the base class for use in
97 : checker_path (the analyzer's diagnostics::paths::path subclass). */
98 :
99 20 : class checker_event : public diagnostics::paths::event
100 : {
101 : public:
102 : /* Implementation of diagnostics::paths::event. */
103 :
104 60028 : location_t get_location () const final override { return m_loc; }
105 15999 : int get_stack_depth () const final override { return m_effective_depth; }
106 : diagnostics::logical_locations::key
107 5075 : get_logical_location () const final override
108 : {
109 5075 : return m_logical_loc;
110 : }
111 : meaning get_meaning () const override;
112 2873 : bool connect_to_next_event_p () const override { return false; }
113 3773 : diagnostics::paths::thread_id_t get_thread_id () const final override
114 : {
115 3773 : return 0;
116 : }
117 :
118 : void
119 : maybe_add_sarif_properties (diagnostics::sarif_builder &,
120 : diagnostics::sarif_object &thread_flow_loc_obj)
121 : const override;
122 :
123 : /* Additional functionality. */
124 70425 : enum event_kind get_kind () const { return m_kind; }
125 11211 : tree get_fndecl () const { return m_effective_fndecl; }
126 :
127 5701 : int get_original_stack_depth () const { return m_original_depth; }
128 :
129 : virtual void prepare_for_emission (checker_path *,
130 : pending_diagnostic *pd,
131 : diagnostics::paths::event_id_t emission_id);
132 21717 : virtual bool is_call_p () const { return false; }
133 8 : virtual bool is_function_entry_p () const { return false; }
134 17403 : virtual bool is_return_p () const { return false; }
135 :
136 : std::unique_ptr<diagnostics::digraphs::digraph>
137 : maybe_make_diagnostic_state_graph (bool debug) const final override;
138 :
139 : virtual const program_state *
140 0 : get_program_state () const { return nullptr; }
141 :
142 : /* For use with %@. */
143 304 : const diagnostics::paths::event_id_t *get_id_ptr () const
144 : {
145 304 : return &m_emission_id;
146 : }
147 :
148 : void dump (pretty_printer *pp) const;
149 : void debug () const;
150 :
151 17355 : void set_location (location_t loc) { m_loc = loc; }
152 :
153 : protected:
154 : checker_event (enum event_kind kind,
155 : const event_loc_info &loc_info);
156 :
157 : private:
158 : const checker_path *m_path;
159 : const enum event_kind m_kind;
160 : protected:
161 : location_t m_loc;
162 : tree m_original_fndecl;
163 : tree m_effective_fndecl;
164 : int m_original_depth;
165 : int m_effective_depth;
166 : pending_diagnostic *m_pending_diagnostic;
167 : diagnostics::paths::event_id_t m_emission_id; // only set once all pruning has occurred
168 : diagnostics::logical_locations::key m_logical_loc;
169 : };
170 :
171 : /* A concrete event subclass for a purely textual event, for use in
172 : debugging path creation and filtering. */
173 :
174 : class debug_event : public checker_event
175 : {
176 : public:
177 :
178 : debug_event (const event_loc_info &loc_info,
179 : const char *desc)
180 : : checker_event (event_kind::debug, loc_info),
181 : m_desc (xstrdup (desc))
182 : {
183 : }
184 0 : ~debug_event ()
185 : {
186 0 : free (m_desc);
187 0 : }
188 :
189 : void print_desc (pretty_printer &) const final override;
190 :
191 : private:
192 : char *m_desc;
193 : };
194 :
195 : /* An abstract event subclass for custom events. These are not filtered,
196 : as they are likely to be pertinent to the diagnostic. */
197 :
198 20 : class custom_event : public checker_event
199 : {
200 : protected:
201 664 : custom_event (const event_loc_info &loc_info)
202 664 : : checker_event (event_kind::custom, loc_info)
203 : {
204 : }
205 : };
206 :
207 : /* A concrete custom_event subclass with a precanned message. */
208 :
209 : class precanned_custom_event : public custom_event
210 : {
211 : public:
212 20 : precanned_custom_event (const event_loc_info &loc_info,
213 : const char *desc)
214 20 : : custom_event (loc_info),
215 20 : m_desc (xstrdup (desc))
216 : {
217 20 : }
218 20 : ~precanned_custom_event ()
219 : {
220 20 : free (m_desc);
221 20 : }
222 :
223 : void print_desc (pretty_printer &) const final override;
224 :
225 : private:
226 : char *m_desc;
227 : };
228 :
229 : /* A concrete event subclass describing the execution of a gimple statement,
230 : for use at high verbosity levels when debugging paths. */
231 :
232 : class statement_event : public checker_event
233 : {
234 : public:
235 : statement_event (const gimple *stmt, tree fndecl, int depth,
236 : const program_state &dst_state);
237 :
238 : void print_desc (pretty_printer &) const final override;
239 :
240 : const program_state *
241 0 : get_program_state () const final override
242 : {
243 0 : return &m_dst_state;
244 : }
245 :
246 : const gimple * const m_stmt;
247 : const program_state m_dst_state;
248 : };
249 :
250 : /* A concrete checker_event subclass referencing a state_transition,
251 : for cases where the state_transition doesn't already have its own event. */
252 :
253 : class state_transition_event : public checker_event
254 : {
255 : public:
256 44 : state_transition_event (const event_loc_info &loc_info,
257 : const state_transition *state_trans)
258 44 : : checker_event (event_kind::state_transition, loc_info),
259 44 : m_state_trans (state_trans)
260 : {
261 44 : gcc_assert (m_state_trans);
262 44 : }
263 :
264 : void print_desc (pretty_printer &) const final override;
265 :
266 : void prepare_for_emission (checker_path *path,
267 : pending_diagnostic *pd,
268 : diagnostics::paths::event_id_t emission_id) final override;
269 :
270 : private:
271 : // borrowed from the exploded_path
272 : const state_transition *m_state_trans;
273 : };
274 :
275 : /* An abstract event subclass describing the creation of a region that
276 : is significant for a diagnostic.
277 :
278 : There are too many combinations to express region creation in one message,
279 : so we emit multiple region_creation_event instances when each pertinent
280 : region is created.
281 :
282 : The events are created by pending_diagnostic's add_region_creation_events
283 : vfunc, which by default creates a region_creation_event_memory_space, and
284 : if a capacity is known, a region_creation_event_capacity, giving e.g.:
285 : (1) region created on stack here
286 : (2) capacity: 100 bytes
287 : but this vfunc can be overridden to create other events if other wordings
288 : are more appropriate foa a given pending_diagnostic. */
289 :
290 : class region_creation_event : public checker_event
291 : {
292 : protected:
293 : region_creation_event (const event_loc_info &loc_info);
294 : };
295 :
296 : /* Concrete subclass of region_creation_event.
297 : Generates a message based on the memory space of the region
298 : e.g. "region created on stack here". */
299 :
300 : class region_creation_event_memory_space : public region_creation_event
301 : {
302 : public:
303 601 : region_creation_event_memory_space (enum memory_space mem_space,
304 : const event_loc_info &loc_info)
305 601 : : region_creation_event (loc_info),
306 601 : m_mem_space (mem_space)
307 : {
308 : }
309 :
310 : void print_desc (pretty_printer &pp) const final override;
311 :
312 : private:
313 : enum memory_space m_mem_space;
314 : };
315 :
316 : /* Concrete subclass of region_creation_event.
317 : Generates a message based on the capacity of the region
318 : e.g. "capacity: 100 bytes". */
319 :
320 : class region_creation_event_capacity : public region_creation_event
321 : {
322 : public:
323 815 : region_creation_event_capacity (tree capacity,
324 : const event_loc_info &loc_info)
325 815 : : region_creation_event (loc_info),
326 815 : m_capacity (capacity)
327 : {
328 815 : gcc_assert (m_capacity);
329 815 : }
330 :
331 : void print_desc (pretty_printer &pp) const final override;
332 :
333 : private:
334 : tree m_capacity;
335 : };
336 :
337 : /* Concrete subclass of region_creation_event.
338 : Generates a message based on the capacity of the region
339 : e.g. "allocated 100 bytes here". */
340 :
341 : class region_creation_event_allocation_size : public region_creation_event
342 : {
343 : public:
344 107 : region_creation_event_allocation_size (tree capacity,
345 : const event_loc_info &loc_info)
346 107 : : region_creation_event (loc_info),
347 107 : m_capacity (capacity)
348 : {}
349 :
350 : void print_desc (pretty_printer &pp) const final override;
351 :
352 : private:
353 : tree m_capacity;
354 : };
355 :
356 : /* Concrete subclass of region_creation_event.
357 : Generates a debug message intended for analyzer developers. */
358 :
359 : class region_creation_event_debug : public region_creation_event
360 : {
361 : public:
362 0 : region_creation_event_debug (const region *reg, tree capacity,
363 : const event_loc_info &loc_info)
364 0 : : region_creation_event (loc_info),
365 0 : m_reg (reg), m_capacity (capacity)
366 : {
367 : }
368 :
369 : void print_desc (pretty_printer &pp) const final override;
370 :
371 : private:
372 : const region *m_reg;
373 : tree m_capacity;
374 : };
375 :
376 : /* An event subclass describing the entry to a function. */
377 :
378 0 : class function_entry_event : public checker_event
379 : {
380 : public:
381 5322 : function_entry_event (const event_loc_info &loc_info,
382 : const program_state &state,
383 : const state_transition_at_call *state_trans)
384 5322 : : checker_event (event_kind::function_entry, loc_info),
385 5322 : m_state (state),
386 5322 : m_state_trans (state_trans)
387 : {
388 : }
389 :
390 : void print_desc (pretty_printer &pp) const override;
391 : meaning get_meaning () const override;
392 :
393 967 : bool is_function_entry_p () const final override { return true; }
394 :
395 : const program_state *
396 4 : get_program_state () const final override
397 : {
398 4 : return &m_state;
399 : }
400 :
401 : void
402 : prepare_for_emission (checker_path *path,
403 : pending_diagnostic *pd,
404 : diagnostics::paths::event_id_t emission_id) final override;
405 :
406 : const state_transition_at_call *
407 72 : get_state_transition_at_call () const { return m_state_trans; }
408 :
409 : private:
410 : const program_state &m_state;
411 : const state_transition_at_call *m_state_trans;
412 : };
413 :
414 : /* Subclass of checker_event describing a state change. */
415 :
416 : class state_change_event : public checker_event
417 : {
418 : public:
419 : state_change_event (const event_loc_info &loc_info,
420 : const gimple *stmt,
421 : const state_machine &sm,
422 : const svalue *sval,
423 : state_machine::state_t from,
424 : state_machine::state_t to,
425 : const svalue *origin,
426 : const program_state &dst_state,
427 : const exploded_node *enode);
428 :
429 : void print_desc (pretty_printer &pp) const final override;
430 : meaning get_meaning () const override;
431 :
432 : const program_state *
433 3 : get_program_state () const final override
434 : {
435 3 : return &m_dst_state;
436 : }
437 :
438 22 : const function *get_dest_function () const
439 : {
440 22 : return m_dst_state.get_current_function ();
441 : }
442 :
443 161 : const exploded_node *get_exploded_node () const { return m_enode; }
444 :
445 : const gimple *m_stmt;
446 : const state_machine &m_sm;
447 : const svalue *m_sval;
448 : state_machine::state_t m_from;
449 : state_machine::state_t m_to;
450 : const svalue *m_origin;
451 : program_state m_dst_state;
452 : const exploded_node *m_enode;
453 : };
454 :
455 : /* Subclass of checker_event; parent class for subclasses that relate to
456 : a superedge. */
457 :
458 0 : class superedge_event : public checker_event
459 : {
460 : public:
461 : void
462 : maybe_add_sarif_properties (diagnostics::sarif_builder &,
463 : diagnostics::sarif_object &thread_flow_loc_obj)
464 : const override;
465 :
466 : bool should_filter_p (int verbosity) const;
467 :
468 : const program_state *
469 : get_program_state () const override;
470 :
471 : virtual const call_and_return_op *
472 : get_call_and_return_op () const;
473 :
474 : protected:
475 : superedge_event (enum event_kind kind, const exploded_edge &eedge,
476 : const event_loc_info &loc_info);
477 :
478 : public:
479 : const exploded_edge &m_eedge;
480 : const superedge *m_sedge;
481 : };
482 :
483 : /* An abstract event subclass for when a CFG edge is followed; it has two
484 : subclasses, representing the start of the edge and the end of the
485 : edge, which come in pairs. */
486 :
487 : class cfg_edge_event : public superedge_event
488 : {
489 : public:
490 : meaning get_meaning () const override;
491 :
492 : ::edge get_cfg_edge () const;
493 :
494 : bool maybe_get_edge_sense (bool *out) const;
495 :
496 : protected:
497 : cfg_edge_event (enum event_kind kind,
498 : const exploded_edge &eedge,
499 : const event_loc_info &loc_info,
500 : const control_flow_op *op);
501 :
502 : const control_flow_op *m_op;
503 : };
504 :
505 : /* A concrete event subclass for the start of a CFG edge
506 : e.g. "following 'false' branch...'. */
507 :
508 : class start_cfg_edge_event : public cfg_edge_event
509 : {
510 : public:
511 2855 : start_cfg_edge_event (const exploded_edge &eedge,
512 : const event_loc_info &loc_info,
513 : const control_flow_op *op)
514 2855 : : cfg_edge_event (event_kind::start_cfg_edge, eedge, loc_info, op)
515 : {
516 : }
517 :
518 : void print_desc (pretty_printer &pp) const override;
519 482 : bool connect_to_next_event_p () const final override { return true; }
520 :
521 : private:
522 : static bool should_print_expr_p (tree);
523 : };
524 :
525 : /* A concrete event subclass for the end of a CFG edge
526 : e.g. "...to here'. */
527 :
528 : class end_cfg_edge_event : public cfg_edge_event
529 : {
530 : public:
531 2855 : end_cfg_edge_event (const exploded_edge &eedge,
532 : const event_loc_info &loc_info,
533 : const control_flow_op *op)
534 2855 : : cfg_edge_event (event_kind::end_cfg_edge, eedge, loc_info, op)
535 : {
536 : }
537 :
538 4986 : void print_desc (pretty_printer &pp) const final override
539 : {
540 4986 : pp_string (&pp, "...to here");
541 4986 : }
542 : };
543 :
544 : /* A concrete event subclass for catching an exception
545 : e.g. "...catching 'struct io_error' here". */
546 :
547 : class catch_cfg_edge_event : public cfg_edge_event
548 : {
549 : public:
550 66 : catch_cfg_edge_event (const exploded_edge &eedge,
551 : const event_loc_info &loc_info,
552 : const control_flow_op &op,
553 : tree type)
554 66 : : cfg_edge_event (event_kind::catch_, eedge, loc_info, &op),
555 66 : m_type (type)
556 : {
557 : }
558 :
559 144 : void print_desc (pretty_printer &pp) const final override
560 : {
561 144 : if (m_type)
562 114 : pp_printf (&pp, "...catching exception of type %qT here", m_type);
563 : else
564 30 : pp_string (&pp, "...catching exception here");
565 144 : }
566 :
567 : meaning get_meaning () const override;
568 :
569 : private:
570 : tree m_type;
571 : };
572 :
573 : struct critical_state
574 : {
575 1872 : critical_state ()
576 1872 : : m_var (NULL_TREE),
577 631 : m_state (nullptr)
578 : {
579 : }
580 312 : critical_state (tree var, state_machine::state_t state)
581 : : m_var (var),
582 : m_state (state)
583 : {
584 : }
585 :
586 : tree m_var;
587 : state_machine::state_t m_state;
588 : };
589 :
590 : /* A concrete event subclass for an interprocedural call. */
591 :
592 0 : class call_event : public superedge_event
593 : {
594 : public:
595 : call_event (const exploded_edge &eedge,
596 : const event_loc_info &loc_info,
597 : const state_transition_at_call *state_trans);
598 :
599 : void print_desc (pretty_printer &pp) const override;
600 : meaning get_meaning () const override;
601 :
602 : bool is_call_p () const final override;
603 :
604 : const program_state *
605 : get_program_state () const final override;
606 :
607 : void
608 : prepare_for_emission (checker_path *path,
609 : pending_diagnostic *pd,
610 : diagnostics::paths::event_id_t emission_id) final override;
611 :
612 : /* Mark this edge event as being either an interprocedural call or
613 : return in which VAR is in STATE, and that this is critical to the
614 : diagnostic (so that print_desc can attempt to get a better description
615 : from any pending_diagnostic). */
616 218 : void record_critical_state (tree var, state_machine::state_t state)
617 : {
618 218 : m_critical_state = critical_state (var, state);
619 218 : }
620 :
621 : const state_transition_at_call *
622 : get_state_transition_at_call () const { return m_state_trans; }
623 :
624 : protected:
625 : tree get_caller_fndecl () const;
626 : tree get_callee_fndecl () const;
627 :
628 : const supernode *m_src_snode;
629 : const supernode *m_dest_snode;
630 : critical_state m_critical_state;
631 : const state_transition_at_call *m_state_trans;
632 : };
633 :
634 : /* A concrete event subclass for an interprocedural return. */
635 :
636 : class return_event : public checker_event
637 : {
638 : public:
639 : return_event (const exploded_edge &eedge,
640 : const event_loc_info &loc_info,
641 : const state_transition_at_return *state_trans);
642 :
643 : void print_desc (pretty_printer &pp) const final override;
644 : meaning get_meaning () const override;
645 :
646 : bool is_return_p () const final override;
647 :
648 : const call_and_return_op *
649 443 : get_call_and_return_op () const
650 : {
651 443 : return m_call_and_return_op;
652 : }
653 :
654 : const program_state *
655 : get_program_state () const override;
656 :
657 : void
658 : prepare_for_emission (checker_path *path,
659 : pending_diagnostic *pd,
660 : diagnostics::paths::event_id_t emission_id) final override;
661 :
662 : /* Mark this edge event as being either an interprocedural call or
663 : return in which VAR is in STATE, and that this is critical to the
664 : diagnostic (so that print_desc can attempt to get a better description
665 : from any pending_diagnostic). */
666 94 : void record_critical_state (tree var, state_machine::state_t state)
667 : {
668 94 : m_critical_state = critical_state (var, state);
669 94 : }
670 :
671 : const exploded_edge &m_eedge;
672 : const supernode *m_src_snode;
673 : const supernode *m_dest_snode;
674 : const call_and_return_op *m_call_and_return_op;
675 : critical_state m_critical_state;
676 : const state_transition_at_return *m_state_trans;
677 : };
678 :
679 : /* A concrete event subclass for the start of a consolidated run of CFG
680 : edges all either TRUE or FALSE e.g. "following 'false' branch...'. */
681 :
682 : class start_consolidated_cfg_edges_event : public checker_event
683 : {
684 : public:
685 111 : start_consolidated_cfg_edges_event (const event_loc_info &loc_info,
686 : bool edge_sense)
687 111 : : checker_event (event_kind::start_consolidated_cfg_edges, loc_info),
688 111 : m_edge_sense (edge_sense)
689 : {
690 : }
691 :
692 : void print_desc (pretty_printer &pp) const final override;
693 : meaning get_meaning () const override;
694 0 : bool connect_to_next_event_p () const final override { return true; }
695 :
696 : private:
697 : bool m_edge_sense;
698 : };
699 :
700 : /* A concrete event subclass for the end of a consolidated run of
701 : CFG edges e.g. "...to here'. */
702 :
703 : class end_consolidated_cfg_edges_event : public checker_event
704 : {
705 : public:
706 111 : end_consolidated_cfg_edges_event (const event_loc_info &loc_info)
707 111 : : checker_event (event_kind::end_consolidated_cfg_edges, loc_info)
708 : {
709 : }
710 :
711 206 : void print_desc (pretty_printer &pp) const final override
712 : {
713 206 : pp_string (&pp, "...to here");
714 206 : }
715 : };
716 :
717 : /* A concrete event subclass for describing an inlined call event
718 : e.g. "inlined call to 'callee' from 'caller'". */
719 :
720 : class inlined_call_event : public checker_event
721 : {
722 : public:
723 165 : inlined_call_event (location_t loc,
724 : tree apparent_callee_fndecl,
725 : tree apparent_caller_fndecl,
726 : int actual_depth,
727 : int stack_depth_adjustment)
728 165 : : checker_event (event_kind::inlined_call,
729 165 : event_loc_info (loc,
730 : apparent_caller_fndecl,
731 165 : actual_depth + stack_depth_adjustment)),
732 165 : m_apparent_callee_fndecl (apparent_callee_fndecl),
733 165 : m_apparent_caller_fndecl (apparent_caller_fndecl)
734 : {
735 165 : gcc_assert (LOCATION_BLOCK (loc) == NULL);
736 165 : }
737 :
738 : void print_desc (pretty_printer &) const final override;
739 : meaning get_meaning () const override;
740 :
741 : private:
742 : tree m_apparent_callee_fndecl;
743 : tree m_apparent_caller_fndecl;
744 : };
745 :
746 : /* A concrete event subclass for a setjmp or sigsetjmp call. */
747 :
748 : class setjmp_event : public checker_event
749 : {
750 : public:
751 20 : setjmp_event (const event_loc_info &loc_info,
752 : const exploded_node *enode,
753 : const gcall &setjmp_call)
754 20 : : checker_event (event_kind::setjmp_, loc_info),
755 20 : m_enode (enode), m_setjmp_call (setjmp_call)
756 : {
757 : }
758 :
759 : void print_desc (pretty_printer &pp) const final override;
760 :
761 : meaning get_meaning () const override;
762 :
763 : void prepare_for_emission (checker_path *path,
764 : pending_diagnostic *pd,
765 : diagnostics::paths::event_id_t emission_id) final override;
766 :
767 : private:
768 : const exploded_node *m_enode;
769 : const gcall &m_setjmp_call;
770 : };
771 :
772 : /* An abstract event subclass for rewinding from a longjmp to a setjmp
773 : (or siglongjmp to sigsetjmp).
774 :
775 : Base class for two from/to subclasses, showing the two halves of the
776 : rewind. */
777 :
778 : class rewind_event : public checker_event
779 : {
780 : public:
781 : tree get_longjmp_caller () const;
782 : tree get_setjmp_caller () const;
783 : const exploded_edge *get_eedge () const { return m_eedge; }
784 :
785 : meaning get_meaning () const override;
786 :
787 : protected:
788 : rewind_event (const exploded_edge *eedge,
789 : enum event_kind kind,
790 : const event_loc_info &loc_info,
791 : const rewind_info_t *rewind_info);
792 : const rewind_info_t *m_rewind_info;
793 :
794 : private:
795 : const exploded_edge *m_eedge;
796 : };
797 :
798 : /* A concrete event subclass for rewinding from a longjmp to a setjmp,
799 : showing the longjmp (or siglongjmp). */
800 :
801 : class rewind_from_longjmp_event : public rewind_event
802 : {
803 : public:
804 15 : rewind_from_longjmp_event (const exploded_edge *eedge,
805 : const event_loc_info &loc_info,
806 : const rewind_info_t *rewind_info)
807 15 : : rewind_event (eedge, event_kind::rewind_from_longjmp, loc_info,
808 15 : rewind_info)
809 : {
810 : }
811 :
812 : void print_desc (pretty_printer &pp) const final override;
813 : };
814 :
815 : /* A concrete event subclass for rewinding from a longjmp to a setjmp,
816 : showing the setjmp (or sigsetjmp). */
817 :
818 : class rewind_to_setjmp_event : public rewind_event
819 : {
820 : public:
821 15 : rewind_to_setjmp_event (const exploded_edge *eedge,
822 : const event_loc_info &loc_info,
823 : const rewind_info_t *rewind_info)
824 15 : : rewind_event (eedge, event_kind::rewind_to_setjmp, loc_info,
825 15 : rewind_info)
826 : {
827 : }
828 :
829 : void print_desc (pretty_printer &pp) const final override;
830 :
831 : void prepare_for_emission (checker_path *path,
832 : pending_diagnostic *pd,
833 : diagnostics::paths::event_id_t emission_id) final override;
834 :
835 : private:
836 : diagnostics::paths::event_id_t m_original_setjmp_event_id;
837 : };
838 :
839 : /* An abstract subclass for throwing/rethrowing an exception. */
840 :
841 : class throw_event : public checker_event
842 : {
843 : public:
844 95 : throw_event (const event_loc_info &loc_info,
845 : const exploded_node *enode,
846 : const gcall &throw_call)
847 95 : : checker_event (event_kind::throw_, loc_info),
848 95 : m_enode (enode),
849 190 : m_throw_call (throw_call)
850 : {
851 : }
852 :
853 : meaning get_meaning () const override;
854 :
855 : protected:
856 : const exploded_node *m_enode;
857 : const gcall &m_throw_call;
858 : };
859 :
860 : /* A concrete event subclass for an explicit "throw EXC;"
861 : or "throw;" (actually, a call to __cxa_throw or __cxa_rethrow). */
862 :
863 : class explicit_throw_event : public throw_event
864 : {
865 : public:
866 69 : explicit_throw_event (const event_loc_info &loc_info,
867 : const exploded_node *enode,
868 : const gcall &throw_call,
869 : tree type,
870 : bool is_rethrow)
871 69 : : throw_event (loc_info, enode, throw_call),
872 69 : m_type (type),
873 69 : m_is_rethrow (is_rethrow)
874 : {
875 : }
876 :
877 : void print_desc (pretty_printer &pp) const final override;
878 :
879 : private:
880 : tree m_type;
881 : bool m_is_rethrow;
882 : };
883 :
884 : /* A concrete event subclass for an exception being thrown
885 : from within a call to a function we don't have the body of,
886 : or where we don't know what function was called. */
887 :
888 : class throw_from_call_to_external_fn_event : public throw_event
889 : {
890 : public:
891 26 : throw_from_call_to_external_fn_event (const event_loc_info &loc_info,
892 : const exploded_node *enode,
893 : const gcall &throw_call,
894 : tree fndecl)
895 26 : : throw_event (loc_info, enode, throw_call),
896 26 : m_fndecl (fndecl)
897 : {
898 : }
899 :
900 : void print_desc (pretty_printer &pp) const final override;
901 :
902 : private:
903 : tree m_fndecl;
904 : };
905 :
906 : /* A concrete event subclass for unwinding a stack frame when
907 : processing an exception. */
908 :
909 : class unwind_event : public checker_event
910 : {
911 : public:
912 16 : unwind_event (const event_loc_info &loc_info)
913 16 : : checker_event (event_kind::unwind, loc_info),
914 16 : m_num_frames (1)
915 : {
916 : }
917 :
918 : meaning get_meaning () const override;
919 :
920 : void print_desc (pretty_printer &pp) const final override;
921 :
922 : int m_num_frames;
923 : };
924 :
925 : /* Concrete subclass of checker_event for use at the end of a path:
926 : a repeat of the warning message at the end of the path (perhaps with
927 : references to pertinent events that occurred on the way), at the point
928 : where the problem occurs. */
929 :
930 : class warning_event : public checker_event
931 : {
932 : public:
933 4161 : warning_event (const event_loc_info &loc_info,
934 : const exploded_node *enode,
935 : const state_machine *sm,
936 : tree var, state_machine::state_t state,
937 : const program_state *program_state_ = nullptr)
938 4161 : : checker_event (event_kind::warning, loc_info),
939 4161 : m_enode (enode),
940 4161 : m_sm (sm), m_var (var), m_state (state)
941 : {
942 4161 : if (program_state_)
943 855 : m_program_state = std::make_unique<program_state> (*program_state_);
944 3923 : }
945 :
946 : void print_desc (pretty_printer &pp) const final override;
947 : meaning get_meaning () const override;
948 :
949 : const program_state *
950 : get_program_state () const final override;
951 :
952 165 : const exploded_node *get_exploded_node () const { return m_enode; }
953 :
954 : private:
955 : const exploded_node *m_enode;
956 : const state_machine *m_sm;
957 : tree m_var;
958 : state_machine::state_t m_state;
959 : /* Optional copy of program state, for when this is different from
960 : m_enode's state: */
961 : std::unique_ptr<program_state> m_program_state;
962 : };
963 :
964 : } // namespace ana
965 :
966 : #endif /* GCC_ANALYZER_CHECKER_EVENT_H */
|