diff mbox series

[19/41] analyzer: new files: analyzer.{cc|h}

Message ID 20200108090302.2425-20-dmalcolm@redhat.com
State New
Headers show
Series v5 of analyzer patch kit | expand

Commit Message

David Malcolm Jan. 8, 2020, 9:02 a.m. UTC
Jeff reviewed an earlier version of this here:
  https://gcc.gnu.org/ml/gcc-patches/2019-12/msg00503.html
My response:
  https://gcc.gnu.org/ml/gcc-patches/2019-12/msg00809.html
I have followup patches that implement the function_set idea.

TODO:
  I haven't yet addressed the is_setjmp_call_p/is_longjmp_call_p concerns

Changed in v5:
- update ChangeLog path
- updated copyright years to include 2020

Changed in v4:
- Remove include of gcc-plugin.h, reworking includes accordingly.
- Wrap everything in #if ENABLE_ANALYZER
- Remove /// comment lines
- Update is_named_call_p to support function pointers:
    https://gcc.gnu.org/ml/gcc-patches/2019-12/msg00178.html

gcc/analyzer/ChangeLog:
	* analyzer.cc: New file.
	* analyzer.h: New file.
---
 gcc/analyzer/analyzer.cc | 150 +++++++++++++++++++++++++++++++++++++++
 gcc/analyzer/analyzer.h  | 124 ++++++++++++++++++++++++++++++++
 2 files changed, 274 insertions(+)
 create mode 100644 gcc/analyzer/analyzer.cc
 create mode 100644 gcc/analyzer/analyzer.h

Comments

Jeff Law Jan. 10, 2020, 3:53 p.m. UTC | #1
On Wed, 2020-01-08 at 04:02 -0500, David Malcolm wrote:
> Jeff reviewed an earlier version of this here:
>   https://gcc.gnu.org/ml/gcc-patches/2019-12/msg00503.html
> My response:
>   https://gcc.gnu.org/ml/gcc-patches/2019-12/msg00809.html
> I have followup patches that implement the function_set idea.
> 
> TODO:
>   I haven't yet addressed the is_setjmp_call_p/is_longjmp_call_p concerns
> 
> Changed in v5:
> - update ChangeLog path
> - updated copyright years to include 2020
> 
> Changed in v4:
> - Remove include of gcc-plugin.h, reworking includes accordingly.
> - Wrap everything in #if ENABLE_ANALYZER
> - Remove /// comment lines
> - Update is_named_call_p to support function pointers:
>     https://gcc.gnu.org/ml/gcc-patches/2019-12/msg00178.html
> 
> gcc/analyzer/ChangeLog:
> 	* analyzer.cc: New file.
> 	* analyzer.h: New file.
So there's a lot more ways to write setjmp.  Some don't even look like
setjmp.  sigsetjmp, savectx, vfork, getcontext all have setjmp like
qualities (returning twice).  They may have an underscore prefix IIRC.

So if what you're really looking for is functions that may return
twice, I think that's the canonical list :-)

jeff
David Malcolm Jan. 10, 2020, 5:02 p.m. UTC | #2
On Fri, 2020-01-10 at 08:53 -0700, Jeff Law wrote:
> On Wed, 2020-01-08 at 04:02 -0500, David Malcolm wrote:
> > Jeff reviewed an earlier version of this here:
> >   https://gcc.gnu.org/ml/gcc-patches/2019-12/msg00503.html
> > My response:
> >   https://gcc.gnu.org/ml/gcc-patches/2019-12/msg00809.html
> > I have followup patches that implement the function_set idea.
> > 
> > TODO:
> >   I haven't yet addressed the is_setjmp_call_p/is_longjmp_call_p
> > concerns
> > 
> > Changed in v5:
> > - update ChangeLog path
> > - updated copyright years to include 2020
> > 
> > Changed in v4:
> > - Remove include of gcc-plugin.h, reworking includes accordingly.
> > - Wrap everything in #if ENABLE_ANALYZER
> > - Remove /// comment lines
> > - Update is_named_call_p to support function pointers:
> >     https://gcc.gnu.org/ml/gcc-patches/2019-12/msg00178.html
> > 
> > gcc/analyzer/ChangeLog:
> > 	* analyzer.cc: New file.
> > 	* analyzer.h: New file.
> So there's a lot more ways to write setjmp.  Some don't even look
> like
> setjmp.  sigsetjmp, savectx, vfork, getcontext all have setjmp like
> qualities (returning twice).  They may have an underscore prefix
> IIRC.
> 
> So if what you're really looking for is functions that may return
> twice, I think that's the canonical list :-)

Thanks - but I don't think "returns twice" is exactly what's needed
here.

I think the needs of code generation/optimization are slightly
different from that of the analyzer here.

I'm special-casing setjmp/longjmp, which have very particular behavior.
Beyond the "returns twice" property the analyzer has special-case
knowledge of things like:
  "the return value from the 2nd return from setjmp is that passed to
longjmp, unless 0 was passed, in which case return 1"

That holds for sigsetjmp/siglongjmp, but not for the other functions,
which have their own behaviors (e.g. getcontext/setcontext can fail and
set errno).

So from the analyzer's point-of-view, those various other functions are
*not* setjmp/longjmp; they are different returns-twice functions.

I picked setjmp/longjmp as being high-priority to model correctly. 
Some of the others in the list you give are rather obscure e.g. savectx
appears to be Solaris-specific and I have no great desire to track down
Solaris documentation and figure out what its behaviors are meant to
be.

So I think this code could be generalized to sigsetjmp/siglongjmp
fairly easily using the setjmp/longjmp logic.  For the other returns-
twice functions, the analyzer's not handling the 2nd return will mean
it will silently fail to explore execution paths involving the 2nd
return, which seems acceptable to me (otherwise there could be state
assumptions we fail to inject, leading to false warnings on paths that
are actually-infeasible).

Dave
diff mbox series

Patch

diff --git a/gcc/analyzer/analyzer.cc b/gcc/analyzer/analyzer.cc
new file mode 100644
index 000000000000..abe0f7dd0819
--- /dev/null
+++ b/gcc/analyzer/analyzer.cc
@@ -0,0 +1,150 @@ 
+/* Utility functions for the analyzer.
+   Copyright (C) 2019-2020 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 "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "function.h"
+#include "basic-block.h"
+#include "gimple.h"
+#include "diagnostic.h"
+#include "intl.h"
+#include "analyzer/analyzer.h"
+
+#if ENABLE_ANALYZER
+
+/* Helper function for checkers.  Is the CALL to the given function name,
+   and with the given number of arguments?
+
+   This doesn't resolve function pointers via the region model;
+   is_named_call_p should be used instead, using a fndecl from
+   get_fndecl_for_call; this function should only be used for special cases
+   where it's not practical to get at the region model, or for special
+   analyzer functions such as __analyzer_dump.  */
+
+bool
+is_special_named_call_p (const gcall *call, const char *funcname,
+			 unsigned int num_args)
+{
+  gcc_assert (funcname);
+
+  tree fndecl = gimple_call_fndecl (call);
+  if (!fndecl)
+    return false;
+
+  return is_named_call_p (fndecl, funcname, call, num_args);
+}
+
+/* Helper function for checkers.  Does FNDECL have the given FUNCNAME?  */
+
+bool
+is_named_call_p (tree fndecl, const char *funcname)
+{
+  gcc_assert (fndecl);
+  gcc_assert (funcname);
+
+  return 0 == strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), funcname);
+}
+
+/* Helper function for checkers.  Does FNDECL have the given FUNCNAME, and
+   does CALL have the given number of arguments?  */
+
+bool
+is_named_call_p (tree fndecl, const char *funcname,
+		 const gcall *call, unsigned int num_args)
+{
+  gcc_assert (fndecl);
+  gcc_assert (funcname);
+
+  if (!is_named_call_p (fndecl, 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_special_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_special_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;
+}
+
+#endif /* #if ENABLE_ANALYZER */
diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/analyzer.h
new file mode 100644
index 000000000000..16c6ab476d2c
--- /dev/null
+++ b/gcc/analyzer/analyzer.h
@@ -0,0 +1,124 @@ 
+/* Utility functions for the analyzer.
+   Copyright (C) 2019-2020 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
+
+#include "function.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 state_change_event;
+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;
+class rewind_info_t;
+
+extern bool is_special_named_call_p (const gcall *call, const char *funcname,
+				     unsigned int num_args);
+extern bool is_named_call_p (tree fndecl, const char *funcname);
+extern bool is_named_call_p (tree fndecl, const char *funcname,
+			     const gcall *call, 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 */