1 // RUN: %clang_analyze_cc1 -verify \ 2 // RUN: -analyzer-checker=core \ 3 // RUN: -analyzer-checker=alpha.deadcode.UnreachableCode \ 4 // RUN: -analyzer-checker=alpha.core.CastSize \ 5 // RUN: -analyzer-checker=unix.Malloc \ 6 // RUN: -analyzer-config unix.DynamicMemoryModeling:Optimistic=true %s 7 8 typedef __typeof(sizeof(int)) size_t; 9 void *malloc(size_t); 10 void free(void *); 11 12 struct MemoryAllocator { 13 void __attribute((ownership_returns(malloc))) * my_malloc(size_t); 14 void __attribute((ownership_takes(malloc, 2))) my_free(void *); 15 void __attribute((ownership_holds(malloc, 2))) my_hold(void *); 16 }; 17 18 void *myglobalpointer; 19 20 struct stuff { 21 void *somefield; 22 }; 23 24 struct stuff myglobalstuff; 25 af1(MemoryAllocator & Alloc)26void af1(MemoryAllocator &Alloc) { 27 void *p = Alloc.my_malloc(12); 28 return; // expected-warning{{Potential leak of memory pointed to by}} 29 } 30 af1_b(MemoryAllocator & Alloc)31void af1_b(MemoryAllocator &Alloc) { 32 void *p = Alloc.my_malloc(12); 33 } // expected-warning{{Potential leak of memory pointed to by}} 34 af1_c(MemoryAllocator & Alloc)35void af1_c(MemoryAllocator &Alloc) { 36 myglobalpointer = Alloc.my_malloc(12); // no-warning 37 } 38 39 // Test that we can pass out allocated memory via pointer-to-pointer. af1_e(MemoryAllocator & Alloc,void ** pp)40void af1_e(MemoryAllocator &Alloc, void **pp) { 41 *pp = Alloc.my_malloc(42); // no-warning 42 } 43 af1_f(MemoryAllocator & Alloc,struct stuff * somestuff)44void af1_f(MemoryAllocator &Alloc, struct stuff *somestuff) { 45 somestuff->somefield = Alloc.my_malloc(12); // no-warning 46 } 47 48 // Allocating memory for a field via multiple indirections to our arguments is OK. af1_g(MemoryAllocator & Alloc,struct stuff ** pps)49void af1_g(MemoryAllocator &Alloc, struct stuff **pps) { 50 *pps = (struct stuff *)Alloc.my_malloc(sizeof(struct stuff)); // no-warning 51 (*pps)->somefield = Alloc.my_malloc(42); // no-warning 52 } 53 af2(MemoryAllocator & Alloc)54void af2(MemoryAllocator &Alloc) { 55 void *p = Alloc.my_malloc(12); 56 Alloc.my_free(p); 57 free(p); // expected-warning{{Attempt to free released memory}} 58 } 59 af2b(MemoryAllocator & Alloc)60void af2b(MemoryAllocator &Alloc) { 61 void *p = Alloc.my_malloc(12); 62 free(p); 63 Alloc.my_free(p); // expected-warning{{Attempt to free released memory}} 64 } 65 af2c(MemoryAllocator & Alloc)66void af2c(MemoryAllocator &Alloc) { 67 void *p = Alloc.my_malloc(12); 68 free(p); 69 Alloc.my_hold(p); // expected-warning{{Attempt to free released memory}} 70 } 71 72 // No leak if malloc returns null. af2e(MemoryAllocator & Alloc)73void af2e(MemoryAllocator &Alloc) { 74 void *p = Alloc.my_malloc(12); 75 if (!p) 76 return; // no-warning 77 free(p); // no-warning 78 } 79 80 // This case inflicts a possible double-free. af3(MemoryAllocator & Alloc)81void af3(MemoryAllocator &Alloc) { 82 void *p = Alloc.my_malloc(12); 83 Alloc.my_hold(p); 84 free(p); // expected-warning{{Attempt to free non-owned memory}} 85 } 86 af4(MemoryAllocator & Alloc)87void * af4(MemoryAllocator &Alloc) { 88 void *p = Alloc.my_malloc(12); 89 Alloc.my_free(p); 90 return p; // expected-warning{{Use of memory after it is freed}} 91 } 92 93 // This case is (possibly) ok, be conservative af5(MemoryAllocator & Alloc)94void * af5(MemoryAllocator &Alloc) { 95 void *p = Alloc.my_malloc(12); 96 Alloc.my_hold(p); 97 return p; // no-warning 98 } 99 100