forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			119 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			119 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			C++
		
	
	
	
| // RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus.NewDelete,cplusplus.NewDeleteLeaks,debug.ExprInspection -analyzer-config c++-allocator-inlining=true -std=c++11 -verify -analyzer-config eagerly-assume=false %s
 | |
| 
 | |
| void clang_analyzer_eval(bool);
 | |
| void clang_analyzer_dump(int);
 | |
| 
 | |
| typedef __typeof__(sizeof(int)) size_t;
 | |
| 
 | |
| void *conjure();
 | |
| void exit(int);
 | |
| 
 | |
| struct S;
 | |
| 
 | |
| S *global_s;
 | |
| 
 | |
| // Recursive operator kinda placement new.
 | |
| void *operator new(size_t size, S *place);
 | |
| 
 | |
| enum class ConstructionKind : char {
 | |
|   Garbage,
 | |
|   Recursive
 | |
| };
 | |
| 
 | |
| struct S {
 | |
| public:
 | |
|   int x;
 | |
|   S(): x(1) {}
 | |
|   S(int y): x(y) {}
 | |
| 
 | |
|   S(ConstructionKind k) {
 | |
|     switch (k) {
 | |
|     case ConstructionKind::Recursive: { // Call one more operator new 'r'ecursively.
 | |
|       S *s = new (nullptr) S(5);
 | |
|       x = s->x + 1;
 | |
|       global_s = s;
 | |
|       return;
 | |
|     }
 | |
|     case ConstructionKind::Garbage: {
 | |
|       // Leaves garbage in 'x'.
 | |
|     }
 | |
|     }
 | |
|   }
 | |
|   ~S() {}
 | |
| };
 | |
| 
 | |
| // Do not try this at home!
 | |
| void *operator new(size_t size, S *place) {
 | |
|   if (!place)
 | |
|     return new S();
 | |
|   return place;
 | |
| }
 | |
| 
 | |
| void testThatCharConstructorIndeedYieldsGarbage() {
 | |
|   S *s = new S(ConstructionKind::Garbage);
 | |
|   clang_analyzer_eval(s->x == 0); // expected-warning{{UNKNOWN}}
 | |
|   clang_analyzer_eval(s->x == 1); // expected-warning{{UNKNOWN}}
 | |
|   // FIXME: This should warn, but MallocChecker doesn't default-bind regions
 | |
|   // returned by standard operator new to garbage.
 | |
|   s->x += 1; // no-warning
 | |
|   delete s;
 | |
| }
 | |
| 
 | |
| 
 | |
| void testChainedOperatorNew() {
 | |
|   S *s;
 | |
|   // * Evaluate standard new.
 | |
|   // * Evaluate constructor S(3).
 | |
|   // * Bind value for standard new.
 | |
|   // * Evaluate our custom new.
 | |
|   // * Evaluate constructor S(Garbage).
 | |
|   // * Bind value for our custom new.
 | |
|   s = new (new S(3)) S(ConstructionKind::Garbage);
 | |
|   clang_analyzer_eval(s->x == 3); // expected-warning{{TRUE}}
 | |
|   // expected-warning@+9{{Potential leak of memory pointed to by 's'}}
 | |
| 
 | |
|   // * Evaluate standard new.
 | |
|   // * Evaluate constructor S(Garbage).
 | |
|   // * Bind value for standard new.
 | |
|   // * Evaluate our custom new.
 | |
|   // * Evaluate constructor S(4).
 | |
|   // * Bind value for our custom new.
 | |
|   s = new (new S(ConstructionKind::Garbage)) S(4);
 | |
|   clang_analyzer_eval(s->x == 4); // expected-warning{{TRUE}}
 | |
|   delete s;
 | |
| 
 | |
|   // -> Enter our custom new (nullptr).
 | |
|   //   * Evaluate standard new.
 | |
|   //   * Inline constructor S().
 | |
|   //   * Bind value for standard new.
 | |
|   // <- Exit our custom new (nullptr).
 | |
|   // * Evaluate constructor S(Garbage).
 | |
|   // * Bind value for our custom new.
 | |
|   s = new (nullptr) S(ConstructionKind::Garbage);
 | |
|   clang_analyzer_eval(s->x == 1); // expected-warning{{TRUE}}
 | |
|   delete s;
 | |
| 
 | |
|   // -> Enter our custom new (nullptr).
 | |
|   //   * Evaluate standard new.
 | |
|   //   * Inline constructor S().
 | |
|   //   * Bind value for standard new.
 | |
|   // <- Exit our custom new (nullptr).
 | |
|   // -> Enter constructor S(Recursive).
 | |
|   //   -> Enter our custom new (nullptr).
 | |
|   //     * Evaluate standard new.
 | |
|   //     * Inline constructor S().
 | |
|   //     * Bind value for standard new.
 | |
|   //   <- Exit our custom new (nullptr).
 | |
|   //   * Evaluate constructor S(5).
 | |
|   //   * Bind value for our custom new (nullptr).
 | |
|   //   * Assign that value to global_s.
 | |
|   // <- Exit constructor S(Recursive).
 | |
|   // * Bind value for our custom new (nullptr).
 | |
|   global_s = nullptr;
 | |
|   s = new (nullptr) S(ConstructionKind::Recursive);
 | |
|   clang_analyzer_eval(global_s); // expected-warning{{TRUE}}
 | |
|   clang_analyzer_eval(global_s->x == 5); // expected-warning{{TRUE}}
 | |
|   clang_analyzer_eval(s->x == 6); // expected-warning{{TRUE}}
 | |
|   delete s;
 | |
| }
 |