xref: /llvm-project/clang/test/Analysis/malloc-annotations.cpp (revision ffe7950ebc62380c3afc7c71f454a1db3f6f5c76)
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)26 void 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)31 void 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)35 void 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)40 void af1_e(MemoryAllocator &Alloc, void **pp) {
41   *pp = Alloc.my_malloc(42); // no-warning
42 }
43 
af1_f(MemoryAllocator & Alloc,struct stuff * somestuff)44 void 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)49 void 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)54 void 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)60 void 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)66 void 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)73 void 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)81 void 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)87 void * 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)94 void * af5(MemoryAllocator &Alloc) {
95   void *p = Alloc.my_malloc(12);
96   Alloc.my_hold(p);
97   return p; // no-warning
98 }
99 
100