[28/49] analyzer: new files: analyzer.{cc|h}
diff mbox series

Message ID 1573867416-55618-29-git-send-email-dmalcolm@redhat.com
State New
Headers show
Series
  • RFC: Add a static analysis framework to GCC
Related show

Commit Message

David Malcolm Nov. 16, 2019, 1:23 a.m. UTC
gcc/ChangeLog:
	* analyzer/analyzer.cc: New file.
	* analyzer/analyzer.h: New file.
---
 gcc/analyzer/analyzer.cc | 125 ++++++++++++++++++++++++++++++++++++++++++++++
 gcc/analyzer/analyzer.h  | 126 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 251 insertions(+)
 create mode 100644 gcc/analyzer/analyzer.cc
 create mode 100644 gcc/analyzer/analyzer.h

Comments

Eric Gallager Dec. 7, 2019, 3:38 a.m. UTC | #1
On 11/15/19, David Malcolm <dmalcolm@redhat.com> wrote:
> gcc/ChangeLog:
> 	* analyzer/analyzer.cc: New file.
> 	* analyzer/analyzer.h: New file.
> ---
>  gcc/analyzer/analyzer.cc | 125
> ++++++++++++++++++++++++++++++++++++++++++++++
>  gcc/analyzer/analyzer.h  | 126
> +++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 251 insertions(+)
>  create mode 100644 gcc/analyzer/analyzer.cc
>  create mode 100644 gcc/analyzer/analyzer.h
>
> diff --git a/gcc/analyzer/analyzer.cc b/gcc/analyzer/analyzer.cc
> new file mode 100644
> index 0000000..399925c
> --- /dev/null
> +++ b/gcc/analyzer/analyzer.cc
> @@ -0,0 +1,125 @@
> +/* Utility functions for the analyzer.
> +   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 "gimple.h"
> +#include "diagnostic.h"
> +#include "intl.h"
> +#include "analyzer/analyzer.h"
> +
> +/* Helper function for checkers.  Is the CALL to the given function name?
> */
> +
> +bool
> +is_named_call_p (const gcall *call, const char *funcname)
> +{
> +  gcc_assert (funcname);
> +
> +  tree fndecl = gimple_call_fndecl (call);
> +  if (!fndecl)
> +    return false;
> +
> +  return 0 == strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), funcname);
> +}
> +
> +/* Helper function for checkers.  Is the CALL to the given function name,
> +   and with the given number of arguments?  */
> +
> +bool
> +is_named_call_p (const gcall *call, const char *funcname,
> +		 unsigned int num_args)
> +{
> +  gcc_assert (funcname);
> +
> +  if (!is_named_call_p (call, funcname))
> +    return false;
> +
> +  if (gimple_call_num_args (call) != num_args)
> +    return false;
> +
> +  return true;
> +}
> +
> +/* Return true if stmt is a setjmp call.  */
> +
> +bool
> +is_setjmp_call_p (const gimple *stmt)
> +{
> +  /* TODO: is there a less hacky way to check for "setjmp"?  */
> +  if (const gcall *call = dyn_cast <const gcall *> (stmt))
> +    if (is_named_call_p (call, "_setjmp", 1))
> +      return true;
> +
> +  return false;
> +}
> +
> +/* Return true if stmt is a longjmp call.  */
> +
> +bool
> +is_longjmp_call_p (const gcall *call)
> +{
> +  /* TODO: is there a less hacky way to check for "longjmp"?  */
> +  if (is_named_call_p (call, "longjmp", 2))
> +    return true;
> +
> +  return false;
> +}
> +
> +/* Generate a label_text instance by formatting FMT, using a
> +   temporary clone of the global_dc's printer (thus using its
> +   formatting callbacks).
> +
> +   Colorize if the global_dc supports colorization and CAN_COLORIZE is
> +   true.  */
> +
> +label_text
> +make_label_text (bool can_colorize, const char *fmt, ...)
> +{
> +  pretty_printer *pp = global_dc->printer->clone ();
> +  pp_clear_output_area (pp);
> +
> +  if (!can_colorize)
> +    pp_show_color (pp) = false;
> +
> +  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 = &ap;
> +  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/analyzer.h b/gcc/analyzer/analyzer.h
> new file mode 100644
> index 0000000..ace8924
> --- /dev/null
> +++ b/gcc/analyzer/analyzer.h
> @@ -0,0 +1,126 @@
> +/* Utility functions for the analyzer.
> +   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_ANALYZER_H
> +#define GCC_ANALYZER_ANALYZER_H
> +
> +/* Forward decls of common types, with indentation to show inheritance. */

I'm wondering about the "with indentation to show inheritance" part...
does that require tweaking any editor configuration files or adding
/*INDENT-OFF*/ comments or anything to prevent automatic formatting
tools from "fixing" the indentation to go back to the normal style of
having everything be aligned?

> +
> +class graphviz_out;
> +class supergraph;
> +class supernode;
> +class superedge;
> +  class cfg_superedge;
> +    class switch_cfg_superedge;
> +  class callgraph_superedge;
> +    class call_superedge;
> +    class return_superedge;
> +class svalue;
> +  class region_svalue;
> +  class constant_svalue;
> +  class poisoned_svalue;
> +  class unknown_svalue;
> +  class setjmp_svalue;
> +class region;
> +  class map_region;
> +  class symbolic_region;
> +class region_model;
> +class region_model_context;
> +  class impl_region_model_context;
> +class constraint_manager;
> +class equiv_class;
> +struct model_merger;
> +struct svalue_id_merger_mapping;
> +struct canonicalization;
> +class pending_diagnostic;
> +class checker_path;
> +class extrinsic_state;
> +class sm_state_map;
> +class stmt_finder;
> +class program_point;
> +class program_state;
> +class exploded_graph;
> +class exploded_node;
> +class exploded_edge;
> +class exploded_cluster;
> +class exploded_path;
> +class analysis_plan;
> +class state_purge_map;
> +class state_purge_per_ssa_name;
> +class state_change;
> +
> +////////////////////////////////////////////////////////////////////////////
> +
> +extern bool is_named_call_p (const gcall *call, const char *funcname);
> +extern bool is_named_call_p (const gcall *call, const char *funcname,
> +			     unsigned int num_args);
> +extern bool is_setjmp_call_p (const gimple *stmt);
> +extern bool is_longjmp_call_p (const gcall *call);
> +
> +extern void register_analyzer_pass ();
> +
> +extern label_text make_label_text (bool can_colorize, const char *fmt,
> ...);
> +
> +////////////////////////////////////////////////////////////////////////////
> +
> +/* An RAII-style class for pushing/popping cfun within a scope.
> +   Doing so ensures we get "In function " announcements
> +   from the diagnostics subsystem.  */
> +
> +class auto_cfun
> +{
> +public:
> +  auto_cfun (function *fun) { push_cfun (fun); }
> +  ~auto_cfun () { pop_cfun (); }
> +};
> +
> +////////////////////////////////////////////////////////////////////////////
> +
> +/* Begin suppressing -Wformat and -Wformat-extra-args.  */
> +
> +#define PUSH_IGNORE_WFORMAT \
> +  _Pragma("GCC diagnostic push") \
> +  _Pragma("GCC diagnostic ignored \"-Wformat\"") \
> +  _Pragma("GCC diagnostic ignored \"-Wformat-extra-args\"")
> +
> +/* Finish suppressing -Wformat and -Wformat-extra-args.  */
> +
> +#define POP_IGNORE_WFORMAT \
> +  _Pragma("GCC diagnostic pop")
> +
> +////////////////////////////////////////////////////////////////////////////
> +
> +/* A template for creating hash traits for a POD type.  */
> +
> +template <typename Type>
> +struct pod_hash_traits : typed_noop_remove<Type>
> +{
> +  typedef Type value_type;
> +  typedef Type compare_type;
> +  static inline hashval_t hash (value_type);
> +  static inline bool equal (const value_type &existing,
> +			    const value_type &candidate);
> +  static inline void mark_deleted (Type &);
> +  static inline void mark_empty (Type &);
> +  static inline bool is_deleted (Type);
> +  static inline bool is_empty (Type);
> +};
> +
> +#endif /* GCC_ANALYZER_ANALYZER_H */
> --
> 1.8.5.3
>
>
Jeff Law Dec. 7, 2019, 3:01 p.m. UTC | #2
On Fri, 2019-11-15 at 20:23 -0500, David Malcolm wrote:
> gcc/ChangeLog:
> 	* analyzer/analyzer.cc: New file.
> 	* analyzer/analyzer.h: New file.
> ---
>  gcc/analyzer/analyzer.cc | 125
> ++++++++++++++++++++++++++++++++++++++++++++++
>  gcc/analyzer/analyzer.h  | 126
> +++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 251 insertions(+)
>  create mode 100644 gcc/analyzer/analyzer.cc
>  create mode 100644 gcc/analyzer/analyzer.h
> 
> diff --git a/gcc/analyzer/analyzer.cc b/gcc/analyzer/analyzer.cc
> new file mode 100644
> index 0000000..399925c
> --- /dev/null
> +++ b/gcc/analyzer/analyzer.cc
> @@ -0,0 +1,125 @@
> +/* Utility functions for the analyzer.
> +   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 "gimple.h"
> +#include "diagnostic.h"
> +#include "intl.h"
> +#include "analyzer/analyzer.h"
> +
> +/* Helper function for checkers.  Is the CALL to the given function
> name?  */
> +
> +bool
> +is_named_call_p (const gcall *call, const char *funcname)
> +{
> +  gcc_assert (funcname);
> +
> +  tree fndecl = gimple_call_fndecl (call);
> +  if (!fndecl)
> +    return false;
> +
> +  return 0 == strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)),
> funcname);
> +}
> +
> +/* Helper function for checkers.  Is the CALL to the given function
> name,
> +   and with the given number of arguments?  */
> +
> +bool
> +is_named_call_p (const gcall *call, const char *funcname,
> +		 unsigned int num_args)
> +{
> +  gcc_assert (funcname);
> +
> +  if (!is_named_call_p (call, funcname))
> +    return false;
> +
> +  if (gimple_call_num_args (call) != num_args)
> +    return false;
> +
> +  return true;
These seem generic enough to live elsewhere.

> +}
> +
> +/* Return true if stmt is a setjmp call.  */
> +
> +bool
> +is_setjmp_call_p (const gimple *stmt)
> +{
> +  /* TODO: is there a less hacky way to check for "setjmp"?  */
> +  if (const gcall *call = dyn_cast <const gcall *> (stmt))
> +    if (is_named_call_p (call, "_setjmp", 1))
> +      return true;
> +
> +  return false;
> +}
> +
> +/* Return true if stmt is a longjmp call.  */
> +
> +bool
> +is_longjmp_call_p (const gcall *call)
> +{
> +  /* TODO: is there a less hacky way to check for "longjmp"?  */
> +  if (is_named_call_p (call, "longjmp", 2))
> +    return true;
> +
> +  return false;
> +}
I thought we already had routines to detect these.  We certainly have
*code* to detect them.   If it's the former we really just want one
implementation (that hands the various permutations we've seen through
the years).  If it's the latter, then we probably want to use these
routines to simplify those implementations.


> +
> +/* Generate a label_text instance by formatting FMT, using a
> +   temporary clone of the global_dc's printer (thus using its
> +   formatting callbacks).
> +
> +   Colorize if the global_dc supports colorization and CAN_COLORIZE
> is
> +   true.  */
> +
> +label_text
> +make_label_text (bool can_colorize, const char *fmt, ...)
> +{
> +  pretty_printer *pp = global_dc->printer->clone ();
> +  pp_clear_output_area (pp);
> +
> +  if (!can_colorize)
> +    pp_show_color (pp) = false;
> +
> +  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 = &ap;
> +  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;
> +}
Is this better in the pretty-printer infrastructure?  

Jeff

Patch
diff mbox series

diff --git a/gcc/analyzer/analyzer.cc b/gcc/analyzer/analyzer.cc
new file mode 100644
index 0000000..399925c
--- /dev/null
+++ b/gcc/analyzer/analyzer.cc
@@ -0,0 +1,125 @@ 
+/* Utility functions for the analyzer.
+   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 "gimple.h"
+#include "diagnostic.h"
+#include "intl.h"
+#include "analyzer/analyzer.h"
+
+/* Helper function for checkers.  Is the CALL to the given function name?  */
+
+bool
+is_named_call_p (const gcall *call, const char *funcname)
+{
+  gcc_assert (funcname);
+
+  tree fndecl = gimple_call_fndecl (call);
+  if (!fndecl)
+    return false;
+
+  return 0 == strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), funcname);
+}
+
+/* Helper function for checkers.  Is the CALL to the given function name,
+   and with the given number of arguments?  */
+
+bool
+is_named_call_p (const gcall *call, const char *funcname,
+		 unsigned int num_args)
+{
+  gcc_assert (funcname);
+
+  if (!is_named_call_p (call, funcname))
+    return false;
+
+  if (gimple_call_num_args (call) != num_args)
+    return false;
+
+  return true;
+}
+
+/* Return true if stmt is a setjmp call.  */
+
+bool
+is_setjmp_call_p (const gimple *stmt)
+{
+  /* TODO: is there a less hacky way to check for "setjmp"?  */
+  if (const gcall *call = dyn_cast <const gcall *> (stmt))
+    if (is_named_call_p (call, "_setjmp", 1))
+      return true;
+
+  return false;
+}
+
+/* Return true if stmt is a longjmp call.  */
+
+bool
+is_longjmp_call_p (const gcall *call)
+{
+  /* TODO: is there a less hacky way to check for "longjmp"?  */
+  if (is_named_call_p (call, "longjmp", 2))
+    return true;
+
+  return false;
+}
+
+/* Generate a label_text instance by formatting FMT, using a
+   temporary clone of the global_dc's printer (thus using its
+   formatting callbacks).
+
+   Colorize if the global_dc supports colorization and CAN_COLORIZE is
+   true.  */
+
+label_text
+make_label_text (bool can_colorize, const char *fmt, ...)
+{
+  pretty_printer *pp = global_dc->printer->clone ();
+  pp_clear_output_area (pp);
+
+  if (!can_colorize)
+    pp_show_color (pp) = false;
+
+  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 = &ap;
+  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/analyzer.h b/gcc/analyzer/analyzer.h
new file mode 100644
index 0000000..ace8924
--- /dev/null
+++ b/gcc/analyzer/analyzer.h
@@ -0,0 +1,126 @@ 
+/* Utility functions for the analyzer.
+   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_ANALYZER_H
+#define GCC_ANALYZER_ANALYZER_H
+
+/* Forward decls of common types, with indentation to show inheritance.  */
+
+class graphviz_out;
+class supergraph;
+class supernode;
+class superedge;
+  class cfg_superedge;
+    class switch_cfg_superedge;
+  class callgraph_superedge;
+    class call_superedge;
+    class return_superedge;
+class svalue;
+  class region_svalue;
+  class constant_svalue;
+  class poisoned_svalue;
+  class unknown_svalue;
+  class setjmp_svalue;
+class region;
+  class map_region;
+  class symbolic_region;
+class region_model;
+class region_model_context;
+  class impl_region_model_context;
+class constraint_manager;
+class equiv_class;
+struct model_merger;
+struct svalue_id_merger_mapping;
+struct canonicalization;
+class pending_diagnostic;
+class checker_path;
+class extrinsic_state;
+class sm_state_map;
+class stmt_finder;
+class program_point;
+class program_state;
+class exploded_graph;
+class exploded_node;
+class exploded_edge;
+class exploded_cluster;
+class exploded_path;
+class analysis_plan;
+class state_purge_map;
+class state_purge_per_ssa_name;
+class state_change;
+
+////////////////////////////////////////////////////////////////////////////
+
+extern bool is_named_call_p (const gcall *call, const char *funcname);
+extern bool is_named_call_p (const gcall *call, const char *funcname,
+			     unsigned int num_args);
+extern bool is_setjmp_call_p (const gimple *stmt);
+extern bool is_longjmp_call_p (const gcall *call);
+
+extern void register_analyzer_pass ();
+
+extern label_text make_label_text (bool can_colorize, const char *fmt, ...);
+
+////////////////////////////////////////////////////////////////////////////
+
+/* An RAII-style class for pushing/popping cfun within a scope.
+   Doing so ensures we get "In function " announcements
+   from the diagnostics subsystem.  */
+
+class auto_cfun
+{
+public:
+  auto_cfun (function *fun) { push_cfun (fun); }
+  ~auto_cfun () { pop_cfun (); }
+};
+
+////////////////////////////////////////////////////////////////////////////
+
+/* Begin suppressing -Wformat and -Wformat-extra-args.  */
+
+#define PUSH_IGNORE_WFORMAT \
+  _Pragma("GCC diagnostic push") \
+  _Pragma("GCC diagnostic ignored \"-Wformat\"") \
+  _Pragma("GCC diagnostic ignored \"-Wformat-extra-args\"")
+
+/* Finish suppressing -Wformat and -Wformat-extra-args.  */
+
+#define POP_IGNORE_WFORMAT \
+  _Pragma("GCC diagnostic pop")
+
+////////////////////////////////////////////////////////////////////////////
+
+/* A template for creating hash traits for a POD type.  */
+
+template <typename Type>
+struct pod_hash_traits : typed_noop_remove<Type>
+{
+  typedef Type value_type;
+  typedef Type compare_type;
+  static inline hashval_t hash (value_type);
+  static inline bool equal (const value_type &existing,
+			    const value_type &candidate);
+  static inline void mark_deleted (Type &);
+  static inline void mark_empty (Type &);
+  static inline bool is_deleted (Type);
+  static inline bool is_empty (Type);
+};
+
+#endif /* GCC_ANALYZER_ANALYZER_H */