brintos

brintos / llvm-project-archived public Read only

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