This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH 32/49] analyzer: new files: pending-diagnostic.{cc|h}
- From: David Malcolm <dmalcolm at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Cc: David Malcolm <dmalcolm at redhat dot com>
- Date: Fri, 15 Nov 2019 20:23:19 -0500
- Subject: [PATCH 32/49] analyzer: new files: pending-diagnostic.{cc|h}
- References: <1573867416-55618-1-git-send-email-dmalcolm@redhat.com>
This patch adds classes used by the analyzer for handling its diagnostics
(queueing them, deduplicating them, precision-of-wording hooks).
gcc/ChangeLog:
* analyzer/pending-diagnostic.cc: New file.
* analyzer/pending-diagnostic.h: New file.
---
gcc/analyzer/pending-diagnostic.cc | 61 +++++++++
gcc/analyzer/pending-diagnostic.h | 265 +++++++++++++++++++++++++++++++++++++
2 files changed, 326 insertions(+)
create mode 100644 gcc/analyzer/pending-diagnostic.cc
create mode 100644 gcc/analyzer/pending-diagnostic.h
diff --git a/gcc/analyzer/pending-diagnostic.cc b/gcc/analyzer/pending-diagnostic.cc
new file mode 100644
index 0000000..96ab824
--- /dev/null
+++ b/gcc/analyzer/pending-diagnostic.cc
@@ -0,0 +1,61 @@
+/* Classes for analyzer diagnostics.
+ Copyright (C) 2019 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/>. */
+
+#include "config.h"
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "intl.h"
+#include "diagnostic.h"
+#include "analyzer/analyzer.h"
+#include "analyzer/pending-diagnostic.h"
+
+/* Generate a label_text by printing FMT.
+
+ Use a clone of the global_dc for formatting callbacks.
+
+ Use this evdesc::event_desc's m_colorize flag to control colorization
+ (so that e.g. we can disable it for JSON output). */
+
+label_text
+evdesc::event_desc::formatted_print (const char *fmt, ...) const
+{
+ pretty_printer *pp = global_dc->printer->clone ();
+
+ pp_show_color (pp) = m_colorize;
+
+ text_info ti;
+ rich_location rich_loc (line_table, UNKNOWN_LOCATION);
+ va_list ap;
+ va_start (ap, fmt);
+ ti.format_spec = _(fmt);
+ ti.args_ptr = ≈
+ ti.err_no = 0;
+ ti.x_data = NULL;
+ ti.m_richloc = &rich_loc;
+ pp_format (pp, &ti);
+ pp_output_formatted_text (pp);
+ va_end (ap);
+
+ label_text result = label_text::take (xstrdup (pp_formatted_text (pp)));
+ delete pp;
+ return result;
+}
diff --git a/gcc/analyzer/pending-diagnostic.h b/gcc/analyzer/pending-diagnostic.h
new file mode 100644
index 0000000..f1ab484
--- /dev/null
+++ b/gcc/analyzer/pending-diagnostic.h
@@ -0,0 +1,265 @@
+/* Classes for analyzer diagnostics.
+ Copyright (C) 2019 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_ANALYZER_PENDING_DIAGNOSTIC_H
+#define GCC_ANALYZER_PENDING_DIAGNOSTIC_H
+
+#include "diagnostic-event-id.h"
+#include "analyzer/sm.h"
+
+/* Various bundles of information used for generating more precise
+ messages for events within a diagnostic_path, for passing to the
+ various "describe_*" vfuncs of pending_diagnostic. See those
+ for more information. */
+
+namespace evdesc {
+
+struct event_desc
+{
+ event_desc (bool colorize) : m_colorize (colorize) {}
+
+ label_text formatted_print (const char *fmt, ...) const
+ ATTRIBUTE_GCC_DIAG(2,3);
+
+ bool m_colorize;
+};
+
+/* For use by pending_diagnostic::describe_state_change. */
+
+struct state_change : public event_desc
+{
+ state_change (bool colorize,
+ tree expr,
+ tree origin,
+ state_machine::state_t old_state,
+ state_machine::state_t new_state,
+ diagnostic_event_id_t event_id)
+ : event_desc (colorize),
+ m_expr (expr), m_origin (origin),
+ m_old_state (old_state), m_new_state (new_state),
+ m_event_id (event_id)
+ {}
+
+ tree m_expr;
+ tree m_origin;
+ state_machine::state_t m_old_state;
+ state_machine::state_t m_new_state;
+ diagnostic_event_id_t m_event_id;
+};
+
+/* For use by pending_diagnostic::describe_call_with_state. */
+
+struct call_with_state : public event_desc
+{
+ call_with_state (bool colorize,
+ tree caller_fndecl, tree callee_fndecl,
+ tree expr, state_machine::state_t state)
+ : event_desc (colorize),
+ m_caller_fndecl (caller_fndecl),
+ m_callee_fndecl (callee_fndecl),
+ m_expr (expr),
+ m_state (state)
+ {
+ }
+
+ tree m_caller_fndecl;
+ tree m_callee_fndecl;
+ tree m_expr;
+ state_machine::state_t m_state;
+};
+
+/* For use by pending_diagnostic::describe_return_of_state. */
+
+struct return_of_state : public event_desc
+{
+ return_of_state (bool colorize,
+ tree caller_fndecl, tree callee_fndecl,
+ state_machine::state_t state)
+ : event_desc (colorize),
+ m_caller_fndecl (caller_fndecl),
+ m_callee_fndecl (callee_fndecl),
+ m_state (state)
+ {
+ }
+
+ tree m_caller_fndecl;
+ tree m_callee_fndecl;
+ state_machine::state_t m_state;
+};
+
+/* For use by pending_diagnostic::describe_final_event. */
+
+struct final_event : public event_desc
+{
+ final_event (bool colorize,
+ tree expr, state_machine::state_t state)
+ : event_desc (colorize),
+ m_expr (expr), m_state (state)
+ {}
+
+ tree m_expr;
+ state_machine::state_t m_state;
+};
+
+} /* end of namespace evdesc */
+
+/* An abstract base class for capturing information about a diagnostic in
+ a form that is ready to emit at a later point (or be rejected).
+ Each kind of diagnostic will have a concrete subclass of
+ pending_diagnostic.
+
+ Normally, gcc diagnostics are emitted using va_list, which can't be
+ portably stored for later use, so we have to use an "emit" virtual
+ function.
+
+ This class also supports comparison, so that multiple pending_diagnostic
+ instances can be de-duplicated.
+
+ As well as emitting a diagnostic, the class has various "precision of
+ wording" virtual functions, for generating descriptions for events
+ within a diagnostic_path. These are optional, but implementing these
+ allows for more precise wordings than the more generic
+ implementation. */
+
+class pending_diagnostic
+{
+ public:
+ virtual ~pending_diagnostic () {}
+
+ /* Vfunc for emitting the diagnostic. The rich_location will have been
+ populated with a diagnostic_path.
+ Return true if a diagnostic is actually emitted. */
+ virtual bool emit (rich_location *) = 0;
+
+ /* Hand-coded RTTI: get an ID for the subclass. */
+ virtual const char *get_kind () const = 0;
+
+ /* Compare for equality with OTHER, which might be of a different
+ subclass. */
+
+ bool equal_p (const pending_diagnostic &other)
+ {
+ /* Check for pointer equality on the IDs from get_kind. */
+ if (get_kind () != other.get_kind ())
+ return false;
+ /* Call vfunc now we know they have the same ID: */
+ return subclass_equal_p (other);
+ }
+
+ /* A vfunc for testing for equality, where we've already
+ checked they have the same ID. See pending_diagnostic_subclass
+ below for a convenience subclass for implementing this. */
+ virtual bool subclass_equal_p (const pending_diagnostic &other) const = 0;
+
+ /* For greatest precision-of-wording, the various following "describe_*"
+ virtual functions give the pending diagnostic a way to describe events
+ in a diagnostic_path in terms that make sense for that diagnostic.
+
+ In each case, return a non-NULL label_text to give the event a custom
+ description; NULL otherwise (falling back on a more generic
+ description). */
+
+ /* Precision-of-wording vfunc for describing a critical state change
+ within the diagnostic_path.
+
+ For example, a double-free diagnostic might use the descriptions:
+ - "first 'free' happens here"
+ - "second 'free' happens here"
+ for the pertinent events, whereas a use-after-free might use the
+ descriptions:
+ - "freed here"
+ - "use after free here"
+ Note how in both cases the first event is a "free": the best
+ description to use depends on the diagnostic. */
+
+ virtual label_text describe_state_change (const evdesc::state_change &)
+ {
+ /* Default no-op implementation. */
+ return label_text ();
+ }
+
+ /* Precision-of-wording vfunc for describing an interprocedural call
+ carrying critial state for the diagnostic, from caller to callee.
+
+ For example a double-free diagnostic might use:
+ - "passing freed pointer 'ptr' in call to 'deallocator' from 'test'"
+ to make it clearer how the freed value moves from caller to
+ callee. */
+
+ virtual label_text describe_call_with_state (const evdesc::call_with_state &)
+ {
+ /* Default no-op implementation. */
+ return label_text ();
+ }
+
+ /* Precision-of-wording vfunc for describing an interprocedural return
+ within the diagnostic_path that carries critial state for the
+ diagnostic, from callee back to caller.
+
+ For example, a deref-of-unchecked-malloc diagnostic might use:
+ - "returning possibly-NULL pointer to 'make_obj' from 'allocator'"
+ to make it clearer how the unchecked value moves from callee
+ back to caller. */
+
+ virtual label_text describe_return_of_state (const evdesc::return_of_state &)
+ {
+ /* Default no-op implementation. */
+ return label_text ();
+ }
+
+ /* Precision-of-wording vfunc for describing the final event within a
+ diagnostic_path.
+
+ For example a double-free diagnostic might use:
+ - "second 'free' here; first 'free' was at (3)"
+ and a use-after-free might use
+ - "use after 'free' here; memory was freed at (2)". */
+
+ virtual label_text describe_final_event (const evdesc::final_event &)
+ {
+ /* Default no-op implementation. */
+ return label_text ();
+ }
+
+ /* End of precision-of-wording vfuncs. */
+};
+
+/* A template to make it easier to make subclasses of pending_diagnostic.
+
+ This uses the curiously-recurring template pattern, to implement
+ pending_diagnostic::subclass_equal_p by casting and calling
+ the operator==
+
+ This assumes that BASE_OTHER has already been checked to have
+ been of the same subclass (which pending_diagnostic::equal_p does). */
+
+template <class Subclass>
+class pending_diagnostic_subclass : public pending_diagnostic
+{
+ public:
+ bool subclass_equal_p (const pending_diagnostic &base_other) const
+ FINAL OVERRIDE
+ {
+ const Subclass &other = (const Subclass &)base_other;
+ return *(const Subclass*)this == other;
+ }
+};
+
+#endif /* GCC_ANALYZER_PENDING_DIAGNOSTIC_H */
--
1.8.5.3