analyzer: fix signal-handler registration location [PR95188]
authorDavid Malcolm <dmalcolm@redhat.com>
Tue, 29 Sep 2020 19:55:33 +0000 (15:55 -0400)
committerDavid Malcolm <dmalcolm@redhat.com>
Tue, 29 Sep 2020 22:31:48 +0000 (18:31 -0400)
PR analyzer/95188 reports that diagnostics from
-Wanalyzer-unsafe-call-within-signal-handler use the wrong
source location when reporting the signal-handler registration
event in the diagnostic_path.  The diagnostics erroneously use the
location of the first stmt in the basic block containing the call
to "signal", rather than that of the call itself.

Fixed thusly.

gcc/analyzer/ChangeLog:
PR analyzer/95188
* engine.cc (stmt_requires_new_enode_p): Split enodes before
"signal" calls.

gcc/testsuite/ChangeLog:
PR analyzer/95188
* gcc.dg/analyzer/signal-registration-loc.c: New test.

gcc/analyzer/engine.cc
gcc/testsuite/gcc.dg/analyzer/signal-registration-loc.c [new file with mode: 0644]

index c15d119..0e79254 100644 (file)
@@ -2677,13 +2677,23 @@ static bool
 stmt_requires_new_enode_p (const gimple *stmt,
                           const gimple *prev_stmt)
 {
-  /* Stop consolidating at calls to
-     "__analyzer_dump_exploded_nodes", so they always appear at the
-     start of an exploded_node.  */
   if (const gcall *call = dyn_cast <const gcall *> (stmt))
-    if (is_special_named_call_p (call, "__analyzer_dump_exploded_nodes",
-                        1))
-      return true;
+    {
+      /* Stop consolidating at calls to
+        "__analyzer_dump_exploded_nodes", so they always appear at the
+        start of an exploded_node.  */
+      if (is_special_named_call_p (call, "__analyzer_dump_exploded_nodes",
+                                  1))
+       return true;
+
+      /* sm-signal.cc injects an additional custom eedge at "signal" calls
+        from the registration enode to the handler enode, separate from the
+        regular next state, which defeats the "detect state change" logic
+        in process_node.  Work around this via special-casing, to ensure
+        we split the enode immediately before any "signal" call.  */
+      if (is_special_named_call_p (call, "signal", 2))
+       return true;
+    }
 
   /* If we had a PREV_STMT with an unknown location, and this stmt
      has a known location, then if a state change happens here, it
diff --git a/gcc/testsuite/gcc.dg/analyzer/signal-registration-loc.c b/gcc/testsuite/gcc.dg/analyzer/signal-registration-loc.c
new file mode 100644 (file)
index 0000000..4bac126
--- /dev/null
@@ -0,0 +1,23 @@
+/* Ensure we use the correct location when reporting where the
+   signal handler was registered (PR analyzer/95188).  */
+
+/* { dg-require-effective-target signal } */
+
+#include <stdio.h>
+#include <signal.h>
+
+int g;
+extern int foo (void);
+
+static void
+handler (int n)
+{
+  fprintf (stderr, "got here: %i\n", g); /* { dg-warning "call to 'fprintf' from within signal handler" } */
+}
+
+int main (int argc, char *argv[])
+{
+  g = foo (); /* { dg-bogus "registering" } */
+  signal (SIGSEGV, handler); /* { dg-message "registering 'handler' as signal handler" } */
+  return 0;
+}