================ @@ -3068,11 +3107,217 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper, C.addTransition(state->set<RegionState>(RS), N); } +static QualType canonicalStrip(QualType QT) { + return QT.getCanonicalType().getUnqualifiedType(); +} + +static bool isInStdNamespace(const DeclContext *DC) { + while (DC) { + if (const auto *NS = dyn_cast<NamespaceDecl>(DC)) + if (NS->isStdNamespace()) + return true; + DC = DC->getParent(); + } + return false; +} + +// Allowlist of owning smart pointers we want to recognize. +// Start with unique_ptr and shared_ptr. (intentionally exclude weak_ptr) +static bool isSmartOwningPtrType(QualType QT) { + QT = canonicalStrip(QT); + + // First try TemplateSpecializationType (for std smart pointers) + const auto *TST = QT->getAs<TemplateSpecializationType>(); + if (TST) { + const TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl(); + if (!TD) + return false; + + const auto *ND = dyn_cast_or_null<NamedDecl>(TD->getTemplatedDecl()); + if (!ND) + return false; + + // Check if it's in std namespace + const DeclContext *DC = ND->getDeclContext(); + if (!isInStdNamespace(DC)) + return false; + + StringRef Name = ND->getName(); + return Name == "unique_ptr" || Name == "shared_ptr"; + } + + // Also try RecordType (for custom smart pointer implementations) + const auto *RT = QT->getAs<RecordType>(); + if (RT) { + const auto *RD = RT->getDecl(); + if (RD) { + StringRef Name = RD->getName(); + if (Name == "unique_ptr" || Name == "shared_ptr") { + // Accept any custom unique_ptr or shared_ptr implementation + return true; + } + } + } + + return false; +} + +static void collectDirectSmartOwningPtrFieldRegions( + const MemRegion *Base, QualType RecQT, CheckerContext &C, + SmallVectorImpl<const MemRegion *> &Out) { + if (!Base) + return; + const auto *CRD = RecQT->getAsCXXRecordDecl(); + if (!CRD) + return; + + for (const FieldDecl *FD : CRD->fields()) { + if (!isSmartOwningPtrType(FD->getType())) + continue; + SVal L = C.getState()->getLValue(FD, loc::MemRegionVal(Base)); + if (const MemRegion *FR = L.getAsRegion()) + Out.push_back(FR); + } +} + void MallocChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const { + // Keep existing post-call handlers. if (const auto *PostFN = PostFnMap.lookup(Call)) { (*PostFN)(this, C.getState(), Call, C); - return; + } + + SmallVector<const MemRegion *, 8> SmartPtrFieldRoots; + + for (unsigned I = 0, E = Call.getNumArgs(); I != E; ++I) { + const Expr *AE = Call.getArgExpr(I); + if (!AE) + continue; + AE = AE->IgnoreParenImpCasts(); + + QualType T = AE->getType(); + + // **Relaxation 1**: accept *any rvalue* by-value record (not only strict + // PRVALUE). + if (AE->isGLValue()) + continue; + + // By-value record only (no refs). + if (!T->isRecordType() || T->isReferenceType()) + continue; + + // **Relaxation 2**: accept common temp/construct forms but don't overfit. + const bool LooksLikeTemp = + isa<CXXTemporaryObjectExpr>(AE) || isa<MaterializeTemporaryExpr>(AE) || + isa<CXXConstructExpr>(AE) || isa<InitListExpr>(AE) || + isa<ImplicitCastExpr>(AE) || // handle common rvalue materializations + isa<CXXBindTemporaryExpr>(AE); // handle CXXBindTemporaryExpr ---------------- steakhal wrote:
You can combine the Types in a single `isa<T, T2,...>`. https://github.com/llvm/llvm-project/pull/152751 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits