@@ -1,6 +1,12 @@
2018-12-23 Martin Sebor <msebor@redhat.com>
Jeff Law <law@redhat.com>
+ * builtins.h (c_strlen_data): Add new fields and comments.
+ * builtins.c (unterminated_array): Change field reference from
+ "len" to "minlen" in c_strlen_data instance.
+ * gimple-fold.c (get_range_strlen): Likewise.
+ * gimple-ssa-sprintf.c (get_string_length): Likewise.
+
* builtins.c (unterminated_array): Rename "data" to "lendata". Fix
a few comments.
(expand_builtin_strnlen, expand_builtin_stpcpy_1): Likewise.
@@ -577,11 +577,11 @@ unterminated_array (tree exp, tree *size /* = NULL */, bool *exact /* = NULL */)
structure if EXP references a unterminated array. */
c_strlen_data lendata = { };
tree len = c_strlen (exp, 1, &lendata);
- if (len == NULL_TREE && lendata.len && lendata.decl)
+ if (len == NULL_TREE && lendata.minlen && lendata.decl)
{
if (size)
{
- len = lendata.len;
+ len = lendata.minlen;
if (lendata.off)
{
/* Constant offsets are already accounted for in LENDATA.MINLEN,
@@ -720,7 +720,7 @@ c_strlen (tree src, int only_value, c_strlen_data *data, unsigned eltsize)
{
data->decl = decl;
data->off = byteoff;
- data->len = ssize_int (len);
+ data->minlen = ssize_int (len);
return NULL_TREE;
}
@@ -794,7 +794,7 @@ c_strlen (tree src, int only_value, c_strlen_data *data, unsigned eltsize)
{
data->decl = decl;
data->off = byteoff;
- data->len = ssize_int (len);
+ data->minlen = ssize_int (len);
return NULL_TREE;
}
@@ -57,10 +57,48 @@ extern bool get_pointer_alignment_1 (tree, unsigned int *,
unsigned HOST_WIDE_INT *);
extern unsigned int get_pointer_alignment (tree);
extern unsigned string_length (const void*, unsigned, unsigned);
+
struct c_strlen_data
{
+ /* [MINLEN, MAXBOUND, MAXLEN] is a range describing the length of
+ one or more strings of possibly unknown length. For a single
+ string of known length the range is a constant where
+ MINLEN == MAXBOUND == MAXLEN holds.
+ For other strings, MINLEN is the length of the shortest known
+ string. MAXBOUND is the length of a string that could be stored
+ in the largest array referenced by the expression. MAXLEN is
+ the length of the longest sequence of non-zero bytes
+ in an object referenced by the expression. For such strings,
+ MINLEN <= MAXBOUND <= MAXLEN holds. For example, given:
+ struct A { char a[7], b[]; };
+ extern struct A *p;
+ n = strlen (p->a);
+ the computed range will be [0, 6, ALL_ONES].
+ However, for a conditional expression involving a string
+ of known length and an array of unknown bound such as
+ n = strlen (i ? p->b : "123");
+ the range will be [3, 3, ALL_ONES].
+ MINLEN != 0 && MAXLEN == ALL_ONES indicates that MINLEN is
+ the length of the shortest known string and implies that
+ the shortest possible string referenced by the expression may
+ actually be the empty string. This distinction is useful for
+ diagnostics. get_range_strlen() return value distinguishes
+ between these two cases.
+ As the tighter (and more optimistic) bound, MAXBOUND is suitable
+ for diagnostics but not for optimization.
+ As the more conservative bound, MAXLEN is intended to be used
+ for optimization. */
+ tree minlen;
+ tree maxlen;
+ tree maxbound;
+ /* When non-null, NONSTR refers to the declaration known to store
+ an unterminated constant character array, as in:
+ const char s[] = { 'a', 'b', 'c' };
+ It is used to diagnose uses of such arrays in functions such as
+ strlen() that expect a nul-terminated string as an argument. */
tree decl;
- tree len;
+ /* Non-constant offset from the beginning of a string not accounted
+ for in the length range. Used to improve diagnostics. */
tree off;
};
@@ -1343,8 +1343,8 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
if (!val && lendata.decl)
{
*nonstr = lendata.decl;
- *minlen = lendata.len;
- *maxlen = lendata.len;
+ *minlen = lendata.minlen;
+ *maxlen = lendata.minlen;
return type == 0 ? false : true;
}
}
@@ -2015,12 +2015,12 @@ get_string_length (tree str, unsigned eltsize)
}
else if (!slen
&& data.decl
- && data.len
- && TREE_CODE (data.len) == INTEGER_CST)
+ && data.minlen
+ && TREE_CODE (data.minlen) == INTEGER_CST)
{
/* STR was not properly NUL terminated, but we have
length information about the unterminated string. */
- fmtresult res (tree_to_shwi (data.len));
+ fmtresult res (tree_to_shwi (data.minlen));
res.nonstr = data.decl;
return res;
}