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