aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimple-fold.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/gimple-fold.c')
-rw-r--r--gcc/gimple-fold.c75
1 files changed, 61 insertions, 14 deletions
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 36a85c7..e873320 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -1280,12 +1280,13 @@ gimple_fold_builtin_memset (gimple_stmt_iterator *gsi, tree c, tree len)
obtained from the upper bound of an array at the end of a struct.
Such an array may hold a string that's longer than its upper bound
due to it being used as a poor-man's flexible array member.
+ Pass NONSTR through to children.
ELTSIZE is 1 for normal single byte character strings, and 2 or
4 for wide characer strings. ELTSIZE is by default 1. */
static bool
get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
- int fuzzy, bool *flexp, unsigned eltsize = 1)
+ int fuzzy, bool *flexp, unsigned eltsize, tree *nonstr)
{
tree var, val = NULL_TREE;
gimple *def_stmt;
@@ -1307,7 +1308,8 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
if (TREE_CODE (aop0) == INDIRECT_REF
&& TREE_CODE (TREE_OPERAND (aop0, 0)) == SSA_NAME)
return get_range_strlen (TREE_OPERAND (aop0, 0), length,
- visited, type, fuzzy, flexp, eltsize);
+ visited, type, fuzzy, flexp,
+ eltsize, nonstr);
}
else if (TREE_CODE (TREE_OPERAND (op, 0)) == COMPONENT_REF && fuzzy)
{
@@ -1335,13 +1337,14 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
return false;
}
else
- val = c_strlen (arg, 1, NULL, eltsize);
+ val = c_strlen (arg, 1, nonstr, eltsize);
if (!val && fuzzy)
{
if (TREE_CODE (arg) == ADDR_EXPR)
return get_range_strlen (TREE_OPERAND (arg, 0), length,
- visited, type, fuzzy, flexp, eltsize);
+ visited, type, fuzzy, flexp,
+ eltsize, nonstr);
if (TREE_CODE (arg) == ARRAY_REF)
{
@@ -1484,7 +1487,7 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
{
tree rhs = gimple_assign_rhs1 (def_stmt);
return get_range_strlen (rhs, length, visited, type, fuzzy, flexp,
- eltsize);
+ eltsize, nonstr);
}
else if (gimple_assign_rhs_code (def_stmt) == COND_EXPR)
{
@@ -1493,7 +1496,7 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
for (unsigned int i = 0; i < 2; i++)
if (!get_range_strlen (ops[i], length, visited, type, fuzzy,
- flexp, eltsize))
+ flexp, eltsize, nonstr))
{
if (fuzzy == 2)
*maxlen = build_all_ones_cst (size_type_node);
@@ -1521,7 +1524,7 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
continue;
if (!get_range_strlen (arg, length, visited, type, fuzzy, flexp,
- eltsize))
+ eltsize, nonstr))
{
if (fuzzy == 2)
*maxlen = build_all_ones_cst (size_type_node);
@@ -1554,21 +1557,30 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
if we can determine string length minimum and maximum; it will use
the minimum from the ones where it can be determined.
STRICT false should be only used for warning code.
+ When non-null, clear *NONSTR if ARG refers to a constant array
+ that is known not be nul-terminated. Otherwise set it to
+ the declaration of the constant non-terminated array.
ELTSIZE is 1 for normal single byte character strings, and 2 or
4 for wide characer strings. ELTSIZE is by default 1. */
bool
-get_range_strlen (tree arg, tree minmaxlen[2], unsigned eltsize, bool strict)
+get_range_strlen (tree arg, tree minmaxlen[2], unsigned eltsize,
+ bool strict, tree *nonstr /* = NULL */)
{
bitmap visited = NULL;
minmaxlen[0] = NULL_TREE;
minmaxlen[1] = NULL_TREE;
+ tree nonstrbuf;
+ if (!nonstr)
+ nonstr = &nonstrbuf;
+ *nonstr = NULL_TREE;
+
bool flexarray = false;
if (!get_range_strlen (arg, minmaxlen, &visited, 1, strict ? 1 : 2,
- &flexarray, eltsize))
+ &flexarray, eltsize, nonstr))
{
minmaxlen[0] = NULL_TREE;
minmaxlen[1] = NULL_TREE;
@@ -1580,19 +1592,39 @@ get_range_strlen (tree arg, tree minmaxlen[2], unsigned eltsize, bool strict)
return flexarray;
}
+/* Return the maximum string length for ARG, counting by TYPE
+ (1, 2 or 4 for normal or wide chars). NONSTR indicates
+ if the caller is prepared to handle unterminated strings.
+
+ If an unterminated string is discovered and our caller handles
+ unterminated strings, then bubble up the offending DECL and
+ return the maximum size. Otherwise return NULL. */
+
tree
-get_maxval_strlen (tree arg, int type)
+get_maxval_strlen (tree arg, int type, tree *nonstr /* = NULL */)
{
bitmap visited = NULL;
tree len[2] = { NULL_TREE, NULL_TREE };
bool dummy;
- if (!get_range_strlen (arg, len, &visited, type, 0, &dummy))
+ /* Set to non-null if ARG refers to an untermianted array. */
+ tree mynonstr = NULL_TREE;
+ if (!get_range_strlen (arg, len, &visited, type, 0, &dummy, 1, &mynonstr))
len[1] = NULL_TREE;
if (visited)
BITMAP_FREE (visited);
- return len[1];
+ if (nonstr)
+ {
+ /* For callers prepared to handle unterminated arrays set
+ *NONSTR to point to the declaration of the array and return
+ the maximum length/size. */
+ *nonstr = mynonstr;
+ return len[1];
+ }
+
+ /* Fail if the constant array isn't nul-terminated. */
+ return mynonstr ? NULL_TREE : len[1];
}
@@ -1635,7 +1667,19 @@ gimple_fold_builtin_strcpy (gimple_stmt_iterator *gsi,
if (!fn)
return false;
- tree len = get_maxval_strlen (src, 0);
+ /* Set to non-null if ARG refers to an unterminated array. */
+ tree nonstr = NULL;
+ tree len = get_maxval_strlen (src, 0, &nonstr);
+
+ if (nonstr)
+ {
+ /* Avoid folding calls with unterminated arrays. */
+ if (!gimple_no_warning_p (stmt))
+ warn_string_no_nul (loc, "strcpy", src, nonstr);
+ gimple_set_no_warning (stmt, true);
+ return false;
+ }
+
if (!len)
return false;
@@ -3506,12 +3550,15 @@ static bool
gimple_fold_builtin_strlen (gimple_stmt_iterator *gsi)
{
gimple *stmt = gsi_stmt (*gsi);
+ tree arg = gimple_call_arg (stmt, 0);
wide_int minlen;
wide_int maxlen;
+ /* Set to non-null if ARG refers to an unterminated array. */
+ tree nonstr;
tree lenrange[2];
- if (!get_range_strlen (gimple_call_arg (stmt, 0), lenrange, 1, true)
+ if (!get_range_strlen (arg, lenrange, 1, true, &nonstr)
&& lenrange[0] && TREE_CODE (lenrange[0]) == INTEGER_CST
&& lenrange[1] && TREE_CODE (lenrange[1]) == INTEGER_CST)
{