1 //== DynamicTypePropagation.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 file contains two checkers. One helps the static analyzer core to track 11 // types, the other does type inference on Obj-C generics and report type 12 // errors. 13 // 14 // Dynamic Type Propagation: 15 // This checker defines the rules for dynamic type gathering and propagation. 16 // 17 // Generics Checker for Objective-C: 18 // This checker tries to find type errors that the compiler is not able to catch 19 // due to the implicit conversions that were introduced for backward 20 // compatibility. 21 // 22 //===----------------------------------------------------------------------===// 23 24 #include "ClangSACheckers.h" 25 #include "clang/AST/RecursiveASTVisitor.h" 26 #include "clang/Basic/Builtins.h" 27 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 28 #include "clang/StaticAnalyzer/Core/Checker.h" 29 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 30 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 31 #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h" 32 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 33 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" 34 35 using namespace clang; 36 using namespace ento; 37 38 // ProgramState trait - The type inflation is tracked by DynamicTypeMap. This is 39 // an auxiliary map that tracks more information about generic types, because in 40 // some cases the most derived type is not the most informative one about the 41 // type parameters. This types that are stored for each symbol in this map must 42 // be specialized. 43 // TODO: In some case the type stored in this map is exactly the same that is 44 // stored in DynamicTypeMap. We should no store duplicated information in those 45 // cases. 46 REGISTER_MAP_WITH_PROGRAMSTATE(MostSpecializedTypeArgsMap, SymbolRef, 47 const ObjCObjectPointerType *) 48 49 namespace { 50 class DynamicTypePropagation: 51 public Checker< check::PreCall, 52 check::PostCall, 53 check::DeadSymbols, 54 check::PostStmt<CastExpr>, 55 check::PostStmt<CXXNewExpr>, 56 check::PreObjCMessage, 57 check::PostObjCMessage > { 58 const ObjCObjectType *getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE, 59 CheckerContext &C) const; 60 61 /// \brief Return a better dynamic type if one can be derived from the cast. 62 const ObjCObjectPointerType *getBetterObjCType(const Expr *CastE, 63 CheckerContext &C) const; 64 65 ExplodedNode *dynamicTypePropagationOnCasts(const CastExpr *CE, 66 ProgramStateRef &State, 67 CheckerContext &C) const; 68 69 mutable std::unique_ptr<BugType> ObjCGenericsBugType; 70 void initBugType() const { 71 if (!ObjCGenericsBugType) 72 ObjCGenericsBugType.reset( 73 new BugType(this, "Generics", categories::CoreFoundationObjectiveC)); 74 } 75 76 class GenericsBugVisitor : public BugReporterVisitorImpl<GenericsBugVisitor> { 77 public: 78 GenericsBugVisitor(SymbolRef S) : Sym(S) {} 79 80 void Profile(llvm::FoldingSetNodeID &ID) const override { 81 static int X = 0; 82 ID.AddPointer(&X); 83 ID.AddPointer(Sym); 84 } 85 86 PathDiagnosticPiece *VisitNode(const ExplodedNode *N, 87 const ExplodedNode *PrevN, 88 BugReporterContext &BRC, 89 BugReport &BR) override; 90 91 private: 92 // The tracked symbol. 93 SymbolRef Sym; 94 }; 95 96 void reportGenericsBug(const ObjCObjectPointerType *From, 97 const ObjCObjectPointerType *To, ExplodedNode *N, 98 SymbolRef Sym, CheckerContext &C, 99 const Stmt *ReportedNode = nullptr) const; 100 public: 101 void checkPreCall(const CallEvent &Call, CheckerContext &C) const; 102 void checkPostCall(const CallEvent &Call, CheckerContext &C) const; 103 void checkPostStmt(const CastExpr *CastE, CheckerContext &C) const; 104 void checkPostStmt(const CXXNewExpr *NewE, CheckerContext &C) const; 105 void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const; 106 void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const; 107 void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const; 108 109 /// This value is set to true, when the Generics checker is turned on. 110 DefaultBool CheckGenerics; 111 }; 112 } 113 114 void DynamicTypePropagation::checkDeadSymbols(SymbolReaper &SR, 115 CheckerContext &C) const { 116 ProgramStateRef State = C.getState(); 117 DynamicTypeMapImpl TypeMap = State->get<DynamicTypeMap>(); 118 for (DynamicTypeMapImpl::iterator I = TypeMap.begin(), E = TypeMap.end(); 119 I != E; ++I) { 120 if (!SR.isLiveRegion(I->first)) { 121 State = State->remove<DynamicTypeMap>(I->first); 122 } 123 } 124 125 if (!SR.hasDeadSymbols()) { 126 C.addTransition(State); 127 return; 128 } 129 130 MostSpecializedTypeArgsMapTy TyArgMap = 131 State->get<MostSpecializedTypeArgsMap>(); 132 for (MostSpecializedTypeArgsMapTy::iterator I = TyArgMap.begin(), 133 E = TyArgMap.end(); 134 I != E; ++I) { 135 if (SR.isDead(I->first)) { 136 State = State->remove<MostSpecializedTypeArgsMap>(I->first); 137 } 138 } 139 140 C.addTransition(State); 141 } 142 143 static void recordFixedType(const MemRegion *Region, const CXXMethodDecl *MD, 144 CheckerContext &C) { 145 assert(Region); 146 assert(MD); 147 148 ASTContext &Ctx = C.getASTContext(); 149 QualType Ty = Ctx.getPointerType(Ctx.getRecordType(MD->getParent())); 150 151 ProgramStateRef State = C.getState(); 152 State = setDynamicTypeInfo(State, Region, Ty, /*CanBeSubclass=*/false); 153 C.addTransition(State); 154 return; 155 } 156 157 void DynamicTypePropagation::checkPreCall(const CallEvent &Call, 158 CheckerContext &C) const { 159 if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) { 160 // C++11 [class.cdtor]p4: When a virtual function is called directly or 161 // indirectly from a constructor or from a destructor, including during 162 // the construction or destruction of the class's non-static data members, 163 // and the object to which the call applies is the object under 164 // construction or destruction, the function called is the final overrider 165 // in the constructor's or destructor's class and not one overriding it in 166 // a more-derived class. 167 168 switch (Ctor->getOriginExpr()->getConstructionKind()) { 169 case CXXConstructExpr::CK_Complete: 170 case CXXConstructExpr::CK_Delegating: 171 // No additional type info necessary. 172 return; 173 case CXXConstructExpr::CK_NonVirtualBase: 174 case CXXConstructExpr::CK_VirtualBase: 175 if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion()) 176 recordFixedType(Target, Ctor->getDecl(), C); 177 return; 178 } 179 180 return; 181 } 182 183 if (const CXXDestructorCall *Dtor = dyn_cast<CXXDestructorCall>(&Call)) { 184 // C++11 [class.cdtor]p4 (see above) 185 if (!Dtor->isBaseDestructor()) 186 return; 187 188 const MemRegion *Target = Dtor->getCXXThisVal().getAsRegion(); 189 if (!Target) 190 return; 191 192 const Decl *D = Dtor->getDecl(); 193 if (!D) 194 return; 195 196 recordFixedType(Target, cast<CXXDestructorDecl>(D), C); 197 return; 198 } 199 } 200 201 void DynamicTypePropagation::checkPostCall(const CallEvent &Call, 202 CheckerContext &C) const { 203 // We can obtain perfect type info for return values from some calls. 204 if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(&Call)) { 205 206 // Get the returned value if it's a region. 207 const MemRegion *RetReg = Call.getReturnValue().getAsRegion(); 208 if (!RetReg) 209 return; 210 211 ProgramStateRef State = C.getState(); 212 const ObjCMethodDecl *D = Msg->getDecl(); 213 214 if (D && D->hasRelatedResultType()) { 215 switch (Msg->getMethodFamily()) { 216 default: 217 break; 218 219 // We assume that the type of the object returned by alloc and new are the 220 // pointer to the object of the class specified in the receiver of the 221 // message. 222 case OMF_alloc: 223 case OMF_new: { 224 // Get the type of object that will get created. 225 const ObjCMessageExpr *MsgE = Msg->getOriginExpr(); 226 const ObjCObjectType *ObjTy = getObjectTypeForAllocAndNew(MsgE, C); 227 if (!ObjTy) 228 return; 229 QualType DynResTy = 230 C.getASTContext().getObjCObjectPointerType(QualType(ObjTy, 0)); 231 C.addTransition(setDynamicTypeInfo(State, RetReg, DynResTy, false)); 232 break; 233 } 234 case OMF_init: { 235 // Assume, the result of the init method has the same dynamic type as 236 // the receiver and propagate the dynamic type info. 237 const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion(); 238 if (!RecReg) 239 return; 240 DynamicTypeInfo RecDynType = getDynamicTypeInfo(State, RecReg); 241 C.addTransition(setDynamicTypeInfo(State, RetReg, RecDynType)); 242 break; 243 } 244 } 245 } 246 return; 247 } 248 249 if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) { 250 // We may need to undo the effects of our pre-call check. 251 switch (Ctor->getOriginExpr()->getConstructionKind()) { 252 case CXXConstructExpr::CK_Complete: 253 case CXXConstructExpr::CK_Delegating: 254 // No additional work necessary. 255 // Note: This will leave behind the actual type of the object for 256 // complete constructors, but arguably that's a good thing, since it 257 // means the dynamic type info will be correct even for objects 258 // constructed with operator new. 259 return; 260 case CXXConstructExpr::CK_NonVirtualBase: 261 case CXXConstructExpr::CK_VirtualBase: 262 if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion()) { 263 // We just finished a base constructor. Now we can use the subclass's 264 // type when resolving virtual calls. 265 const Decl *D = C.getLocationContext()->getDecl(); 266 recordFixedType(Target, cast<CXXConstructorDecl>(D), C); 267 } 268 return; 269 } 270 } 271 } 272 273 /// TODO: Handle explicit casts. 274 /// Handle C++ casts. 275 /// 276 /// Precondition: the cast is between ObjCObjectPointers. 277 ExplodedNode *DynamicTypePropagation::dynamicTypePropagationOnCasts( 278 const CastExpr *CE, ProgramStateRef &State, CheckerContext &C) const { 279 // We only track type info for regions. 280 const MemRegion *ToR = C.getSVal(CE).getAsRegion(); 281 if (!ToR) 282 return C.getPredecessor(); 283 284 if (isa<ExplicitCastExpr>(CE)) 285 return C.getPredecessor(); 286 287 if (const Type *NewTy = getBetterObjCType(CE, C)) { 288 State = setDynamicTypeInfo(State, ToR, QualType(NewTy, 0)); 289 return C.addTransition(State); 290 } 291 return C.getPredecessor(); 292 } 293 294 void DynamicTypePropagation::checkPostStmt(const CXXNewExpr *NewE, 295 CheckerContext &C) const { 296 if (NewE->isArray()) 297 return; 298 299 // We only track dynamic type info for regions. 300 const MemRegion *MR = C.getSVal(NewE).getAsRegion(); 301 if (!MR) 302 return; 303 304 C.addTransition(setDynamicTypeInfo(C.getState(), MR, NewE->getType(), 305 /*CanBeSubclass=*/false)); 306 } 307 308 const ObjCObjectType * 309 DynamicTypePropagation::getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE, 310 CheckerContext &C) const { 311 if (MsgE->getReceiverKind() == ObjCMessageExpr::Class) { 312 if (const ObjCObjectType *ObjTy 313 = MsgE->getClassReceiver()->getAs<ObjCObjectType>()) 314 return ObjTy; 315 } 316 317 if (MsgE->getReceiverKind() == ObjCMessageExpr::SuperClass) { 318 if (const ObjCObjectType *ObjTy 319 = MsgE->getSuperType()->getAs<ObjCObjectType>()) 320 return ObjTy; 321 } 322 323 const Expr *RecE = MsgE->getInstanceReceiver(); 324 if (!RecE) 325 return nullptr; 326 327 RecE= RecE->IgnoreParenImpCasts(); 328 if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(RecE)) { 329 const StackFrameContext *SFCtx = C.getStackFrame(); 330 // Are we calling [self alloc]? If this is self, get the type of the 331 // enclosing ObjC class. 332 if (DRE->getDecl() == SFCtx->getSelfDecl()) { 333 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(SFCtx->getDecl())) 334 if (const ObjCObjectType *ObjTy = 335 dyn_cast<ObjCObjectType>(MD->getClassInterface()->getTypeForDecl())) 336 return ObjTy; 337 } 338 } 339 return nullptr; 340 } 341 342 // Return a better dynamic type if one can be derived from the cast. 343 // Compare the current dynamic type of the region and the new type to which we 344 // are casting. If the new type is lower in the inheritance hierarchy, pick it. 345 const ObjCObjectPointerType * 346 DynamicTypePropagation::getBetterObjCType(const Expr *CastE, 347 CheckerContext &C) const { 348 const MemRegion *ToR = C.getSVal(CastE).getAsRegion(); 349 assert(ToR); 350 351 // Get the old and new types. 352 const ObjCObjectPointerType *NewTy = 353 CastE->getType()->getAs<ObjCObjectPointerType>(); 354 if (!NewTy) 355 return nullptr; 356 QualType OldDTy = getDynamicTypeInfo(C.getState(), ToR).getType(); 357 if (OldDTy.isNull()) { 358 return NewTy; 359 } 360 const ObjCObjectPointerType *OldTy = 361 OldDTy->getAs<ObjCObjectPointerType>(); 362 if (!OldTy) 363 return nullptr; 364 365 // Id the old type is 'id', the new one is more precise. 366 if (OldTy->isObjCIdType() && !NewTy->isObjCIdType()) 367 return NewTy; 368 369 // Return new if it's a subclass of old. 370 const ObjCInterfaceDecl *ToI = NewTy->getInterfaceDecl(); 371 const ObjCInterfaceDecl *FromI = OldTy->getInterfaceDecl(); 372 if (ToI && FromI && FromI->isSuperClassOf(ToI)) 373 return NewTy; 374 375 return nullptr; 376 } 377 378 static const ObjCObjectPointerType *getMostInformativeDerivedClassImpl( 379 const ObjCObjectPointerType *From, const ObjCObjectPointerType *To, 380 const ObjCObjectPointerType *MostInformativeCandidate, ASTContext &C) { 381 // Checking if from and to are the same classes modulo specialization. 382 if (From->getInterfaceDecl()->getCanonicalDecl() == 383 To->getInterfaceDecl()->getCanonicalDecl()) { 384 if (To->isSpecialized()) { 385 assert(MostInformativeCandidate->isSpecialized()); 386 return MostInformativeCandidate; 387 } 388 return From; 389 } 390 const auto *SuperOfTo = 391 To->getObjectType()->getSuperClassType()->getAs<ObjCObjectType>(); 392 assert(SuperOfTo); 393 QualType SuperPtrOfToQual = 394 C.getObjCObjectPointerType(QualType(SuperOfTo, 0)); 395 const auto *SuperPtrOfTo = SuperPtrOfToQual->getAs<ObjCObjectPointerType>(); 396 if (To->isUnspecialized()) 397 return getMostInformativeDerivedClassImpl(From, SuperPtrOfTo, SuperPtrOfTo, 398 C); 399 else 400 return getMostInformativeDerivedClassImpl(From, SuperPtrOfTo, 401 MostInformativeCandidate, C); 402 } 403 404 /// A downcast may loose specialization information. E. g.: 405 /// MutableMap<T, U> : Map 406 /// The downcast to MutableMap looses the information about the types of the 407 /// Map (due to the type parameters are not being forwarded to Map), and in 408 /// general there is no way to recover that information from the 409 /// declaration. In order to have to most information, lets find the most 410 /// derived type that has all the type parameters forwarded. 411 /// 412 /// Get the a subclass of \p From (which has a lower bound \p To) that do not 413 /// loose information about type parameters. \p To has to be a subclass of 414 /// \p From. From has to be specialized. 415 static const ObjCObjectPointerType * 416 getMostInformativeDerivedClass(const ObjCObjectPointerType *From, 417 const ObjCObjectPointerType *To, ASTContext &C) { 418 return getMostInformativeDerivedClassImpl(From, To, To, C); 419 } 420 421 /// Inputs: 422 /// \param StaticLowerBound Static lower bound for a symbol. The dynamic lower 423 /// bound might be the subclass of this type. 424 /// \param StaticUpperBound A static upper bound for a symbol. 425 /// \p StaticLowerBound expected to be the subclass of \p StaticUpperBound. 426 /// \param Current The type that was inferred for a symbol in a previous 427 /// context. Might be null when this is the first time that inference happens. 428 /// Precondition: 429 /// \p StaticLowerBound or \p StaticUpperBound is specialized. If \p Current 430 /// is not null, it is specialized. 431 /// Possible cases: 432 /// (1) The \p Current is null and \p StaticLowerBound <: \p StaticUpperBound 433 /// (2) \p StaticLowerBound <: \p Current <: \p StaticUpperBound 434 /// (3) \p Current <: \p StaticLowerBound <: \p StaticUpperBound 435 /// (4) \p StaticLowerBound <: \p StaticUpperBound <: \p Current 436 /// Effect: 437 /// Use getMostInformativeDerivedClass with the upper and lower bound of the 438 /// set {\p StaticLowerBound, \p Current, \p StaticUpperBound}. The computed 439 /// lower bound must be specialized. If the result differs from \p Current or 440 /// \p Current is null, store the result. 441 static bool 442 storeWhenMoreInformative(ProgramStateRef &State, SymbolRef Sym, 443 const ObjCObjectPointerType *const *Current, 444 const ObjCObjectPointerType *StaticLowerBound, 445 const ObjCObjectPointerType *StaticUpperBound, 446 ASTContext &C) { 447 // Precondition 448 assert(StaticUpperBound->isSpecialized() || 449 StaticLowerBound->isSpecialized()); 450 assert(!Current || (*Current)->isSpecialized()); 451 452 // Case (1) 453 if (!Current) { 454 if (StaticUpperBound->isUnspecialized()) { 455 State = State->set<MostSpecializedTypeArgsMap>(Sym, StaticLowerBound); 456 return true; 457 } 458 // Upper bound is specialized. 459 const ObjCObjectPointerType *WithMostInfo = 460 getMostInformativeDerivedClass(StaticUpperBound, StaticLowerBound, C); 461 State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo); 462 return true; 463 } 464 465 // Case (3) 466 if (C.canAssignObjCInterfaces(StaticLowerBound, *Current)) { 467 return false; 468 } 469 470 // Case (4) 471 if (C.canAssignObjCInterfaces(*Current, StaticUpperBound)) { 472 // The type arguments might not be forwarded at any point of inheritance. 473 const ObjCObjectPointerType *WithMostInfo = 474 getMostInformativeDerivedClass(*Current, StaticUpperBound, C); 475 WithMostInfo = 476 getMostInformativeDerivedClass(WithMostInfo, StaticLowerBound, C); 477 if (WithMostInfo == *Current) 478 return false; 479 State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo); 480 return true; 481 } 482 483 // Case (2) 484 const ObjCObjectPointerType *WithMostInfo = 485 getMostInformativeDerivedClass(*Current, StaticLowerBound, C); 486 if (WithMostInfo != *Current) { 487 State = State->set<MostSpecializedTypeArgsMap>(Sym, WithMostInfo); 488 return true; 489 } 490 491 return false; 492 } 493 494 /// Type inference based on static type information that is available for the 495 /// cast and the tracked type information for the given symbol. When the tracked 496 /// symbol and the destination type of the cast are unrelated, report an error. 497 void DynamicTypePropagation::checkPostStmt(const CastExpr *CE, 498 CheckerContext &C) const { 499 if (CE->getCastKind() != CK_BitCast) 500 return; 501 502 QualType OriginType = CE->getSubExpr()->getType(); 503 QualType DestType = CE->getType(); 504 505 const auto *OrigObjectPtrType = OriginType->getAs<ObjCObjectPointerType>(); 506 const auto *DestObjectPtrType = DestType->getAs<ObjCObjectPointerType>(); 507 508 if (!OrigObjectPtrType || !DestObjectPtrType) 509 return; 510 511 ProgramStateRef State = C.getState(); 512 ExplodedNode *AfterTypeProp = dynamicTypePropagationOnCasts(CE, State, C); 513 514 ASTContext &ASTCtxt = C.getASTContext(); 515 516 // This checker detects the subtyping relationships using the assignment 517 // rules. In order to be able to do this the kindofness must be stripped 518 // first. The checker treats every type as kindof type anyways: when the 519 // tracked type is the subtype of the static type it tries to look up the 520 // methods in the tracked type first. 521 OrigObjectPtrType = OrigObjectPtrType->stripObjCKindOfTypeAndQuals(ASTCtxt); 522 DestObjectPtrType = DestObjectPtrType->stripObjCKindOfTypeAndQuals(ASTCtxt); 523 524 // TODO: erase tracked information when there is a cast to unrelated type 525 // and everything is unspecialized statically. 526 if (OrigObjectPtrType->isUnspecialized() && 527 DestObjectPtrType->isUnspecialized()) 528 return; 529 530 SymbolRef Sym = State->getSVal(CE, C.getLocationContext()).getAsSymbol(); 531 if (!Sym) 532 return; 533 534 // Check which assignments are legal. 535 bool OrigToDest = 536 ASTCtxt.canAssignObjCInterfaces(DestObjectPtrType, OrigObjectPtrType); 537 bool DestToOrig = 538 ASTCtxt.canAssignObjCInterfaces(OrigObjectPtrType, DestObjectPtrType); 539 const ObjCObjectPointerType *const *TrackedType = 540 State->get<MostSpecializedTypeArgsMap>(Sym); 541 542 // Downcasts and upcasts handled in an uniform way regardless of being 543 // explicit. Explicit casts however can happen between mismatched types. 544 if (isa<ExplicitCastExpr>(CE) && !OrigToDest && !DestToOrig) { 545 // Mismatched types. If the DestType specialized, store it. Forget the 546 // tracked type otherwise. 547 if (DestObjectPtrType->isSpecialized()) { 548 State = State->set<MostSpecializedTypeArgsMap>(Sym, DestObjectPtrType); 549 C.addTransition(State, AfterTypeProp); 550 } else if (TrackedType) { 551 State = State->remove<MostSpecializedTypeArgsMap>(Sym); 552 C.addTransition(State, AfterTypeProp); 553 } 554 return; 555 } 556 557 // The tracked type should be the sub or super class of the static destination 558 // type. When an (implicit) upcast or a downcast happens according to static 559 // types, and there is no subtyping relationship between the tracked and the 560 // static destination types, it indicates an error. 561 if (TrackedType && 562 !ASTCtxt.canAssignObjCInterfaces(DestObjectPtrType, *TrackedType) && 563 !ASTCtxt.canAssignObjCInterfaces(*TrackedType, DestObjectPtrType)) { 564 static CheckerProgramPointTag IllegalConv(this, "IllegalConversion"); 565 ExplodedNode *N = C.addTransition(State, AfterTypeProp, &IllegalConv); 566 reportGenericsBug(*TrackedType, DestObjectPtrType, N, Sym, C); 567 return; 568 } 569 570 // Handle downcasts and upcasts. 571 572 const ObjCObjectPointerType *LowerBound = DestObjectPtrType; 573 const ObjCObjectPointerType *UpperBound = OrigObjectPtrType; 574 if (OrigToDest && !DestToOrig) 575 std::swap(LowerBound, UpperBound); 576 577 // The id type is not a real bound. Eliminate it. 578 LowerBound = LowerBound->isObjCIdType() ? UpperBound : LowerBound; 579 UpperBound = UpperBound->isObjCIdType() ? LowerBound : UpperBound; 580 581 if (storeWhenMoreInformative(State, Sym, TrackedType, LowerBound, UpperBound, 582 ASTCtxt)) { 583 C.addTransition(State, AfterTypeProp); 584 } 585 } 586 587 static const Expr *stripCastsAndSugar(const Expr *E) { 588 E = E->IgnoreParenImpCasts(); 589 if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) 590 E = POE->getSyntacticForm()->IgnoreParenImpCasts(); 591 if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E)) 592 E = OVE->getSourceExpr()->IgnoreParenImpCasts(); 593 return E; 594 } 595 596 static bool isObjCTypeParamDependent(QualType Type) { 597 // It is illegal to typedef parameterized types inside an interface. Therfore 598 // an Objective-C type can only be dependent on a type parameter when the type 599 // parameter structurally present in the type itself. 600 class IsObjCTypeParamDependentTypeVisitor 601 : public RecursiveASTVisitor<IsObjCTypeParamDependentTypeVisitor> { 602 public: 603 IsObjCTypeParamDependentTypeVisitor() : Result(false) {} 604 bool VisitTypedefType(const TypedefType *Type) { 605 if (isa<ObjCTypeParamDecl>(Type->getDecl())) { 606 Result = true; 607 return false; 608 } 609 return true; 610 } 611 612 bool Result; 613 }; 614 615 IsObjCTypeParamDependentTypeVisitor Visitor; 616 Visitor.TraverseType(Type); 617 return Visitor.Result; 618 } 619 620 /// A method might not be available in the interface indicated by the static 621 /// type. However it might be available in the tracked type. In order to 622 /// properly substitute the type parameters we need the declaration context of 623 /// the method. The more specialized the enclosing class of the method is, the 624 /// more likely that the parameter substitution will be successful. 625 static const ObjCMethodDecl * 626 findMethodDecl(const ObjCMessageExpr *MessageExpr, 627 const ObjCObjectPointerType *TrackedType, ASTContext &ASTCtxt) { 628 const ObjCMethodDecl *Method = nullptr; 629 630 QualType ReceiverType = MessageExpr->getReceiverType(); 631 const auto *ReceiverObjectPtrType = 632 ReceiverType->getAs<ObjCObjectPointerType>(); 633 634 // Do this "devirtualization" on instance and class methods only. Trust the 635 // static type on super and super class calls. 636 if (MessageExpr->getReceiverKind() == ObjCMessageExpr::Instance || 637 MessageExpr->getReceiverKind() == ObjCMessageExpr::Class) { 638 // When the receiver type is id, Class, or some super class of the tracked 639 // type, look up the method in the tracked type, not in the receiver type. 640 // This way we preserve more information. 641 if (ReceiverType->isObjCIdType() || ReceiverType->isObjCClassType() || 642 ASTCtxt.canAssignObjCInterfaces(ReceiverObjectPtrType, TrackedType)) { 643 const ObjCInterfaceDecl *InterfaceDecl = TrackedType->getInterfaceDecl(); 644 // The method might not be found. 645 Selector Sel = MessageExpr->getSelector(); 646 Method = InterfaceDecl->lookupInstanceMethod(Sel); 647 if (!Method) 648 Method = InterfaceDecl->lookupClassMethod(Sel); 649 } 650 } 651 652 // Fallback to statick method lookup when the one based on the tracked type 653 // failed. 654 return Method ? Method : MessageExpr->getMethodDecl(); 655 } 656 657 /// Get the returned ObjCObjectPointerType by a method based on the tracked type 658 /// information, or null pointer when the returned type is not an 659 /// ObjCObjectPointerType. 660 static QualType getReturnTypeForMethod( 661 const ObjCMethodDecl *Method, ArrayRef<QualType> TypeArgs, 662 const ObjCObjectPointerType *SelfType, ASTContext &C) { 663 QualType StaticResultType = Method->getReturnType(); 664 665 // Is the return type declared as instance type? 666 if (StaticResultType == C.getObjCInstanceType()) 667 return QualType(SelfType, 0); 668 669 // Check whether the result type depends on a type parameter. 670 if (!isObjCTypeParamDependent(StaticResultType)) 671 return QualType(); 672 673 QualType ResultType = StaticResultType.substObjCTypeArgs( 674 C, TypeArgs, ObjCSubstitutionContext::Result); 675 676 return ResultType; 677 } 678 679 /// When the receiver has a tracked type, use that type to validate the 680 /// argumments of the message expression and the return value. 681 void DynamicTypePropagation::checkPreObjCMessage(const ObjCMethodCall &M, 682 CheckerContext &C) const { 683 ProgramStateRef State = C.getState(); 684 SymbolRef Sym = M.getReceiverSVal().getAsSymbol(); 685 if (!Sym) 686 return; 687 688 const ObjCObjectPointerType *const *TrackedType = 689 State->get<MostSpecializedTypeArgsMap>(Sym); 690 if (!TrackedType) 691 return; 692 693 // Get the type arguments from tracked type and substitute type arguments 694 // before do the semantic check. 695 696 ASTContext &ASTCtxt = C.getASTContext(); 697 const ObjCMessageExpr *MessageExpr = M.getOriginExpr(); 698 const ObjCMethodDecl *Method = 699 findMethodDecl(MessageExpr, *TrackedType, ASTCtxt); 700 701 // It is possible to call non-existent methods in Obj-C. 702 if (!Method) 703 return; 704 705 Optional<ArrayRef<QualType>> TypeArgs = 706 (*TrackedType)->getObjCSubstitutions(Method->getDeclContext()); 707 // This case might happen when there is an unspecialized override of a 708 // specialized method. 709 if (!TypeArgs) 710 return; 711 712 for (unsigned i = 0; i < Method->param_size(); i++) { 713 const Expr *Arg = MessageExpr->getArg(i); 714 const ParmVarDecl *Param = Method->parameters()[i]; 715 716 QualType OrigParamType = Param->getType(); 717 if (!isObjCTypeParamDependent(OrigParamType)) 718 continue; 719 720 QualType ParamType = OrigParamType.substObjCTypeArgs( 721 ASTCtxt, *TypeArgs, ObjCSubstitutionContext::Parameter); 722 // Check if it can be assigned 723 const auto *ParamObjectPtrType = ParamType->getAs<ObjCObjectPointerType>(); 724 const auto *ArgObjectPtrType = 725 stripCastsAndSugar(Arg)->getType()->getAs<ObjCObjectPointerType>(); 726 if (!ParamObjectPtrType || !ArgObjectPtrType) 727 continue; 728 729 // Check if we have more concrete tracked type that is not a super type of 730 // the static argument type. 731 SVal ArgSVal = M.getArgSVal(i); 732 SymbolRef ArgSym = ArgSVal.getAsSymbol(); 733 if (ArgSym) { 734 const ObjCObjectPointerType *const *TrackedArgType = 735 State->get<MostSpecializedTypeArgsMap>(ArgSym); 736 if (TrackedArgType && 737 ASTCtxt.canAssignObjCInterfaces(ArgObjectPtrType, *TrackedArgType)) { 738 ArgObjectPtrType = *TrackedArgType; 739 } 740 } 741 742 // Warn when argument is incompatible with the parameter. 743 if (!ASTCtxt.canAssignObjCInterfaces(ParamObjectPtrType, 744 ArgObjectPtrType)) { 745 static CheckerProgramPointTag Tag(this, "ArgTypeMismatch"); 746 ExplodedNode *N = C.addTransition(State, &Tag); 747 reportGenericsBug(ArgObjectPtrType, ParamObjectPtrType, N, Sym, C, Arg); 748 return; 749 } 750 } 751 } 752 753 /// This callback is used to infer the types for Class variables. This info is 754 /// used later to validate messages that sent to classes. Class variables are 755 /// initialized with by invoking the 'class' method on a class. 756 /// This method is also used to infer the type information for the return 757 /// types. 758 // TODO: right now it only tracks generic types. Extend this to track every 759 // type in the DynamicTypeMap and diagnose type errors! 760 void DynamicTypePropagation::checkPostObjCMessage(const ObjCMethodCall &M, 761 CheckerContext &C) const { 762 const ObjCMessageExpr *MessageExpr = M.getOriginExpr(); 763 764 SymbolRef RetSym = M.getReturnValue().getAsSymbol(); 765 if (!RetSym) 766 return; 767 768 Selector Sel = MessageExpr->getSelector(); 769 ProgramStateRef State = C.getState(); 770 // Inference for class variables. 771 // We are only interested in cases where the class method is invoked on a 772 // class. This method is provided by the runtime and available on all classes. 773 if (MessageExpr->getReceiverKind() == ObjCMessageExpr::Class && 774 Sel.getAsString() == "class") { 775 776 QualType ReceiverType = MessageExpr->getClassReceiver(); 777 const auto *ReceiverClassType = ReceiverType->getAs<ObjCObjectType>(); 778 QualType ReceiverClassPointerType = 779 C.getASTContext().getObjCObjectPointerType( 780 QualType(ReceiverClassType, 0)); 781 782 if (!ReceiverClassType->isSpecialized()) 783 return; 784 const auto *InferredType = 785 ReceiverClassPointerType->getAs<ObjCObjectPointerType>(); 786 assert(InferredType); 787 788 State = State->set<MostSpecializedTypeArgsMap>(RetSym, InferredType); 789 C.addTransition(State); 790 return; 791 } 792 793 // Tracking for return types. 794 SymbolRef RecSym = M.getReceiverSVal().getAsSymbol(); 795 if (!RecSym) 796 return; 797 798 const ObjCObjectPointerType *const *TrackedType = 799 State->get<MostSpecializedTypeArgsMap>(RecSym); 800 if (!TrackedType) 801 return; 802 803 ASTContext &ASTCtxt = C.getASTContext(); 804 const ObjCMethodDecl *Method = 805 findMethodDecl(MessageExpr, *TrackedType, ASTCtxt); 806 if (!Method) 807 return; 808 809 Optional<ArrayRef<QualType>> TypeArgs = 810 (*TrackedType)->getObjCSubstitutions(Method->getDeclContext()); 811 if (!TypeArgs) 812 return; 813 814 QualType ResultType = 815 getReturnTypeForMethod(Method, *TypeArgs, *TrackedType, ASTCtxt); 816 // The static type is the same as the deduced type. 817 if (ResultType.isNull()) 818 return; 819 820 const MemRegion *RetRegion = M.getReturnValue().getAsRegion(); 821 ExplodedNode *Pred = C.getPredecessor(); 822 // When there is an entry available for the return symbol in DynamicTypeMap, 823 // the call was inlined, and the information in the DynamicTypeMap is should 824 // be precise. 825 if (RetRegion && !State->get<DynamicTypeMap>(RetRegion)) { 826 // TODO: we have duplicated information in DynamicTypeMap and 827 // MostSpecializedTypeArgsMap. We should only store anything in the later if 828 // the stored data differs from the one stored in the former. 829 State = setDynamicTypeInfo(State, RetRegion, ResultType, 830 /*CanBeSubclass=*/true); 831 Pred = C.addTransition(State); 832 } 833 834 const auto *ResultPtrType = ResultType->getAs<ObjCObjectPointerType>(); 835 836 if (!ResultPtrType || ResultPtrType->isUnspecialized()) 837 return; 838 839 // When the result is a specialized type and it is not tracked yet, track it 840 // for the result symbol. 841 if (!State->get<MostSpecializedTypeArgsMap>(RetSym)) { 842 State = State->set<MostSpecializedTypeArgsMap>(RetSym, ResultPtrType); 843 C.addTransition(State, Pred); 844 } 845 } 846 847 void DynamicTypePropagation::reportGenericsBug( 848 const ObjCObjectPointerType *From, const ObjCObjectPointerType *To, 849 ExplodedNode *N, SymbolRef Sym, CheckerContext &C, 850 const Stmt *ReportedNode) const { 851 if (!CheckGenerics) 852 return; 853 854 initBugType(); 855 SmallString<192> Buf; 856 llvm::raw_svector_ostream OS(Buf); 857 OS << "Conversion from value of type '"; 858 QualType::print(From, Qualifiers(), OS, C.getLangOpts(), llvm::Twine()); 859 OS << "' to incompatible type '"; 860 QualType::print(To, Qualifiers(), OS, C.getLangOpts(), llvm::Twine()); 861 OS << "'"; 862 std::unique_ptr<BugReport> R( 863 new BugReport(*ObjCGenericsBugType, OS.str(), N)); 864 R->markInteresting(Sym); 865 R->addVisitor(llvm::make_unique<GenericsBugVisitor>(Sym)); 866 if (ReportedNode) 867 R->addRange(ReportedNode->getSourceRange()); 868 C.emitReport(std::move(R)); 869 } 870 871 PathDiagnosticPiece *DynamicTypePropagation::GenericsBugVisitor::VisitNode( 872 const ExplodedNode *N, const ExplodedNode *PrevN, BugReporterContext &BRC, 873 BugReport &BR) { 874 ProgramStateRef state = N->getState(); 875 ProgramStateRef statePrev = PrevN->getState(); 876 877 const ObjCObjectPointerType *const *TrackedType = 878 state->get<MostSpecializedTypeArgsMap>(Sym); 879 const ObjCObjectPointerType *const *TrackedTypePrev = 880 statePrev->get<MostSpecializedTypeArgsMap>(Sym); 881 if (!TrackedType) 882 return nullptr; 883 884 if (TrackedTypePrev && *TrackedTypePrev == *TrackedType) 885 return nullptr; 886 887 // Retrieve the associated statement. 888 const Stmt *S = nullptr; 889 ProgramPoint ProgLoc = N->getLocation(); 890 if (Optional<StmtPoint> SP = ProgLoc.getAs<StmtPoint>()) { 891 S = SP->getStmt(); 892 } 893 894 if (!S) 895 return nullptr; 896 897 const LangOptions &LangOpts = BRC.getASTContext().getLangOpts(); 898 899 SmallString<256> Buf; 900 llvm::raw_svector_ostream OS(Buf); 901 OS << "Type '"; 902 QualType::print(*TrackedType, Qualifiers(), OS, LangOpts, llvm::Twine()); 903 OS << "' is inferred from "; 904 905 if (const auto *ExplicitCast = dyn_cast<ExplicitCastExpr>(S)) { 906 OS << "explicit cast (from '"; 907 QualType::print(ExplicitCast->getSubExpr()->getType().getTypePtr(), 908 Qualifiers(), OS, LangOpts, llvm::Twine()); 909 OS << "' to '"; 910 QualType::print(ExplicitCast->getType().getTypePtr(), Qualifiers(), OS, 911 LangOpts, llvm::Twine()); 912 OS << "')"; 913 } else if (const auto *ImplicitCast = dyn_cast<ImplicitCastExpr>(S)) { 914 OS << "implicit cast (from '"; 915 QualType::print(ImplicitCast->getSubExpr()->getType().getTypePtr(), 916 Qualifiers(), OS, LangOpts, llvm::Twine()); 917 OS << "' to '"; 918 QualType::print(ImplicitCast->getType().getTypePtr(), Qualifiers(), OS, 919 LangOpts, llvm::Twine()); 920 OS << "')"; 921 } else { 922 OS << "this context"; 923 } 924 925 // Generate the extra diagnostic. 926 PathDiagnosticLocation Pos(S, BRC.getSourceManager(), 927 N->getLocationContext()); 928 return new PathDiagnosticEventPiece(Pos, OS.str(), true, nullptr); 929 } 930 931 /// Register checkers. 932 void ento::registerObjCGenericsChecker(CheckerManager &mgr) { 933 DynamicTypePropagation *checker = 934 mgr.registerChecker<DynamicTypePropagation>(); 935 checker->CheckGenerics = true; 936 } 937 938 void ento::registerDynamicTypePropagation(CheckerManager &mgr) { 939 mgr.registerChecker<DynamicTypePropagation>(); 940 } 941