On Wed, 2020-01-22 at 20:40 +0100, Jakub Jelinek wrote:
> On Wed, Jan 22, 2020 at 02:35:13PM -0500, David Malcolm wrote:
> > PR analyzer/93316 reports various testsuite failures where I
> > accidentally relied on properties of x86_64-pc-linux-gnu.
> > 
> > The following patch fixes them on sparc-sun-solaris2.11 (gcc211 in
> > the
> > GCC compile farm), and, I hope, the other configurations showing
> > failures.
> > 
> > There may still be other failures for pattern-test-2.c, which I'm
> > tracking separately as PR analyzer/93291.
> > 
> > Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu;
> > tested on stage 1 on sparc-sun-solaris2.11.
> > 
> > gcc/analyzer/ChangeLog:
> >     PR analyzer/93316
> >     * analyzer.cc (is_setjmp_call_p): Check for "setjmp" as well as
> >     "_setjmp".
> 
> Please see calls.c (special_function_p), you should treat certainly
> also sigsetjmp as a setjmp call, and similarly to special_function_p,
> skip over _ or __ prefixes before the setjmp or sigsetjmp name.
> Similarly for longjmp/siglongjmp.
> 
>       Jakub

Thanks.

This patch removes the hack in is_setjmp_call_p of looking for
"setjmp" and "_setjmp", replacing it with some logic adapted from
special_function_p in calls.c, ignoring up to 2 leading underscores from
the fndecl's name when checking for a function by name.

It also requires that such functions are "extern" and at file scope
for them to be matched.

The patch also generalizes the setjmp/longjmp handling in the analyzer
to also work with sigsetjmp/siglongjmp.  Doing so requires generalizing
some hardcoded functions in diagnostics (which were hardcoded to avoid
user-facing messages referring to "_setjmp", which is an implementation
detail) - the patch adds a new function, get_user_facing_name for this,
for use on calls that matched is_named_call_p and
is_specical_named_call_p.

Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.

OK for master?

gcc/analyzer/ChangeLog:
        * analyzer.cc  (is_named_call_p): Check that fndecl is "extern"
        and at file scope.  Potentially disregard prefix _ or __ in
        fndecl's name.  Bail if the identifier is NULL.
        (is_setjmp_call_p): Expect a gcall rather than plain gimple.
        Remove special-case check for leading prefix, and also check for
        sigsetjmp.
        (is_longjmp_call_p): Also check for siglongjmp.
        (get_user_facing_name): New function.
        * analyzer.h (is_setjmp_call_p): Expect a gcall rather than plain
        gimple.
        (get_user_facing_name): New decl.
        * checker-path.cc (setjmp_event::get_desc): Use
        get_user_facing_name to avoid hardcoding the function name.
        (rewind_event::rewind_event): Add rewind_info param, using it to
        initialize new m_rewind_info field, and strengthen the assertion.
        (rewind_from_longjmp_event::get_desc): Use get_user_facing_name to
        avoid hardcoding the function name.
        (rewind_to_setjmp_event::get_desc): Likewise.
        * checker-path.h (setjmp_event::setjmp_event): Add setjmp_call
        param and use it to initialize...
        (setjmp_event::m_setjmp_call): New field.
        (rewind_event::rewind_event): Add rewind_info param.
        (rewind_event::m_rewind_info): New protected field.
        (rewind_from_longjmp_event::rewind_from_longjmp_event): Add
        rewind_info param.
        (class rewind_to_setjmp_event): Move rewind_info field to parent
        class.
        * diagnostic-manager.cc (diagnostic_manager::add_events_for_eedge):
        Update setjmp-handling for is_setjmp_call_p requiring a gcall;
        pass the call to the new setjmp_event.
        * engine.cc (exploded_node::on_stmt): Update for is_setjmp_call_p
        requiring a gcall.
        (stale_jmp_buf::emit): Use get_user_facing_name to avoid
        hardcoding the function names.
        (exploded_node::on_longjmp): Pass the longjmp_call when
        constructing rewind_info.
        (rewind_info_t::add_events_to_path): Pass the rewind_info_t to the
        rewind_from_longjmp_event's ctor.
        * exploded-graph.h (rewind_info_t::rewind_info_t): Add
        longjmp_call param.
        (rewind_info_t::get_longjmp_call): New.
        (rewind_info_t::m_longjmp_call): New.
        * region-model.cc (region_model::on_setjmp): Update comment to
        indicate this is also for sigsetjmp.
        * region-model.h (struct setjmp_record): Likewise.
        (class setjmp_svalue): Likewise.

gcc/testsuite/ChangeLog:
        * gcc.dg/analyzer/sigsetjmp-5.c: New test.
        * gcc.dg/analyzer/sigsetjmp-6.c: New test.
---
 gcc/analyzer/analyzer.cc                    | 83 +++++++++++++++++----
 gcc/analyzer/analyzer.h                     |  4 +-
 gcc/analyzer/checker-path.cc                | 14 ++--
 gcc/analyzer/checker-path.h                 | 30 +++++---
 gcc/analyzer/diagnostic-manager.cc          |  6 +-
 gcc/analyzer/engine.cc                      | 21 +++---
 gcc/analyzer/exploded-graph.h               | 14 +++-
 gcc/analyzer/region-model.cc                |  8 +-
 gcc/analyzer/region-model.h                 |  9 ++-
 gcc/testsuite/gcc.dg/analyzer/sigsetjmp-5.c | 19 +++++
 gcc/testsuite/gcc.dg/analyzer/sigsetjmp-6.c | 35 +++++++++
 11 files changed, 188 insertions(+), 55 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/analyzer/sigsetjmp-5.c
 create mode 100644 gcc/testsuite/gcc.dg/analyzer/sigsetjmp-6.c

diff --git a/gcc/analyzer/analyzer.cc b/gcc/analyzer/analyzer.cc
index 3884788ee9e..1b5e4c9ecf8 100644
--- a/gcc/analyzer/analyzer.cc
+++ b/gcc/analyzer/analyzer.cc
@@ -54,7 +54,10 @@ is_special_named_call_p (const gcall *call, const char 
*funcname,
   return is_named_call_p (fndecl, funcname, call, num_args);
 }
 
-/* Helper function for checkers.  Does FNDECL have the given FUNCNAME?  */
+/* Helper function for checkers.  Is FNDECL an extern fndecl at file scope
+   that has the given FUNCNAME?
+
+   Compare with special_function_p in calls.c.  */
 
 bool
 is_named_call_p (tree fndecl, const char *funcname)
@@ -62,11 +65,38 @@ is_named_call_p (tree fndecl, const char *funcname)
   gcc_assert (fndecl);
   gcc_assert (funcname);
 
-  return 0 == strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), funcname);
+  /* Exclude functions not at the file scope, or not `extern',
+     since they are not the magic functions we would otherwise
+     think they are.  */
+  if (!((DECL_CONTEXT (fndecl) == NULL_TREE
+        || TREE_CODE (DECL_CONTEXT (fndecl)) == TRANSLATION_UNIT_DECL)
+       && TREE_PUBLIC (fndecl)))
+    return false;
+
+  tree identifier = DECL_NAME (fndecl);
+  if (identifier == NULL)
+    return false;
+
+  const char *name = IDENTIFIER_POINTER (identifier);
+  const char *tname = name;
+
+  /* Potentially disregard prefix _ or __ in FNDECL's name, but not if
+     FUNCNAME itself has leading underscores (e.g. when looking for
+     "__analyzer_eval").  */
+  if (funcname[0] != '_' && name[0] == '_')
+    {
+      if (name[1] == '_')
+       tname += 2;
+      else
+       tname += 1;
+    }
+
+  return 0 == strcmp (tname, funcname);
 }
 
-/* Helper function for checkers.  Does FNDECL have the given FUNCNAME, and
-   does CALL have the given number of arguments?  */
+/* Helper function for checkers.  Is FNDECL an extern fndecl at file scope
+   that has the given FUNCNAME, and does CALL have the given number of
+   arguments?  */
 
 bool
 is_named_call_p (tree fndecl, const char *funcname,
@@ -84,32 +114,57 @@ is_named_call_p (tree fndecl, const char *funcname,
   return true;
 }
 
-/* Return true if stmt is a setjmp call.  */
+/* Return true if stmt is a setjmp or sigsetjmp call.  */
 
 bool
-is_setjmp_call_p (const gimple *stmt)
+is_setjmp_call_p (const gcall *call)
 {
-  /* 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)
-       || is_special_named_call_p (call, "_setjmp", 1))
-      return true;
+  if (is_special_named_call_p (call, "setjmp", 1)
+      || is_special_named_call_p (call, "sigsetjmp", 2))
+    return true;
 
   return false;
 }
 
-/* Return true if stmt is a longjmp call.  */
+/* Return true if stmt is a longjmp or siglongjmp 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))
+  if (is_special_named_call_p (call, "longjmp", 2)
+      || is_special_named_call_p (call, "siglongjmp", 2))
     return true;
 
   return false;
 }
 
+/* For a CALL that matched is_special_named_call_p or is_named_call_p for
+   some name, return a name for the called function suitable for use in
+   diagnostics (stripping the leading underscores).  */
+
+const char *
+get_user_facing_name (const gcall *call)
+{
+  tree fndecl = gimple_call_fndecl (call);
+  gcc_assert (fndecl);
+
+  tree identifier = DECL_NAME (fndecl);
+  gcc_assert (identifier);
+
+  const char *name = IDENTIFIER_POINTER (identifier);
+
+  /* Strip prefix _ or __ in FNDECL's name.  */
+  if (name[0] == '_')
+    {
+      if (name[1] == '_')
+       return name + 2;
+      else
+       return name + 1;
+    }
+
+  return name;
+}
+
 /* Generate a label_text instance by formatting FMT, using a
    temporary clone of the global_dc's printer (thus using its
    formatting callbacks).
diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/analyzer.h
index e84e6958cec..90ed241c553 100644
--- a/gcc/analyzer/analyzer.h
+++ b/gcc/analyzer/analyzer.h
@@ -78,9 +78,11 @@ extern bool is_special_named_call_p (const gcall *call, 
const char *funcname,
 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_setjmp_call_p (const gcall *call);
 extern bool is_longjmp_call_p (const gcall *call);
 
+extern const char *get_user_facing_name (const gcall *call);
+
 extern void register_analyzer_pass ();
 
 extern label_text make_label_text (bool can_colorize, const char *fmt, ...);
diff --git a/gcc/analyzer/checker-path.cc b/gcc/analyzer/checker-path.cc
index f7455ba1245..7f6cdf599cf 100644
--- a/gcc/analyzer/checker-path.cc
+++ b/gcc/analyzer/checker-path.cc
@@ -709,7 +709,7 @@ setjmp_event::get_desc (bool can_colorize) const
 {
   return make_label_text (can_colorize,
                          "%qs called here",
-                         "setjmp");
+                         get_user_facing_name (m_setjmp_call));
 }
 
 /* Implementation of checker_event::prepare_for_emission vfunc for 
setjmp_event.
@@ -748,11 +748,13 @@ rewind_event::get_setjmp_caller () const
 
 rewind_event::rewind_event (const exploded_edge *eedge,
                            enum event_kind kind,
-                           location_t loc, tree fndecl, int depth)
+                           location_t loc, tree fndecl, int depth,
+                           const rewind_info_t *rewind_info)
 : checker_event (kind, loc, fndecl, depth),
+  m_rewind_info (rewind_info),
   m_eedge (eedge)
 {
-  gcc_assert (m_eedge->m_custom_info); // a rewind_info_t
+  gcc_assert (m_eedge->m_custom_info == m_rewind_info);
 }
 
 /* class rewind_from_longjmp_event : public rewind_event.  */
@@ -763,7 +765,8 @@ rewind_event::rewind_event (const exploded_edge *eedge,
 label_text
 rewind_from_longjmp_event::get_desc (bool can_colorize) const
 {
-  const char *src_name = "longjmp";
+  const char *src_name
+    = get_user_facing_name (m_rewind_info->get_longjmp_call ());
 
   if (get_longjmp_caller () == get_setjmp_caller ())
     /* Special-case: purely intraprocedural rewind.  */
@@ -786,7 +789,8 @@ rewind_from_longjmp_event::get_desc (bool can_colorize) 
const
 label_text
 rewind_to_setjmp_event::get_desc (bool can_colorize) const
 {
-  const char *dst_name = "setjmp";
+  const char *dst_name
+    = get_user_facing_name (m_rewind_info->get_setjmp_call ());
 
   /* If we can, identify the ID of the setjmp_event.  */
   if (m_original_setjmp_event_id.known_p ())
diff --git a/gcc/analyzer/checker-path.h b/gcc/analyzer/checker-path.h
index cceffe079fa..30cb43c13ba 100644
--- a/gcc/analyzer/checker-path.h
+++ b/gcc/analyzer/checker-path.h
@@ -329,15 +329,15 @@ public:
   bool is_return_p () const FINAL OVERRIDE;
 };
 
-/* A concrete event subclass for a setjmp call.  */
+/* A concrete event subclass for a setjmp or sigsetjmp call.  */
 
 class setjmp_event : public checker_event
 {
 public:
   setjmp_event (location_t loc, const exploded_node *enode,
-               tree fndecl, int depth)
+               tree fndecl, int depth, const gcall *setjmp_call)
   : checker_event (EK_SETJMP, loc, fndecl, depth),
-    m_enode (enode)
+    m_enode (enode), m_setjmp_call (setjmp_call)
   {
   }
 
@@ -349,9 +349,12 @@ public:
 
 private:
   const exploded_node *m_enode;
+  const gcall *m_setjmp_call;
 };
 
-/* An abstract event subclass for rewinding from a longjmp to a setjmp.
+/* An abstract event subclass for rewinding from a longjmp to a setjmp
+   (or siglongjmp to sigsetjmp).
+
    Base class for two from/to subclasses, showing the two halves of the
    rewind.  */
 
@@ -365,21 +368,25 @@ public:
  protected:
   rewind_event (const exploded_edge *eedge,
                enum event_kind kind,
-               location_t loc, tree fndecl, int depth);
+               location_t loc, tree fndecl, int depth,
+               const rewind_info_t *rewind_info);
+  const rewind_info_t *m_rewind_info;
 
  private:
   const exploded_edge *m_eedge;
 };
 
 /* A concrete event subclass for rewinding from a longjmp to a setjmp,
-   showing the longjmp.  */
+   showing the longjmp (or siglongjmp).  */
 
 class rewind_from_longjmp_event : public rewind_event
 {
 public:
   rewind_from_longjmp_event (const exploded_edge *eedge,
-                            location_t loc, tree fndecl, int depth)
-  : rewind_event (eedge, EK_REWIND_FROM_LONGJMP, loc, fndecl, depth)
+                            location_t loc, tree fndecl, int depth,
+                            const rewind_info_t *rewind_info)
+  : rewind_event (eedge, EK_REWIND_FROM_LONGJMP, loc, fndecl, depth,
+                 rewind_info)
   {
   }
 
@@ -387,7 +394,7 @@ public:
 };
 
 /* A concrete event subclass for rewinding from a longjmp to a setjmp,
-   showing the setjmp.  */
+   showing the setjmp (or sigsetjmp).  */
 
 class rewind_to_setjmp_event : public rewind_event
 {
@@ -395,8 +402,8 @@ public:
   rewind_to_setjmp_event (const exploded_edge *eedge,
                          location_t loc, tree fndecl, int depth,
                          const rewind_info_t *rewind_info)
-  : rewind_event (eedge, EK_REWIND_TO_SETJMP, loc, fndecl, depth),
-    m_rewind_info (rewind_info)
+  : rewind_event (eedge, EK_REWIND_TO_SETJMP, loc, fndecl, depth,
+                 rewind_info)
   {
   }
 
@@ -408,7 +415,6 @@ public:
 
 private:
   diagnostic_event_id_t m_original_setjmp_event_id;
-  const rewind_info_t *m_rewind_info;
 };
 
 /* Concrete subclass of checker_event for use at the end of a path:
diff --git a/gcc/analyzer/diagnostic-manager.cc 
b/gcc/analyzer/diagnostic-manager.cc
index 02bc4a61e60..eb1fa05533e 100644
--- a/gcc/analyzer/diagnostic-manager.cc
+++ b/gcc/analyzer/diagnostic-manager.cc
@@ -818,12 +818,14 @@ diagnostic_manager::add_events_for_eedge (const 
exploded_edge &eedge,
     case PK_BEFORE_STMT:
       {
        const gimple *stmt = dst_point.get_stmt ();
-       if (is_setjmp_call_p (stmt))
+       const gcall *call = dyn_cast <const gcall *> (stmt);
+       if (call && is_setjmp_call_p (call))
          emission_path->add_event
            (new setjmp_event (stmt->location,
                               dst_node,
                               dst_point.get_fndecl (),
-                              dst_stack_depth));
+                              dst_stack_depth,
+                              call));
        else
          emission_path->add_event
            (new statement_event (stmt,
diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc
index 737ea1dd6e4..1fdedf49224 100644
--- a/gcc/analyzer/engine.cc
+++ b/gcc/analyzer/engine.cc
@@ -1001,7 +1001,7 @@ exploded_node::on_stmt (exploded_graph &eg,
        {
          /* This is handled elsewhere.  */
        }
-      else if (is_setjmp_call_p (stmt))
+      else if (is_setjmp_call_p (call))
        state->m_region_model->on_setjmp (call, this, &ctxt);
       else if (is_longjmp_call_p (call))
        {
@@ -1126,7 +1126,8 @@ public:
     return warning_at
       (richloc, OPT_Wanalyzer_stale_setjmp_buffer,
        "%qs called after enclosing function of %qs has returned",
-       "longjmp", "setjmp");
+       get_user_facing_name (m_longjmp_call),
+       get_user_facing_name (m_setjmp_call));
   }
 
   const char *get_kind () const FINAL OVERRIDE
@@ -1143,10 +1144,10 @@ private:
   const gcall *m_longjmp_call;
 };
 
-/* Handle LONGJMP_CALL, a call to "longjmp".
+/* Handle LONGJMP_CALL, a call to longjmp or siglongjmp.
 
-   Attempt to locate where "setjmp" was called on the jmp_buf and build an
-   exploded_node and exploded_edge to it representing a rewind to that frame,
+   Attempt to locate where setjmp/sigsetjmp was called on the jmp_buf and build
+   an exploded_node and exploded_edge to it representing a rewind to that 
frame,
    handling the various kinds of failure that can occur.  */
 
 void
@@ -1174,9 +1175,9 @@ exploded_node::on_longjmp (exploded_graph &eg,
 
   const setjmp_record tmp_setjmp_record = setjmp_sval->get_setjmp_record ();
 
-  /* Build a custom enode and eedge for rewinding from the longjmp
-     call back to the setjmp.  */
-  rewind_info_t rewind_info (tmp_setjmp_record);
+  /* Build a custom enode and eedge for rewinding from the longjmp/siglongjmp
+     call back to the setjmp/sigsetjmp.  */
+  rewind_info_t rewind_info (tmp_setjmp_record, longjmp_call);
 
   const gcall *setjmp_call = rewind_info.get_setjmp_call ();
   const program_point &setjmp_point = rewind_info.get_setjmp_point ();
@@ -1217,7 +1218,7 @@ exploded_node::on_longjmp (exploded_graph &eg,
       exploded_edge *eedge
        = eg.add_edge (const_cast<exploded_node *> (this), next, NULL,
                       change,
-                      new rewind_info_t (tmp_setjmp_record));
+                      new rewind_info_t (tmp_setjmp_record, longjmp_call));
 
       /* For any diagnostics that were queued here (such as leaks) we want
         the checker_path to show the rewinding events after the "final event"
@@ -1369,7 +1370,7 @@ rewind_info_t::add_events_to_path (checker_path 
*emission_path,
     (new rewind_from_longjmp_event
      (&eedge, src_point.get_supernode ()->get_end_location (),
       src_point.get_fndecl (),
-      src_stack_depth));
+      src_stack_depth, this));
   emission_path->add_event
     (new rewind_to_setjmp_event
      (&eedge, get_setjmp_call ()->location,
diff --git a/gcc/analyzer/exploded-graph.h b/gcc/analyzer/exploded-graph.h
index 3d1445c87ad..a3e758ed751 100644
--- a/gcc/analyzer/exploded-graph.h
+++ b/gcc/analyzer/exploded-graph.h
@@ -302,13 +302,15 @@ private:
 };
 
 /* Extra data for an exploded_edge that represents a rewind from a
-   longjmp to a setjmp.  */
+   longjmp to a setjmp (or from a siglongjmp to a sigsetjmp).  */
 
 class rewind_info_t : public exploded_edge::custom_info_t
 {
 public:
-  rewind_info_t (const setjmp_record &setjmp_record)
-  : m_setjmp_record (setjmp_record)
+  rewind_info_t (const setjmp_record &setjmp_record,
+                const gcall *longjmp_call)
+  : m_setjmp_record (setjmp_record),
+    m_longjmp_call (longjmp_call)
   {}
 
   void print (pretty_printer *pp) FINAL OVERRIDE
@@ -339,6 +341,11 @@ public:
     return m_setjmp_record.m_setjmp_call;
   }
 
+  const gcall *get_longjmp_call () const
+  {
+    return m_longjmp_call;
+  }
+
   const exploded_node *get_enode_origin () const
   {
     return m_setjmp_record.m_enode;
@@ -346,6 +353,7 @@ public:
 
 private:
   setjmp_record m_setjmp_record;
+  const gcall *m_longjmp_call;
 };
 
 /* Statistics about aspects of an exploded_graph.  */
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 25a22f8fc65..985f1bd56ac 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -4480,11 +4480,11 @@ region_model::on_return (const greturn *return_stmt, 
region_model_context *ctxt)
     set_value (get_lvalue (lhs, ctxt), get_rvalue (rhs, ctxt), ctxt);
 }
 
-/* Update this model for a call and return of "setjmp" at CALL within ENODE,
-   using CTXT to report any diagnostics.
+/* Update this model for a call and return of setjmp/sigsetjmp at CALL within
+   ENODE, using CTXT to report any diagnostics.
 
-   This is for the initial direct invocation of setjmp (which returns 0),
-   as opposed to any second return due to longjmp.  */
+   This is for the initial direct invocation of setjmp/sigsetjmp (which returns
+   0), as opposed to any second return due to longjmp/sigsetjmp.  */
 
 void
 region_model::on_setjmp (const gcall *call, const exploded_node *enode,
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index f7fb7b0b6d0..70e3eb4c716 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -718,8 +718,8 @@ is_a_helper <poisoned_svalue *>::test (svalue *sval)
 
 namespace ana {
 
-/* A bundle of information recording a setjmp call, corresponding roughly
-   to a jmp_buf.  */
+/* A bundle of information recording a setjmp/sigsetjmp call, corresponding
+   roughly to a jmp_buf.  */
 
 struct setjmp_record
 {
@@ -739,8 +739,9 @@ struct setjmp_record
   const gcall *m_setjmp_call;
 };
 
-/* Concrete subclass of svalue representing setjmp buffers, so that
-   longjmp can potentially "return" to an entirely different function.  */
+/* Concrete subclass of svalue representing buffers for setjmp/sigsetjmp,
+   so that longjmp/siglongjmp can potentially "return" to an entirely
+   different function.  */
 
 class setjmp_svalue : public svalue
 {
diff --git a/gcc/testsuite/gcc.dg/analyzer/sigsetjmp-5.c 
b/gcc/testsuite/gcc.dg/analyzer/sigsetjmp-5.c
new file mode 100644
index 00000000000..68afe9d1c97
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/sigsetjmp-5.c
@@ -0,0 +1,19 @@
+#include <setjmp.h>
+#include <stddef.h>
+#include "analyzer-decls.h"
+
+static jmp_buf env;
+
+static void inner (void)
+{
+  sigsetjmp (env, 0); /* { dg-message "'sigsetjmp' called here" } */
+}
+
+void outer (void)
+{
+  int i;
+
+  inner ();
+
+  siglongjmp (env, 42); /* { dg-warning "'siglongjmp' called after enclosing 
function of 'sigsetjmp' has returned" } */
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/sigsetjmp-6.c 
b/gcc/testsuite/gcc.dg/analyzer/sigsetjmp-6.c
new file mode 100644
index 00000000000..fcd9d0bbb47
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/sigsetjmp-6.c
@@ -0,0 +1,35 @@
+#include <setjmp.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+extern int foo (int) __attribute__ ((__pure__));
+
+static jmp_buf env;
+
+static void inner (void)
+{
+  void *ptr = malloc (1024); /* { dg-message "allocated here" }  */
+
+  siglongjmp (env, 1); /* { dg-warning "leak of 'ptr'" "warning" } */
+  /* { dg-message "rewinding from 'siglongjmp' in 'inner'" " event: rewind 
from" { target *-*-* } .-1 } */
+
+  free (ptr);
+}
+
+void outer (void)
+{
+  int i;
+
+  foo (0);
+
+  i = sigsetjmp(env, 0); /* { dg-message "'sigsetjmp' called here" "event: 
sigsetjmp call" } */
+  /* { dg-message "to 'sigsetjmp' in 'outer'" "event: rewind to"  { target 
*-*-* } .-1 } */
+
+  if (i == 0)
+    {
+      foo (1);
+      inner ();
+    }
+
+  foo (3);
+}
-- 
2.21.0

Reply via email to