1263509Sdim//== DynamicTypePropagation.cpp -------------------------------- -*- C++ -*--=// 2239313Sdim// 3239313Sdim// The LLVM Compiler Infrastructure 4239313Sdim// 5239313Sdim// This file is distributed under the University of Illinois Open Source 6239313Sdim// License. See LICENSE.TXT for details. 7239313Sdim// 8239313Sdim//===----------------------------------------------------------------------===// 9239313Sdim// 10239313Sdim// This checker defines the rules for dynamic type gathering and propagation. 11239313Sdim// 12239313Sdim//===----------------------------------------------------------------------===// 13239313Sdim 14239313Sdim#include "ClangSACheckers.h" 15252723Sdim#include "clang/Basic/Builtins.h" 16252723Sdim#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 17239313Sdim#include "clang/StaticAnalyzer/Core/Checker.h" 18239313Sdim#include "clang/StaticAnalyzer/Core/CheckerManager.h" 19239313Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 20239313Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 21239313Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" 22239313Sdim 23239313Sdimusing namespace clang; 24239313Sdimusing namespace ento; 25239313Sdim 26239313Sdimnamespace { 27239313Sdimclass DynamicTypePropagation: 28239462Sdim public Checker< check::PreCall, 29239462Sdim check::PostCall, 30252723Sdim check::PostStmt<ImplicitCastExpr>, 31252723Sdim check::PostStmt<CXXNewExpr> > { 32239313Sdim const ObjCObjectType *getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE, 33239313Sdim CheckerContext &C) const; 34239313Sdim 35239313Sdim /// \brief Return a better dynamic type if one can be derived from the cast. 36239313Sdim const ObjCObjectPointerType *getBetterObjCType(const Expr *CastE, 37239313Sdim CheckerContext &C) const; 38239313Sdimpublic: 39239462Sdim void checkPreCall(const CallEvent &Call, CheckerContext &C) const; 40239313Sdim void checkPostCall(const CallEvent &Call, CheckerContext &C) const; 41239313Sdim void checkPostStmt(const ImplicitCastExpr *CastE, CheckerContext &C) const; 42252723Sdim void checkPostStmt(const CXXNewExpr *NewE, CheckerContext &C) const; 43239313Sdim}; 44239313Sdim} 45239313Sdim 46239462Sdimstatic void recordFixedType(const MemRegion *Region, const CXXMethodDecl *MD, 47239462Sdim CheckerContext &C) { 48239462Sdim assert(Region); 49239462Sdim assert(MD); 50239462Sdim 51239462Sdim ASTContext &Ctx = C.getASTContext(); 52239462Sdim QualType Ty = Ctx.getPointerType(Ctx.getRecordType(MD->getParent())); 53239462Sdim 54239462Sdim ProgramStateRef State = C.getState(); 55239462Sdim State = State->setDynamicTypeInfo(Region, Ty, /*CanBeSubclass=*/false); 56239462Sdim C.addTransition(State); 57239462Sdim return; 58239462Sdim} 59239462Sdim 60239462Sdimvoid DynamicTypePropagation::checkPreCall(const CallEvent &Call, 61239462Sdim CheckerContext &C) const { 62239462Sdim if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) { 63239462Sdim // C++11 [class.cdtor]p4: When a virtual function is called directly or 64239462Sdim // indirectly from a constructor or from a destructor, including during 65263509Sdim // the construction or destruction of the class's non-static data members, 66239462Sdim // and the object to which the call applies is the object under 67239462Sdim // construction or destruction, the function called is the final overrider 68239462Sdim // in the constructor's or destructor's class and not one overriding it in 69239462Sdim // a more-derived class. 70239462Sdim 71239462Sdim switch (Ctor->getOriginExpr()->getConstructionKind()) { 72239462Sdim case CXXConstructExpr::CK_Complete: 73239462Sdim case CXXConstructExpr::CK_Delegating: 74239462Sdim // No additional type info necessary. 75239462Sdim return; 76239462Sdim case CXXConstructExpr::CK_NonVirtualBase: 77239462Sdim case CXXConstructExpr::CK_VirtualBase: 78239462Sdim if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion()) 79239462Sdim recordFixedType(Target, Ctor->getDecl(), C); 80239462Sdim return; 81239462Sdim } 82239462Sdim 83239462Sdim return; 84239462Sdim } 85239462Sdim 86239462Sdim if (const CXXDestructorCall *Dtor = dyn_cast<CXXDestructorCall>(&Call)) { 87239462Sdim // C++11 [class.cdtor]p4 (see above) 88245431Sdim if (!Dtor->isBaseDestructor()) 89245431Sdim return; 90239462Sdim 91239462Sdim const MemRegion *Target = Dtor->getCXXThisVal().getAsRegion(); 92239462Sdim if (!Target) 93239462Sdim return; 94239462Sdim 95245431Sdim const Decl *D = Dtor->getDecl(); 96239462Sdim if (!D) 97239462Sdim return; 98239462Sdim 99239462Sdim recordFixedType(Target, cast<CXXDestructorDecl>(D), C); 100239462Sdim return; 101239462Sdim } 102239462Sdim} 103239462Sdim 104239313Sdimvoid DynamicTypePropagation::checkPostCall(const CallEvent &Call, 105239313Sdim CheckerContext &C) const { 106239313Sdim // We can obtain perfect type info for return values from some calls. 107239313Sdim if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(&Call)) { 108239313Sdim 109239313Sdim // Get the returned value if it's a region. 110245431Sdim const MemRegion *RetReg = Call.getReturnValue().getAsRegion(); 111239313Sdim if (!RetReg) 112239313Sdim return; 113239313Sdim 114239313Sdim ProgramStateRef State = C.getState(); 115252723Sdim const ObjCMethodDecl *D = Msg->getDecl(); 116252723Sdim 117252723Sdim if (D && D->hasRelatedResultType()) { 118252723Sdim switch (Msg->getMethodFamily()) { 119252723Sdim default: 120252723Sdim break; 121239313Sdim 122252723Sdim // We assume that the type of the object returned by alloc and new are the 123252723Sdim // pointer to the object of the class specified in the receiver of the 124252723Sdim // message. 125252723Sdim case OMF_alloc: 126252723Sdim case OMF_new: { 127252723Sdim // Get the type of object that will get created. 128252723Sdim const ObjCMessageExpr *MsgE = Msg->getOriginExpr(); 129252723Sdim const ObjCObjectType *ObjTy = getObjectTypeForAllocAndNew(MsgE, C); 130252723Sdim if (!ObjTy) 131252723Sdim return; 132252723Sdim QualType DynResTy = 133239313Sdim C.getASTContext().getObjCObjectPointerType(QualType(ObjTy, 0)); 134252723Sdim C.addTransition(State->setDynamicTypeInfo(RetReg, DynResTy, false)); 135252723Sdim break; 136252723Sdim } 137252723Sdim case OMF_init: { 138252723Sdim // Assume, the result of the init method has the same dynamic type as 139252723Sdim // the receiver and propagate the dynamic type info. 140252723Sdim const MemRegion *RecReg = Msg->getReceiverSVal().getAsRegion(); 141252723Sdim if (!RecReg) 142252723Sdim return; 143252723Sdim DynamicTypeInfo RecDynType = State->getDynamicTypeInfo(RecReg); 144252723Sdim C.addTransition(State->setDynamicTypeInfo(RetReg, RecDynType)); 145252723Sdim break; 146252723Sdim } 147252723Sdim } 148239313Sdim } 149239462Sdim return; 150239313Sdim } 151239462Sdim 152239462Sdim if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) { 153239462Sdim // We may need to undo the effects of our pre-call check. 154239462Sdim switch (Ctor->getOriginExpr()->getConstructionKind()) { 155239462Sdim case CXXConstructExpr::CK_Complete: 156239462Sdim case CXXConstructExpr::CK_Delegating: 157239462Sdim // No additional work necessary. 158239462Sdim // Note: This will leave behind the actual type of the object for 159239462Sdim // complete constructors, but arguably that's a good thing, since it 160239462Sdim // means the dynamic type info will be correct even for objects 161239462Sdim // constructed with operator new. 162239462Sdim return; 163239462Sdim case CXXConstructExpr::CK_NonVirtualBase: 164239462Sdim case CXXConstructExpr::CK_VirtualBase: 165239462Sdim if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion()) { 166239462Sdim // We just finished a base constructor. Now we can use the subclass's 167239462Sdim // type when resolving virtual calls. 168239462Sdim const Decl *D = C.getLocationContext()->getDecl(); 169239462Sdim recordFixedType(Target, cast<CXXConstructorDecl>(D), C); 170239462Sdim } 171239462Sdim return; 172239462Sdim } 173239462Sdim } 174239313Sdim} 175239313Sdim 176239313Sdimvoid DynamicTypePropagation::checkPostStmt(const ImplicitCastExpr *CastE, 177239313Sdim CheckerContext &C) const { 178239313Sdim // We only track dynamic type info for regions. 179239313Sdim const MemRegion *ToR = C.getSVal(CastE).getAsRegion(); 180239313Sdim if (!ToR) 181239313Sdim return; 182239313Sdim 183239313Sdim switch (CastE->getCastKind()) { 184239313Sdim default: 185239313Sdim break; 186239313Sdim case CK_BitCast: 187239313Sdim // Only handle ObjCObjects for now. 188239313Sdim if (const Type *NewTy = getBetterObjCType(CastE, C)) 189239313Sdim C.addTransition(C.getState()->setDynamicTypeInfo(ToR, QualType(NewTy,0))); 190239313Sdim break; 191239313Sdim } 192239313Sdim return; 193239313Sdim} 194239313Sdim 195252723Sdimvoid DynamicTypePropagation::checkPostStmt(const CXXNewExpr *NewE, 196252723Sdim CheckerContext &C) const { 197252723Sdim if (NewE->isArray()) 198252723Sdim return; 199252723Sdim 200252723Sdim // We only track dynamic type info for regions. 201252723Sdim const MemRegion *MR = C.getSVal(NewE).getAsRegion(); 202252723Sdim if (!MR) 203252723Sdim return; 204252723Sdim 205252723Sdim C.addTransition(C.getState()->setDynamicTypeInfo(MR, NewE->getType(), 206252723Sdim /*CanBeSubclass=*/false)); 207252723Sdim} 208252723Sdim 209239313Sdimconst ObjCObjectType * 210239313SdimDynamicTypePropagation::getObjectTypeForAllocAndNew(const ObjCMessageExpr *MsgE, 211239313Sdim CheckerContext &C) const { 212239313Sdim if (MsgE->getReceiverKind() == ObjCMessageExpr::Class) { 213239313Sdim if (const ObjCObjectType *ObjTy 214239313Sdim = MsgE->getClassReceiver()->getAs<ObjCObjectType>()) 215239313Sdim return ObjTy; 216239313Sdim } 217239313Sdim 218239313Sdim if (MsgE->getReceiverKind() == ObjCMessageExpr::SuperClass) { 219239313Sdim if (const ObjCObjectType *ObjTy 220239313Sdim = MsgE->getSuperType()->getAs<ObjCObjectType>()) 221239313Sdim return ObjTy; 222239313Sdim } 223239313Sdim 224239313Sdim const Expr *RecE = MsgE->getInstanceReceiver(); 225239313Sdim if (!RecE) 226239313Sdim return 0; 227239313Sdim 228239313Sdim RecE= RecE->IgnoreParenImpCasts(); 229239313Sdim if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(RecE)) { 230239313Sdim const StackFrameContext *SFCtx = C.getStackFrame(); 231239313Sdim // Are we calling [self alloc]? If this is self, get the type of the 232239313Sdim // enclosing ObjC class. 233239313Sdim if (DRE->getDecl() == SFCtx->getSelfDecl()) { 234239313Sdim if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(SFCtx->getDecl())) 235239313Sdim if (const ObjCObjectType *ObjTy = 236239313Sdim dyn_cast<ObjCObjectType>(MD->getClassInterface()->getTypeForDecl())) 237239313Sdim return ObjTy; 238239313Sdim } 239239313Sdim } 240239313Sdim return 0; 241239313Sdim} 242239313Sdim 243239313Sdim// Return a better dynamic type if one can be derived from the cast. 244239313Sdim// Compare the current dynamic type of the region and the new type to which we 245239313Sdim// are casting. If the new type is lower in the inheritance hierarchy, pick it. 246239313Sdimconst ObjCObjectPointerType * 247239313SdimDynamicTypePropagation::getBetterObjCType(const Expr *CastE, 248239313Sdim CheckerContext &C) const { 249239313Sdim const MemRegion *ToR = C.getSVal(CastE).getAsRegion(); 250239313Sdim assert(ToR); 251239313Sdim 252239313Sdim // Get the old and new types. 253239313Sdim const ObjCObjectPointerType *NewTy = 254239313Sdim CastE->getType()->getAs<ObjCObjectPointerType>(); 255239313Sdim if (!NewTy) 256239313Sdim return 0; 257239313Sdim QualType OldDTy = C.getState()->getDynamicTypeInfo(ToR).getType(); 258239313Sdim if (OldDTy.isNull()) { 259239313Sdim return NewTy; 260239313Sdim } 261239313Sdim const ObjCObjectPointerType *OldTy = 262239313Sdim OldDTy->getAs<ObjCObjectPointerType>(); 263239313Sdim if (!OldTy) 264239313Sdim return 0; 265239313Sdim 266239313Sdim // Id the old type is 'id', the new one is more precise. 267239313Sdim if (OldTy->isObjCIdType() && !NewTy->isObjCIdType()) 268239313Sdim return NewTy; 269239313Sdim 270239313Sdim // Return new if it's a subclass of old. 271239313Sdim const ObjCInterfaceDecl *ToI = NewTy->getInterfaceDecl(); 272239313Sdim const ObjCInterfaceDecl *FromI = OldTy->getInterfaceDecl(); 273239313Sdim if (ToI && FromI && FromI->isSuperClassOf(ToI)) 274239313Sdim return NewTy; 275239313Sdim 276239313Sdim return 0; 277239313Sdim} 278239313Sdim 279239313Sdimvoid ento::registerDynamicTypePropagation(CheckerManager &mgr) { 280239313Sdim mgr.registerChecker<DynamicTypePropagation>(); 281239313Sdim} 282