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