================
@@ -3068,12 +3124,225 @@ void MallocChecker::checkDeadSymbols(SymbolReaper 
&SymReaper,
   C.addTransition(state->set<RegionState>(RS), N);
 }
 
+// Helper function to check if a name is a recognized smart owning pointer name
+static bool isSmartOwningPtrName(StringRef Name) {
+  return Name == "unique_ptr" || Name == "shared_ptr";
+}
+
+// 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 = QT->getCanonicalTypeUnqualified();
+
+  // First try TemplateSpecializationType (for both std and custom smart
+  // pointers)
+  if (const auto *TST = QT->getAs<TemplateSpecializationType>()) {
+    const TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl();
+    if (!TD)
+      return false;
+
+    const auto *ND = dyn_cast_or_null<NamedDecl>(TD->getTemplatedDecl());
+    if (!ND)
+      return false;
+
+    // Accept both std and custom smart pointer implementations for broader
+    // coverage
+    return isSmartOwningPtrName(ND->getName());
+  }
+
+  return false;
+}
+
+/// Check if a record type has smart owning pointer fields (directly or in base
+/// classes).
+static bool hasSmartOwningPtrField(const CXXRecordDecl *CRD) {
+  // Check direct fields
+  if (llvm::any_of(CRD->fields(), [](const FieldDecl *FD) {
+        return isSmartOwningPtrType(FD->getType());
+      }))
+    return true;
+
+  // Check fields from base classes
+  for (const CXXBaseSpecifier &Base : CRD->bases()) {
+    if (const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl()) {
+      if (hasSmartOwningPtrField(BaseDecl))
+        return true;
+    }
+  }
+  return false;
+}
+
+/// Check if an expression is an rvalue record type passed by value.
+static bool isRvalueByValueRecord(const Expr *AE) {
+  if (AE->isGLValue())
+    return false;
+
+  QualType T = AE->getType();
+  if (!T->isRecordType() || T->isReferenceType())
+    return false;
+
+  // Accept common temp/construct forms but don't overfit.
+  return isa<CXXTemporaryObjectExpr, MaterializeTemporaryExpr, 
CXXConstructExpr,
+             InitListExpr, ImplicitCastExpr, CXXBindTemporaryExpr>(AE);
+}
+
+/// Check if an expression is an rvalue record with smart owning pointer fields
+/// passed by value.
+static bool isRvalueByValueRecordWithSmartOwningPtr(const Expr *AE) {
+  if (!isRvalueByValueRecord(AE))
+    return false;
+
+  const auto *CRD = AE->getType()->getAsCXXRecordDecl();
+  return CRD && hasSmartOwningPtrField(CRD);
+}
+
+/// Check if a CXXRecordDecl has a name matching recognized smart pointer 
names.
+static bool isSmartOwningPtrRecord(const CXXRecordDecl *RD) {
+  if (!RD)
+    return false;
+
+  // Check the record name directly and accept both std and custom smart 
pointer
+  // implementations for broader coverage
+  return isSmartOwningPtrName(RD->getName());
+}
+
+/// Check if a call is a constructor of a smart owning pointer class that
+/// accepts pointer parameters.
+static bool isSmartOwningPtrCall(const CallEvent &Call) {
+  // Only check for smart pointer constructor calls
+  const auto *CD = dyn_cast_or_null<CXXConstructorDecl>(Call.getDecl());
+  if (!CD)
+    return false;
+
+  const auto *RD = CD->getParent();
+  if (!isSmartOwningPtrRecord(RD))
+    return false;
+
+  // Check if constructor takes a pointer parameter
+  for (const auto *Param : CD->parameters()) {
+    QualType ParamType = Param->getType();
+    if (ParamType->isPointerType() && !ParamType->isFunctionPointerType() &&
+        !ParamType->isVoidPointerType()) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+static void collectSmartOwningPtrFieldRegions(
+    const MemRegion *Base, QualType RecQT, CheckerContext &C,
----------------
NagyDonat wrote:

The variable name `const MemRegion *Base` is a bit unfortunate because it 
appears to refer to the frequently used method `MemRegion::getBaseRegion` which 
uses the word "base" in a different meaning:
- `SomeRegion.getBaseRegion()` returns the largest cohesive block of memory 
that contains the given region: e.g. calling it on the field region 
`array[5].field.otherfield` would return the region corresponding to `array`.
- This variable name is called "base" because (at least in the recursive calls) 
it is the subobject corresponding to a certain base class.

(Perhaps this would be more clear for others, but during the first review I 
completely missed that this variable is not connected to `getBaseRegion`.)

To clarify the naming, I'd suggest:
- renaming this parameter `cost MemRegion *Base` to e.g. `const MemRegion *Reg` 
(a natural name for "the" region);
- later in the body of the function renaming `BaseRegion` to e.g. 
`BaseObjRegion` (to highlight that it's a region corresponding to a base 
_object_).



https://github.com/llvm/llvm-project/pull/152751
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to