From 4804c5fe965eef2f346de53d9e896ea2cd88f0b9 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Thu, 19 Dec 2019 15:50:29 -0500 Subject: [PATCH] analyzer: introduce a set of known async-signal-unsafe functions 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/ChangeLog | 12 +++++ gcc/analyzer/analyzer-selftests.cc | 1 + gcc/analyzer/analyzer-selftests.h | 1 + gcc/analyzer/sm-signal.cc | 57 +++++++++++++++++++++--- gcc/testsuite/ChangeLog | 4 ++ gcc/testsuite/gcc.dg/analyzer/signal-5.c | 21 +++++++++ 6 files changed, 89 insertions(+), 7 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/analyzer/signal-5.c diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog index 93efb47bb7c..bb3ac7267d9 100644 --- a/gcc/analyzer/ChangeLog +++ b/gcc/analyzer/ChangeLog @@ -1,3 +1,15 @@ +2020-01-14 David Malcolm + + * 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. + 2020-01-14 David Malcolm * analyzer-selftests.cc (selftest::run_analyzer_selftests): Call diff --git a/gcc/analyzer/analyzer-selftests.cc b/gcc/analyzer/analyzer-selftests.cc index 99b730a6be5..2b8fa81fdb1 100644 --- a/gcc/analyzer/analyzer-selftests.cc +++ b/gcc/analyzer/analyzer-selftests.cc @@ -54,6 +54,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 61e3a024dff..80be32f4770 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 ee41d1976c0..0057ab96d44 100644 --- a/gcc/analyzer/sm-signal.cc +++ b/gcc/analyzer/sm-signal.cc @@ -56,6 +56,8 @@ along with GCC; see the file COPYING3. If not see #include "analyzer/diagnostic-manager.h" #include "shortest-paths.h" #include "analyzer/exploded-graph.h" +#include "analyzer/function-set.h" +#include "analyzer/analyzer-selftests.h" #if ENABLE_ANALYZER @@ -246,16 +248,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. */ @@ -325,4 +351,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/ChangeLog b/gcc/testsuite/ChangeLog index efff14c4141..8013bdbc2eb 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2020-01-14 David Malcolm + + * gcc.dg/analyzer/signal-5.c: New test. + 2020-01-14 David Malcolm * gcc.dg/analyzer/data-model-1.c: Remove xfail. 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 00000000000..4e464fffda5 --- /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 +#include + +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.30.2