clang API Documentation
00001 // MacOSXAPIChecker.h - Checks proper use of various MacOS X APIs --*- C++ -*-// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This defines MacOSXAPIChecker, which is an assortment of checks on calls 00011 // to various, widely used Apple APIs. 00012 // 00013 // FIXME: What's currently in BasicObjCFoundationChecks.cpp should be migrated 00014 // to here, using the new Checker interface. 00015 // 00016 //===----------------------------------------------------------------------===// 00017 00018 #include "ClangSACheckers.h" 00019 #include "clang/Basic/TargetInfo.h" 00020 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 00021 #include "clang/StaticAnalyzer/Core/Checker.h" 00022 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 00023 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 00024 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" 00025 #include "llvm/ADT/SmallString.h" 00026 #include "llvm/ADT/StringSwitch.h" 00027 #include "llvm/Support/raw_ostream.h" 00028 00029 using namespace clang; 00030 using namespace ento; 00031 00032 namespace { 00033 class MacOSXAPIChecker : public Checker< check::PreStmt<CallExpr> > { 00034 mutable std::unique_ptr<BugType> BT_dispatchOnce; 00035 00036 public: 00037 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; 00038 00039 void CheckDispatchOnce(CheckerContext &C, const CallExpr *CE, 00040 StringRef FName) const; 00041 00042 typedef void (MacOSXAPIChecker::*SubChecker)(CheckerContext &, 00043 const CallExpr *, 00044 StringRef FName) const; 00045 }; 00046 } //end anonymous namespace 00047 00048 //===----------------------------------------------------------------------===// 00049 // dispatch_once and dispatch_once_f 00050 //===----------------------------------------------------------------------===// 00051 00052 void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE, 00053 StringRef FName) const { 00054 if (CE->getNumArgs() < 1) 00055 return; 00056 00057 // Check if the first argument is stack allocated. If so, issue a warning 00058 // because that's likely to be bad news. 00059 ProgramStateRef state = C.getState(); 00060 const MemRegion *R = 00061 state->getSVal(CE->getArg(0), C.getLocationContext()).getAsRegion(); 00062 if (!R || !isa<StackSpaceRegion>(R->getMemorySpace())) 00063 return; 00064 00065 ExplodedNode *N = C.generateSink(state); 00066 if (!N) 00067 return; 00068 00069 if (!BT_dispatchOnce) 00070 BT_dispatchOnce.reset(new BugType(this, "Improper use of 'dispatch_once'", 00071 "API Misuse (Apple)")); 00072 00073 // Handle _dispatch_once. In some versions of the OS X SDK we have the case 00074 // that dispatch_once is a macro that wraps a call to _dispatch_once. 00075 // _dispatch_once is then a function which then calls the real dispatch_once. 00076 // Users do not care; they just want the warning at the top-level call. 00077 if (CE->getLocStart().isMacroID()) { 00078 StringRef TrimmedFName = FName.ltrim("_"); 00079 if (TrimmedFName != FName) 00080 FName = TrimmedFName; 00081 } 00082 00083 SmallString<256> S; 00084 llvm::raw_svector_ostream os(S); 00085 os << "Call to '" << FName << "' uses"; 00086 if (const VarRegion *VR = dyn_cast<VarRegion>(R)) 00087 os << " the local variable '" << VR->getDecl()->getName() << '\''; 00088 else 00089 os << " stack allocated memory"; 00090 os << " for the predicate value. Using such transient memory for " 00091 "the predicate is potentially dangerous."; 00092 if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace())) 00093 os << " Perhaps you intended to declare the variable as 'static'?"; 00094 00095 BugReport *report = new BugReport(*BT_dispatchOnce, os.str(), N); 00096 report->addRange(CE->getArg(0)->getSourceRange()); 00097 C.emitReport(report); 00098 } 00099 00100 //===----------------------------------------------------------------------===// 00101 // Central dispatch function. 00102 //===----------------------------------------------------------------------===// 00103 00104 void MacOSXAPIChecker::checkPreStmt(const CallExpr *CE, 00105 CheckerContext &C) const { 00106 StringRef Name = C.getCalleeName(CE); 00107 if (Name.empty()) 00108 return; 00109 00110 SubChecker SC = 00111 llvm::StringSwitch<SubChecker>(Name) 00112 .Cases("dispatch_once", 00113 "_dispatch_once", 00114 "dispatch_once_f", 00115 &MacOSXAPIChecker::CheckDispatchOnce) 00116 .Default(nullptr); 00117 00118 if (SC) 00119 (this->*SC)(C, CE, Name); 00120 } 00121 00122 //===----------------------------------------------------------------------===// 00123 // Registration. 00124 //===----------------------------------------------------------------------===// 00125 00126 void ento::registerMacOSXAPIChecker(CheckerManager &mgr) { 00127 mgr.registerChecker<MacOSXAPIChecker>(); 00128 }