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