The SARIF 3.38.8 "kinds" property has some verbs for expressing
control flow, but is missing some of the awkward special cases.

The spec says "If none of these values are appropriate, a SARIF
producer MAY use any value."

This patch adds the following new values:

* "throw" for throwing an exception
* "catch" for catching an exception
* "unwind" for unwinding stack frame(s) during exception-handling
* "setjmp" for calls to setjmp
* "longjmp" for calls to longjmp that rewind the program counter/stack
to the location of a previous setjmp call

Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
Pushed to trunk as r16-5021-g0a2c4b6dd2019d.

gcc/analyzer/ChangeLog:
        PR analyzer/122544
        * checker-event.cc (catch_cfg_edge_event::get_meaning): New.
        (setjmp_event::get_meaning): New.
        (rewind_event::get_meaning): New.
        (throw_event::get_meaning): New.
        (unwind_event::get_meaning): New.
        * checker-event.h (catch_cfg_edge_event::get_meaning): New decl.
        (setjmp_event::get_meaning): New decl.
        (rewind_event::get_meaning): New decl.
        (throw_event::get_meaning): New decl.
        (unwind_event::get_meaning): New decl.

gcc/ChangeLog:
        PR analyzer/122544
        * diagnostics/paths.cc (event::meaning::maybe_get_verb_str):
        Handle the new verbs.
        * diagnostics/paths.h (event::meaning::verb): Add new values
        for special control flow operations.
        (event::meaning::meaning): Add ctor taking just a verb.

gcc/testsuite/ChangeLog:
        PR analyzer/122544
        * g++.dg/analyzer/exception-path-1-sarif.py: New test script.
        * g++.dg/analyzer/exception-path-1.C: Add SARIF output, and use
        the above to check it.
        * g++.dg/analyzer/exception-path-unwind-multiple-2-sarif.py: New
        test script.
        * g++.dg/analyzer/exception-path-unwind-multiple-2.C: Add SARIF
        output, and use the above to check it.
        * gcc.dg/analyzer/setjmp-3-sarif.py: New test script.
        * gcc.dg/analyzer/setjmp-3.c: Add SARIF output, and use
        the above to check it.
---
 gcc/analyzer/checker-event.cc                 | 32 +++++++++++++++++++
 gcc/analyzer/checker-event.h                  | 10 ++++++
 gcc/diagnostics/paths.cc                      | 16 ++++++++++
 gcc/diagnostics/paths.h                       | 13 +++++++-
 .../g++.dg/analyzer/exception-path-1-sarif.py | 22 +++++++++++++
 .../g++.dg/analyzer/exception-path-1.C        |  9 ++++++
 .../exception-path-unwind-multiple-2-sarif.py | 23 +++++++++++++
 .../exception-path-unwind-multiple-2.C        |  9 ++++++
 .../gcc.dg/analyzer/setjmp-3-sarif.py         | 23 +++++++++++++
 gcc/testsuite/gcc.dg/analyzer/setjmp-3.c      |  9 ++++++
 10 files changed, 165 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/analyzer/exception-path-1-sarif.py
 create mode 100644 
gcc/testsuite/g++.dg/analyzer/exception-path-unwind-multiple-2-sarif.py
 create mode 100644 gcc/testsuite/gcc.dg/analyzer/setjmp-3-sarif.py

diff --git a/gcc/analyzer/checker-event.cc b/gcc/analyzer/checker-event.cc
index 790ebc714380..3e54c2a408c0 100644
--- a/gcc/analyzer/checker-event.cc
+++ b/gcc/analyzer/checker-event.cc
@@ -833,6 +833,14 @@ start_cfg_edge_event::should_print_expr_p (tree expr)
   return false;
 }
 
+/* class catch_cfg_edge_event : public cfg_edge_event.  */
+
+diagnostics::paths::event::meaning
+catch_cfg_edge_event::get_meaning () const
+{
+  return meaning (verb::catch_);
+}
+
 /* class call_event : public superedge_event.  */
 
 /* call_event's ctor.  */
@@ -1034,6 +1042,12 @@ setjmp_event::print_desc (pretty_printer &pp) const
             get_user_facing_name (m_setjmp_call));
 }
 
+diagnostics::paths::event::meaning
+setjmp_event::get_meaning () const
+{
+  return meaning (verb::setjmp_);
+}
+
 /* Implementation of checker_event::prepare_for_emission vfunc for 
setjmp_event.
 
    Record this setjmp's event ID into the path, so that rewind events can
@@ -1066,6 +1080,12 @@ rewind_event::get_setjmp_caller () const
   return m_eedge->m_dest->get_function ()->decl;
 }
 
+diagnostics::paths::event::meaning
+rewind_event::get_meaning () const
+{
+  return meaning (verb::longjmp_);
+}
+
 /* rewind_event's ctor.  */
 
 rewind_event::rewind_event (const exploded_edge *eedge,
@@ -1163,6 +1183,12 @@ rewind_to_setjmp_event::prepare_for_emission 
(checker_path *path,
 
 /* class throw_event : public checker_event.  */
 
+diagnostics::paths::event::meaning
+throw_event::get_meaning () const
+{
+  return meaning (verb::throw_);
+}
+
 /* class explicit_throw_event : public throw_event.  */
 void
 explicit_throw_event::print_desc (pretty_printer &pp) const
@@ -1205,6 +1231,12 @@ unwind_event::print_desc (pretty_printer &pp) const
     pp_printf (&pp, "unwinding stack frame");
 }
 
+diagnostics::paths::event::meaning
+unwind_event::get_meaning () const
+{
+  return meaning (verb::unwind_);
+}
+
 /* class warning_event : public checker_event.  */
 
 /* Implementation of diagnostics::paths::event::print_desc vfunc for
diff --git a/gcc/analyzer/checker-event.h b/gcc/analyzer/checker-event.h
index 909e3889e28a..fc51be10c956 100644
--- a/gcc/analyzer/checker-event.h
+++ b/gcc/analyzer/checker-event.h
@@ -539,6 +539,8 @@ public:
       pp_string (&pp, "...catching exception here");
   }
 
+  meaning get_meaning () const override;
+
 private:
   tree m_type;
 };
@@ -666,6 +668,8 @@ public:
 
   void print_desc (pretty_printer &pp) const final override;
 
+  meaning get_meaning () const override;
+
   void prepare_for_emission (checker_path *path,
                             pending_diagnostic *pd,
                             diagnostics::paths::event_id_t emission_id) final 
override;
@@ -688,6 +692,8 @@ public:
   tree get_setjmp_caller () const;
   const exploded_edge *get_eedge () const { return m_eedge; }
 
+  meaning get_meaning () const override;
+
  protected:
   rewind_event (const exploded_edge *eedge,
                enum event_kind kind,
@@ -754,6 +760,8 @@ public:
   {
   }
 
+  meaning get_meaning () const override;
+
 protected:
   const exploded_node *m_enode;
   const gcall &m_throw_call;
@@ -817,6 +825,8 @@ public:
   {
   }
 
+  meaning get_meaning () const override;
+
   void print_desc (pretty_printer &pp) const final override;
 
   int m_num_frames;
diff --git a/gcc/diagnostics/paths.cc b/gcc/diagnostics/paths.cc
index 824b810cb3bf..8e29dae2cd71 100644
--- a/gcc/diagnostics/paths.cc
+++ b/gcc/diagnostics/paths.cc
@@ -97,6 +97,22 @@ event::meaning::maybe_get_verb_str (enum verb v)
       return "branch";
     case verb::danger:
       return "danger";
+
+    /* Special control flow operations.
+
+       These are not part of SARIF v2.1.0 section 3.38.8, but the
+       spec allows other values; see
+       https://github.com/oasis-tcs/sarif-spec/issues/735  */
+    case verb::throw_:
+      return "throw";
+    case verb::catch_:
+      return "catch";
+    case verb::unwind_:
+      return "unwind";
+    case verb::setjmp_:
+      return "setjmp";
+    case verb::longjmp_:
+      return "longjmp";
     }
 }
 
diff --git a/gcc/diagnostics/paths.h b/gcc/diagnostics/paths.h
index d30c4203ec5e..f7dff8d7c691 100644
--- a/gcc/diagnostics/paths.h
+++ b/gcc/diagnostics/paths.h
@@ -96,7 +96,14 @@ class event
     return_,
     branch,
 
-    danger
+    danger,
+
+    // Special control flow operations:
+    throw_,
+    catch_,
+    unwind_, // unwinding stack frame(s) during exception-handling
+    setjmp_,
+    longjmp_
   };
   enum class noun
   {
@@ -131,6 +138,10 @@ class event
       m_property (property::unknown)
     {
     }
+    meaning (enum verb verb)
+    : m_verb (verb), m_noun (noun::unknown), m_property (property::unknown)
+    {
+    }
     meaning (enum verb verb, enum noun noun)
     : m_verb (verb), m_noun (noun), m_property (property::unknown)
     {
diff --git a/gcc/testsuite/g++.dg/analyzer/exception-path-1-sarif.py 
b/gcc/testsuite/g++.dg/analyzer/exception-path-1-sarif.py
new file mode 100644
index 000000000000..8958d96b81a8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/exception-path-1-sarif.py
@@ -0,0 +1,22 @@
+from sarif import *
+
+import pytest
+
[email protected](scope='function', autouse=True)
+def sarif():
+    return sarif_from_env()
+
+def test_kinds(sarif):
+    result = get_result_by_index(sarif, 0)
+
+    assert result['level'] == 'note'
+
+    events = result["codeFlows"][0]["threadFlows"][0]['locations']
+
+    # Event "(1)": "throwing exception of type 'value_error' here..." (index 
== 0)
+    assert events[0]['location']['message']['text'] == "throwing exception of 
type 'value_error' here..."
+    assert events[0]['kinds'] == ["throw"]
+
+    # Event "(2)": "...catching exception of type 'value_error' here" (index 
== 1)
+    assert events[1]['location']['message']['text'] == "...catching exception 
of type 'value_error' here"
+    assert events[1]['kinds'] == ["catch"]
diff --git a/gcc/testsuite/g++.dg/analyzer/exception-path-1.C 
b/gcc/testsuite/g++.dg/analyzer/exception-path-1.C
index 486ca1938923..d923d62121bf 100644
--- a/gcc/testsuite/g++.dg/analyzer/exception-path-1.C
+++ b/gcc/testsuite/g++.dg/analyzer/exception-path-1.C
@@ -1,3 +1,5 @@
+/* { dg-additional-options "-fdiagnostics-add-output=sarif" } */
+
 /* Verify that we follow the correct paths when we know the typeinfo of
    an exception.  */
 
@@ -32,3 +34,10 @@ int test ()
   __analyzer_dump_path (); // { dg-bogus "path" }
   return 0;
 }
+
+/* Verify that some JSON was written to a file with the expected name.  */
+/* { dg-final { verify-sarif-file } } */
+
+/* Use a Python script to verify various properties about the generated
+   .sarif file:
+   { dg-final { run-sarif-pytest exception-path-1.C 
"exception-path-1-sarif.py" } } */
diff --git 
a/gcc/testsuite/g++.dg/analyzer/exception-path-unwind-multiple-2-sarif.py 
b/gcc/testsuite/g++.dg/analyzer/exception-path-unwind-multiple-2-sarif.py
new file mode 100644
index 000000000000..b817a6434b07
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/exception-path-unwind-multiple-2-sarif.py
@@ -0,0 +1,23 @@
+from sarif import *
+
+import pytest
+
[email protected](scope='function', autouse=True)
+def sarif():
+    return sarif_from_env()
+
+def test_kinds(sarif):
+    result = get_result_by_index(sarif, 0)
+
+    assert result['level'] == 'note'
+
+    events = result["codeFlows"][0]["threadFlows"][0]['locations']
+
+    assert events[-4]['location']['message']['text'] == "throwing exception of 
type 'value_error' here..."
+    assert events[-4]['kinds'] == ["throw"]
+
+    assert events[-3]['location']['message']['text'] == "unwinding 2 stack 
frames"
+    assert events[-3]['kinds'] == ["unwind"]
+
+    assert events[-2]['location']['message']['text'] == "...catching exception 
of type 'value_error' here"
+    assert events[-2]['kinds'] == ["catch"]
diff --git a/gcc/testsuite/g++.dg/analyzer/exception-path-unwind-multiple-2.C 
b/gcc/testsuite/g++.dg/analyzer/exception-path-unwind-multiple-2.C
index 2608f17079d3..aa1ff89ffb51 100644
--- a/gcc/testsuite/g++.dg/analyzer/exception-path-unwind-multiple-2.C
+++ b/gcc/testsuite/g++.dg/analyzer/exception-path-unwind-multiple-2.C
@@ -1,3 +1,5 @@
+/* { dg-additional-options "-fdiagnostics-add-output=sarif" } */
+
 /* Verify that we follow the correct paths when we know the typeinfo of
    an exception: interprocedural case where unwind multiple frame,
    failing to match the type.  */
@@ -53,3 +55,10 @@ int outer ()
   __analyzer_dump_path (); // { dg-bogus "path" }
   return 0;
 }
+
+/* Verify that some JSON was written to a file with the expected name.  */
+/* { dg-final { verify-sarif-file } } */
+
+/* Use a Python script to verify various properties about the generated
+   .sarif file:
+   { dg-final { run-sarif-pytest exception-path-unwind-multiple-2.C 
"exception-path-unwind-multiple-2-sarif.py" } } */
diff --git a/gcc/testsuite/gcc.dg/analyzer/setjmp-3-sarif.py 
b/gcc/testsuite/gcc.dg/analyzer/setjmp-3-sarif.py
new file mode 100644
index 000000000000..922d3380ecb8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/setjmp-3-sarif.py
@@ -0,0 +1,23 @@
+from sarif import *
+
+import pytest
+
[email protected](scope='function', autouse=True)
+def sarif():
+    return sarif_from_env()
+
+def test_kinds(sarif):
+    result = get_result_by_index(sarif, 0)
+
+    assert result['level'] == 'note'
+
+    events = result["codeFlows"][0]["threadFlows"][0]['locations']
+
+    assert events[1]['location']['message']['text'] == "'setjmp' called here"
+    assert events[1]['kinds'] == ["setjmp"]
+
+    assert events[6]['location']['message']['text'] == "rewinding from 
'longjmp' in 'inner'..."
+    assert events[6]['kinds'] == ["longjmp"]
+
+    assert events[7]['location']['message']['text'].startswith("...to 'setjmp' 
in 'outer'")
+    assert events[7]['kinds'] == ["longjmp"]
diff --git a/gcc/testsuite/gcc.dg/analyzer/setjmp-3.c 
b/gcc/testsuite/gcc.dg/analyzer/setjmp-3.c
index 3e4f870e5e8f..a19ce8412b8f 100644
--- a/gcc/testsuite/gcc.dg/analyzer/setjmp-3.c
+++ b/gcc/testsuite/gcc.dg/analyzer/setjmp-3.c
@@ -1,4 +1,6 @@
 /* { dg-additional-options "-fdiagnostics-show-line-numbers 
-fdiagnostics-path-format=inline-events -fdiagnostics-show-caret" } */
+/* { dg-additional-options "-fdiagnostics-add-output=sarif" } */
+
 /* { dg-enable-nn-line-numbers "" } */
 /* { dg-require-effective-target indirect_jumps } */
 
@@ -107,3 +109,10 @@ void outer (void)
     |      |       (11) here
     |
     { dg-end-multiline-output "" } */
+
+/* Verify that some JSON was written to a file with the expected name.  */
+/* { dg-final { verify-sarif-file } } */
+
+/* Use a Python script to verify various properties about the generated
+   .sarif file:
+   { dg-final { run-sarif-pytest setjmp-3.c "setjmp-3-sarif.py" } } */
-- 
2.26.3

Reply via email to