1 1.1 joerg //= UnixAPIChecker.h - Checks preconditions for various Unix APIs --*- C++ -*-// 2 1.1 joerg // 3 1.1 joerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 1.1 joerg // See https://llvm.org/LICENSE.txt for license information. 5 1.1 joerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 1.1 joerg // 7 1.1 joerg //===----------------------------------------------------------------------===// 8 1.1 joerg // 9 1.1 joerg // This defines UnixAPIChecker, which is an assortment of checks on calls 10 1.1 joerg // to various, widely used UNIX/Posix functions. 11 1.1 joerg // 12 1.1 joerg //===----------------------------------------------------------------------===// 13 1.1 joerg 14 1.1 joerg #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 15 1.1 joerg #include "clang/Basic/TargetInfo.h" 16 1.1 joerg #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 17 1.1 joerg #include "clang/StaticAnalyzer/Core/Checker.h" 18 1.1 joerg #include "clang/StaticAnalyzer/Core/CheckerManager.h" 19 1.1 joerg #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 20 1.1 joerg #include "llvm/ADT/Optional.h" 21 1.1 joerg #include "llvm/ADT/STLExtras.h" 22 1.1 joerg #include "llvm/ADT/SmallString.h" 23 1.1.1.2 joerg #include "llvm/ADT/StringExtras.h" 24 1.1 joerg #include "llvm/Support/raw_ostream.h" 25 1.1 joerg 26 1.1 joerg using namespace clang; 27 1.1 joerg using namespace ento; 28 1.1 joerg 29 1.1 joerg enum class OpenVariant { 30 1.1 joerg /// The standard open() call: 31 1.1 joerg /// int open(const char *path, int oflag, ...); 32 1.1 joerg Open, 33 1.1 joerg 34 1.1 joerg /// The variant taking a directory file descriptor and a relative path: 35 1.1 joerg /// int openat(int fd, const char *path, int oflag, ...); 36 1.1 joerg OpenAt 37 1.1 joerg }; 38 1.1 joerg 39 1.1 joerg namespace { 40 1.1 joerg 41 1.1 joerg class UnixAPIMisuseChecker : public Checker< check::PreStmt<CallExpr> > { 42 1.1 joerg mutable std::unique_ptr<BugType> BT_open, BT_pthreadOnce; 43 1.1 joerg mutable Optional<uint64_t> Val_O_CREAT; 44 1.1 joerg 45 1.1 joerg public: 46 1.1 joerg DefaultBool CheckMisuse, CheckPortability; 47 1.1 joerg 48 1.1 joerg void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; 49 1.1 joerg 50 1.1 joerg void CheckOpen(CheckerContext &C, const CallExpr *CE) const; 51 1.1 joerg void CheckOpenAt(CheckerContext &C, const CallExpr *CE) const; 52 1.1 joerg void CheckPthreadOnce(CheckerContext &C, const CallExpr *CE) const; 53 1.1 joerg 54 1.1 joerg void CheckOpenVariant(CheckerContext &C, 55 1.1 joerg const CallExpr *CE, OpenVariant Variant) const; 56 1.1 joerg 57 1.1 joerg void ReportOpenBug(CheckerContext &C, 58 1.1 joerg ProgramStateRef State, 59 1.1 joerg const char *Msg, 60 1.1 joerg SourceRange SR) const; 61 1.1 joerg 62 1.1 joerg }; 63 1.1 joerg 64 1.1 joerg class UnixAPIPortabilityChecker : public Checker< check::PreStmt<CallExpr> > { 65 1.1 joerg public: 66 1.1 joerg void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; 67 1.1 joerg 68 1.1 joerg private: 69 1.1 joerg mutable std::unique_ptr<BugType> BT_mallocZero; 70 1.1 joerg 71 1.1 joerg void CheckCallocZero(CheckerContext &C, const CallExpr *CE) const; 72 1.1 joerg void CheckMallocZero(CheckerContext &C, const CallExpr *CE) const; 73 1.1 joerg void CheckReallocZero(CheckerContext &C, const CallExpr *CE) const; 74 1.1 joerg void CheckReallocfZero(CheckerContext &C, const CallExpr *CE) const; 75 1.1 joerg void CheckAllocaZero(CheckerContext &C, const CallExpr *CE) const; 76 1.1 joerg void CheckAllocaWithAlignZero(CheckerContext &C, const CallExpr *CE) const; 77 1.1 joerg void CheckVallocZero(CheckerContext &C, const CallExpr *CE) const; 78 1.1 joerg 79 1.1 joerg bool ReportZeroByteAllocation(CheckerContext &C, 80 1.1 joerg ProgramStateRef falseState, 81 1.1 joerg const Expr *arg, 82 1.1 joerg const char *fn_name) const; 83 1.1 joerg void BasicAllocationCheck(CheckerContext &C, 84 1.1 joerg const CallExpr *CE, 85 1.1 joerg const unsigned numArgs, 86 1.1 joerg const unsigned sizeArg, 87 1.1 joerg const char *fn) const; 88 1.1 joerg }; 89 1.1 joerg 90 1.1 joerg } //end anonymous namespace 91 1.1 joerg 92 1.1 joerg static void LazyInitialize(const CheckerBase *Checker, 93 1.1 joerg std::unique_ptr<BugType> &BT, 94 1.1 joerg const char *name) { 95 1.1 joerg if (BT) 96 1.1 joerg return; 97 1.1 joerg BT.reset(new BugType(Checker, name, categories::UnixAPI)); 98 1.1 joerg } 99 1.1 joerg 100 1.1 joerg //===----------------------------------------------------------------------===// 101 1.1 joerg // "open" (man 2 open) 102 1.1 joerg //===----------------------------------------------------------------------===/ 103 1.1 joerg 104 1.1 joerg void UnixAPIMisuseChecker::checkPreStmt(const CallExpr *CE, 105 1.1 joerg CheckerContext &C) const { 106 1.1 joerg const FunctionDecl *FD = C.getCalleeDecl(CE); 107 1.1 joerg if (!FD || FD->getKind() != Decl::Function) 108 1.1 joerg return; 109 1.1 joerg 110 1.1 joerg // Don't treat functions in namespaces with the same name a Unix function 111 1.1 joerg // as a call to the Unix function. 112 1.1 joerg const DeclContext *NamespaceCtx = FD->getEnclosingNamespaceContext(); 113 1.1 joerg if (NamespaceCtx && isa<NamespaceDecl>(NamespaceCtx)) 114 1.1 joerg return; 115 1.1 joerg 116 1.1 joerg StringRef FName = C.getCalleeName(FD); 117 1.1 joerg if (FName.empty()) 118 1.1 joerg return; 119 1.1 joerg 120 1.1 joerg if (FName == "open") 121 1.1 joerg CheckOpen(C, CE); 122 1.1 joerg 123 1.1 joerg else if (FName == "openat") 124 1.1 joerg CheckOpenAt(C, CE); 125 1.1 joerg 126 1.1 joerg else if (FName == "pthread_once") 127 1.1 joerg CheckPthreadOnce(C, CE); 128 1.1 joerg } 129 1.1 joerg void UnixAPIMisuseChecker::ReportOpenBug(CheckerContext &C, 130 1.1 joerg ProgramStateRef State, 131 1.1 joerg const char *Msg, 132 1.1 joerg SourceRange SR) const { 133 1.1 joerg ExplodedNode *N = C.generateErrorNode(State); 134 1.1 joerg if (!N) 135 1.1 joerg return; 136 1.1 joerg 137 1.1 joerg LazyInitialize(this, BT_open, "Improper use of 'open'"); 138 1.1 joerg 139 1.1 joerg auto Report = std::make_unique<PathSensitiveBugReport>(*BT_open, Msg, N); 140 1.1 joerg Report->addRange(SR); 141 1.1 joerg C.emitReport(std::move(Report)); 142 1.1 joerg } 143 1.1 joerg 144 1.1 joerg void UnixAPIMisuseChecker::CheckOpen(CheckerContext &C, 145 1.1 joerg const CallExpr *CE) const { 146 1.1 joerg CheckOpenVariant(C, CE, OpenVariant::Open); 147 1.1 joerg } 148 1.1 joerg 149 1.1 joerg void UnixAPIMisuseChecker::CheckOpenAt(CheckerContext &C, 150 1.1 joerg const CallExpr *CE) const { 151 1.1 joerg CheckOpenVariant(C, CE, OpenVariant::OpenAt); 152 1.1 joerg } 153 1.1 joerg 154 1.1 joerg void UnixAPIMisuseChecker::CheckOpenVariant(CheckerContext &C, 155 1.1 joerg const CallExpr *CE, 156 1.1 joerg OpenVariant Variant) const { 157 1.1 joerg // The index of the argument taking the flags open flags (O_RDONLY, 158 1.1 joerg // O_WRONLY, O_CREAT, etc.), 159 1.1 joerg unsigned int FlagsArgIndex; 160 1.1 joerg const char *VariantName; 161 1.1 joerg switch (Variant) { 162 1.1 joerg case OpenVariant::Open: 163 1.1 joerg FlagsArgIndex = 1; 164 1.1 joerg VariantName = "open"; 165 1.1 joerg break; 166 1.1 joerg case OpenVariant::OpenAt: 167 1.1 joerg FlagsArgIndex = 2; 168 1.1 joerg VariantName = "openat"; 169 1.1 joerg break; 170 1.1 joerg }; 171 1.1 joerg 172 1.1 joerg // All calls should at least provide arguments up to the 'flags' parameter. 173 1.1 joerg unsigned int MinArgCount = FlagsArgIndex + 1; 174 1.1 joerg 175 1.1 joerg // If the flags has O_CREAT set then open/openat() require an additional 176 1.1 joerg // argument specifying the file mode (permission bits) for the created file. 177 1.1 joerg unsigned int CreateModeArgIndex = FlagsArgIndex + 1; 178 1.1 joerg 179 1.1 joerg // The create mode argument should be the last argument. 180 1.1 joerg unsigned int MaxArgCount = CreateModeArgIndex + 1; 181 1.1 joerg 182 1.1 joerg ProgramStateRef state = C.getState(); 183 1.1 joerg 184 1.1 joerg if (CE->getNumArgs() < MinArgCount) { 185 1.1 joerg // The frontend should issue a warning for this case, so this is a sanity 186 1.1 joerg // check. 187 1.1 joerg return; 188 1.1 joerg } else if (CE->getNumArgs() == MaxArgCount) { 189 1.1 joerg const Expr *Arg = CE->getArg(CreateModeArgIndex); 190 1.1 joerg QualType QT = Arg->getType(); 191 1.1 joerg if (!QT->isIntegerType()) { 192 1.1 joerg SmallString<256> SBuf; 193 1.1 joerg llvm::raw_svector_ostream OS(SBuf); 194 1.1 joerg OS << "The " << CreateModeArgIndex + 1 195 1.1 joerg << llvm::getOrdinalSuffix(CreateModeArgIndex + 1) 196 1.1 joerg << " argument to '" << VariantName << "' is not an integer"; 197 1.1 joerg 198 1.1 joerg ReportOpenBug(C, state, 199 1.1 joerg SBuf.c_str(), 200 1.1 joerg Arg->getSourceRange()); 201 1.1 joerg return; 202 1.1 joerg } 203 1.1 joerg } else if (CE->getNumArgs() > MaxArgCount) { 204 1.1 joerg SmallString<256> SBuf; 205 1.1 joerg llvm::raw_svector_ostream OS(SBuf); 206 1.1 joerg OS << "Call to '" << VariantName << "' with more than " << MaxArgCount 207 1.1 joerg << " arguments"; 208 1.1 joerg 209 1.1 joerg ReportOpenBug(C, state, 210 1.1 joerg SBuf.c_str(), 211 1.1 joerg CE->getArg(MaxArgCount)->getSourceRange()); 212 1.1 joerg return; 213 1.1 joerg } 214 1.1 joerg 215 1.1 joerg // The definition of O_CREAT is platform specific. We need a better way 216 1.1 joerg // of querying this information from the checking environment. 217 1.1 joerg if (!Val_O_CREAT.hasValue()) { 218 1.1 joerg if (C.getASTContext().getTargetInfo().getTriple().getVendor() 219 1.1 joerg == llvm::Triple::Apple) 220 1.1 joerg Val_O_CREAT = 0x0200; 221 1.1 joerg else { 222 1.1 joerg // FIXME: We need a more general way of getting the O_CREAT value. 223 1.1 joerg // We could possibly grovel through the preprocessor state, but 224 1.1 joerg // that would require passing the Preprocessor object to the ExprEngine. 225 1.1 joerg // See also: MallocChecker.cpp / M_ZERO. 226 1.1 joerg return; 227 1.1 joerg } 228 1.1 joerg } 229 1.1 joerg 230 1.1 joerg // Now check if oflags has O_CREAT set. 231 1.1 joerg const Expr *oflagsEx = CE->getArg(FlagsArgIndex); 232 1.1 joerg const SVal V = C.getSVal(oflagsEx); 233 1.1 joerg if (!V.getAs<NonLoc>()) { 234 1.1 joerg // The case where 'V' can be a location can only be due to a bad header, 235 1.1 joerg // so in this case bail out. 236 1.1 joerg return; 237 1.1 joerg } 238 1.1 joerg NonLoc oflags = V.castAs<NonLoc>(); 239 1.1 joerg NonLoc ocreateFlag = C.getSValBuilder() 240 1.1 joerg .makeIntVal(Val_O_CREAT.getValue(), oflagsEx->getType()).castAs<NonLoc>(); 241 1.1 joerg SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And, 242 1.1 joerg oflags, ocreateFlag, 243 1.1 joerg oflagsEx->getType()); 244 1.1 joerg if (maskedFlagsUC.isUnknownOrUndef()) 245 1.1 joerg return; 246 1.1 joerg DefinedSVal maskedFlags = maskedFlagsUC.castAs<DefinedSVal>(); 247 1.1 joerg 248 1.1 joerg // Check if maskedFlags is non-zero. 249 1.1 joerg ProgramStateRef trueState, falseState; 250 1.1 joerg std::tie(trueState, falseState) = state->assume(maskedFlags); 251 1.1 joerg 252 1.1 joerg // Only emit an error if the value of 'maskedFlags' is properly 253 1.1 joerg // constrained; 254 1.1 joerg if (!(trueState && !falseState)) 255 1.1 joerg return; 256 1.1 joerg 257 1.1 joerg if (CE->getNumArgs() < MaxArgCount) { 258 1.1 joerg SmallString<256> SBuf; 259 1.1 joerg llvm::raw_svector_ostream OS(SBuf); 260 1.1 joerg OS << "Call to '" << VariantName << "' requires a " 261 1.1 joerg << CreateModeArgIndex + 1 262 1.1 joerg << llvm::getOrdinalSuffix(CreateModeArgIndex + 1) 263 1.1 joerg << " argument when the 'O_CREAT' flag is set"; 264 1.1 joerg ReportOpenBug(C, trueState, 265 1.1 joerg SBuf.c_str(), 266 1.1 joerg oflagsEx->getSourceRange()); 267 1.1 joerg } 268 1.1 joerg } 269 1.1 joerg 270 1.1 joerg //===----------------------------------------------------------------------===// 271 1.1 joerg // pthread_once 272 1.1 joerg //===----------------------------------------------------------------------===// 273 1.1 joerg 274 1.1 joerg void UnixAPIMisuseChecker::CheckPthreadOnce(CheckerContext &C, 275 1.1 joerg const CallExpr *CE) const { 276 1.1 joerg 277 1.1 joerg // This is similar to 'CheckDispatchOnce' in the MacOSXAPIChecker. 278 1.1 joerg // They can possibly be refactored. 279 1.1 joerg 280 1.1 joerg if (CE->getNumArgs() < 1) 281 1.1 joerg return; 282 1.1 joerg 283 1.1 joerg // Check if the first argument is stack allocated. If so, issue a warning 284 1.1 joerg // because that's likely to be bad news. 285 1.1 joerg ProgramStateRef state = C.getState(); 286 1.1 joerg const MemRegion *R = C.getSVal(CE->getArg(0)).getAsRegion(); 287 1.1 joerg if (!R || !isa<StackSpaceRegion>(R->getMemorySpace())) 288 1.1 joerg return; 289 1.1 joerg 290 1.1 joerg ExplodedNode *N = C.generateErrorNode(state); 291 1.1 joerg if (!N) 292 1.1 joerg return; 293 1.1 joerg 294 1.1 joerg SmallString<256> S; 295 1.1 joerg llvm::raw_svector_ostream os(S); 296 1.1 joerg os << "Call to 'pthread_once' uses"; 297 1.1 joerg if (const VarRegion *VR = dyn_cast<VarRegion>(R)) 298 1.1 joerg os << " the local variable '" << VR->getDecl()->getName() << '\''; 299 1.1 joerg else 300 1.1 joerg os << " stack allocated memory"; 301 1.1 joerg os << " for the \"control\" value. Using such transient memory for " 302 1.1 joerg "the control value is potentially dangerous."; 303 1.1 joerg if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace())) 304 1.1 joerg os << " Perhaps you intended to declare the variable as 'static'?"; 305 1.1 joerg 306 1.1 joerg LazyInitialize(this, BT_pthreadOnce, "Improper use of 'pthread_once'"); 307 1.1 joerg 308 1.1 joerg auto report = 309 1.1 joerg std::make_unique<PathSensitiveBugReport>(*BT_pthreadOnce, os.str(), N); 310 1.1 joerg report->addRange(CE->getArg(0)->getSourceRange()); 311 1.1 joerg C.emitReport(std::move(report)); 312 1.1 joerg } 313 1.1 joerg 314 1.1 joerg //===----------------------------------------------------------------------===// 315 1.1 joerg // "calloc", "malloc", "realloc", "reallocf", "alloca" and "valloc" 316 1.1 joerg // with allocation size 0 317 1.1 joerg //===----------------------------------------------------------------------===// 318 1.1 joerg 319 1.1 joerg // FIXME: Eventually these should be rolled into the MallocChecker, but right now 320 1.1 joerg // they're more basic and valuable for widespread use. 321 1.1 joerg 322 1.1 joerg // Returns true if we try to do a zero byte allocation, false otherwise. 323 1.1 joerg // Fills in trueState and falseState. 324 1.1 joerg static bool IsZeroByteAllocation(ProgramStateRef state, 325 1.1 joerg const SVal argVal, 326 1.1 joerg ProgramStateRef *trueState, 327 1.1 joerg ProgramStateRef *falseState) { 328 1.1 joerg std::tie(*trueState, *falseState) = 329 1.1 joerg state->assume(argVal.castAs<DefinedSVal>()); 330 1.1 joerg 331 1.1 joerg return (*falseState && !*trueState); 332 1.1 joerg } 333 1.1 joerg 334 1.1 joerg // Generates an error report, indicating that the function whose name is given 335 1.1 joerg // will perform a zero byte allocation. 336 1.1 joerg // Returns false if an error occurred, true otherwise. 337 1.1 joerg bool UnixAPIPortabilityChecker::ReportZeroByteAllocation( 338 1.1 joerg CheckerContext &C, 339 1.1 joerg ProgramStateRef falseState, 340 1.1 joerg const Expr *arg, 341 1.1 joerg const char *fn_name) const { 342 1.1 joerg ExplodedNode *N = C.generateErrorNode(falseState); 343 1.1 joerg if (!N) 344 1.1 joerg return false; 345 1.1 joerg 346 1.1 joerg LazyInitialize(this, BT_mallocZero, 347 1.1 joerg "Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)"); 348 1.1 joerg 349 1.1 joerg SmallString<256> S; 350 1.1 joerg llvm::raw_svector_ostream os(S); 351 1.1 joerg os << "Call to '" << fn_name << "' has an allocation size of 0 bytes"; 352 1.1 joerg auto report = 353 1.1 joerg std::make_unique<PathSensitiveBugReport>(*BT_mallocZero, os.str(), N); 354 1.1 joerg 355 1.1 joerg report->addRange(arg->getSourceRange()); 356 1.1 joerg bugreporter::trackExpressionValue(N, arg, *report); 357 1.1 joerg C.emitReport(std::move(report)); 358 1.1 joerg 359 1.1 joerg return true; 360 1.1 joerg } 361 1.1 joerg 362 1.1 joerg // Does a basic check for 0-sized allocations suitable for most of the below 363 1.1 joerg // functions (modulo "calloc") 364 1.1 joerg void UnixAPIPortabilityChecker::BasicAllocationCheck(CheckerContext &C, 365 1.1 joerg const CallExpr *CE, 366 1.1 joerg const unsigned numArgs, 367 1.1 joerg const unsigned sizeArg, 368 1.1 joerg const char *fn) const { 369 1.1 joerg // Sanity check for the correct number of arguments 370 1.1 joerg if (CE->getNumArgs() != numArgs) 371 1.1 joerg return; 372 1.1 joerg 373 1.1 joerg // Check if the allocation size is 0. 374 1.1 joerg ProgramStateRef state = C.getState(); 375 1.1 joerg ProgramStateRef trueState = nullptr, falseState = nullptr; 376 1.1 joerg const Expr *arg = CE->getArg(sizeArg); 377 1.1 joerg SVal argVal = C.getSVal(arg); 378 1.1 joerg 379 1.1 joerg if (argVal.isUnknownOrUndef()) 380 1.1 joerg return; 381 1.1 joerg 382 1.1 joerg // Is the value perfectly constrained to zero? 383 1.1 joerg if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) { 384 1.1 joerg (void) ReportZeroByteAllocation(C, falseState, arg, fn); 385 1.1 joerg return; 386 1.1 joerg } 387 1.1 joerg // Assume the value is non-zero going forward. 388 1.1 joerg assert(trueState); 389 1.1 joerg if (trueState != state) 390 1.1 joerg C.addTransition(trueState); 391 1.1 joerg } 392 1.1 joerg 393 1.1 joerg void UnixAPIPortabilityChecker::CheckCallocZero(CheckerContext &C, 394 1.1 joerg const CallExpr *CE) const { 395 1.1 joerg unsigned int nArgs = CE->getNumArgs(); 396 1.1 joerg if (nArgs != 2) 397 1.1 joerg return; 398 1.1 joerg 399 1.1 joerg ProgramStateRef state = C.getState(); 400 1.1 joerg ProgramStateRef trueState = nullptr, falseState = nullptr; 401 1.1 joerg 402 1.1 joerg unsigned int i; 403 1.1 joerg for (i = 0; i < nArgs; i++) { 404 1.1 joerg const Expr *arg = CE->getArg(i); 405 1.1 joerg SVal argVal = C.getSVal(arg); 406 1.1 joerg if (argVal.isUnknownOrUndef()) { 407 1.1 joerg if (i == 0) 408 1.1 joerg continue; 409 1.1 joerg else 410 1.1 joerg return; 411 1.1 joerg } 412 1.1 joerg 413 1.1 joerg if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) { 414 1.1 joerg if (ReportZeroByteAllocation(C, falseState, arg, "calloc")) 415 1.1 joerg return; 416 1.1 joerg else if (i == 0) 417 1.1 joerg continue; 418 1.1 joerg else 419 1.1 joerg return; 420 1.1 joerg } 421 1.1 joerg } 422 1.1 joerg 423 1.1 joerg // Assume the value is non-zero going forward. 424 1.1 joerg assert(trueState); 425 1.1 joerg if (trueState != state) 426 1.1 joerg C.addTransition(trueState); 427 1.1 joerg } 428 1.1 joerg 429 1.1 joerg void UnixAPIPortabilityChecker::CheckMallocZero(CheckerContext &C, 430 1.1 joerg const CallExpr *CE) const { 431 1.1 joerg BasicAllocationCheck(C, CE, 1, 0, "malloc"); 432 1.1 joerg } 433 1.1 joerg 434 1.1 joerg void UnixAPIPortabilityChecker::CheckReallocZero(CheckerContext &C, 435 1.1 joerg const CallExpr *CE) const { 436 1.1 joerg BasicAllocationCheck(C, CE, 2, 1, "realloc"); 437 1.1 joerg } 438 1.1 joerg 439 1.1 joerg void UnixAPIPortabilityChecker::CheckReallocfZero(CheckerContext &C, 440 1.1 joerg const CallExpr *CE) const { 441 1.1 joerg BasicAllocationCheck(C, CE, 2, 1, "reallocf"); 442 1.1 joerg } 443 1.1 joerg 444 1.1 joerg void UnixAPIPortabilityChecker::CheckAllocaZero(CheckerContext &C, 445 1.1 joerg const CallExpr *CE) const { 446 1.1 joerg BasicAllocationCheck(C, CE, 1, 0, "alloca"); 447 1.1 joerg } 448 1.1 joerg 449 1.1 joerg void UnixAPIPortabilityChecker::CheckAllocaWithAlignZero( 450 1.1 joerg CheckerContext &C, 451 1.1 joerg const CallExpr *CE) const { 452 1.1 joerg BasicAllocationCheck(C, CE, 2, 0, "__builtin_alloca_with_align"); 453 1.1 joerg } 454 1.1 joerg 455 1.1 joerg void UnixAPIPortabilityChecker::CheckVallocZero(CheckerContext &C, 456 1.1 joerg const CallExpr *CE) const { 457 1.1 joerg BasicAllocationCheck(C, CE, 1, 0, "valloc"); 458 1.1 joerg } 459 1.1 joerg 460 1.1 joerg void UnixAPIPortabilityChecker::checkPreStmt(const CallExpr *CE, 461 1.1 joerg CheckerContext &C) const { 462 1.1 joerg const FunctionDecl *FD = C.getCalleeDecl(CE); 463 1.1 joerg if (!FD || FD->getKind() != Decl::Function) 464 1.1 joerg return; 465 1.1 joerg 466 1.1 joerg // Don't treat functions in namespaces with the same name a Unix function 467 1.1 joerg // as a call to the Unix function. 468 1.1 joerg const DeclContext *NamespaceCtx = FD->getEnclosingNamespaceContext(); 469 1.1 joerg if (NamespaceCtx && isa<NamespaceDecl>(NamespaceCtx)) 470 1.1 joerg return; 471 1.1 joerg 472 1.1 joerg StringRef FName = C.getCalleeName(FD); 473 1.1 joerg if (FName.empty()) 474 1.1 joerg return; 475 1.1 joerg 476 1.1 joerg if (FName == "calloc") 477 1.1 joerg CheckCallocZero(C, CE); 478 1.1 joerg 479 1.1 joerg else if (FName == "malloc") 480 1.1 joerg CheckMallocZero(C, CE); 481 1.1 joerg 482 1.1 joerg else if (FName == "realloc") 483 1.1 joerg CheckReallocZero(C, CE); 484 1.1 joerg 485 1.1 joerg else if (FName == "reallocf") 486 1.1 joerg CheckReallocfZero(C, CE); 487 1.1 joerg 488 1.1 joerg else if (FName == "alloca" || FName == "__builtin_alloca") 489 1.1 joerg CheckAllocaZero(C, CE); 490 1.1 joerg 491 1.1 joerg else if (FName == "__builtin_alloca_with_align") 492 1.1 joerg CheckAllocaWithAlignZero(C, CE); 493 1.1 joerg 494 1.1 joerg else if (FName == "valloc") 495 1.1 joerg CheckVallocZero(C, CE); 496 1.1 joerg } 497 1.1 joerg 498 1.1 joerg //===----------------------------------------------------------------------===// 499 1.1 joerg // Registration. 500 1.1 joerg //===----------------------------------------------------------------------===// 501 1.1 joerg 502 1.1 joerg #define REGISTER_CHECKER(CHECKERNAME) \ 503 1.1 joerg void ento::register##CHECKERNAME(CheckerManager &mgr) { \ 504 1.1 joerg mgr.registerChecker<CHECKERNAME>(); \ 505 1.1 joerg } \ 506 1.1 joerg \ 507 1.1.1.2 joerg bool ento::shouldRegister##CHECKERNAME(const CheckerManager &mgr) { \ 508 1.1 joerg return true; \ 509 1.1 joerg } 510 1.1 joerg 511 1.1 joerg REGISTER_CHECKER(UnixAPIMisuseChecker) 512 1.1 joerg REGISTER_CHECKER(UnixAPIPortabilityChecker) 513