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.
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.
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.
-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
-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
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
--- /dev/null
+#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" } */
+}