1 #include <stdlib.h> 2 3 typedef void *(*allocator_t) (size_t); 4 typedef void (*deallocator_t) (void *); 5 6 static allocator_t __attribute__((noinline)) get_malloc(void)7get_malloc (void) 8 { 9 return malloc; 10 } 11 12 static allocator_t __attribute__((noinline)) get_alloca(void)13get_alloca (void) 14 { 15 /* On e.g. Solaris, alloca is a macro so we can't take its address; 16 use __builtin_alloca instead. */ 17 return __builtin_alloca; 18 } 19 20 static deallocator_t __attribute__((noinline)) get_free(void)21get_free (void) 22 { 23 return free; 24 } 25 test_1(void * ptr)26void test_1 (void *ptr) 27 { 28 deallocator_t dealloc_fn = free; 29 dealloc_fn (ptr); /* { dg-message "first 'free' here" } */ 30 dealloc_fn (ptr); /* { dg-warning "double-'free'" } */ 31 } 32 test_2(void * ptr)33void test_2 (void *ptr) 34 { 35 deallocator_t dealloc_fn = get_free (); 36 dealloc_fn (ptr); /* { dg-message "first 'free' here" } */ 37 dealloc_fn (ptr); /* { dg-warning "double-'free'" } */ 38 } 39 40 static void __attribute__((noinline)) called_by_test_3(void * ptr,deallocator_t dealloc_fn)41called_by_test_3 (void *ptr, deallocator_t dealloc_fn) 42 { 43 dealloc_fn (ptr); /* { dg-warning "double-'free'" } */ 44 } 45 test_3(void * ptr)46void test_3 (void *ptr) 47 { 48 called_by_test_3 (ptr, free); 49 called_by_test_3 (ptr, free); 50 } 51 test_4(void)52int *test_4 (void) 53 { 54 allocator_t alloc_fn = get_malloc (); 55 int *ptr = alloc_fn (sizeof (int)); /* { dg-message "this call could return NULL" } */ 56 *ptr = 42; /* { dg-warning "dereference of possibly-NULL 'ptr'" } */ 57 return ptr; 58 } 59 test_5(void)60int *test_5 (void) 61 { 62 allocator_t alloc_fn = get_alloca (); 63 deallocator_t dealloc_fn = get_free (); 64 int *ptr = alloc_fn (sizeof (int)); /* { dg-message "pointer is from here" } */ 65 /* TODO: message should read "memory is allocated on the stack here". */ 66 dealloc_fn (ptr); /* { dg-warning "'free' of 'ptr' which points to memory not on the heap" } */ 67 } 68 69 static void __attribute__((noinline)) called_by_test_6a(void * ptr)70called_by_test_6a (void *ptr) 71 { 72 free (ptr); /* { dg-warning "double-'free'" "" { xfail *-*-* } } */ 73 } 74 75 static deallocator_t __attribute__((noinline)) called_by_test_6b(void)76called_by_test_6b (void) 77 { 78 return called_by_test_6a; 79 } 80 test_6(void * ptr)81void test_6 (void *ptr) 82 { 83 deallocator_t dealloc_fn = called_by_test_6b (); 84 dealloc_fn (ptr); 85 dealloc_fn (ptr); 86 } 87