Commit aac9480d by Martin Sebor Committed by Martin Sebor

PR middle-end/71924 - missing -Wreturn-local-addr returning alloca result

PR middle-end/71924 - missing -Wreturn-local-addr returning alloca result
PR middle-end/90549 - missing -Wreturn-local-addr maybe returning an address of a local array plus offset

gcc/ChangeLog:

	PR middle-end/71924
	PR middle-end/90549
	* gimple-ssa-isolate-paths.c (isolate_path): Add attribute.  Update
	comment.
	(args_loc_t): New type.
	(args_loc_t, locmap_t): same.
	(diag_returned_locals): New function.
	(is_addr_local): Same.
	(handle_return_addr_local_phi_arg, warn_return_addr_local): Same.
	(find_implicit_erroneous_behavior): Call warn_return_addr_local_phi_arg.
	(find_explicit_erroneous_behavior): Call warn_return_addr_local.

gcc/testsuite/ChangeLog:

	PR middle-end/71924
	PR middle-end/90549
	* gcc.c-torture/execute/return-addr.c: New test.
	* gcc.dg/Wreturn-local-addr-2.c: New test.
	* gcc.dg/Wreturn-local-addr-4.c: New test.
	* gcc.dg/Wreturn-local-addr-5.c: New test.
	* gcc.dg/Wreturn-local-addr-6.c: New test.
	* gcc.dg/Wreturn-local-addr-7.c: New test.
	* gcc.dg/Wreturn-local-addr-8.c: New test.
	* gcc.dg/Wreturn-local-addr-9.c: New test.
	* gcc.dg/Wreturn-local-addr-10.c: New test.
	* gcc.dg/Walloca-4.c: Handle expected warnings.
	* gcc.dg/pr41551.c: Same.
	* gcc.dg/pr59523.c: Same.
	* gcc.dg/tree-ssa/pr88775-2.c: Same.
	* gcc.dg/tree-ssa/alias-37.c: Same.
	* gcc.dg/winline-7.c: Same.

From-SVN: r273261
parent 7d64aec4
2019-07-08 Martin Sebor <msebor@redhat.com>
PR middle-end/71924
PR middle-end/90549
* gimple-ssa-isolate-paths.c (isolate_path): Add attribute. Update
comment.
(args_loc_t): New type.
(args_loc_t, locmap_t): same.
(diag_returned_locals): New function.
(is_addr_local): Same.
(handle_return_addr_local_phi_arg, warn_return_addr_local): Same.
(find_implicit_erroneous_behavior): Call warn_return_addr_local_phi_arg.
(find_explicit_erroneous_behavior): Call warn_return_addr_local.
2019-07-08 Jakub Jelinek <jakub@redhat.com> 2019-07-08 Jakub Jelinek <jakub@redhat.com>
* tree-vect-stmts.c (scan_operand_equal_p): Look through MEM_REF * tree-vect-stmts.c (scan_operand_equal_p): Look through MEM_REF
......
2019-07-08 Martin Sebor <msebor@redhat.com>
PR middle-end/71924
PR middle-end/90549
* gcc.c-torture/execute/return-addr.c: New test.
* gcc.dg/Wreturn-local-addr-2.c: New test.
* gcc.dg/Wreturn-local-addr-4.c: New test.
* gcc.dg/Wreturn-local-addr-5.c: New test.
* gcc.dg/Wreturn-local-addr-6.c: New test.
* gcc.dg/Wreturn-local-addr-7.c: New test.
* gcc.dg/Wreturn-local-addr-8.c: New test.
* gcc.dg/Wreturn-local-addr-9.c: New test.
* gcc.dg/Wreturn-local-addr-10.c: New test.
* gcc.dg/Walloca-4.c: Handle expected warnings.
* gcc.dg/pr41551.c: Same.
* gcc.dg/pr59523.c: Same.
* gcc.dg/tree-ssa/pr88775-2.c: Same.
* gcc.dg/tree-ssa/alias-37.c: Same.
* gcc.dg/winline-7.c: Same.
2019-07-08 Jakub Jelinek <jakub@redhat.com> 2019-07-08 Jakub Jelinek <jakub@redhat.com>
* g++.dg/vect/simd-6.cc: Replace xfail with target x86. * g++.dg/vect/simd-6.cc: Replace xfail with target x86.
......
/* Test to verify that a function that returns either the address
of a local variable or a non-local via a MAX_EXPR or MIN_EXPR
doesn't return null when the result of the expression is
the latter. */
#define NOIPA __attribute__ ((noclone, noinline, noipa))
#define A(expr) \
((expr) \
? (void)0 \
: (__builtin_printf ("assertion failed on line %i: %s\n", \
__LINE__, #expr), \
__builtin_abort ()))
typedef __UINTPTR_TYPE__ uintptr_t;
/* Return a bigger value than P. The address still points (just
past) the local variable pointed to by P so the caller does
return the address of a local variable but that's hidden from
GCC by the attribute and the point of the test is to verify
that the address in the return statement in the caller isn't
replaced by null when GCC cannot prove the address doesn't
reference a non-local variable. */
NOIPA char* get_max_2 (char *p)
{
return p + 1;
}
NOIPA char* get_max_3 (char *p, char *q)
{
return p < q ? q + 1 : p + 1;
}
/* Analogous to the above. The expressions are undefined because
they form an address prior to the beginning of the object but
it's hidden from GCC by the attributes. */
NOIPA char* get_min_2 (char *p)
{
return p - 1;
}
NOIPA char* get_min_3 (char *p, char *q)
{
return p < q ? p - 1 : q - 1;
}
NOIPA void* test_max_2 (void)
{
char c;
char *p = get_max_2 (&c);
void *q = p > &c ? p : &c; /* MAX_EXPR */
return q;
}
NOIPA void* test_max_3 (void)
{
char c;
char d;
char *p = get_max_3 (&c, &d);
void *q = p < &c ? &c < &d ? &d : &c : p;
return q;
}
NOIPA void* test_min_2 (void)
{
char c;
char *p = get_min_2 (&c);
void *q = p < &c ? p : &c; /* MIN_EXPR" */
return q;
}
NOIPA void* test_min_3 (void)
{
char c;
char d;
char *p = get_min_3 (&c, &d);
void *q = p > &c ? &c > &d ? &d : &c : p;
return q;
}
NOIPA void* test_min_3_phi (int i)
{
char a, b;
char *p0 = &a;
char *p1 = &b;
char *p2 = get_min_3 (&a, &b);
char *p3 = get_min_3 (&a, &b);
char *p4 = p2 < p0 ? p2 : p0;
char *p5 = p3 < p1 ? p3 : p1;
__builtin_printf ("%p %p %p %p\n", p2, p3, p4, p5);
if (i == 1)
return p4;
else
return p5;
}
int main ()
{
A (0 != test_max_2 ());
A (0 != test_max_3 ());
A (0 != test_min_2 ());
A (0 != test_min_3 ());
A (0 != test_min_3_phi (0));
}
...@@ -7,11 +7,12 @@ ...@@ -7,11 +7,12 @@
{ {
char *src; char *src;
_Bool _Bool use_alloca = (((rear_ptr - w) * sizeof (char)) < 4096U);
use_alloca = (((rear_ptr - w) * sizeof (char)) < 4096U);
if (use_alloca) if (use_alloca)
src = (char *) __builtin_alloca ((rear_ptr - w) * sizeof (char)); src = (char *) __builtin_alloca ((rear_ptr - w) * sizeof (char));
else else
src = (char *) __builtin_malloc ((rear_ptr - w) * sizeof (char)); src = (char *) __builtin_malloc ((rear_ptr - w) * sizeof (char));
return src; return src;
} }
/* { dg-prune-output "-Wreturn-local-addr" } */
/* PR c/71924 - missing -Wreturn-local-addr returning alloca result
Test reduced from libstdc++-v3/testsuite/ext/ext_pointer/1.cc.
It verifies that iteration in find_implicit_erroneous_behavior
in gimple-ssa-isolate-path.c terminates under specific conditions.
{ dg-do compile }
{ dg-options "-O2 -Wall" } */
typedef __UINTPTR_TYPE__ uintptr_t;
struct A { int i; };
struct P { uintptr_t d; };
static inline struct A* get (const struct P *p)
{
if (p->d == 1)
return 0;
return (struct A*)((uintptr_t)p + p->d);
}
static inline void set (struct P *p, struct A* q)
{
/* The basic block below would cause an infinite loop in
find_implicit_erroneous_behavior due to assuming the DUPLICATE
pointer returned from isolate_path would distinct from the one
passed to it. (Replacing the if statement with the ternary ?:
expression did not have this effect (it gets optimized early
on).
<bb 4> [local count: 1073741823]:
# _14 = PHI <0B(2), &MEM <struct A[2]> [(void *)&a + 4B](3)>
_2 = _14->i;
if (_2 != 2)
goto <bb 5>; [0.00%]
else
goto <bb 6>; [100.00%]
*/
if (!q)
p->d = 1;
else
p->d = (uintptr_t)(q) - (uintptr_t)(p);
}
void f (void)
{
struct A a[2] = { { 1 }, { 2 } };
struct P p, q;
set (&p, a);
set (&q, get (&p));
set (&q, get (&q) + 0);
set (&q, get (&q) + 1);
if (get (&q)[0].i != get (&p)[1].i)
__builtin_abort ();
}
/* PR c/71924 - missing -Wreturn-local-addr returning alloca result
{ dg-do compile }
{ dg-options "-O2 -Wall" } */
#define ATTR(...) __attribute__ ((__VA_ARGS__))
struct A { int a, b, c; };
struct B { int a, b, c[]; };
void sink (void*, ...);
ATTR (noipa) void*
return_alloca (int n)
{
void *p = __builtin_alloca (n);
sink (p);
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_alloca_index_cst (int n)
{
int *p = (int*)__builtin_alloca (n);
p = &p[1];
sink (p);
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_alloca_plus_cst (int n)
{
int *p = (int*)__builtin_alloca (n);
p += 1;
sink (p);
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_alloca_plus_var (int n, int i)
{
char *p = (char*)__builtin_alloca (n);
p += i;
sink (p);
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_alloca_member_1 (int n)
{
struct A *p = (struct A*)__builtin_alloca (n);
sink (&p->a);
return &p->a; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_alloca_member_2 (int n)
{
struct A *p = (struct A*)__builtin_alloca (n);
sink (&p->b);
return &p->b; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_alloca_flexarray (int n)
{
struct B *p = (struct B*)__builtin_alloca (n);
sink (p->c);
return p->c; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_array (void)
{
int a[32];
void *p = a;
sink (p);
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_array_index_cst (void)
{
int a[32];
void *p = &a[2];
sink (p);
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_array_plus_cst (void)
{
int a[32];
void *p = a + 2;
sink (p);
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_array_plus_var (int i)
{
int a[32];
void *p = a + i;
sink (p);
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_array_member_1 (void)
{
struct A a[2];
int *p = &a[1].a;
sink (a, p);
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_array_member_2 (void)
{
struct A a[32];
int *p = &a[1].b;
sink (a, p);
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_vla (int n)
{
char a[n];
void *p = a;
sink (p);
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_vla_index_cst (int n)
{
char a[n];
char *p = &a[3];
sink (p);
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_vla_plus_cst (int n)
{
char a[n];
char *p = a + 3;
sink (p);
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_vla_index_var (int n, int i)
{
char a[n];
char *p = &a[i];
sink (p);
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_vla_plus_var (int n, int i)
{
char a[n];
char *p = a + i;
sink (p);
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_vla_member_1 (int n, int i)
{
struct A a[n];
void *p = &a[i].a;
sink (a, p);
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_vla_member_2 (int n, int i)
{
struct A a[n];
void *p = &a[i].b;
sink (a, p);
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_alloca_or_alloca (int n, int i)
{
void *p = i ? __builtin_alloca (n * i) : __builtin_alloca (n);
sink (p);
/* The warning here should really be "function returns". */
return p; /* { dg-warning "function (returns|may return) address of local" } */
}
ATTR (noipa) void*
return_alloca_or_alloca_2 (int n, int i)
{
void *p0 = __builtin_alloca (n);
void *p1 = __builtin_alloca (n * 2);
void *p = i ? p0 : p1;
sink (p0, p1, p);
/* Same as above. */
return p; /* { dg-warning "function (returns|may return) address of local" } */
}
ATTR (noipa) void*
return_array_or_array (int i)
{
int a[5];
int b[7];
void *p = i ? a : b;
sink (a, b, p);
/* The warning here should really be "function returns". */
return p; /* { dg-warning "function (returns|may return) address of local" } */
}
ATTR (noipa) void*
return_array_or_array_plus_var (int i, int j)
{
int a[5];
int b[7];
void *p0 = a + i;
void *p1 = b + j;
void *p = i < j ? p0 : p1;
sink (a, b, p0, p1, p);
/* The warning here should really be "function returns". */
return p; /* { dg-warning "function (returns|may return) address of local" } */
}
extern int global[32];
ATTR (noipa) void*
may_return_global_or_alloca (int n, int i)
{
void *p = i ? global : __builtin_alloca (n);
sink (p);
return p; /* { dg-warning "function may return address of local" } */
}
ATTR (noipa) void*
may_return_global_or_alloca_plus_cst (int n, int i)
{
int *p = i ? global : (int*)__builtin_alloca (n);
p += 7;
sink (p);
return p; /* { dg-warning "function may return address of local" } */
}
ATTR (noipa) void*
may_return_global_or_array (int n, int i)
{
int a[32];
void *p = i ? global : a;
sink (p);
return p; /* { dg-warning "function may return address of local" } */
}
ATTR (noipa) void*
may_return_global_or_array_plus_cst (int n, int i)
{
int a[32];
int *p = i ? global : a;
p += 4;
sink (p);
return p; /* { dg-warning "function may return address of local" } */
}
ATTR (noipa) void*
may_return_global_or_vla (int n, int i)
{
int a[n];
void *p = i ? global : a;
sink (p);
return p; /* { dg-warning "function may return address of local" } */
}
ATTR (noipa) void*
may_return_global_or_vla_plus_cst (int n, int i)
{
int a[n];
int *p = i ? global : a;
p += 4;
sink (p);
return p; /* { dg-warning "function may return address of local" } */
}
/* PR c/71924 - missing -Wreturn-local-addr returning alloca result
{ dg-do compile }
{ dg-options "-O2 -Wall" } */
#define ATTR(...) __attribute__ ((__VA_ARGS__))
typedef __INTPTR_TYPE__ intptr_t;
struct A { int a, b, c; };
struct B { int a, b, c[]; };
extern int g1[5], g2[5], g3[5], g4[5], g5[5];
void sink (void*, ...);
/* Verify that a pointer difference expression is handled correctly
even when converted to a pointer. */
ATTR (noipa) void*
return_local_diff_cst (void)
{
int a[5];
void *p = (void*)(&a[4] - &a[1]);
return p;
}
ATTR (noipa) void*
return_local_diff_var (int i, int j)
{
int a[5];
void *p = (void*)(&a[j] - &a[i]);
return p;
}
ATTR (noipa) void*
return_2_locals (int i)
{
int a[1]; /* { dg-message "declared here" } */
int b[2]; /* { dg-message "declared here" } */
void *p = i < 0 ? a : b;
return p; /* { dg-warning "function returns address of local" } */
}
/* Verify that returning the address of a local converted to intptr_t
is not diagnosed (see bug 90737 for a case the front-end gets wrong). */
ATTR (noipa) intptr_t
return_int_2_locals (int i)
{
int a[1];
int b[2];
void *p = i < 0 ? a : b;
return (intptr_t)p;
}
/* Verify that a conditional expression with a pointer first operand
is handled correctly. */
ATTR (noipa) void*
return_2_locals_ptrcond (void *q)
{
int a[1]; /* { dg-message "declared here" } */
int b[2]; /* { dg-message "declared here" } */
void *p = q ? a : b;
return p; /* { dg-warning "function returns address of local" } */
}
/* Verify that a preincrement expression with a pointer operand is
handled correctly. */
ATTR (noipa) void*
return_2_locals_ptrinc (void *q)
{
int a[1]; /* { dg-message "declared here" } */
int b[2]; /* { dg-message "declared here" } */
int *p = q ? a : b;
return ++p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_3_locals (int i)
{
int a[1]; /* { dg-message "declared here" } */
int b[2]; /* { dg-message "declared here" } */
int c[3]; /* { dg-message "declared here" } */
void *p = i < 0 ? a : 0 < i ? c : b;
return p; /* { dg-warning "function returns address of local" } */
}
/* Verify that a conditional expression with a pointer first operand
is handled correctly. */
ATTR (noipa) void*
return_3_locals_ptrcond (void *p, void *q)
{
int a[1]; /* { dg-message "declared here" } */
int b[2]; /* { dg-message "declared here" } */
int c[3]; /* { dg-message "declared here" } */
void *r = q ? r ? a : b : c;
return r; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_5_locals (int i)
{
int a[1]; /* { dg-message "declared here" } */
int b[2]; /* { dg-message "declared here" } */
int c[3]; /* { dg-message "declared here" } */
int d[4]; /* { dg-message "declared here" } */
int e[5]; /* { dg-message "declared here" } */
void *p = i < -1 ? a : i < 0 ? b : 1 < i ? e : 0 < i ? d : c;
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_1_global_4_locals (int i)
{
int a[1]; /* { dg-message "declared here" } */
int b[2]; /* { dg-message "declared here" } */
int c[3]; /* { dg-message "declared here" } */
int d[4]; /* { dg-message "declared here" } */
void *p = i < -1 ? a : i < 0 ? b : 1 < i ? g1 : 0 < i ? d : c;
return p; /* { dg-warning "function may return address of local" } */
}
ATTR (noipa) void*
return_2_globals_3_locals (int i)
{
int a[1]; /* { dg-message "declared here" } */
int b[2]; /* { dg-message "declared here" } */
int c[3]; /* { dg-message "declared here" } */
void *p = i < -1 ? a : i < 0 ? b : 1 < i ? g1 : 0 < i ? g2 : c;
return p; /* { dg-warning "function may return address of local" } */
}
ATTR (noipa) void*
return_3_globals_2_locals (int i)
{
int a[1]; /* { dg-message "declared here" } */
int b[2]; /* { dg-message "declared here" } */
void *p = i < -1 ? a : i < 0 ? b : 1 < i ? g1 : 0 < i ? g2 : g3;
return p; /* { dg-warning "function may return address of local" } */
}
ATTR (noipa) void*
return_4_globals_1_local (int i)
{
int a[1]; /* { dg-message "declared here" } */
void *p = i < -1 ? a : i < 0 ? g1 : 1 < i ? g2 : 0 < i ? g4 : g3;
return p; /* { dg-warning "function may return address of local" } */
}
ATTR (noipa) void*
return_all_globals (int i)
{
void *p = i < -1 ? g1 : i < 0 ? g2 : 1 < i ? g3 : 0 < i ? g5 : g4;
return p;
}
ATTR (noipa) void*
return_2_alloca_local_cstoff (int n, int i)
{
int *a = __builtin_alloca (n); /* { dg-message "declared here" } */
int *b = __builtin_alloca (n); /* { dg-message "declared here" } */
int *p = i < 0 ? a : b;
p += 1;
sink (p);
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_alloca_local_cstoff (int n, int i)
{
int *a = __builtin_alloca (n); /* { dg-message "declared here" } */
int b[2]; /* { dg-message "declared here" } */
int *p = i < 0 ? a : b;
p += 1;
sink (p);
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_local_alloca_cstoff (int n, int i)
{
int a[2]; /* { dg-message "declared here" } */
int *b = __builtin_alloca (n); /* { dg-message "declared here" } */
int *p = i < 0 ? a : b;
p += 1;
sink (p);
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_2_locals_cstoff (int i)
{
int a[1]; /* { dg-message "declared here" } */
int b[2]; /* { dg-message "declared here" } */
int *p = i < 0 ? a : b;
p += 1;
sink (p);
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_2_globals_3_locals_cstoff (int i)
{
int a[1]; /* { dg-message "declared here" } */
int b[2]; /* { dg-message "declared here" } */
int c[3]; /* { dg-message "declared here" } */
int *p = i < -1 ? a : i < 0 ? b : 1 < i ? g1 : 0 < i ? g2 : c;
p += 1;
sink (p);
return p; /* { dg-warning "function may return address of local" } */
}
ATTR (noipa) void*
return_3_globals_alloca_local_varoff (int n, int i, int j)
{
int *a = __builtin_alloca (n); /* { dg-message "declared here" } */
int b[2]; /* { dg-message "declared here" } */
int *p = i < -1 ? a : i < 0 ? b : 1 < i ? g1 : 0 < i ? g2 : g3;
p += j;
sink (p);
return p; /* { dg-warning "function may return address of local" } */
}
ATTR (noipa) void*
return_3_globals_2_locals_varoff (int i, int j)
{
int a[1]; /* { dg-message "declared here" } */
int b[2]; /* { dg-message "declared here" } */
int *p = i < -1 ? a : i < 0 ? b : 1 < i ? g1 : 0 < i ? g2 : g3;
p += j;
sink (p);
return p; /* { dg-warning "function may return address of local" } */
}
/* PR c/71924 - missing -Wreturn-local-addr returning alloca result
{ dg-do compile }
{ dg-options "-O2 -Wall" } */
#define ATTR(...) __attribute__ ((__VA_ARGS__))
struct A { int a, b, c; };
struct B { int a, b, c[]; };
extern int g1[5], g2[5], g3[5], g4[5], g5[5];
void sink (void*, ...);
ATTR (noipa) void*
return_2_locals (int i)
{
int a[1]; /* { dg-message "declared here" } */
int b[2]; /* { dg-message "declared here" } */
void *p = b;
if (i < 0)
p = a;
sink (p);
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_2_locals_after_2_globals (int i, int j)
{
int a[1]; /* { dg-message "declared here" } */
int b[2]; /* { dg-message "declared here" } */
int *p;
if (i < 0)
p = g1;
else
p = g2;
sink (p);
if (j < 0)
p = a;
else
p = b;
sink (p);
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_3_locals (int i)
{
int a[1]; /* { dg-message "declared here" } */
int b[2]; /* { dg-message "declared here" } */
int c[3]; /* { dg-message "declared here" } */
void *p = b + 1;
if (i < 0)
p = a;
else if (0 < i)
p = c + 2;
sink (p);
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_5_locals (int i)
{
int a[1]; /* { dg-message "declared here" } */
int b[2]; /* { dg-message "declared here" } */
int c[3]; /* { dg-message "declared here" } */
int d[4]; /* { dg-message "declared here" } */
int e[5]; /* { dg-message "declared here" } */
void *p = &c[2];
if (i < -1)
p = a;
else if (i < 0)
p = &b[1];
else if (1 < i)
p = &e[4];
else if (0 < i)
p = &d[3];
sink (p);
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_5_locals_switch (int i)
{
int a[1]; /* { dg-message "declared here" } */
int b[2]; /* { dg-message "declared here" } */
int c[3]; /* { dg-message "declared here" } */
int d[4]; /* { dg-message "declared here" } */
int e[5]; /* { dg-message "declared here" } */
void *p = 0;
switch (i)
{
case 0: p = &a[1]; break;
case 1: p = &b[2]; break;
case 2: p = &c[3]; break;
case 3: p = &d[4]; break;
default: p = &e[5]; break;
}
sink (p);
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_1_global_4_locals (int i)
{
int a[1]; /* { dg-message "declared here" } */
int b[2]; /* { dg-message "declared here" } */
int c[3]; /* { dg-message "declared here" } */
int d[4]; /* { dg-message "declared here" } */
void *p = c;
if (i < -1)
sink (p = a);
else if (i < 0)
sink (p = b);
else if (1 < i)
sink (p = g1);
else if (0 < i)
sink (p = d);
sink (p, a, b, c, d);
return p; /* { dg-warning "function may return address of local" } */
}
ATTR (noipa) void*
return_1_global_4_locals_switch (int i)
{
int a[1]; /* { dg-message "declared here" } */
int b[2]; /* { dg-message "declared here" } */
int c[3]; /* { dg-message "declared here" } */
int d[4]; /* { dg-message "declared here" } */
void *p = 0;
switch (i)
{
case 0: p = &a[0]; break;
case 1: p = &b[1]; break;
case 2: p = &c[2]; break;
case 3: p = &d[3]; break;
}
sink (p);
return p; /* { dg-warning "function may return address of local" } */
}
ATTR (noipa) void*
return_2_globals_3_locals (int i)
{
int a[1]; /* { dg-message "declared here" } */
int b[2]; /* { dg-message "declared here" } */
int c[3]; /* { dg-message "declared here" } */
void *p = c;
if (i < -1)
p = a;
else if (i < 0)
p = b;
else if (1 < i)
p = g1;
else if (0 < i)
p = g2;
sink (p);
return p; /* { dg-warning "function may return address of local" } */
}
ATTR (noipa) void*
return_3_globals_2_locals (int i)
{
int a[1]; /* { dg-message "declared here" } */
int b[2]; /* { dg-message "declared here" } */
void *p = g3;
if (i < -1)
p = a;
else if (i < 0)
p = b;
else if (1 < i)
p = g1;
else if (0 < i)
p = g2;
sink (p);
return p; /* { dg-warning "function may return address of local" } */
}
ATTR (noipa) void*
return_4_globals_1_local (int i)
{
int a[1]; /* { dg-message "declared here" } */
void *p = g3;
if (i < -1)
p = a;
else if (i < 0)
p = g1;
else if (1 < i)
p = g2;
else if (0 < i)
p = g4;
sink (p);
return p; /* { dg-warning "function may return address of local" } */
}
ATTR (noipa) void*
return_all_globals (int i)
{
void *p = g4;
if (i < -1)
p = g1;
else if (i < 0)
p = g2;
else if (1 < i)
p = g3;
else if (0 < i)
p = g5;
return p;
}
ATTR (noipa) void*
return_2_alloca_local_cstoff (int n, int i)
{
int *a = __builtin_alloca (n); /* { dg-message "declared here" } */
int *b = __builtin_alloca (n); /* { dg-message "declared here" } */
int *p = i < 0 ? a : b;
p += 1;
sink (p);
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_alloca_local_cstoff (int n, int i)
{
int *a = __builtin_alloca (n); /* { dg-message "declared here" } */
int b[2]; /* { dg-message "declared here" } */
int *p = b;
if (i < 0)
p = a;
p += 1;
sink (p);
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_local_alloca_cstoff (int n, int i)
{
int a[2]; /* { dg-message "declared here" } */
int *b = __builtin_alloca (n); /* { dg-message "declared here" } */
int *p = b;
if (i < 0)
p = a;
p += 1;
sink (p);
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_2_locals_cstoff (int i)
{
int a[1]; /* { dg-message "declared here" } */
int b[2]; /* { dg-message "declared here" } */
int *p = b;
if (i < 0)
p = a;
p += 1;
sink (p);
return p; /* { dg-warning "function returns address of local" } */
}
ATTR (noipa) void*
return_2_globals_3_locals_cstoff (int i)
{
int a[1]; /* { dg-message "declared here" } */
int b[2]; /* { dg-message "declared here" } */
int c[3]; /* { dg-message "declared here" } */
int *p = c;
if (i < -1)
p = a;
else if (i < 0)
p = b;
else if (1 < i)
p = g1;
else if (0 < i)
p = g2;
p += 1;
sink (p);
return p; /* { dg-warning "function may return address of local" } */
}
ATTR (noipa) void*
return_3_globals_alloca_local_varoff (int n, int i, int j)
{
int *a = __builtin_alloca (n); /* { dg-message "declared here" } */
int b[2]; /* { dg-message "declared here" } */
int *p = g3;
if (i < -1)
p = a;
else if (i < 0)
p = b;
else if (1 < i)
p = g1;
else if (0 < i)
p = g2;
p += j;
sink (p);
return p; /* { dg-warning "function may return address of local" } */
}
ATTR (noipa) void*
return_3_globals_2_locals_varoff (int i, int j)
{
int a[1]; /* { dg-message "declared here" } */
int b[2]; /* { dg-message "declared here" } */
int *p = g3;
if (i < -1)
p = a;
else if (i < 0)
p = b;
else if (1 < i)
p = g1;
else if (0 < i)
p = g2;
p += j;
sink (p);
return p; /* { dg-warning "function may return address of local" } */
}
/* PR c/71924 - missing -Wreturn-local-addr returning alloca result
{ dg-do compile }
{ dg-options "-O2 -Wall" } */
void sink (void*);
void* loop_idx (int x)
{
char a[32]; /* { dg-message "declared here" } */
char *p = a;
sink (a);
int i;
for (i = 0; i != 32; ++i)
if (p[i] == x)
break;
p = i < 32 ? &p[i] : 0;
return p; /* { dg-warning "may return address of local variable" } */
}
void* loop_ptr (int i, int x)
{
char a[32]; /* { dg-message "declared here" } */
char *p;
sink (a);
/* The warning for the statement below would ideally be a "returns"
because it definitely returns the address of a, but when both
returns get merged into one we end up with a "may return". */
for (p = a; *p; ++p)
if (*p == x)
return p; /* { dg-warning "(returns|may return) address of local variable" "missing location" { xfail *-*-* } } */
/* { dg-warning "(returns|may return) address of local variable" "pr90735" { target *-*-* } 0 } */
return 0;
}
/* PR c/71924 - missing -Wreturn-local-addr returning alloca result
{ dg-do compile }
{ dg-options "-O2 -Wall" } */
typedef __SIZE_TYPE__ size_t;
void* memcpy (void*, const void*, size_t);
void* mempcpy (void*, const void*, size_t);
void* memmove (void*, const void*, size_t);
char* stpcpy (char*, const char*);
char* stpncpy (char*, const char*, size_t);
size_t strlen (const char*);
size_t strnlen (const char*, size_t);
char* strcat (char*, const char*);
char* strncat (char*, const char*, size_t);
char* strcpy (char*, const char*);
char* strncpy (char*, const char*, size_t);
char* strdup (const char*);
char* strchr (const char*, int);
char* strrchr (const char*, int);
char* strstr (const char*, const char*);
void sink (void*, ...);
void* return_memcpy (const void *s, unsigned n)
{
char a[n]; /* { dg-message "declared here" } */
void *p = memcpy (a, s, n);
sink (p);
return p; /* { dg-warning "\\\[-Wreturn-local-addr]" } */
}
void* return_memcpy_cst (const void *s, unsigned n)
{
char a[n]; /* { dg-message "declared here" } */
void *p = memcpy (a + 1, s, n);
sink (p);
return p; /* { dg-warning "\\\[-Wreturn-local-addr]" } */
}
void* return_memcpy_var (const void *s, unsigned n, int i)
{
char a[n]; /* { dg-message "declared here" } */
void *p = memcpy (a + i, s, n);
sink (p);
return p; /* { dg-warning "\\\[-Wreturn-local-addr]" } */
}
void* return_mempcpy (const void *s, unsigned n)
{
char a[n]; /* { dg-message "declared here" } */
void *p = mempcpy (a, s, n);
sink (p);
return p; /* { dg-warning "\\\[-Wreturn-local-addr]" } */
}
void* return_memmove_cst (unsigned n)
{
char a[n]; /* { dg-message "declared here" } */
sink (a);
void *p = memmove (a + 1, a, n);
sink (p);
return p; /* { dg-warning "\\\[-Wreturn-local-addr]" } */
}
void* return_memmove_var (unsigned n, int i)
{
char a[n]; /* { dg-message "declared here" } */
sink (a);
void *p = memmove (a + i, a, n);
sink (p);
return p; /* { dg-warning "\\\[-Wreturn-local-addr]" } */
}
char* return_stpcpy (unsigned n, const char *s)
{
char a[n]; /* { dg-message "declared here" } */
char *p = stpcpy (a, s);
sink (p);
return p; /* { dg-warning "\\\[-Wreturn-local-addr]" } */
}
char* return_stpncpy (unsigned n, const char *s)
{
char a[n]; /* { dg-message "declared here" } */
char *p = stpncpy (a, s, n);
sink (p);
return p; /* { dg-warning "\\\[-Wreturn-local-addr]" } */
}
char* return_strcat (unsigned n, const char *s)
{
char a[n]; /* { dg-message "declared here" } */
sink (a);
char *p = strcat (a, s);
sink (p);
return p; /* { dg-warning "\\\[-Wreturn-local-addr]" } */
}
char* return_strncat (unsigned n, const char *s)
{
char a[n]; /* { dg-message "declared here" } */
sink (a);
char *p = strncat (a, s, n);
sink (p);
return p; /* { dg-warning "\\\[-Wreturn-local-addr]" } */
}
char* return_strcpy (unsigned n, const char *s)
{
char a[n]; /* { dg-message "declared here" } */
char *p = strcpy (a, s);
sink (p);
return p; /* { dg-warning "\\\[-Wreturn-local-addr]" } */
}
char* return_strcpy_plus_strlen (unsigned n, const char *s)
{
char a[n]; /* { dg-message "declared here" } */
char *p = strcpy (a, s);
sink (p);
p += strlen (p);
return p; /* { dg-warning "\\\[-Wreturn-local-addr]" } */
}
char* return_strcpy_cst_plus_strlen (unsigned n, const char *s)
{
char a[n]; /* { dg-message "declared here" } */
sink (a);
char *p = strcpy (a + 1, s);
sink (p);
p += strlen (p);
return p; /* { dg-warning "\\\[-Wreturn-local-addr]" } */
}
char* return_strcpy_var_plus_strlen (unsigned n, const char *s, int i)
{
char a[n]; /* { dg-message "declared here" } */
sink (a);
char *p = strcpy (a + i, s);
sink (p);
p += strlen (p);
return p; /* { dg-warning "\\\[-Wreturn-local-addr]" } */
}
char* return_strncpy (unsigned n, const char *s)
{
char a[n]; /* { dg-message "declared here" } */
char *p = strncpy (a, s, n);
sink (p);
return p; /* { dg-warning "\\\[-Wreturn-local-addr]" } */
}
char* return_strncpy_plus_strnlen (unsigned n, const char *s)
{
char a[n]; /* { dg-message "declared here" } */
char *p = strncpy (a, s, n);
p += strnlen (p, n);
sink (p);
return p; /* { dg-warning "\\\[-Wreturn-local-addr]" } */
}
char* return_strdup (unsigned n)
{
char a[n];
sink (a);
char *p = strdup (a);
return p;
}
char* return_strchr (unsigned n, int c)
{
char a[n]; /* { dg-message "declared here" } */
sink (a);
char *p = strchr (a, c);
return p; /* { dg-warning "\\\[-Wreturn-local-addr]" } */
}
char* return_strstr (unsigned n, const char *s)
{
char a[n]; /* { dg-message "declared here" } */
sink (a);
char *p = strstr (a, s);
if (p)
p += strlen (p);
return p; /* { dg-warning "\\\[-Wreturn-local-addr]" } */
}
char* return_strrchr (unsigned n, int c)
{
char a[n]; /* { dg-message "declared here" } */
sink (a);
char *p = strrchr (a, c);
return p; /* { dg-warning "\\\[-Wreturn-local-addr]" } */
}
/* Test to verify that a PHI with a COND_EXPR argument in a return
statement is handled correctly.
{ dg-do compile }
{ dg-options "-O2 -Wall" } */
extern struct S s;
void* f (int n)
{
void *p;
int x = 0;
for (int i = n; i >= 0; i--)
{
p = &s;
if (p == (void*)-1)
x = 1;
else if (p)
return p;
}
/* The return statement below ends up with the following IL:
<bb 6> [local count: 59055800]:
# x_10 = PHI <1(5), 0(2)>
_5 = x_10 != 0 ? -1B : 0B;
<bb 7> [local count: 114863532]:
# _3 = PHI <&s(4), _5(6), &s(3)>
return _3; */
return x ? (void*)-1 : 0;
}
void* g (int n)
{
void *p;
int x = 0; /* { dg-message "declared here" } */
for (int i = n; i >= 0; i--)
{
p = &s;
if (p == (void*)-1)
x = 1;
else if (p)
return p;
}
/* The return statement below does not reference a COND_EXPR argument. */
return x ? &x : 0; /* { dg-warning "may return address of local variable" "missing location" { xfail *-*-* } } */
/* { dg-warning "may return address of local variable" "pr90735" { target *-*-* } 0 } */
}
/* Test to verify that a MAX_EXPR and MIN_EXPR in a return statement
is handled correctly and that all local variables whose address
is or may be returned are identified.
{ dg-do compile }
{ dg-options "-O2 -Wall" } */
char* sink (char*, ...);
void* test_max_2 (void)
{
char c; /* { dg-message "declared here" } */
char *p = sink (&c);
void *q = p > &c ? p : &c; /* MAX_EXPR */
return q; /* { dg-warning "\\\[-Wreturn-local-addr" } */
}
void* test_max_3 (void)
{
char c; /* { dg-message "declared here" } */
char d; /* { dg-message "declared here" } */
char *p = sink (&c, &d);
void *q = p < &c ? &c < &d ? &d : &c : p;
return q; /* { dg-warning "\\\[-Wreturn-local-addr" } */
}
void* test_min_2 (void)
{
char c; /* { dg-message "declared here" } */
char *p = sink (&c);
void *q = p < &c ? p : &c; /* MIN_EXPR" */
return q; /* { dg-warning "\\\[-Wreturn-local-addr" } */
}
void* test_min_3 (void)
{
char c; /* { dg-message "declared here" } */
char d; /* { dg-message "declared here" } */
char *p = sink (&c, &d);
void *q = p > &c ? &c > &d ? &d : &c : p;
return q; /* { dg-warning "\\\[-Wreturn-local-addr" } */
}
void* test_min_2_phi (int i)
{
char a; /* { dg-message "declared here" } */
char *p = &a;
char *q = sink (&a);
p = p < q ? p : q;
if (i == 1)
return p;
/* { dg-warning "may return address of local variable" "missing location" { xfail *-*-* } } */
else
return q;
}
void* test_min_3_phi (int i)
{
char a; /* { dg-message "declared here" } */
char b; /* { dg-message "declared here" } */
char *p0 = &a;
char *p1 = &b;
char *p2 = sink (&a, &b);
char *p3 = sink (&a, &b);
char *p4 = p2 < p0 ? p2 : p0;
char *p5 = p3 < p1 ? p3 : p1;
if (i == 1)
/* { dg-warning "may return address of local variable" "missing location" { xfail *-*-* } } */
return p4;
else
/* { dg-warning "may return address of local variable" "missing location" { xfail *-*-* } } */
return p5;
}
/* The directive below "swallows" warnings for both test_min_2_phi
and test_min_3_phi.
{ dg-warning "may return address of local variable" "pr90735" { target *-*-* } 0 } */
/* PR c/71924 - missing -Wreturn-local-addr returning alloca result
Test derived from gcc.c-torture/execute/20071108-1.c. It shows
a false positive at -Os caused by the jump threading/vrp1 pass.
{ dg-do compile }
{ dg-options "-Os -fdump-tree-optimized" } */
struct S
{
int i;
};
void* f (void);
__attribute__ ((noinline))
struct S* g (int i)
{
struct S *p = f (), q;
if (p == 0)
p = &q;
p->i = i;
if (p == &q)
p = 0;
/* With -Os the warning pass sees:
...
<bb 4>
# p_1 = PHI <&q(2), p_5(3)>
p_1->i = i_6(D);
if (&q == p_1)
goto <bb 6>; [14.90%]
else
goto <bb 5>; [85.10%]
<bb 5>
<bb 6>
# p_2 = PHI <0B(4), p_1(5)>
q ={v} {CLOBBER};
return p_2;
}
which leads to: */
return p; /* { dg-bogus "may return address of local variable" "" { xfail *-*-* } } */
/* Whereas as -O2 the pass sees:
<bb 2>
p_5 = f ();
if (p_5 == 0B)
goto <bb 4>; [30.00%]
else
goto <bb 3>; [70.00%]
<bb 3>
# p_2 = PHI <0B(5), p_5(4)>
q ={v} {CLOBBER};
return p_2;
<bb 4>
p_5->i = i_6(D);
goto <bb 3>; [100.00%]
<bb 5>
q.i = i_6(D);
goto <bb 3>; [100.00%]
}
and no warning. */
}
...@@ -10,3 +10,5 @@ int main(void) ...@@ -10,3 +10,5 @@ int main(void)
int var, *p = &var; int var, *p = &var;
return (double)(uintptr_t)(p); return (double)(uintptr_t)(p);
} }
/* { dg-prune-output "-Wreturn-local-addr" } */
...@@ -16,3 +16,5 @@ foo (int a, int *b, int *c, int *d) ...@@ -16,3 +16,5 @@ foo (int a, int *b, int *c, int *d)
r[i] = 1; r[i] = 1;
return r; return r;
} }
/* { dg-prune-output "-Wreturn-local-addr" } */
...@@ -12,7 +12,7 @@ int *foo (int bogus, int n) ...@@ -12,7 +12,7 @@ int *foo (int bogus, int n)
p = &a[2]; p = &a[2];
else else
p = &i; p = &i;
return p; return p; /* { dg-warning "\\\[-Wreturn-local-addr" } */
} }
/* { dg-final { scan-tree-dump "Deleted dead store" "dse1" } } */ /* { dg-final { scan-tree-dump "Deleted dead store" "dse1" } } */
...@@ -41,3 +41,5 @@ f5 (void) ...@@ -41,3 +41,5 @@ f5 (void)
int c[64] = {}, d[64] = {}; int c[64] = {}, d[64] = {};
return (__UINTPTR_TYPE__) &c[64] != (__UINTPTR_TYPE__) &d[0]; return (__UINTPTR_TYPE__) &c[64] != (__UINTPTR_TYPE__) &d[0];
} }
/* { dg-prune-output "-Wreturn-local-addr" } */
...@@ -13,3 +13,5 @@ inline void *t (void) ...@@ -13,3 +13,5 @@ inline void *t (void)
{ {
return q (); /* { dg-message "called from here" } */ return q (); /* { dg-message "called from here" } */
} }
/* { dg-prune-output "-Wreturn-local-addr" } */
...@@ -23,6 +23,8 @@ a copy of the GCC Runtime Library Exception along with this program; ...@@ -23,6 +23,8 @@ a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */ <http://www.gnu.org/licenses/>. */
#pragma GCC optimize ("no-isolate-erroneous-paths-dereference")
/* powerpc 32-bit not supported. */ /* powerpc 32-bit not supported. */
#if !defined __powerpc__ || defined __powerpc64__ #if !defined __powerpc__ || defined __powerpc64__
......
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