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