clang API Documentation
00001 //===--- CallAndMessageChecker.cpp ------------------------------*- C++ -*--==// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This defines CallAndMessageChecker, a builtin checker that checks for various 00011 // errors of call and objc message expressions. 00012 // 00013 //===----------------------------------------------------------------------===// 00014 00015 #include "ClangSACheckers.h" 00016 #include "clang/AST/ParentMap.h" 00017 #include "clang/Basic/TargetInfo.h" 00018 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 00019 #include "clang/StaticAnalyzer/Core/Checker.h" 00020 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 00021 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 00022 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 00023 #include "llvm/ADT/SmallString.h" 00024 #include "llvm/Support/raw_ostream.h" 00025 00026 using namespace clang; 00027 using namespace ento; 00028 00029 namespace { 00030 00031 struct ChecksFilter { 00032 DefaultBool Check_CallAndMessageUnInitRefArg; 00033 DefaultBool Check_CallAndMessageChecker; 00034 00035 CheckName CheckName_CallAndMessageUnInitRefArg; 00036 CheckName CheckName_CallAndMessageChecker; 00037 }; 00038 00039 class CallAndMessageChecker 00040 : public Checker< check::PreStmt<CallExpr>, 00041 check::PreStmt<CXXDeleteExpr>, 00042 check::PreObjCMessage, 00043 check::PreCall > { 00044 mutable std::unique_ptr<BugType> BT_call_null; 00045 mutable std::unique_ptr<BugType> BT_call_undef; 00046 mutable std::unique_ptr<BugType> BT_cxx_call_null; 00047 mutable std::unique_ptr<BugType> BT_cxx_call_undef; 00048 mutable std::unique_ptr<BugType> BT_call_arg; 00049 mutable std::unique_ptr<BugType> BT_cxx_delete_undef; 00050 mutable std::unique_ptr<BugType> BT_msg_undef; 00051 mutable std::unique_ptr<BugType> BT_objc_prop_undef; 00052 mutable std::unique_ptr<BugType> BT_objc_subscript_undef; 00053 mutable std::unique_ptr<BugType> BT_msg_arg; 00054 mutable std::unique_ptr<BugType> BT_msg_ret; 00055 mutable std::unique_ptr<BugType> BT_call_few_args; 00056 00057 public: 00058 ChecksFilter Filter; 00059 00060 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; 00061 void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const; 00062 void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const; 00063 void checkPreCall(const CallEvent &Call, CheckerContext &C) const; 00064 00065 private: 00066 bool PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange ArgRange, 00067 const Expr *ArgEx, bool IsFirstArgument, 00068 bool CheckUninitFields, const CallEvent &Call, 00069 std::unique_ptr<BugType> &BT, 00070 const ParmVarDecl *ParamDecl) const; 00071 00072 static void emitBadCall(BugType *BT, CheckerContext &C, const Expr *BadE); 00073 void emitNilReceiverBug(CheckerContext &C, const ObjCMethodCall &msg, 00074 ExplodedNode *N) const; 00075 00076 void HandleNilReceiver(CheckerContext &C, 00077 ProgramStateRef state, 00078 const ObjCMethodCall &msg) const; 00079 00080 void LazyInit_BT(const char *desc, std::unique_ptr<BugType> &BT) const { 00081 if (!BT) 00082 BT.reset(new BuiltinBug(this, desc)); 00083 } 00084 bool uninitRefOrPointer(CheckerContext &C, const SVal &V, 00085 const SourceRange &ArgRange, 00086 const Expr *ArgEx, std::unique_ptr<BugType> &BT, 00087 const ParmVarDecl *ParamDecl, const char *BD) const; 00088 }; 00089 } // end anonymous namespace 00090 00091 void CallAndMessageChecker::emitBadCall(BugType *BT, CheckerContext &C, 00092 const Expr *BadE) { 00093 ExplodedNode *N = C.generateSink(); 00094 if (!N) 00095 return; 00096 00097 BugReport *R = new BugReport(*BT, BT->getName(), N); 00098 if (BadE) { 00099 R->addRange(BadE->getSourceRange()); 00100 if (BadE->isGLValue()) 00101 BadE = bugreporter::getDerefExpr(BadE); 00102 bugreporter::trackNullOrUndefValue(N, BadE, *R); 00103 } 00104 C.emitReport(R); 00105 } 00106 00107 static StringRef describeUninitializedArgumentInCall(const CallEvent &Call, 00108 bool IsFirstArgument) { 00109 switch (Call.getKind()) { 00110 case CE_ObjCMessage: { 00111 const ObjCMethodCall &Msg = cast<ObjCMethodCall>(Call); 00112 switch (Msg.getMessageKind()) { 00113 case OCM_Message: 00114 return "Argument in message expression is an uninitialized value"; 00115 case OCM_PropertyAccess: 00116 assert(Msg.isSetter() && "Getters have no args"); 00117 return "Argument for property setter is an uninitialized value"; 00118 case OCM_Subscript: 00119 if (Msg.isSetter() && IsFirstArgument) 00120 return "Argument for subscript setter is an uninitialized value"; 00121 return "Subscript index is an uninitialized value"; 00122 } 00123 llvm_unreachable("Unknown message kind."); 00124 } 00125 case CE_Block: 00126 return "Block call argument is an uninitialized value"; 00127 default: 00128 return "Function call argument is an uninitialized value"; 00129 } 00130 } 00131 00132 bool CallAndMessageChecker::uninitRefOrPointer(CheckerContext &C, 00133 const SVal &V, 00134 const SourceRange &ArgRange, 00135 const Expr *ArgEx, 00136 std::unique_ptr<BugType> &BT, 00137 const ParmVarDecl *ParamDecl, 00138 const char *BD) const { 00139 if (!Filter.Check_CallAndMessageUnInitRefArg) 00140 return false; 00141 00142 // No parameter declaration available, i.e. variadic function argument. 00143 if(!ParamDecl) 00144 return false; 00145 00146 // If parameter is declared as pointer to const in function declaration, 00147 // then check if corresponding argument in function call is 00148 // pointing to undefined symbol value (uninitialized memory). 00149 StringRef Message; 00150 00151 if (ParamDecl->getType()->isPointerType()) { 00152 Message = "Function call argument is a pointer to uninitialized value"; 00153 } else if (ParamDecl->getType()->isReferenceType()) { 00154 Message = "Function call argument is an uninitialized value"; 00155 } else 00156 return false; 00157 00158 if(!ParamDecl->getType()->getPointeeType().isConstQualified()) 00159 return false; 00160 00161 if (const MemRegion *SValMemRegion = V.getAsRegion()) { 00162 const ProgramStateRef State = C.getState(); 00163 const SVal PSV = State->getSVal(SValMemRegion); 00164 if (PSV.isUndef()) { 00165 if (ExplodedNode *N = C.generateSink()) { 00166 LazyInit_BT(BD, BT); 00167 BugReport *R = new BugReport(*BT, Message, N); 00168 R->addRange(ArgRange); 00169 if (ArgEx) { 00170 bugreporter::trackNullOrUndefValue(N, ArgEx, *R); 00171 } 00172 C.emitReport(R); 00173 } 00174 return true; 00175 } 00176 } 00177 return false; 00178 } 00179 00180 bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, 00181 SVal V, 00182 SourceRange ArgRange, 00183 const Expr *ArgEx, 00184 bool IsFirstArgument, 00185 bool CheckUninitFields, 00186 const CallEvent &Call, 00187 std::unique_ptr<BugType> &BT, 00188 const ParmVarDecl *ParamDecl 00189 ) const { 00190 const char *BD = "Uninitialized argument value"; 00191 00192 if (uninitRefOrPointer(C, V, ArgRange, ArgEx, BT, ParamDecl, BD)) 00193 return true; 00194 00195 if (V.isUndef()) { 00196 if (ExplodedNode *N = C.generateSink()) { 00197 LazyInit_BT(BD, BT); 00198 00199 // Generate a report for this bug. 00200 StringRef Desc = 00201 describeUninitializedArgumentInCall(Call, IsFirstArgument); 00202 BugReport *R = new BugReport(*BT, Desc, N); 00203 R->addRange(ArgRange); 00204 if (ArgEx) 00205 bugreporter::trackNullOrUndefValue(N, ArgEx, *R); 00206 C.emitReport(R); 00207 } 00208 return true; 00209 } 00210 00211 if (!CheckUninitFields) 00212 return false; 00213 00214 if (Optional<nonloc::LazyCompoundVal> LV = 00215 V.getAs<nonloc::LazyCompoundVal>()) { 00216 00217 class FindUninitializedField { 00218 public: 00219 SmallVector<const FieldDecl *, 10> FieldChain; 00220 private: 00221 StoreManager &StoreMgr; 00222 MemRegionManager &MrMgr; 00223 Store store; 00224 public: 00225 FindUninitializedField(StoreManager &storeMgr, 00226 MemRegionManager &mrMgr, Store s) 00227 : StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {} 00228 00229 bool Find(const TypedValueRegion *R) { 00230 QualType T = R->getValueType(); 00231 if (const RecordType *RT = T->getAsStructureType()) { 00232 const RecordDecl *RD = RT->getDecl()->getDefinition(); 00233 assert(RD && "Referred record has no definition"); 00234 for (const auto *I : RD->fields()) { 00235 const FieldRegion *FR = MrMgr.getFieldRegion(I, R); 00236 FieldChain.push_back(I); 00237 T = I->getType(); 00238 if (T->getAsStructureType()) { 00239 if (Find(FR)) 00240 return true; 00241 } 00242 else { 00243 const SVal &V = StoreMgr.getBinding(store, loc::MemRegionVal(FR)); 00244 if (V.isUndef()) 00245 return true; 00246 } 00247 FieldChain.pop_back(); 00248 } 00249 } 00250 00251 return false; 00252 } 00253 }; 00254 00255 const LazyCompoundValData *D = LV->getCVData(); 00256 FindUninitializedField F(C.getState()->getStateManager().getStoreManager(), 00257 C.getSValBuilder().getRegionManager(), 00258 D->getStore()); 00259 00260 if (F.Find(D->getRegion())) { 00261 if (ExplodedNode *N = C.generateSink()) { 00262 LazyInit_BT(BD, BT); 00263 SmallString<512> Str; 00264 llvm::raw_svector_ostream os(Str); 00265 os << "Passed-by-value struct argument contains uninitialized data"; 00266 00267 if (F.FieldChain.size() == 1) 00268 os << " (e.g., field: '" << *F.FieldChain[0] << "')"; 00269 else { 00270 os << " (e.g., via the field chain: '"; 00271 bool first = true; 00272 for (SmallVectorImpl<const FieldDecl *>::iterator 00273 DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){ 00274 if (first) 00275 first = false; 00276 else 00277 os << '.'; 00278 os << **DI; 00279 } 00280 os << "')"; 00281 } 00282 00283 // Generate a report for this bug. 00284 BugReport *R = new BugReport(*BT, os.str(), N); 00285 R->addRange(ArgRange); 00286 00287 // FIXME: enhance track back for uninitialized value for arbitrary 00288 // memregions 00289 C.emitReport(R); 00290 } 00291 return true; 00292 } 00293 } 00294 00295 return false; 00296 } 00297 00298 void CallAndMessageChecker::checkPreStmt(const CallExpr *CE, 00299 CheckerContext &C) const{ 00300 00301 const Expr *Callee = CE->getCallee()->IgnoreParens(); 00302 ProgramStateRef State = C.getState(); 00303 const LocationContext *LCtx = C.getLocationContext(); 00304 SVal L = State->getSVal(Callee, LCtx); 00305 00306 if (L.isUndef()) { 00307 if (!BT_call_undef) 00308 BT_call_undef.reset(new BuiltinBug( 00309 this, "Called function pointer is an uninitalized pointer value")); 00310 emitBadCall(BT_call_undef.get(), C, Callee); 00311 return; 00312 } 00313 00314 ProgramStateRef StNonNull, StNull; 00315 std::tie(StNonNull, StNull) = State->assume(L.castAs<DefinedOrUnknownSVal>()); 00316 00317 if (StNull && !StNonNull) { 00318 if (!BT_call_null) 00319 BT_call_null.reset(new BuiltinBug( 00320 this, "Called function pointer is null (null dereference)")); 00321 emitBadCall(BT_call_null.get(), C, Callee); 00322 return; 00323 } 00324 00325 C.addTransition(StNonNull); 00326 } 00327 00328 void CallAndMessageChecker::checkPreStmt(const CXXDeleteExpr *DE, 00329 CheckerContext &C) const { 00330 00331 SVal Arg = C.getSVal(DE->getArgument()); 00332 if (Arg.isUndef()) { 00333 StringRef Desc; 00334 ExplodedNode *N = C.generateSink(); 00335 if (!N) 00336 return; 00337 if (!BT_cxx_delete_undef) 00338 BT_cxx_delete_undef.reset( 00339 new BuiltinBug(this, "Uninitialized argument value")); 00340 if (DE->isArrayFormAsWritten()) 00341 Desc = "Argument to 'delete[]' is uninitialized"; 00342 else 00343 Desc = "Argument to 'delete' is uninitialized"; 00344 BugType *BT = BT_cxx_delete_undef.get(); 00345 BugReport *R = new BugReport(*BT, Desc, N); 00346 bugreporter::trackNullOrUndefValue(N, DE, *R); 00347 C.emitReport(R); 00348 return; 00349 } 00350 } 00351 00352 00353 void CallAndMessageChecker::checkPreCall(const CallEvent &Call, 00354 CheckerContext &C) const { 00355 ProgramStateRef State = C.getState(); 00356 00357 // If this is a call to a C++ method, check if the callee is null or 00358 // undefined. 00359 if (const CXXInstanceCall *CC = dyn_cast<CXXInstanceCall>(&Call)) { 00360 SVal V = CC->getCXXThisVal(); 00361 if (V.isUndef()) { 00362 if (!BT_cxx_call_undef) 00363 BT_cxx_call_undef.reset( 00364 new BuiltinBug(this, "Called C++ object pointer is uninitialized")); 00365 emitBadCall(BT_cxx_call_undef.get(), C, CC->getCXXThisExpr()); 00366 return; 00367 } 00368 00369 ProgramStateRef StNonNull, StNull; 00370 std::tie(StNonNull, StNull) = 00371 State->assume(V.castAs<DefinedOrUnknownSVal>()); 00372 00373 if (StNull && !StNonNull) { 00374 if (!BT_cxx_call_null) 00375 BT_cxx_call_null.reset( 00376 new BuiltinBug(this, "Called C++ object pointer is null")); 00377 emitBadCall(BT_cxx_call_null.get(), C, CC->getCXXThisExpr()); 00378 return; 00379 } 00380 00381 State = StNonNull; 00382 } 00383 00384 const Decl *D = Call.getDecl(); 00385 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D); 00386 if (FD) { 00387 // If we have a declaration, we can make sure we pass enough parameters to 00388 // the function. 00389 unsigned Params = FD->getNumParams(); 00390 if (Call.getNumArgs() < Params) { 00391 ExplodedNode *N = C.generateSink(); 00392 if (!N) 00393 return; 00394 00395 LazyInit_BT("Function call with too few arguments", BT_call_few_args); 00396 00397 SmallString<512> Str; 00398 llvm::raw_svector_ostream os(Str); 00399 os << "Function taking " << Params << " argument" 00400 << (Params == 1 ? "" : "s") << " is called with less (" 00401 << Call.getNumArgs() << ")"; 00402 00403 BugReport *R = new BugReport(*BT_call_few_args, os.str(), N); 00404 C.emitReport(R); 00405 } 00406 } 00407 00408 // Don't check for uninitialized field values in arguments if the 00409 // caller has a body that is available and we have the chance to inline it. 00410 // This is a hack, but is a reasonable compromise betweens sometimes warning 00411 // and sometimes not depending on if we decide to inline a function. 00412 const bool checkUninitFields = 00413 !(C.getAnalysisManager().shouldInlineCall() && (D && D->getBody())); 00414 00415 std::unique_ptr<BugType> *BT; 00416 if (isa<ObjCMethodCall>(Call)) 00417 BT = &BT_msg_arg; 00418 else 00419 BT = &BT_call_arg; 00420 00421 for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i) { 00422 const ParmVarDecl *ParamDecl = nullptr; 00423 if(FD && i < FD->getNumParams()) 00424 ParamDecl = FD->getParamDecl(i); 00425 if (PreVisitProcessArg(C, Call.getArgSVal(i), Call.getArgSourceRange(i), 00426 Call.getArgExpr(i), /*IsFirstArgument=*/i == 0, 00427 checkUninitFields, Call, *BT, ParamDecl)) 00428 return; 00429 } 00430 00431 // If we make it here, record our assumptions about the callee. 00432 C.addTransition(State); 00433 } 00434 00435 void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg, 00436 CheckerContext &C) const { 00437 SVal recVal = msg.getReceiverSVal(); 00438 if (recVal.isUndef()) { 00439 if (ExplodedNode *N = C.generateSink()) { 00440 BugType *BT = nullptr; 00441 switch (msg.getMessageKind()) { 00442 case OCM_Message: 00443 if (!BT_msg_undef) 00444 BT_msg_undef.reset(new BuiltinBug(this, 00445 "Receiver in message expression " 00446 "is an uninitialized value")); 00447 BT = BT_msg_undef.get(); 00448 break; 00449 case OCM_PropertyAccess: 00450 if (!BT_objc_prop_undef) 00451 BT_objc_prop_undef.reset(new BuiltinBug( 00452 this, "Property access on an uninitialized object pointer")); 00453 BT = BT_objc_prop_undef.get(); 00454 break; 00455 case OCM_Subscript: 00456 if (!BT_objc_subscript_undef) 00457 BT_objc_subscript_undef.reset(new BuiltinBug( 00458 this, "Subscript access on an uninitialized object pointer")); 00459 BT = BT_objc_subscript_undef.get(); 00460 break; 00461 } 00462 assert(BT && "Unknown message kind."); 00463 00464 BugReport *R = new BugReport(*BT, BT->getName(), N); 00465 const ObjCMessageExpr *ME = msg.getOriginExpr(); 00466 R->addRange(ME->getReceiverRange()); 00467 00468 // FIXME: getTrackNullOrUndefValueVisitor can't handle "super" yet. 00469 if (const Expr *ReceiverE = ME->getInstanceReceiver()) 00470 bugreporter::trackNullOrUndefValue(N, ReceiverE, *R); 00471 C.emitReport(R); 00472 } 00473 return; 00474 } else { 00475 // Bifurcate the state into nil and non-nil ones. 00476 DefinedOrUnknownSVal receiverVal = recVal.castAs<DefinedOrUnknownSVal>(); 00477 00478 ProgramStateRef state = C.getState(); 00479 ProgramStateRef notNilState, nilState; 00480 std::tie(notNilState, nilState) = state->assume(receiverVal); 00481 00482 // Handle receiver must be nil. 00483 if (nilState && !notNilState) { 00484 HandleNilReceiver(C, state, msg); 00485 return; 00486 } 00487 } 00488 } 00489 00490 void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C, 00491 const ObjCMethodCall &msg, 00492 ExplodedNode *N) const { 00493 00494 if (!BT_msg_ret) 00495 BT_msg_ret.reset( 00496 new BuiltinBug(this, "Receiver in message expression is 'nil'")); 00497 00498 const ObjCMessageExpr *ME = msg.getOriginExpr(); 00499 00500 QualType ResTy = msg.getResultType(); 00501 00502 SmallString<200> buf; 00503 llvm::raw_svector_ostream os(buf); 00504 os << "The receiver of message '"; 00505 ME->getSelector().print(os); 00506 os << "' is nil"; 00507 if (ResTy->isReferenceType()) { 00508 os << ", which results in forming a null reference"; 00509 } else { 00510 os << " and returns a value of type '"; 00511 msg.getResultType().print(os, C.getLangOpts()); 00512 os << "' that will be garbage"; 00513 } 00514 00515 BugReport *report = new BugReport(*BT_msg_ret, os.str(), N); 00516 report->addRange(ME->getReceiverRange()); 00517 // FIXME: This won't track "self" in messages to super. 00518 if (const Expr *receiver = ME->getInstanceReceiver()) { 00519 bugreporter::trackNullOrUndefValue(N, receiver, *report); 00520 } 00521 C.emitReport(report); 00522 } 00523 00524 static bool supportsNilWithFloatRet(const llvm::Triple &triple) { 00525 return (triple.getVendor() == llvm::Triple::Apple && 00526 (triple.isiOS() || !triple.isMacOSXVersionLT(10,5))); 00527 } 00528 00529 void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, 00530 ProgramStateRef state, 00531 const ObjCMethodCall &Msg) const { 00532 ASTContext &Ctx = C.getASTContext(); 00533 static CheckerProgramPointTag Tag(this, "NilReceiver"); 00534 00535 // Check the return type of the message expression. A message to nil will 00536 // return different values depending on the return type and the architecture. 00537 QualType RetTy = Msg.getResultType(); 00538 CanQualType CanRetTy = Ctx.getCanonicalType(RetTy); 00539 const LocationContext *LCtx = C.getLocationContext(); 00540 00541 if (CanRetTy->isStructureOrClassType()) { 00542 // Structure returns are safe since the compiler zeroes them out. 00543 SVal V = C.getSValBuilder().makeZeroVal(RetTy); 00544 C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag); 00545 return; 00546 } 00547 00548 // Other cases: check if sizeof(return type) > sizeof(void*) 00549 if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap() 00550 .isConsumedExpr(Msg.getOriginExpr())) { 00551 // Compute: sizeof(void *) and sizeof(return type) 00552 const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy); 00553 const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy); 00554 00555 if (CanRetTy.getTypePtr()->isReferenceType()|| 00556 (voidPtrSize < returnTypeSize && 00557 !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) && 00558 (Ctx.FloatTy == CanRetTy || 00559 Ctx.DoubleTy == CanRetTy || 00560 Ctx.LongDoubleTy == CanRetTy || 00561 Ctx.LongLongTy == CanRetTy || 00562 Ctx.UnsignedLongLongTy == CanRetTy)))) { 00563 if (ExplodedNode *N = C.generateSink(state, nullptr, &Tag)) 00564 emitNilReceiverBug(C, Msg, N); 00565 return; 00566 } 00567 00568 // Handle the safe cases where the return value is 0 if the 00569 // receiver is nil. 00570 // 00571 // FIXME: For now take the conservative approach that we only 00572 // return null values if we *know* that the receiver is nil. 00573 // This is because we can have surprises like: 00574 // 00575 // ... = [[NSScreens screens] objectAtIndex:0]; 00576 // 00577 // What can happen is that [... screens] could return nil, but 00578 // it most likely isn't nil. We should assume the semantics 00579 // of this case unless we have *a lot* more knowledge. 00580 // 00581 SVal V = C.getSValBuilder().makeZeroVal(RetTy); 00582 C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag); 00583 return; 00584 } 00585 00586 C.addTransition(state); 00587 } 00588 00589 #define REGISTER_CHECKER(name) \ 00590 void ento::register##name(CheckerManager &mgr) { \ 00591 CallAndMessageChecker *Checker = \ 00592 mgr.registerChecker<CallAndMessageChecker>(); \ 00593 Checker->Filter.Check_##name = true; \ 00594 Checker->Filter.CheckName_##name = mgr.getCurrentCheckName(); \ 00595 } 00596 00597 REGISTER_CHECKER(CallAndMessageUnInitRefArg) 00598 REGISTER_CHECKER(CallAndMessageChecker)