summaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Core
diff options
context:
space:
mode:
Diffstat (limited to 'lib/StaticAnalyzer/Core')
-rw-r--r--lib/StaticAnalyzer/Core/BugReporterVisitors.cpp37
-rw-r--r--lib/StaticAnalyzer/Core/CallEvent.cpp63
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp150
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineC.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCXX.cpp43
-rw-r--r--lib/StaticAnalyzer/Core/IssueHash.cpp2
-rw-r--r--lib/StaticAnalyzer/Core/ProgramState.cpp5
-rw-r--r--lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp46
-rw-r--r--lib/StaticAnalyzer/Core/Store.cpp4
9 files changed, 201 insertions, 151 deletions
diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index c87bc685d8b9..d4d33c1746ce 100644
--- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -269,6 +269,8 @@ namespace {
/// pointer dereference outside.
class NoStoreFuncVisitor final : public BugReporterVisitor {
const SubRegion *RegionOfInterest;
+ const SourceManager &SM;
+ const PrintingPolicy &PP;
static constexpr const char *DiagnosticsMsg =
"Returning without writing to '";
@@ -284,7 +286,10 @@ class NoStoreFuncVisitor final : public BugReporterVisitor {
llvm::SmallPtrSet<const StackFrameContext *, 32> FramesModifyingCalculated;
public:
- NoStoreFuncVisitor(const SubRegion *R) : RegionOfInterest(R) {}
+ NoStoreFuncVisitor(const SubRegion *R)
+ : RegionOfInterest(R),
+ SM(R->getMemRegionManager()->getContext().getSourceManager()),
+ PP(R->getMemRegionManager()->getContext().getPrintingPolicy()) {}
void Profile(llvm::FoldingSetNodeID &ID) const override {
static int Tag = 0;
@@ -307,8 +312,6 @@ public:
CallEventRef<> Call =
BRC.getStateManager().getCallEventManager().getCaller(SCtx, State);
- const PrintingPolicy &PP = BRC.getASTContext().getPrintingPolicy();
- const SourceManager &SM = BRC.getSourceManager();
// Region of interest corresponds to an IVar, exiting a method
// which could have written into that IVar, but did not.
@@ -318,16 +321,14 @@ public:
IvarR->getDecl()) &&
!isRegionOfInterestModifiedInFrame(N))
return notModifiedMemberDiagnostics(
- Ctx, SM, PP, *CallExitLoc, Call,
- MC->getReceiverSVal().getAsRegion());
+ Ctx, *CallExitLoc, Call, MC->getReceiverSVal().getAsRegion());
if (const auto *CCall = dyn_cast<CXXConstructorCall>(Call)) {
- const MemRegion *ThisRegion = CCall->getCXXThisVal().getAsRegion();
- if (RegionOfInterest->isSubRegionOf(ThisRegion)
+ const MemRegion *ThisR = CCall->getCXXThisVal().getAsRegion();
+ if (RegionOfInterest->isSubRegionOf(ThisR)
&& !CCall->getDecl()->isImplicit()
&& !isRegionOfInterestModifiedInFrame(N))
- return notModifiedMemberDiagnostics(Ctx, SM, PP, *CallExitLoc,
- CCall, ThisRegion);
+ return notModifiedMemberDiagnostics(Ctx, *CallExitLoc, Call, ThisR);
}
ArrayRef<ParmVarDecl *> parameters = getCallParameters(Call);
@@ -344,7 +345,7 @@ public:
return nullptr;
return notModifiedParameterDiagnostics(
- Ctx, SM, PP, *CallExitLoc, Call, PVD, R, IndirectionLevel);
+ Ctx, *CallExitLoc, Call, PVD, R, IndirectionLevel);
}
QualType PT = T->getPointeeType();
if (PT.isNull() || PT->isVoidType()) break;
@@ -446,8 +447,6 @@ private:
/// in a given function.
std::shared_ptr<PathDiagnosticPiece> notModifiedMemberDiagnostics(
const LocationContext *Ctx,
- const SourceManager &SM,
- const PrintingPolicy &PP,
CallExitBegin &CallExitLoc,
CallEventRef<> Call,
const MemRegion *ArgRegion) {
@@ -474,8 +473,6 @@ private:
/// before we get to the super region of \c RegionOfInterest
std::shared_ptr<PathDiagnosticPiece>
notModifiedParameterDiagnostics(const LocationContext *Ctx,
- const SourceManager &SM,
- const PrintingPolicy &PP,
CallExitBegin &CallExitLoc,
CallEventRef<> Call,
const ParmVarDecl *PVD,
@@ -612,8 +609,7 @@ public:
const ExplodedNode *N, const MemRegion *R,
bool EnableNullFPSuppression, BugReport &BR,
const SVal V) {
- AnalyzerOptions &Options = N->getState()->getStateManager()
- .getOwningEngine()->getAnalysisManager().options;
+ AnalyzerOptions &Options = N->getState()->getAnalysisManager().options;
if (EnableNullFPSuppression && Options.shouldSuppressNullReturnPaths()
&& V.getAs<Loc>())
BR.addVisitor(llvm::make_unique<MacroNullReturnSuppressionVisitor>(
@@ -740,9 +736,7 @@ public:
RetVal = State->getSVal(*LValue);
// See if the return value is NULL. If so, suppress the report.
- SubEngine *Eng = State->getStateManager().getOwningEngine();
- assert(Eng && "Cannot file a bug report without an owning engine");
- AnalyzerOptions &Options = Eng->getAnalysisManager().options;
+ AnalyzerOptions &Options = State->getAnalysisManager().options;
bool EnableNullFPSuppression = false;
if (InEnableNullFPSuppression && Options.shouldSuppressNullReturnPaths())
@@ -1321,9 +1315,7 @@ SuppressInlineDefensiveChecksVisitor::
SuppressInlineDefensiveChecksVisitor(DefinedSVal Value, const ExplodedNode *N)
: V(Value) {
// Check if the visitor is disabled.
- SubEngine *Eng = N->getState()->getStateManager().getOwningEngine();
- assert(Eng && "Cannot file a bug report without an owning engine");
- AnalyzerOptions &Options = Eng->getAnalysisManager().options;
+ AnalyzerOptions &Options = N->getState()->getAnalysisManager().options;
if (!Options.shouldSuppressInlinedDefensiveChecks())
IsSatisfied = true;
@@ -1603,6 +1595,7 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N,
LVNode->getSVal(Inner).getAsRegion();
if (R) {
+
// Mark both the variable region and its contents as interesting.
SVal V = LVState->getRawSVal(loc::MemRegionVal(R));
report.addVisitor(
diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp
index 8db7b06f186d..fe9260e32dd8 100644
--- a/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -27,6 +27,7 @@
#include "clang/AST/Type.h"
#include "clang/Analysis/AnalysisDeclContext.h"
#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/CFGStmtMap.h"
#include "clang/Analysis/ProgramPoint.h"
#include "clang/CrossTU/CrossTranslationUnit.h"
#include "clang/Basic/IdentifierTable.h"
@@ -166,6 +167,68 @@ bool CallEvent::isGlobalCFunction(StringRef FunctionName) const {
return CheckerContext::isCLibraryFunction(FD, FunctionName);
}
+AnalysisDeclContext *CallEvent::getCalleeAnalysisDeclContext() const {
+ const Decl *D = getDecl();
+
+ // If the callee is completely unknown, we cannot construct the stack frame.
+ if (!D)
+ return nullptr;
+
+ // FIXME: Skip virtual functions for now. There's no easy procedure to foresee
+ // the exact decl that should be used, especially when it's not a definition.
+ if (const Decl *RD = getRuntimeDefinition().getDecl())
+ if (RD != D)
+ return nullptr;
+
+ return LCtx->getAnalysisDeclContext()->getManager()->getContext(D);
+}
+
+const StackFrameContext *CallEvent::getCalleeStackFrame() const {
+ AnalysisDeclContext *ADC = getCalleeAnalysisDeclContext();
+ if (!ADC)
+ return nullptr;
+
+ const Expr *E = getOriginExpr();
+ if (!E)
+ return nullptr;
+
+ // Recover CFG block via reverse lookup.
+ // TODO: If we were to keep CFG element information as part of the CallEvent
+ // instead of doing this reverse lookup, we would be able to build the stack
+ // frame for non-expression-based calls, and also we wouldn't need the reverse
+ // lookup.
+ CFGStmtMap *Map = LCtx->getAnalysisDeclContext()->getCFGStmtMap();
+ const CFGBlock *B = Map->getBlock(E);
+ assert(B);
+
+ // Also recover CFG index by scanning the CFG block.
+ unsigned Idx = 0, Sz = B->size();
+ for (; Idx < Sz; ++Idx)
+ if (auto StmtElem = (*B)[Idx].getAs<CFGStmt>())
+ if (StmtElem->getStmt() == E)
+ break;
+ assert(Idx < Sz);
+
+ return ADC->getManager()->getStackFrame(ADC, LCtx, E, B, Idx);
+}
+
+const VarRegion *CallEvent::getParameterLocation(unsigned Index) const {
+ const StackFrameContext *SFC = getCalleeStackFrame();
+ // We cannot construct a VarRegion without a stack frame.
+ if (!SFC)
+ return nullptr;
+
+ const ParmVarDecl *PVD = parameters()[Index];
+ const VarRegion *VR =
+ State->getStateManager().getRegionManager().getVarRegion(PVD, SFC);
+
+ // This sanity check would fail if our parameter declaration doesn't
+ // correspond to the stack frame's function declaration.
+ assert(VR->getStackFrame() == SFC);
+
+ return VR;
+}
+
/// Returns true if a type is a pointer-to-const or reference-to-const
/// with no further indirection.
static bool isPointerToConst(QualType Ty) {
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 188316c096e3..2b4bdd754fdb 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -117,56 +117,42 @@ STATISTIC(NumTimesRetriedWithoutInlining,
/// the construction context was present and contained references to these
/// AST nodes.
class ConstructedObjectKey {
- typedef std::pair<
- llvm::PointerUnion<const Stmt *, const CXXCtorInitializer *>,
- const LocationContext *> ConstructedObjectKeyImpl;
+ typedef std::pair<ConstructionContextItem, const LocationContext *>
+ ConstructedObjectKeyImpl;
- ConstructedObjectKeyImpl Impl;
+ const ConstructedObjectKeyImpl Impl;
const void *getAnyASTNodePtr() const {
- if (const Stmt *S = getStmt())
+ if (const Stmt *S = getItem().getStmtOrNull())
return S;
else
- return getCXXCtorInitializer();
+ return getItem().getCXXCtorInitializer();
}
public:
- ConstructedObjectKey(
- llvm::PointerUnion<const Stmt *, const CXXCtorInitializer *> P,
- const LocationContext *LC)
- : Impl(P, LC) {
- // This is the full list of statements that require additional actions when
- // encountered. This list may be expanded when new actions are implemented.
- assert(getCXXCtorInitializer() || isa<DeclStmt>(getStmt()) ||
- isa<CXXNewExpr>(getStmt()) || isa<CXXBindTemporaryExpr>(getStmt()) ||
- isa<MaterializeTemporaryExpr>(getStmt()) ||
- isa<CXXConstructExpr>(getStmt()));
- }
-
- const Stmt *getStmt() const {
- return Impl.first.dyn_cast<const Stmt *>();
- }
+ explicit ConstructedObjectKey(const ConstructionContextItem &Item,
+ const LocationContext *LC)
+ : Impl(Item, LC) {}
- const CXXCtorInitializer *getCXXCtorInitializer() const {
- return Impl.first.dyn_cast<const CXXCtorInitializer *>();
- }
-
- const LocationContext *getLocationContext() const {
- return Impl.second;
- }
+ const ConstructionContextItem &getItem() const { return Impl.first; }
+ const LocationContext *getLocationContext() const { return Impl.second; }
void print(llvm::raw_ostream &OS, PrinterHelper *Helper, PrintingPolicy &PP) {
- OS << '(' << getLocationContext() << ',' << getAnyASTNodePtr() << ") ";
- if (const Stmt *S = getStmt()) {
+ OS << '(' << getLocationContext() << ',' << getAnyASTNodePtr() << ','
+ << getItem().getKindAsString();
+ if (getItem().getKind() == ConstructionContextItem::ArgumentKind)
+ OS << " #" << getItem().getIndex();
+ OS << ") ";
+ if (const Stmt *S = getItem().getStmtOrNull()) {
S->printPretty(OS, Helper, PP);
} else {
- const CXXCtorInitializer *I = getCXXCtorInitializer();
+ const CXXCtorInitializer *I = getItem().getCXXCtorInitializer();
OS << I->getAnyMember()->getNameAsString();
}
}
void Profile(llvm::FoldingSetNodeID &ID) const {
- ID.AddPointer(Impl.first.getOpaqueValue());
+ ID.Add(Impl.first);
ID.AddPointer(Impl.second);
}
@@ -184,15 +170,6 @@ typedef llvm::ImmutableMap<ConstructedObjectKey, SVal>
REGISTER_TRAIT_WITH_PROGRAMSTATE(ObjectsUnderConstruction,
ObjectsUnderConstructionMap)
-// Additionally, track a set of destructors that correspond to elided
-// constructors when copy elision occurs.
-typedef std::pair<const CXXBindTemporaryExpr *, const LocationContext *>
- ElidedDestructorItem;
-typedef llvm::ImmutableSet<ElidedDestructorItem>
- ElidedDestructorSet;
-REGISTER_TRAIT_WITH_PROGRAMSTATE(ElidedDestructors,
- ElidedDestructorSet)
-
//===----------------------------------------------------------------------===//
// Engine construction and deletion.
//===----------------------------------------------------------------------===//
@@ -449,31 +426,32 @@ ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State,
return State;
}
-ProgramStateRef ExprEngine::addObjectUnderConstruction(
- ProgramStateRef State,
- llvm::PointerUnion<const Stmt *, const CXXCtorInitializer *> P,
- const LocationContext *LC, SVal V) {
- ConstructedObjectKey Key(P, LC->getStackFrame());
+ProgramStateRef
+ExprEngine::addObjectUnderConstruction(ProgramStateRef State,
+ const ConstructionContextItem &Item,
+ const LocationContext *LC, SVal V) {
+ ConstructedObjectKey Key(Item, LC->getStackFrame());
// FIXME: Currently the state might already contain the marker due to
// incorrect handling of temporaries bound to default parameters.
assert(!State->get<ObjectsUnderConstruction>(Key) ||
- isa<CXXBindTemporaryExpr>(Key.getStmt()));
+ Key.getItem().getKind() ==
+ ConstructionContextItem::TemporaryDestructorKind);
return State->set<ObjectsUnderConstruction>(Key, V);
}
-Optional<SVal> ExprEngine::getObjectUnderConstruction(
- ProgramStateRef State,
- llvm::PointerUnion<const Stmt *, const CXXCtorInitializer *> P,
- const LocationContext *LC) {
- ConstructedObjectKey Key(P, LC->getStackFrame());
+Optional<SVal>
+ExprEngine::getObjectUnderConstruction(ProgramStateRef State,
+ const ConstructionContextItem &Item,
+ const LocationContext *LC) {
+ ConstructedObjectKey Key(Item, LC->getStackFrame());
return Optional<SVal>::create(State->get<ObjectsUnderConstruction>(Key));
}
-ProgramStateRef ExprEngine::finishObjectConstruction(
- ProgramStateRef State,
- llvm::PointerUnion<const Stmt *, const CXXCtorInitializer *> P,
- const LocationContext *LC) {
- ConstructedObjectKey Key(P, LC->getStackFrame());
+ProgramStateRef
+ExprEngine::finishObjectConstruction(ProgramStateRef State,
+ const ConstructionContextItem &Item,
+ const LocationContext *LC) {
+ ConstructedObjectKey Key(Item, LC->getStackFrame());
assert(State->contains<ObjectsUnderConstruction>(Key));
return State->remove<ObjectsUnderConstruction>(Key);
}
@@ -481,25 +459,26 @@ ProgramStateRef ExprEngine::finishObjectConstruction(
ProgramStateRef ExprEngine::elideDestructor(ProgramStateRef State,
const CXXBindTemporaryExpr *BTE,
const LocationContext *LC) {
- ElidedDestructorItem I(BTE, LC);
- assert(!State->contains<ElidedDestructors>(I));
- return State->add<ElidedDestructors>(I);
+ ConstructedObjectKey Key({BTE, /*IsElided=*/true}, LC);
+ // FIXME: Currently the state might already contain the marker due to
+ // incorrect handling of temporaries bound to default parameters.
+ return State->set<ObjectsUnderConstruction>(Key, UnknownVal());
}
ProgramStateRef
ExprEngine::cleanupElidedDestructor(ProgramStateRef State,
const CXXBindTemporaryExpr *BTE,
const LocationContext *LC) {
- ElidedDestructorItem I(BTE, LC);
- assert(State->contains<ElidedDestructors>(I));
- return State->remove<ElidedDestructors>(I);
+ ConstructedObjectKey Key({BTE, /*IsElided=*/true}, LC);
+ assert(State->contains<ObjectsUnderConstruction>(Key));
+ return State->remove<ObjectsUnderConstruction>(Key);
}
bool ExprEngine::isDestructorElided(ProgramStateRef State,
const CXXBindTemporaryExpr *BTE,
const LocationContext *LC) {
- ElidedDestructorItem I(BTE, LC);
- return State->contains<ElidedDestructors>(I);
+ ConstructedObjectKey Key({BTE, /*IsElided=*/true}, LC);
+ return State->contains<ObjectsUnderConstruction>(Key);
}
bool ExprEngine::areAllObjectsFullyConstructed(ProgramStateRef State,
@@ -512,10 +491,6 @@ bool ExprEngine::areAllObjectsFullyConstructed(ProgramStateRef State,
if (I.first.getLocationContext() == LC)
return false;
- for (auto I: State->get<ElidedDestructors>())
- if (I.second == LC)
- return false;
-
LC = LC->getParent();
}
return true;
@@ -560,14 +535,6 @@ static void printObjectsUnderConstructionForContext(raw_ostream &Out,
Key.print(Out, nullptr, PP);
Out << " : " << Value << NL;
}
-
- for (auto I : State->get<ElidedDestructors>()) {
- if (I.second != LC)
- continue;
- Out << '(' << I.second << ',' << (const void *)I.first << ") ";
- I.first->printPretty(Out, nullptr, PP);
- Out << " : (constructor elided)" << NL;
- }
}
void ExprEngine::printState(raw_ostream &Out, ProgramStateRef State,
@@ -2252,25 +2219,14 @@ void ExprEngine::processEndOfFunction(NodeBuilderContext& BC,
for (auto I : State->get<ObjectsUnderConstruction>())
if (I.first.getLocationContext() == LC) {
// The comment above only pardons us for not cleaning up a
- // CXXBindTemporaryExpr. If any other statements are found here,
+ // temporary destructor. If any other statements are found here,
// it must be a separate problem.
- assert(isa<CXXBindTemporaryExpr>(I.first.getStmt()));
+ assert(I.first.getItem().getKind() ==
+ ConstructionContextItem::TemporaryDestructorKind ||
+ I.first.getItem().getKind() ==
+ ConstructionContextItem::ElidedDestructorKind);
State = State->remove<ObjectsUnderConstruction>(I.first);
- // Also cleanup the elided destructor info.
- ElidedDestructorItem Item(
- cast<CXXBindTemporaryExpr>(I.first.getStmt()),
- I.first.getLocationContext());
- State = State->remove<ElidedDestructors>(Item);
}
-
- // Also suppress the assertion for elided destructors when temporary
- // destructors are not provided at all by the CFG, because there's no
- // good place to clean them up.
- if (!AMgr.getAnalyzerOptions().includeTemporaryDtorsInCFG())
- for (auto I : State->get<ElidedDestructors>())
- if (I.second == LC)
- State = State->remove<ElidedDestructors>(I);
-
LC = LC->getParent();
}
if (State != Pred->getState()) {
@@ -2338,7 +2294,7 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) {
// Evaluate the LHS of the case value.
llvm::APSInt V1 = Case->getLHS()->EvaluateKnownConstInt(getContext());
assert(V1.getBitWidth() == getContext().getIntWidth(CondE->getType()));
-
+
// Get the RHS of the case, if it exists.
llvm::APSInt V2;
if (const Expr *E = Case->getRHS())
@@ -2538,12 +2494,12 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
ExplodedNodeSet CheckedSet;
getCheckerManager().runCheckersForPreStmt(CheckedSet, Pred, M, *this);
- ExplodedNodeSet EvalSet;
- ValueDecl *Member = M->getMemberDecl();
+ ExplodedNodeSet EvalSet;
+ ValueDecl *Member = M->getMemberDecl();
// Handle static member variables and enum constants accessed via
// member syntax.
- if (isa<VarDecl>(Member) || isa<EnumConstantDecl>(Member)) {
+ if (isa<VarDecl>(Member) || isa<EnumConstantDecl>(Member)) {
for (const auto I : CheckedSet)
VisitCommonDeclRefExpr(M, Member, I, EvalSet);
} else {
diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index c7b1a9ac82f0..61b7a290e42a 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -684,7 +684,7 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred,
// known to be false, 1 if the value is known to be true and a new symbol
// when the assumption is unknown.
nonloc::ConcreteInt Zero(getBasicVals().getValue(0, B->getType()));
- X = evalBinOp(N->getState(), BO_NE,
+ X = evalBinOp(N->getState(), BO_NE,
svalBuilder.evalCast(RHSVal, B->getType(), RHS->getType()),
Zero, B->getType());
}
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index dc124fc3ff2d..4f1766a813c6 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -221,25 +221,42 @@ std::pair<ProgramStateRef, SVal> ExprEngine::prepareForObjectConstruction(
// and construct directly into the final object. This call
// also sets the CallOpts flags for us.
SVal V;
+ // If the elided copy/move constructor is not supported, there's still
+ // benefit in trying to model the non-elided constructor.
+ // Stash our state before trying to elide, as it'll get overwritten.
+ ProgramStateRef PreElideState = State;
+ EvalCallOptions PreElideCallOpts = CallOpts;
+
std::tie(State, V) = prepareForObjectConstruction(
CE, State, LCtx, TCC->getConstructionContextAfterElision(), CallOpts);
- // Remember that we've elided the constructor.
- State = addObjectUnderConstruction(State, CE, LCtx, V);
+ // FIXME: This definition of "copy elision has not failed" is unreliable.
+ // It doesn't indicate that the constructor will actually be inlined
+ // later; it is still up to evalCall() to decide.
+ if (!CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion) {
+ // Remember that we've elided the constructor.
+ State = addObjectUnderConstruction(State, CE, LCtx, V);
- // Remember that we've elided the destructor.
- if (BTE)
- State = elideDestructor(State, BTE, LCtx);
+ // Remember that we've elided the destructor.
+ if (BTE)
+ State = elideDestructor(State, BTE, LCtx);
- // Instead of materialization, shamelessly return
- // the final object destination.
- if (MTE)
- State = addObjectUnderConstruction(State, MTE, LCtx, V);
+ // Instead of materialization, shamelessly return
+ // the final object destination.
+ if (MTE)
+ State = addObjectUnderConstruction(State, MTE, LCtx, V);
- return std::make_pair(State, V);
+ return std::make_pair(State, V);
+ } else {
+ // Copy elision failed. Revert the changes and proceed as if we have
+ // a simple temporary.
+ State = PreElideState;
+ CallOpts = PreElideCallOpts;
+ }
+ LLVM_FALLTHROUGH;
}
case ConstructionContext::SimpleTemporaryObjectKind: {
- const auto *TCC = cast<SimpleTemporaryObjectConstructionContext>(CC);
+ const auto *TCC = cast<TemporaryObjectConstructionContext>(CC);
const CXXBindTemporaryExpr *BTE = TCC->getCXXBindTemporaryExpr();
const MaterializeTemporaryExpr *MTE = TCC->getMaterializedTemporaryExpr();
SVal V = UnknownVal();
@@ -274,6 +291,10 @@ std::pair<ProgramStateRef, SVal> ExprEngine::prepareForObjectConstruction(
CallOpts.IsTemporaryCtorOrDtor = true;
return std::make_pair(State, V);
}
+ case ConstructionContext::ArgumentKind: {
+ // Function argument constructors. Not implemented yet.
+ break;
+ }
}
}
// If we couldn't find an existing region to construct into, assume we're
diff --git a/lib/StaticAnalyzer/Core/IssueHash.cpp b/lib/StaticAnalyzer/Core/IssueHash.cpp
index 274ebe7a941b..6c55c61dd399 100644
--- a/lib/StaticAnalyzer/Core/IssueHash.cpp
+++ b/lib/StaticAnalyzer/Core/IssueHash.cpp
@@ -26,7 +26,7 @@
using namespace clang;
-// Get a string representation of the parts of the signature that can be
+// Get a string representation of the parts of the signature that can be
// overloaded on.
static std::string GetSignature(const FunctionDecl *Target) {
if (!Target)
diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp
index 2b401607293b..94e2e00d8bbc 100644
--- a/lib/StaticAnalyzer/Core/ProgramState.cpp
+++ b/lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/Analysis/CFG.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
@@ -494,6 +495,10 @@ void ProgramState::dumpTaint() const {
printTaint(llvm::errs());
}
+AnalysisManager& ProgramState::getAnalysisManager() const {
+ return stateMgr->getOwningEngine()->getAnalysisManager();
+}
+
//===----------------------------------------------------------------------===//
// Generic Data Map.
//===----------------------------------------------------------------------===//
diff --git a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index beae0dfae289..62c54fc956a9 100644
--- a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -440,7 +440,7 @@ static bool shouldRearrange(ProgramStateRef State, BinaryOperator::Opcode Op,
SymbolRef Sym, llvm::APSInt Int, QualType Ty) {
return Sym->getType() == Ty &&
(!BinaryOperator::isComparisonOp(Op) ||
- (isWithinConstantOverflowBounds(Sym, State) &&
+ (isWithinConstantOverflowBounds(Sym, State) &&
isWithinConstantOverflowBounds(Int)));
}
@@ -1236,11 +1236,21 @@ SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) {
return Sym == Val.getAsSymbol();
}
+ SVal cache(SymbolRef Sym, SVal V) {
+ Cached[Sym] = V;
+ return V;
+ }
+
+ SVal skip(SymbolRef Sym) {
+ return cache(Sym, SVB.makeSymbolVal(Sym));
+ }
+
public:
Simplifier(ProgramStateRef State)
: State(State), SVB(State->getStateManager().getSValBuilder()) {}
SVal VisitSymbolData(const SymbolData *S) {
+ // No cache here.
if (const llvm::APSInt *I =
SVB.getKnownValue(State, SVB.makeSymbolVal(S)))
return Loc::isLocType(S->getType()) ? (SVal)SVB.makeIntLocVal(*I)
@@ -1257,11 +1267,9 @@ SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) {
return I->second;
SVal LHS = Visit(S->getLHS());
- if (isUnchanged(S->getLHS(), LHS)) {
- SVal V = SVB.makeSymbolVal(S);
- Cached[S] = V;
- return V;
- }
+ if (isUnchanged(S->getLHS(), LHS))
+ return skip(S);
+
SVal RHS;
// By looking at the APSInt in the right-hand side of S, we cannot
// figure out if it should be treated as a Loc or as a NonLoc.
@@ -1281,9 +1289,8 @@ SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) {
RHS = SVB.makeIntVal(S->getRHS());
}
- SVal V = SVB.evalBinOp(State, S->getOpcode(), LHS, RHS, S->getType());
- Cached[S] = V;
- return V;
+ return cache(
+ S, SVB.evalBinOp(State, S->getOpcode(), LHS, RHS, S->getType()));
}
SVal VisitSymSymExpr(const SymSymExpr *S) {
@@ -1291,16 +1298,21 @@ SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) {
if (I != Cached.end())
return I->second;
+ // For now don't try to simplify mixed Loc/NonLoc expressions
+ // because they often appear from LocAsInteger operations
+ // and we don't know how to combine a LocAsInteger
+ // with a concrete value.
+ if (Loc::isLocType(S->getLHS()->getType()) !=
+ Loc::isLocType(S->getRHS()->getType()))
+ return skip(S);
+
SVal LHS = Visit(S->getLHS());
SVal RHS = Visit(S->getRHS());
- if (isUnchanged(S->getLHS(), LHS) && isUnchanged(S->getRHS(), RHS)) {
- SVal V = SVB.makeSymbolVal(S);
- Cached[S] = V;
- return V;
- }
- SVal V = SVB.evalBinOp(State, S->getOpcode(), LHS, RHS, S->getType());
- Cached[S] = V;
- return V;
+ if (isUnchanged(S->getLHS(), LHS) && isUnchanged(S->getRHS(), RHS))
+ return skip(S);
+
+ return cache(
+ S, SVB.evalBinOp(State, S->getOpcode(), LHS, RHS, S->getType()));
}
SVal VisitSymExpr(SymbolRef S) { return nonloc::SymbolVal(S); }
diff --git a/lib/StaticAnalyzer/Core/Store.cpp b/lib/StaticAnalyzer/Core/Store.cpp
index 5ab5c082269b..94188a9ef698 100644
--- a/lib/StaticAnalyzer/Core/Store.cpp
+++ b/lib/StaticAnalyzer/Core/Store.cpp
@@ -448,10 +448,10 @@ SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset,
// value. See also the similar FIXME in getLValueFieldOrIvar().
if (Base.isUnknownOrUndef() || Base.getAs<loc::ConcreteInt>())
return Base;
-
+
if (Base.getAs<loc::GotoLabel>())
return UnknownVal();
-
+
const SubRegion *BaseRegion =
Base.castAs<loc::MemRegionVal>().getRegionAs<SubRegion>();