Skip to content

Commit

Permalink
[analyzer] Fix invalidation when returning into a ctor initializer.
Browse files Browse the repository at this point in the history
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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@364870 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
haoNoQ committed Jul 1, 2019
1 parent 273f872 commit 6d6bd29
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 5 deletions.
17 changes: 12 additions & 5 deletions lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
25 changes: 25 additions & 0 deletions test/Analysis/rvo.cpp
Original file line number Diff line number Diff line change
@@ -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'}}
}

0 comments on commit 6d6bd29

Please sign in to comment.