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:
Martin Sebor 2017-02-03 16:38:15 +00:00 committed by Martin Sebor
parent 46a2ab580a
commit 3f3430400b
8 changed files with 109 additions and 21 deletions

View file

@ -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

View file

@ -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);

View file

@ -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 *);

View file

@ -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;
}

View file

@ -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

View 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"} } */

View file

@ -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))

View file

@ -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. */