1 // RUN: %clang_analyze_cc1 -std=c++11 -fblocks %s \ 2 // RUN: -verify=expected,newdelete \ 3 // RUN: -analyzer-checker=core \ 4 // RUN: -analyzer-checker=cplusplus.NewDelete 5 // 6 // RUN: %clang_analyze_cc1 -DLEAKS -std=c++11 -fblocks %s \ 7 // RUN: -verify=expected,newdelete,leak \ 8 // RUN: -analyzer-checker=core \ 9 // RUN: -analyzer-checker=cplusplus.NewDelete \ 10 // RUN: -analyzer-checker=cplusplus.NewDeleteLeaks 11 // 12 // RUN: %clang_analyze_cc1 -std=c++11 -fblocks -verify %s \ 13 // RUN: -verify=expected,leak \ 14 // RUN: -analyzer-checker=core \ 15 // RUN: -analyzer-checker=cplusplus.NewDeleteLeaks 16 // 17 // RUN: %clang_analyze_cc1 -std=c++17 -fblocks %s \ 18 // RUN: -verify=expected,newdelete \ 19 // RUN: -analyzer-checker=core \ 20 // RUN: -analyzer-checker=cplusplus.NewDelete 21 // 22 // RUN: %clang_analyze_cc1 -DLEAKS -std=c++17 -fblocks %s \ 23 // RUN: -verify=expected,newdelete,leak \ 24 // RUN: -analyzer-checker=core \ 25 // RUN: -analyzer-checker=cplusplus.NewDelete \ 26 // RUN: -analyzer-checker=cplusplus.NewDeleteLeaks 27 // 28 // RUN: %clang_analyze_cc1 -std=c++17 -fblocks -verify %s \ 29 // RUN: -verify=expected,leak \ 30 // RUN: -analyzer-checker=core \ 31 // RUN: -analyzer-checker=cplusplus.NewDeleteLeaks 32 33 #include "Inputs/system-header-simulator-cxx.h" 34 35 typedef __typeof__(sizeof(int)) size_t; 36 extern "C" void *malloc(size_t); 37 extern "C" void free (void* ptr); 38 int *global; 39 40 //----- Standard non-placement operators 41 void testGlobalOpNew() { 42 void *p = operator new(0); 43 } // leak-warning{{Potential leak of memory pointed to by 'p'}} 44 45 void testGlobalOpNewArray() { 46 void *p = operator new[](0); 47 } // leak-warning{{Potential leak of memory pointed to by 'p'}} 48 49 void testGlobalNewExpr() { 50 int *p = new int; 51 } // leak-warning{{Potential leak of memory pointed to by 'p'}} 52 53 void testGlobalNewExprArray() { 54 int *p = new int[0]; 55 } // leak-warning{{Potential leak of memory pointed to by 'p'}} 56 57 //----- Standard nothrow placement operators 58 void testGlobalNoThrowPlacementOpNewBeforeOverload() { 59 void *p = operator new(0, std::nothrow); 60 } // leak-warning{{Potential leak of memory pointed to by 'p'}} 61 62 void testGlobalNoThrowPlacementExprNewBeforeOverload() { 63 int *p = new(std::nothrow) int; 64 } // leak-warning{{Potential leak of memory pointed to by 'p'}} 65 66 //----- Other cases 67 void testNewMemoryIsInHeap() { 68 int *p = new int; 69 if (global != p) // condition is always true as 'p' wraps a heap region that 70 // is different from a region wrapped by 'global' 71 global = p; // pointer escapes 72 } 73 74 struct PtrWrapper { 75 int *x; 76 77 PtrWrapper(int *input) : x(input) {} 78 }; 79 80 void testNewInvalidationPlacement(PtrWrapper *w) { 81 // Ensure that we don't consider this a leak. 82 new (w) PtrWrapper(new int); // no warn 83 } 84 85 //----------------------------------------- 86 // check for usage of zero-allocated memory 87 //----------------------------------------- 88 89 void testUseZeroAlloc1() { 90 int *p = (int *)operator new(0); 91 *p = 1; // newdelete-warning {{Use of memory allocated with size zero}} 92 delete p; 93 } 94 95 int testUseZeroAlloc2() { 96 int *p = (int *)operator new[](0); 97 return p[0]; // newdelete-warning {{Use of memory allocated with size zero}} 98 delete[] p; 99 } 100 101 void f(int); 102 103 void testUseZeroAlloc3() { 104 int *p = new int[0]; 105 f(*p); // newdelete-warning {{Use of memory allocated with size zero}} 106 delete[] p; 107 } 108 109 //--------------- 110 // other checks 111 //--------------- 112 113 class SomeClass { 114 public: 115 void f(int *p); 116 }; 117 118 void f(int *p1, int *p2 = 0, int *p3 = 0); 119 void g(SomeClass &c, ...); 120 121 void testUseFirstArgAfterDelete() { 122 int *p = new int; 123 delete p; 124 f(p); // newdelete-warning{{Use of memory after it is freed}} 125 } 126 127 void testUseMiddleArgAfterDelete(int *p) { 128 delete p; 129 f(0, p); // newdelete-warning{{Use of memory after it is freed}} 130 } 131 132 void testUseLastArgAfterDelete(int *p) { 133 delete p; 134 f(0, 0, p); // newdelete-warning{{Use of memory after it is freed}} 135 } 136 137 void testUseSeveralArgsAfterDelete(int *p) { 138 delete p; 139 f(p, p, p); // newdelete-warning{{Use of memory after it is freed}} 140 } 141 142 void testUseRefArgAfterDelete(SomeClass &c) { 143 delete &c; 144 g(c); // newdelete-warning{{Use of memory after it is freed}} 145 } 146 147 void testVariadicArgAfterDelete() { 148 SomeClass c; 149 int *p = new int; 150 delete p; 151 g(c, 0, p); // newdelete-warning{{Use of memory after it is freed}} 152 } 153 154 void testUseMethodArgAfterDelete(int *p) { 155 SomeClass *c = new SomeClass; 156 delete p; 157 c->f(p); // newdelete-warning{{Use of memory after it is freed}} 158 } 159 160 void testUseThisAfterDelete() { 161 SomeClass *c = new SomeClass; 162 delete c; 163 c->f(0); // newdelete-warning{{Use of memory after it is freed}} 164 } 165 166 void testDoubleDelete() { 167 int *p = new int; 168 delete p; 169 delete p; // newdelete-warning{{Attempt to free released memory}} 170 } 171 172 void testExprDeleteArg() { 173 int i; 174 delete &i; // newdelete-warning{{Argument to 'delete' is the address of the local variable 'i', which is not memory allocated by 'new'}} 175 } 176 177 void testExprDeleteArrArg() { 178 int i; 179 delete[] & i; // newdelete-warning{{Argument to 'delete[]' is the address of the local variable 'i', which is not memory allocated by 'new[]'}} 180 } 181 182 void testAllocDeallocNames() { 183 int *p = new(std::nothrow) int[1]; 184 delete[] (++p); 185 // newdelete-warning@-1{{Argument to 'delete[]' is offset by 4 bytes from the start of memory allocated by 'new[]'}} 186 } 187 188 //-------------------------------- 189 // Test escape of newed const pointer. Note, a const pointer can be deleted. 190 //-------------------------------- 191 struct StWithConstPtr { 192 const int *memp; 193 }; 194 void escape(const int &x); 195 void escapeStruct(const StWithConstPtr &x); 196 void escapePtr(const StWithConstPtr *x); 197 void escapeVoidPtr(const void *x); 198 199 void testConstEscape() { 200 int *p = new int(1); 201 escape(*p); 202 } // no-warning 203 204 void testConstEscapeStruct() { 205 StWithConstPtr *St = new StWithConstPtr(); 206 escapeStruct(*St); 207 } // no-warning 208 209 void testConstEscapeStructPtr() { 210 StWithConstPtr *St = new StWithConstPtr(); 211 escapePtr(St); 212 } // no-warning 213 214 void testConstEscapeMember() { 215 StWithConstPtr St; 216 St.memp = new int(2); 217 escapeVoidPtr(St.memp); 218 } // no-warning 219 220 void testConstEscapePlacementNew() { 221 int *x = (int *)malloc(sizeof(int)); 222 void *y = new (x) int; 223 escapeVoidPtr(y); 224 } // no-warning 225 226 //============== Test Uninitialized delete delete[]======================== 227 void testUninitDelete() { 228 int *x; 229 int * y = new int; 230 delete y; 231 delete x; // expected-warning{{Argument to 'delete' is uninitialized}} 232 } 233 234 void testUninitDeleteArray() { 235 int *x; 236 int * y = new int[5]; 237 delete[] y; 238 delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}} 239 } 240 241 void testUninitFree() { 242 int *x; 243 free(x); // expected-warning{{1st function call argument is an uninitialized value}} 244 } 245 246 void testUninitDeleteSink() { 247 int *x; 248 delete x; // expected-warning{{Argument to 'delete' is uninitialized}} 249 (*(volatile int *)0 = 1); // no warn 250 } 251 252 void testUninitDeleteArraySink() { 253 int *x; 254 delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}} 255 (*(volatile int *)0 = 1); // no warn 256 } 257 258 namespace reference_count { 259 class control_block { 260 unsigned count; 261 public: 262 control_block() : count(0) {} 263 void retain() { ++count; } 264 int release() { return --count; } 265 }; 266 267 template <typename T> 268 class shared_ptr { 269 T *p; 270 control_block *control; 271 272 public: 273 shared_ptr() : p(0), control(0) {} 274 explicit shared_ptr(T *p) : p(p), control(new control_block) { 275 control->retain(); 276 } 277 shared_ptr(const shared_ptr &other) : p(other.p), control(other.control) { 278 if (control) 279 control->retain(); 280 } 281 ~shared_ptr() { 282 if (control && control->release() == 0) { 283 delete p; 284 delete control; 285 } 286 }; 287 288 T &operator *() { 289 return *p; 290 }; 291 292 void swap(shared_ptr &other) { 293 T *tmp = p; 294 p = other.p; 295 other.p = tmp; 296 297 control_block *ctrlTmp = control; 298 control = other.control; 299 other.control = ctrlTmp; 300 } 301 }; 302 303 template <typename T, typename... Args> 304 shared_ptr<T> make_shared(Args &&...args) { 305 return shared_ptr<T>(new T(static_cast<Args &&>(args)...)); 306 } 307 308 void testSingle() { 309 shared_ptr<int> a(new int); 310 *a = 1; 311 } 312 313 void testMake() { 314 shared_ptr<int> a = make_shared<int>(); 315 *a = 1; 316 } 317 318 void testMakeInParens() { 319 shared_ptr<int> a = (make_shared<int>()); // no warn 320 *a = 1; 321 } 322 323 void testDouble() { 324 shared_ptr<int> a(new int); 325 shared_ptr<int> b = a; 326 *a = 1; 327 } 328 329 void testInvalidated() { 330 shared_ptr<int> a(new int); 331 shared_ptr<int> b = a; 332 *a = 1; 333 334 extern void use(shared_ptr<int> &); 335 use(b); 336 } 337 338 void testNestedScope() { 339 shared_ptr<int> a(new int); 340 { 341 shared_ptr<int> b = a; 342 } 343 *a = 1; 344 } 345 346 void testSwap() { 347 shared_ptr<int> a(new int); 348 shared_ptr<int> b; 349 shared_ptr<int> c = a; 350 shared_ptr<int>(c).swap(b); 351 } 352 353 void testUseAfterFree() { 354 int *p = new int; 355 { 356 shared_ptr<int> a(p); 357 shared_ptr<int> b = a; 358 } 359 360 // FIXME: We should get a warning here, but we don't because we've 361 // conservatively modeled ~shared_ptr. 362 *p = 1; 363 } 364 } 365 366 // Test double delete 367 class DerefClass{ 368 public: 369 int *x; 370 DerefClass() {} 371 ~DerefClass() { 372 int i = 0; 373 x = &i; 374 *x = 1; 375 } 376 }; 377 378 void testDoubleDeleteClassInstance() { 379 DerefClass *foo = new DerefClass(); 380 delete foo; 381 delete foo; // newdelete-warning {{Attempt to delete released memory}} 382 } 383 384 class EmptyClass{ 385 public: 386 EmptyClass() {} 387 ~EmptyClass() {} 388 }; 389 390 void testDoubleDeleteEmptyClass() { 391 EmptyClass *foo = new EmptyClass(); 392 delete foo; 393 delete foo; // newdelete-warning {{Attempt to delete released memory}} 394 } 395 396 struct Base { 397 virtual ~Base() {} 398 }; 399 400 struct Derived : Base { 401 }; 402 403 Base *allocate() { 404 return new Derived; 405 } 406 407 void shouldNotReportLeak() { 408 Derived *p = (Derived *)allocate(); 409 delete p; 410 } 411 412 template<void *allocate_fn(size_t)> 413 void* allocate_via_nttp(size_t n) { 414 return allocate_fn(n); 415 } 416 417 template<void deallocate_fn(void*)> 418 void deallocate_via_nttp(void* ptr) { 419 deallocate_fn(ptr); 420 } 421 422 void testNTTPNewNTTPDelete() { 423 void* p = allocate_via_nttp<::operator new>(10); 424 deallocate_via_nttp<::operator delete>(p); 425 } // no warn 426 427 void testNTTPNewDirectDelete() { 428 void* p = allocate_via_nttp<::operator new>(10); 429 ::operator delete(p); 430 } // no warn 431 432 void testDirectNewNTTPDelete() { 433 void* p = ::operator new(10); 434 deallocate_via_nttp<::operator delete>(p); 435 } 436 437 void not_free(void*) { 438 } 439 440 void testLeakBecauseNTTPIsNotDeallocation() { 441 void* p = ::operator new(10); 442 deallocate_via_nttp<not_free>(p); 443 } // leak-warning{{Potential leak of memory pointed to by 'p'}} 444