clang API Documentation

DynamicTypePropagation.cpp
Go to the documentation of this file.
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 }