mirror of
https://github.com/Gericom/teak-llvm.git
synced 2025-06-21 04:25:45 -04:00
[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) =
|
std::tie(State, Target) =
|
||||||
prepareForObjectConstruction(Call.getOriginExpr(), State, LCtx,
|
prepareForObjectConstruction(Call.getOriginExpr(), State, LCtx,
|
||||||
RTC->getConstructionContext(), CallOpts);
|
RTC->getConstructionContext(), CallOpts);
|
||||||
assert(Target.getAsRegion());
|
const MemRegion *TargetR = Target.getAsRegion();
|
||||||
// Invalidate the region so that it didn't look uninitialized. Don't notify
|
assert(TargetR);
|
||||||
// the checkers.
|
// Invalidate the region so that it didn't look uninitialized. If this is
|
||||||
State = State->invalidateRegions(Target.getAsRegion(), E, Count, LCtx,
|
// 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,
|
/* CausedByPointerEscape=*/false, nullptr,
|
||||||
&Call, nullptr);
|
&Call, &ITraits);
|
||||||
|
|
||||||
R = State->getSVal(Target.castAs<Loc>(), E->getType());
|
R = State->getSVal(Target.castAs<Loc>(), E->getType());
|
||||||
} else {
|
} else {
|
||||||
|
25
clang/test/Analysis/rvo.cpp
Normal file
25
clang/test/Analysis/rvo.cpp
Normal 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'}}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user