diff options
Diffstat (limited to 'gcc/diagnostics/paths.h')
-rw-r--r-- | gcc/diagnostics/paths.h | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/gcc/diagnostics/paths.h b/gcc/diagnostics/paths.h new file mode 100644 index 0000000..d30c420 --- /dev/null +++ b/gcc/diagnostics/paths.h @@ -0,0 +1,250 @@ +/* Paths through the code associated with a diagnostic. + Copyright (C) 2019-2025 Free Software Foundation, Inc. + Contributed by David Malcolm <dmalcolm@redhat.com> + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#ifndef GCC_DIAGNOSTICS_PATHS_H +#define GCC_DIAGNOSTICS_PATHS_H + +#include "diagnostic.h" /* for ATTRIBUTE_GCC_DIAG. */ +#include "diagnostics/event-id.h" +#include "diagnostics/logical-locations.h" + +namespace diagnostics { + namespace digraphs { + class digraph; + } // namespace digraphs + namespace logical_locations { + class manager; + } // logical_locations + class sarif_builder; + class sarif_object; +} //namespace diagnostics + +namespace diagnostics { +namespace paths { + +/* A diagnostics::paths::path is an optional additional piece of metadata associated + with a diagnostic (via its rich_location). + + It describes a sequence of events predicted by the compiler that + lead to the problem occurring, with their locations in the user's source, + and text descriptions. + + For example, the following error has a 3-event path: + + test.c: In function 'demo': + test.c:29:5: error: passing NULL as argument 1 to 'PyList_Append' which + requires a non-NULL parameter + 29 | PyList_Append(list, item); + | ^~~~~~~~~~~~~~~~~~~~~~~~~ + 'demo': events 1-3 + 25 | list = PyList_New(0); + | ^~~~~~~~~~~~~ + | | + | (1) when 'PyList_New' fails, returning NULL + 26 | + 27 | for (i = 0; i < count; i++) { + | ~~~ + | | + | (2) when 'i < count' + 28 | item = PyLong_FromLong(random()); + 29 | PyList_Append(list, item); + | ~~~~~~~~~~~~~~~~~~~~~~~~~ + | | + | (3) when calling 'PyList_Append', passing NULL from (1) as argument 1 + + The diagnostic-printing code has consolidated the path into a single + run of events, since all the events are near each other and within the same + function; more complicated examples (such as interprocedural paths) + might be printed as multiple runs of events. */ + +/* Abstract base classes, describing events within a path, and the paths + themselves. */ + +/* One event within a path. */ + +class event +{ + public: + /* Enums for giving a sense of what this event means. + Roughly corresponds to SARIF v2.1.0 section 3.38.8. */ + enum class verb + { + unknown, + + acquire, + release, + enter, + exit, + call, + return_, + branch, + + danger + }; + enum class noun + { + unknown, + + taint, + sensitive, // this one isn't in SARIF v2.1.0; filed as https://github.com/oasis-tcs/sarif-spec/issues/530 + function, + lock, + memory, + resource + }; + enum class property + { + unknown, + + true_, + false_ + }; + /* A bundle of such enums, allowing for descriptions of the meaning of + an event, such as + - "acquire memory": meaning (verb::acquire, noun::memory) + - "take true branch"": meaning (verb::branch, property::true) + - "return from function": meaning (verb::return, noun::function) + etc, as per SARIF's threadFlowLocation "kinds" property + (SARIF v2.1.0 section 3.38.8). */ + struct meaning + { + meaning () + : m_verb (verb::unknown), + m_noun (noun::unknown), + m_property (property::unknown) + { + } + meaning (enum verb verb, enum noun noun) + : m_verb (verb), m_noun (noun), m_property (property::unknown) + { + } + meaning (enum verb verb, enum property property) + : m_verb (verb), m_noun (noun::unknown), m_property (property) + { + } + + void dump_to_pp (pretty_printer *pp) const; + + static const char *maybe_get_verb_str (enum verb); + static const char *maybe_get_noun_str (enum noun); + static const char *maybe_get_property_str (enum property); + + enum verb m_verb; + enum noun m_noun; + enum property m_property; + }; + + virtual ~event () {} + + virtual location_t get_location () const = 0; + + /* Stack depth, so that consumers can visualize the interprocedural + calls, returns, and frame nesting. */ + virtual int get_stack_depth () const = 0; + + /* Print a localized (and possibly colorized) description of this event. */ + virtual void print_desc (pretty_printer &pp) const = 0; + + /* Get a logical location for this event, or null if there is none. */ + virtual logical_locations::key get_logical_location () const = 0; + + virtual meaning get_meaning () const = 0; + + /* True iff we should draw a line connecting this event to the + next event (e.g. to highlight control flow). */ + virtual bool connect_to_next_event_p () const = 0; + + virtual thread_id_t get_thread_id () const = 0; + + /* Hook for SARIF output to allow for adding diagnostic-specific + properties to the threadFlowLocation object's property bag. */ + virtual void + maybe_add_sarif_properties (sarif_builder &, + sarif_object &/*thread_flow_loc_obj*/) const + { + } + + /* Hook for capturing state at this event, potentially for visualizing + in HTML output, or for adding to SARIF. */ + virtual std::unique_ptr<digraphs::digraph> + maybe_make_diagnostic_state_graph (bool debug) const; + + label_text get_desc (pretty_printer &ref_pp) const; +}; + +/* Abstract base class representing a thread of execution within + a diagnostics::paths::path. + Each event is associated with one thread. + Typically there is just one thread per diagnostics::paths::path. */ + +class thread +{ +public: + virtual ~thread () {} + virtual label_text get_name (bool can_colorize) const = 0; +}; + +/* Abstract base class for getting at a sequence of events. */ + +class path +{ + public: + virtual ~path () {} + virtual unsigned num_events () const = 0; + virtual const event & get_event (int idx) const = 0; + virtual unsigned num_threads () const = 0; + virtual const thread & + get_thread (thread_id_t) const = 0; + + /* Return true iff the two events are both within the same function, + or both outside of any function. */ + virtual bool + same_function_p (int event_idx_a, + int event_idx_b) const = 0; + + bool interprocedural_p () const; + bool multithreaded_p () const; + + const logical_locations::manager &get_logical_location_manager () const + { + return m_logical_loc_mgr; + } + +protected: + path (const logical_locations::manager &logical_loc_mgr) + : m_logical_loc_mgr (logical_loc_mgr) + { + } + +private: + bool get_first_event_in_a_function (unsigned *out_idx) const; + + const logical_locations::manager &m_logical_loc_mgr; +}; + +} // namespace paths +} // namespace diagnostics + +/* Concrete subclasses of the above can be found in + simple-diagnostic-path.h. */ + +extern void debug (diagnostics::paths::path *path); + +#endif /* ! GCC_DIAGNOSTICS_PATHS_H */ |