forked from OSchip/llvm-project
[analyzer] Fix FP warnings when binding a temporary to a local static variable
Summary: When binding a temporary object to a static local variable, the analyzer would complain about a dangling reference even though the temporary's lifetime should be extended past the end of the function. This commit tries to detect these cases and construct them in a global memory region instead of a local one. Reviewers: jordan_rose CC: cfe-commits Differential Revision: http://llvm-reviews.chandlerc.com/D1133 llvm-svn: 187196
This commit is contained in:
parent
240d480c5f
commit
cf878bbe65
|
@ -1272,6 +1272,11 @@ public:
|
|||
const BlockDataRegion *getBlockDataRegion(const BlockTextRegion *bc,
|
||||
const LocationContext *lc = NULL);
|
||||
|
||||
/// Create a CXXTempObjectRegion for temporaries which are lifetime-extended
|
||||
/// by static references. This differs from getCXXTempObjectRegion in the
|
||||
/// super-region used.
|
||||
const CXXTempObjectRegion *getCXXStaticTempObjectRegion(const Expr *Ex);
|
||||
|
||||
private:
|
||||
template <typename RegionTy, typename A1>
|
||||
RegionTy* getRegion(const A1 a1);
|
||||
|
|
|
@ -209,7 +209,18 @@ ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State,
|
|||
|
||||
// Create a temporary object region for the inner expression (which may have
|
||||
// a more derived type) and bind the value into it.
|
||||
const TypedValueRegion *TR = MRMgr.getCXXTempObjectRegion(Inner, LC);
|
||||
const TypedValueRegion *TR = NULL;
|
||||
if (const MaterializeTemporaryExpr *MT =
|
||||
dyn_cast<MaterializeTemporaryExpr>(Result)) {
|
||||
StorageDuration SD = MT->getStorageDuration();
|
||||
// If this object is bound to a reference with static storage duration, we
|
||||
// put it in a different region to prevent "address leakage" warnings.
|
||||
if (SD == SD_Static || SD == SD_Thread)
|
||||
TR = MRMgr.getCXXStaticTempObjectRegion(Inner);
|
||||
}
|
||||
if (!TR)
|
||||
TR = MRMgr.getCXXTempObjectRegion(Inner, LC);
|
||||
|
||||
SVal Reg = loc::MemRegionVal(TR);
|
||||
|
||||
if (V.isUnknown())
|
||||
|
|
|
@ -864,6 +864,12 @@ MemRegionManager::getBlockDataRegion(const BlockTextRegion *BC,
|
|||
return getSubRegion<BlockDataRegion>(BC, LC, sReg);
|
||||
}
|
||||
|
||||
const CXXTempObjectRegion *
|
||||
MemRegionManager::getCXXStaticTempObjectRegion(const Expr *Ex) {
|
||||
return getSubRegion<CXXTempObjectRegion>(
|
||||
Ex, getGlobalsRegion(MemRegion::GlobalInternalSpaceRegionKind, NULL));
|
||||
}
|
||||
|
||||
const CompoundLiteralRegion*
|
||||
MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr *CL,
|
||||
const LocationContext *LC) {
|
||||
|
|
|
@ -20,6 +20,10 @@ const int& g3() {
|
|||
return s3; // expected-warning{{Address of stack memory associated with local variable 's1' returned}} expected-warning {{reference to stack memory associated with local variable 's1' returned}}
|
||||
}
|
||||
|
||||
void g4() {
|
||||
static const int &x = 3; // no warning
|
||||
}
|
||||
|
||||
int get_value();
|
||||
|
||||
const int &get_reference1() { return get_value(); } // expected-warning{{Address of stack memory associated with temporary object of type 'int' returned}} expected-warning {{returning reference to local temporary}}
|
||||
|
|
|
@ -141,3 +141,19 @@ namespace destructors {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void testStaticMaterializeTemporaryExpr() {
|
||||
static const Trivial &ref = getTrivial();
|
||||
clang_analyzer_eval(ref.value == 42); // expected-warning{{TRUE}}
|
||||
|
||||
static const Trivial &directRef = Trivial(42);
|
||||
clang_analyzer_eval(directRef.value == 42); // expected-warning{{TRUE}}
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
thread_local static const Trivial &threadRef = getTrivial();
|
||||
clang_analyzer_eval(threadRef.value == 42); // expected-warning{{TRUE}}
|
||||
|
||||
thread_local static const Trivial &threadDirectRef = Trivial(42);
|
||||
clang_analyzer_eval(threadDirectRef.value == 42); // expected-warning{{TRUE}}
|
||||
#endif
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue