| /* Exercise -Wuse-after-free with user-defined deallocators. |
| { 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 |
| |
| #define A(...) __attribute__ ((malloc (__VA_ARGS__))) |
| |
| EXTERN_C void free (void *); |
| EXTERN_C void* realloc (void *, size_t); |
| |
| typedef struct List { struct List *next; } List; |
| |
| // User-defined allocator/deallocator just like like realloc and free. |
| extern void list_free (List *); |
| extern List* list_realloc (size_t, List *); |
| extern A (list_realloc, 2) List* list_realloc (size_t, List *); |
| extern A (list_free, 1) List* list_realloc (size_t, List *); |
| |
| |
| void sink (void *); |
| |
| extern int ei; |
| extern List *elp, *elpa[]; |
| |
| void nowarn_list_free (struct List *lp) |
| { |
| { |
| list_free (lp); |
| lp = 0; |
| sink (lp); |
| } |
| { |
| list_free (elp); |
| elp = 0; |
| sink (elp); |
| } |
| { |
| list_free (elpa[0]); |
| elpa[0] = 0; |
| sink (elpa[0]); |
| } |
| { |
| void *vp = elpa[0]; |
| list_free (elpa[0]); |
| sink (vp); |
| } |
| { |
| List *p = elpa[1]; |
| if (ei & 1) |
| list_free (p); |
| if (ei & 2) |
| sink (p); |
| } |
| { |
| struct List *next = lp->next; |
| list_free (lp); |
| list_free (next); |
| } |
| } |
| |
| |
| void nowarn_list_free_list (List *head) |
| { |
| for (List *p = head, *q; p; p = q) |
| { |
| q = p->next; |
| list_free (p); |
| } |
| } |
| |
| void warn_list_free_list (List *head) |
| { |
| List *p = head; |
| for (; p; p = p->next) // { dg-warning "\\\[-Wuse-after-free" } |
| list_free (p); // { dg-message "call to '\(void \)?list_free\(\\(List\\*\\)\)?'" "note" } |
| } |