forked from OSchip/llvm-project
				
			[analyzer] Fix invalidation when returning into a ctor initializer.
Due to RVO the target region of a function that returns an object by value isn't necessarily a temporary object region; it may be an arbitrary memory region. In particular, it may be a field of a bigger object. Make sure we don't invalidate the bigger object when said function is evaluated conservatively. Differential Revision: https://reviews.llvm.org/D63968 llvm-svn: 364870
This commit is contained in:
		
							parent
							
								
									512f4838c4
								
							
						
					
					
						commit
						ceb639dbee
					
				| 
						 | 
				
			
			@ -634,12 +634,19 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call,
 | 
			
		|||
    std::tie(State, Target) =
 | 
			
		||||
        prepareForObjectConstruction(Call.getOriginExpr(), State, LCtx,
 | 
			
		||||
                                     RTC->getConstructionContext(), CallOpts);
 | 
			
		||||
    assert(Target.getAsRegion());
 | 
			
		||||
    // Invalidate the region so that it didn't look uninitialized. Don't notify
 | 
			
		||||
    // the checkers.
 | 
			
		||||
    State = State->invalidateRegions(Target.getAsRegion(), E, Count, LCtx,
 | 
			
		||||
    const MemRegion *TargetR = Target.getAsRegion();
 | 
			
		||||
    assert(TargetR);
 | 
			
		||||
    // Invalidate the region so that it didn't look uninitialized. If this is
 | 
			
		||||
    // a field or element constructor, we do not want to invalidate
 | 
			
		||||
    // the whole structure. Pointer escape is meaningless because
 | 
			
		||||
    // the structure is a product of conservative evaluation
 | 
			
		||||
    // and therefore contains nothing interesting at this point.
 | 
			
		||||
    RegionAndSymbolInvalidationTraits ITraits;
 | 
			
		||||
    ITraits.setTrait(TargetR,
 | 
			
		||||
        RegionAndSymbolInvalidationTraits::TK_DoNotInvalidateSuperRegion);
 | 
			
		||||
    State = State->invalidateRegions(TargetR, E, Count, LCtx,
 | 
			
		||||
                                     /* CausedByPointerEscape=*/false, nullptr,
 | 
			
		||||
                                     &Call, nullptr);
 | 
			
		||||
                                     &Call, &ITraits);
 | 
			
		||||
 | 
			
		||||
    R = State->getSVal(Target.castAs<Loc>(), E->getType());
 | 
			
		||||
  } else {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,25 @@
 | 
			
		|||
// RUN: %clang_analyze_cc1 -analyzer-checker core,cplusplus \
 | 
			
		||||
// RUN:                    -analyzer-checker debug.ExprInspection -verify %s
 | 
			
		||||
 | 
			
		||||
void clang_analyzer_eval(bool);
 | 
			
		||||
 | 
			
		||||
struct A {
 | 
			
		||||
  int x;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
A getA();
 | 
			
		||||
 | 
			
		||||
struct B {
 | 
			
		||||
  int *p;
 | 
			
		||||
  A a;
 | 
			
		||||
 | 
			
		||||
  B(int *p) : p(p), a(getA()) {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void foo() {
 | 
			
		||||
  B b1(nullptr);
 | 
			
		||||
  clang_analyzer_eval(b1.p == nullptr); // expected-warning{{TRUE}}
 | 
			
		||||
  B b2(new int); // No leak yet!
 | 
			
		||||
  clang_analyzer_eval(b2.p == nullptr); // expected-warning{{FALSE}}
 | 
			
		||||
  // expected-warning@-1{{Potential leak of memory pointed to by 'b2.p'}}
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue