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 checker defines the rules for dynamic type gathering and propagation. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "ClangSACheckers.h" 15 #include "clang/Basic/Builtins.h" 16 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 17 #include "clang/StaticAnalyzer/Core/Checker.h" 18 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 19 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 20 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 21 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" 22 23 using namespace clang; 24 using namespace ento; 25 26 namespace { 27 class DynamicTypePropagation: 28 public Checker< check::PreCall, 29 check::PostCall, 30 check::PostStmt<ImplicitCastExpr> > { 31 const ObjCObjectType *getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE, 32 CheckerContext &C) const; 33 34 /// \brief Return a better dynamic type if one can be derived from the cast. 35 const ObjCObjectPointerType *getBetterObjCType(const Expr *CastE, 36 CheckerContext &C) const; 37 public: 38 void checkPreCall(const CallEvent &Call, CheckerContext &C) const; 39 void checkPostCall(const CallEvent &Call, CheckerContext &C) const; 40 void checkPostStmt(const ImplicitCastExpr *CastE, CheckerContext &C) const; 41 }; 42 } 43 44 static void recordFixedType(const MemRegion *Region, const CXXMethodDecl *MD, 45 CheckerContext &C) { 46 assert(Region); 47 assert(MD); 48 49 ASTContext &Ctx = C.getASTContext(); 50 QualType Ty = Ctx.getPointerType(Ctx.getRecordType(MD->getParent())); 51 52 ProgramStateRef State = C.getState(); 53 State = State->setDynamicTypeInfo(Region, Ty, /*CanBeSubclass=*/false); 54 C.addTransition(State); 55 return; 56 } 57 58 void DynamicTypePropagation::checkPreCall(const CallEvent &Call, 59 CheckerContext &C) const { 60 if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) { 61 // C++11 [class.cdtor]p4: When a virtual function is called directly or 62 // indirectly from a constructor or from a destructor, including during 63 // the construction or destruction of the classs non-static data members, 64 // and the object to which the call applies is the object under 65 // construction or destruction, the function called is the final overrider 66 // in the constructor's or destructor's class and not one overriding it in 67 // a more-derived class. 68 69 switch (Ctor->getOriginExpr()->getConstructionKind()) { 70 case CXXConstructExpr::CK_Complete: 71 case CXXConstructExpr::CK_Delegating: 72 // No additional type info necessary. 73 return; 74 case CXXConstructExpr::CK_NonVirtualBase: 75 case CXXConstructExpr::CK_VirtualBase: 76 if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion()) 77 recordFixedType(Target, Ctor->getDecl(), C); 78 return; 79 } 80 81 return; 82 } 83 84 if (const CXXDestructorCall *Dtor = dyn_cast<CXXDestructorCall>(&Call)) { 85 // C++11 [class.cdtor]p4 (see above) 86 if (!Dtor->isBaseDestructor()) 87 return; 88 89 const MemRegion *Target = Dtor->getCXXThisVal().getAsRegion(); 90 if (!Target) 91 return; 92 93 const Decl *D = Dtor->getDecl(); 94 if (!D) 95 return; 96 97 recordFixedType(Target, cast<CXXDestructorDecl>(D), C); 98 return; 99 } 100 } 101 102 void DynamicTypePropagation::checkPostCall(const CallEvent &Call, 103 CheckerContext &C) const { 104 // We can obtain perfect type info for return values from some calls. 105 if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(&Call)) { 106 107 // Get the returned value if it's a region. 108 const MemRegion *RetReg = Call.getReturnValue().getAsRegion(); 109 if (!RetReg) 110 return; 111 112 ProgramStateRef State = C.getState(); 113 const ObjCMethodDecl *D = Msg->getDecl(); 114 115 if (D && D->hasRelatedResultType()) { 116 switch (Msg->getMethodFamily()) { 117 default: 118 break; 119 120 // We assume that the type of the object returned by alloc and new are the 121 // pointer to the object of the class specified in the receiver of the 122 // message. 123 case OMF_alloc: 124 case OMF_new: { 125 // Get the type of object that will get created. 126 const ObjCMessageExpr *MsgE = Msg->getOriginExpr(); 127 const ObjCObjectType *ObjTy = getObjectTypeForAllocAndNew(MsgE, C); 128 if (!ObjTy) 129 return; 130 QualType DynResTy = 131 C.getASTContext().getObjCObjectPointerType(QualType(ObjTy, 0)); 132 C.addTransition(State->setDynamicTypeInfo(RetReg, DynResTy, false)); 133 break; 134 } 135 case OMF_init: { 136 // Assume, the result of the init method has the same dynamic type as 137 // the receiver and propagate the dynamic type info. 138 const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion(); 139 if (!RecReg) 140 return; 141 DynamicTypeInfo RecDynType = State->getDynamicTypeInfo(RecReg); 142 C.addTransition(State->setDynamicTypeInfo(RetReg, RecDynType)); 143 break; 144 } 145 } 146 } 147 return; 148 } 149 150 if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) { 151 // We may need to undo the effects of our pre-call check. 152 switch (Ctor->getOriginExpr()->getConstructionKind()) { 153 case CXXConstructExpr::CK_Complete: 154 case CXXConstructExpr::CK_Delegating: 155 // No additional work necessary. 156 // Note: This will leave behind the actual type of the object for 157 // complete constructors, but arguably that's a good thing, since it 158 // means the dynamic type info will be correct even for objects 159 // constructed with operator new. 160 return; 161 case CXXConstructExpr::CK_NonVirtualBase: 162 case CXXConstructExpr::CK_VirtualBase: 163 if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion()) { 164 // We just finished a base constructor. Now we can use the subclass's 165 // type when resolving virtual calls. 166 const Decl *D = C.getLocationContext()->getDecl(); 167 recordFixedType(Target, cast<CXXConstructorDecl>(D), C); 168 } 169 return; 170 } 171 } 172 } 173 174 void DynamicTypePropagation::checkPostStmt(const ImplicitCastExpr *CastE, 175 CheckerContext &C) const { 176 // We only track dynamic type info for regions. 177 const MemRegion *ToR = C.getSVal(CastE).getAsRegion(); 178 if (!ToR) 179 return; 180 181 switch (CastE->getCastKind()) { 182 default: 183 break; 184 case CK_BitCast: 185 // Only handle ObjCObjects for now. 186 if (const Type *NewTy = getBetterObjCType(CastE, C)) 187 C.addTransition(C.getState()->setDynamicTypeInfo(ToR, QualType(NewTy,0))); 188 break; 189 } 190 return; 191 } 192 193 const ObjCObjectType * 194 DynamicTypePropagation::getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE, 195 CheckerContext &C) const { 196 if (MsgE->getReceiverKind() == ObjCMessageExpr::Class) { 197 if (const ObjCObjectType *ObjTy 198 = MsgE->getClassReceiver()->getAs<ObjCObjectType>()) 199 return ObjTy; 200 } 201 202 if (MsgE->getReceiverKind() == ObjCMessageExpr::SuperClass) { 203 if (const ObjCObjectType *ObjTy 204 = MsgE->getSuperType()->getAs<ObjCObjectType>()) 205 return ObjTy; 206 } 207 208 const Expr *RecE = MsgE->getInstanceReceiver(); 209 if (!RecE) 210 return 0; 211 212 RecE= RecE->IgnoreParenImpCasts(); 213 if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(RecE)) { 214 const StackFrameContext *SFCtx = C.getStackFrame(); 215 // Are we calling [self alloc]? If this is self, get the type of the 216 // enclosing ObjC class. 217 if (DRE->getDecl() == SFCtx->getSelfDecl()) { 218 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(SFCtx->getDecl())) 219 if (const ObjCObjectType *ObjTy = 220 dyn_cast<ObjCObjectType>(MD->getClassInterface()->getTypeForDecl())) 221 return ObjTy; 222 } 223 } 224 return 0; 225 } 226 227 // Return a better dynamic type if one can be derived from the cast. 228 // Compare the current dynamic type of the region and the new type to which we 229 // are casting. If the new type is lower in the inheritance hierarchy, pick it. 230 const ObjCObjectPointerType * 231 DynamicTypePropagation::getBetterObjCType(const Expr *CastE, 232 CheckerContext &C) const { 233 const MemRegion *ToR = C.getSVal(CastE).getAsRegion(); 234 assert(ToR); 235 236 // Get the old and new types. 237 const ObjCObjectPointerType *NewTy = 238 CastE->getType()->getAs<ObjCObjectPointerType>(); 239 if (!NewTy) 240 return 0; 241 QualType OldDTy = C.getState()->getDynamicTypeInfo(ToR).getType(); 242 if (OldDTy.isNull()) { 243 return NewTy; 244 } 245 const ObjCObjectPointerType *OldTy = 246 OldDTy->getAs<ObjCObjectPointerType>(); 247 if (!OldTy) 248 return 0; 249 250 // Id the old type is 'id', the new one is more precise. 251 if (OldTy->isObjCIdType() && !NewTy->isObjCIdType()) 252 return NewTy; 253 254 // Return new if it's a subclass of old. 255 const ObjCInterfaceDecl *ToI = NewTy->getInterfaceDecl(); 256 const ObjCInterfaceDecl *FromI = OldTy->getInterfaceDecl(); 257 if (ToI && FromI && FromI->isSuperClassOf(ToI)) 258 return NewTy; 259 260 return 0; 261 } 262 263 void ento::registerDynamicTypePropagation(CheckerManager &mgr) { 264 mgr.registerChecker<DynamicTypePropagation>(); 265 } 266