Home | History | Annotate | Download | only in Checkers
      1 //===--- CallAndMessageChecker.cpp ------------------------------*- C++ -*--==//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This defines CallAndMessageChecker, a builtin checker that checks for various
     11 // errors of call and objc message expressions.
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     15 #include "ClangSACheckers.h"
     16 #include "clang/AST/ParentMap.h"
     17 #include "clang/Basic/TargetInfo.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/SmallString.h"
     24 #include "llvm/Support/raw_ostream.h"
     25 
     26 using namespace clang;
     27 using namespace ento;
     28 
     29 namespace {
     30 
     31 struct ChecksFilter {
     32   DefaultBool Check_CallAndMessageUnInitRefArg;
     33   DefaultBool Check_CallAndMessageChecker;
     34 
     35   CheckName CheckName_CallAndMessageUnInitRefArg;
     36   CheckName CheckName_CallAndMessageChecker;
     37 };
     38 
     39 class CallAndMessageChecker
     40   : public Checker< check::PreStmt<CallExpr>,
     41                     check::PreStmt<CXXDeleteExpr>,
     42                     check::PreObjCMessage,
     43                     check::PreCall > {
     44   mutable std::unique_ptr<BugType> BT_call_null;
     45   mutable std::unique_ptr<BugType> BT_call_undef;
     46   mutable std::unique_ptr<BugType> BT_cxx_call_null;
     47   mutable std::unique_ptr<BugType> BT_cxx_call_undef;
     48   mutable std::unique_ptr<BugType> BT_call_arg;
     49   mutable std::unique_ptr<BugType> BT_cxx_delete_undef;
     50   mutable std::unique_ptr<BugType> BT_msg_undef;
     51   mutable std::unique_ptr<BugType> BT_objc_prop_undef;
     52   mutable std::unique_ptr<BugType> BT_objc_subscript_undef;
     53   mutable std::unique_ptr<BugType> BT_msg_arg;
     54   mutable std::unique_ptr<BugType> BT_msg_ret;
     55   mutable std::unique_ptr<BugType> BT_call_few_args;
     56 
     57 public:
     58   ChecksFilter Filter;
     59 
     60   void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
     61   void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const;
     62   void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
     63   void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
     64 
     65 private:
     66   bool PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange ArgRange,
     67                           const Expr *ArgEx, bool IsFirstArgument,
     68                           bool CheckUninitFields, const CallEvent &Call,
     69                           std::unique_ptr<BugType> &BT,
     70                           const ParmVarDecl *ParamDecl) const;
     71 
     72   static void emitBadCall(BugType *BT, CheckerContext &C, const Expr *BadE);
     73   void emitNilReceiverBug(CheckerContext &C, const ObjCMethodCall &msg,
     74                           ExplodedNode *N) const;
     75 
     76   void HandleNilReceiver(CheckerContext &C,
     77                          ProgramStateRef state,
     78                          const ObjCMethodCall &msg) const;
     79 
     80   void LazyInit_BT(const char *desc, std::unique_ptr<BugType> &BT) const {
     81     if (!BT)
     82       BT.reset(new BuiltinBug(this, desc));
     83   }
     84   bool uninitRefOrPointer(CheckerContext &C, const SVal &V,
     85                           const SourceRange &ArgRange,
     86                           const Expr *ArgEx, std::unique_ptr<BugType> &BT,
     87                           const ParmVarDecl *ParamDecl, const char *BD) const;
     88 };
     89 } // end anonymous namespace
     90 
     91 void CallAndMessageChecker::emitBadCall(BugType *BT, CheckerContext &C,
     92                                         const Expr *BadE) {
     93   ExplodedNode *N = C.generateSink();
     94   if (!N)
     95     return;
     96 
     97   BugReport *R = new BugReport(*BT, BT->getName(), N);
     98   if (BadE) {
     99     R->addRange(BadE->getSourceRange());
    100     if (BadE->isGLValue())
    101       BadE = bugreporter::getDerefExpr(BadE);
    102     bugreporter::trackNullOrUndefValue(N, BadE, *R);
    103   }
    104   C.emitReport(R);
    105 }
    106 
    107 static StringRef describeUninitializedArgumentInCall(const CallEvent &Call,
    108                                                      bool IsFirstArgument) {
    109   switch (Call.getKind()) {
    110   case CE_ObjCMessage: {
    111     const ObjCMethodCall &Msg = cast<ObjCMethodCall>(Call);
    112     switch (Msg.getMessageKind()) {
    113     case OCM_Message:
    114       return "Argument in message expression is an uninitialized value";
    115     case OCM_PropertyAccess:
    116       assert(Msg.isSetter() && "Getters have no args");
    117       return "Argument for property setter is an uninitialized value";
    118     case OCM_Subscript:
    119       if (Msg.isSetter() && IsFirstArgument)
    120         return "Argument for subscript setter is an uninitialized value";
    121       return "Subscript index is an uninitialized value";
    122     }
    123     llvm_unreachable("Unknown message kind.");
    124   }
    125   case CE_Block:
    126     return "Block call argument is an uninitialized value";
    127   default:
    128     return "Function call argument is an uninitialized value";
    129   }
    130 }
    131 
    132 bool CallAndMessageChecker::uninitRefOrPointer(CheckerContext &C,
    133                                                const SVal &V,
    134                                                const SourceRange &ArgRange,
    135                                                const Expr *ArgEx,
    136                                                std::unique_ptr<BugType> &BT,
    137                                                const ParmVarDecl *ParamDecl,
    138                                                const char *BD) const {
    139   if (!Filter.Check_CallAndMessageUnInitRefArg)
    140     return false;
    141 
    142   // No parameter declaration available, i.e. variadic function argument.
    143   if(!ParamDecl)
    144     return false;
    145 
    146   // If parameter is declared as pointer to const in function declaration,
    147   // then check if corresponding argument in function call is
    148   // pointing to undefined symbol value (uninitialized memory).
    149   StringRef Message;
    150 
    151   if (ParamDecl->getType()->isPointerType()) {
    152     Message = "Function call argument is a pointer to uninitialized value";
    153   } else if (ParamDecl->getType()->isReferenceType()) {
    154     Message = "Function call argument is an uninitialized value";
    155   } else
    156     return false;
    157 
    158   if(!ParamDecl->getType()->getPointeeType().isConstQualified())
    159     return false;
    160 
    161   if (const MemRegion *SValMemRegion = V.getAsRegion()) {
    162     const ProgramStateRef State = C.getState();
    163     const SVal PSV = State->getSVal(SValMemRegion);
    164     if (PSV.isUndef()) {
    165       if (ExplodedNode *N = C.generateSink()) {
    166         LazyInit_BT(BD, BT);
    167         BugReport *R = new BugReport(*BT, Message, N);
    168         R->addRange(ArgRange);
    169         if (ArgEx) {
    170           bugreporter::trackNullOrUndefValue(N, ArgEx, *R);
    171         }
    172         C.emitReport(R);
    173       }
    174       return true;
    175     }
    176   }
    177   return false;
    178 }
    179 
    180 bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
    181                                                SVal V,
    182                                                SourceRange ArgRange,
    183                                                const Expr *ArgEx,
    184                                                bool IsFirstArgument,
    185                                                bool CheckUninitFields,
    186                                                const CallEvent &Call,
    187                                                std::unique_ptr<BugType> &BT,
    188                                                const ParmVarDecl *ParamDecl
    189                                                ) const {
    190   const char *BD = "Uninitialized argument value";
    191 
    192   if (uninitRefOrPointer(C, V, ArgRange, ArgEx, BT, ParamDecl, BD))
    193     return true;
    194 
    195   if (V.isUndef()) {
    196     if (ExplodedNode *N = C.generateSink()) {
    197       LazyInit_BT(BD, BT);
    198 
    199       // Generate a report for this bug.
    200       StringRef Desc =
    201           describeUninitializedArgumentInCall(Call, IsFirstArgument);
    202       BugReport *R = new BugReport(*BT, Desc, N);
    203       R->addRange(ArgRange);
    204       if (ArgEx)
    205         bugreporter::trackNullOrUndefValue(N, ArgEx, *R);
    206       C.emitReport(R);
    207     }
    208     return true;
    209   }
    210 
    211   if (!CheckUninitFields)
    212     return false;
    213 
    214   if (Optional<nonloc::LazyCompoundVal> LV =
    215           V.getAs<nonloc::LazyCompoundVal>()) {
    216 
    217     class FindUninitializedField {
    218     public:
    219       SmallVector<const FieldDecl *, 10> FieldChain;
    220     private:
    221       StoreManager &StoreMgr;
    222       MemRegionManager &MrMgr;
    223       Store store;
    224     public:
    225       FindUninitializedField(StoreManager &storeMgr,
    226                              MemRegionManager &mrMgr, Store s)
    227       : StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}
    228 
    229       bool Find(const TypedValueRegion *R) {
    230         QualType T = R->getValueType();
    231         if (const RecordType *RT = T->getAsStructureType()) {
    232           const RecordDecl *RD = RT->getDecl()->getDefinition();
    233           assert(RD && "Referred record has no definition");
    234           for (const auto *I : RD->fields()) {
    235             const FieldRegion *FR = MrMgr.getFieldRegion(I, R);
    236             FieldChain.push_back(I);
    237             T = I->getType();
    238             if (T->getAsStructureType()) {
    239               if (Find(FR))
    240                 return true;
    241             }
    242             else {
    243               const SVal &V = StoreMgr.getBinding(store, loc::MemRegionVal(FR));
    244               if (V.isUndef())
    245                 return true;
    246             }
    247             FieldChain.pop_back();
    248           }
    249         }
    250 
    251         return false;
    252       }
    253     };
    254 
    255     const LazyCompoundValData *D = LV->getCVData();
    256     FindUninitializedField F(C.getState()->getStateManager().getStoreManager(),
    257                              C.getSValBuilder().getRegionManager(),
    258                              D->getStore());
    259 
    260     if (F.Find(D->getRegion())) {
    261       if (ExplodedNode *N = C.generateSink()) {
    262         LazyInit_BT(BD, BT);
    263         SmallString<512> Str;
    264         llvm::raw_svector_ostream os(Str);
    265         os << "Passed-by-value struct argument contains uninitialized data";
    266 
    267         if (F.FieldChain.size() == 1)
    268           os << " (e.g., field: '" << *F.FieldChain[0] << "')";
    269         else {
    270           os << " (e.g., via the field chain: '";
    271           bool first = true;
    272           for (SmallVectorImpl<const FieldDecl *>::iterator
    273                DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
    274             if (first)
    275               first = false;
    276             else
    277               os << '.';
    278             os << **DI;
    279           }
    280           os << "')";
    281         }
    282 
    283         // Generate a report for this bug.
    284         BugReport *R = new BugReport(*BT, os.str(), N);
    285         R->addRange(ArgRange);
    286 
    287         // FIXME: enhance track back for uninitialized value for arbitrary
    288         // memregions
    289         C.emitReport(R);
    290       }
    291       return true;
    292     }
    293   }
    294 
    295   return false;
    296 }
    297 
    298 void CallAndMessageChecker::checkPreStmt(const CallExpr *CE,
    299                                          CheckerContext &C) const{
    300 
    301   const Expr *Callee = CE->getCallee()->IgnoreParens();
    302   ProgramStateRef State = C.getState();
    303   const LocationContext *LCtx = C.getLocationContext();
    304   SVal L = State->getSVal(Callee, LCtx);
    305 
    306   if (L.isUndef()) {
    307     if (!BT_call_undef)
    308       BT_call_undef.reset(new BuiltinBug(
    309           this, "Called function pointer is an uninitalized pointer value"));
    310     emitBadCall(BT_call_undef.get(), C, Callee);
    311     return;
    312   }
    313 
    314   ProgramStateRef StNonNull, StNull;
    315   std::tie(StNonNull, StNull) = State->assume(L.castAs<DefinedOrUnknownSVal>());
    316 
    317   if (StNull && !StNonNull) {
    318     if (!BT_call_null)
    319       BT_call_null.reset(new BuiltinBug(
    320           this, "Called function pointer is null (null dereference)"));
    321     emitBadCall(BT_call_null.get(), C, Callee);
    322     return;
    323   }
    324 
    325   C.addTransition(StNonNull);
    326 }
    327 
    328 void CallAndMessageChecker::checkPreStmt(const CXXDeleteExpr *DE,
    329                                          CheckerContext &C) const {
    330 
    331   SVal Arg = C.getSVal(DE->getArgument());
    332   if (Arg.isUndef()) {
    333     StringRef Desc;
    334     ExplodedNode *N = C.generateSink();
    335     if (!N)
    336       return;
    337     if (!BT_cxx_delete_undef)
    338       BT_cxx_delete_undef.reset(
    339           new BuiltinBug(this, "Uninitialized argument value"));
    340     if (DE->isArrayFormAsWritten())
    341       Desc = "Argument to 'delete[]' is uninitialized";
    342     else
    343       Desc = "Argument to 'delete' is uninitialized";
    344     BugType *BT = BT_cxx_delete_undef.get();
    345     BugReport *R = new BugReport(*BT, Desc, N);
    346     bugreporter::trackNullOrUndefValue(N, DE, *R);
    347     C.emitReport(R);
    348     return;
    349   }
    350 }
    351 
    352 
    353 void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
    354                                          CheckerContext &C) const {
    355   ProgramStateRef State = C.getState();
    356 
    357   // If this is a call to a C++ method, check if the callee is null or
    358   // undefined.
    359   if (const CXXInstanceCall *CC = dyn_cast<CXXInstanceCall>(&Call)) {
    360     SVal V = CC->getCXXThisVal();
    361     if (V.isUndef()) {
    362       if (!BT_cxx_call_undef)
    363         BT_cxx_call_undef.reset(
    364             new BuiltinBug(this, "Called C++ object pointer is uninitialized"));
    365       emitBadCall(BT_cxx_call_undef.get(), C, CC->getCXXThisExpr());
    366       return;
    367     }
    368 
    369     ProgramStateRef StNonNull, StNull;
    370     std::tie(StNonNull, StNull) =
    371         State->assume(V.castAs<DefinedOrUnknownSVal>());
    372 
    373     if (StNull && !StNonNull) {
    374       if (!BT_cxx_call_null)
    375         BT_cxx_call_null.reset(
    376             new BuiltinBug(this, "Called C++ object pointer is null"));
    377       emitBadCall(BT_cxx_call_null.get(), C, CC->getCXXThisExpr());
    378       return;
    379     }
    380 
    381     State = StNonNull;
    382   }
    383 
    384   const Decl *D = Call.getDecl();
    385   const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
    386   if (FD) {
    387     // If we have a declaration, we can make sure we pass enough parameters to
    388     // the function.
    389     unsigned Params = FD->getNumParams();
    390     if (Call.getNumArgs() < Params) {
    391       ExplodedNode *N = C.generateSink();
    392       if (!N)
    393         return;
    394 
    395       LazyInit_BT("Function call with too few arguments", BT_call_few_args);
    396 
    397       SmallString<512> Str;
    398       llvm::raw_svector_ostream os(Str);
    399       os << "Function taking " << Params << " argument"
    400          << (Params == 1 ? "" : "s") << " is called with less ("
    401          << Call.getNumArgs() << ")";
    402 
    403       BugReport *R = new BugReport(*BT_call_few_args, os.str(), N);
    404       C.emitReport(R);
    405     }
    406   }
    407 
    408   // Don't check for uninitialized field values in arguments if the
    409   // caller has a body that is available and we have the chance to inline it.
    410   // This is a hack, but is a reasonable compromise betweens sometimes warning
    411   // and sometimes not depending on if we decide to inline a function.
    412   const bool checkUninitFields =
    413     !(C.getAnalysisManager().shouldInlineCall() && (D && D->getBody()));
    414 
    415   std::unique_ptr<BugType> *BT;
    416   if (isa<ObjCMethodCall>(Call))
    417     BT = &BT_msg_arg;
    418   else
    419     BT = &BT_call_arg;
    420 
    421   for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i) {
    422     const ParmVarDecl *ParamDecl = nullptr;
    423     if(FD && i < FD->getNumParams())
    424       ParamDecl = FD->getParamDecl(i);
    425     if (PreVisitProcessArg(C, Call.getArgSVal(i), Call.getArgSourceRange(i),
    426                            Call.getArgExpr(i), /*IsFirstArgument=*/i == 0,
    427                            checkUninitFields, Call, *BT, ParamDecl))
    428       return;
    429   }
    430 
    431   // If we make it here, record our assumptions about the callee.
    432   C.addTransition(State);
    433 }
    434 
    435 void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
    436                                                 CheckerContext &C) const {
    437   SVal recVal = msg.getReceiverSVal();
    438   if (recVal.isUndef()) {
    439     if (ExplodedNode *N = C.generateSink()) {
    440       BugType *BT = nullptr;
    441       switch (msg.getMessageKind()) {
    442       case OCM_Message:
    443         if (!BT_msg_undef)
    444           BT_msg_undef.reset(new BuiltinBug(this,
    445                                             "Receiver in message expression "
    446                                             "is an uninitialized value"));
    447         BT = BT_msg_undef.get();
    448         break;
    449       case OCM_PropertyAccess:
    450         if (!BT_objc_prop_undef)
    451           BT_objc_prop_undef.reset(new BuiltinBug(
    452               this, "Property access on an uninitialized object pointer"));
    453         BT = BT_objc_prop_undef.get();
    454         break;
    455       case OCM_Subscript:
    456         if (!BT_objc_subscript_undef)
    457           BT_objc_subscript_undef.reset(new BuiltinBug(
    458               this, "Subscript access on an uninitialized object pointer"));
    459         BT = BT_objc_subscript_undef.get();
    460         break;
    461       }
    462       assert(BT && "Unknown message kind.");
    463 
    464       BugReport *R = new BugReport(*BT, BT->getName(), N);
    465       const ObjCMessageExpr *ME = msg.getOriginExpr();
    466       R->addRange(ME->getReceiverRange());
    467 
    468       // FIXME: getTrackNullOrUndefValueVisitor can't handle "super" yet.
    469       if (const Expr *ReceiverE = ME->getInstanceReceiver())
    470         bugreporter::trackNullOrUndefValue(N, ReceiverE, *R);
    471       C.emitReport(R);
    472     }
    473     return;
    474   } else {
    475     // Bifurcate the state into nil and non-nil ones.
    476     DefinedOrUnknownSVal receiverVal = recVal.castAs<DefinedOrUnknownSVal>();
    477 
    478     ProgramStateRef state = C.getState();
    479     ProgramStateRef notNilState, nilState;
    480     std::tie(notNilState, nilState) = state->assume(receiverVal);
    481 
    482     // Handle receiver must be nil.
    483     if (nilState && !notNilState) {
    484       HandleNilReceiver(C, state, msg);
    485       return;
    486     }
    487   }
    488 }
    489 
    490 void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
    491                                                const ObjCMethodCall &msg,
    492                                                ExplodedNode *N) const {
    493 
    494   if (!BT_msg_ret)
    495     BT_msg_ret.reset(
    496         new BuiltinBug(this, "Receiver in message expression is 'nil'"));
    497 
    498   const ObjCMessageExpr *ME = msg.getOriginExpr();
    499 
    500   QualType ResTy = msg.getResultType();
    501 
    502   SmallString<200> buf;
    503   llvm::raw_svector_ostream os(buf);
    504   os << "The receiver of message '";
    505   ME->getSelector().print(os);
    506   os << "' is nil";
    507   if (ResTy->isReferenceType()) {
    508     os << ", which results in forming a null reference";
    509   } else {
    510     os << " and returns a value of type '";
    511     msg.getResultType().print(os, C.getLangOpts());
    512     os << "' that will be garbage";
    513   }
    514 
    515   BugReport *report = new BugReport(*BT_msg_ret, os.str(), N);
    516   report->addRange(ME->getReceiverRange());
    517   // FIXME: This won't track "self" in messages to super.
    518   if (const Expr *receiver = ME->getInstanceReceiver()) {
    519     bugreporter::trackNullOrUndefValue(N, receiver, *report);
    520   }
    521   C.emitReport(report);
    522 }
    523 
    524 static bool supportsNilWithFloatRet(const llvm::Triple &triple) {
    525   return (triple.getVendor() == llvm::Triple::Apple &&
    526           (triple.isiOS() || !triple.isMacOSXVersionLT(10,5)));
    527 }
    528 
    529 void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
    530                                               ProgramStateRef state,
    531                                               const ObjCMethodCall &Msg) const {
    532   ASTContext &Ctx = C.getASTContext();
    533   static CheckerProgramPointTag Tag(this, "NilReceiver");
    534 
    535   // Check the return type of the message expression.  A message to nil will
    536   // return different values depending on the return type and the architecture.
    537   QualType RetTy = Msg.getResultType();
    538   CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
    539   const LocationContext *LCtx = C.getLocationContext();
    540 
    541   if (CanRetTy->isStructureOrClassType()) {
    542     // Structure returns are safe since the compiler zeroes them out.
    543     SVal V = C.getSValBuilder().makeZeroVal(RetTy);
    544     C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
    545     return;
    546   }
    547 
    548   // Other cases: check if sizeof(return type) > sizeof(void*)
    549   if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap()
    550                                   .isConsumedExpr(Msg.getOriginExpr())) {
    551     // Compute: sizeof(void *) and sizeof(return type)
    552     const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
    553     const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
    554 
    555     if (CanRetTy.getTypePtr()->isReferenceType()||
    556         (voidPtrSize < returnTypeSize &&
    557          !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) &&
    558            (Ctx.FloatTy == CanRetTy ||
    559             Ctx.DoubleTy == CanRetTy ||
    560             Ctx.LongDoubleTy == CanRetTy ||
    561             Ctx.LongLongTy == CanRetTy ||
    562             Ctx.UnsignedLongLongTy == CanRetTy)))) {
    563       if (ExplodedNode *N = C.generateSink(state, nullptr, &Tag))
    564         emitNilReceiverBug(C, Msg, N);
    565       return;
    566     }
    567 
    568     // Handle the safe cases where the return value is 0 if the
    569     // receiver is nil.
    570     //
    571     // FIXME: For now take the conservative approach that we only
    572     // return null values if we *know* that the receiver is nil.
    573     // This is because we can have surprises like:
    574     //
    575     //   ... = [[NSScreens screens] objectAtIndex:0];
    576     //
    577     // What can happen is that [... screens] could return nil, but
    578     // it most likely isn't nil.  We should assume the semantics
    579     // of this case unless we have *a lot* more knowledge.
    580     //
    581     SVal V = C.getSValBuilder().makeZeroVal(RetTy);
    582     C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
    583     return;
    584   }
    585 
    586   C.addTransition(state);
    587 }
    588 
    589 #define REGISTER_CHECKER(name)                                                 \
    590   void ento::register##name(CheckerManager &mgr) {                             \
    591     CallAndMessageChecker *Checker =                                           \
    592         mgr.registerChecker<CallAndMessageChecker>();                          \
    593     Checker->Filter.Check_##name = true;                                       \
    594     Checker->Filter.CheckName_##name = mgr.getCurrentCheckName();              \
    595   }
    596 
    597 REGISTER_CHECKER(CallAndMessageUnInitRefArg)
    598 REGISTER_CHECKER(CallAndMessageChecker)
    599