aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2017-02-03 16:38:15 +0000
committerMartin Sebor <msebor@gcc.gnu.org>2017-02-03 09:38:15 -0700
commit3f3430400b2ce552a5dbdae49a3a482687b96afa (patch)
treec78749d08d207350d71edfc1c5b9871d422a1f1c /gcc
parent46a2ab580a762b0fc3e64dc4ab24d459a4bd1fd2 (diff)
downloadgcc-3f3430400b2ce552a5dbdae49a3a482687b96afa.zip
gcc-3f3430400b2ce552a5dbdae49a3a482687b96afa.tar.gz
gcc-3f3430400b2ce552a5dbdae49a3a482687b96afa.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog11
-rw-r--r--gcc/gimple-fold.c44
-rw-r--r--gcc/gimple-fold.h2
-rw-r--r--gcc/gimple-ssa-sprintf.c8
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr79352.c45
-rw-r--r--gcc/tree.c9
-rw-r--r--gcc/tree.h6
8 files changed, 109 insertions, 21 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 269d619..a8203a4 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index ef1afd1..1cd22a8 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -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);
diff --git a/gcc/gimple-fold.h b/gcc/gimple-fold.h
index 38fb8e7..e4931a1 100644
--- a/gcc/gimple-fold.h
+++ b/gcc/gimple-fold.h
@@ -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 *);
diff --git a/gcc/gimple-ssa-sprintf.c b/gcc/gimple-ssa-sprintf.c
index 10c6d8e..3670bac 100644
--- a/gcc/gimple-ssa-sprintf.c
+++ b/gcc/gimple-ssa-sprintf.c
@@ -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;
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index c5e31c7..ff8ce70 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr79352.c b/gcc/testsuite/gcc.dg/tree-ssa/pr79352.c
new file mode 100644
index 0000000..4a153b7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr79352.c
@@ -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"} } */
diff --git a/gcc/tree.c b/gcc/tree.c
index 8426834..804ab5e 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -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))
diff --git a/gcc/tree.h b/gcc/tree.h
index 6341446..f63a678 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -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. */