aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2017-12-18 22:49:57 +0000
committerMartin Sebor <msebor@gcc.gnu.org>2017-12-18 15:49:57 -0700
commit06199618c1c047366fdafd2b0fafdace1fb44abc (patch)
treea0d1d0ffb97b3a497c587d6dd9e1ecfd092a08ec /gcc
parentadaefe2a50b56505b9745955da5231cd87ce9d8a (diff)
downloadgcc-06199618c1c047366fdafd2b0fafdace1fb44abc.zip
gcc-06199618c1c047366fdafd2b0fafdace1fb44abc.tar.gz
gcc-06199618c1c047366fdafd2b0fafdace1fb44abc.tar.bz2
PR middle-end/83373 - False positive reported by -Wstringop-overflow
PR middle-end/83373 - False positive reported by -Wstringop-overflow PR tree-optimization/78450 - strlen(s) return value can be assumed to be less than the size of s gcc/ChangeLog: PR middle-end/83373 PR tree-optimization/78450 * tree-ssa-strlen.c (maybe_set_strlen_range): New function. (handle_builtin_strlen): Call it. gcc/testsuite/ChangeLog: PR middle-end/83373 PR tree-optimization/78450 * gcc.dg/pr83373.c: New test. * gcc.dg/strlenopt-36.c: New test. * gcc.dg/strlenopt-37.c: New test. From-SVN: r255790
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/testsuite/ChangeLog8
-rw-r--r--gcc/testsuite/gcc.dg/pr83373.c33
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-36.c86
-rw-r--r--gcc/testsuite/gcc.dg/strlenopt-37.c83
-rw-r--r--gcc/tree-ssa-strlen.c42
6 files changed, 259 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 948271e..d165b5c 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,10 @@
+2017-12-18 Martin Sebor <msebor@redhat.com>
+
+ PR middle-end/83373
+ PR tree-optimization/78450
+ * tree-ssa-strlen.c (maybe_set_strlen_range): New function.
+ (handle_builtin_strlen): Call it.
+
2017-12-18 Segher Boessenkool <segher@kernel.crashing.org>
PR rtl-optimization/83424
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 129d142..eb2eba7 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2017-12-18 Martin Sebor <msebor@redhat.com>
+
+ PR middle-end/83373
+ PR tree-optimization/78450
+ * gcc.dg/pr83373.c: New test.
+ * gcc.dg/strlenopt-36.c: New test.
+ * gcc.dg/strlenopt-37.c: New test.
+
2017-12-18 Marek Polacek <polacek@redhat.com>
PR c++/83116
diff --git a/gcc/testsuite/gcc.dg/pr83373.c b/gcc/testsuite/gcc.dg/pr83373.c
new file mode 100644
index 0000000..6b0de09
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr83373.c
@@ -0,0 +1,33 @@
+/* PR middle-end/83373 - False positive reported by -Wstringop-overflow
+ { dg-do compile }
+ { dg-options "-O2 -Wstringop-overflow" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+char buf[100];
+
+void get_data (char*);
+
+__attribute__ ((nonnull(1, 2)))
+inline char* my_strcpy (char* dst, const char* src, size_t size)
+{
+ size_t len = __builtin_strlen (src);
+ if (len < size)
+ __builtin_memcpy (dst, src, len + 1);
+ else
+ {
+ __builtin_memcpy (dst, src, size - 1); /* { dg-bogus "\\\[-Wstringop-oveflow]" } */
+ dst[size - 1] = '\0';
+ }
+
+ return dst;
+}
+
+void test(void)
+{
+ char data[20] = "12345";
+
+ get_data (data);
+
+ my_strcpy (buf, data, sizeof buf);
+}
diff --git a/gcc/testsuite/gcc.dg/strlenopt-36.c b/gcc/testsuite/gcc.dg/strlenopt-36.c
new file mode 100644
index 0000000..d6fcca2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-36.c
@@ -0,0 +1,86 @@
+/* PR tree-optimization/78450 - strlen(s) return value can be assumed
+ to be less than the size of s
+ { dg-do compile }
+ { dg-options "-O2 -fdump-tree-optimized" } */
+
+#include "strlenopt.h"
+
+extern char a7[7], a6[6], a5[5], a4[4], a3[3], a2[2], a1[1];
+extern char a0[0]; /* Intentionally not tested here. */
+extern char ax[]; /* Same. */
+
+struct MemArrays {
+ char a7[7], a6[6], a5[5], a4[4], a3[3], a2[2], a1[1];
+ char a0[0]; /* Not tested here. */
+};
+
+struct NestedMemArrays {
+ struct { char a7[7]; } ma7;
+ struct { char a6[6]; } ma6;
+ struct { char a5[5]; } ma5;
+ struct { char a4[4]; } ma4;
+ struct { char a3[3]; } ma3;
+ struct { char a2[2]; } ma2;
+ struct { char a1[1]; } ma1;
+ struct { char a0[0]; } ma0;
+ char last;
+};
+
+extern void failure_on_line (int);
+
+#define TEST_FAIL(line) \
+ do { \
+ failure_on_line (line); \
+ } while (0)
+
+#define T(expr) \
+ if (!(expr)) TEST_FAIL (__LINE__); else (void)0
+
+
+void test_array (void)
+{
+ T (strlen (a7) < sizeof a7);
+ T (strlen (a6) < sizeof a6);
+ T (strlen (a5) < sizeof a5);
+ T (strlen (a4) < sizeof a4);
+ T (strlen (a3) < sizeof a3);
+
+ /* The following two calls are folded too early which defeats
+ the strlen() optimization.
+ T (strlen (a2) == 1);
+ T (strlen (a1) == 0); */
+}
+
+void test_memarray (struct MemArrays *ma)
+{
+ T (strlen (ma->a7) < sizeof ma->a7);
+ T (strlen (ma->a6) < sizeof ma->a6);
+ T (strlen (ma->a5) < sizeof ma->a5);
+ T (strlen (ma->a4) < sizeof ma->a4);
+ T (strlen (ma->a3) < sizeof ma->a3);
+
+ /* The following two calls are folded too early which defeats
+ the strlen() optimization.
+ T (strlen (ma->a2) == 1);
+ T (strlen (ma->a1) == 0); */
+}
+
+/* Verify that the range of strlen(A) of a last struct member is
+ set even when the array is the sole member of a struct as long
+ as the struct itself is a member of another struct. The converse
+ is tested in stlenopt-37.c. */
+void test_nested_memarray (struct NestedMemArrays *ma)
+{
+ T (strlen (ma->ma7.a7) < sizeof ma->ma7.a7);
+ T (strlen (ma->ma6.a6) < sizeof ma->ma6.a6);
+ T (strlen (ma->ma5.a5) < sizeof ma->ma5.a5);
+ T (strlen (ma->ma4.a4) < sizeof ma->ma4.a4);
+ T (strlen (ma->ma3.a3) < sizeof ma->ma3.a3);
+
+ /* The following two calls are folded too early which defeats
+ the strlen() optimization.
+ T (strlen (ma->ma2.a2) == 1);
+ T (strlen (ma->ma1.a1) == 0); */
+}
+
+/* { dg-final { scan-tree-dump-not "failure_on_line" "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-37.c b/gcc/testsuite/gcc.dg/strlenopt-37.c
new file mode 100644
index 0000000..865653c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-37.c
@@ -0,0 +1,83 @@
+/* PR tree-optimization/78450 - strlen(s) return value can be assumed
+ to be less than the size of s
+ { dg-do compile }
+ { dg-options "-O2 -fdump-tree-optimized" } */
+
+#include "strlenopt.h"
+
+extern char ax[];
+
+struct MemArray7 { char a7[7]; };
+struct MemArray6 { char a6[6]; };
+struct MemArray5 { char a5[5]; };
+struct MemArray4 { char a4[4]; };
+struct MemArray3 { char a3[3]; };
+struct MemArray2 { char a2[2]; };
+struct MemArray1 { char a1[1]; };
+struct MemArray0 { int n; char a0[0]; };
+struct MemArrayX { int n; char ax[]; };
+
+struct MemArrays
+{
+ struct MemArray7 *ma7;
+ struct MemArray6 *ma6;
+ struct MemArray5 *ma5;
+ struct MemArray4 *ma4;
+ struct MemArray3 *ma3;
+ struct MemArray2 *ma2;
+ struct MemArray1 *ma1;
+ struct MemArray0 *ma0;
+ struct MemArrayX *max;
+};
+
+extern void if_stmt_on_line (int);
+extern void else_stmt_on_line (int);
+
+#define T(expr) \
+ (!!(expr) ? if_stmt_on_line (__LINE__) : else_stmt_on_line (__LINE__))
+
+void test_memarray_lt (struct MemArrays *p)
+{
+ T (strlen (p->ma7->a7) < sizeof p->ma7->a7);
+ T (strlen (p->ma6->a6) < sizeof p->ma6->a6);
+ T (strlen (p->ma5->a5) < sizeof p->ma5->a5);
+ T (strlen (p->ma4->a4) < sizeof p->ma4->a4);
+ T (strlen (p->ma3->a3) < sizeof p->ma3->a3);
+ T (strlen (p->ma2->a2) < sizeof p->ma2->a2);
+ T (strlen (p->ma1->a1) < sizeof p->ma1->a1);
+
+ T (strlen (p->ma0->a0) < 1);
+ T (strlen (p->max->ax) < 1);
+}
+
+void test_memarray_eq (struct MemArrays *p)
+{
+ T (strlen (p->ma7->a7) == sizeof p->ma7->a7);
+ T (strlen (p->ma6->a6) == sizeof p->ma6->a6);
+ T (strlen (p->ma5->a5) == sizeof p->ma5->a5);
+ T (strlen (p->ma4->a4) == sizeof p->ma4->a4);
+ T (strlen (p->ma3->a3) == sizeof p->ma3->a3);
+ T (strlen (p->ma2->a2) == sizeof p->ma2->a2);
+ T (strlen (p->ma1->a1) == sizeof p->ma1->a1);
+
+ T (strlen (p->ma0->a0) == 1);
+ T (strlen (p->max->ax) == 1);
+}
+
+void test_memarray_gt (struct MemArrays *p)
+{
+ T (strlen (p->ma7->a7) > sizeof p->ma7->a7);
+ T (strlen (p->ma6->a6) > sizeof p->ma6->a6);
+ T (strlen (p->ma5->a5) > sizeof p->ma5->a5);
+ T (strlen (p->ma4->a4) > sizeof p->ma4->a4);
+ T (strlen (p->ma3->a3) > sizeof p->ma3->a3);
+ T (strlen (p->ma2->a2) > sizeof p->ma2->a2);
+ T (strlen (p->ma1->a1) > sizeof p->ma1->a1);
+
+ T (strlen (p->ma0->a0) > 1);
+ T (strlen (p->max->ax) > 1);
+ }
+
+/* Verify that no if or else statements have been eliminated.
+ { dg-final { scan-tree-dump-times "if_stmt_on_line" 27 "optimized" } }
+ { dg-final { scan-tree-dump-times "else_stmt_on_line" 27 "optimized" } } */
diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
index e75d133..0386883 100644
--- a/gcc/tree-ssa-strlen.c
+++ b/gcc/tree-ssa-strlen.c
@@ -1152,6 +1152,44 @@ adjust_last_stmt (strinfo *si, gimple *stmt, bool is_strcat)
update_stmt (last.stmt);
}
+/* For an LHS that is an SSA_NAME and for strlen() argument SRC, set
+ LHS range info to [0, N] if SRC refers to a character array A[N]
+ with unknown length bounded by N. */
+
+static void
+maybe_set_strlen_range (tree lhs, tree src)
+{
+ if (TREE_CODE (lhs) != SSA_NAME)
+ return;
+
+ if (TREE_CODE (src) == SSA_NAME)
+ {
+ gimple *def = SSA_NAME_DEF_STMT (src);
+ if (is_gimple_assign (def)
+ && gimple_assign_rhs_code (def) == ADDR_EXPR)
+ src = gimple_assign_rhs1 (def);
+ }
+
+ if (TREE_CODE (src) != ADDR_EXPR)
+ return;
+
+ /* The last array member of a struct can be bigger than its size
+ suggests if it's treated as a poor-man's flexible array member. */
+ src = TREE_OPERAND (src, 0);
+ if (TREE_CODE (TREE_TYPE (src)) != ARRAY_TYPE
+ || array_at_struct_end_p (src))
+ return;
+
+ tree type = TREE_TYPE (src);
+ if (tree dom = TYPE_DOMAIN (type))
+ if (tree maxval = TYPE_MAX_VALUE (dom))
+ {
+ wide_int max = wi::to_wide (maxval);
+ wide_int min = wi::zero (max.get_precision ());
+ set_range_info (lhs, VR_RANGE, min, max);
+ }
+}
+
/* Handle a strlen call. If strlen of the argument is known, replace
the strlen call with the known value, otherwise remember that strlen
of the argument is stored in the lhs SSA_NAME. */
@@ -1262,6 +1300,10 @@ handle_builtin_strlen (gimple_stmt_iterator *gsi)
set_strinfo (idx, si);
find_equal_ptrs (src, idx);
+ /* For SRC that is an array of N elements, set LHS's range
+ to [0, N]. */
+ maybe_set_strlen_range (lhs, src);
+
if (strlen_to_stridx)
{
location_t loc = gimple_location (stmt);