This patch uses the class function_set from the previous patch to
generalize the test for an fprintf inside a signal handler to
check for a set of known async-signal-unsafe functions.
gcc/analyzer/ChangeLog:
* analyzer-selftests.cc (selftest::run_analyzer_selftests): Call
selftest::analyzer_sm_signal_cc_tests.
* analyzer-selftests.h (selftest::analyzer_sm_signal_cc_tests):
New decl.
* sm-signal.cc: Include "analyzer/function-set.h" and
"analyzer/analyzer-selftests.h".
(get_async_signal_unsafe_fns): New function.
(signal_unsafe_p): Reimplement in terms of the above.
(selftest::analyzer_sm_signal_cc_tests): New function.
gcc/testsuite/ChangeLog:
* gcc.dg/analyzer/signal-5.c: New test.
---
gcc/analyzer/analyzer-selftests.cc | 1 +
gcc/analyzer/analyzer-selftests.h | 1 +
gcc/analyzer/sm-signal.cc | 57 +++++++++++++++++++++---
gcc/testsuite/gcc.dg/analyzer/signal-5.c | 21 +++++++++
4 files changed, 73 insertions(+), 7 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/analyzer/signal-5.c
diff --git a/gcc/analyzer/analyzer-selftests.cc
b/gcc/analyzer/analyzer-selftests.cc
index 8201c21525c4..f90dad8e991f 100644
--- a/gcc/analyzer/analyzer-selftests.cc
+++ b/gcc/analyzer/analyzer-selftests.cc
@@ -53,6 +53,7 @@ run_analyzer_selftests ()
analyzer_program_point_cc_tests ();
analyzer_program_state_cc_tests ();
analyzer_region_model_cc_tests ();
+ analyzer_sm_signal_cc_tests ();
#endif /* #if ENABLE_ANALYZER */
}
diff --git a/gcc/analyzer/analyzer-selftests.h
b/gcc/analyzer/analyzer-selftests.h
index de9bb3130df0..225b717c9d13 100644
--- a/gcc/analyzer/analyzer-selftests.h
+++ b/gcc/analyzer/analyzer-selftests.h
@@ -37,6 +37,7 @@ extern void analyzer_function_set_cc_tests ();
extern void analyzer_program_point_cc_tests ();
extern void analyzer_program_state_cc_tests ();
extern void analyzer_region_model_cc_tests ();
+extern void analyzer_sm_signal_cc_tests ();
} /* end of namespace selftest. */
diff --git a/gcc/analyzer/sm-signal.cc b/gcc/analyzer/sm-signal.cc
index e01ff30d9172..98105b4f60fb 100644
--- a/gcc/analyzer/sm-signal.cc
+++ b/gcc/analyzer/sm-signal.cc
@@ -32,8 +32,10 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/analyzer.h"
#include "analyzer/checker-path.h"
#include "analyzer/exploded-graph.h"
+#include "analyzer/function-set.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/sm.h"
+#include "analyzer/analyzer-selftests.h"
#if ENABLE_ANALYZER
@@ -224,16 +226,40 @@ public:
tree m_fndecl;
};
-/* Return true if CALL is known to be unsafe to call from a signal handler. */
+/* Get a set of functions that are known to be unsafe to call from an
+ async signal handler. */
-static bool
-signal_unsafe_p (tree callee_fndecl)
+static function_set
+get_async_signal_unsafe_fns ()
{
- // TODO: maintain a list of known unsafe functions
- if (is_named_call_p (callee_fndecl, "fprintf"))
- return true;
+ // TODO: populate this list more fully
+ static const char * const async_signal_unsafe_fns[] = {
+ /* This array must be kept sorted. */
+ "fprintf",
+ "free",
+ "malloc",
+ "printf",
+ "snprintf",
+ "sprintf",
+ "vfprintf",
+ "vprintf",
+ "vsnprintf",
+ "vsprintf"
+ };
+ const size_t count
+ = sizeof(async_signal_unsafe_fns) / sizeof (async_signal_unsafe_fns[0]);
+ function_set fs (async_signal_unsafe_fns, count);
+ return fs;
+};
- return false;
+/* Return true if FNDECL is known to be unsafe to call from a signal
+ handler. */
+
+static bool
+signal_unsafe_p (tree fndecl)
+{
+ function_set fs = get_async_signal_unsafe_fns ();
+ return fs.contains_decl_p (fndecl);
}
/* Implementation of state_machine::on_stmt vfunc for signal_state_machine. */
@@ -303,4 +329,21 @@ make_signal_state_machine (logger *logger)
return new signal_state_machine (logger);
}
+#if CHECKING_P
+
+namespace selftest {
+
+/* Run all of the selftests within this file. */
+
+void
+analyzer_sm_signal_cc_tests ()
+{
+ function_set fs = get_async_signal_unsafe_fns ();
+ fs.assert_sorted ();
+ fs.assert_sane ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
#endif /* #if ENABLE_ANALYZER */
diff --git a/gcc/testsuite/gcc.dg/analyzer/signal-5.c
b/gcc/testsuite/gcc.dg/analyzer/signal-5.c
new file mode 100644
index 000000000000..4e464fffda54
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/signal-5.c
@@ -0,0 +1,21 @@
+/* Example of other bad calls within a signal handler. */
+
+#include <stdlib.h>
+#include <signal.h>
+
+extern void do_stuff (void *ptr);
+extern void body_of_program(void);
+
+static void handler(int signum)
+{
+ void *ptr = malloc (1024); /* { dg-warning "call to 'malloc' from within
signal handler" } */
+ do_stuff (ptr);
+ free (ptr); /* { dg-warning "call to 'free' 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