[clang] Reland: [clang] Diagnose dangling issues for the "Container<GSLPointer>" case. #107213 (PR #108344)
Haojian Wu via cfe-commits
cfe-commits at lists.llvm.org
Mon Sep 23 13:33:43 PDT 2024
================
@@ -327,6 +369,103 @@ static bool shouldTrackFirstArgument(const FunctionDecl *FD) {
return false;
}
+// Returns true if the given constructor is a copy-like constructor, such as
+// `Ctor(Owner<U>&&)` or `Ctor(const Owner<U>&)`.
+static bool isCopyLikeConstructor(const CXXConstructorDecl *Ctor) {
+ if (!Ctor || Ctor->param_size() != 1)
+ return false;
+ const auto *ParamRefType =
+ Ctor->getParamDecl(0)->getType()->getAs<ReferenceType>();
+ if (!ParamRefType)
+ return false;
+
+ // Check if the first parameter type "Owner<U>".
+ if (const auto *TST =
+ ParamRefType->getPointeeType()->getAs<TemplateSpecializationType>())
+ return TST->getTemplateName()
+ .getAsTemplateDecl()
+ ->getTemplatedDecl()
+ ->hasAttr<OwnerAttr>();
+ return false;
+}
+
+// Returns true if we should perform the GSL analysis on the first argument for
+// the given constructor.
+static bool
+shouldTrackFirstArgumentForConstructor(const CXXConstructExpr *Ctor) {
+ const auto *LHSRecordDecl = Ctor->getConstructor()->getParent();
+
+ // Case 1, construct a GSL pointer, e.g. std::string_view
+ // Always inspect when LHS is a pointer.
+ if (LHSRecordDecl->hasAttr<PointerAttr>())
+ return true;
+
+ if (Ctor->getConstructor()->getNumParams() != 1 ||
+ !isContainerOfPointer(LHSRecordDecl))
+ return false;
+
+ // Now, the LHS is an Owner<Pointer> type, e.g., std::vector<string_view>.
+ //
+ // At a high level, we cannot precisely determine what the nested pointer
+ // owns. However, by analyzing the RHS owner type, we can use heuristics to
+ // infer ownership information. These heuristics are designed to be
+ // conservative, minimizing false positives while still providing meaningful
+ // diagnostics.
+ //
+ // While this inference isn't perfect, it helps catch common use-after-free
+ // patterns.
+ auto RHSArgType = Ctor->getArg(0)->getType();
+ const auto *RHSRD = RHSArgType->getAsRecordDecl();
+ // LHS is constructed from an intializer_list.
+ //
+ // std::initializer_list is a proxy object that provides access to the backing
+ // array. We perform analysis on it to determine if there are any dangling
+ // temporaries in the backing array.
+ // E.g. std::vector<string_view> abc = {string()};
+ if (isStdInitializerListOfPointer(RHSRD))
+ return true;
+
+ // RHS must be an owner.
+ if (!isRecordWithAttr<OwnerAttr>(RHSArgType))
+ return false;
+
+ // Bail out if the RHS is Owner<Pointer>.
+ //
+ // We cannot reliably determine what the LHS nested pointer owns -- it could
+ // be the entire RHS or the nested pointer in RHS. To avoid false positives,
+ // we skip this case, such as:
+ // std::stack<std::string_view> s(std::deque<std::string_view>{});
+ //
+ // TODO: this also has a false negative, it doesn't catch the case like:
+ // std::optional<span<int*>> os = std::vector<int*>{}
----------------
hokein wrote:
Added.
https://github.com/llvm/llvm-project/pull/108344
More information about the cfe-commits
mailing list