diff options
Diffstat (limited to 'gcc/analyzer')
-rw-r--r-- | gcc/analyzer/call-info.cc | 21 | ||||
-rw-r--r-- | gcc/analyzer/call-info.h | 34 | ||||
-rw-r--r-- | gcc/analyzer/region-model-impl-calls.cc | 28 | ||||
-rw-r--r-- | gcc/analyzer/region-model-manager.cc | 2 | ||||
-rw-r--r-- | gcc/analyzer/region-model-manager.h | 4 | ||||
-rw-r--r-- | gcc/analyzer/region-model.cc | 36 | ||||
-rw-r--r-- | gcc/analyzer/region-model.h | 3 | ||||
-rw-r--r-- | gcc/analyzer/region.cc | 22 | ||||
-rw-r--r-- | gcc/analyzer/region.h | 60 | ||||
-rw-r--r-- | gcc/analyzer/store.cc | 17 | ||||
-rw-r--r-- | gcc/analyzer/store.h | 2 |
11 files changed, 195 insertions, 34 deletions
diff --git a/gcc/analyzer/call-info.cc b/gcc/analyzer/call-info.cc index ffdab73..7a1c4ed 100644 --- a/gcc/analyzer/call-info.cc +++ b/gcc/analyzer/call-info.cc @@ -141,24 +141,15 @@ call_info::call_info (const call_details &cd) gcc_assert (m_fndecl); } -/* class success_call_info : public call_info. */ - -/* Implementation of call_info::get_desc vfunc for success_call_info. */ - -label_text -success_call_info::get_desc (bool can_colorize) const -{ - return make_label_text (can_colorize, "when %qE succeeds", get_fndecl ()); -} - -/* class failed_call_info : public call_info. */ - -/* Implementation of call_info::get_desc vfunc for failed_call_info. */ +/* class succeed_or_fail_call_info : public call_info. */ label_text -failed_call_info::get_desc (bool can_colorize) const +succeed_or_fail_call_info::get_desc (bool can_colorize) const { - return make_label_text (can_colorize, "when %qE fails", get_fndecl ()); + if (m_success) + return make_label_text (can_colorize, "when %qE succeeds", get_fndecl ()); + else + return make_label_text (can_colorize, "when %qE fails", get_fndecl ()); } } // namespace ana diff --git a/gcc/analyzer/call-info.h b/gcc/analyzer/call-info.h index 4bb7dd7..2fd5077 100644 --- a/gcc/analyzer/call-info.h +++ b/gcc/analyzer/call-info.h @@ -51,17 +51,36 @@ private: }; /* Subclass of call_info for a "success" outcome of a call, - adding a "when `FNDECL' succeeds" message. + adding either a + "when `FNDECL' succeeds" message (when 'success' is true) + or a + "when `FNDECL' fails" message (when 'success' is false). This is still abstract: the custom_edge_info::update_model vfunc must be implemented. */ -class success_call_info : public call_info +class succeed_or_fail_call_info : public call_info { public: label_text get_desc (bool can_colorize) const final override; protected: - success_call_info (const call_details &cd) : call_info (cd) {} + succeed_or_fail_call_info (const call_details &cd, bool success) + : call_info (cd), m_success (success) {} + + bool m_success; +}; + +/* Subclass of call_info for a "success" outcome of a call, + adding a "when `FNDECL' succeeds" message. + This is still abstract: the custom_edge_info::update_model vfunc + must be implemented. */ + +class success_call_info : public succeed_or_fail_call_info +{ +protected: + success_call_info (const call_details &cd) + : succeed_or_fail_call_info (cd, true) + {} }; /* Subclass of call_info for a "failure" outcome of a call, @@ -69,13 +88,12 @@ protected: This is still abstract: the custom_edge_info::update_model vfunc must be implemented. */ -class failed_call_info : public call_info +class failed_call_info : public succeed_or_fail_call_info { -public: - label_text get_desc (bool can_colorize) const final override; - protected: - failed_call_info (const call_details &cd) : call_info (cd) {} + failed_call_info (const call_details &cd) + : succeed_or_fail_call_info (cd, false) + {} }; } // namespace ana diff --git a/gcc/analyzer/region-model-impl-calls.cc b/gcc/analyzer/region-model-impl-calls.cc index 30fa765..bc644f8 100644 --- a/gcc/analyzer/region-model-impl-calls.cc +++ b/gcc/analyzer/region-model-impl-calls.cc @@ -413,6 +413,20 @@ region_model::impl_call_calloc (const call_details &cd) } } +/* Handle the on_call_pre part of "__errno_location". */ + +void +region_model::impl_call_errno_location (const call_details &cd) +{ + if (cd.get_lhs_region ()) + { + const region *errno_reg = m_mgr->get_errno_region (); + const svalue *errno_ptr = m_mgr->get_ptr_svalue (cd.get_lhs_type (), + errno_reg); + cd.maybe_set_lhs (errno_ptr); + } +} + /* Handle the on_call_pre part of "error" and "error_at_line" from GNU's non-standard <error.h>. MIN_ARGS identifies the minimum number of expected arguments @@ -1013,7 +1027,7 @@ region_model::impl_call_realloc (const call_details &cd) } } -/* Handle the on_call_pre part of "strchr" and "__builtin_strchr". */ +/* Handle the on_call_post part of "strchr" and "__builtin_strchr". */ void region_model::impl_call_strchr (const call_details &cd) @@ -1075,13 +1089,13 @@ region_model::impl_call_strchr (const call_details &cd) bool m_found; }; - /* Bifurcate state, creating a "not found" out-edge. */ + /* Body of region_model::impl_call_strchr. */ if (cd.get_ctxt ()) - cd.get_ctxt ()->bifurcate (make_unique<strchr_call_info> (cd, false)); - - /* The "unbifurcated" state is the "found" case. */ - strchr_call_info found (cd, true); - found.update_model (this, NULL, cd.get_ctxt ()); + { + cd.get_ctxt ()->bifurcate (make_unique<strchr_call_info> (cd, false)); + cd.get_ctxt ()->bifurcate (make_unique<strchr_call_info> (cd, true)); + cd.get_ctxt ()->terminate_path (); + } } /* Handle the on_call_pre part of "strcpy" and "__builtin_strcpy_chk". */ diff --git a/gcc/analyzer/region-model-manager.cc b/gcc/analyzer/region-model-manager.cc index de01627..08bf5d2 100644 --- a/gcc/analyzer/region-model-manager.cc +++ b/gcc/analyzer/region-model-manager.cc @@ -74,6 +74,8 @@ region_model_manager::region_model_manager (logger *logger) m_fndecls_map (), m_labels_map (), m_globals_region (alloc_region_id (), &m_root_region), m_globals_map (), + m_thread_local_region (alloc_region_id (), &m_root_region), + m_errno_region (alloc_region_id (), &m_thread_local_region), m_store_mgr (this), m_range_mgr (new bounded_ranges_manager ()), m_known_fn_mgr (logger) diff --git a/gcc/analyzer/region-model-manager.h b/gcc/analyzer/region-model-manager.h index 3d8f76e..0ff253b 100644 --- a/gcc/analyzer/region-model-manager.h +++ b/gcc/analyzer/region-model-manager.h @@ -107,6 +107,7 @@ public: { return &m_globals_region; } + const errno_region *get_errno_region () const { return &m_errno_region; } const function_region *get_region_for_fndecl (tree fndecl); const label_region *get_region_for_label (tree label); const decl_region *get_region_for_global (tree expr); @@ -287,6 +288,9 @@ private: typedef globals_map_t::iterator globals_iterator_t; globals_map_t m_globals_map; + thread_local_region m_thread_local_region; + errno_region m_errno_region; + consolidation_map<field_region> m_field_regions; consolidation_map<element_region> m_element_regions; consolidation_map<offset_region> m_offset_regions; diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index edf3412..0ca454a 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -2223,7 +2223,7 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt, case BUILT_IN_REALLOC: return false; case BUILT_IN_STRCHR: - impl_call_strchr (cd); + /* Handle in "on_call_post". */ return false; case BUILT_IN_STRCPY: case BUILT_IN_STRCPY_CHK: @@ -2288,6 +2288,11 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt, impl_call_realloc (cd); return false; } + else if (is_named_call_p (callee_fndecl, "__errno_location", call, 0)) + { + impl_call_errno_location (cd); + return false; + } else if (is_named_call_p (callee_fndecl, "error")) { if (impl_call_error (cd, 3, out_terminate_path)) @@ -2341,7 +2346,7 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt, else if (is_named_call_p (callee_fndecl, "strchr", call, 2) && POINTER_TYPE_P (cd.get_arg_type (0))) { - impl_call_strchr (cd); + /* Handle in "on_call_post". */ return false; } else if (is_named_call_p (callee_fndecl, "strlen", call, 1) @@ -2418,6 +2423,12 @@ region_model::on_call_post (const gcall *call, impl_call_pipe (cd); return; } + else if (is_named_call_p (callee_fndecl, "strchr", call, 2) + && POINTER_TYPE_P (cd.get_arg_type (0))) + { + impl_call_strchr (cd); + return; + } /* Was this fndecl referenced by __attribute__((malloc(FOO)))? */ if (lookup_attribute ("*dealloc", DECL_ATTRIBUTES (callee_fndecl))) @@ -2435,6 +2446,10 @@ region_model::on_call_post (const gcall *call, impl_call_realloc (cd); return; + case BUILT_IN_STRCHR: + impl_call_strchr (cd); + return; + case BUILT_IN_VA_END: impl_call_va_end (cd); return; @@ -6408,6 +6423,23 @@ region_model::maybe_complain_about_infoleak (const region *dst_reg, copied_sval)); } +/* Set errno to a positive symbolic int, as if some error has occurred. */ + +void +region_model::set_errno (const call_details &cd) +{ + const region *errno_reg = m_mgr->get_errno_region (); + conjured_purge p (this, cd.get_ctxt ()); + const svalue *new_errno_sval + = m_mgr->get_or_create_conjured_svalue (integer_type_node, + cd.get_call_stmt (), + errno_reg, p); + const svalue *zero + = m_mgr->get_or_create_int_cst (integer_type_node, 0); + add_constraint (new_errno_sval, GT_EXPR, zero, cd.get_ctxt ()); + set_value (errno_reg, new_errno_sval, cd.get_ctxt ()); +} + /* class noop_region_model_context : public region_model_context. */ void diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h index 5c0bc44..0caaf82 100644 --- a/gcc/analyzer/region-model.h +++ b/gcc/analyzer/region-model.h @@ -349,6 +349,7 @@ class region_model void impl_call_analyzer_get_unknown_ptr (const call_details &cd); void impl_call_builtin_expect (const call_details &cd); void impl_call_calloc (const call_details &cd); + void impl_call_errno_location (const call_details &cd); bool impl_call_error (const call_details &cd, unsigned min_args, bool *out_terminate_path); void impl_call_fgets (const call_details &cd); @@ -544,6 +545,8 @@ class region_model const region *src_reg, region_model_context *ctxt); + void set_errno (const call_details &cd); + /* Implemented in sm-fd.cc */ void mark_as_valid_fd (const svalue *sval, region_model_context *ctxt); diff --git a/gcc/analyzer/region.cc b/gcc/analyzer/region.cc index 4bc1918..6d97590 100644 --- a/gcc/analyzer/region.cc +++ b/gcc/analyzer/region.cc @@ -1050,6 +1050,17 @@ root_region::dump_to_pp (pretty_printer *pp, bool simple) const pp_string (pp, "root_region()"); } +/* class thread_local_region : public space_region. */ + +void +thread_local_region::dump_to_pp (pretty_printer *pp, bool simple) const +{ + if (simple) + pp_string (pp, "thread_local_region"); + else + pp_string (pp, "thread_local_region()"); +} + /* class symbolic_region : public map_region. */ /* symbolic_region's ctor. */ @@ -1811,6 +1822,17 @@ var_arg_region::get_frame_region () const return as_a <const frame_region *> (get_parent_region ()); } +/* class errno_region : public region. */ + +void +errno_region::dump_to_pp (pretty_printer *pp, bool simple) const +{ + if (simple) + pp_string (pp, "errno_region"); + else + pp_string (pp, "errno_region()"); +} + /* class unknown_region : public region. */ /* Implementation of region::dump_to_pp vfunc for unknown_region. */ diff --git a/gcc/analyzer/region.h b/gcc/analyzer/region.h index 6315fac..ecae887 100644 --- a/gcc/analyzer/region.h +++ b/gcc/analyzer/region.h @@ -34,7 +34,8 @@ enum memory_space MEMSPACE_GLOBALS, MEMSPACE_STACK, MEMSPACE_HEAP, - MEMSPACE_READONLY_DATA + MEMSPACE_READONLY_DATA, + MEMSPACE_THREAD_LOCAL }; /* An enum for discriminating between the different concrete subclasses @@ -49,6 +50,7 @@ enum region_kind RK_LABEL, RK_STACK, RK_HEAP, + RK_THREAD_LOCAL, RK_ROOT, RK_SYMBOLIC, RK_DECL, @@ -62,6 +64,7 @@ enum region_kind RK_STRING, RK_BIT_RANGE, RK_VAR_ARG, + RK_ERRNO, RK_UNKNOWN, }; @@ -77,6 +80,8 @@ enum region_kind code_region (RK_CODE): represents the code segment, containing functions stack_region (RK_STACK): a stack, containing all stack frames heap_region (RK_HEAP): the heap, containing heap_allocated_regions + thread_local_region (RK_THREAD_LOCAL): thread-local data for the thread + being analyzed root_region (RK_ROOT): the top-level region function_region (RK_FUNCTION): the code for a particular function label_region (RK_LABEL): a particular label within a function @@ -102,6 +107,7 @@ enum region_kind within another region var_arg_region (RK_VAR_ARG): a region for the N-th vararg within a frame_region for a variadic call + errno_region (RK_ERRNO): a region for holding "errno" unknown_region (RK_UNKNOWN): for handling unimplemented tree codes. */ /* Abstract base class for representing ways of accessing chunks of memory. @@ -555,6 +561,32 @@ is_a_helper <const heap_region *>::test (const region *reg) namespace ana { +/* Concrete space_region subclass: thread-local data for the thread + being analyzed. */ + +class thread_local_region : public space_region +{ +public: + thread_local_region (unsigned id, region *parent) + : space_region (id, parent) + {} + + enum region_kind get_kind () const final override { return RK_THREAD_LOCAL; } + void dump_to_pp (pretty_printer *pp, bool simple) const final override; +}; + +} // namespace ana + +template <> +template <> +inline bool +is_a_helper <const thread_local_region *>::test (const region *reg) +{ + return reg->get_kind () == RK_THREAD_LOCAL; +} + +namespace ana { + /* Concrete region subclass. The root region, containing all regions (either directly, or as descendents). Unique within a region_model_manager. */ @@ -1362,6 +1394,32 @@ template <> struct default_hash_traits<var_arg_region::key_t> namespace ana { +/* A region for errno for the current thread. */ + +class errno_region : public region +{ +public: + errno_region (unsigned id, const thread_local_region *parent) + : region (complexity (parent), id, parent, integer_type_node) + {} + + enum region_kind get_kind () const final override { return RK_ERRNO; } + + void dump_to_pp (pretty_printer *pp, bool simple) const final override; +}; + +} // namespace ana + +template <> +template <> +inline bool +is_a_helper <const errno_region *>::test (const region *reg) +{ + return reg->get_kind () == RK_ERRNO; +} + +namespace ana { + /* An unknown region, for handling unimplemented tree codes. */ class unknown_region : public region diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc index c0f5ed1..636d4aa 100644 --- a/gcc/analyzer/store.cc +++ b/gcc/analyzer/store.cc @@ -2036,6 +2036,17 @@ binding_cluster::on_asm (const gasm *stmt, m_touched = true; } +/* Return true if this cluster has escaped. */ + +bool +binding_cluster::escaped_p () const +{ + /* Consider the "errno" region to always have escaped. */ + if (m_base_region->get_kind () == RK_ERRNO) + return true; + return m_escaped; +} + /* Return true if this binding_cluster has no information i.e. if there are no bindings, and it hasn't been marked as having escaped, or touched symbolically. */ @@ -2946,6 +2957,10 @@ store::escaped_p (const region *base_reg) const gcc_assert (base_reg); gcc_assert (base_reg->get_base_region () == base_reg); + /* "errno" can always be modified by external code. */ + if (base_reg->get_kind () == RK_ERRNO) + return true; + if (binding_cluster **cluster_slot = const_cast <cluster_map_t &>(m_cluster_map).get (base_reg)) return (*cluster_slot)->escaped_p (); @@ -3192,6 +3207,7 @@ store::replay_call_summary_cluster (call_summary_replay &r, case RK_CODE: case RK_STACK: case RK_HEAP: + case RK_THREAD_LOCAL: case RK_ROOT: /* Child regions. */ case RK_FIELD: @@ -3242,6 +3258,7 @@ store::replay_call_summary_cluster (call_summary_replay &r, case RK_HEAP_ALLOCATED: case RK_DECL: + case RK_ERRNO: { const region *caller_dest_reg = r.convert_region_from_summary (summary_base_reg); diff --git a/gcc/analyzer/store.h b/gcc/analyzer/store.h index 1087782..6243ec6 100644 --- a/gcc/analyzer/store.h +++ b/gcc/analyzer/store.h @@ -644,7 +644,7 @@ public: void on_asm (const gasm *stmt, store_manager *mgr, const conjured_purge &p); - bool escaped_p () const { return m_escaped; } + bool escaped_p () const; bool touched_p () const { return m_touched; } bool redundant_p () const; |