Commit 3f343040 by Martin Sebor Committed by Martin Sebor

PR tree-optimization/79352 - -fprintf-return-value doesn't handle flexible-like…

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
parent 46a2ab58
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> 2017-02-03 Martin Liska <mliska@suse.cz>
PR lto/66295 PR lto/66295
......
...@@ -1177,11 +1177,15 @@ gimple_fold_builtin_memset (gimple_stmt_iterator *gsi, tree c, tree len) ...@@ -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. length and 2 for maximum value ARG can have.
When FUZZY is set and the length of a string cannot be determined, When FUZZY is set and the length of a string cannot be determined,
the function instead considers as the maximum possible length the 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 static bool
get_range_strlen (tree arg, tree length[2], bitmap *visited, int type, get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
bool fuzzy) bool fuzzy, bool *flexp)
{ {
tree var, val; tree var, val;
gimple *def_stmt; gimple *def_stmt;
...@@ -1202,7 +1206,7 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type, ...@@ -1202,7 +1206,7 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
if (TREE_CODE (aop0) == INDIRECT_REF if (TREE_CODE (aop0) == INDIRECT_REF
&& TREE_CODE (TREE_OPERAND (aop0, 0)) == SSA_NAME) && TREE_CODE (TREE_OPERAND (aop0, 0)) == SSA_NAME)
return get_range_strlen (TREE_OPERAND (aop0, 0), return get_range_strlen (TREE_OPERAND (aop0, 0),
length, visited, type, fuzzy); length, visited, type, fuzzy, flexp);
} }
if (type == 2) if (type == 2)
...@@ -1219,7 +1223,7 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type, ...@@ -1219,7 +1223,7 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
{ {
if (TREE_CODE (arg) == ADDR_EXPR) if (TREE_CODE (arg) == ADDR_EXPR)
return get_range_strlen (TREE_OPERAND (arg, 0), length, return get_range_strlen (TREE_OPERAND (arg, 0), length,
visited, type, fuzzy); visited, type, fuzzy, flexp);
if (TREE_CODE (arg) == COMPONENT_REF if (TREE_CODE (arg) == COMPONENT_REF
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (arg, 1))) == ARRAY_TYPE) && 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, ...@@ -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 bound on the length of the array. This may be overly
optimistic if the array itself isn't NUL-terminated and optimistic if the array itself isn't NUL-terminated and
the caller relies on the subsequent member to contain 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); arg = TREE_OPERAND (arg, 1);
val = TYPE_SIZE_UNIT (TREE_TYPE (arg)); val = TYPE_SIZE_UNIT (TREE_TYPE (arg));
if (!val || integer_zerop (val)) if (!val || integer_zerop (val))
...@@ -1295,14 +1304,14 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type, ...@@ -1295,14 +1304,14 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
|| gimple_assign_unary_nop_p (def_stmt)) || gimple_assign_unary_nop_p (def_stmt))
{ {
tree rhs = gimple_assign_rhs1 (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) else if (gimple_assign_rhs_code (def_stmt) == COND_EXPR)
{ {
tree op2 = gimple_assign_rhs2 (def_stmt); tree op2 = gimple_assign_rhs2 (def_stmt);
tree op3 = gimple_assign_rhs3 (def_stmt); tree op3 = gimple_assign_rhs3 (def_stmt);
return get_range_strlen (op2, length, visited, type, fuzzy) return get_range_strlen (op2, length, visited, type, fuzzy, flexp)
&& get_range_strlen (op3, length, visited, type, fuzzy); && get_range_strlen (op3, length, visited, type, fuzzy, flexp);
} }
return false; return false;
...@@ -1325,7 +1334,7 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type, ...@@ -1325,7 +1334,7 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
if (arg == gimple_phi_result (def_stmt)) if (arg == gimple_phi_result (def_stmt))
continue; continue;
if (!get_range_strlen (arg, length, visited, type, fuzzy)) if (!get_range_strlen (arg, length, visited, type, fuzzy, flexp))
{ {
if (fuzzy) if (fuzzy)
*maxlen = build_all_ones_cst (size_type_node); *maxlen = build_all_ones_cst (size_type_node);
...@@ -1349,19 +1358,26 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type, ...@@ -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 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 to 3 and MINMAXLEN[1] to 7, the longest string that could be
stored in array. 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; bitmap visited = NULL;
minmaxlen[0] = NULL_TREE; minmaxlen[0] = NULL_TREE;
minmaxlen[1] = 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) if (visited)
BITMAP_FREE (visited); BITMAP_FREE (visited);
return flexarray;
} }
tree tree
...@@ -1369,7 +1385,9 @@ get_maxval_strlen (tree arg, int type) ...@@ -1369,7 +1385,9 @@ get_maxval_strlen (tree arg, int type)
{ {
bitmap visited = NULL; bitmap visited = NULL;
tree len[2] = { NULL_TREE, NULL_TREE }; 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; len[1] = NULL_TREE;
if (visited) if (visited)
BITMAP_FREE (visited); BITMAP_FREE (visited);
......
...@@ -24,7 +24,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -24,7 +24,7 @@ along with GCC; see the file COPYING3. If not see
extern tree canonicalize_constructor_val (tree, tree); extern tree canonicalize_constructor_val (tree, tree);
extern tree get_symbol_constant_value (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 tree get_maxval_strlen (tree, int);
extern void gimplify_and_update_call_from_tree (gimple_stmt_iterator *, tree); extern void gimplify_and_update_call_from_tree (gimple_stmt_iterator *, tree);
extern bool fold_stmt (gimple_stmt_iterator *); extern bool fold_stmt (gimple_stmt_iterator *);
......
...@@ -1800,7 +1800,7 @@ get_string_length (tree str) ...@@ -1800,7 +1800,7 @@ get_string_length (tree str)
aren't known to point any such arrays result in LENRANGE[1] set aren't known to point any such arrays result in LENRANGE[1] set
to SIZE_MAX. */ to SIZE_MAX. */
tree lenrange[2]; tree lenrange[2];
get_range_strlen (str, lenrange); bool flexarray = get_range_strlen (str, lenrange);
if (lenrange [0] || lenrange [1]) if (lenrange [0] || lenrange [1])
{ {
...@@ -1843,7 +1843,11 @@ get_string_length (tree str) ...@@ -1843,7 +1843,11 @@ get_string_length (tree str)
res.range.min = 0; 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; return res;
} }
......
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> 2017-02-03 Martin Liska <mliska@suse.cz>
PR lto/66295 PR lto/66295
......
/* 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) ...@@ -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 /* 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 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 bool
array_at_struct_end_p (tree ref) array_at_struct_end_p (tree ref, bool allow_compref)
{ {
if (TREE_CODE (ref) != ARRAY_REF 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; return false;
while (handled_component_p (ref)) while (handled_component_p (ref))
......
...@@ -4855,8 +4855,10 @@ extern tree array_ref_low_bound (tree); ...@@ -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 /* 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 a structure. If this is the case, the array may be allocated larger
than its upper bound implies. */ than its upper bound implies. When second argument is true considers
extern bool array_at_struct_end_p (tree); 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 /* 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. */ by EXP. This does not include any offset in DECL_FIELD_BIT_OFFSET. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment