clang API Documentation
00001 //== DynamicTypePropagation.cpp -------------------------------- -*- C++ -*--=// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This checker defines the rules for dynamic type gathering and propagation. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 #include "ClangSACheckers.h" 00015 #include "clang/Basic/Builtins.h" 00016 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 00017 #include "clang/StaticAnalyzer/Core/Checker.h" 00018 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 00019 #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 00020 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 00021 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" 00022 00023 using namespace clang; 00024 using namespace ento; 00025 00026 namespace { 00027 class DynamicTypePropagation: 00028 public Checker< check::PreCall, 00029 check::PostCall, 00030 check::PostStmt<ImplicitCastExpr>, 00031 check::PostStmt<CXXNewExpr> > { 00032 const ObjCObjectType *getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE, 00033 CheckerContext &C) const; 00034 00035 /// \brief Return a better dynamic type if one can be derived from the cast. 00036 const ObjCObjectPointerType *getBetterObjCType(const Expr *CastE, 00037 CheckerContext &C) const; 00038 public: 00039 void checkPreCall(const CallEvent &Call, CheckerContext &C) const; 00040 void checkPostCall(const CallEvent &Call, CheckerContext &C) const; 00041 void checkPostStmt(const ImplicitCastExpr *CastE, CheckerContext &C) const; 00042 void checkPostStmt(const CXXNewExpr *NewE, CheckerContext &C) const; 00043 }; 00044 } 00045 00046 static void recordFixedType(const MemRegion *Region, const CXXMethodDecl *MD, 00047 CheckerContext &C) { 00048 assert(Region); 00049 assert(MD); 00050 00051 ASTContext &Ctx = C.getASTContext(); 00052 QualType Ty = Ctx.getPointerType(Ctx.getRecordType(MD->getParent())); 00053 00054 ProgramStateRef State = C.getState(); 00055 State = State->setDynamicTypeInfo(Region, Ty, /*CanBeSubclass=*/false); 00056 C.addTransition(State); 00057 return; 00058 } 00059 00060 void DynamicTypePropagation::checkPreCall(const CallEvent &Call, 00061 CheckerContext &C) const { 00062 if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) { 00063 // C++11 [class.cdtor]p4: When a virtual function is called directly or 00064 // indirectly from a constructor or from a destructor, including during 00065 // the construction or destruction of the class's non-static data members, 00066 // and the object to which the call applies is the object under 00067 // construction or destruction, the function called is the final overrider 00068 // in the constructor's or destructor's class and not one overriding it in 00069 // a more-derived class. 00070 00071 switch (Ctor->getOriginExpr()->getConstructionKind()) { 00072 case CXXConstructExpr::CK_Complete: 00073 case CXXConstructExpr::CK_Delegating: 00074 // No additional type info necessary. 00075 return; 00076 case CXXConstructExpr::CK_NonVirtualBase: 00077 case CXXConstructExpr::CK_VirtualBase: 00078 if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion()) 00079 recordFixedType(Target, Ctor->getDecl(), C); 00080 return; 00081 } 00082 00083 return; 00084 } 00085 00086 if (const CXXDestructorCall *Dtor = dyn_cast<CXXDestructorCall>(&Call)) { 00087 // C++11 [class.cdtor]p4 (see above) 00088 if (!Dtor->isBaseDestructor()) 00089 return; 00090 00091 const MemRegion *Target = Dtor->getCXXThisVal().getAsRegion(); 00092 if (!Target) 00093 return; 00094 00095 const Decl *D = Dtor->getDecl(); 00096 if (!D) 00097 return; 00098 00099 recordFixedType(Target, cast<CXXDestructorDecl>(D), C); 00100 return; 00101 } 00102 } 00103 00104 void DynamicTypePropagation::checkPostCall(const CallEvent &Call, 00105 CheckerContext &C) const { 00106 // We can obtain perfect type info for return values from some calls. 00107 if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(&Call)) { 00108 00109 // Get the returned value if it's a region. 00110 const MemRegion *RetReg = Call.getReturnValue().getAsRegion(); 00111 if (!RetReg) 00112 return; 00113 00114 ProgramStateRef State = C.getState(); 00115 const ObjCMethodDecl *D = Msg->getDecl(); 00116 00117 if (D && D->hasRelatedResultType()) { 00118 switch (Msg->getMethodFamily()) { 00119 default: 00120 break; 00121 00122 // We assume that the type of the object returned by alloc and new are the 00123 // pointer to the object of the class specified in the receiver of the 00124 // message. 00125 case OMF_alloc: 00126 case OMF_new: { 00127 // Get the type of object that will get created. 00128 const ObjCMessageExpr *MsgE = Msg->getOriginExpr(); 00129 const ObjCObjectType *ObjTy = getObjectTypeForAllocAndNew(MsgE, C); 00130 if (!ObjTy) 00131 return; 00132 QualType DynResTy = 00133 C.getASTContext().getObjCObjectPointerType(QualType(ObjTy, 0)); 00134 C.addTransition(State->setDynamicTypeInfo(RetReg, DynResTy, false)); 00135 break; 00136 } 00137 case OMF_init: { 00138 // Assume, the result of the init method has the same dynamic type as 00139 // the receiver and propagate the dynamic type info. 00140 const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion(); 00141 if (!RecReg) 00142 return; 00143 DynamicTypeInfo RecDynType = State->getDynamicTypeInfo(RecReg); 00144 C.addTransition(State->setDynamicTypeInfo(RetReg, RecDynType)); 00145 break; 00146 } 00147 } 00148 } 00149 return; 00150 } 00151 00152 if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) { 00153 // We may need to undo the effects of our pre-call check. 00154 switch (Ctor->getOriginExpr()->getConstructionKind()) { 00155 case CXXConstructExpr::CK_Complete: 00156 case CXXConstructExpr::CK_Delegating: 00157 // No additional work necessary. 00158 // Note: This will leave behind the actual type of the object for 00159 // complete constructors, but arguably that's a good thing, since it 00160 // means the dynamic type info will be correct even for objects 00161 // constructed with operator new. 00162 return; 00163 case CXXConstructExpr::CK_NonVirtualBase: 00164 case CXXConstructExpr::CK_VirtualBase: 00165 if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion()) { 00166 // We just finished a base constructor. Now we can use the subclass's 00167 // type when resolving virtual calls. 00168 const Decl *D = C.getLocationContext()->getDecl(); 00169 recordFixedType(Target, cast<CXXConstructorDecl>(D), C); 00170 } 00171 return; 00172 } 00173 } 00174 } 00175 00176 void DynamicTypePropagation::checkPostStmt(const ImplicitCastExpr *CastE, 00177 CheckerContext &C) const { 00178 // We only track dynamic type info for regions. 00179 const MemRegion *ToR = C.getSVal(CastE).getAsRegion(); 00180 if (!ToR) 00181 return; 00182 00183 switch (CastE->getCastKind()) { 00184 default: 00185 break; 00186 case CK_BitCast: 00187 // Only handle ObjCObjects for now. 00188 if (const Type *NewTy = getBetterObjCType(CastE, C)) 00189 C.addTransition(C.getState()->setDynamicTypeInfo(ToR, QualType(NewTy,0))); 00190 break; 00191 } 00192 return; 00193 } 00194 00195 void DynamicTypePropagation::checkPostStmt(const CXXNewExpr *NewE, 00196 CheckerContext &C) const { 00197 if (NewE->isArray()) 00198 return; 00199 00200 // We only track dynamic type info for regions. 00201 const MemRegion *MR = C.getSVal(NewE).getAsRegion(); 00202 if (!MR) 00203 return; 00204 00205 C.addTransition(C.getState()->setDynamicTypeInfo(MR, NewE->getType(), 00206 /*CanBeSubclass=*/false)); 00207 } 00208 00209 const ObjCObjectType * 00210 DynamicTypePropagation::getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE, 00211 CheckerContext &C) const { 00212 if (MsgE->getReceiverKind() == ObjCMessageExpr::Class) { 00213 if (const ObjCObjectType *ObjTy 00214 = MsgE->getClassReceiver()->getAs<ObjCObjectType>()) 00215 return ObjTy; 00216 } 00217 00218 if (MsgE->getReceiverKind() == ObjCMessageExpr::SuperClass) { 00219 if (const ObjCObjectType *ObjTy 00220 = MsgE->getSuperType()->getAs<ObjCObjectType>()) 00221 return ObjTy; 00222 } 00223 00224 const Expr *RecE = MsgE->getInstanceReceiver(); 00225 if (!RecE) 00226 return nullptr; 00227 00228 RecE= RecE->IgnoreParenImpCasts(); 00229 if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(RecE)) { 00230 const StackFrameContext *SFCtx = C.getStackFrame(); 00231 // Are we calling [self alloc]? If this is self, get the type of the 00232 // enclosing ObjC class. 00233 if (DRE->getDecl() == SFCtx->getSelfDecl()) { 00234 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(SFCtx->getDecl())) 00235 if (const ObjCObjectType *ObjTy = 00236 dyn_cast<ObjCObjectType>(MD->getClassInterface()->getTypeForDecl())) 00237 return ObjTy; 00238 } 00239 } 00240 return nullptr; 00241 } 00242 00243 // Return a better dynamic type if one can be derived from the cast. 00244 // Compare the current dynamic type of the region and the new type to which we 00245 // are casting. If the new type is lower in the inheritance hierarchy, pick it. 00246 const ObjCObjectPointerType * 00247 DynamicTypePropagation::getBetterObjCType(const Expr *CastE, 00248 CheckerContext &C) const { 00249 const MemRegion *ToR = C.getSVal(CastE).getAsRegion(); 00250 assert(ToR); 00251 00252 // Get the old and new types. 00253 const ObjCObjectPointerType *NewTy = 00254 CastE->getType()->getAs<ObjCObjectPointerType>(); 00255 if (!NewTy) 00256 return nullptr; 00257 QualType OldDTy = C.getState()->getDynamicTypeInfo(ToR).getType(); 00258 if (OldDTy.isNull()) { 00259 return NewTy; 00260 } 00261 const ObjCObjectPointerType *OldTy = 00262 OldDTy->getAs<ObjCObjectPointerType>(); 00263 if (!OldTy) 00264 return nullptr; 00265 00266 // Id the old type is 'id', the new one is more precise. 00267 if (OldTy->isObjCIdType() && !NewTy->isObjCIdType()) 00268 return NewTy; 00269 00270 // Return new if it's a subclass of old. 00271 const ObjCInterfaceDecl *ToI = NewTy->getInterfaceDecl(); 00272 const ObjCInterfaceDecl *FromI = OldTy->getInterfaceDecl(); 00273 if (ToI && FromI && FromI->isSuperClassOf(ToI)) 00274 return NewTy; 00275 00276 return nullptr; 00277 } 00278 00279 void ento::registerDynamicTypePropagation(CheckerManager &mgr) { 00280 mgr.registerChecker<DynamicTypePropagation>(); 00281 }