DynamicTypePropagation.cpp revision 239462
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/StaticAnalyzer/Core/Checker.h" 16#include "clang/StaticAnalyzer/Core/CheckerManager.h" 17#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 18#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 19#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" 20#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 21#include "clang/Basic/Builtins.h" 22 23using namespace clang; 24using namespace ento; 25 26namespace { 27class 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; 37public: 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 44static 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 58void 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 class���s 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 87 const MemRegion *Target = Dtor->getCXXThisVal().getAsRegion(); 88 if (!Target) 89 return; 90 91 // FIXME: getRuntimeDefinition() can be expensive. It would be better to do 92 // this when we are entering the stack frame for the destructor. 93 const Decl *D = Dtor->getRuntimeDefinition().getDecl(); 94 if (!D) 95 return; 96 97 recordFixedType(Target, cast<CXXDestructorDecl>(D), C); 98 return; 99 } 100} 101 102void 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 SVal Result = C.getSVal(Call.getOriginExpr()); 109 const MemRegion *RetReg = Result.getAsRegion(); 110 if (!RetReg) 111 return; 112 113 ProgramStateRef State = C.getState(); 114 115 switch (Msg->getMethodFamily()) { 116 default: 117 break; 118 119 // We assume that the type of the object returned by alloc and new are the 120 // pointer to the object of the class specified in the receiver of the 121 // message. 122 case OMF_alloc: 123 case OMF_new: { 124 // Get the type of object that will get created. 125 const ObjCMessageExpr *MsgE = Msg->getOriginExpr(); 126 const ObjCObjectType *ObjTy = getObjectTypeForAllocAndNew(MsgE, C); 127 if (!ObjTy) 128 return; 129 QualType DynResTy = 130 C.getASTContext().getObjCObjectPointerType(QualType(ObjTy, 0)); 131 C.addTransition(State->setDynamicTypeInfo(RetReg, DynResTy, false)); 132 break; 133 } 134 case OMF_init: { 135 // Assume, the result of the init method has the same dynamic type as 136 // the receiver and propagate the dynamic type info. 137 const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion(); 138 if (!RecReg) 139 return; 140 DynamicTypeInfo RecDynType = State->getDynamicTypeInfo(RecReg); 141 C.addTransition(State->setDynamicTypeInfo(RetReg, RecDynType)); 142 break; 143 } 144 } 145 146 return; 147 } 148 149 if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) { 150 // We may need to undo the effects of our pre-call check. 151 switch (Ctor->getOriginExpr()->getConstructionKind()) { 152 case CXXConstructExpr::CK_Complete: 153 case CXXConstructExpr::CK_Delegating: 154 // No additional work necessary. 155 // Note: This will leave behind the actual type of the object for 156 // complete constructors, but arguably that's a good thing, since it 157 // means the dynamic type info will be correct even for objects 158 // constructed with operator new. 159 return; 160 case CXXConstructExpr::CK_NonVirtualBase: 161 case CXXConstructExpr::CK_VirtualBase: 162 if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion()) { 163 // We just finished a base constructor. Now we can use the subclass's 164 // type when resolving virtual calls. 165 const Decl *D = C.getLocationContext()->getDecl(); 166 recordFixedType(Target, cast<CXXConstructorDecl>(D), C); 167 } 168 return; 169 } 170 } 171} 172 173void DynamicTypePropagation::checkPostStmt(const ImplicitCastExpr *CastE, 174 CheckerContext &C) const { 175 // We only track dynamic type info for regions. 176 const MemRegion *ToR = C.getSVal(CastE).getAsRegion(); 177 if (!ToR) 178 return; 179 180 switch (CastE->getCastKind()) { 181 default: 182 break; 183 case CK_BitCast: 184 // Only handle ObjCObjects for now. 185 if (const Type *NewTy = getBetterObjCType(CastE, C)) 186 C.addTransition(C.getState()->setDynamicTypeInfo(ToR, QualType(NewTy,0))); 187 break; 188 } 189 return; 190} 191 192const ObjCObjectType * 193DynamicTypePropagation::getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE, 194 CheckerContext &C) const { 195 if (MsgE->getReceiverKind() == ObjCMessageExpr::Class) { 196 if (const ObjCObjectType *ObjTy 197 = MsgE->getClassReceiver()->getAs<ObjCObjectType>()) 198 return ObjTy; 199 } 200 201 if (MsgE->getReceiverKind() == ObjCMessageExpr::SuperClass) { 202 if (const ObjCObjectType *ObjTy 203 = MsgE->getSuperType()->getAs<ObjCObjectType>()) 204 return ObjTy; 205 } 206 207 const Expr *RecE = MsgE->getInstanceReceiver(); 208 if (!RecE) 209 return 0; 210 211 RecE= RecE->IgnoreParenImpCasts(); 212 if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(RecE)) { 213 const StackFrameContext *SFCtx = C.getStackFrame(); 214 // Are we calling [self alloc]? If this is self, get the type of the 215 // enclosing ObjC class. 216 if (DRE->getDecl() == SFCtx->getSelfDecl()) { 217 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(SFCtx->getDecl())) 218 if (const ObjCObjectType *ObjTy = 219 dyn_cast<ObjCObjectType>(MD->getClassInterface()->getTypeForDecl())) 220 return ObjTy; 221 } 222 } 223 return 0; 224} 225 226// Return a better dynamic type if one can be derived from the cast. 227// Compare the current dynamic type of the region and the new type to which we 228// are casting. If the new type is lower in the inheritance hierarchy, pick it. 229const ObjCObjectPointerType * 230DynamicTypePropagation::getBetterObjCType(const Expr *CastE, 231 CheckerContext &C) const { 232 const MemRegion *ToR = C.getSVal(CastE).getAsRegion(); 233 assert(ToR); 234 235 // Get the old and new types. 236 const ObjCObjectPointerType *NewTy = 237 CastE->getType()->getAs<ObjCObjectPointerType>(); 238 if (!NewTy) 239 return 0; 240 QualType OldDTy = C.getState()->getDynamicTypeInfo(ToR).getType(); 241 if (OldDTy.isNull()) { 242 return NewTy; 243 } 244 const ObjCObjectPointerType *OldTy = 245 OldDTy->getAs<ObjCObjectPointerType>(); 246 if (!OldTy) 247 return 0; 248 249 // Id the old type is 'id', the new one is more precise. 250 if (OldTy->isObjCIdType() && !NewTy->isObjCIdType()) 251 return NewTy; 252 253 // Return new if it's a subclass of old. 254 const ObjCInterfaceDecl *ToI = NewTy->getInterfaceDecl(); 255 const ObjCInterfaceDecl *FromI = OldTy->getInterfaceDecl(); 256 if (ToI && FromI && FromI->isSuperClassOf(ToI)) 257 return NewTy; 258 259 return 0; 260} 261 262void ento::registerDynamicTypePropagation(CheckerManager &mgr) { 263 mgr.registerChecker<DynamicTypePropagation>(); 264} 265