1 // RUN: %clang_cc1 -analyze -analyzer-checker=core,cplusplus.NewDelete -std=c++11 -fblocks -verify %s 2 // RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.cplusplus.NewDeleteLeaks -DLEAKS -std=c++11 -fblocks -verify %s 3 #include "Inputs/system-header-simulator-cxx.h" 4 5 typedef __typeof__(sizeof(int)) size_t; 6 extern "C" void *malloc(size_t); 7 int *global; 8 9 //------------------ 10 // check for leaks 11 //------------------ 12 13 //----- Standard non-placement operators 14 void testGlobalOpNew() { 15 void *p = operator new(0); 16 } 17 #ifdef LEAKS 18 // expected-warning@-2{{Potential leak of memory pointed to by 'p'}} 19 #endif 20 21 void testGlobalOpNewArray() { 22 void *p = operator new[](0); 23 } 24 #ifdef LEAKS 25 // expected-warning@-2{{Potential leak of memory pointed to by 'p'}} 26 #endif 27 28 void testGlobalNewExpr() { 29 int *p = new int; 30 } 31 #ifdef LEAKS 32 // expected-warning@-2{{Potential leak of memory pointed to by 'p'}} 33 #endif 34 35 void testGlobalNewExprArray() { 36 int *p = new int[0]; 37 } 38 #ifdef LEAKS 39 // expected-warning@-2{{Potential leak of memory pointed to by 'p'}} 40 #endif 41 42 //----- Standard nothrow placement operators 43 void testGlobalNoThrowPlacementOpNewBeforeOverload() { 44 void *p = operator new(0, std::nothrow); 45 } 46 #ifdef LEAKS 47 // expected-warning@-2{{Potential leak of memory pointed to by 'p'}} 48 #endif 49 50 void testGlobalNoThrowPlacementExprNewBeforeOverload() { 51 int *p = new(std::nothrow) int; 52 } 53 #ifdef LEAKS 54 // expected-warning@-2{{Potential leak of memory pointed to by 'p'}} 55 #endif 56 57 //----- Standard pointer placement operators 58 void testGlobalPointerPlacementNew() { 59 int i; 60 61 void *p1 = operator new(0, &i); // no warn 62 63 void *p2 = operator new[](0, &i); // no warn 64 65 int *p3 = new(&i) int; // no warn 66 67 int *p4 = new(&i) int[0]; // no warn 68 } 69 70 //----- Other cases 71 void testNewMemoryIsInHeap() { 72 int *p = new int; 73 if (global != p) // condition is always true as 'p' wraps a heap region that 74 // is different from a region wrapped by 'global' 75 global = p; // pointer escapes 76 } 77 78 struct PtrWrapper { 79 int *x; 80 81 PtrWrapper(int *input) : x(input) {} 82 }; 83 84 void testNewInvalidationPlacement(PtrWrapper *w) { 85 // Ensure that we don't consider this a leak. 86 new (w) PtrWrapper(new int); // no warn 87 } 88 89 //--------------- 90 // other checks 91 //--------------- 92 93 class SomeClass { 94 public: 95 void f(int *p); 96 }; 97 98 void f(int *p1, int *p2 = 0, int *p3 = 0); 99 void g(SomeClass &c, ...); 100 101 void testUseFirstArgAfterDelete() { 102 int *p = new int; 103 delete p; 104 f(p); // expected-warning{{Use of memory after it is freed}} 105 } 106 107 void testUseMiddleArgAfterDelete(int *p) { 108 delete p; 109 f(0, p); // expected-warning{{Use of memory after it is freed}} 110 } 111 112 void testUseLastArgAfterDelete(int *p) { 113 delete p; 114 f(0, 0, p); // expected-warning{{Use of memory after it is freed}} 115 } 116 117 void testUseSeveralArgsAfterDelete(int *p) { 118 delete p; 119 f(p, p, p); // expected-warning{{Use of memory after it is freed}} 120 } 121 122 void testUseRefArgAfterDelete(SomeClass &c) { 123 delete &c; 124 g(c); // expected-warning{{Use of memory after it is freed}} 125 } 126 127 void testVariadicArgAfterDelete() { 128 SomeClass c; 129 int *p = new int; 130 delete p; 131 g(c, 0, p); // expected-warning{{Use of memory after it is freed}} 132 } 133 134 void testUseMethodArgAfterDelete(int *p) { 135 SomeClass *c = new SomeClass; 136 delete p; 137 c->f(p); // expected-warning{{Use of memory after it is freed}} 138 } 139 140 void testUseThisAfterDelete() { 141 SomeClass *c = new SomeClass; 142 delete c; 143 c->f(0); // expected-warning{{Use of memory after it is freed}} 144 } 145 146 void testDeleteAlloca() { 147 int *p = (int *)__builtin_alloca(sizeof(int)); 148 delete p; // expected-warning{{Memory allocated by alloca() should not be deallocated}} 149 } 150 151 void testDoubleDelete() { 152 int *p = new int; 153 delete p; 154 delete p; // expected-warning{{Attempt to free released memory}} 155 } 156 157 void testExprDeleteArg() { 158 int i; 159 delete &i; // expected-warning{{Argument to 'delete' is the address of the local variable 'i', which is not memory allocated by 'new'}} 160 } 161 162 void testExprDeleteArrArg() { 163 int i; 164 delete[] &i; // expected-warning{{Argument to 'delete[]' is the address of the local variable 'i', which is not memory allocated by 'new[]'}} 165 } 166 167 void testAllocDeallocNames() { 168 int *p = new(std::nothrow) int[1]; 169 delete[] (++p); // expected-warning{{Argument to 'delete[]' is offset by 4 bytes from the start of memory allocated by 'new[]'}} 170 } 171 172 //-------------------------------- 173 // Test escape of newed const pointer. Note, a const pointer can be deleted. 174 //-------------------------------- 175 struct StWithConstPtr { 176 const int *memp; 177 }; 178 void escape(const int &x); 179 void escapeStruct(const StWithConstPtr &x); 180 void escapePtr(const StWithConstPtr *x); 181 void escapeVoidPtr(const void *x); 182 183 void testConstEscape() { 184 int *p = new int(1); 185 escape(*p); 186 } // no-warning 187 188 void testConstEscapeStruct() { 189 StWithConstPtr *St = new StWithConstPtr(); 190 escapeStruct(*St); 191 } // no-warning 192 193 void testConstEscapeStructPtr() { 194 StWithConstPtr *St = new StWithConstPtr(); 195 escapePtr(St); 196 } // no-warning 197 198 void testConstEscapeMember() { 199 StWithConstPtr St; 200 St.memp = new int(2); 201 escapeVoidPtr(St.memp); 202 } // no-warning 203 204 void testConstEscapePlacementNew() { 205 int *x = (int *)malloc(sizeof(int)); 206 void *y = new (x) int; 207 escapeVoidPtr(y); 208 } // no-warning 209 210 211 namespace reference_count { 212 class control_block { 213 unsigned count; 214 public: 215 control_block() : count(0) {} 216 void retain() { ++count; } 217 int release() { return --count; } 218 }; 219 220 template <typename T> 221 class shared_ptr { 222 T *p; 223 control_block *control; 224 225 public: 226 shared_ptr() : p(0), control(0) {} 227 explicit shared_ptr(T *p) : p(p), control(new control_block) { 228 control->retain(); 229 } 230 shared_ptr(shared_ptr &other) : p(other.p), control(other.control) { 231 if (control) 232 control->retain(); 233 } 234 ~shared_ptr() { 235 if (control && control->release() == 0) { 236 delete p; 237 delete control; 238 } 239 }; 240 241 T &operator *() { 242 return *p; 243 }; 244 245 void swap(shared_ptr &other) { 246 T *tmp = p; 247 p = other.p; 248 other.p = tmp; 249 250 control_block *ctrlTmp = control; 251 control = other.control; 252 other.control = ctrlTmp; 253 } 254 }; 255 256 void testSingle() { 257 shared_ptr<int> a(new int); 258 *a = 1; 259 } 260 261 void testDouble() { 262 shared_ptr<int> a(new int); 263 shared_ptr<int> b = a; 264 *a = 1; 265 } 266 267 void testInvalidated() { 268 shared_ptr<int> a(new int); 269 shared_ptr<int> b = a; 270 *a = 1; 271 272 extern void use(shared_ptr<int> &); 273 use(b); 274 } 275 276 void testNestedScope() { 277 shared_ptr<int> a(new int); 278 { 279 shared_ptr<int> b = a; 280 } 281 *a = 1; 282 } 283 284 void testSwap() { 285 shared_ptr<int> a(new int); 286 shared_ptr<int> b; 287 shared_ptr<int> c = a; 288 shared_ptr<int>(c).swap(b); 289 } 290 291 void testUseAfterFree() { 292 int *p = new int; 293 { 294 shared_ptr<int> a(p); 295 shared_ptr<int> b = a; 296 } 297 298 // FIXME: We should get a warning here, but we don't because we've 299 // conservatively modeled ~shared_ptr. 300 *p = 1; 301 } 302 } 303 304