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/CheckerManager.h" 21 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 22 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h" 23 #include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h" 24 #include "llvm/ADT/SmallString.h" 25 #include "llvm/ADT/StringSwitch.h" 26 #include "llvm/Support/raw_ostream.h" 27 28 using namespace clang; 29 using namespace ento; 30 31 namespace { 32 class MacOSXAPIChecker : public CheckerVisitor<MacOSXAPIChecker> { 33 enum SubChecks { 34 DispatchOnce = 0, 35 DispatchOnceF, 36 NumChecks 37 }; 38 39 BugType *BTypes[NumChecks]; 40 41 public: 42 MacOSXAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); } 43 static void *getTag() { static unsigned tag = 0; return &tag; } 44 45 void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); 46 }; 47 } //end anonymous namespace 48 49 static void RegisterMacOSXAPIChecker(ExprEngine &Eng) { 50 Eng.registerCheck(new MacOSXAPIChecker()); 51 } 52 53 void ento::registerMacOSXAPIChecker(CheckerManager &mgr) { 54 mgr.addCheckerRegisterFunction(RegisterMacOSXAPIChecker); 55 } 56 57 //===----------------------------------------------------------------------===// 58 // dispatch_once and dispatch_once_f 59 //===----------------------------------------------------------------------===// 60 61 static void CheckDispatchOnce(CheckerContext &C, const CallExpr *CE, 62 BugType *&BT, const IdentifierInfo *FI) { 63 64 if (!BT) { 65 llvm::SmallString<128> S; 66 llvm::raw_svector_ostream os(S); 67 os << "Improper use of '" << FI->getName() << '\''; 68 BT = new BugType(os.str(), "Mac OS X API"); 69 } 70 71 if (CE->getNumArgs() < 1) 72 return; 73 74 // Check if the first argument is stack allocated. If so, issue a warning 75 // because that's likely to be bad news. 76 const GRState *state = C.getState(); 77 const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion(); 78 if (!R || !isa<StackSpaceRegion>(R->getMemorySpace())) 79 return; 80 81 ExplodedNode *N = C.generateSink(state); 82 if (!N) 83 return; 84 85 llvm::SmallString<256> S; 86 llvm::raw_svector_ostream os(S); 87 os << "Call to '" << FI->getName() << "' uses"; 88 if (const VarRegion *VR = dyn_cast<VarRegion>(R)) 89 os << " the local variable '" << VR->getDecl()->getName() << '\''; 90 else 91 os << " stack allocated memory"; 92 os << " for the predicate value. Using such transient memory for " 93 "the predicate is potentially dangerous."; 94 if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace())) 95 os << " Perhaps you intended to declare the variable as 'static'?"; 96 97 EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), N); 98 report->addRange(CE->getArg(0)->getSourceRange()); 99 C.EmitReport(report); 100 } 101 102 //===----------------------------------------------------------------------===// 103 // Central dispatch function. 104 //===----------------------------------------------------------------------===// 105 106 typedef void (*SubChecker)(CheckerContext &C, const CallExpr *CE, BugType *&BT, 107 const IdentifierInfo *FI); 108 namespace { 109 class SubCheck { 110 SubChecker SC; 111 BugType **BT; 112 public: 113 SubCheck(SubChecker sc, BugType *& bt) : SC(sc), BT(&bt) {} 114 SubCheck() : SC(NULL), BT(NULL) {} 115 116 void run(CheckerContext &C, const CallExpr *CE, 117 const IdentifierInfo *FI) const { 118 if (SC) 119 SC(C, CE, *BT, FI); 120 } 121 }; 122 } // end anonymous namespace 123 124 void MacOSXAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) { 125 // FIXME: Mostly copy and paste from UnixAPIChecker. Should refactor. 126 const GRState *state = C.getState(); 127 const Expr *Callee = CE->getCallee(); 128 const FunctionTextRegion *Fn = 129 dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion()); 130 131 if (!Fn) 132 return; 133 134 const IdentifierInfo *FI = Fn->getDecl()->getIdentifier(); 135 if (!FI) 136 return; 137 138 const SubCheck &SC = 139 llvm::StringSwitch<SubCheck>(FI->getName()) 140 .Case("dispatch_once", SubCheck(CheckDispatchOnce, BTypes[DispatchOnce])) 141 .Case("dispatch_once_f", SubCheck(CheckDispatchOnce, 142 BTypes[DispatchOnceF])) 143 .Default(SubCheck()); 144 145 SC.run(C, CE, FI); 146 } 147