public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r13-3770] analyzer: start adding support for errno
@ 2022-11-08  2:54 David Malcolm
  0 siblings, 0 replies; only message in thread
From: David Malcolm @ 2022-11-08  2:54 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:3d2d04cda493fb55ff47b042010943ce2e04cab2

commit r13-3770-g3d2d04cda493fb55ff47b042010943ce2e04cab2
Author: David Malcolm <dmalcolm@redhat.com>
Date:   Mon Nov 7 21:52:46 2022 -0500

    analyzer: start adding support for errno
    
    gcc/analyzer/ChangeLog:
            * region-model-impl-calls.cc
            (region_model::impl_call_errno_location): New.
            * region-model-manager.cc
            (region_model_manager::region_model_manager): Initialize
            m_thread_local_region and m_errno_region.
            * region-model-manager.h (region_model_manager::get_errno_region):
            New accessor.
            (region_model_manager::m_thread_local_region): New.
            (region_model_manager::m_errno_region): New.
            * region-model.cc (region_model::on_call_pre): Special-case
            "__errno_location".
            (region_model::set_errno): New.
            * region-model.h (impl_call_errno_location): New decl.
            (region_model::set_errno): New decl.
            * region.cc (thread_local_region::dump_to_pp): New.
            (errno_region::dump_to_pp): New.
            * region.h (enum memory_space): Add MEMSPACE_THREAD_LOCAL.
            (enum region_kind): Add RK_THREAD_LOCAL and RK_ERRNO.
            (class thread_local_region): New.
            (is_a_helper <const thread_local_region *>::test): New.
            (class errno_region): New.
            (is_a_helper <const errno_region *>::test): New.
            * store.cc (binding_cluster::escaped_p): New.
            (store::escaped_p): Treat errno as always having escaped.
            (store::replay_call_summary_cluster): Handle RK_THREAD_LOCAL and
            RK_ERRNO.
            * store.h (binding_cluster::escaped_p): Remove definition.
    
    gcc/testsuite/ChangeLog:
            * gcc.dg/analyzer/errno-1.c: New test.
    
    Signed-off-by: David Malcolm <dmalcolm@redhat.com>

Diff:
---
 gcc/analyzer/region-model-impl-calls.cc | 14 ++++++++
 gcc/analyzer/region-model-manager.cc    |  2 ++
 gcc/analyzer/region-model-manager.h     |  4 +++
 gcc/analyzer/region-model.cc            | 22 ++++++++++++
 gcc/analyzer/region-model.h             |  3 ++
 gcc/analyzer/region.cc                  | 22 ++++++++++++
 gcc/analyzer/region.h                   | 60 ++++++++++++++++++++++++++++++++-
 gcc/analyzer/store.cc                   | 17 ++++++++++
 gcc/analyzer/store.h                    |  2 +-
 gcc/testsuite/gcc.dg/analyzer/errno-1.c | 23 +++++++++++++
 10 files changed, 167 insertions(+), 2 deletions(-)

diff --git a/gcc/analyzer/region-model-impl-calls.cc b/gcc/analyzer/region-model-impl-calls.cc
index 46dbbb53bdc..bc644f8f3ad 100644
--- a/gcc/analyzer/region-model-impl-calls.cc
+++ b/gcc/analyzer/region-model-impl-calls.cc
@@ -413,6 +413,20 @@ region_model::impl_call_calloc (const call_details &cd)
     }
 }
 
+/* Handle the on_call_pre part of "__errno_location".  */
+
+void
+region_model::impl_call_errno_location (const call_details &cd)
+{
+  if (cd.get_lhs_region ())
+    {
+      const region *errno_reg = m_mgr->get_errno_region ();
+      const svalue *errno_ptr = m_mgr->get_ptr_svalue (cd.get_lhs_type (),
+						       errno_reg);
+      cd.maybe_set_lhs (errno_ptr);
+    }
+}
+
 /* Handle the on_call_pre part of "error" and "error_at_line" from
    GNU's non-standard <error.h>.
    MIN_ARGS identifies the minimum number of expected arguments
diff --git a/gcc/analyzer/region-model-manager.cc b/gcc/analyzer/region-model-manager.cc
index de01627bdb6..08bf5d2e758 100644
--- a/gcc/analyzer/region-model-manager.cc
+++ b/gcc/analyzer/region-model-manager.cc
@@ -74,6 +74,8 @@ region_model_manager::region_model_manager (logger *logger)
   m_fndecls_map (), m_labels_map (),
   m_globals_region (alloc_region_id (), &m_root_region),
   m_globals_map (),
+  m_thread_local_region (alloc_region_id (), &m_root_region),
+  m_errno_region (alloc_region_id (), &m_thread_local_region),
   m_store_mgr (this),
   m_range_mgr (new bounded_ranges_manager ()),
   m_known_fn_mgr (logger)
diff --git a/gcc/analyzer/region-model-manager.h b/gcc/analyzer/region-model-manager.h
index 3d8f76ee24c..0ff253b624c 100644
--- a/gcc/analyzer/region-model-manager.h
+++ b/gcc/analyzer/region-model-manager.h
@@ -107,6 +107,7 @@ public:
   {
     return &m_globals_region;
   }
+  const errno_region *get_errno_region () const { return &m_errno_region; }
   const function_region *get_region_for_fndecl (tree fndecl);
   const label_region *get_region_for_label (tree label);
   const decl_region *get_region_for_global (tree expr);
@@ -287,6 +288,9 @@ private:
   typedef globals_map_t::iterator globals_iterator_t;
   globals_map_t m_globals_map;
 
+  thread_local_region m_thread_local_region;
+  errno_region m_errno_region;
+
   consolidation_map<field_region> m_field_regions;
   consolidation_map<element_region> m_element_regions;
   consolidation_map<offset_region> m_offset_regions;
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index e182d2e0e1a..0ca454a0f9c 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -2288,6 +2288,11 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt,
 	  impl_call_realloc (cd);
 	  return false;
 	}
+      else if (is_named_call_p (callee_fndecl, "__errno_location", call, 0))
+	{
+	  impl_call_errno_location (cd);
+	  return false;
+	}
       else if (is_named_call_p (callee_fndecl, "error"))
 	{
 	  if (impl_call_error (cd, 3, out_terminate_path))
@@ -6418,6 +6423,23 @@ region_model::maybe_complain_about_infoleak (const region *dst_reg,
 							   copied_sval));
 }
 
+/* Set errno to a positive symbolic int, as if some error has occurred.  */
+
+void
+region_model::set_errno (const call_details &cd)
+{
+  const region *errno_reg = m_mgr->get_errno_region ();
+  conjured_purge p (this, cd.get_ctxt ());
+  const svalue *new_errno_sval
+    = m_mgr->get_or_create_conjured_svalue (integer_type_node,
+					    cd.get_call_stmt (),
+					    errno_reg, p);
+  const svalue *zero
+    = m_mgr->get_or_create_int_cst (integer_type_node, 0);
+  add_constraint (new_errno_sval, GT_EXPR, zero, cd.get_ctxt ());
+  set_value (errno_reg, new_errno_sval, cd.get_ctxt ());
+}
+
 /* class noop_region_model_context : public region_model_context.  */
 
 void
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index 5c0bc44a57a..0caaf82936b 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -349,6 +349,7 @@ class region_model
   void impl_call_analyzer_get_unknown_ptr (const call_details &cd);
   void impl_call_builtin_expect (const call_details &cd);
   void impl_call_calloc (const call_details &cd);
+  void impl_call_errno_location (const call_details &cd);
   bool impl_call_error (const call_details &cd, unsigned min_args,
 			bool *out_terminate_path);
   void impl_call_fgets (const call_details &cd);
@@ -544,6 +545,8 @@ class region_model
 				      const region *src_reg,
 				      region_model_context *ctxt);
 
+  void set_errno (const call_details &cd);
+
   /* Implemented in sm-fd.cc  */
   void mark_as_valid_fd (const svalue *sval, region_model_context *ctxt);
 
diff --git a/gcc/analyzer/region.cc b/gcc/analyzer/region.cc
index 4bc191848a4..6d97590a83a 100644
--- a/gcc/analyzer/region.cc
+++ b/gcc/analyzer/region.cc
@@ -1050,6 +1050,17 @@ root_region::dump_to_pp (pretty_printer *pp, bool simple) const
     pp_string (pp, "root_region()");
 }
 
+/* class thread_local_region : public space_region.  */
+
+void
+thread_local_region::dump_to_pp (pretty_printer *pp, bool simple) const
+{
+  if (simple)
+    pp_string (pp, "thread_local_region");
+  else
+    pp_string (pp, "thread_local_region()");
+}
+
 /* class symbolic_region : public map_region.  */
 
 /* symbolic_region's ctor.  */
@@ -1811,6 +1822,17 @@ var_arg_region::get_frame_region () const
   return as_a <const frame_region *> (get_parent_region ());
 }
 
+/* class errno_region : public region.  */
+
+void
+errno_region::dump_to_pp (pretty_printer *pp, bool simple) const
+{
+  if (simple)
+    pp_string (pp, "errno_region");
+  else
+    pp_string (pp, "errno_region()");
+}
+
 /* class unknown_region : public region.  */
 
 /* Implementation of region::dump_to_pp vfunc for unknown_region.  */
diff --git a/gcc/analyzer/region.h b/gcc/analyzer/region.h
index 6315fac62e5..ecae887edaf 100644
--- a/gcc/analyzer/region.h
+++ b/gcc/analyzer/region.h
@@ -34,7 +34,8 @@ enum memory_space
   MEMSPACE_GLOBALS,
   MEMSPACE_STACK,
   MEMSPACE_HEAP,
-  MEMSPACE_READONLY_DATA
+  MEMSPACE_READONLY_DATA,
+  MEMSPACE_THREAD_LOCAL
 };
 
 /* An enum for discriminating between the different concrete subclasses
@@ -49,6 +50,7 @@ enum region_kind
   RK_LABEL,
   RK_STACK,
   RK_HEAP,
+  RK_THREAD_LOCAL,
   RK_ROOT,
   RK_SYMBOLIC,
   RK_DECL,
@@ -62,6 +64,7 @@ enum region_kind
   RK_STRING,
   RK_BIT_RANGE,
   RK_VAR_ARG,
+  RK_ERRNO,
   RK_UNKNOWN,
 };
 
@@ -77,6 +80,8 @@ enum region_kind
        code_region (RK_CODE): represents the code segment, containing functions
        stack_region (RK_STACK): a stack, containing all stack frames
        heap_region (RK_HEAP): the heap, containing heap_allocated_regions
+       thread_local_region (RK_THREAD_LOCAL): thread-local data for the thread
+                                              being analyzed
      root_region (RK_ROOT): the top-level region
      function_region (RK_FUNCTION): the code for a particular function
      label_region (RK_LABEL): a particular label within a function
@@ -102,6 +107,7 @@ enum region_kind
 				      within another region
      var_arg_region (RK_VAR_ARG): a region for the N-th vararg within a
 				  frame_region for a variadic call
+     errno_region (RK_ERRNO): a region for holding "errno"
      unknown_region (RK_UNKNOWN): for handling unimplemented tree codes.  */
 
 /* Abstract base class for representing ways of accessing chunks of memory.
@@ -555,6 +561,32 @@ is_a_helper <const heap_region *>::test (const region *reg)
 
 namespace ana {
 
+/* Concrete space_region subclass: thread-local data for the thread
+   being analyzed.  */
+
+class thread_local_region : public space_region
+{
+public:
+  thread_local_region (unsigned id, region *parent)
+  : space_region (id, parent)
+  {}
+
+  enum region_kind get_kind () const final override { return RK_THREAD_LOCAL; }
+  void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+};
+
+} // namespace ana
+
+template <>
+template <>
+inline bool
+is_a_helper <const thread_local_region *>::test (const region *reg)
+{
+  return reg->get_kind () == RK_THREAD_LOCAL;
+}
+
+namespace ana {
+
 /* Concrete region subclass.  The root region, containing all regions
    (either directly, or as descendents).
    Unique within a region_model_manager.  */
@@ -1362,6 +1394,32 @@ template <> struct default_hash_traits<var_arg_region::key_t>
 
 namespace ana {
 
+/* A region for errno for the current thread.  */
+
+class errno_region : public region
+{
+public:
+  errno_region (unsigned id, const thread_local_region *parent)
+  : region (complexity (parent), id, parent, integer_type_node)
+  {}
+
+  enum region_kind get_kind () const final override { return RK_ERRNO; }
+
+  void dump_to_pp (pretty_printer *pp, bool simple) const final override;
+};
+
+} // namespace ana
+
+template <>
+template <>
+inline bool
+is_a_helper <const errno_region *>::test (const region *reg)
+{
+  return reg->get_kind () == RK_ERRNO;
+}
+
+namespace ana {
+
 /* An unknown region, for handling unimplemented tree codes.  */
 
 class unknown_region : public region
diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc
index c0f5ed104e1..636d4aa52da 100644
--- a/gcc/analyzer/store.cc
+++ b/gcc/analyzer/store.cc
@@ -2036,6 +2036,17 @@ binding_cluster::on_asm (const gasm *stmt,
   m_touched = true;
 }
 
+/* Return true if this cluster has escaped.  */
+
+bool
+binding_cluster::escaped_p () const
+{
+  /* Consider the "errno" region to always have escaped.  */
+  if (m_base_region->get_kind () == RK_ERRNO)
+    return true;
+  return m_escaped;
+}
+
 /* Return true if this binding_cluster has no information
    i.e. if there are no bindings, and it hasn't been marked as having
    escaped, or touched symbolically.  */
@@ -2946,6 +2957,10 @@ store::escaped_p (const region *base_reg) const
   gcc_assert (base_reg);
   gcc_assert (base_reg->get_base_region () == base_reg);
 
+  /* "errno" can always be modified by external code.  */
+  if (base_reg->get_kind () == RK_ERRNO)
+    return true;
+
   if (binding_cluster **cluster_slot
       = const_cast <cluster_map_t &>(m_cluster_map).get (base_reg))
     return (*cluster_slot)->escaped_p ();
@@ -3192,6 +3207,7 @@ store::replay_call_summary_cluster (call_summary_replay &r,
     case RK_CODE:
     case RK_STACK:
     case RK_HEAP:
+    case RK_THREAD_LOCAL:
     case RK_ROOT:
     /* Child regions.  */
     case RK_FIELD:
@@ -3242,6 +3258,7 @@ store::replay_call_summary_cluster (call_summary_replay &r,
 
     case RK_HEAP_ALLOCATED:
     case RK_DECL:
+    case RK_ERRNO:
       {
 	const region *caller_dest_reg
 	  = r.convert_region_from_summary (summary_base_reg);
diff --git a/gcc/analyzer/store.h b/gcc/analyzer/store.h
index 1087782a326..6243ec65ea1 100644
--- a/gcc/analyzer/store.h
+++ b/gcc/analyzer/store.h
@@ -644,7 +644,7 @@ public:
   void on_asm (const gasm *stmt, store_manager *mgr,
 	       const conjured_purge &p);
 
-  bool escaped_p () const { return m_escaped; }
+  bool escaped_p () const;
   bool touched_p () const { return m_touched; }
 
   bool redundant_p () const;
diff --git a/gcc/testsuite/gcc.dg/analyzer/errno-1.c b/gcc/testsuite/gcc.dg/analyzer/errno-1.c
new file mode 100644
index 00000000000..6b9d28c1079
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/errno-1.c
@@ -0,0 +1,23 @@
+#include <errno.h>
+#include "analyzer-decls.h"
+
+extern void external_fn (void);
+
+int test_reading_errno (void)
+{
+  return errno;
+}
+
+void test_setting_errno (int val)
+{
+  errno = val;
+}
+
+void test_storing_to_errno (int val)
+{
+  __analyzer_eval (errno == val); /* { dg-warning "UNKNOWN" } */
+  errno = val;
+  __analyzer_eval (errno == val); /* { dg-warning "TRUE" } */
+  external_fn ();
+  __analyzer_eval (errno == val); /* { dg-warning "UNKNOWN" } */  
+}

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-11-08  2:54 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-08  2:54 [gcc r13-3770] analyzer: start adding support for errno David Malcolm

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).