Commit 06199618 by Martin Sebor Committed by Martin Sebor

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
parent adaefe2a
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> 2017-12-18 Segher Boessenkool <segher@kernel.crashing.org>
PR rtl-optimization/83424 PR rtl-optimization/83424
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> 2017-12-18 Marek Polacek <polacek@redhat.com>
PR c++/83116 PR c++/83116
......
/* 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);
}
/* 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" } } */
/* 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" } } */
...@@ -1152,6 +1152,44 @@ adjust_last_stmt (strinfo *si, gimple *stmt, bool is_strcat) ...@@ -1152,6 +1152,44 @@ adjust_last_stmt (strinfo *si, gimple *stmt, bool is_strcat)
update_stmt (last.stmt); 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 /* Handle a strlen call. If strlen of the argument is known, replace
the strlen call with the known value, otherwise remember that strlen the strlen call with the known value, otherwise remember that strlen
of the argument is stored in the lhs SSA_NAME. */ of the argument is stored in the lhs SSA_NAME. */
...@@ -1262,6 +1300,10 @@ handle_builtin_strlen (gimple_stmt_iterator *gsi) ...@@ -1262,6 +1300,10 @@ handle_builtin_strlen (gimple_stmt_iterator *gsi)
set_strinfo (idx, si); set_strinfo (idx, si);
find_equal_ptrs (src, idx); 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) if (strlen_to_stridx)
{ {
location_t loc = gimple_location (stmt); location_t loc = gimple_location (stmt);
......
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