Skip to content
Snippets Groups Projects
Commit 2221fb6f authored by Mark Wielaard's avatar Mark Wielaard
Browse files

analyzer: Add exit, and _exit replacement, to sm-signal.

Warn about using exit in signal handler and suggest _exit as alternative.

gcc/analyzer/ChangeLog:

	* sm-signal.cc(signal_unsafe_call::emit): Possibly add
	gcc_rich_location note for replacement.
	(signal_unsafe_call::get_replacement_fn): New private function.
	(get_async_signal_unsafe_fns): Add "exit".

gcc/testsuite/ChangeLog:

	* gcc.dg/analyzer/signal-exit.c: New testcase.
parent dc50686d
No related branches found
No related tags found
No related merge requests found
2020-05-22 Mark Wielaard <mark@klomp.org>
* sm-signal.cc(signal_unsafe_call::emit): Possibly add
gcc_rich_location note for replacement.
(signal_unsafe_call::get_replacement_fn): New private function.
(get_async_signal_unsafe_fns): Add "exit".
2020-04-28 David Malcolm <dmalcolm@redhat.com>
PR analyzer/94816
......
......@@ -123,13 +123,32 @@ public:
bool emit (rich_location *rich_loc) FINAL OVERRIDE
{
auto_diagnostic_group d;
diagnostic_metadata m;
/* CWE-479: Signal Handler Use of a Non-reentrant Function. */
m.add_cwe (479);
return warning_meta (rich_loc, m,
OPT_Wanalyzer_unsafe_call_within_signal_handler,
"call to %qD from within signal handler",
m_unsafe_fndecl);
if (warning_meta (rich_loc, m,
OPT_Wanalyzer_unsafe_call_within_signal_handler,
"call to %qD from within signal handler",
m_unsafe_fndecl))
{
/* If we know a possible alternative function, add a note
suggesting the replacement. */
if (const char *replacement = get_replacement_fn ())
{
location_t note_loc = gimple_location (m_unsafe_call);
/* It would be nice to add a fixit, but the gimple call
location covers the whole call expression. It isn't
currently possible to cut this down to just the call
symbol. So the fixit would replace too much.
note_rich_loc.add_fixit_replace (replacement); */
inform (note_loc,
"%qs is a possible signal-safe alternative for %qD",
replacement, m_unsafe_fndecl);
}
return true;
}
return false;
}
label_text describe_state_change (const evdesc::state_change &change)
......@@ -156,6 +175,20 @@ private:
const signal_state_machine &m_sm;
const gcall *m_unsafe_call;
tree m_unsafe_fndecl;
/* Returns a replacement function as text if it exists. Currently
only "exit" has a signal-safe replacement "_exit", which does
slightly less, but can be used in a signal handler. */
const char *
get_replacement_fn ()
{
gcc_assert (m_unsafe_fndecl && DECL_P (m_unsafe_fndecl));
if (id_equal ("exit", DECL_NAME (m_unsafe_fndecl)))
return "_exit";
return NULL;
}
};
/* signal_state_machine's ctor. */
......@@ -259,6 +292,7 @@ get_async_signal_unsafe_fns ()
// TODO: populate this list more fully
static const char * const async_signal_unsafe_fns[] = {
/* This array must be kept sorted. */
"exit",
"fprintf",
"free",
"malloc",
......
2020-05-22 Mark Wielaard <mark@klomp.org>
* gcc.dg/analyzer/signal-exit.c: New testcase.
2020-05-22 Uroš Bizjak <ubizjak@gmail.com>
 
PR target/95255
......
/* Example of a bad call within a signal handler with replacement
alternative. 'handler' calls 'exit', and 'exit' is not allowed
from a signal handler. But '_exit' is allowed. */
#include <signal.h>
#include <stdlib.h>
extern void body_of_program(void);
static void handler(int signum)
{
exit(1); /* { dg-warning "call to 'exit' from within signal handler" "warning" } */
/* { dg-message "note: '_exit' is a possible signal-safe alternative for 'exit'" "replacement note" { target *-*-* } .-1 } */
}
int main(int argc, const char *argv)
{
signal(SIGINT, handler); /* { dg-message "registering 'handler' as signal handler" } */
body_of_program();
return 0;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment