MacOSXAPIChecker.cpp revision 027a6abdd6cedc0b8203da72eed6d15c796dce9d
1// MacOSXAPIChecker.h - Checks proper use of various MacOS X APIs --*- C++ -*-// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This defines MacOSXAPIChecker, which is an assortment of checks on calls 11// to various, widely used Mac OS X functions. 12// 13// FIXME: What's currently in BasicObjCFoundationChecks.cpp should be migrated 14// to here, using the new Checker interface. 15// 16//===----------------------------------------------------------------------===// 17 18#include "ClangSACheckers.h" 19#include "clang/Basic/TargetInfo.h" 20#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 21#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h" 22#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h" 23#include "llvm/ADT/SmallString.h" 24#include "llvm/ADT/StringSwitch.h" 25#include "llvm/Support/raw_ostream.h" 26 27using namespace clang; 28using namespace ento; 29 30namespace { 31class MacOSXAPIChecker : public CheckerVisitor<MacOSXAPIChecker> { 32 enum SubChecks { 33 DispatchOnce = 0, 34 DispatchOnceF, 35 NumChecks 36 }; 37 38 BugType *BTypes[NumChecks]; 39 40public: 41 MacOSXAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); } 42 static void *getTag() { static unsigned tag = 0; return &tag; } 43 44 void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); 45}; 46} //end anonymous namespace 47 48void ento::registerMacOSXAPIChecker(ExprEngine &Eng) { 49 Eng.registerCheck(new MacOSXAPIChecker()); 50} 51 52//===----------------------------------------------------------------------===// 53// dispatch_once and dispatch_once_f 54//===----------------------------------------------------------------------===// 55 56static void CheckDispatchOnce(CheckerContext &C, const CallExpr *CE, 57 BugType *&BT, const IdentifierInfo *FI) { 58 59 if (!BT) { 60 llvm::SmallString<128> S; 61 llvm::raw_svector_ostream os(S); 62 os << "Improper use of '" << FI->getName() << '\''; 63 BT = new BugType(os.str(), "Mac OS X API"); 64 } 65 66 if (CE->getNumArgs() < 1) 67 return; 68 69 // Check if the first argument is stack allocated. If so, issue a warning 70 // because that's likely to be bad news. 71 const GRState *state = C.getState(); 72 const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion(); 73 if (!R || !isa<StackSpaceRegion>(R->getMemorySpace())) 74 return; 75 76 ExplodedNode *N = C.generateSink(state); 77 if (!N) 78 return; 79 80 llvm::SmallString<256> S; 81 llvm::raw_svector_ostream os(S); 82 os << "Call to '" << FI->getName() << "' uses"; 83 if (const VarRegion *VR = dyn_cast<VarRegion>(R)) 84 os << " the local variable '" << VR->getDecl()->getName() << '\''; 85 else 86 os << " stack allocated memory"; 87 os << " for the predicate value. Using such transient memory for " 88 "the predicate is potentially dangerous."; 89 if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace())) 90 os << " Perhaps you intended to declare the variable as 'static'?"; 91 92 EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), N); 93 report->addRange(CE->getArg(0)->getSourceRange()); 94 C.EmitReport(report); 95} 96 97//===----------------------------------------------------------------------===// 98// Central dispatch function. 99//===----------------------------------------------------------------------===// 100 101typedef void (*SubChecker)(CheckerContext &C, const CallExpr *CE, BugType *&BT, 102 const IdentifierInfo *FI); 103namespace { 104 class SubCheck { 105 SubChecker SC; 106 BugType **BT; 107 public: 108 SubCheck(SubChecker sc, BugType *& bt) : SC(sc), BT(&bt) {} 109 SubCheck() : SC(NULL), BT(NULL) {} 110 111 void run(CheckerContext &C, const CallExpr *CE, 112 const IdentifierInfo *FI) const { 113 if (SC) 114 SC(C, CE, *BT, FI); 115 } 116 }; 117} // end anonymous namespace 118 119void MacOSXAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) { 120 // FIXME: Mostly copy and paste from UnixAPIChecker. Should refactor. 121 const GRState *state = C.getState(); 122 const Expr *Callee = CE->getCallee(); 123 const FunctionTextRegion *Fn = 124 dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion()); 125 126 if (!Fn) 127 return; 128 129 const IdentifierInfo *FI = Fn->getDecl()->getIdentifier(); 130 if (!FI) 131 return; 132 133 const SubCheck &SC = 134 llvm::StringSwitch<SubCheck>(FI->getName()) 135 .Case("dispatch_once", SubCheck(CheckDispatchOnce, BTypes[DispatchOnce])) 136 .Case("dispatch_once_f", SubCheck(CheckDispatchOnce, 137 BTypes[DispatchOnceF])) 138 .Default(SubCheck()); 139 140 SC.run(C, CE, FI); 141} 142