| /* 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; |
| } |