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__)))
8 
9 typedef struct FILE   FILE;
10 typedef __SIZE_TYPE__ size_t;
11 
12 void  free (void*);
13 void* malloc (size_t);
14 void* realloc (void*, size_t);
15 
16 /* Declare functions with the minimum attributes malloc how they're
17    likely going to be declared in <stdio.h>.  */
18                int   fclose (FILE*);
19 A (fclose)     FILE* fdopen (int);
20 A (fclose)     FILE* fopen (const char*, const char*);
21 A (fclose)     FILE* fmemopen(void *, size_t, const char *);
22 A (fclose)     FILE* freopen (const char*, const char*, FILE*);
23 A (freopen, 3) FILE* freopen (const char*, const char*, FILE*);
24 A (fclose)     FILE* tmpfile (void);
25 
26 A (fclose)     FILE* open_memstream (char**, size_t*);
27 A (fclose)     FILE* open_wmemstream (char**, size_t*);
28 
29                int   pclose (FILE*);
30 A (pclose)     FILE* popen (const char*, const char*);
31 
32                void  release (void*);
33 A (release)    FILE* acquire (void);
34 
35 void sink (FILE*);
36 
37 
nowarn_fdopen(void)38 void nowarn_fdopen (void)
39 {
40   {
41     FILE *q = fdopen (0);
42     if (!q)
43       return;
44 
45     fclose (q);
46   }
47 
48   {
49     FILE *q = fdopen (0);
50     if (!q)
51       return;
52 
53     q = freopen ("1", "r", q);
54     fclose (q);
55   }
56 
57   {
58     FILE *q = fdopen (0);
59     if (!q)
60       return;
61 
62     sink (q);
63   }
64 }
65 
66 
warn_fdopen(void)67 void warn_fdopen (void)
68 {
69   {
70     FILE *q = fdopen (0);     // { dg-message "returned from 'fdopen'" "note" }
71     sink (q);
72     release (q);              // { dg-warning "'release' called on pointer returned from a mismatched allocation function" }
73   }
74   {
75     FILE *q = fdopen (0);     // { dg-message "returned from 'fdopen'" "note" }
76     sink (q);
77     free (q);                 // { dg-warning "'free' called on pointer returned from a mismatched allocation function" }
78   }
79 
80   {
81     FILE *q = fdopen (0);     // { dg-message "returned from 'fdopen'" "note" }
82     sink (q);
83     q = realloc (q, 7);       // { dg-warning "'realloc' called on pointer returned from a mismatched allocation function" }
84     sink (q);
85   }
86 }
87 
88 
nowarn_fopen(void)89 void nowarn_fopen (void)
90 {
91   {
92     FILE *q = fopen ("1", "r");
93     sink (q);
94     fclose (q);
95   }
96 
97   {
98     FILE *q = fopen ("2", "r");
99     sink (q);
100     q = freopen ("3", "r", q);
101     sink (q);
102     fclose (q);
103   }
104 
105   {
106     FILE *q = fopen ("4", "r");
107     sink (q);
108   }
109 }
110 
111 
warn_fopen(void)112 void warn_fopen (void)
113 {
114   {
115     FILE *q = fopen ("1", "r");
116     sink (q);
117     release (q);              // { dg-warning "'release' called on pointer returned from a mismatched allocation function" }
118   }
119   {
120     FILE *q = fdopen (0);
121     sink (q);
122     free (q);                 // { dg-warning "'free' called on pointer returned from a mismatched allocation function" }
123   }
124 
125   {
126     FILE *q = fdopen (0);
127     sink (q);
128     q = realloc (q, 7);       // { dg-warning "'realloc' called on pointer returned from a mismatched allocation function" }
129     sink (q);
130   }
131 }
132 
133 
test_freopen(FILE * p[])134 void test_freopen (FILE *p[])
135 {
136   {
137     FILE *q = freopen ("1", "r", p[0]);
138     sink (q);
139     fclose (q);
140   }
141   {
142     FILE *q = freopen ("2", "r", p[1]);
143     sink (q);
144     q = freopen ("3", "r", q);
145     sink (q);
146     fclose (q);
147   }
148 
149   {
150     FILE *q;
151     q = freopen ("3", "r", p[2]); // { dg-message "returned from 'freopen'" }
152     sink (q);
153     q = realloc (q, 7);       // { dg-warning "'realloc' called on pointer returned from a mismatched allocation function" }
154     sink (q);
155   }
156 }
157 
158 
test_tmpfile(void)159 void test_tmpfile (void)
160 {
161   {
162     FILE *p = tmpfile ();
163     sink (p);
164     fclose (p);
165   }
166 
167   {
168     FILE *p = tmpfile ();
169     sink (p);
170     p = freopen ("1", "r", p);
171     sink (p);
172     fclose (p);
173   }
174 
175   {
176     FILE *p = tmpfile ();     // { dg-message "returned from 'tmpfile'" "note" }
177     sink (p);
178     pclose (p);               // { dg-warning "'pclose' called on pointer returned from a mismatched allocation function" }
179   }
180 }
181 
182 
test_open_memstream(char ** bufp,size_t * sizep)183 void test_open_memstream (char **bufp, size_t *sizep)
184 {
185   {
186     FILE *p = open_memstream (bufp, sizep);
187     sink (p);
188     fclose (p);
189   }
190 
191   {
192     FILE *p = open_memstream (bufp, sizep);
193     sink (p);
194     p = freopen ("1", "r", p);
195     sink (p);
196     fclose (p);
197   }
198 
199   {
200     FILE *p;
201     p = open_memstream (bufp, sizep);   // { dg-message "returned from 'open_memstream'" "note" }
202     sink (p);
203     pclose (p);               // { dg-warning "'pclose' called on pointer returned from a mismatched allocation function" }
204   }
205 
206   {
207     FILE *p;
208     p = open_memstream (bufp, sizep);   // { dg-message "returned from 'open_memstream'" "note" }
209     sink (p);
210     free (p);                 // { dg-warning "'free' called on pointer returned from a mismatched allocation function" }
211   }
212 
213   {
214     FILE *p;
215     p = open_memstream (bufp, sizep);   // { dg-message "returned from 'open_memstream'" "note" }
216     sink (p);
217     release (p);              // { dg-warning "'release' called on pointer returned from a mismatched allocation function" }
218   }
219 }
220 
221 
test_open_wmemstream(char ** bufp,size_t * sizep)222 void test_open_wmemstream (char **bufp, size_t *sizep)
223 {
224   {
225     FILE *p = open_wmemstream (bufp, sizep);
226     sink (p);
227     fclose (p);
228   }
229 
230   {
231     FILE *p = open_wmemstream (bufp, sizep);
232     sink (p);
233     p = freopen ("1", "r", p);
234     sink (p);
235     fclose (p);
236   }
237 
238   {
239     FILE *p;
240     p = open_wmemstream (bufp, sizep);  // { dg-message "returned from 'open_wmemstream'" "note" }
241     sink (p);
242     pclose (p);               // { dg-warning "'pclose' called on pointer returned from a mismatched allocation function" }
243   }
244 
245   {
246     FILE *p;
247     p = open_wmemstream (bufp, sizep);  // { dg-message "returned from 'open_wmemstream'" "note" }
248     sink (p);
249     free (p);                 // { dg-warning "'free' called on pointer returned from a mismatched allocation function" }
250   }
251 
252   {
253     FILE *p;
254     p = open_wmemstream (bufp, sizep);  // { dg-message "returned from 'open_wmemstream'" "note" }
255     sink (p);
256     release (p);              // { dg-warning "'release' called on pointer returned from a mismatched allocation function" }
257   }
258 }
259 
260 
warn_malloc(void)261 void warn_malloc (void)
262 {
263   {
264     FILE *p = malloc (100);   // { dg-message "returned from 'malloc'" "note" }
265     sink (p);
266     fclose (p);               // { dg-warning "'fclose' called on pointer returned from a mismatched allocation function" }
267   }
268 
269   {
270     FILE *p = malloc (100);   // { dg-message "returned from 'malloc'" "note" }
271     sink (p);
272     p = freopen ("1", "r", p);// { dg-warning "'freopen' called on pointer returned from a mismatched allocation function" }
273   }
274 
275   {
276     FILE *p = malloc (100);   // { dg-message "returned from 'malloc'" "note" }
277     sink (p);
278     pclose (p);               // { dg-warning "'pclose' called on pointer returned from a mismatched allocation function" }
279   }
280 }
281 
282 
test_acquire(void)283 void test_acquire (void)
284 {
285   {
286     FILE *p = acquire ();
287     release (p);
288   }
289 
290   {
291     FILE *p = acquire ();
292     sink (p);
293     release (p);
294   }
295 
296   {
297     FILE *p = acquire ();     // { dg-message "returned from 'acquire'" "note" }
298     sink (p);
299     fclose (p);               // { dg-warning "'fclose' called on pointer returned from a mismatched allocation function" }
300   }
301 
302   {
303     FILE *p = acquire ();     // { dg-message "returned from 'acquire'" "note" }
304     sink (p);
305     pclose (p);               // { dg-warning "'pclose' called on pointer returned from a mismatched allocation function" }
306   }
307 
308   {
309     FILE *p = acquire ();     // { dg-message "returned from 'acquire'" "note" }
310     sink (p);
311     p = freopen ("1", "r", p);  // { dg-warning "'freopen' called on pointer returned from a mismatched allocation function" }
312     sink (p);
313   }
314 
315   {
316     FILE *p = acquire ();     // { dg-message "returned from 'acquire'" "note" }
317     sink (p);
318     free (p);               // { dg-warning "'free' called on pointer returned from a mismatched allocation function" }
319   }
320 
321   {
322     FILE *p = acquire ();     // { dg-message "returned from 'acquire'" "note" }
323     sink (p);
324     p = realloc (p, 123);     // { dg-warning "'realloc' called on pointer returned from a mismatched allocation function" }
325     sink (p);
326   }
327 }
328