1 //= UnixAPIChecker.h - Checks preconditions for various Unix APIs --*- C++ -*-// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This defines UnixAPIChecker, which is an assortment of checks on calls 10 // to various, widely used UNIX/Posix functions. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "clang/Basic/TargetInfo.h" 15 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 16 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 17 #include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h" 18 #include "clang/StaticAnalyzer/Core/Checker.h" 19 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 20 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 21 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 22 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h" 23 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h" 24 #include "llvm/ADT/STLExtras.h" 25 #include "llvm/ADT/SmallString.h" 26 #include "llvm/ADT/StringExtras.h" 27 #include "llvm/Support/raw_ostream.h" 28 #include <optional> 29 30 using namespace clang; 31 using namespace ento; 32 33 enum class OpenVariant { 34 /// The standard open() call: 35 /// int open(const char *path, int oflag, ...); 36 Open, 37 38 /// The variant taking a directory file descriptor and a relative path: 39 /// int openat(int fd, const char *path, int oflag, ...); 40 OpenAt 41 }; 42 43 namespace { 44 45 class UnixAPIMisuseChecker 46 : public Checker<check::PreCall, check::ASTDecl<TranslationUnitDecl>> { 47 const BugType BT_open{this, "Improper use of 'open'", categories::UnixAPI}; 48 const BugType BT_getline{this, "Improper use of getdelim", 49 categories::UnixAPI}; 50 const BugType BT_pthreadOnce{this, "Improper use of 'pthread_once'", 51 categories::UnixAPI}; 52 const BugType BT_ArgumentNull{this, "NULL pointer", categories::UnixAPI}; 53 mutable std::optional<uint64_t> Val_O_CREAT; 54 55 ProgramStateRef 56 EnsurePtrNotNull(SVal PtrVal, const Expr *PtrExpr, CheckerContext &C, 57 ProgramStateRef State, const StringRef PtrDescr, 58 std::optional<std::reference_wrapper<const BugType>> BT = 59 std::nullopt) const; 60 61 ProgramStateRef EnsureGetdelimBufferAndSizeCorrect( 62 SVal LinePtrPtrSVal, SVal SizePtrSVal, const Expr *LinePtrPtrExpr, 63 const Expr *SizePtrExpr, CheckerContext &C, ProgramStateRef State) const; 64 65 public: 66 void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager &Mgr, 67 BugReporter &BR) const; 68 69 void checkPreCall(const CallEvent &Call, CheckerContext &C) const; 70 71 void CheckOpen(CheckerContext &C, const CallEvent &Call) const; 72 void CheckOpenAt(CheckerContext &C, const CallEvent &Call) const; 73 void CheckGetDelim(CheckerContext &C, const CallEvent &Call) const; 74 void CheckPthreadOnce(CheckerContext &C, const CallEvent &Call) const; 75 76 void CheckOpenVariant(CheckerContext &C, const CallEvent &Call, 77 OpenVariant Variant) const; 78 79 void ReportOpenBug(CheckerContext &C, ProgramStateRef State, const char *Msg, 80 SourceRange SR) const; 81 }; 82 83 class UnixAPIPortabilityChecker : public Checker< check::PreStmt<CallExpr> > { 84 public: 85 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; 86 87 private: 88 const BugType BT_mallocZero{ 89 this, "Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)", 90 categories::UnixAPI}; 91 92 void CheckCallocZero(CheckerContext &C, const CallExpr *CE) const; 93 void CheckMallocZero(CheckerContext &C, const CallExpr *CE) const; 94 void CheckReallocZero(CheckerContext &C, const CallExpr *CE) const; 95 void CheckReallocfZero(CheckerContext &C, const CallExpr *CE) const; 96 void CheckAllocaZero(CheckerContext &C, const CallExpr *CE) const; 97 void CheckAllocaWithAlignZero(CheckerContext &C, const CallExpr *CE) const; 98 void CheckVallocZero(CheckerContext &C, const CallExpr *CE) const; 99 100 bool ReportZeroByteAllocation(CheckerContext &C, 101 ProgramStateRef falseState, 102 const Expr *arg, 103 const char *fn_name) const; 104 void BasicAllocationCheck(CheckerContext &C, 105 const CallExpr *CE, 106 const unsigned numArgs, 107 const unsigned sizeArg, 108 const char *fn) const; 109 }; 110 111 } // end anonymous namespace 112 113 ProgramStateRef UnixAPIMisuseChecker::EnsurePtrNotNull( 114 SVal PtrVal, const Expr *PtrExpr, CheckerContext &C, ProgramStateRef State, 115 const StringRef PtrDescr, 116 std::optional<std::reference_wrapper<const BugType>> BT) const { 117 const auto Ptr = PtrVal.getAs<DefinedSVal>(); 118 if (!Ptr) 119 return State; 120 121 const auto [PtrNotNull, PtrNull] = State->assume(*Ptr); 122 if (!PtrNotNull && PtrNull) { 123 if (ExplodedNode *N = C.generateErrorNode(PtrNull)) { 124 auto R = std::make_unique<PathSensitiveBugReport>( 125 BT.value_or(std::cref(BT_ArgumentNull)), 126 (PtrDescr + " pointer might be NULL.").str(), N); 127 if (PtrExpr) 128 bugreporter::trackExpressionValue(N, PtrExpr, *R); 129 C.emitReport(std::move(R)); 130 } 131 return nullptr; 132 } 133 134 return PtrNotNull; 135 } 136 137 void UnixAPIMisuseChecker::checkASTDecl(const TranslationUnitDecl *TU, 138 AnalysisManager &Mgr, 139 BugReporter &) const { 140 // The definition of O_CREAT is platform specific. 141 // Try to get the macro value from the preprocessor. 142 Val_O_CREAT = tryExpandAsInteger("O_CREAT", Mgr.getPreprocessor()); 143 // If we failed, fall-back to known values. 144 if (!Val_O_CREAT) { 145 if (TU->getASTContext().getTargetInfo().getTriple().getVendor() == 146 llvm::Triple::Apple) 147 Val_O_CREAT = 0x0200; 148 } 149 } 150 151 //===----------------------------------------------------------------------===// 152 // "open" (man 2 open) 153 //===----------------------------------------------------------------------===/ 154 155 void UnixAPIMisuseChecker::checkPreCall(const CallEvent &Call, 156 CheckerContext &C) const { 157 const FunctionDecl *FD = dyn_cast_if_present<FunctionDecl>(Call.getDecl()); 158 if (!FD || FD->getKind() != Decl::Function) 159 return; 160 161 // Don't treat functions in namespaces with the same name a Unix function 162 // as a call to the Unix function. 163 const DeclContext *NamespaceCtx = FD->getEnclosingNamespaceContext(); 164 if (isa_and_nonnull<NamespaceDecl>(NamespaceCtx)) 165 return; 166 167 StringRef FName = C.getCalleeName(FD); 168 if (FName.empty()) 169 return; 170 171 if (FName == "open") 172 CheckOpen(C, Call); 173 174 else if (FName == "openat") 175 CheckOpenAt(C, Call); 176 177 else if (FName == "pthread_once") 178 CheckPthreadOnce(C, Call); 179 180 else if (is_contained({"getdelim", "getline"}, FName)) 181 CheckGetDelim(C, Call); 182 } 183 void UnixAPIMisuseChecker::ReportOpenBug(CheckerContext &C, 184 ProgramStateRef State, 185 const char *Msg, 186 SourceRange SR) const { 187 ExplodedNode *N = C.generateErrorNode(State); 188 if (!N) 189 return; 190 191 auto Report = std::make_unique<PathSensitiveBugReport>(BT_open, Msg, N); 192 Report->addRange(SR); 193 C.emitReport(std::move(Report)); 194 } 195 196 void UnixAPIMisuseChecker::CheckOpen(CheckerContext &C, 197 const CallEvent &Call) const { 198 CheckOpenVariant(C, Call, OpenVariant::Open); 199 } 200 201 void UnixAPIMisuseChecker::CheckOpenAt(CheckerContext &C, 202 const CallEvent &Call) const { 203 CheckOpenVariant(C, Call, OpenVariant::OpenAt); 204 } 205 206 void UnixAPIMisuseChecker::CheckOpenVariant(CheckerContext &C, 207 const CallEvent &Call, 208 OpenVariant Variant) const { 209 // The index of the argument taking the flags open flags (O_RDONLY, 210 // O_WRONLY, O_CREAT, etc.), 211 unsigned int FlagsArgIndex; 212 const char *VariantName; 213 switch (Variant) { 214 case OpenVariant::Open: 215 FlagsArgIndex = 1; 216 VariantName = "open"; 217 break; 218 case OpenVariant::OpenAt: 219 FlagsArgIndex = 2; 220 VariantName = "openat"; 221 break; 222 }; 223 224 // All calls should at least provide arguments up to the 'flags' parameter. 225 unsigned int MinArgCount = FlagsArgIndex + 1; 226 227 // If the flags has O_CREAT set then open/openat() require an additional 228 // argument specifying the file mode (permission bits) for the created file. 229 unsigned int CreateModeArgIndex = FlagsArgIndex + 1; 230 231 // The create mode argument should be the last argument. 232 unsigned int MaxArgCount = CreateModeArgIndex + 1; 233 234 ProgramStateRef state = C.getState(); 235 236 if (Call.getNumArgs() < MinArgCount) { 237 // The frontend should issue a warning for this case. Just return. 238 return; 239 } else if (Call.getNumArgs() == MaxArgCount) { 240 const Expr *Arg = Call.getArgExpr(CreateModeArgIndex); 241 QualType QT = Arg->getType(); 242 if (!QT->isIntegerType()) { 243 SmallString<256> SBuf; 244 llvm::raw_svector_ostream OS(SBuf); 245 OS << "The " << CreateModeArgIndex + 1 246 << llvm::getOrdinalSuffix(CreateModeArgIndex + 1) 247 << " argument to '" << VariantName << "' is not an integer"; 248 249 ReportOpenBug(C, state, 250 SBuf.c_str(), 251 Arg->getSourceRange()); 252 return; 253 } 254 } else if (Call.getNumArgs() > MaxArgCount) { 255 SmallString<256> SBuf; 256 llvm::raw_svector_ostream OS(SBuf); 257 OS << "Call to '" << VariantName << "' with more than " << MaxArgCount 258 << " arguments"; 259 260 ReportOpenBug(C, state, SBuf.c_str(), 261 Call.getArgExpr(MaxArgCount)->getSourceRange()); 262 return; 263 } 264 265 if (!Val_O_CREAT) { 266 return; 267 } 268 269 // Now check if oflags has O_CREAT set. 270 const Expr *oflagsEx = Call.getArgExpr(FlagsArgIndex); 271 const SVal V = Call.getArgSVal(FlagsArgIndex); 272 if (!isa<NonLoc>(V)) { 273 // The case where 'V' can be a location can only be due to a bad header, 274 // so in this case bail out. 275 return; 276 } 277 NonLoc oflags = V.castAs<NonLoc>(); 278 NonLoc ocreateFlag = C.getSValBuilder() 279 .makeIntVal(*Val_O_CREAT, oflagsEx->getType()) 280 .castAs<NonLoc>(); 281 SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And, 282 oflags, ocreateFlag, 283 oflagsEx->getType()); 284 if (maskedFlagsUC.isUnknownOrUndef()) 285 return; 286 DefinedSVal maskedFlags = maskedFlagsUC.castAs<DefinedSVal>(); 287 288 // Check if maskedFlags is non-zero. 289 ProgramStateRef trueState, falseState; 290 std::tie(trueState, falseState) = state->assume(maskedFlags); 291 292 // Only emit an error if the value of 'maskedFlags' is properly 293 // constrained; 294 if (!(trueState && !falseState)) 295 return; 296 297 if (Call.getNumArgs() < MaxArgCount) { 298 SmallString<256> SBuf; 299 llvm::raw_svector_ostream OS(SBuf); 300 OS << "Call to '" << VariantName << "' requires a " 301 << CreateModeArgIndex + 1 302 << llvm::getOrdinalSuffix(CreateModeArgIndex + 1) 303 << " argument when the 'O_CREAT' flag is set"; 304 ReportOpenBug(C, trueState, 305 SBuf.c_str(), 306 oflagsEx->getSourceRange()); 307 } 308 } 309 310 //===----------------------------------------------------------------------===// 311 // getdelim and getline 312 //===----------------------------------------------------------------------===// 313 314 ProgramStateRef UnixAPIMisuseChecker::EnsureGetdelimBufferAndSizeCorrect( 315 SVal LinePtrPtrSVal, SVal SizePtrSVal, const Expr *LinePtrPtrExpr, 316 const Expr *SizePtrExpr, CheckerContext &C, ProgramStateRef State) const { 317 static constexpr llvm::StringLiteral SizeGreaterThanBufferSize = 318 "The buffer from the first argument is smaller than the size " 319 "specified by the second parameter"; 320 static constexpr llvm::StringLiteral SizeUndef = 321 "The buffer from the first argument is not NULL, but the size specified " 322 "by the second parameter is undefined."; 323 324 auto EmitBugReport = [this, &C, SizePtrExpr, LinePtrPtrExpr]( 325 ProgramStateRef BugState, StringRef ErrMsg) { 326 if (ExplodedNode *N = C.generateErrorNode(BugState)) { 327 auto R = std::make_unique<PathSensitiveBugReport>(BT_getline, ErrMsg, N); 328 bugreporter::trackExpressionValue(N, SizePtrExpr, *R); 329 bugreporter::trackExpressionValue(N, LinePtrPtrExpr, *R); 330 C.emitReport(std::move(R)); 331 } 332 }; 333 334 // We have a pointer to a pointer to the buffer, and a pointer to the size. 335 // We want what they point at. 336 auto LinePtrSVal = getPointeeVal(LinePtrPtrSVal, State)->getAs<DefinedSVal>(); 337 auto NSVal = getPointeeVal(SizePtrSVal, State); 338 if (!LinePtrSVal || !NSVal || NSVal->isUnknown()) 339 return nullptr; 340 341 assert(LinePtrPtrExpr && SizePtrExpr); 342 343 const auto [LinePtrNotNull, LinePtrNull] = State->assume(*LinePtrSVal); 344 if (LinePtrNotNull && !LinePtrNull) { 345 // If `*lineptr` is not null, but `*n` is undefined, there is UB. 346 if (NSVal->isUndef()) { 347 EmitBugReport(LinePtrNotNull, SizeUndef); 348 return nullptr; 349 } 350 351 // If it is defined, and known, its size must be less than or equal to 352 // the buffer size. 353 auto NDefSVal = NSVal->getAs<DefinedSVal>(); 354 auto &SVB = C.getSValBuilder(); 355 auto LineBufSize = 356 getDynamicExtent(LinePtrNotNull, LinePtrSVal->getAsRegion(), SVB); 357 auto LineBufSizeGtN = SVB.evalBinOp(LinePtrNotNull, BO_GE, LineBufSize, 358 *NDefSVal, SVB.getConditionType()) 359 .getAs<DefinedOrUnknownSVal>(); 360 if (!LineBufSizeGtN) 361 return LinePtrNotNull; 362 if (auto LineBufSizeOk = LinePtrNotNull->assume(*LineBufSizeGtN, true)) 363 return LineBufSizeOk; 364 365 EmitBugReport(LinePtrNotNull, SizeGreaterThanBufferSize); 366 return nullptr; 367 } 368 return State; 369 } 370 371 void UnixAPIMisuseChecker::CheckGetDelim(CheckerContext &C, 372 const CallEvent &Call) const { 373 ProgramStateRef State = C.getState(); 374 375 // The parameter `n` must not be NULL. 376 SVal SizePtrSval = Call.getArgSVal(1); 377 State = EnsurePtrNotNull(SizePtrSval, Call.getArgExpr(1), C, State, "Size"); 378 if (!State) 379 return; 380 381 // The parameter `lineptr` must not be NULL. 382 SVal LinePtrPtrSVal = Call.getArgSVal(0); 383 State = 384 EnsurePtrNotNull(LinePtrPtrSVal, Call.getArgExpr(0), C, State, "Line"); 385 if (!State) 386 return; 387 388 State = EnsureGetdelimBufferAndSizeCorrect(LinePtrPtrSVal, SizePtrSval, 389 Call.getArgExpr(0), 390 Call.getArgExpr(1), C, State); 391 if (!State) 392 return; 393 394 C.addTransition(State); 395 } 396 397 //===----------------------------------------------------------------------===// 398 // pthread_once 399 //===----------------------------------------------------------------------===// 400 401 void UnixAPIMisuseChecker::CheckPthreadOnce(CheckerContext &C, 402 const CallEvent &Call) const { 403 404 // This is similar to 'CheckDispatchOnce' in the MacOSXAPIChecker. 405 // They can possibly be refactored. 406 407 if (Call.getNumArgs() < 1) 408 return; 409 410 // Check if the first argument is stack allocated. If so, issue a warning 411 // because that's likely to be bad news. 412 ProgramStateRef state = C.getState(); 413 const MemRegion *R = Call.getArgSVal(0).getAsRegion(); 414 if (!R || !isa<StackSpaceRegion>(R->getMemorySpace())) 415 return; 416 417 ExplodedNode *N = C.generateErrorNode(state); 418 if (!N) 419 return; 420 421 SmallString<256> S; 422 llvm::raw_svector_ostream os(S); 423 os << "Call to 'pthread_once' uses"; 424 if (const VarRegion *VR = dyn_cast<VarRegion>(R)) 425 os << " the local variable '" << VR->getDecl()->getName() << '\''; 426 else 427 os << " stack allocated memory"; 428 os << " for the \"control\" value. Using such transient memory for " 429 "the control value is potentially dangerous."; 430 if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace())) 431 os << " Perhaps you intended to declare the variable as 'static'?"; 432 433 auto report = 434 std::make_unique<PathSensitiveBugReport>(BT_pthreadOnce, os.str(), N); 435 report->addRange(Call.getArgExpr(0)->getSourceRange()); 436 C.emitReport(std::move(report)); 437 } 438 439 //===----------------------------------------------------------------------===// 440 // "calloc", "malloc", "realloc", "reallocf", "alloca" and "valloc" 441 // with allocation size 0 442 //===----------------------------------------------------------------------===// 443 444 // FIXME: Eventually these should be rolled into the MallocChecker, but right now 445 // they're more basic and valuable for widespread use. 446 447 // Returns true if we try to do a zero byte allocation, false otherwise. 448 // Fills in trueState and falseState. 449 static bool IsZeroByteAllocation(ProgramStateRef state, 450 const SVal argVal, 451 ProgramStateRef *trueState, 452 ProgramStateRef *falseState) { 453 std::tie(*trueState, *falseState) = 454 state->assume(argVal.castAs<DefinedSVal>()); 455 456 return (*falseState && !*trueState); 457 } 458 459 // Generates an error report, indicating that the function whose name is given 460 // will perform a zero byte allocation. 461 // Returns false if an error occurred, true otherwise. 462 bool UnixAPIPortabilityChecker::ReportZeroByteAllocation( 463 CheckerContext &C, 464 ProgramStateRef falseState, 465 const Expr *arg, 466 const char *fn_name) const { 467 ExplodedNode *N = C.generateErrorNode(falseState); 468 if (!N) 469 return false; 470 471 SmallString<256> S; 472 llvm::raw_svector_ostream os(S); 473 os << "Call to '" << fn_name << "' has an allocation size of 0 bytes"; 474 auto report = 475 std::make_unique<PathSensitiveBugReport>(BT_mallocZero, os.str(), N); 476 477 report->addRange(arg->getSourceRange()); 478 bugreporter::trackExpressionValue(N, arg, *report); 479 C.emitReport(std::move(report)); 480 481 return true; 482 } 483 484 // Does a basic check for 0-sized allocations suitable for most of the below 485 // functions (modulo "calloc") 486 void UnixAPIPortabilityChecker::BasicAllocationCheck(CheckerContext &C, 487 const CallExpr *CE, 488 const unsigned numArgs, 489 const unsigned sizeArg, 490 const char *fn) const { 491 // Check for the correct number of arguments. 492 if (CE->getNumArgs() != numArgs) 493 return; 494 495 // Check if the allocation size is 0. 496 ProgramStateRef state = C.getState(); 497 ProgramStateRef trueState = nullptr, falseState = nullptr; 498 const Expr *arg = CE->getArg(sizeArg); 499 SVal argVal = C.getSVal(arg); 500 501 if (argVal.isUnknownOrUndef()) 502 return; 503 504 // Is the value perfectly constrained to zero? 505 if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) { 506 (void) ReportZeroByteAllocation(C, falseState, arg, fn); 507 return; 508 } 509 // Assume the value is non-zero going forward. 510 assert(trueState); 511 if (trueState != state) 512 C.addTransition(trueState); 513 } 514 515 void UnixAPIPortabilityChecker::CheckCallocZero(CheckerContext &C, 516 const CallExpr *CE) const { 517 unsigned int nArgs = CE->getNumArgs(); 518 if (nArgs != 2) 519 return; 520 521 ProgramStateRef state = C.getState(); 522 ProgramStateRef trueState = nullptr, falseState = nullptr; 523 524 unsigned int i; 525 for (i = 0; i < nArgs; i++) { 526 const Expr *arg = CE->getArg(i); 527 SVal argVal = C.getSVal(arg); 528 if (argVal.isUnknownOrUndef()) { 529 if (i == 0) 530 continue; 531 else 532 return; 533 } 534 535 if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) { 536 if (ReportZeroByteAllocation(C, falseState, arg, "calloc")) 537 return; 538 else if (i == 0) 539 continue; 540 else 541 return; 542 } 543 } 544 545 // Assume the value is non-zero going forward. 546 assert(trueState); 547 if (trueState != state) 548 C.addTransition(trueState); 549 } 550 551 void UnixAPIPortabilityChecker::CheckMallocZero(CheckerContext &C, 552 const CallExpr *CE) const { 553 BasicAllocationCheck(C, CE, 1, 0, "malloc"); 554 } 555 556 void UnixAPIPortabilityChecker::CheckReallocZero(CheckerContext &C, 557 const CallExpr *CE) const { 558 BasicAllocationCheck(C, CE, 2, 1, "realloc"); 559 } 560 561 void UnixAPIPortabilityChecker::CheckReallocfZero(CheckerContext &C, 562 const CallExpr *CE) const { 563 BasicAllocationCheck(C, CE, 2, 1, "reallocf"); 564 } 565 566 void UnixAPIPortabilityChecker::CheckAllocaZero(CheckerContext &C, 567 const CallExpr *CE) const { 568 BasicAllocationCheck(C, CE, 1, 0, "alloca"); 569 } 570 571 void UnixAPIPortabilityChecker::CheckAllocaWithAlignZero( 572 CheckerContext &C, 573 const CallExpr *CE) const { 574 BasicAllocationCheck(C, CE, 2, 0, "__builtin_alloca_with_align"); 575 } 576 577 void UnixAPIPortabilityChecker::CheckVallocZero(CheckerContext &C, 578 const CallExpr *CE) const { 579 BasicAllocationCheck(C, CE, 1, 0, "valloc"); 580 } 581 582 void UnixAPIPortabilityChecker::checkPreStmt(const CallExpr *CE, 583 CheckerContext &C) const { 584 const FunctionDecl *FD = C.getCalleeDecl(CE); 585 if (!FD || FD->getKind() != Decl::Function) 586 return; 587 588 // Don't treat functions in namespaces with the same name a Unix function 589 // as a call to the Unix function. 590 const DeclContext *NamespaceCtx = FD->getEnclosingNamespaceContext(); 591 if (isa_and_nonnull<NamespaceDecl>(NamespaceCtx)) 592 return; 593 594 StringRef FName = C.getCalleeName(FD); 595 if (FName.empty()) 596 return; 597 598 if (FName == "calloc") 599 CheckCallocZero(C, CE); 600 601 else if (FName == "malloc") 602 CheckMallocZero(C, CE); 603 604 else if (FName == "realloc") 605 CheckReallocZero(C, CE); 606 607 else if (FName == "reallocf") 608 CheckReallocfZero(C, CE); 609 610 else if (FName == "alloca" || FName == "__builtin_alloca") 611 CheckAllocaZero(C, CE); 612 613 else if (FName == "__builtin_alloca_with_align") 614 CheckAllocaWithAlignZero(C, CE); 615 616 else if (FName == "valloc") 617 CheckVallocZero(C, CE); 618 } 619 620 //===----------------------------------------------------------------------===// 621 // Registration. 622 //===----------------------------------------------------------------------===// 623 624 #define REGISTER_CHECKER(CHECKERNAME) \ 625 void ento::register##CHECKERNAME(CheckerManager &mgr) { \ 626 mgr.registerChecker<CHECKERNAME>(); \ 627 } \ 628 \ 629 bool ento::shouldRegister##CHECKERNAME(const CheckerManager &mgr) { \ 630 return true; \ 631 } 632 633 REGISTER_CHECKER(UnixAPIMisuseChecker) 634 REGISTER_CHECKER(UnixAPIPortabilityChecker) 635