blob: e309bdf041a029e2f2a98fc66aa82a3704db1465 [file] [log] [blame]
/* Verify that accessing freed objects by built-in functions is diagnosed.
{ dg-do compile }
{ dg-options "-Wall" } */
typedef __SIZE_TYPE__ size_t;
#if __cplusplus
# define EXTERN_C extern "C"
#else
# define EXTERN_C extern
#endif
EXTERN_C void free (void*);
EXTERN_C void* realloc (void*, size_t);
EXTERN_C void* memcpy (void*, const void*, size_t);
EXTERN_C char* strcpy (char*, const char*);
EXTERN_C size_t strlen (const char*);
void sink (void*, ...);
struct Member { char *p; char a[4]; };
int nowarn_strcpy_memptr (struct Member *p)
{
char *q = strcpy (p->p, p->a);
free (p);
return *q;
}
int nowarn_strlen_memptr (struct Member *p)
{
const char *q = p->p;
free (p);
return strlen (q);
}
int warn_strlen_memptr (struct Member *p)
{
free (p); // { dg-message "call to '\(void \)?free\(\\(void\\*\\)\)?'" "note" }
return strlen (p->p); // { dg-warning "-Wuse-after-free" }
}
int warn_strlen_memarray (struct Member *p)
{
{
free (p);
return strlen (p->a); // { dg-warning "-Wuse-after-free" }
}
{
char *q = p->a;
free (p);
return strlen (q); // { dg-warning "-Wuse-after-free" "pr??????" { xfail *-*-* } }
}
}
void* nowarn_realloc_success (void *p)
{
void *q = realloc (p, 7);
if (!q)
/* When realloc fails the original pointer remains valid. */
return p;
return q;
}
void* nowarn_realloc_equal (void *p, int *moved)
{
void *q = realloc (p, 7);
/* Verify that equality is not diagnosed at the default level
(it is diagnosed at level 3). */
*moved = !(p == q);
return q;
}
void* nowarn_realloc_unequal (void *p, int *moved)
{
void *q = realloc (p, 7);
/* Verify that inequality is not diagnosed at the default level
(it is diagnosed at level 3). */
*moved = p != q;
return q;
}
void* warn_realloc_relational (void *p, int *rel)
{
void *q = realloc (p, 7); // { dg-message "call to '\(void\\* \)?realloc\(\\(void\\*, size_t\\)\)?'" "note" }
/* Verify that all relational expressions are diagnosed at the default
level. */
rel[0] = (char*)p < (char*)q; // { dg-warning "-Wuse-after-free" }
rel[1] = (char*)p <= (char*)q; // { dg-warning "-Wuse-after-free" }
rel[2] = (char*)p >= (char*)q; // { dg-warning "-Wuse-after-free" }
rel[3] = (char*)p > (char*)q; // { dg-warning "-Wuse-after-free" }
return q;
}
void* warn_realloc_unchecked (void *p, int *moved)
{
void *q = realloc (p, 7); // { dg-message "call to '\(void\\* \)?realloc\(\\(void\\*, size_t\\)\)?'" "note" }
/* Use subtraction rather than inequality to trigger the warning
at the default level (equality is diagnosed only at level 3). */
*moved = (char*)p - (char*)q; // { dg-warning "-Wuse-after-free" }
return q;
}
void* nowarn_realloc_unchecked_copy (void *p1, void *p2, const void *s,
int n, int *x)
{
void *p3 = memcpy (p1, s, n);
void *p4 = realloc (p2, 7);
*x = p3 != p4;
return p4;
}
void* warn_realloc_unchecked_copy (void *p, const void *s, int n, int *moved)
{
void *p2 = memcpy (p, s, n);
void *q = realloc (p, 7); // { dg-message "call to '\(void\\* \)?realloc\(\\(void\\*, size_t\\)\)?'" "note" }
*moved = (char*)p2 - (char*)q; // { dg-warning "-Wuse-after-free" }
return q;
}
void* warn_realloc_failed (void *p, int *moved)
{
void *q = realloc (p, 7); // { dg-message "call to '\(void\\* \)?realloc\(\\(void\\*, size_t\\)\)?'" "note" }
if (q)
{
/* When realloc succeeds the original pointer is invalid. */
*moved = (char*)p - (char*)q; // { dg-warning "-Wuse-after-free" }
return q;
}
return p;
}
extern void *evp;
void* warn_realloc_extern (void *p, int *moved)
{
evp = realloc (p, 7);
if (evp)
{
/* When realloc succeeds the original pointer is invalid. */
*moved = (char*)p - (char*)evp; // { dg-warning "-Wuse-after-free" "escaped" }
return evp;
}
return p; // { dg-bogus "-Wuse-after-free" "safe use after realloc failure" { xfail *-*-* } }
}
struct A { void *p, *q; int moved; };
void* warn_realloc_arg (struct A *p)
{
p->q = realloc (p->p, 7);
if (p->q)
{
/* When realloc succeeds the original pointer is invalid. */
p->moved = p->p != p->q; // { dg-warning "-Wuse-after-free" "escaped" { xfail *-*-* } }
return p->q;
}
return p->p;
}