diff options
Diffstat (limited to 'lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp | 139 |
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(); |