summaryrefslogtreecommitdiffstats
path: root/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp')
-rw-r--r--lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp139
1 files changed, 37 insertions, 102 deletions
diff --git a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
index 76f20b6..f1f06c7 100644
--- a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
@@ -13,22 +13,21 @@
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
using namespace ento;
namespace {
class MacOSKeychainAPIChecker : public Checker<check::PreStmt<CallExpr>,
- check::PreStmt<ReturnStmt>,
check::PostStmt<CallExpr>,
- check::EndPath,
check::DeadSymbols> {
mutable OwningPtr<BugType> BT;
@@ -56,14 +55,12 @@ public:
};
void checkPreStmt(const CallExpr *S, CheckerContext &C) const;
- void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
void checkPostStmt(const CallExpr *S, CheckerContext &C) const;
void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
- void checkEndPath(CheckerContext &C) const;
private:
typedef std::pair<SymbolRef, const AllocationState*> AllocationPair;
- typedef llvm::SmallVector<AllocationPair, 2> AllocationPairVec;
+ typedef SmallVector<AllocationPair, 2> AllocationPairVec;
enum APIKind {
/// Denotes functions tracked by this checker.
@@ -94,7 +91,8 @@ private:
inline void initBugType() const {
if (!BT)
- BT.reset(new BugType("Improper use of SecKeychain API", "Mac OS API"));
+ BT.reset(new BugType("Improper use of SecKeychain API",
+ "API Misuse (Apple)"));
}
void generateDeallocatorMismatchReport(const AllocationPair &AP,
@@ -102,8 +100,8 @@ private:
CheckerContext &C) const;
/// Find the allocation site for Sym on the path leading to the node N.
- const Stmt *getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
- CheckerContext &C) const;
+ const ExplodedNode *getAllocationNode(const ExplodedNode *N, SymbolRef Sym,
+ CheckerContext &C) const;
BugReport *generateAllocatedDataNotReleasedReport(const AllocationPair &AP,
ExplodedNode *N,
@@ -220,7 +218,7 @@ static SymbolRef getAsPointeeSymbol(const Expr *Expr,
ProgramStateRef State = C.getState();
SVal ArgV = State->getSVal(Expr, C.getLocationContext());
- if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(&ArgV)) {
+ if (Optional<loc::MemRegionVal> X = ArgV.getAs<loc::MemRegionVal>()) {
StoreManager& SM = C.getStoreManager();
SymbolRef sym = SM.getBinding(State->getStore(), *X).getAsLocSymbol();
if (sym)
@@ -396,16 +394,18 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
return;
}
// If kCFAllocatorNull, which does not deallocate, we still have to
- // find the deallocator. Otherwise, assume that the user had written a
- // custom deallocator which does the right thing.
- if (DE->getFoundDecl()->getName() != "kCFAllocatorNull") {
- State = State->remove<AllocatedData>(ArgSM);
- C.addTransition(State);
+ // find the deallocator.
+ if (DE->getFoundDecl()->getName() == "kCFAllocatorNull")
return;
- }
}
+ // In all other cases, assume the user supplied a correct deallocator
+ // that will free memory so stop tracking.
+ State = State->remove<AllocatedData>(ArgSM);
+ C.addTransition(State);
+ return;
}
- return;
+
+ llvm_unreachable("We know of no other possible APIs.");
}
// The call is deallocating a value we previously allocated, so remove it
@@ -422,7 +422,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
// If the buffer can be null and the return status can be an error,
// report a bad call to free.
- if (State->assume(cast<DefinedSVal>(ArgSVal), false) &&
+ if (State->assume(ArgSVal.castAs<DefinedSVal>(), false) &&
!definitelyDidnotReturnError(AS->Region, State, C.getSValBuilder())) {
ExplodedNode *N = C.addTransition(State);
if (!N)
@@ -486,31 +486,9 @@ void MacOSKeychainAPIChecker::checkPostStmt(const CallExpr *CE,
}
}
-void MacOSKeychainAPIChecker::checkPreStmt(const ReturnStmt *S,
- CheckerContext &C) const {
- const Expr *retExpr = S->getRetValue();
- if (!retExpr)
- return;
-
- // If inside inlined call, skip it.
- const LocationContext *LC = C.getLocationContext();
- if (LC->getParent() != 0)
- return;
-
- // Check if the value is escaping through the return.
- ProgramStateRef state = C.getState();
- SymbolRef sym = state->getSVal(retExpr, LC).getAsLocSymbol();
- if (!sym)
- return;
- state = state->remove<AllocatedData>(sym);
-
- // Proceed from the new state.
- C.addTransition(state);
-}
-
// TODO: This logic is the same as in Malloc checker.
-const Stmt *
-MacOSKeychainAPIChecker::getAllocationSite(const ExplodedNode *N,
+const ExplodedNode *
+MacOSKeychainAPIChecker::getAllocationNode(const ExplodedNode *N,
SymbolRef Sym,
CheckerContext &C) const {
const LocationContext *LeakContext = N->getLocationContext();
@@ -528,12 +506,7 @@ MacOSKeychainAPIChecker::getAllocationSite(const ExplodedNode *N,
N = N->pred_empty() ? NULL : *(N->pred_begin());
}
- ProgramPoint P = AllocNode->getLocation();
- if (CallExitEnd *Exit = dyn_cast<CallExitEnd>(&P))
- return Exit->getCalleeContext()->getCallSite();
- if (clang::PostStmt *PS = dyn_cast<clang::PostStmt>(&P))
- return PS->getStmt();
- return 0;
+ return AllocNode;
}
BugReport *MacOSKeychainAPIChecker::
@@ -551,11 +524,22 @@ BugReport *MacOSKeychainAPIChecker::
// With leaks, we want to unique them by the location where they were
// allocated, and only report a single path.
PathDiagnosticLocation LocUsedForUniqueing;
- if (const Stmt *AllocStmt = getAllocationSite(N, AP.first, C))
+ const ExplodedNode *AllocNode = getAllocationNode(N, AP.first, C);
+ const Stmt *AllocStmt = 0;
+ ProgramPoint P = AllocNode->getLocation();
+ if (Optional<CallExitEnd> Exit = P.getAs<CallExitEnd>())
+ AllocStmt = Exit->getCalleeContext()->getCallSite();
+ else if (Optional<clang::PostStmt> PS = P.getAs<clang::PostStmt>())
+ AllocStmt = PS->getStmt();
+
+ if (AllocStmt)
LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocStmt,
- C.getSourceManager(), N->getLocationContext());
+ C.getSourceManager(),
+ AllocNode->getLocationContext());
+
+ BugReport *Report = new BugReport(*BT, os.str(), N, LocUsedForUniqueing,
+ AllocNode->getLocationContext()->getDecl());
- BugReport *Report = new BugReport(*BT, os.str(), N, LocUsedForUniqueing);
Report->addVisitor(new SecKeychainBugVisitor(AP.first));
markInteresting(Report, AP);
return Report;
@@ -604,55 +588,6 @@ void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR,
C.addTransition(State, N);
}
-// TODO: Remove this after we ensure that checkDeadSymbols are always called.
-void MacOSKeychainAPIChecker::checkEndPath(CheckerContext &C) const {
- ProgramStateRef state = C.getState();
-
- // If inside inlined call, skip it.
- if (C.getLocationContext()->getParent() != 0)
- return;
-
- AllocatedDataTy AS = state->get<AllocatedData>();
- if (AS.isEmpty())
- return;
-
- // Anything which has been allocated but not freed (nor escaped) will be
- // found here, so report it.
- bool Changed = false;
- AllocationPairVec Errors;
- for (AllocatedDataTy::iterator I = AS.begin(), E = AS.end(); I != E; ++I ) {
- Changed = true;
- state = state->remove<AllocatedData>(I->first);
- // If the allocated symbol is null or if error code was returned at
- // allocation, do not report.
- ConstraintManager &CMgr = state->getConstraintManager();
- ConditionTruthVal AllocFailed = CMgr.isNull(state, I.getKey());
- if (AllocFailed.isConstrainedTrue() ||
- definitelyReturnedError(I->second.Region, state,
- C.getSValBuilder())) {
- continue;
- }
- Errors.push_back(std::make_pair(I->first, &I->second));
- }
-
- // If no change, do not generate a new state.
- if (!Changed) {
- C.addTransition(state);
- return;
- }
-
- static SimpleProgramPointTag Tag("MacOSKeychainAPIChecker : EndPathLeak");
- ExplodedNode *N = C.addTransition(C.getState(), C.getPredecessor(), &Tag);
-
- // Generate the error reports.
- for (AllocationPairVec::iterator I = Errors.begin(), E = Errors.end();
- I != E; ++I) {
- C.emitReport(generateAllocatedDataNotReleasedReport(*I, N, C));
- }
-
- C.addTransition(state, N);
-}
-
PathDiagnosticPiece *MacOSKeychainAPIChecker::SecKeychainBugVisitor::VisitNode(
const ExplodedNode *N,
@@ -668,8 +603,8 @@ PathDiagnosticPiece *MacOSKeychainAPIChecker::SecKeychainBugVisitor::VisitNode(
// (!ASPrev && AS) ~ We started tracking symbol in node N, it must be the
// allocation site.
- const CallExpr *CE = cast<CallExpr>(cast<StmtPoint>(N->getLocation())
- .getStmt());
+ const CallExpr *CE =
+ cast<CallExpr>(N->getLocation().castAs<StmtPoint>().getStmt());
const FunctionDecl *funDecl = CE->getDirectCallee();
assert(funDecl && "We do not support indirect function calls as of now.");
StringRef funName = funDecl->getName();
OpenPOWER on IntegriCloud