summaryrefslogtreecommitdiffstats
path: root/clang/lib/StaticAnalyzer
diff options
context:
space:
mode:
authorGabor Horvath <xazax@google.com>2019-12-09 16:26:38 -0800
committerGabor Horvath <xazax@google.com>2019-12-11 11:44:10 -0800
commit5882e6f36fd9bfc7382e6763c5591b3497428d83 (patch)
treea92ae113503296056e71cafeb7a63b83e0065558 /clang/lib/StaticAnalyzer
parent19e83a9b4cd4b0c2918d975f52bdfc6ba82d839f (diff)
downloadbcm5719-llvm-5882e6f36fd9bfc7382e6763c5591b3497428d83.tar.gz
bcm5719-llvm-5882e6f36fd9bfc7382e6763c5591b3497428d83.zip
[analyzer] Escape symbols conjured into specific regions during a conservative EvalCall
This patch introduced additional PointerEscape callbacks after conservative calls for output parameters. This should not really affect the current checkers but the upcoming FuchsiaHandleChecker relies on this heavily. Differential Revision: https://reviews.llvm.org/D71224
Diffstat (limited to 'clang/lib/StaticAnalyzer')
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp10
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngine.cpp88
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp6
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp44
4 files changed, 109 insertions, 39 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp
index d0def691893..2ef50a727ec 100644
--- a/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp
@@ -40,6 +40,7 @@ class AnalysisOrderChecker
check::EndFunction,
check::NewAllocator,
check::Bind,
+ check::PointerEscape,
check::RegionChanges,
check::LiveSymbols> {
@@ -165,6 +166,15 @@ public:
llvm::errs() << "RegionChanges\n";
return State;
}
+
+ ProgramStateRef checkPointerEscape(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call,
+ PointerEscapeKind Kind) const {
+ if (isCallbackEnabled(State, "PointerEscape"))
+ llvm::errs() << "PointerEscape\n";
+ return State;
+ }
};
} // end anonymous namespace
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index efbc20f0925..2a23d1cae7b 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1172,13 +1172,16 @@ void ExprEngine::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE,
}
}
-ProgramStateRef ExprEngine::escapeValue(ProgramStateRef State, SVal V,
- PointerEscapeKind K) const {
+ProgramStateRef ExprEngine::escapeValues(ProgramStateRef State,
+ ArrayRef<SVal> Vs,
+ PointerEscapeKind K,
+ const CallEvent *Call) const {
class CollectReachableSymbolsCallback final : public SymbolVisitor {
- InvalidatedSymbols Symbols;
+ InvalidatedSymbols &Symbols;
public:
- explicit CollectReachableSymbolsCallback(ProgramStateRef) {}
+ explicit CollectReachableSymbolsCallback(InvalidatedSymbols &Symbols)
+ : Symbols(Symbols) {}
const InvalidatedSymbols &getSymbols() const { return Symbols; }
@@ -1187,11 +1190,13 @@ ProgramStateRef ExprEngine::escapeValue(ProgramStateRef State, SVal V,
return true;
}
};
+ InvalidatedSymbols Symbols;
+ CollectReachableSymbolsCallback CallBack(Symbols);
+ for (SVal V : Vs)
+ State->scanReachableSymbols(V, CallBack);
- const CollectReachableSymbolsCallback &Scanner =
- State->scanReachableSymbols<CollectReachableSymbolsCallback>(V);
return getCheckerManager().runCheckersForPointerEscape(
- State, Scanner.getSymbols(), /*CallEvent*/ nullptr, K, nullptr);
+ State, CallBack.getSymbols(), Call, K, nullptr);
}
void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
@@ -1484,7 +1489,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
for (auto Child : Ex->children()) {
assert(Child);
SVal Val = State->getSVal(Child, LCtx);
- State = escapeValue(State, Val, PSK_EscapeOther);
+ State = escapeValues(State, Val, PSK_EscapeOther);
}
Bldr2.generateNode(S, N, State);
@@ -2685,33 +2690,52 @@ void ExprEngine::VisitAtomicExpr(const AtomicExpr *AE, ExplodedNode *Pred,
// destructor. We won't see the destructor during analysis, but it's there.
// (4) We are binding to a MemRegion with stack storage that the store
// does not understand.
+ProgramStateRef ExprEngine::processPointerEscapedOnBind(
+ ProgramStateRef State, ArrayRef<std::pair<SVal, SVal>> LocAndVals,
+ const LocationContext *LCtx, PointerEscapeKind Kind,
+ const CallEvent *Call) {
+ SmallVector<SVal, 8> Escaped;
+ for (const std::pair<SVal, SVal> &LocAndVal : LocAndVals) {
+ // Cases (1) and (2).
+ const MemRegion *MR = LocAndVal.first.getAsRegion();
+ if (!MR || !MR->hasStackStorage()) {
+ Escaped.push_back(LocAndVal.second);
+ continue;
+ }
+
+ // Case (3).
+ if (const auto *VR = dyn_cast<VarRegion>(MR->getBaseRegion()))
+ if (VR->hasStackParametersStorage() && VR->getStackFrame()->inTopFrame())
+ if (const auto *RD = VR->getValueType()->getAsCXXRecordDecl())
+ if (!RD->hasTrivialDestructor()) {
+ Escaped.push_back(LocAndVal.second);
+ continue;
+ }
+
+ // Case (4): in order to test that, generate a new state with the binding
+ // added. If it is the same state, then it escapes (since the store cannot
+ // represent the binding).
+ // Do this only if we know that the store is not supposed to generate the
+ // same state.
+ SVal StoredVal = State->getSVal(MR);
+ if (StoredVal != LocAndVal.second)
+ if (State ==
+ (State->bindLoc(loc::MemRegionVal(MR), LocAndVal.second, LCtx)))
+ Escaped.push_back(LocAndVal.second);
+ }
+
+ if (Escaped.empty())
+ return State;
+
+ return escapeValues(State, Escaped, Kind, Call);
+}
+
ProgramStateRef
ExprEngine::processPointerEscapedOnBind(ProgramStateRef State, SVal Loc,
SVal Val, const LocationContext *LCtx) {
-
- // Cases (1) and (2).
- const MemRegion *MR = Loc.getAsRegion();
- if (!MR || !MR->hasStackStorage())
- return escapeValue(State, Val, PSK_EscapeOnBind);
-
- // Case (3).
- if (const auto *VR = dyn_cast<VarRegion>(MR->getBaseRegion()))
- if (VR->hasStackParametersStorage() && VR->getStackFrame()->inTopFrame())
- if (const auto *RD = VR->getValueType()->getAsCXXRecordDecl())
- if (!RD->hasTrivialDestructor())
- return escapeValue(State, Val, PSK_EscapeOnBind);
-
- // Case (4): in order to test that, generate a new state with the binding
- // added. If it is the same state, then it escapes (since the store cannot
- // represent the binding).
- // Do this only if we know that the store is not supposed to generate the
- // same state.
- SVal StoredVal = State->getSVal(MR);
- if (StoredVal != Val)
- if (State == (State->bindLoc(loc::MemRegionVal(MR), Val, LCtx)))
- return escapeValue(State, Val, PSK_EscapeOnBind);
-
- return State;
+ std::pair<SVal, SVal> LocAndVal(Loc, Val);
+ return processPointerEscapedOnBind(State, LocAndVal, LCtx, PSK_EscapeOnBind,
+ nullptr);
}
ProgramStateRef
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 02a398c77ac..b17f26aa9c5 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -102,8 +102,8 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
state = state->BindExpr(B, LCtx, Result);
} else {
// If we cannot evaluate the operation escape the operands.
- state = escapeValue(state, LeftV, PSK_EscapeOther);
- state = escapeValue(state, RightV, PSK_EscapeOther);
+ state = escapeValues(state, LeftV, PSK_EscapeOther);
+ state = escapeValues(state, RightV, PSK_EscapeOther);
}
Bldr.generateNode(B, *it, state);
@@ -275,7 +275,7 @@ ProgramStateRef ExprEngine::handleLValueBitCast(
V = evalMinus(V);
state = state->BindExpr(CastE, LCtx, V);
if (V.isUnknown() && !OrigV.isUnknown()) {
- state = escapeValue(state, OrigV, PSK_EscapeOther);
+ state = escapeValues(state, OrigV, PSK_EscapeOther);
}
Bldr.generateNode(CastE, Pred, state);
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 345d4d817de..01a371e664b 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/Decl.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "PrettyStackTraceLocationContext.h"
#include "clang/AST/CXXInheritance.h"
@@ -592,9 +593,45 @@ void ExprEngine::evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
for (auto I : dstCallEvaluated)
finishArgumentConstruction(dstArgumentCleanup, I, Call);
- // Finally, run any post-call checks.
- getCheckerManager().runCheckersForPostCall(Dst, dstArgumentCleanup,
+ ExplodedNodeSet dstPostCall;
+ getCheckerManager().runCheckersForPostCall(dstPostCall, dstArgumentCleanup,
Call, *this);
+
+ // Escaping symbols conjured during invalidating the regions above.
+ // Note that, for inlined calls the nodes were put back into the worklist,
+ // so we can assume that every node belongs to a conservative call at this
+ // point.
+
+ // Run pointerEscape callback with the newly conjured symbols.
+ SmallVector<std::pair<SVal, SVal>, 8> Escaped;
+ for (auto I : dstPostCall) {
+ NodeBuilder B(I, Dst, *currBldrCtx);
+ ProgramStateRef State = I->getState();
+ Escaped.clear();
+ {
+ unsigned Arg = -1;
+ for (const ParmVarDecl *PVD : Call.parameters()) {
+ ++Arg;
+ QualType ParamTy = PVD->getType();
+ if (ParamTy.isNull() ||
+ (!ParamTy->isPointerType() && !ParamTy->isReferenceType()))
+ continue;
+ QualType Pointee = ParamTy->getPointeeType();
+ if (Pointee.isConstQualified() || Pointee->isVoidType())
+ continue;
+ if (const MemRegion *MR = Call.getArgSVal(Arg).getAsRegion())
+ Escaped.emplace_back(loc::MemRegionVal(MR), State->getSVal(MR, Pointee));
+ }
+ }
+
+ State = processPointerEscapedOnBind(State, Escaped, I->getLocationContext(),
+ PSK_EscapeOutParameters, &Call);
+
+ if (State == I->getState())
+ Dst.insert(I);
+ else
+ B.generateNode(I->getLocation(), State, I);
+ }
}
ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call,
@@ -670,8 +707,7 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call,
// Conservatively evaluate call by invalidating regions and binding
// a conjured return value.
void ExprEngine::conservativeEvalCall(const CallEvent &Call, NodeBuilder &Bldr,
- ExplodedNode *Pred,
- ProgramStateRef State) {
+ ExplodedNode *Pred, ProgramStateRef State) {
State = Call.invalidateRegions(currBldrCtx->blockCount(), State);
State = bindReturnValue(Call, Pred->getLocationContext(), State);
OpenPOWER on IntegriCloud