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)7 get_malloc (void)
8 {
9   return malloc;
10 }
11 
12 static allocator_t __attribute__((noinline))
get_alloca(void)13 get_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)21 get_free (void)
22 {
23   return free;
24 }
25 
test_1(void * ptr)26 void 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)33 void 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)41 called_by_test_3 (void *ptr, deallocator_t dealloc_fn)
42 {
43   dealloc_fn (ptr); /* { dg-warning "double-'free'" } */
44 }
45 
test_3(void * ptr)46 void test_3 (void *ptr)
47 {
48   called_by_test_3 (ptr, free);
49   called_by_test_3 (ptr, free);
50 }
51 
test_4(void)52 int *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)60 int *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)70 called_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)76 called_by_test_6b (void)
77 {
78   return called_by_test_6a;
79 }
80 
test_6(void * ptr)81 void test_6 (void *ptr)
82 {
83   deallocator_t dealloc_fn = called_by_test_6b ();
84   dealloc_fn (ptr);
85   dealloc_fn (ptr);
86 }
87