PR tree-optimization/79352 - -fprintf-return-value doesn't handle flexible-like array members properly
gcc/ChangeLog: PR tree-optimization/79352 * gimple-fold.c (get_range_strlen): Add argument. (get_range_strlen): Change return type to bool. (get_maxval_strlen): Pass in a dummy argument. * gimple-fold.h (get_range_strlen): Change return type to bool. * gimple-ssa-sprintf.c (get_string_length): Set unlikely counter. * tree.h (array_at_struct_end_p): Add argument. * tree.c (array_at_struct_end_p): Handle it. gcc/testsuite/ChangeLog: PR tree-optimization/79352 * gcc.dg/tree-ssa/pr79352.c: New test. From-SVN: r245156
This commit is contained in:
parent
46a2ab580a
commit
3f3430400b
8 changed files with 109 additions and 21 deletions
|
@ -1,3 +1,14 @@
|
|||
2017-02-03 Martin Sebor <msebor@redhat.com>
|
||||
|
||||
PR tree-optimization/79352
|
||||
* gimple-fold.c (get_range_strlen): Add argument.
|
||||
(get_range_strlen): Change return type to bool.
|
||||
(get_maxval_strlen): Pass in a dummy argument.
|
||||
* gimple-fold.h (get_range_strlen): Change return type to bool.
|
||||
* gimple-ssa-sprintf.c (get_string_length): Set unlikely counter.
|
||||
* tree.h (array_at_struct_end_p): Add argument.
|
||||
* tree.c (array_at_struct_end_p): Handle it.
|
||||
|
||||
2017-02-03 Martin Liska <mliska@suse.cz>
|
||||
|
||||
PR lto/66295
|
||||
|
|
|
@ -1177,11 +1177,15 @@ gimple_fold_builtin_memset (gimple_stmt_iterator *gsi, tree c, tree len)
|
|||
length and 2 for maximum value ARG can have.
|
||||
When FUZZY is set and the length of a string cannot be determined,
|
||||
the function instead considers as the maximum possible length the
|
||||
size of a character array it may refer to. */
|
||||
size of a character array it may refer to.
|
||||
Set *FLEXP to true if the range of the string lengths has been
|
||||
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. */
|
||||
|
||||
static bool
|
||||
get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
|
||||
bool fuzzy)
|
||||
bool fuzzy, bool *flexp)
|
||||
{
|
||||
tree var, val;
|
||||
gimple *def_stmt;
|
||||
|
@ -1202,7 +1206,7 @@ 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);
|
||||
length, visited, type, fuzzy, flexp);
|
||||
}
|
||||
|
||||
if (type == 2)
|
||||
|
@ -1219,7 +1223,7 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
|
|||
{
|
||||
if (TREE_CODE (arg) == ADDR_EXPR)
|
||||
return get_range_strlen (TREE_OPERAND (arg, 0), length,
|
||||
visited, type, fuzzy);
|
||||
visited, type, fuzzy, flexp);
|
||||
|
||||
if (TREE_CODE (arg) == COMPONENT_REF
|
||||
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (arg, 1))) == ARRAY_TYPE)
|
||||
|
@ -1228,7 +1232,12 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
|
|||
bound on the length of the array. This may be overly
|
||||
optimistic if the array itself isn't NUL-terminated and
|
||||
the caller relies on the subsequent member to contain
|
||||
the NUL. */
|
||||
the NUL.
|
||||
Set *FLEXP to true if the array whose bound is being
|
||||
used is at the end of a struct. */
|
||||
if (array_at_struct_end_p (arg, true))
|
||||
*flexp = true;
|
||||
|
||||
arg = TREE_OPERAND (arg, 1);
|
||||
val = TYPE_SIZE_UNIT (TREE_TYPE (arg));
|
||||
if (!val || integer_zerop (val))
|
||||
|
@ -1295,14 +1304,14 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
|
|||
|| gimple_assign_unary_nop_p (def_stmt))
|
||||
{
|
||||
tree rhs = gimple_assign_rhs1 (def_stmt);
|
||||
return get_range_strlen (rhs, length, visited, type, fuzzy);
|
||||
return get_range_strlen (rhs, length, visited, type, fuzzy, flexp);
|
||||
}
|
||||
else if (gimple_assign_rhs_code (def_stmt) == COND_EXPR)
|
||||
{
|
||||
tree op2 = gimple_assign_rhs2 (def_stmt);
|
||||
tree op3 = gimple_assign_rhs3 (def_stmt);
|
||||
return get_range_strlen (op2, length, visited, type, fuzzy)
|
||||
&& get_range_strlen (op3, length, visited, type, fuzzy);
|
||||
return get_range_strlen (op2, length, visited, type, fuzzy, flexp)
|
||||
&& get_range_strlen (op3, length, visited, type, fuzzy, flexp);
|
||||
}
|
||||
return false;
|
||||
|
||||
|
@ -1325,7 +1334,7 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
|
|||
if (arg == gimple_phi_result (def_stmt))
|
||||
continue;
|
||||
|
||||
if (!get_range_strlen (arg, length, visited, type, fuzzy))
|
||||
if (!get_range_strlen (arg, length, visited, type, fuzzy, flexp))
|
||||
{
|
||||
if (fuzzy)
|
||||
*maxlen = build_all_ones_cst (size_type_node);
|
||||
|
@ -1349,19 +1358,26 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
|
|||
and array declared as 'char array[8]', MINMAXLEN[0] will be set
|
||||
to 3 and MINMAXLEN[1] to 7, the longest string that could be
|
||||
stored in array.
|
||||
*/
|
||||
Return true if the range of the string lengths has been 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. */
|
||||
|
||||
void get_range_strlen (tree arg, tree minmaxlen[2])
|
||||
bool
|
||||
get_range_strlen (tree arg, tree minmaxlen[2])
|
||||
{
|
||||
bitmap visited = NULL;
|
||||
|
||||
minmaxlen[0] = NULL_TREE;
|
||||
minmaxlen[1] = NULL_TREE;
|
||||
|
||||
get_range_strlen (arg, minmaxlen, &visited, 1, true);
|
||||
bool flexarray = false;
|
||||
get_range_strlen (arg, minmaxlen, &visited, 1, true, &flexarray);
|
||||
|
||||
if (visited)
|
||||
BITMAP_FREE (visited);
|
||||
|
||||
return flexarray;
|
||||
}
|
||||
|
||||
tree
|
||||
|
@ -1369,7 +1385,9 @@ get_maxval_strlen (tree arg, int type)
|
|||
{
|
||||
bitmap visited = NULL;
|
||||
tree len[2] = { NULL_TREE, NULL_TREE };
|
||||
if (!get_range_strlen (arg, len, &visited, type, false))
|
||||
|
||||
bool dummy;
|
||||
if (!get_range_strlen (arg, len, &visited, type, false, &dummy))
|
||||
len[1] = NULL_TREE;
|
||||
if (visited)
|
||||
BITMAP_FREE (visited);
|
||||
|
|
|
@ -24,7 +24,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
|
||||
extern tree canonicalize_constructor_val (tree, tree);
|
||||
extern tree get_symbol_constant_value (tree);
|
||||
extern void get_range_strlen (tree, tree[2]);
|
||||
extern bool get_range_strlen (tree, tree[2]);
|
||||
extern tree get_maxval_strlen (tree, int);
|
||||
extern void gimplify_and_update_call_from_tree (gimple_stmt_iterator *, tree);
|
||||
extern bool fold_stmt (gimple_stmt_iterator *);
|
||||
|
|
|
@ -1800,7 +1800,7 @@ get_string_length (tree str)
|
|||
aren't known to point any such arrays result in LENRANGE[1] set
|
||||
to SIZE_MAX. */
|
||||
tree lenrange[2];
|
||||
get_range_strlen (str, lenrange);
|
||||
bool flexarray = get_range_strlen (str, lenrange);
|
||||
|
||||
if (lenrange [0] || lenrange [1])
|
||||
{
|
||||
|
@ -1843,7 +1843,11 @@ get_string_length (tree str)
|
|||
res.range.min = 0;
|
||||
}
|
||||
|
||||
res.range.unlikely = res.range.max;
|
||||
/* If the range of string length has been estimated from the size
|
||||
of an array at the end of a struct assume that it's longer than
|
||||
the array bound says it is in case it's used as a poor man's
|
||||
flexible array member, such as in struct S { char a[4]; }; */
|
||||
res.range.unlikely = flexarray ? HOST_WIDE_INT_MAX : res.range.max;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
2017-02-03 Martin Sebor <msebor@redhat.com>
|
||||
|
||||
PR tree-optimization/79352
|
||||
* gcc.dg/tree-ssa/pr79352.c: New test.
|
||||
|
||||
2017-02-03 Martin Liska <mliska@suse.cz>
|
||||
|
||||
PR lto/66295
|
||||
|
|
45
gcc/testsuite/gcc.dg/tree-ssa/pr79352.c
Normal file
45
gcc/testsuite/gcc.dg/tree-ssa/pr79352.c
Normal file
|
@ -0,0 +1,45 @@
|
|||
/* PR tree-optimization/79352 - -fprintf-return-value doesn't handle
|
||||
flexible-like array members properly
|
||||
{ dg-compile }
|
||||
{ dg-options "-O2 -fdump-tree-optimized" } */
|
||||
|
||||
struct A { int i; char a1[1]; };
|
||||
struct B { int i; char a3[3]; };
|
||||
struct C { int i; char ax[]; };
|
||||
|
||||
int test_array_1 (int i, struct A *a)
|
||||
{
|
||||
return __builtin_snprintf (0, 0, "%-s", a->a1);
|
||||
}
|
||||
|
||||
int test_array_3 (int i, struct B *b)
|
||||
{
|
||||
return __builtin_snprintf (0, 0, "%-s", b->a3);
|
||||
}
|
||||
|
||||
int test_array_1_3 (int i, struct A *a, struct B *b)
|
||||
{
|
||||
return __builtin_snprintf (0, 0, "%-s", i ? a->a1 : b->a3);
|
||||
}
|
||||
|
||||
int test_string_and_array_3 (int i, struct B *b)
|
||||
{
|
||||
return __builtin_snprintf (0, 0, "%-s", i ? "123" : b->a3);
|
||||
}
|
||||
|
||||
int test_flexarray (struct C *c)
|
||||
{
|
||||
return __builtin_snprintf (0, 0, "%-s", c->ax);
|
||||
}
|
||||
|
||||
int test_array_and_flexarray (int i, struct B *b, struct C *c)
|
||||
{
|
||||
return __builtin_snprintf (0, 0, "%-s", i ? b->a3 : c->ax);
|
||||
}
|
||||
|
||||
int test_string_and_flexarray (int i, struct C *c)
|
||||
{
|
||||
return __builtin_snprintf (0, 0, "%-s", i ? "123" : c->ax);
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "snprintf" 7 "optimized"} } */
|
|
@ -13195,13 +13195,16 @@ array_ref_up_bound (tree exp)
|
|||
|
||||
/* Returns true if REF is an array reference to an array at the end of
|
||||
a structure. If this is the case, the array may be allocated larger
|
||||
than its upper bound implies. */
|
||||
than its upper bound implies. When ALLOW_COMPREF is true considers
|
||||
REF when it's a COMPONENT_REF in addition ARRAY_REF and
|
||||
ARRAY_RANGE_REF. */
|
||||
|
||||
bool
|
||||
array_at_struct_end_p (tree ref)
|
||||
array_at_struct_end_p (tree ref, bool allow_compref)
|
||||
{
|
||||
if (TREE_CODE (ref) != ARRAY_REF
|
||||
&& TREE_CODE (ref) != ARRAY_RANGE_REF)
|
||||
&& TREE_CODE (ref) != ARRAY_RANGE_REF
|
||||
&& (!allow_compref || TREE_CODE (ref) != COMPONENT_REF))
|
||||
return false;
|
||||
|
||||
while (handled_component_p (ref))
|
||||
|
|
|
@ -4855,8 +4855,10 @@ extern tree array_ref_low_bound (tree);
|
|||
|
||||
/* Returns true if REF is an array reference to an array at the end of
|
||||
a structure. If this is the case, the array may be allocated larger
|
||||
than its upper bound implies. */
|
||||
extern bool array_at_struct_end_p (tree);
|
||||
than its upper bound implies. When second argument is true considers
|
||||
REF when it's a COMPONENT_REF in addition ARRAY_REF and
|
||||
ARRAY_RANGE_REF. */
|
||||
extern bool array_at_struct_end_p (tree, bool = false);
|
||||
|
||||
/* Return a tree representing the offset, in bytes, of the field referenced
|
||||
by EXP. This does not include any offset in DECL_FIELD_BIT_OFFSET. */
|
||||
|
|
Loading…
Add table
Reference in a new issue