sm-signal.cc was failing to warn about the use of an fprintf call in a
signal handler when the signal handler function was non-static.

The root cause was a failure to copy global sm-state within
sm_state_map::clone_with_remapping as called by
program_state::can_merge_with_p, which led to the exploded node for
the entrypoint to the handler in the "normal" state being erroneously
reused for the "in_signal_handler" state, thus losing the global state,
and thus failing to warn.

This patch fixes the above, so that non-equal global sm-state values
prevent merger of program_state, thus requiring separate exploded nodes
for the "normal" and "in signal handler" states, and thus triggering
the warning for the reproducer.

Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
Pushed to dmalcolm/analyzer on the GCC git mirror.

gcc/analyzer/ChangeLog:
        * program-state.cc (sm_state_map::clone_with_remapping): Copy
        m_global_state.
        (selftest::test_program_state_merging_2): New selftest.
        (selftest::analyzer_program_state_cc_tests): Call it.

gcc/testsuite/ChangeLog:
        * gcc.dg/analyzer/signal-6.c: New test.
---
 gcc/analyzer/program-state.cc            | 35 ++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/analyzer/signal-6.c | 20 ++++++++++++++
 2 files changed, 55 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/analyzer/signal-6.c

diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc
index 3ed78b40928b..a5afb1c1bc07 100644
--- a/gcc/analyzer/program-state.cc
+++ b/gcc/analyzer/program-state.cc
@@ -59,6 +59,7 @@ sm_state_map *
 sm_state_map::clone_with_remapping (const one_way_svalue_id_map &id_map) const
 {
   sm_state_map *result = new sm_state_map ();
+  result->m_global_state = m_global_state;
   for (typename map_t::iterator iter = m_map.begin ();
        iter != m_map.end ();
        ++iter)
@@ -1323,6 +1324,39 @@ test_program_state_merging ()
   ASSERT_EQ (s0, merged);
 }
 
+/* Verify that program_states with different global-state in an sm-state
+   can't be merged.  */
+
+static void
+test_program_state_merging_2 ()
+{
+  auto_delete_vec <state_machine> checkers;
+  checkers.safe_push (make_signal_state_machine (NULL));
+  extrinsic_state ext_state (checkers);
+
+  program_state s0 (ext_state);
+  {
+    sm_state_map *smap0 = s0.m_checker_states[0];
+    const state_machine::state_t TEST_STATE_0 = 0;
+    smap0->set_global_state (TEST_STATE_0);
+    ASSERT_EQ (smap0->get_global_state (), TEST_STATE_0);
+  }
+
+  program_state s1 (ext_state);
+  {
+    sm_state_map *smap1 = s1.m_checker_states[0];
+    const state_machine::state_t TEST_STATE_1 = 1;
+    smap1->set_global_state (TEST_STATE_1);
+    ASSERT_EQ (smap1->get_global_state (), TEST_STATE_1);
+  }
+
+  ASSERT_NE (s0, s1);
+
+  /* They ought to not be mergeable.  */
+  program_state merged (ext_state);
+  ASSERT_FALSE (s0.can_merge_with_p (s1, ext_state, &merged));
+}
+
 /* Run all of the selftests within this file.  */
 
 void
@@ -1330,6 +1364,7 @@ analyzer_program_state_cc_tests ()
 {
   test_sm_state_map ();
   test_program_state_merging ();
+  test_program_state_merging_2 ();
 }
 
 } // namespace selftest
diff --git a/gcc/testsuite/gcc.dg/analyzer/signal-6.c 
b/gcc/testsuite/gcc.dg/analyzer/signal-6.c
new file mode 100644
index 000000000000..f51845167f5c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/signal-6.c
@@ -0,0 +1,20 @@
+#include <stdio.h>
+#include <signal.h>
+
+extern void body_of_program(void);
+
+/* Example of a non-static signal handler.  */
+
+void handler(int signum)
+{
+  fprintf(stderr, "LOG: %i", signum); /* { dg-warning "call to 'fprintf' from 
within signal handler" } */
+}
+
+int main(int argc, const char *argv)
+{
+  signal(SIGINT, handler); /* { dg-message "registering 'handler' as signal 
handler" } */
+
+  body_of_program();
+
+  return 0;
+}
-- 
2.21.0

Reply via email to