[committed] New warning: -Wanalyzer-jump-through-null [PR105947]
Commit Message
This patch adds a new warning to -fanalyzer for jumps through NULL
function pointers.
Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
Pushed to trunk as r13-1979-ge1a9168153d2bf.
gcc/analyzer/ChangeLog:
PR analyzer/105947
* analyzer.opt (Wanalyzer-jump-through-null): New option.
* engine.cc (class jump_through_null): New.
(exploded_graph::process_node): Complain about jumps through NULL
function pointers.
gcc/ChangeLog:
PR analyzer/105947
* doc/invoke.texi: Add -Wanalyzer-jump-through-null.
gcc/testsuite/ChangeLog:
PR analyzer/105947
* gcc.dg/analyzer/function-ptr-5.c: New test.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
---
gcc/analyzer/analyzer.opt | 4 ++
gcc/analyzer/engine.cc | 49 +++++++++++++++++++
gcc/doc/invoke.texi | 12 +++++
.../gcc.dg/analyzer/function-ptr-5.c | 42 ++++++++++++++++
4 files changed, 107 insertions(+)
create mode 100644 gcc/testsuite/gcc.dg/analyzer/function-ptr-5.c
@@ -98,6 +98,10 @@ Wanalyzer-free-of-non-heap
Common Var(warn_analyzer_free_of_non_heap) Init(1) Warning
Warn about code paths in which a non-heap pointer is freed.
+Wanalyzer-jump-through-null
+Common Var(warn_analyzer_jump_through_null) Init(1) Warning
+Warn about code paths in which a NULL function pointer is called.
+
Wanalyzer-malloc-leak
Common Var(warn_analyzer_malloc_leak) Init(1) Warning
Warn about code paths in which a heap-allocated pointer leaks.
@@ -3705,6 +3705,46 @@ private:
bool m_terminate_path;
};
+/* A subclass of pending_diagnostic for complaining about jumps through NULL
+ function pointers. */
+
+class jump_through_null : public pending_diagnostic_subclass<jump_through_null>
+{
+public:
+ jump_through_null (const gcall *call)
+ : m_call (call)
+ {}
+
+ const char *get_kind () const final override
+ {
+ return "jump_through_null";
+ }
+
+ bool operator== (const jump_through_null &other) const
+ {
+ return m_call == other.m_call;
+ }
+
+ int get_controlling_option () const final override
+ {
+ return OPT_Wanalyzer_jump_through_null;
+ }
+
+ bool emit (rich_location *rich_loc) final override
+ {
+ return warning_at (rich_loc, get_controlling_option (),
+ "jump through null pointer");
+ }
+
+ label_text describe_final_event (const evdesc::final_event &ev) final override
+ {
+ return ev.formatted_print ("jump through null pointer here");
+ }
+
+private:
+ const gcall *m_call;
+};
+
/* The core of exploded_graph::process_worklist (the main analysis loop),
handling one node in the worklist.
@@ -4046,6 +4086,15 @@ exploded_graph::process_node (exploded_node *node)
logger);
if (!call_discovered)
{
+ /* Check for jump through NULL. */
+ if (tree fn_ptr = gimple_call_fn (call))
+ {
+ const svalue *fn_ptr_sval
+ = model->get_rvalue (fn_ptr, &ctxt);
+ if (fn_ptr_sval->all_zeroes_p ())
+ ctxt.warn (new jump_through_null (call));
+ }
+
/* An unknown function or a special function was called
at this point, in such case, don't terminate the
analysis of the current function.
@@ -453,6 +453,7 @@ Objective-C and Objective-C++ Dialects}.
-Wno-analyzer-fd-use-without-check @gol
-Wno-analyzer-file-leak @gol
-Wno-analyzer-free-of-non-heap @gol
+-Wno-analyzer-jump-through-null @gol
-Wno-analyzer-malloc-leak @gol
-Wno-analyzer-mismatching-deallocation @gol
-Wno-analyzer-null-argument @gol
@@ -9756,6 +9757,7 @@ Enabling this option effectively enables the following warnings:
-Wanalyzer-fd-use-without-check @gol
-Wanalyzer-file-leak @gol
-Wanalyzer-free-of-non-heap @gol
+-Wanalyzer-jump-through-null @gol
-Wanalyzer-malloc-leak @gol
-Wanalyzer-mismatching-deallocation @gol
-Wanalyzer-null-argument @gol
@@ -9942,6 +9944,16 @@ is called on a non-heap pointer (e.g. an on-stack buffer, or a global).
See @uref{https://cwe.mitre.org/data/definitions/590.html, CWE-590: Free of Memory not on the Heap}.
+@item -Wno-analyzer-jump-through-null
+@opindex Wanalyzer-jump-through-null
+@opindex Wno-analyzer-jump-through-null
+This warning requires @option{-fanalyzer}, which enables it; use
+@option{-Wno-analyzer-jump-through-null}
+to disable it.
+
+This diagnostic warns for paths through the code in which a @code{NULL}
+function pointer is called.
+
@item -Wno-analyzer-malloc-leak
@opindex Wanalyzer-malloc-leak
@opindex Wno-analyzer-malloc-leak
new file mode 100644
@@ -0,0 +1,42 @@
+#define NULL ((void *)0)
+
+void calling_null_fn_ptr_1 (void)
+{
+ void (*fn_ptr) (void) = NULL;
+ fn_ptr (); /* { dg-warning "jump through null pointer" } */
+}
+
+int calling_null_fn_ptr_2 (void)
+{
+ int (*fn_ptr) (void) = NULL;
+ return fn_ptr (); /* { dg-warning "jump through null pointer" } */
+}
+
+typedef void (*void_void_fn_ptr) (void);
+
+void calling_const_fn_ptr (void)
+{
+ void_void_fn_ptr fn_ptr = (void_void_fn_ptr)0xffd2;
+ return fn_ptr ();
+}
+
+void skipping_init (int flag)
+{
+ void_void_fn_ptr fn_ptr = NULL;
+ if (flag) /* { dg-message "branch" } */
+ fn_ptr = (void_void_fn_ptr)0xffd2;
+ fn_ptr (); /* { dg-warning "jump through null pointer" } */
+}
+
+struct callbacks
+{
+ void_void_fn_ptr on_redraw;
+ void_void_fn_ptr on_cleanup;
+};
+
+void test_callbacks (void)
+{
+ struct callbacks cb;
+ __builtin_memset (&cb, 0, sizeof (cb));
+ cb.on_cleanup (); /* { dg-warning "jump through null pointer" } */
+}