1 /* PR middle-end/94527 - Add an attribute that marks a function as freeing
2 an object
3 Verify that attribute malloc with one or two arguments has the expected
4 effect on diagnostics.
5 { dg-options "-Wall -ftrack-macro-expansion=0" } */
6
7 #define A(...) __attribute__ ((malloc (__VA_ARGS__), noipa))
8
9 typedef __SIZE_TYPE__ size_t;
10 typedef struct A A;
11 typedef struct B B;
12
13 /* A pointer returned by any of the four functions must be deallocated
14 either by dealloc() or by realloc_{A,B}(). */
15 A (__builtin_free) A* alloc_A (int);
16 A (__builtin_free) B* alloc_B (int);
17 A (__builtin_free) A* realloc_A (A *p, int n) { return p; }
18 A (__builtin_free) B* realloc_B (B *p, int n) { return p; }
19
20 A (realloc_A) A* alloc_A (int);
21 A (realloc_B) B* alloc_B (int);
22 A (realloc_A) A* realloc_A (A*, int);
23 A (realloc_B) B* realloc_B (B*, int);
24
25 void dealloc (void*);
26 A (dealloc) void* alloc (int);
27
28 void sink (void*);
29 void* source (void);
30
31 void test_alloc_A (void)
32 {
33 {
34 void *p = alloc_A (1);
35 p = realloc_A (p, 2);
36 __builtin_free (p);
37 }
38
39 {
40 void *p = alloc_A (1);
41 /* Verify that calling realloc doesn't trigger a warning even though
42 alloc_A is not directly associated with it. */
43 p = __builtin_realloc (p, 2);
44 sink (p);
45 }
46
47 {
48 void *p = alloc_A (1); // { dg-message "returned from 'alloc_A'" }
49 dealloc (p); // { dg-warning "'dealloc' called on pointer returned from a mismatched allocation function" }
50 }
51
52 {
53 /* Because alloc_A() and realloc_B() share free() as a deallocator
54 they must also be valid as each other's deallocators. */
55 void *p = alloc_A (1);
56 p = realloc_B ((B*)p, 2);
57 __builtin_free (p);
58 }
59
60 {
61 void *p = alloc_A (1);
62 p = realloc_A (p, 2);
63 p = __builtin_realloc (p, 3);
64 __builtin_free (p);
65 }
66 }
67
68
69 void test_realloc_A (void *ptr)
70 {
71 {
72 void *p = realloc_A (0, 1);
73 p = realloc_A (p, 2);
74 __builtin_free (p);
75 }
76
77 {
78 void *p = realloc_A (ptr, 2);
79 p = realloc_A (p, 2);
80 __builtin_free (p);
81 }
82
83 {
84 void *p = realloc_A (0, 3);
85 p = __builtin_realloc (p, 2);
86 sink (p);
87 }
88
89 {
90 void *p = realloc_A (0, 4); // { dg-message "returned from 'realloc_A'" }
91 dealloc (p); // { dg-warning "'dealloc' called on pointer returned from a mismatched allocation function" }
92 }
93
94 {
95 /* Because realloc_A() and realloc_B() share free() as a deallocator
96 they must also be valid as each other's deallocators. */
97 void *p = realloc_A (0, 5);
98 p = realloc_B ((B*)p, 2);
99 __builtin_free (p);
100 }
101
102 {
103 void *p = realloc_A (0, 6);
104 p = realloc_A ((A*)p, 2);
105 p = __builtin_realloc (p, 3);
106 __builtin_free (p);
107 }
108 }
109
110
111 void test_realloc (void)
112 {
113 extern void free (void*);
114 extern void* realloc (void*, size_t);
115
116 {
117 void *p = realloc (source (), 1);
118 p = realloc_A (p, 2);
119 __builtin_free (p);
120 }
121
122 {
123 void *p = realloc (source (), 2);
124 p = realloc_A (p, 2);
125 free (p);
126 }
127
128 {
129 void *p = realloc (source (), 3);
130 free (p);
131 }
132
133 {
134 void *p = realloc (source (), 4);
135 __builtin_free (p);
136 }
137
138 {
139 void *p = realloc (source (), 5); // { dg-message "returned from 'realloc'" }
140 dealloc (p); // { dg-warning "'dealloc' called on pointer returned from a mismatched allocation function" }
141 }
142 }