From c72c57c9e9b69944e3e009cd5e209634839581d3 Mon Sep 17 00:00:00 2001 From: dim Date: Mon, 8 Apr 2013 18:45:10 +0000 Subject: Vendor import of clang trunk r178860: http://llvm.org/svn/llvm-project/cfe/trunk@178860 --- .../Checkers/MacOSKeychainAPIChecker.cpp | 139 ++++++--------------- 1 file changed, 37 insertions(+), 102 deletions(-) (limited to 'lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp') 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, check::PostStmt, - check::EndPath, check::DeadSymbols> { mutable OwningPtr 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 AllocationPair; - typedef llvm::SmallVector AllocationPairVec; + typedef SmallVector 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(&ArgV)) { + if (Optional X = ArgV.getAs()) { 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(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(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(ArgSVal), false) && + if (State->assume(ArgSVal.castAs(), 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(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(&P)) - return Exit->getCalleeContext()->getCallSite(); - if (clang::PostStmt *PS = dyn_cast(&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 Exit = P.getAs()) + AllocStmt = Exit->getCalleeContext()->getCallSite(); + else if (Optional PS = P.getAs()) + 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(); - 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(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(cast(N->getLocation()) - .getStmt()); + const CallExpr *CE = + cast(N->getLocation().castAs().getStmt()); const FunctionDecl *funDecl = CE->getDirectCallee(); assert(funDecl && "We do not support indirect function calls as of now."); StringRef funName = funDecl->getName(); -- cgit v1.1