// Try to retrieve the function declaration and find the function parameter // types which are pointers/references to a non-pointer const. // We do not invalidate the corresponding argument regions. static void findPtrToConstParams(llvm::SmallSet<unsigned, 1> &PreserveArgs, const CallOrObjCMessage &Call) { const Decl *CallDecl = Call.getDecl(); if (!CallDecl) return; if (const FunctionDecl *FDecl = dyn_cast<FunctionDecl>(CallDecl)) { const IdentifierInfo *II = FDecl->getIdentifier(); // List the cases, where the region should be invalidated even if the // argument is const. if (II) { StringRef FName = II->getName(); // - 'int pthread_setspecific(ptheread_key k, const void *)' stores a // value into thread local storage. The value can later be retrieved with // 'void *ptheread_getspecific(pthread_key)'. So even thought the // parameter is 'const void *', the region escapes through the call. // - funopen - sets a buffer for future IO calls. // - ObjC functions that end with "NoCopy" can free memory, of the passed // in buffer. // - Many CF containers allow objects to escape through custom // allocators/deallocators upon container construction. // - NSXXInsertXX, for example NSMapInsertIfAbsent, since they can // be deallocated by NSMapRemove. // - Any call that has a callback as one of the arguments. if (FName == "pthread_setspecific" || FName == "funopen" || FName.endswith("NoCopy") || (FName.startswith("NS") && (FName.find("Insert") != StringRef::npos)) || Call.isCFCGAllowingEscape(FName) || Call.hasNonZeroCallbackArg()) return; } for (unsigned Idx = 0, E = Call.getNumArgs(); Idx != E; ++Idx) { if (FDecl && Idx < FDecl->getNumParams()) { if (isPointerToConst(FDecl->getParamDecl(Idx))) PreserveArgs.insert(Idx); } } return; } if (const ObjCMethodDecl *MDecl = dyn_cast<ObjCMethodDecl>(CallDecl)) { assert(MDecl->param_size() <= Call.getNumArgs()); unsigned Idx = 0; if (Call.hasNonZeroCallbackArg()) return; for (clang::ObjCMethodDecl::param_const_iterator I = MDecl->param_begin(), E = MDecl->param_end(); I != E; ++I, ++Idx) { if (isPointerToConst(*I)) PreserveArgs.insert(Idx); } return; } }
// Try to retrieve the function declaration and find the function parameter // types which are pointers/references to a non-pointer const. // We will not invalidate the corresponding argument regions. static void findPtrToConstParams(llvm::SmallSet<unsigned, 1> &PreserveArgs, const CallEvent &Call) { unsigned Idx = 0; for (CallEvent::param_type_iterator I = Call.param_type_begin(), E = Call.param_type_end(); I != E; ++I, ++Idx) { if (isPointerToConst(*I)) PreserveArgs.insert(Idx); } }
static const TypeVec throwsException(const FunctionDecl *Func, llvm::SmallSet<const FunctionDecl *, 32> &CallStack) { if (CallStack.count(Func)) return TypeVec(); if (const Stmt *Body = Func->getBody()) { CallStack.insert(Func); const TypeVec Result = throwsException(Body, TypeVec(), CallStack); CallStack.erase(Func); return Result; } TypeVec Result; if (const auto *FPT = Func->getType()->getAs<FunctionProtoType>()) { for (const QualType Ex : FPT->exceptions()) { Result.push_back(Ex.getTypePtr()); } } return Result; }
void ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, const CXXRecordDecl *PB, int64_t Offset, llvm::SmallSet<const CXXRecordDecl*, 32> &mark, llvm::SmallSet<const CXXRecordDecl*, 32> &IndirectPrimary) { for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), e = RD->bases_end(); i != e; ++i) { const CXXRecordDecl *Base = cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); #if 0 const ASTRecordLayout &L = Ctx.getASTRecordLayout(Base); const CXXRecordDecl *PB = L.getPrimaryBase(); if (PB && L.getPrimaryBaseWasVirtual() && IndirectPrimary.count(PB)) { int64_t BaseOffset; // FIXME: calculate this. BaseOffset = (1<<63) | (1<<31); VBases.push_back(PB); VBaseOffsets.push_back(BaseOffset); } #endif int64_t BaseOffset = Offset;; // FIXME: Calculate BaseOffset. if (i->isVirtual()) { if (Base == PB) { // Only lay things out once. if (mark.count(Base)) continue; // Mark it so we don't lay it out twice. mark.insert(Base); assert (IndirectPrimary.count(Base) && "IndirectPrimary was wrong"); VBases.push_back(Base); VBaseOffsets.push_back(Offset); } else if (IndirectPrimary.count(Base)) { // Someone else will eventually lay this out. ; } else { // Only lay things out once. if (mark.count(Base)) continue; // Mark it so we don't lay it out twice. mark.insert(Base); LayoutVirtualBase(Base); BaseOffset = *(VBaseOffsets.end()-1); } } if (Base->getNumVBases()) { const ASTRecordLayout &L = Ctx.getASTRecordLayout(Base); const CXXRecordDecl *PB = L.getPrimaryBase(); LayoutVirtualBases(Base, PB, BaseOffset, mark, IndirectPrimary); } } }
void ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *Class, const CXXRecordDecl *RD, const CXXRecordDecl *PB, uint64_t Offset, llvm::SmallSet<const CXXRecordDecl*, 32> &mark, llvm::SmallSet<const CXXRecordDecl*, 32> &IndirectPrimary) { for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), e = RD->bases_end(); i != e; ++i) { assert(!i->getType()->isDependentType() && "Cannot layout class with dependent bases."); const CXXRecordDecl *Base = cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); uint64_t BaseOffset = Offset; if (i->isVirtual()) { if (Base == PB) { // Only lay things out once. if (mark.count(Base)) continue; // Mark it so we don't lay it out twice. mark.insert(Base); assert (IndirectPrimary.count(Base) && "IndirectPrimary was wrong"); VBases.push_back(std::make_pair(Base, Offset)); } else if (IndirectPrimary.count(Base)) { // Someone else will eventually lay this out. ; } else { // Only lay things out once. if (mark.count(Base)) continue; // Mark it so we don't lay it out twice. mark.insert(Base); LayoutVirtualBase(Base); BaseOffset = VBases.back().second; } } else { if (RD == Class) BaseOffset = getBaseOffset(Base); else { const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); BaseOffset = Offset + Layout.getBaseClassOffset(Base); } } if (Base->getNumVBases()) { const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(Base); const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBaseInfo().getBase(); LayoutVirtualBases(Class, Base, PrimaryBase, BaseOffset, mark, IndirectPrimary); } } }
void ASTRecordLayoutBuilder::SelectPrimaryForBase(const CXXRecordDecl *RD, llvm::SmallSet<const CXXRecordDecl*, 32> &IndirectPrimary) { const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD); const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual(); if (PrimaryBaseWasVirtual) IndirectPrimary.insert(PrimaryBase); for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), e = RD->bases_end(); i != e; ++i) { const CXXRecordDecl *Base = cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); // Only bases with virtual bases participate in computing the // indirect primary virtual base classes. if (Base->getNumVBases()) SelectPrimaryForBase(Base, IndirectPrimary); } }
void ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD, const CXXRecordDecl *&FirstPrimary, llvm::SmallSet<const CXXRecordDecl*, 32> &IndirectPrimary) { for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), e = RD->bases_end(); i != e; ++i) { const CXXRecordDecl *Base = cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); if (!i->isVirtual()) { SelectPrimaryVBase(Base, FirstPrimary, IndirectPrimary); if (PrimaryBase) return; continue; } if (IsNearlyEmpty(Base)) { if (FirstPrimary==0) FirstPrimary = Base; if (!IndirectPrimary.count(Base)) { setPrimaryBase(Base, true); return; } } } }