[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:
Artem Dergachev 2019-07-01 23:02:18 +00:00
parent 512f4838c4
commit ceb639dbee
2 changed files with 37 additions and 5 deletions

View File

@ -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 {

View File

@ -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'}}
}