DynamicTypePropagation.cpp revision d4fe57f7f7a8793227effc1274d70ec44cee9a4f
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::PostCall, 29 check::PostStmt<ImplicitCastExpr> > { 30 const ObjCObjectType *getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE, 31 CheckerContext &C) const; 32 33 /// \brief Return a better dynamic type if one can be derived from the cast. 34 const ObjCObjectPointerType *getBetterObjCType(const Expr *CastE, 35 CheckerContext &C) const; 36public: 37 void checkPostCall(const CallEvent &Call, CheckerContext &C) const; 38 void checkPostStmt(const ImplicitCastExpr *CastE, CheckerContext &C) const; 39}; 40} 41 42void DynamicTypePropagation::checkPostCall(const CallEvent &Call, 43 CheckerContext &C) const { 44 // We can obtain perfect type info for return values from some calls. 45 if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(&Call)) { 46 47 // Get the returned value if it's a region. 48 SVal Result = C.getSVal(Call.getOriginExpr()); 49 const MemRegion *RetReg = Result.getAsRegion(); 50 if (!RetReg) 51 return; 52 53 ProgramStateRef State = C.getState(); 54 55 switch (Msg->getMethodFamily()) { 56 default: 57 break; 58 59 // We assume that the type of the object returned by alloc and new are the 60 // pointer to the object of the class specified in the receiver of the 61 // message. 62 case OMF_alloc: 63 case OMF_new: { 64 // Get the type of object that will get created. 65 const ObjCMessageExpr *MsgE = Msg->getOriginExpr(); 66 const ObjCObjectType *ObjTy = getObjectTypeForAllocAndNew(MsgE, C); 67 if (!ObjTy) 68 return; 69 QualType DynResTy = 70 C.getASTContext().getObjCObjectPointerType(QualType(ObjTy, 0)); 71 C.addTransition(State->setDynamicTypeInfo(RetReg, DynResTy)); 72 break; 73 } 74 case OMF_init: { 75 // Assume, the result of the init method has the same dynamic type as 76 // the receiver and propagate the dynamic type info. 77 const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion(); 78 if (!RecReg) 79 return; 80 DynamicTypeInfo RecDynType = State->getDynamicTypeInfo(RecReg); 81 C.addTransition(State->setDynamicTypeInfo(RetReg, RecDynType)); 82 break; 83 } 84 } 85 } 86} 87 88void DynamicTypePropagation::checkPostStmt(const ImplicitCastExpr *CastE, 89 CheckerContext &C) const { 90 // We only track dynamic type info for regions. 91 const MemRegion *ToR = C.getSVal(CastE).getAsRegion(); 92 if (!ToR) 93 return; 94 95 switch (CastE->getCastKind()) { 96 default: 97 break; 98 case CK_BitCast: 99 // Only handle ObjCObjects for now. 100 if (const Type *NewTy = getBetterObjCType(CastE, C)) 101 C.addTransition(C.getState()->setDynamicTypeInfo(ToR, QualType(NewTy,0))); 102 break; 103 } 104 return; 105} 106 107const ObjCObjectType * 108DynamicTypePropagation::getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE, 109 CheckerContext &C) const { 110 if (MsgE->getReceiverKind() == ObjCMessageExpr::Class) { 111 if (const ObjCObjectType *ObjTy 112 = MsgE->getClassReceiver()->getAs<ObjCObjectType>()) 113 return ObjTy; 114 } 115 116 if (MsgE->getReceiverKind() == ObjCMessageExpr::SuperClass) { 117 if (const ObjCObjectType *ObjTy 118 = MsgE->getSuperType()->getAs<ObjCObjectType>()) 119 return ObjTy; 120 } 121 122 const Expr *RecE = MsgE->getInstanceReceiver(); 123 if (!RecE) 124 return 0; 125 126 RecE= RecE->IgnoreParenImpCasts(); 127 if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(RecE)) { 128 const StackFrameContext *SFCtx = C.getCurrentStackFrame(); 129 // Are we calling [self alloc]? If this is self, get the type of the 130 // enclosing ObjC class. 131 if (DRE->getDecl() == SFCtx->getSelfDecl()) { 132 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(SFCtx->getDecl())) 133 if (const ObjCObjectType *ObjTy = 134 dyn_cast<ObjCObjectType>(MD->getClassInterface()->getTypeForDecl())) 135 return ObjTy; 136 } 137 } 138 return 0; 139} 140 141// Return a better dynamic type if one can be derived from the cast. 142// Compare the current dynamic type of the region and the new type to which we 143// are casting. If the new type is lower in the inheritance hierarchy, pick it. 144const ObjCObjectPointerType * 145DynamicTypePropagation::getBetterObjCType(const Expr *CastE, 146 CheckerContext &C) const { 147 const MemRegion *ToR = C.getSVal(CastE).getAsRegion(); 148 assert(ToR); 149 150 // Get the old and new types. 151 const ObjCObjectPointerType *NewTy = 152 CastE->getType()->getAs<ObjCObjectPointerType>(); 153 if (!NewTy) 154 return 0; 155 QualType OldDTy = C.getState()->getDynamicTypeInfo(ToR).getType(); 156 if (OldDTy.isNull()) { 157 return NewTy; 158 } 159 const ObjCObjectPointerType *OldTy = 160 OldDTy->getAs<ObjCObjectPointerType>(); 161 if (!OldTy) 162 return 0; 163 164 // Id the old type is 'id', the new one is more precise. 165 if (OldTy->isObjCIdType() && !NewTy->isObjCIdType()) 166 return NewTy; 167 168 // Return new if it's a subclass of old. 169 const ObjCInterfaceDecl *ToI = NewTy->getInterfaceDecl(); 170 const ObjCInterfaceDecl *FromI = OldTy->getInterfaceDecl(); 171 if (ToI && FromI && FromI->isSuperClassOf(ToI)) 172 return NewTy; 173 174 return 0; 175} 176 177void ento::registerDynamicTypePropagation(CheckerManager &mgr) { 178 mgr.registerChecker<DynamicTypePropagation>(); 179} 180