diff options
author | Martin Liska <mliska@suse.cz> | 2022-08-08 09:05:36 +0200 |
---|---|---|
committer | Martin Liska <mliska@suse.cz> | 2022-08-08 09:05:36 +0200 |
commit | b3a187edd33b89acf19ba46f3b8070d7c977ac57 (patch) | |
tree | 43549f6851052eb2844ea76358af30a9fd302ec5 /gcc/analyzer | |
parent | 89eca196c99645ee1abefcf8b4a9dd84edd87ad6 (diff) | |
parent | 2633c8d8f338f1e2b53d3757f3edf4179bfcc218 (diff) | |
download | gcc-b3a187edd33b89acf19ba46f3b8070d7c977ac57.zip gcc-b3a187edd33b89acf19ba46f3b8070d7c977ac57.tar.gz gcc-b3a187edd33b89acf19ba46f3b8070d7c977ac57.tar.bz2 |
Merge branch 'master' into devel/sphinx
Diffstat (limited to 'gcc/analyzer')
-rw-r--r-- | gcc/analyzer/ChangeLog | 18 | ||||
-rw-r--r-- | gcc/analyzer/analyzer.opt | 4 | ||||
-rw-r--r-- | gcc/analyzer/engine.cc | 49 | ||||
-rw-r--r-- | gcc/analyzer/sm-fd.cc | 129 |
4 files changed, 197 insertions, 3 deletions
diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog index d1cb3ad..0b93219 100644 --- a/gcc/analyzer/ChangeLog +++ b/gcc/analyzer/ChangeLog @@ -1,3 +1,21 @@ +2022-08-05 David Malcolm <dmalcolm@redhat.com> + + 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. + +2022-08-02 Immad Mir <mirimmad@outlook.com> + + PR analyzer/106298 + * sm-fd.cc (fd_state_machine::on_open): Add + creat, dup, dup2 and dup3 functions. + (enum dup): New. + (fd_state_machine::valid_to_unchecked_state): New. + (fd_state_machine::on_creat): New. + (fd_state_machine::on_dup): New. + 2022-07-28 David Malcolm <dmalcolm@redhat.com> PR analyzer/105893 diff --git a/gcc/analyzer/analyzer.opt b/gcc/analyzer/analyzer.opt index 808ff36..c6d9c53 100644 --- a/gcc/analyzer/analyzer.opt +++ b/gcc/analyzer/analyzer.opt @@ -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. diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc index 85b7c5e..e8db00d 100644 --- a/gcc/analyzer/engine.cc +++ b/gcc/analyzer/engine.cc @@ -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. diff --git a/gcc/analyzer/sm-fd.cc b/gcc/analyzer/sm-fd.cc index ed923ad..8bb76d7 100644 --- a/gcc/analyzer/sm-fd.cc +++ b/gcc/analyzer/sm-fd.cc @@ -69,6 +69,14 @@ enum access_directions DIRS_WRITE }; +/* An enum for distinguishing between dup, dup2 and dup3. */ +enum dup +{ + DUP_1, + DUP_2, + DUP_3 +}; + class fd_state_machine : public state_machine { public: @@ -114,7 +122,9 @@ public: bool is_readonly_fd_p (state_t s) const; bool is_writeonly_fd_p (state_t s) const; enum access_mode get_access_mode_from_flag (int flag) const; - + /* Function for one-to-one correspondence between valid + and unchecked states. */ + state_t valid_to_unchecked_state (state_t state) const; /* State for a constant file descriptor (>= 0) */ state_t m_constant_fd; @@ -147,6 +157,8 @@ public: private: void on_open (sm_context *sm_ctxt, const supernode *node, const gimple *stmt, const gcall *call) const; + void on_creat (sm_context *sm_ctxt, const supernode *node, const gimple *stmt, + const gcall *call) const; void on_close (sm_context *sm_ctxt, const supernode *node, const gimple *stmt, const gcall *call) const; void on_read (sm_context *sm_ctxt, const supernode *node, const gimple *stmt, @@ -170,6 +182,9 @@ private: const gimple *stmt, const gcall *call, const tree callee_fndecl, const char *attr_name, access_directions fd_attr_access_dir) const; + void check_for_dup (sm_context *sm_ctxt, const supernode *node, + const gimple *stmt, const gcall *call, const tree callee_fndecl, + enum dup kind) const; }; /* Base diagnostic class relative to fd_state_machine. */ @@ -723,6 +738,20 @@ fd_state_machine::is_constant_fd_p (state_t state) const return (state == m_constant_fd); } +fd_state_machine::state_t +fd_state_machine::valid_to_unchecked_state (state_t state) const +{ + if (state == m_valid_read_write) + return m_unchecked_read_write; + else if (state == m_valid_write_only) + return m_unchecked_write_only; + else if (state == m_valid_read_only) + return m_unchecked_read_only; + else + gcc_unreachable (); + return NULL; +} + bool fd_state_machine::on_stmt (sm_context *sm_ctxt, const supernode *node, const gimple *stmt) const @@ -736,6 +765,11 @@ fd_state_machine::on_stmt (sm_context *sm_ctxt, const supernode *node, return true; } // "open" + if (is_named_call_p (callee_fndecl, "creat", call, 2)) + { + on_creat (sm_ctxt, node, stmt, call); + } // "creat" + if (is_named_call_p (callee_fndecl, "close", call, 1)) { on_close (sm_ctxt, node, stmt, call); @@ -754,6 +788,23 @@ fd_state_machine::on_stmt (sm_context *sm_ctxt, const supernode *node, return true; } // "read" + if (is_named_call_p (callee_fndecl, "dup", call, 1)) + { + check_for_dup (sm_ctxt, node, stmt, call, callee_fndecl, DUP_1); + return true; + } + + if (is_named_call_p (callee_fndecl, "dup2", call, 2)) + { + check_for_dup (sm_ctxt, node, stmt, call, callee_fndecl, DUP_2); + return true; + } + + if (is_named_call_p (callee_fndecl, "dup3", call, 3)) + { + check_for_dup (sm_ctxt, node, stmt, call, callee_fndecl, DUP_3); + return true; + } { // Handle __attribute__((fd_arg)) @@ -900,6 +951,78 @@ fd_state_machine::on_open (sm_context *sm_ctxt, const supernode *node, } void +fd_state_machine::on_creat (sm_context *sm_ctxt, const supernode *node, + const gimple *stmt, const gcall *call) const +{ + tree lhs = gimple_call_lhs (call); + if (lhs) + sm_ctxt->on_transition (node, stmt, lhs, m_start, m_unchecked_write_only); + else + sm_ctxt->warn (node, stmt, NULL_TREE, new fd_leak (*this, NULL_TREE)); +} + +void +fd_state_machine::check_for_dup (sm_context *sm_ctxt, const supernode *node, + const gimple *stmt, const gcall *call, + const tree callee_fndecl, enum dup kind) const +{ + tree lhs = gimple_call_lhs (call); + tree arg_1 = gimple_call_arg (call, 0); + state_t state_arg_1 = sm_ctxt->get_state (stmt, arg_1); + if (state_arg_1 == m_stop) + return; + if (!(is_constant_fd_p (state_arg_1) || is_valid_fd_p (state_arg_1))) + { + check_for_open_fd (sm_ctxt, node, stmt, call, callee_fndecl, + DIRS_READ_WRITE); + if (kind == DUP_1) + return; + } + switch (kind) + { + case DUP_1: + if (lhs) + { + if (is_constant_fd_p (state_arg_1)) + sm_ctxt->set_next_state (stmt, lhs, m_unchecked_read_write); + else + sm_ctxt->set_next_state (stmt, lhs, + valid_to_unchecked_state (state_arg_1)); + } + break; + + case DUP_2: + case DUP_3: + tree arg_2 = gimple_call_arg (call, 1); + state_t state_arg_2 = sm_ctxt->get_state (stmt, arg_2); + tree diag_arg_2 = sm_ctxt->get_diagnostic_tree (arg_2); + if (state_arg_2 == m_stop) + return; + /* Check if -1 was passed as second argument to dup2. */ + if (!(is_constant_fd_p (state_arg_2) || is_valid_fd_p (state_arg_2))) + { + sm_ctxt->warn ( + node, stmt, arg_2, + new fd_use_without_check (*this, diag_arg_2, callee_fndecl)); + return; + } + /* dup2 returns value of its second argument on success.But, the + access mode of the returned file descriptor depends on the duplicated + file descriptor i.e the first argument. */ + if (lhs) + { + if (is_constant_fd_p (state_arg_1)) + sm_ctxt->set_next_state (stmt, lhs, m_unchecked_read_write); + else + sm_ctxt->set_next_state (stmt, lhs, + valid_to_unchecked_state (state_arg_1)); + } + + break; + } +} + +void fd_state_machine::on_close (sm_context *sm_ctxt, const supernode *node, const gimple *stmt, const gcall *call) const { @@ -964,6 +1087,8 @@ fd_state_machine::check_for_open_fd ( } switch (callee_fndecl_dir) { + case DIRS_READ_WRITE: + break; case DIRS_READ: if (is_writeonly_fd_p (state)) { @@ -984,8 +1109,6 @@ fd_state_machine::check_for_open_fd ( *this, diag_arg, DIRS_READ, callee_fndecl)); } break; - default: - gcc_unreachable (); } } } |