Hi,
While trying out -fanalyzer on the bzip2 source code I noticed that it
did warn about some unsafe calls in the signal handler, but din't warn
about the exit call:
https://sourceware.org/pipermail/bzip2-devel/2020q2/000107.html
It was easy to add exit to the async_signal_unsafe_fns, but since
there is a signal safe _exit call (which is what you should use in a
signal handler, so no unsafe calls are made, like to the at_exit
handlers) I also wanted to add a fixit hint.
The fixit hint is emitted, but it is somewhat hard to see. Is there a
better way to do this for analyzer warnings so that it is a bit more
prominent?
This is how it currently looks:
/opt/local/gcc/bin/gcc -g -O2 -fanalyzer -c bzip2.c
bzip2.c: In function ‘mySIGSEGVorSIGBUScatcher’:
bzip2.c:874:4: warning: call to ‘exit’ from within signal handler [CWE-479]
[-Wanalyzer-unsafe-call-within-signal-handler]
874 | exit(exitValue);
| ^~~~~~~~~~~~~~~
| _exit
‘main’: events 1-2
|
| 1784 | IntNative main ( IntNative argc, Char *argv[] )
| | ^~~~
| | |
| | (1) entry to ‘main’
|......
| 1800 | smallMode = False;
| | ~~~~~~~~~
| | |
| | (2) registering ‘mySIGSEGVorSIGBUScatcher’ as signal handler
|
event 3
|
|cc1:
| (3): later on, when the signal is delivered to the process
|
+--> ‘mySIGSEGVorSIGBUScatcher’: events 4-5
|
| 816 | void mySIGSEGVorSIGBUScatcher ( IntNative n )
| | ^~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (4) entry to ‘mySIGSEGVorSIGBUScatcher’
|......
| 874 | exit(exitValue);
| | ~~~~~~~~~~~~~~~
| | |
| | (5) call to ‘exit’ from within signal handler
|
Thanks,
Mark
---
gcc/analyzer/sm-signal.cc | 34 +++++++++++++++++++++++++++++-----
1 file changed, 29 insertions(+), 5 deletions(-)
diff --git a/gcc/analyzer/sm-signal.cc b/gcc/analyzer/sm-signal.cc
index 5935e229e77c..99e87706af63 100644
--- a/gcc/analyzer/sm-signal.cc
+++ b/gcc/analyzer/sm-signal.cc
@@ -108,8 +108,9 @@ class signal_unsafe_call
{
public:
signal_unsafe_call (const signal_state_machine &sm, const gcall *unsafe_call,
- tree unsafe_fndecl)
- : m_sm (sm), m_unsafe_call (unsafe_call), m_unsafe_fndecl (unsafe_fndecl)
+ tree unsafe_fndecl, const char *replacement)
+ : m_sm (sm), m_unsafe_call (unsafe_call), m_unsafe_fndecl (unsafe_fndecl),
+ m_replacement (replacement)
{
gcc_assert (m_unsafe_fndecl);
}
@@ -126,6 +127,8 @@ public:
diagnostic_metadata m;
/* CWE-479: Signal Handler Use of a Non-reentrant Function. */
m.add_cwe (479);
+ if (m_replacement != NULL)
+ rich_loc->add_fixit_replace (m_replacement);
return warning_meta (rich_loc, m,
OPT_Wanalyzer_unsafe_call_within_signal_handler,
"call to %qD from within signal handler",
@@ -156,6 +159,7 @@ private:
const signal_state_machine &m_sm;
const gcall *m_unsafe_call;
tree m_unsafe_fndecl;
+ const char *m_replacement;
};
/* signal_state_machine's ctor. */
@@ -259,6 +263,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",
@@ -286,6 +291,20 @@ signal_unsafe_p (tree fndecl)
return fs.contains_decl_p (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 *
+replacement_fn (tree fndecl)
+{
+ gcc_assert (fndecl && DECL_P (fndecl));
+
+ if (strcmp ("exit", IDENTIFIER_POINTER (DECL_NAME (fndecl))) == 0)
+ return "_exit";
+
+ return NULL;
+}
+
/* Implementation of state_machine::on_stmt vfunc for signal_state_machine. */
bool
@@ -315,9 +334,14 @@ signal_state_machine::on_stmt (sm_context *sm_ctxt,
if (const gcall *call = dyn_cast <const gcall *> (stmt))
if (tree callee_fndecl = sm_ctxt->get_fndecl_for_call (call))
if (signal_unsafe_p (callee_fndecl))
- sm_ctxt->warn_for_state (node, stmt, NULL_TREE, m_in_signal_handler,
- new signal_unsafe_call (*this, call,
- callee_fndecl));
+ {
+ const char *replace = replacement_fn (callee_fndecl);
+ sm_ctxt->warn_for_state (node, stmt, NULL_TREE,
+ m_in_signal_handler,
+ new signal_unsafe_call (*this, call,
+ callee_fndecl,
+ replace));
+ }
}
return false;
--
2.20.1