clang API Documentation
00001 //= UnixAPIChecker.h - Checks preconditions for various Unix 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 UnixAPIChecker, which is an assortment of checks on calls 00011 // to various, widely used UNIX/Posix functions. 00012 // 00013 //===----------------------------------------------------------------------===// 00014 00015 #include "ClangSACheckers.h" 00016 #include "clang/StaticAnalyzer/Core/Checker.h" 00017 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 00018 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 00019 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 00020 #include "clang/Basic/TargetInfo.h" 00021 #include "llvm/ADT/Optional.h" 00022 #include "llvm/ADT/SmallString.h" 00023 #include "llvm/ADT/STLExtras.h" 00024 #include "llvm/ADT/StringSwitch.h" 00025 #include <fcntl.h> 00026 00027 using namespace clang; 00028 using namespace ento; 00029 using llvm::Optional; 00030 00031 namespace { 00032 class UnixAPIChecker : public Checker< check::PreStmt<CallExpr> > { 00033 mutable OwningPtr<BugType> BT_open, BT_pthreadOnce, BT_mallocZero; 00034 mutable Optional<uint64_t> Val_O_CREAT; 00035 00036 public: 00037 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; 00038 00039 void CheckOpen(CheckerContext &C, const CallExpr *CE) const; 00040 void CheckPthreadOnce(CheckerContext &C, const CallExpr *CE) const; 00041 void CheckCallocZero(CheckerContext &C, const CallExpr *CE) const; 00042 void CheckMallocZero(CheckerContext &C, const CallExpr *CE) const; 00043 void CheckReallocZero(CheckerContext &C, const CallExpr *CE) const; 00044 void CheckAllocaZero(CheckerContext &C, const CallExpr *CE) const; 00045 void CheckVallocZero(CheckerContext &C, const CallExpr *CE) const; 00046 00047 typedef void (UnixAPIChecker::*SubChecker)(CheckerContext &, 00048 const CallExpr *) const; 00049 private: 00050 bool ReportZeroByteAllocation(CheckerContext &C, 00051 ProgramStateRef falseState, 00052 const Expr *arg, 00053 const char *fn_name) const; 00054 void BasicAllocationCheck(CheckerContext &C, 00055 const CallExpr *CE, 00056 const unsigned numArgs, 00057 const unsigned sizeArg, 00058 const char *fn) const; 00059 }; 00060 } //end anonymous namespace 00061 00062 //===----------------------------------------------------------------------===// 00063 // Utility functions. 00064 //===----------------------------------------------------------------------===// 00065 00066 static inline void LazyInitialize(OwningPtr<BugType> &BT, 00067 const char *name) { 00068 if (BT) 00069 return; 00070 BT.reset(new BugType(name, categories::UnixAPI)); 00071 } 00072 00073 //===----------------------------------------------------------------------===// 00074 // "open" (man 2 open) 00075 //===----------------------------------------------------------------------===// 00076 00077 void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const { 00078 // The definition of O_CREAT is platform specific. We need a better way 00079 // of querying this information from the checking environment. 00080 if (!Val_O_CREAT.hasValue()) { 00081 if (C.getASTContext().getTargetInfo().getTriple().getVendor() 00082 == llvm::Triple::Apple) 00083 Val_O_CREAT = 0x0200; 00084 else { 00085 // FIXME: We need a more general way of getting the O_CREAT value. 00086 // We could possibly grovel through the preprocessor state, but 00087 // that would require passing the Preprocessor object to the ExprEngine. 00088 return; 00089 } 00090 } 00091 00092 // Look at the 'oflags' argument for the O_CREAT flag. 00093 ProgramStateRef state = C.getState(); 00094 00095 if (CE->getNumArgs() < 2) { 00096 // The frontend should issue a warning for this case, so this is a sanity 00097 // check. 00098 return; 00099 } 00100 00101 // Now check if oflags has O_CREAT set. 00102 const Expr *oflagsEx = CE->getArg(1); 00103 const SVal V = state->getSVal(oflagsEx, C.getLocationContext()); 00104 if (!isa<NonLoc>(V)) { 00105 // The case where 'V' can be a location can only be due to a bad header, 00106 // so in this case bail out. 00107 return; 00108 } 00109 NonLoc oflags = cast<NonLoc>(V); 00110 NonLoc ocreateFlag = 00111 cast<NonLoc>(C.getSValBuilder().makeIntVal(Val_O_CREAT.getValue(), 00112 oflagsEx->getType())); 00113 SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And, 00114 oflags, ocreateFlag, 00115 oflagsEx->getType()); 00116 if (maskedFlagsUC.isUnknownOrUndef()) 00117 return; 00118 DefinedSVal maskedFlags = cast<DefinedSVal>(maskedFlagsUC); 00119 00120 // Check if maskedFlags is non-zero. 00121 ProgramStateRef trueState, falseState; 00122 llvm::tie(trueState, falseState) = state->assume(maskedFlags); 00123 00124 // Only emit an error if the value of 'maskedFlags' is properly 00125 // constrained; 00126 if (!(trueState && !falseState)) 00127 return; 00128 00129 if (CE->getNumArgs() < 3) { 00130 ExplodedNode *N = C.generateSink(trueState); 00131 if (!N) 00132 return; 00133 00134 LazyInitialize(BT_open, "Improper use of 'open'"); 00135 00136 BugReport *report = 00137 new BugReport(*BT_open, 00138 "Call to 'open' requires a third argument when " 00139 "the 'O_CREAT' flag is set", N); 00140 report->addRange(oflagsEx->getSourceRange()); 00141 C.EmitReport(report); 00142 } 00143 } 00144 00145 //===----------------------------------------------------------------------===// 00146 // pthread_once 00147 //===----------------------------------------------------------------------===// 00148 00149 void UnixAPIChecker::CheckPthreadOnce(CheckerContext &C, 00150 const CallExpr *CE) const { 00151 00152 // This is similar to 'CheckDispatchOnce' in the MacOSXAPIChecker. 00153 // They can possibly be refactored. 00154 00155 if (CE->getNumArgs() < 1) 00156 return; 00157 00158 // Check if the first argument is stack allocated. If so, issue a warning 00159 // because that's likely to be bad news. 00160 ProgramStateRef state = C.getState(); 00161 const MemRegion *R = 00162 state->getSVal(CE->getArg(0), C.getLocationContext()).getAsRegion(); 00163 if (!R || !isa<StackSpaceRegion>(R->getMemorySpace())) 00164 return; 00165 00166 ExplodedNode *N = C.generateSink(state); 00167 if (!N) 00168 return; 00169 00170 SmallString<256> S; 00171 llvm::raw_svector_ostream os(S); 00172 os << "Call to 'pthread_once' uses"; 00173 if (const VarRegion *VR = dyn_cast<VarRegion>(R)) 00174 os << " the local variable '" << VR->getDecl()->getName() << '\''; 00175 else 00176 os << " stack allocated memory"; 00177 os << " for the \"control\" value. Using such transient memory for " 00178 "the control value is potentially dangerous."; 00179 if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace())) 00180 os << " Perhaps you intended to declare the variable as 'static'?"; 00181 00182 LazyInitialize(BT_pthreadOnce, "Improper use of 'pthread_once'"); 00183 00184 BugReport *report = new BugReport(*BT_pthreadOnce, os.str(), N); 00185 report->addRange(CE->getArg(0)->getSourceRange()); 00186 C.EmitReport(report); 00187 } 00188 00189 //===----------------------------------------------------------------------===// 00190 // "calloc", "malloc", "realloc", "alloca" and "valloc" with allocation size 0 00191 //===----------------------------------------------------------------------===// 00192 // FIXME: Eventually these should be rolled into the MallocChecker, but right now 00193 // they're more basic and valuable for widespread use. 00194 00195 // Returns true if we try to do a zero byte allocation, false otherwise. 00196 // Fills in trueState and falseState. 00197 static bool IsZeroByteAllocation(ProgramStateRef state, 00198 const SVal argVal, 00199 ProgramStateRef *trueState, 00200 ProgramStateRef *falseState) { 00201 llvm::tie(*trueState, *falseState) = 00202 state->assume(cast<DefinedSVal>(argVal)); 00203 00204 return (*falseState && !*trueState); 00205 } 00206 00207 // Generates an error report, indicating that the function whose name is given 00208 // will perform a zero byte allocation. 00209 // Returns false if an error occured, true otherwise. 00210 bool UnixAPIChecker::ReportZeroByteAllocation(CheckerContext &C, 00211 ProgramStateRef falseState, 00212 const Expr *arg, 00213 const char *fn_name) const { 00214 ExplodedNode *N = C.generateSink(falseState); 00215 if (!N) 00216 return false; 00217 00218 LazyInitialize(BT_mallocZero, 00219 "Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)"); 00220 00221 SmallString<256> S; 00222 llvm::raw_svector_ostream os(S); 00223 os << "Call to '" << fn_name << "' has an allocation size of 0 bytes"; 00224 BugReport *report = new BugReport(*BT_mallocZero, os.str(), N); 00225 00226 report->addRange(arg->getSourceRange()); 00227 report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, arg, 00228 report)); 00229 C.EmitReport(report); 00230 00231 return true; 00232 } 00233 00234 // Does a basic check for 0-sized allocations suitable for most of the below 00235 // functions (modulo "calloc") 00236 void UnixAPIChecker::BasicAllocationCheck(CheckerContext &C, 00237 const CallExpr *CE, 00238 const unsigned numArgs, 00239 const unsigned sizeArg, 00240 const char *fn) const { 00241 // Sanity check for the correct number of arguments 00242 if (CE->getNumArgs() != numArgs) 00243 return; 00244 00245 // Check if the allocation size is 0. 00246 ProgramStateRef state = C.getState(); 00247 ProgramStateRef trueState = NULL, falseState = NULL; 00248 const Expr *arg = CE->getArg(sizeArg); 00249 SVal argVal = state->getSVal(arg, C.getLocationContext()); 00250 00251 if (argVal.isUnknownOrUndef()) 00252 return; 00253 00254 // Is the value perfectly constrained to zero? 00255 if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) { 00256 (void) ReportZeroByteAllocation(C, falseState, arg, fn); 00257 return; 00258 } 00259 // Assume the the value is non-zero going forward. 00260 assert(trueState); 00261 if (trueState != state) 00262 C.addTransition(trueState); 00263 } 00264 00265 void UnixAPIChecker::CheckCallocZero(CheckerContext &C, 00266 const CallExpr *CE) const { 00267 unsigned int nArgs = CE->getNumArgs(); 00268 if (nArgs != 2) 00269 return; 00270 00271 ProgramStateRef state = C.getState(); 00272 ProgramStateRef trueState = NULL, falseState = NULL; 00273 00274 unsigned int i; 00275 for (i = 0; i < nArgs; i++) { 00276 const Expr *arg = CE->getArg(i); 00277 SVal argVal = state->getSVal(arg, C.getLocationContext()); 00278 if (argVal.isUnknownOrUndef()) { 00279 if (i == 0) 00280 continue; 00281 else 00282 return; 00283 } 00284 00285 if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) { 00286 if (ReportZeroByteAllocation(C, falseState, arg, "calloc")) 00287 return; 00288 else if (i == 0) 00289 continue; 00290 else 00291 return; 00292 } 00293 } 00294 00295 // Assume the the value is non-zero going forward. 00296 assert(trueState); 00297 if (trueState != state) 00298 C.addTransition(trueState); 00299 } 00300 00301 void UnixAPIChecker::CheckMallocZero(CheckerContext &C, 00302 const CallExpr *CE) const { 00303 BasicAllocationCheck(C, CE, 1, 0, "malloc"); 00304 } 00305 00306 void UnixAPIChecker::CheckReallocZero(CheckerContext &C, 00307 const CallExpr *CE) const { 00308 BasicAllocationCheck(C, CE, 2, 1, "realloc"); 00309 } 00310 00311 void UnixAPIChecker::CheckAllocaZero(CheckerContext &C, 00312 const CallExpr *CE) const { 00313 BasicAllocationCheck(C, CE, 1, 0, "alloca"); 00314 } 00315 00316 void UnixAPIChecker::CheckVallocZero(CheckerContext &C, 00317 const CallExpr *CE) const { 00318 BasicAllocationCheck(C, CE, 1, 0, "valloc"); 00319 } 00320 00321 00322 //===----------------------------------------------------------------------===// 00323 // Central dispatch function. 00324 //===----------------------------------------------------------------------===// 00325 00326 void UnixAPIChecker::checkPreStmt(const CallExpr *CE, 00327 CheckerContext &C) const { 00328 StringRef FName = C.getCalleeName(CE); 00329 if (FName.empty()) 00330 return; 00331 00332 SubChecker SC = 00333 llvm::StringSwitch<SubChecker>(FName) 00334 .Case("open", &UnixAPIChecker::CheckOpen) 00335 .Case("pthread_once", &UnixAPIChecker::CheckPthreadOnce) 00336 .Case("calloc", &UnixAPIChecker::CheckCallocZero) 00337 .Case("malloc", &UnixAPIChecker::CheckMallocZero) 00338 .Case("realloc", &UnixAPIChecker::CheckReallocZero) 00339 .Cases("alloca", "__builtin_alloca", &UnixAPIChecker::CheckAllocaZero) 00340 .Case("valloc", &UnixAPIChecker::CheckVallocZero) 00341 .Default(NULL); 00342 00343 if (SC) 00344 (this->*SC)(C, CE); 00345 } 00346 00347 //===----------------------------------------------------------------------===// 00348 // Registration. 00349 //===----------------------------------------------------------------------===// 00350 00351 void ento::registerUnixAPIChecker(CheckerManager &mgr) { 00352 mgr.registerChecker<UnixAPIChecker>(); 00353 }