RuntimeDefinition CXXInstanceCall::getRuntimeDefinition() const { // Do we have a decl at all? const Decl *D = getDecl(); if (!D) return RuntimeDefinition(); // If the method is non-virtual, we know we can inline it. const CXXMethodDecl *MD = cast<CXXMethodDecl>(D); if (!MD->isVirtual()) return AnyFunctionCall::getRuntimeDefinition(); // Do we know the implicit 'this' object being called? const MemRegion *R = getCXXThisVal().getAsRegion(); if (!R) return RuntimeDefinition(); // Do we know anything about the type of 'this'? DynamicTypeInfo DynType = getState()->getDynamicTypeInfo(R); if (!DynType.isValid()) return RuntimeDefinition(); // Is the type a C++ class? (This is mostly a defensive check.) QualType RegionType = DynType.getType()->getPointeeType(); assert(!RegionType.isNull() && "DynamicTypeInfo should always be a pointer."); const CXXRecordDecl *RD = RegionType->getAsCXXRecordDecl(); if (!RD || !RD->hasDefinition()) return RuntimeDefinition(); // Find the decl for this method in that class. const CXXMethodDecl *Result = MD->getCorrespondingMethodInClass(RD, true); if (!Result) { // We might not even get the original statically-resolved method due to // some particularly nasty casting (e.g. casts to sister classes). // However, we should at least be able to search up and down our own class // hierarchy, and some real bugs have been caught by checking this. assert(!RD->isDerivedFrom(MD->getParent()) && "Couldn't find known method"); // FIXME: This is checking that our DynamicTypeInfo is at least as good as // the static type. However, because we currently don't update // DynamicTypeInfo when an object is cast, we can't actually be sure the // DynamicTypeInfo is up to date. This assert should be re-enabled once // this is fixed. <rdar://problem/12287087> //assert(!MD->getParent()->isDerivedFrom(RD) && "Bad DynamicTypeInfo"); return RuntimeDefinition(); } // Does the decl that we found have an implementation? const FunctionDecl *Definition; if (!Result->hasBody(Definition)) return RuntimeDefinition(); // We found a definition. If we're not sure that this devirtualization is // actually what will happen at runtime, make sure to provide the region so // that ExprEngine can decide what to do with it. if (DynType.canBeASubClass()) return RuntimeDefinition(Definition, R->StripCasts()); return RuntimeDefinition(Definition, /*DispatchRegion=*/0); }
RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const { const ObjCMessageExpr *E = getOriginExpr(); assert(E); Selector Sel = E->getSelector(); if (E->isInstanceMessage()) { // Find the the receiver type. const ObjCObjectPointerType *ReceiverT = 0; bool CanBeSubClassed = false; QualType SupersType = E->getSuperType(); const MemRegion *Receiver = 0; if (!SupersType.isNull()) { // Super always means the type of immediate predecessor to the method // where the call occurs. ReceiverT = cast<ObjCObjectPointerType>(SupersType); } else { Receiver = getReceiverSVal().getAsRegion(); if (!Receiver) return RuntimeDefinition(); DynamicTypeInfo DTI = getState()->getDynamicTypeInfo(Receiver); QualType DynType = DTI.getType(); CanBeSubClassed = DTI.canBeASubClass(); ReceiverT = dyn_cast<ObjCObjectPointerType>(DynType); if (ReceiverT && CanBeSubClassed) if (ObjCInterfaceDecl *IDecl = ReceiverT->getInterfaceDecl()) if (!canBeOverridenInSubclass(IDecl, Sel)) CanBeSubClassed = false; } // Lookup the method implementation. if (ReceiverT) if (ObjCInterfaceDecl *IDecl = ReceiverT->getInterfaceDecl()) { const ObjCMethodDecl *MD = IDecl->lookupPrivateMethod(Sel); if (CanBeSubClassed) return RuntimeDefinition(MD, Receiver); else return RuntimeDefinition(MD, 0); } } else { // This is a class method. // If we have type info for the receiver class, we are calling via // class name. if (ObjCInterfaceDecl *IDecl = E->getReceiverInterface()) { // Find/Return the method implementation. return RuntimeDefinition(IDecl->lookupPrivateClassMethod(Sel)); } } return RuntimeDefinition(); }
RuntimeDefinition CXXInstanceCall::getRuntimeDefinition() const { // Do we have a decl at all? const Decl *D = getDecl(); if (!D) return RuntimeDefinition(); // If the method is non-virtual, we know we can inline it. const CXXMethodDecl *MD = cast<CXXMethodDecl>(D); if (!MD->isVirtual()) return AnyFunctionCall::getRuntimeDefinition(); // Do we know the implicit 'this' object being called? const MemRegion *R = getCXXThisVal().getAsRegion(); if (!R) return RuntimeDefinition(); // Do we know anything about the type of 'this'? DynamicTypeInfo DynType = getState()->getDynamicTypeInfo(R); if (!DynType.isValid()) return RuntimeDefinition(); // Is the type a C++ class? (This is mostly a defensive check.) QualType RegionType = DynType.getType()->getPointeeType(); const CXXRecordDecl *RD = RegionType->getAsCXXRecordDecl(); if (!RD || !RD->hasDefinition()) return RuntimeDefinition(); // Find the decl for this method in that class. const CXXMethodDecl *Result = MD->getCorrespondingMethodInClass(RD, true); assert(Result && "At the very least the static decl should show up."); // Does the decl that we found have an implementation? const FunctionDecl *Definition; if (!Result->hasBody(Definition)) return RuntimeDefinition(); // We found a definition. If we're not sure that this devirtualization is // actually what will happen at runtime, make sure to provide the region so // that ExprEngine can decide what to do with it. if (DynType.canBeASubClass()) return RuntimeDefinition(Definition, R->StripCasts()); return RuntimeDefinition(Definition, /*DispatchRegion=*/0); }
RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const { const ObjCMessageExpr *E = getOriginExpr(); assert(E); Selector Sel = E->getSelector(); if (E->isInstanceMessage()) { // Find the the receiver type. const ObjCObjectPointerType *ReceiverT = 0; bool CanBeSubClassed = false; QualType SupersType = E->getSuperType(); const MemRegion *Receiver = 0; if (!SupersType.isNull()) { // Super always means the type of immediate predecessor to the method // where the call occurs. ReceiverT = cast<ObjCObjectPointerType>(SupersType); } else { Receiver = getReceiverSVal().getAsRegion(); if (!Receiver) return RuntimeDefinition(); DynamicTypeInfo DTI = getState()->getDynamicTypeInfo(Receiver); QualType DynType = DTI.getType(); CanBeSubClassed = DTI.canBeASubClass(); ReceiverT = dyn_cast<ObjCObjectPointerType>(DynType); if (ReceiverT && CanBeSubClassed) if (ObjCInterfaceDecl *IDecl = ReceiverT->getInterfaceDecl()) if (!canBeOverridenInSubclass(IDecl, Sel)) CanBeSubClassed = false; } // Lookup the method implementation. if (ReceiverT) if (ObjCInterfaceDecl *IDecl = ReceiverT->getInterfaceDecl()) { // Repeatedly calling lookupPrivateMethod() is expensive, especially // when in many cases it returns null. We cache the results so // that repeated queries on the same ObjCIntefaceDecl and Selector // don't incur the same cost. On some test cases, we can see the // same query being issued thousands of times. // // NOTE: This cache is essentially a "global" variable, but it // only gets lazily created when we get here. The value of the // cache probably comes from it being global across ExprEngines, // where the same queries may get issued. If we are worried about // concurrency, or possibly loading/unloading ASTs, etc., we may // need to revisit this someday. In terms of memory, this table // stays around until clang quits, which also may be bad if we // need to release memory. typedef std::pair<const ObjCInterfaceDecl*, Selector> PrivateMethodKey; typedef llvm::DenseMap<PrivateMethodKey, Optional<const ObjCMethodDecl *> > PrivateMethodCache; static PrivateMethodCache PMC; Optional<const ObjCMethodDecl *> &Val = PMC[std::make_pair(IDecl, Sel)]; // Query lookupPrivateMethod() if the cache does not hit. if (!Val.hasValue()) Val = IDecl->lookupPrivateMethod(Sel); const ObjCMethodDecl *MD = Val.getValue(); if (CanBeSubClassed) return RuntimeDefinition(MD, Receiver); else return RuntimeDefinition(MD, 0); } } else { // This is a class method. // If we have type info for the receiver class, we are calling via // class name. if (ObjCInterfaceDecl *IDecl = E->getReceiverInterface()) { // Find/Return the method implementation. return RuntimeDefinition(IDecl->lookupPrivateClassMethod(Sel)); } } return RuntimeDefinition(); }