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