aboutsummaryrefslogtreecommitdiff
path: root/gcc/analyzer
diff options
context:
space:
mode:
authorMartin Liska <mliska@suse.cz>2022-11-08 12:36:43 +0100
committerMartin Liska <mliska@suse.cz>2022-11-08 12:36:43 +0100
commit4b13c73bba935443be3207abf26f7ba05f79badc (patch)
treea6bb1525d07859fa8fc6f61dd13df7ddfd1ac254 /gcc/analyzer
parent33f5dde0cd15df9cf89b29280d4ff5fcf7b30e66 (diff)
parentfa271afb58423014e2feef9f15c1a87428e64ddc (diff)
downloadgcc-devel/sphinx.zip
gcc-devel/sphinx.tar.gz
gcc-devel/sphinx.tar.bz2
Merge branch 'master' into devel/sphinxdevel/sphinx
Diffstat (limited to 'gcc/analyzer')
-rw-r--r--gcc/analyzer/call-info.cc21
-rw-r--r--gcc/analyzer/call-info.h34
-rw-r--r--gcc/analyzer/region-model-impl-calls.cc28
-rw-r--r--gcc/analyzer/region-model-manager.cc2
-rw-r--r--gcc/analyzer/region-model-manager.h4
-rw-r--r--gcc/analyzer/region-model.cc36
-rw-r--r--gcc/analyzer/region-model.h3
-rw-r--r--gcc/analyzer/region.cc22
-rw-r--r--gcc/analyzer/region.h60
-rw-r--r--gcc/analyzer/store.cc17
-rw-r--r--gcc/analyzer/store.h2
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;