builtins.h (c_strlen_data): Add new fields and comments.
* 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. Co-Authored-By: Jeff Law <law@redhat.com> From-SVN: r267378
This commit is contained in:
parent
e09aa5bd6d
commit
b71bbbe2b2
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user