brintos

brintos / llvm-project-archived public Read only

0
0
Text · 23.9 KiB · e71fe47 Raw
697 lines · cpp
1//===--- CallAndMessageChecker.cpp ------------------------------*- 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 CallAndMessageChecker, a builtin checker that checks for various10// errors of call and objc message expressions.11//12//===----------------------------------------------------------------------===//13 14#include "clang/AST/ExprCXX.h"15#include "clang/AST/ParentMap.h"16#include "clang/Basic/TargetInfo.h"17#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"18#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"19#include "clang/StaticAnalyzer/Core/Checker.h"20#include "clang/StaticAnalyzer/Core/CheckerManager.h"21#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"22#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"23#include "llvm/ADT/StringExtras.h"24#include "llvm/Support/raw_ostream.h"25 26using namespace clang;27using namespace ento;28 29namespace {30 31class CallAndMessageChecker32    : public Checker<check::PreObjCMessage, check::ObjCMessageNil,33                     check::PreCall> {34  const BugType CallNullBug{35      this, "Called function pointer is null (null dereference)"};36  const BugType CallUndefBug{37      this, "Called function pointer is an uninitialized pointer value"};38  const BugType CXXCallNullBug{this, "Called C++ object pointer is null"};39  const BugType CXXCallUndefBug{this,40                                "Called C++ object pointer is uninitialized"};41  const BugType CallArgBug{this, "Uninitialized argument value"};42  const BugType CXXDeleteUndefBug{this, "Uninitialized argument value"};43  const BugType MsgUndefBug{44      this, "Receiver in message expression is an uninitialized value"};45  const BugType ObjCPropUndefBug{46      this, "Property access on an uninitialized object pointer"};47  const BugType ObjCSubscriptUndefBug{48      this, "Subscript access on an uninitialized object pointer"};49  const BugType MsgArgBug{this, "Uninitialized argument value"};50  const BugType MsgRetBug{this, "Receiver in message expression is 'nil'"};51  const BugType CallFewArgsBug{this, "Function call with too few arguments"};52 53public:54  // Like a checker family, CallAndMessageChecker can produce many kinds of55  // warnings which can be separately enabled or disabled. However, for56  // historical reasons these warning kinds are represented by checker options57  // (and not separate checker frontends with their own names) because58  // CallAndMessage is among the oldest checkers out there, and can59  // be responsible for the majority of the reports on any given project. This60  // is obviously not ideal, but changing checker name has the consequence of61  // changing the issue hashes associated with the reports, and databases62  // relying on this (CodeChecker, for instance) would suffer greatly.63  // If we ever end up making changes to the issue hash generation algorithm, or64  // the warning messages here, we should totally jump on the opportunity to65  // convert these to actual checker frontends.66  enum CheckKind {67    CK_FunctionPointer,68    CK_ParameterCount,69    CK_CXXThisMethodCall,70    CK_CXXDeallocationArg,71    CK_ArgInitializedness,72    CK_ArgPointeeInitializedness,73    CK_NilReceiver,74    CK_UndefReceiver,75    CK_NumCheckKinds76  };77 78  bool ChecksEnabled[CK_NumCheckKinds] = {false};79 80  void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;81 82  /// Fill in the return value that results from messaging nil based on the83  /// return type and architecture and diagnose if the return value will be84  /// garbage.85  void checkObjCMessageNil(const ObjCMethodCall &msg, CheckerContext &C) const;86 87  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;88 89  ProgramStateRef checkFunctionPointerCall(const CallExpr *CE,90                                           CheckerContext &C,91                                           ProgramStateRef State) const;92 93  ProgramStateRef checkCXXMethodCall(const CXXInstanceCall *CC,94                                     CheckerContext &C,95                                     ProgramStateRef State) const;96 97  ProgramStateRef checkParameterCount(const CallEvent &Call, CheckerContext &C,98                                      ProgramStateRef State) const;99 100  ProgramStateRef checkCXXDeallocation(const CXXDeallocatorCall *DC,101                                       CheckerContext &C,102                                       ProgramStateRef State) const;103 104  ProgramStateRef checkArgInitializedness(const CallEvent &Call,105                                          CheckerContext &C,106                                          ProgramStateRef State) const;107 108private:109  bool PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange ArgRange,110                          const Expr *ArgEx, int ArgumentNumber,111                          bool CheckUninitFields, const CallEvent &Call,112                          const BugType &BT,113                          const ParmVarDecl *ParamDecl) const;114 115  static void emitBadCall(const BugType &BT, CheckerContext &C,116                          const Expr *BadE);117  void emitNilReceiverBug(CheckerContext &C, const ObjCMethodCall &msg,118                          ExplodedNode *N) const;119 120  void HandleNilReceiver(CheckerContext &C,121                         ProgramStateRef state,122                         const ObjCMethodCall &msg) const;123 124  bool uninitRefOrPointer(CheckerContext &C, SVal V, SourceRange ArgRange,125                          const Expr *ArgEx, const BugType &BT,126                          const ParmVarDecl *ParamDecl,127                          int ArgumentNumber) const;128};129} // end anonymous namespace130 131void CallAndMessageChecker::emitBadCall(const BugType &BT, CheckerContext &C,132                                        const Expr *BadE) {133  ExplodedNode *N = C.generateErrorNode();134  if (!N)135    return;136 137  auto R = std::make_unique<PathSensitiveBugReport>(BT, BT.getDescription(), N);138  if (BadE) {139    R->addRange(BadE->getSourceRange());140    if (BadE->isGLValue())141      BadE = bugreporter::getDerefExpr(BadE);142    bugreporter::trackExpressionValue(N, BadE, *R);143  }144  C.emitReport(std::move(R));145}146 147static void describeUninitializedArgumentInCall(const CallEvent &Call,148                                                int ArgumentNumber,149                                                llvm::raw_svector_ostream &Os) {150  switch (Call.getKind()) {151  case CE_ObjCMessage: {152    const ObjCMethodCall &Msg = cast<ObjCMethodCall>(Call);153    switch (Msg.getMessageKind()) {154    case OCM_Message:155      Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)156         << " argument in message expression is an uninitialized value";157      return;158    case OCM_PropertyAccess:159      assert(Msg.isSetter() && "Getters have no args");160      Os << "Argument for property setter is an uninitialized value";161      return;162    case OCM_Subscript:163      if (Msg.isSetter() && (ArgumentNumber == 0))164        Os << "Argument for subscript setter is an uninitialized value";165      else166        Os << "Subscript index is an uninitialized value";167      return;168    }169    llvm_unreachable("Unknown message kind.");170  }171  case CE_Block:172    Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)173       << " block call argument is an uninitialized value";174    return;175  default:176    Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)177       << " function call argument is an uninitialized value";178    return;179  }180}181 182bool CallAndMessageChecker::uninitRefOrPointer(183    CheckerContext &C, SVal V, SourceRange ArgRange, const Expr *ArgEx,184    const BugType &BT, const ParmVarDecl *ParamDecl, int ArgumentNumber) const {185 186  // The pointee being uninitialized is a sign of code smell, not a bug, no need187  // to sink here.188  if (!ChecksEnabled[CK_ArgPointeeInitializedness])189    return false;190 191  // No parameter declaration available, i.e. variadic function argument.192  if(!ParamDecl)193    return false;194 195  // If parameter is declared as pointer to const in function declaration,196  // then check if corresponding argument in function call is197  // pointing to undefined symbol value (uninitialized memory).198  SmallString<200> Buf;199  llvm::raw_svector_ostream Os(Buf);200 201  if (ParamDecl->getType()->isPointerType()) {202    Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)203       << " function call argument is a pointer to uninitialized value";204  } else if (ParamDecl->getType()->isReferenceType()) {205    Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)206       << " function call argument is an uninitialized value";207  } else208    return false;209 210  if(!ParamDecl->getType()->getPointeeType().isConstQualified())211    return false;212 213  if (const MemRegion *SValMemRegion = V.getAsRegion()) {214    const ProgramStateRef State = C.getState();215    const SVal PSV = State->getSVal(SValMemRegion, C.getASTContext().CharTy);216    if (PSV.isUndef()) {217      if (ExplodedNode *N = C.generateErrorNode()) {218        auto R = std::make_unique<PathSensitiveBugReport>(BT, Os.str(), N);219        R->addRange(ArgRange);220        if (ArgEx)221          bugreporter::trackExpressionValue(N, ArgEx, *R);222 223        C.emitReport(std::move(R));224      }225      return true;226    }227  }228  return false;229}230 231namespace {232class FindUninitializedField {233public:234  SmallVector<const FieldDecl *, 10> FieldChain;235 236private:237  StoreManager &StoreMgr;238  MemRegionManager &MrMgr;239  Store store;240 241public:242  FindUninitializedField(StoreManager &storeMgr, MemRegionManager &mrMgr,243                         Store s)244      : StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}245 246  bool Find(const TypedValueRegion *R) {247    QualType T = R->getValueType();248    if (const RecordType *RT = T->getAsStructureType()) {249      const RecordDecl *RD = RT->getDecl()->getDefinition();250      assert(RD && "Referred record has no definition");251      for (const auto *I : RD->fields()) {252        if (I->isUnnamedBitField())253          continue;254        const FieldRegion *FR = MrMgr.getFieldRegion(I, R);255        FieldChain.push_back(I);256        T = I->getType();257        if (T->isStructureType()) {258          if (Find(FR))259            return true;260        } else {261          SVal V = StoreMgr.getBinding(store, loc::MemRegionVal(FR));262          if (V.isUndef())263            return true;264        }265        FieldChain.pop_back();266      }267    }268 269    return false;270  }271};272} // namespace273 274bool CallAndMessageChecker::PreVisitProcessArg(275    CheckerContext &C, SVal V, SourceRange ArgRange, const Expr *ArgEx,276    int ArgumentNumber, bool CheckUninitFields, const CallEvent &Call,277    const BugType &BT, const ParmVarDecl *ParamDecl) const {278  if (uninitRefOrPointer(C, V, ArgRange, ArgEx, BT, ParamDecl, ArgumentNumber))279    return true;280 281  if (V.isUndef()) {282    if (!ChecksEnabled[CK_ArgInitializedness]) {283      C.addSink();284      return true;285    }286    if (ExplodedNode *N = C.generateErrorNode()) {287      // Generate a report for this bug.288      SmallString<200> Buf;289      llvm::raw_svector_ostream Os(Buf);290      describeUninitializedArgumentInCall(Call, ArgumentNumber, Os);291      auto R = std::make_unique<PathSensitiveBugReport>(BT, Os.str(), N);292 293      R->addRange(ArgRange);294      if (ArgEx)295        bugreporter::trackExpressionValue(N, ArgEx, *R);296      C.emitReport(std::move(R));297    }298    return true;299  }300 301  if (!CheckUninitFields)302    return false;303 304  if (auto LV = V.getAs<nonloc::LazyCompoundVal>()) {305    const LazyCompoundValData *D = LV->getCVData();306    FindUninitializedField F(C.getState()->getStateManager().getStoreManager(),307                             C.getSValBuilder().getRegionManager(),308                             D->getStore());309 310    if (F.Find(D->getRegion())) {311      if (!ChecksEnabled[CK_ArgInitializedness]) {312        C.addSink();313        return true;314      }315      if (ExplodedNode *N = C.generateErrorNode()) {316        SmallString<512> Str;317        llvm::raw_svector_ostream os(Str);318        os << "Passed-by-value struct argument contains uninitialized data";319 320        if (F.FieldChain.size() == 1)321          os << " (e.g., field: '" << *F.FieldChain[0] << "')";322        else {323          os << " (e.g., via the field chain: '";324          bool first = true;325          for (const FieldDecl *FD : F.FieldChain) {326            if (first)327              first = false;328            else329              os << '.';330            os << *FD;331          }332          os << "')";333        }334 335        // Generate a report for this bug.336        auto R = std::make_unique<PathSensitiveBugReport>(BT, os.str(), N);337        R->addRange(ArgRange);338 339        if (ArgEx)340          bugreporter::trackExpressionValue(N, ArgEx, *R);341        // FIXME: enhance track back for uninitialized value for arbitrary342        // memregions343        C.emitReport(std::move(R));344      }345      return true;346    }347  }348 349  return false;350}351 352ProgramStateRef CallAndMessageChecker::checkFunctionPointerCall(353    const CallExpr *CE, CheckerContext &C, ProgramStateRef State) const {354 355  const Expr *Callee = CE->getCallee()->IgnoreParens();356  const LocationContext *LCtx = C.getLocationContext();357  SVal L = State->getSVal(Callee, LCtx);358 359  if (L.isUndef()) {360    if (!ChecksEnabled[CK_FunctionPointer]) {361      C.addSink(State);362      return nullptr;363    }364    emitBadCall(CallUndefBug, C, Callee);365    return nullptr;366  }367 368  ProgramStateRef StNonNull, StNull;369  std::tie(StNonNull, StNull) = State->assume(L.castAs<DefinedOrUnknownSVal>());370 371  if (StNull && !StNonNull) {372    if (!ChecksEnabled[CK_FunctionPointer]) {373      C.addSink(StNull);374      return nullptr;375    }376    emitBadCall(CallNullBug, C, Callee);377    return nullptr;378  }379 380  return StNonNull;381}382 383ProgramStateRef CallAndMessageChecker::checkParameterCount(384    const CallEvent &Call, CheckerContext &C, ProgramStateRef State) const {385 386  // If we have a function or block declaration, we can make sure we pass387  // enough parameters.388  unsigned Params = Call.parameters().size();389  if (Call.getNumArgs() >= Params)390    return State;391 392  if (!ChecksEnabled[CK_ParameterCount]) {393    C.addSink(State);394    return nullptr;395  }396 397  ExplodedNode *N = C.generateErrorNode();398  if (!N)399    return nullptr;400 401  SmallString<512> Str;402  llvm::raw_svector_ostream os(Str);403  if (isa<AnyFunctionCall>(Call)) {404    os << "Function ";405  } else {406    assert(isa<BlockCall>(Call));407    os << "Block ";408  }409  os << "taking " << Params << " argument" << (Params == 1 ? "" : "s")410     << " is called with fewer (" << Call.getNumArgs() << ")";411 412  C.emitReport(413      std::make_unique<PathSensitiveBugReport>(CallFewArgsBug, os.str(), N));414  return nullptr;415}416 417ProgramStateRef CallAndMessageChecker::checkCXXMethodCall(418    const CXXInstanceCall *CC, CheckerContext &C, ProgramStateRef State) const {419 420  SVal V = CC->getCXXThisVal();421  if (V.isUndef()) {422    if (!ChecksEnabled[CK_CXXThisMethodCall]) {423      C.addSink(State);424      return nullptr;425    }426    emitBadCall(CXXCallUndefBug, C, CC->getCXXThisExpr());427    return nullptr;428  }429 430  ProgramStateRef StNonNull, StNull;431  std::tie(StNonNull, StNull) = State->assume(V.castAs<DefinedOrUnknownSVal>());432 433  if (StNull && !StNonNull) {434    if (!ChecksEnabled[CK_CXXThisMethodCall]) {435      C.addSink(StNull);436      return nullptr;437    }438    emitBadCall(CXXCallNullBug, C, CC->getCXXThisExpr());439    return nullptr;440  }441 442  return StNonNull;443}444 445ProgramStateRef446CallAndMessageChecker::checkCXXDeallocation(const CXXDeallocatorCall *DC,447                                            CheckerContext &C,448                                            ProgramStateRef State) const {449  const CXXDeleteExpr *DE = DC->getOriginExpr();450  assert(DE);451  SVal Arg = C.getSVal(DE->getArgument());452  if (!Arg.isUndef())453    return State;454 455  if (!ChecksEnabled[CK_CXXDeallocationArg]) {456    C.addSink(State);457    return nullptr;458  }459 460  StringRef Desc;461  ExplodedNode *N = C.generateErrorNode();462  if (!N)463    return nullptr;464  if (DE->isArrayFormAsWritten())465    Desc = "Argument to 'delete[]' is uninitialized";466  else467    Desc = "Argument to 'delete' is uninitialized";468  auto R = std::make_unique<PathSensitiveBugReport>(CXXDeleteUndefBug, Desc, N);469  bugreporter::trackExpressionValue(N, DE, *R);470  C.emitReport(std::move(R));471  return nullptr;472}473 474ProgramStateRef CallAndMessageChecker::checkArgInitializedness(475    const CallEvent &Call, CheckerContext &C, ProgramStateRef State) const {476 477  const Decl *D = Call.getDecl();478 479  // Don't check for uninitialized field values in arguments if the480  // caller has a body that is available and we have the chance to inline it.481  // This is a hack, but is a reasonable compromise betweens sometimes warning482  // and sometimes not depending on if we decide to inline a function.483  const bool checkUninitFields =484      !(C.getAnalysisManager().shouldInlineCall() && (D && D->getBody()));485 486  const BugType &BT = isa<ObjCMethodCall>(Call) ? MsgArgBug : CallArgBug;487 488  const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);489  for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i) {490    const ParmVarDecl *ParamDecl = nullptr;491    if (FD && i < FD->getNumParams())492      ParamDecl = FD->getParamDecl(i);493    if (PreVisitProcessArg(C, Call.getArgSVal(i), Call.getArgSourceRange(i),494                           Call.getArgExpr(i), i, checkUninitFields, Call, BT,495                           ParamDecl))496      return nullptr;497  }498  return State;499}500 501void CallAndMessageChecker::checkPreCall(const CallEvent &Call,502                                         CheckerContext &C) const {503  ProgramStateRef State = C.getState();504 505  if (const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()))506    State = checkFunctionPointerCall(CE, C, State);507 508  if (!State)509    return;510 511  if (Call.getDecl())512    State = checkParameterCount(Call, C, State);513 514  if (!State)515    return;516 517  if (const auto *CC = dyn_cast<CXXInstanceCall>(&Call))518    State = checkCXXMethodCall(CC, C, State);519 520  if (!State)521    return;522 523  if (const auto *DC = dyn_cast<CXXDeallocatorCall>(&Call))524    State = checkCXXDeallocation(DC, C, State);525 526  if (!State)527    return;528 529  State = checkArgInitializedness(Call, C, State);530 531  // If we make it here, record our assumptions about the callee.532  C.addTransition(State);533}534 535void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg,536                                                CheckerContext &C) const {537  SVal recVal = msg.getReceiverSVal();538  if (recVal.isUndef()) {539    if (!ChecksEnabled[CK_UndefReceiver]) {540      C.addSink();541      return;542    }543    if (ExplodedNode *N = C.generateErrorNode()) {544      const BugType *BT = nullptr;545      switch (msg.getMessageKind()) {546      case OCM_Message:547        BT = &MsgUndefBug;548        break;549      case OCM_PropertyAccess:550        BT = &ObjCPropUndefBug;551        break;552      case OCM_Subscript:553        BT = &ObjCSubscriptUndefBug;554        break;555      }556      assert(BT && "Unknown message kind.");557 558      auto R = std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);559      const ObjCMessageExpr *ME = msg.getOriginExpr();560      R->addRange(ME->getReceiverRange());561 562      // FIXME: getTrackNullOrUndefValueVisitor can't handle "super" yet.563      if (const Expr *ReceiverE = ME->getInstanceReceiver())564        bugreporter::trackExpressionValue(N, ReceiverE, *R);565      C.emitReport(std::move(R));566    }567    return;568  }569}570 571void CallAndMessageChecker::checkObjCMessageNil(const ObjCMethodCall &msg,572                                                CheckerContext &C) const {573  HandleNilReceiver(C, C.getState(), msg);574}575 576void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,577                                               const ObjCMethodCall &msg,578                                               ExplodedNode *N) const {579  if (!ChecksEnabled[CK_NilReceiver]) {580    C.addSink();581    return;582  }583 584  const ObjCMessageExpr *ME = msg.getOriginExpr();585 586  QualType ResTy = msg.getResultType();587 588  SmallString<200> buf;589  llvm::raw_svector_ostream os(buf);590  os << "The receiver of message '";591  ME->getSelector().print(os);592  os << "' is nil";593  if (ResTy->isReferenceType()) {594    os << ", which results in forming a null reference";595  } else {596    os << " and returns a value of type '";597    msg.getResultType().print(os, C.getLangOpts());598    os << "' that will be garbage";599  }600 601  auto report =602      std::make_unique<PathSensitiveBugReport>(MsgRetBug, os.str(), N);603  report->addRange(ME->getReceiverRange());604  // FIXME: This won't track "self" in messages to super.605  if (const Expr *receiver = ME->getInstanceReceiver()) {606    bugreporter::trackExpressionValue(N, receiver, *report);607  }608  C.emitReport(std::move(report));609}610 611static bool supportsNilWithFloatRet(const llvm::Triple &triple) {612  return (triple.getVendor() == llvm::Triple::Apple &&613          (triple.isiOS() || triple.isWatchOS() ||614           !triple.isMacOSXVersionLT(10,5)));615}616 617void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,618                                              ProgramStateRef state,619                                              const ObjCMethodCall &Msg) const {620  ASTContext &Ctx = C.getASTContext();621 622  // Check the return type of the message expression.  A message to nil will623  // return different values depending on the return type and the architecture.624  QualType RetTy = Msg.getResultType();625  CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);626  const LocationContext *LCtx = C.getLocationContext();627 628  if (CanRetTy->isStructureOrClassType()) {629    // Structure returns are safe since the compiler zeroes them out.630    SVal V = C.getSValBuilder().makeZeroVal(RetTy);631    C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V));632    return;633  }634 635  // Other cases: check if sizeof(return type) > sizeof(void*)636  if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap()637                                  .isConsumedExpr(Msg.getOriginExpr())) {638    // Compute: sizeof(void *) and sizeof(return type)639    const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);640    const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);641 642    if (CanRetTy.getTypePtr()->isReferenceType()||643        (voidPtrSize < returnTypeSize &&644         !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) &&645           (Ctx.FloatTy == CanRetTy ||646            Ctx.DoubleTy == CanRetTy ||647            Ctx.LongDoubleTy == CanRetTy ||648            Ctx.LongLongTy == CanRetTy ||649            Ctx.UnsignedLongLongTy == CanRetTy)))) {650      if (ExplodedNode *N = C.generateErrorNode(state))651        emitNilReceiverBug(C, Msg, N);652      return;653    }654 655    // Handle the safe cases where the return value is 0 if the656    // receiver is nil.657    //658    // FIXME: For now take the conservative approach that we only659    // return null values if we *know* that the receiver is nil.660    // This is because we can have surprises like:661    //662    //   ... = [[NSScreens screens] objectAtIndex:0];663    //664    // What can happen is that [... screens] could return nil, but665    // it most likely isn't nil.  We should assume the semantics666    // of this case unless we have *a lot* more knowledge.667    //668    SVal V = C.getSValBuilder().makeZeroVal(RetTy);669    C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V));670    return;671  }672 673  C.addTransition(state);674}675 676void ento::registerCallAndMessageChecker(CheckerManager &Mgr) {677  CallAndMessageChecker *Chk = Mgr.registerChecker<CallAndMessageChecker>();678 679#define QUERY_CHECKER_OPTION(OPTION)                                           \680  Chk->ChecksEnabled[CallAndMessageChecker::CK_##OPTION] =                     \681      Mgr.getAnalyzerOptions().getCheckerBooleanOption(                        \682          Mgr.getCurrentCheckerName(), #OPTION);683 684  QUERY_CHECKER_OPTION(FunctionPointer)685  QUERY_CHECKER_OPTION(ParameterCount)686  QUERY_CHECKER_OPTION(CXXThisMethodCall)687  QUERY_CHECKER_OPTION(CXXDeallocationArg)688  QUERY_CHECKER_OPTION(ArgInitializedness)689  QUERY_CHECKER_OPTION(ArgPointeeInitializedness)690  QUERY_CHECKER_OPTION(NilReceiver)691  QUERY_CHECKER_OPTION(UndefReceiver)692}693 694bool ento::shouldRegisterCallAndMessageChecker(const CheckerManager &) {695  return true;696}697