/* Exercise basic cases of -Wuse-after-free without optimization. { dg-do compile } { dg-options "-O0 -Wall" } */ typedef __SIZE_TYPE__ size_t; #if __cplusplus # define EXTERN_C extern "C" #else # define EXTERN_C extern #endif EXTERN_C void* alloca (size_t); EXTERN_C void* calloc (size_t, size_t); EXTERN_C void* malloc (size_t); EXTERN_C void free (void*); void sink (void *); extern void* evp; extern void* evpa[]; extern int ei; struct List { struct List *next; }; void nowarn_free (void *vp, struct List *lp) { { free (vp); vp = 0; sink (vp); } { free (evp); evp = 0; sink (evp); } { free (evpa[0]); evpa[0] = 0; sink (evpa[0]); } { void *vp = evpa[0]; free (evpa[1]); sink (vp); } { void *p = evpa[1]; if (ei & 1) free (p); if (ei & 2) sink (p); } { struct List *next = lp->next; free (lp); free (next); } } void nowarn_free_arg (void *p, void *q) { free (p); if (q) free (q); } void nowarn_free_extern (void) { extern void *ep, *eq; free (ep); ep = eq; free (ep); } void nowarn_free_assign (void) { extern void *ep; free (ep); ep = 0; free (ep); } #pragma GCC diagnostic push /* Verify that -Wuse-after-free works with #pragma diagnostic. Note that the option name should not need to include a trailing =, even though it's a multi-level option. (specifying the level after the option, as in "-Wuse-after-free=2", doesn't work. */ #pragma GCC diagnostic ignored "-Wuse-after-free" void nowarn_double_free_suppressed (void *p) { free (p); free (p); } #pragma GCC diagnostic pop void warn_double_free_arg (void *p) { free (p); // { dg-message "call to '\(void \)?free\(\\(void\\*\\)\)?'" "note" } // Verify exactly one warning is issued. free (p); // { dg-warning "\\\-Wuse-after-free" } // { dg-bogus "\\\-Wuse-after-free" "duplicate warning" { target *-*-* } .-1 } } void warn_double_free_extern (void) { /* GCC assumes free() clobbers global memory and the warning is too simplistic to see through that assumption. */ extern void *ep, *eq; { eq = ep; free (ep); // { dg-message "call to 'free'" "pr??????" { xfail *-*-* } } free (eq); // { dg-warning "\\\-Wuse-after-free" "pr??????" { xfail *-*-* } } } } void warn_deref_after_free (int *p, int i) { int *q0 = p, *q1 = p + 1, *qi = p + i; free (p); // { dg-message "call to '\(void \)?free\(\\(void\\*\\)\)?'" "note" } *p = 0; // { dg-warning "\\\-Wuse-after-free" } *q0 = 0; // { dg-warning "\\\-Wuse-after-free" } *q1 = 0; // { dg-warning "\\\-Wuse-after-free" } *qi = 0; // { dg-warning "\\\-Wuse-after-free" } } void warn_array_ref_after_free (int *p, int i) { free (p); // { dg-message "call to '\(void \)?free\(\\(void\\*\\)\)?'" "note" } p[i] = 0; // { dg-warning "\\\-Wuse-after-free" } } void nowarn_free_list (struct List *head) { for (struct List *p = head, *q; p; p = q) { q = p->next; free (p); } } void warn_free_list (struct List *head) { struct List *p = head; for (; p; p = p->next) // { dg-warning "\\\[-Wuse-after-free" } free (p); // { dg-message "call to '\(void \)?free\(\\(void\\*\\)\)?'" "note" } } void warn_free (void *vp) { { free (vp); // { dg-message "call to '\(void \)?free\(\\(void\\*\\)\)?'" "note" } evp = vp; // { dg-warning "-Wuse-after-free" } evpa[0] = vp; // { dg-warning "-Wuse-after-free" } evpa[1] = evp; } }