1 /* { dg-require-effective-target alloca } */
2 
3 #include <stdlib.h>
4 
5 extern int foo (void);
6 extern int bar (void);
7 extern void could_free (void *);
8 extern void cant_free (const void *); /* since it's a const void *.  */
9 
test_1(void)10 void test_1 (void)
11 {
12   void *ptr = malloc (1024);
13   free (ptr);
14   free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */
15 }
16 
test_2(void * ptr)17 void test_2 (void *ptr)
18 {
19   free (ptr);
20   free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */
21 }
22 
test_2a(void * ptr)23 void test_2a (void *ptr)
24 {
25   __builtin_free (ptr);
26   __builtin_free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */
27 }
28 
test_3(void)29 int *test_3 (void)
30 {
31   int *ptr = (int *)malloc (sizeof (int));
32   *ptr = 42; /* { dg-warning "dereference of possibly-NULL 'ptr' \\\[CWE-690\\\]" } */
33   return ptr;
34 }
35 
test_3a(void)36 int *test_3a (void)
37 {
38   int *ptr = (int *)__builtin_malloc (sizeof (int));
39   *ptr = 42; /* { dg-warning "dereference of possibly-NULL 'ptr' \\\[CWE-690\\\]" } */
40   return ptr;
41 }
42 
test_4(void)43 int *test_4 (void)
44 {
45   int *ptr = (int *)malloc (sizeof (int));
46   if (ptr)
47     *ptr = 42;
48   else
49     *ptr = 43; /* { dg-warning "dereference of NULL 'ptr' \\\[CWE-476\\\]" } */
50   return ptr;
51 }
52 
test_5(int * ptr)53 int test_5 (int *ptr)
54 {
55   free (ptr);
56   return *ptr; /* { dg-warning "use after 'free' of 'ptr'" } */
57 }
58 
test_6(void * ptr)59 void test_6 (void *ptr)
60 {
61   void *q;
62   q = ptr;
63   free (ptr);
64   free (q); /* { dg-warning "double-'free' of 'q'" } */
65   /* The above case requires us to handle equivalence classes in
66      state transitions.  */
67 }
68 
test_7(void)69 void test_7 (void)
70 {
71   void *ptr = malloc(4096);
72   if (!ptr)
73     return;
74   __builtin_memset(ptr, 0, 4096);
75   free(ptr);
76 }
77 
test_8(void)78 void *test_8 (void)
79 {
80   void *ptr = malloc(4096);
81   if (!ptr)
82     return NULL;
83   __builtin_memset(ptr, 0, 4096);
84   return ptr;
85   /* This needs phi nodes to affect equivalence classes, or we get a false report
86      of a leak.  */
87 }
88 
test_9(void)89 void test_9 (void)
90 {
91   void *ptr = malloc (1024);
92 
93   int i;
94   for (i = 0; i < 1024; i++)
95     free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */
96 }
97 
test_10(void)98 void test_10 (void)
99 {
100   void *ptr = malloc (1024);
101 
102   int i;
103   for (i = 0; i < 1024; i++)
104     foo ();
105 
106   free (ptr);
107   free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */
108 }
109 
test_11(void)110 void test_11 (void)
111 {
112   void *ptr = malloc (1024);
113 
114   while (foo ())
115     bar ();
116 
117   free (ptr);
118   free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */
119 }
120 
test_12(void)121 void test_12 (void)
122 {
123   void *ptr = malloc (1024);
124 
125   while (1)
126     {
127       free (ptr);
128       free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */
129     }
130 }
131 
test_13(void)132 void test_13 (void)
133 {
134   void *p = malloc (1024); /* { dg-message "allocated here" } */
135   void *q = malloc (1024);
136 
137   foo ();
138   if (!q)
139     {
140       free (q);
141       return; /* { dg-warning "leak of 'p'" } */
142     }
143   bar ();
144   free (q);
145   free (p);
146 }
147 
test_14(void)148 void test_14 (void)
149 {
150   void *p, *q;
151   p = malloc (1024);
152   if (!p)
153     return;
154 
155   q = malloc (1024);
156   if (!q)
157     {
158       free (p);
159       free (q);
160       /* oops: missing "return".  */
161     }
162   bar ();
163   free (q); /* Although this looks like a double-'free' of q,
164 	       it's known to be NULL for the case where free is
165 	       called twice on it.  */
166   free (p); /* { dg-warning "double-'free' of 'p'" } */
167 }
168 
test_15(void)169 void test_15 (void)
170 {
171   void *p = NULL, *q = NULL;
172 
173   p = malloc (1024);
174   if (!p)
175     goto fail;
176 
177   foo ();
178 
179   q = malloc (1024);
180   if (!q)
181     goto fail;
182 
183   bar ();
184 
185  fail:
186   free (q);
187   free (p);
188 }
189 
test_16(void)190 void test_16 (void)
191 {
192   void *p, *q;
193 
194   p = malloc (1024);
195   if (!p)
196     goto fail;
197 
198   foo ();
199 
200   q = malloc (1024);
201   if (!q)
202     goto fail;
203 
204   bar ();
205 
206  fail:
207   free (q); /* { dg-warning "free of uninitialized 'q'" "" { xfail *-*-* } } */
208   /* TODO(xfail): implement uninitialized detection.  */
209   free (p);
210 }
211 
test_17(void)212 void test_17 (void)
213 {
214   void *ptr = malloc (1024); /* { dg-message "allocated here" } */
215 } /* { dg-warning "leak of 'ptr'" } */
216 
test_18(void)217 void test_18 (void)
218 {
219   void *ptr = malloc (64); /* { dg-message "allocated here" } */
220   ptr = NULL; /* { dg-warning "leak of 'ptr'" } */
221 }
222 
test_19(void)223 void test_19 (void)
224 {
225   void *ptr = malloc (64);
226   free (ptr);
227   ptr = NULL;
228   free (ptr);
229 }
230 
231 void *global_ptr_20;
232 
test_20(void)233 void test_20 (void)
234 {
235   global_ptr_20 = malloc (1024);
236 }
237 
test_21(int i)238 int *test_21 (int i)
239 {
240   int *ptr = malloc (sizeof (int));
241   if (!ptr)
242     abort ();
243   *ptr = i;
244   return ptr;
245 }
246 
test_22(void)247 void test_22 (void)
248 {
249   void *ptr = malloc (1024);
250 
251   int i;
252   for (i = 5; i < 10; i++)
253     foo ();
254 
255   free (ptr);
256   free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */
257 }
258 
test_23(int n)259 int *test_23 (int n)
260 {
261   int *ptr = (int *)calloc (n, sizeof (int));
262   ptr[0] = 42; /* { dg-warning "dereference of possibly-NULL 'ptr' \\\[CWE-690\\\]" } */
263   return ptr;
264 }
265 
test_23a(int n)266 int *test_23a (int n)
267 {
268   int *ptr = (int *)__builtin_calloc (n, sizeof (int));
269   ptr[0] = 42; /* { dg-warning "dereference of possibly-NULL 'ptr' \\\[CWE-690\\\]" } */
270   return ptr;
271 }
272 
test_24(void)273 int test_24 (void)
274 {
275   void *ptr = __builtin_alloca (sizeof (int)); /* { dg-message "memory is allocated on the stack here" } */
276   free (ptr); /* { dg-warning "'free' of memory allocated on the stack by 'alloca' \\('ptr'\\) will corrupt the heap \\\[CWE-590\\\]" } */
277 }
278 
test_25(void)279 int test_25 (void)
280 {
281   char tmp[100];
282   void *p = tmp; /* { dg-message "pointer is from here" } */
283   free (p); /* { dg-warning "'free' of 'p' which points to memory not on the heap \\\[CWE-590\\\]" } */
284   /* TODO: more precise messages here.  */
285 }
286 
287 char global_buffer[100];
288 
test_26(void)289 int test_26 (void)
290 {
291   void *p = global_buffer; /* { dg-message "pointer is from here" } */
292   free (p); /* { dg-warning "'free' of 'p' which points to memory not on the heap \\\[CWE-590\\\]" } */
293   /* TODO: more precise messages here.  */
294 }
295 
296 struct coord {
297   float x;
298   float y;
299 };
300 
test_27(void)301 struct coord *test_27 (void)
302 {
303   struct coord *p = (struct coord *) malloc (sizeof (struct coord)); /* { dg-message "this call could return NULL" } */
304   p->x = 0.f;  /* { dg-warning "dereference of possibly-NULL 'p' \\\[CWE-690\\\]" } */
305 
306   /* Only the first such usage should be reported: */
307   p->y = 0.f;
308 
309   return p;
310 }
311 
test_28(void)312 struct coord *test_28 (void)
313 {
314   struct coord *p = NULL;
315   p->x = 0.f; /* { dg-warning "dereference of NULL 'p' \\\[CWE-476\\\]" } */
316 
317   /* Only the first such usage should be reported: */
318   p->y = 0.f;
319 
320   return p;
321 }
322 
323 struct link
324 {
325   struct link *m_ptr;
326 };
327 
test_29(void)328 struct link *test_29 (void)
329 {
330   struct link *res = (struct link *)malloc (sizeof (struct link));
331   if (!res)
332     return NULL;
333   res->m_ptr = (struct link *)malloc (sizeof (struct link));
334   return res;
335 }
336 
test_29a(void)337 struct link *test_29a (void)
338 {
339   struct link *res = (struct link *)malloc (sizeof (struct link));
340   if (!res)
341     return NULL;
342   res->m_ptr = (struct link *)malloc (sizeof (struct link));
343   if (!res->m_ptr)
344     {
345       free (res);
346       return NULL;
347     }
348   res->m_ptr->m_ptr = (struct link *)malloc (sizeof (struct link));
349   return res;
350 }
351 
352 /* Without consolidation by EC, this one shows two leaks:
353      warning: leak of '<unknown>'
354      warning: leak of 'tmp.m_ptr'
355    We should only show the latter (favoring the most user-readable
356    expression in the equivalence class).  */
test_30(void)357 void test_30 (void)
358 {
359   struct link tmp;
360   tmp.m_ptr = (struct link *)malloc (sizeof (struct link)); /* { dg-message "allocated here" } */
361 } /* { dg-warning "leak of 'tmp.m_ptr'" } */
362 /* { dg-bogus "leak of '<unknown>'" "leak of unknown" { target *-*-* } .-1 } */
363 
test_31(void)364 void test_31 (void)
365 {
366   struct link tmp;
367   void *ptr = malloc (sizeof (struct link)); /* { dg-message "allocated here" } */
368   tmp.m_ptr = (struct link *)ptr;
369 } /* { dg-warning "leak of 'ptr'" } */
370 /* { dg-bogus "leak of 'tmp.m_ptr'" "" { target *-*-* } .-1 } */
371 
test_32(void)372 void test_32 (void)
373 {
374   void *ptr = malloc (1024);
375   could_free (ptr);
376 } /* { dg-bogus "leak" } */
377 
test_33(void)378 void test_33 (void)
379 {
380   void *ptr = malloc (1024); /* { dg-message "allocated here" } */
381   cant_free (ptr);
382 } /* { dg-warning "leak of 'ptr'" } */
383 
test_34(void)384 void test_34 (void)
385 {
386   float *q;
387   struct coord *p = malloc (sizeof (struct coord));
388   if (!p)
389     return;
390   p->x = 0.0f;
391   q = &p->x;
392   free (p);
393   *q = 1.0f; /* { dg-warning "use after 'free' of 'q'" } */
394 };
395 
test_35(void)396 int test_35 (void)
397 {
398   void *ptr = malloc(4096);
399   if (!ptr)
400     return -1;
401   __builtin_memset(ptr, 0, 4096);
402   free(ptr);
403   return 0;
404 }
405 
test_36(void)406 void test_36 (void)
407 {
408   void *ptr = malloc(4096);
409   if (!ptr)
410     return;
411   __builtin_memset(ptr, 0, 4096);
412   free(ptr);
413 }
414 
test_37a(void)415 void *test_37a (void)
416 {
417   void *ptr = malloc(4096); /* { dg-message "this call could return NULL" } */
418   __builtin_memset(ptr, 0, 4096); /* { dg-warning "use of possibly-NULL 'ptr' where non-null expected \\\[CWE-690\\\]" } */
419   return ptr;
420 }
421 
test_37b(void)422 int test_37b (void)
423 {
424   void *p = malloc(4096);
425   void *q = malloc(4096); /* { dg-message "this call could return NULL" } */
426   if (p) {
427     __builtin_memset(p, 0, 4096); /* Not a bug: checked */
428   } else {
429     __builtin_memset(q, 0, 4096); /* { dg-warning "use of possibly-NULL 'q' where non-null expected \\\[CWE-690\\\]" } */
430   }
431   free(p);
432   free(q);
433   return 0;
434 }
435 
436 extern void might_use_ptr (void *ptr);
437 
test_38(int i)438 void test_38(int i)
439 {
440   void *p;
441 
442   p = malloc(1024);
443   if (p) {
444     free(p);
445     might_use_ptr(p); /* { dg-warning "use after 'free' of 'p'" "" { xfail *-*-* } } */
446     // TODO: xfail
447   }
448 }
449 
450 int *
test_39(int i)451 test_39 (int i)
452 {
453   int *p = (int*)malloc(sizeof(int*)); /* { dg-message "this call could return NULL" } */
454   *p = i; /* { dg-warning "dereference of possibly-NULL 'p' \\\[CWE-690\\\]" } */
455   return p;
456 }
457 
458 int *
test_40(int i)459 test_40 (int i)
460 {
461   int *p = (int*)malloc(sizeof(int*));
462   i = *p; /* { dg-warning "dereference of possibly-NULL 'p' \\\[CWE-690\\\]" } */
463   /* TODO: (it's also uninitialized) */
464   return p;
465 }
466 
467 char *
test_41(int flag)468 test_41 (int flag)
469 {
470   char *buffer;
471 
472   if (flag) {
473     buffer = (char*)malloc(4096);
474   } else {
475     buffer = NULL;
476   }
477 
478   buffer[0] = 'a'; /* { dg-warning "dereference of possibly-NULL 'buffer' \\\[CWE-690\\\]" "possibly-NULL" } */
479   /* { dg-warning "dereference of NULL 'buffer' \\\[CWE-476\\\]" "NULL" { target *-*-* } .-1 } */
480 
481   return buffer;
482 }
483 
test_42a(void)484 void test_42a (void)
485 {
486   void *p = malloc (1024); /* { dg-message "allocated here" } */
487   free (p + 64); /* this could well corrupt the heap.  */
488   /* TODO: ^^^ we should warn about this.  */
489 } /* { dg-warning "leak of 'p'" } */
490 /* TODO: presumably we should complain about the bogus free, but then
491    maybe not complain about the leak.  */
492 // CWE-761: Free of Pointer not at Start of Buffer
493 
test_42b(void)494 void test_42b (void)
495 {
496   void *p = malloc (1024); /* { dg-message "allocated here" } */
497   free (p - 64); /* this could well corrupt the heap.  */
498   /* TODO: ^^^ we should warn about this.  */
499 } /* { dg-warning "leak of 'p'" } */
500 /* TODO: presumably we should complain about the bogus free, but then
501    maybe not complain about the leak.  */
502 // CWE-761: Free of Pointer not at Start of Buffer
503 
test_42c(void)504 void test_42c (void)
505 {
506   void *p = malloc (1024);
507   void *q = p + 64;
508   free (q - 64); /* this is probably OK.  */
509 } /* { dg-bogus "leak of 'p'" } */
510 
511 void *
test_42d(void)512 test_42d (void)
513 {
514   void *p = malloc (1024);
515   void *q = p + 64;
516   return q;
517 } /* { dg-bogus "leak of 'p'" } */
518 
519 #if 0
520 void test_31 (void *p)
521 {
522   void *q = realloc (p, 1024);
523   free (p); /* FIXME: this is a double-'free'.  */
524   free (q);
525 }
526 
527 void test_32 (void)
528 {
529   void *p = malloc (64);
530   p = realloc (p, 1024); /* FIXME: this leaks if it fails.  */
531   free (p);
532 }
533 #endif
534 
535 struct link global_link;
536 
test_43(void)537 void test_43 (void)
538 {
539   global_link.m_ptr = malloc (sizeof (struct link)); /* { dg-message "allocated here" } */
540   global_link.m_ptr = NULL; /* { dg-warning "leak of 'global_link.m_ptr'" } */
541 }
542 
543 struct link *global_ptr;
544 
test_44(void)545 void test_44 (void)
546 {
547   global_ptr = malloc (sizeof (struct link));
548   if (!global_ptr)
549     return;
550   global_ptr->m_ptr = malloc (sizeof (struct link)); /* { dg-message "allocated here" } */
551   free (global_ptr); /* { dg-warning "leak of '<unknown>'" } */
552   /* TODO: should be more precise than just '<unknown>'.  */
553 }
554 
555 extern void might_take_ownership (void *ptr);
556 
test_45(void)557 void test_45 (void)
558 {
559   void *p = malloc (1024);
560   might_take_ownership (p);
561 }
562 
test_46(void)563 void test_46 (void)
564 {
565   struct link *p = (struct link *)malloc (sizeof (struct link));
566   if (!p)
567     return;
568   struct link *q = (struct link *)malloc (sizeof (struct link));
569   p->m_ptr = q;
570   might_take_ownership (p);
571 }
572 
573 extern int maybe_alloc (char **);
574 
test_47(void)575 int test_47 (void)
576 {
577   char *p = ((void *)0);
578   int p_size = 0;
579 
580   p = malloc (16);
581   if (p) {
582     free (p);
583   } else {
584     int retval = maybe_alloc (&p); /* this might write to "p".  */
585     if (retval)
586       return (retval);
587     p_size = __builtin_strlen(p); /* { dg-bogus "non-null expected" } */
588     free (p);
589   }
590   return p_size;
591 }
592 
test_48(void)593 void test_48 (void)
594 {
595   int *p = NULL; /* { dg-message "'p' is NULL" } */
596   *p = 1; /* { dg-warning "dereference of NULL 'p' \\\[CWE-476\\\]" } */
597 }
598 
599 /* As test_48, but where the assignment of NULL is not at the start of a BB.  */
600 
test_49(int i)601 int test_49 (int i)
602 {
603   int *p;
604   int x;
605 
606   x = i * 2;
607   p = NULL; /* { dg-message "'p' is NULL" } */
608   *p = 1; /* { dg-warning "dereference of NULL 'p' \\\[CWE-476\\\]" } */
609   return x;
610 }
611 
612 /* { dg-prune-output "\\\[-Wfree-nonheap-object" } */
613