Avoid assuming maximum string length is constant [PR102960].

Resolves:
PR tree-optimization/102960 - ICE: in sign_mask, at wide-int.h:855 in GCC 10.3.0

gcc/ChangeLog:

	PR tree-optimization/102960
	* gimple-fold.c (get_range_strlen): Take bitmap as an argument rather
	than a pointer to it.
	(get_range_strlen_tree): Same.  Remove bitmap allocation.  Use
	an auto_bitmap.
	(get_maxval_strlen): Use an auto_bitmap.
	* tree-ssa-strlen.c (get_range_strlen_dynamic): Factor out PHI
	handling...
	(get_range_strlen_phi): ...into this function.
	Avoid assuming maximum string length is constant
	(printf_strlen_execute): Dump pointer query cache contents when
	details are requisted.

gcc/testsuite/ChangeLog:

	PR tree-optimization/102960
	* gcc.dg/Wstringop-overflow-84.c: New test.
This commit is contained in:
Martin Sebor 2021-11-16 09:18:25 -07:00
parent 0002a8a199
commit ba6e17e78d
3 changed files with 102 additions and 89 deletions

View File

@ -86,7 +86,7 @@ enum strlen_range_kind {
};
static bool
get_range_strlen (tree, bitmap *, strlen_range_kind, c_strlen_data *, unsigned);
get_range_strlen (tree, bitmap, strlen_range_kind, c_strlen_data *, unsigned);
/* Return true when DECL can be referenced from current unit.
FROM_DECL (if non-null) specify constructor of variable DECL was taken from.
@ -1525,7 +1525,7 @@ gimple_fold_builtin_memset (gimple_stmt_iterator *gsi, tree c, tree len)
/* Helper of get_range_strlen for ARG that is not an SSA_NAME. */
static bool
get_range_strlen_tree (tree arg, bitmap *visited, strlen_range_kind rkind,
get_range_strlen_tree (tree arg, bitmap visited, strlen_range_kind rkind,
c_strlen_data *pdata, unsigned eltsize)
{
gcc_assert (TREE_CODE (arg) != SSA_NAME);
@ -1849,7 +1849,7 @@ get_range_strlen_tree (tree arg, bitmap *visited, strlen_range_kind rkind,
Return true if *PDATA was successfully populated and false otherwise. */
static bool
get_range_strlen (tree arg, bitmap *visited,
get_range_strlen (tree arg, bitmap visited,
strlen_range_kind rkind,
c_strlen_data *pdata, unsigned eltsize)
{
@ -1863,9 +1863,7 @@ get_range_strlen (tree arg, bitmap *visited,
return false;
/* If we were already here, break the infinite cycle. */
if (!*visited)
*visited = BITMAP_ALLOC (NULL);
if (!bitmap_set_bit (*visited, SSA_NAME_VERSION (arg)))
if (!bitmap_set_bit (visited, SSA_NAME_VERSION (arg)))
return true;
tree var = arg;
@ -1962,10 +1960,10 @@ get_range_strlen (tree arg, bitmap *visited,
bool
get_range_strlen (tree arg, c_strlen_data *pdata, unsigned eltsize)
{
bitmap visited = NULL;
auto_bitmap visited;
tree maxbound = pdata->maxbound;
if (!get_range_strlen (arg, &visited, SRK_LENRANGE, pdata, eltsize))
if (!get_range_strlen (arg, visited, SRK_LENRANGE, pdata, eltsize))
{
/* On failure extend the length range to an impossible maximum
(a valid MAXLEN must be less than PTRDIFF_MAX - 1). Other
@ -1981,9 +1979,6 @@ get_range_strlen (tree arg, c_strlen_data *pdata, unsigned eltsize)
if (maxbound && pdata->maxbound == maxbound)
pdata->maxbound = build_all_ones_cst (size_type_node);
if (visited)
BITMAP_FREE (visited);
return !integer_all_onesp (pdata->maxlen);
}
@ -2005,19 +2000,16 @@ get_maxval_strlen (tree arg, strlen_range_kind rkind, tree *nonstr = NULL)
/* ARG must have an integral type when RKIND says so. */
gcc_assert (rkind != SRK_INT_VALUE || INTEGRAL_TYPE_P (TREE_TYPE (arg)));
bitmap visited = NULL;
auto_bitmap visited;
/* Reset DATA.MAXLEN if the call fails or when DATA.MAXLEN
is unbounded. */
c_strlen_data lendata = { };
if (!get_range_strlen (arg, &visited, rkind, &lendata, /* eltsize = */1))
if (!get_range_strlen (arg, visited, rkind, &lendata, /* eltsize = */1))
lendata.maxlen = NULL_TREE;
else if (lendata.maxlen && integer_all_onesp (lendata.maxlen))
lendata.maxlen = NULL_TREE;
if (visited)
BITMAP_FREE (visited);
if (nonstr)
{
/* For callers prepared to handle unterminated arrays set

View File

@ -0,0 +1,15 @@
/* PR middle-end/102960 - ICE: in sign_mask, at wide-int.h:855 in GCC 10.3.0
{ dg-do compile }
{ dg-options "-Og -Wall" } */
void f (int i)
{
const char *s;
if (i)
s = &"abcd"[i];
__builtin_printf ("%s", s);
}
/* The use of s in the call to sprintf should result in:
{ dg-prune-output "-Wmaybe-uninitialized" } */

View File

@ -193,6 +193,8 @@ struct laststmt_struct
} laststmt;
static int get_stridx_plus_constant (strinfo *, unsigned HOST_WIDE_INT, tree);
static bool get_range_strlen_dynamic (tree, gimple *s, c_strlen_data *,
bitmap, range_query *, unsigned *);
/* Sets MINMAX to either the constant value or the range VAL is in
and returns either the constant value or VAL on success or null
@ -1087,6 +1089,76 @@ dump_strlen_info (FILE *fp, gimple *stmt, range_query *rvals)
}
}
/* Helper of get_range_strlen_dynamic(). See below. */
static bool
get_range_strlen_phi (tree src, gphi *phi,
c_strlen_data *pdata, bitmap visited,
range_query *rvals, unsigned *pssa_def_max)
{
if (!bitmap_set_bit (visited, SSA_NAME_VERSION (src)))
return true;
if (*pssa_def_max == 0)
return false;
--*pssa_def_max;
/* Iterate over the PHI arguments and determine the minimum and maximum
length/size of each and incorporate them into the overall result. */
for (unsigned i = 0; i != gimple_phi_num_args (phi); ++i)
{
tree arg = gimple_phi_arg_def (phi, i);
if (arg == gimple_phi_result (phi))
continue;
c_strlen_data argdata = { };
if (!get_range_strlen_dynamic (arg, phi, &argdata, visited, rvals,
pssa_def_max))
{
pdata->maxlen = build_all_ones_cst (size_type_node);
continue;
}
/* Set the DECL of an unterminated array this argument refers to
if one hasn't been found yet. */
if (!pdata->decl && argdata.decl)
pdata->decl = argdata.decl;
if (!argdata.minlen
|| (integer_zerop (argdata.minlen)
&& (!argdata.maxbound
|| integer_all_onesp (argdata.maxbound))
&& integer_all_onesp (argdata.maxlen)))
{
/* Set the upper bound of the length to unbounded. */
pdata->maxlen = build_all_ones_cst (size_type_node);
continue;
}
/* Adjust the minimum and maximum length determined so far and
the upper bound on the array size. */
if (!pdata->minlen
|| tree_int_cst_lt (argdata.minlen, pdata->minlen))
pdata->minlen = argdata.minlen;
if (!pdata->maxlen
|| (argdata.maxlen
&& TREE_CODE (argdata.maxlen) == INTEGER_CST
&& tree_int_cst_lt (pdata->maxlen, argdata.maxlen)))
pdata->maxlen = argdata.maxlen;
if (!pdata->maxbound
|| TREE_CODE (pdata->maxbound) != INTEGER_CST
|| (argdata.maxbound
&& tree_int_cst_lt (pdata->maxbound, argdata.maxbound)
&& !integer_all_onesp (argdata.maxbound)))
pdata->maxbound = argdata.maxbound;
}
return true;
}
/* Attempt to determine the length of the string SRC. On success, store
the length in *PDATA and return true. Otherwise, return false.
VISITED is a bitmap of visited PHI nodes. RVALS points to the valuation
@ -1095,7 +1167,7 @@ dump_strlen_info (FILE *fp, gimple *stmt, range_query *rvals)
static bool
get_range_strlen_dynamic (tree src, gimple *stmt,
c_strlen_data *pdata, bitmap *visited,
c_strlen_data *pdata, bitmap visited,
range_query *rvals, unsigned *pssa_def_max)
{
int idx = get_stridx (src, stmt);
@ -1104,72 +1176,9 @@ get_range_strlen_dynamic (tree src, gimple *stmt,
if (TREE_CODE (src) == SSA_NAME)
{
gimple *def_stmt = SSA_NAME_DEF_STMT (src);
if (gimple_code (def_stmt) == GIMPLE_PHI)
{
if (!*visited)
*visited = BITMAP_ALLOC (NULL);
if (!bitmap_set_bit (*visited, SSA_NAME_VERSION (src)))
return true;
if (*pssa_def_max == 0)
return false;
--*pssa_def_max;
/* Iterate over the PHI arguments and determine the minimum
and maximum length/size of each and incorporate them into
the overall result. */
gphi *phi = as_a <gphi *> (def_stmt);
for (unsigned i = 0; i != gimple_phi_num_args (phi); ++i)
{
tree arg = gimple_phi_arg_def (phi, i);
if (arg == gimple_phi_result (def_stmt))
continue;
c_strlen_data argdata = { };
if (get_range_strlen_dynamic (arg, phi, &argdata, visited,
rvals, pssa_def_max))
{
/* Set the DECL of an unterminated array this argument
refers to if one hasn't been found yet. */
if (!pdata->decl && argdata.decl)
pdata->decl = argdata.decl;
if (!argdata.minlen
|| (integer_zerop (argdata.minlen)
&& (!argdata.maxbound
|| integer_all_onesp (argdata.maxbound))
&& integer_all_onesp (argdata.maxlen)))
{
/* Set the upper bound of the length to unbounded. */
pdata->maxlen = build_all_ones_cst (size_type_node);
continue;
}
/* Adjust the minimum and maximum length determined
so far and the upper bound on the array size. */
if (!pdata->minlen
|| tree_int_cst_lt (argdata.minlen, pdata->minlen))
pdata->minlen = argdata.minlen;
if (!pdata->maxlen
|| (argdata.maxlen
&& tree_int_cst_lt (pdata->maxlen, argdata.maxlen)))
pdata->maxlen = argdata.maxlen;
if (!pdata->maxbound
|| TREE_CODE (pdata->maxbound) != INTEGER_CST
|| (argdata.maxbound
&& tree_int_cst_lt (pdata->maxbound,
argdata.maxbound)
&& !integer_all_onesp (argdata.maxbound)))
pdata->maxbound = argdata.maxbound;
}
else
pdata->maxlen = build_all_ones_cst (size_type_node);
}
return true;
}
if (gphi *phi = dyn_cast<gphi *>(def_stmt))
return get_range_strlen_phi (src, phi, pdata, visited, rvals,
pssa_def_max);
}
/* Return success regardless of the result and handle *PDATA
@ -1286,11 +1295,11 @@ void
get_range_strlen_dynamic (tree src, gimple *stmt, c_strlen_data *pdata,
range_query *rvals)
{
bitmap visited = NULL;
auto_bitmap visited;
tree maxbound = pdata->maxbound;
unsigned limit = param_ssa_name_def_chain_limit;
if (!get_range_strlen_dynamic (src, stmt, pdata, &visited, rvals, &limit))
if (!get_range_strlen_dynamic (src, stmt, pdata, visited, rvals, &limit))
{
/* On failure extend the length range to an impossible maximum
(a valid MAXLEN must be less than PTRDIFF_MAX - 1). Other
@ -1305,9 +1314,6 @@ get_range_strlen_dynamic (tree src, gimple *stmt, c_strlen_data *pdata,
MAXBOUND to SIZE_MAX. Otherwise leave it null (if it is null). */
if (maxbound && pdata->maxbound == maxbound)
pdata->maxbound = build_all_ones_cst (size_type_node);
if (visited)
BITMAP_FREE (visited);
}
/* Invalidate string length information for strings whose length might
@ -5831,7 +5837,7 @@ printf_strlen_execute (function *fun, bool warn_only)
walker.walk (ENTRY_BLOCK_PTR_FOR_FN (fun));
if (dump_file && (dump_flags & TDF_DETAILS))
walker.ptr_qry.dump (dump_file);
walker.ptr_qry.dump (dump_file, true);
ssa_ver_to_stridx.release ();
strinfo_pool.release ();