https://github.com/pjalwadi updated https://github.com/llvm/llvm-project/pull/180471
>From ba1722e9b5629fcf5cf04dc269856f5aceb0cbc4 Mon Sep 17 00:00:00 2001 From: prajwal jalwadi <[email protected]> Date: Mon, 9 Feb 2026 09:50:37 +0530 Subject: [PATCH] "[Clang][UnsafeBufferUsage] Warn about two-arg string_view constructors" -m "This patch extends the unsafe buffer usage warning to cover std::string_view constructors that take a pointer and size, similar to the existing check for std::span. The warning message has been updated to be generic ('container construction' instead of 'span construction') and existing tests have been updated to match. Fixes #166644." --- clang/docs/ReleaseNotes.rst | 3 + .../Analysis/Analyses/UnsafeBufferUsage.h | 4 ++ .../Analyses/UnsafeBufferUsageGadgets.def | 1 + .../clang/Basic/DiagnosticSemaKinds.td | 3 + clang/lib/Analysis/UnsafeBufferUsage.cpp | 66 +++++++++++++++++++ clang/lib/Sema/AnalysisBasedWarnings.cpp | 20 ++++++ .../warn-unsafe-buffer-usage-string-view.cpp | 19 ++++++ 7 files changed, 116 insertions(+) create mode 100644 clang/test/SemaCXX/warn-unsafe-buffer-usage-string-view.cpp diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index a1bb1bd2467b7..7567dd0477f3c 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -227,6 +227,9 @@ Improvements to Clang's diagnostics when accessing a member function on a past-the-end array element. (#GH179128) +- ``-Wunsafe-buffer-usage`` now warns about unsafe two-parameter constructors of + ``std::string_view`` (pointer and size), consistent with the existing warning for ``std::span``. + Improvements to Clang's time-trace ---------------------------------- diff --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h index 876682ad779d4..bffb45022b8bc 100644 --- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h +++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h @@ -129,6 +129,10 @@ class UnsafeBufferUsageHandler { bool IsRelatedToDecl, ASTContext &Ctx) = 0; + virtual void handleUnsafeOperationInStringView(const Stmt *Operation, + bool IsRelatedToDecl, + ASTContext &Ctx) = 0; + /// Invoked when a fix is suggested against a variable. This function groups /// all variables that must be fixed together (i.e their types must be changed /// to the same target type to prevent type mismatches) into a single fixit. diff --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def index 129ce95c1c0e0..7ce3c5f0fc7c5 100644 --- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def +++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def @@ -42,6 +42,7 @@ WARNING_OPTIONAL_GADGET(ArraySubscript) WARNING_OPTIONAL_GADGET(UnsafeLibcFunctionCall) WARNING_OPTIONAL_GADGET(UnsafeFormatAttributedFunctionCall) WARNING_OPTIONAL_GADGET(SpanTwoParamConstructor) // Uses of `std::span(arg0, arg1)` +WARNING_OPTIONAL_GADGET(StringViewTwoParamConstructor) FIXABLE_GADGET(ULCArraySubscript) // `DRE[any]` in an Unspecified Lvalue Context FIXABLE_GADGET(DerefSimplePtrArithFixable) FIXABLE_GADGET(PointerDereference) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index f12677ac11600..bbc8ecdbbc3f6 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -13549,6 +13549,9 @@ def note_safe_buffer_usage_suggestions_disabled : Note< def warn_unsafe_buffer_usage_in_container : Warning< "the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information">, InGroup<UnsafeBufferUsageInContainer>, DefaultIgnore; +def warn_unsafe_buffer_usage_in_string_view : Warning< + "the two-parameter std::string_view construction is unsafe as it can introduce mismatch between buffer size and the bound information">, + InGroup<UnsafeBufferUsageInContainer>, DefaultIgnore; def warn_unsafe_buffer_usage_unique_ptr_array_access : Warning<"direct access using operator[] on std::unique_ptr<T[]> is unsafe due to lack of bounds checking">, InGroup<UnsafeBufferUsageInUniquePtrArrayAccess>, DefaultIgnore; def warn_unsafe_buffer_usage_in_static_sized_array : Warning<"direct access on T[N] is unsafe due to the lack of bounds checking">, diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp index 193851cc5f381..ba8c3d0b723ba 100644 --- a/clang/lib/Analysis/UnsafeBufferUsage.cpp +++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -1805,6 +1805,70 @@ class SpanTwoParamConstructorGadget : public WarningGadget { SmallVector<const Expr *, 1> getUnsafePtrs() const override { return {}; } }; +class StringViewTwoParamConstructorGadget : public WarningGadget { + static constexpr const char *const StringViewTwoParamConstructorTag = + "stringViewTwoParamConstructor"; + const CXXConstructExpr *Ctor; // the string_view constructor expression + +public: + StringViewTwoParamConstructorGadget(const MatchResult &Result) + : WarningGadget(Kind::StringViewTwoParamConstructor), + Ctor(Result.getNodeAs<CXXConstructExpr>( + StringViewTwoParamConstructorTag)) {} + + static bool classof(const Gadget *G) { + return G->getKind() == Kind::StringViewTwoParamConstructor; + } + + static bool matches(const Stmt *S, ASTContext &Ctx, MatchResult &Result) { + const auto *CE = dyn_cast<CXXConstructExpr>(S); + if (!CE) + return false; + const auto *CDecl = CE->getConstructor(); + const auto *CRecordDecl = CDecl->getParent(); + + // MATCH: std::basic_string_view + bool IsStringView = + CRecordDecl->isInStdNamespace() && + CDecl->getDeclName().getAsString() == "basic_string_view" && + CE->getNumArgs() == 2; + + if (!IsStringView || isSafeSpanTwoParamConstruct(*CE, Ctx)) + return false; + + Result.addNode(StringViewTwoParamConstructorTag, DynTypedNode::create(*CE)); + return true; + } + + static bool matches(const Stmt *S, ASTContext &Ctx, + const UnsafeBufferUsageHandler *Handler, + MatchResult &Result) { + if (ignoreUnsafeBufferInContainer(*S, Handler)) + return false; + return matches(S, Ctx, Result); + } + + void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler, + bool IsRelatedToDecl, + ASTContext &Ctx) const override { + Handler.handleUnsafeOperationInStringView(Ctor, IsRelatedToDecl, Ctx); + } + + SourceLocation getSourceLoc() const override { return Ctor->getBeginLoc(); } + + DeclUseList getClaimedVarUseSites() const override { + // If the constructor call is of the form `std::string_view{var, n}`, `var` + // is considered an unsafe variable. + if (auto *DRE = dyn_cast<DeclRefExpr>(Ctor->getArg(0))) { + if (isa<VarDecl>(DRE->getDecl())) + return {DRE}; + } + return {}; + } + + SmallVector<const Expr *, 1> getUnsafePtrs() const override { return {}; } +}; + /// A pointer initialization expression of the form: /// \code /// int *p = q; @@ -2954,6 +3018,8 @@ std::set<const Expr *> clang::findUnsafePointers(const FunctionDecl *FD) { const Expr *UnsafeArg = nullptr) override {} void handleUnsafeOperationInContainer(const Stmt *, bool, ASTContext &) override {} + void handleUnsafeOperationInStringView(const Stmt *, bool, + ASTContext &) override {} void handleUnsafeVariableGroup(const VarDecl *, const VariableGroupsManager &, FixItList &&, const Decl *, diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 4f04bc3999a24..4dfb709e00e23 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -2568,6 +2568,26 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler { } } + void handleUnsafeOperationInStringView(const Stmt *Operation, + bool IsRelatedToDecl, + ASTContext &Ctx) override { + SourceLocation Loc; + SourceRange Range; + unsigned MsgParam = 0; + + // This function only handles SpanTwoParamConstructorGadget so far, which + // always gives a CXXConstructExpr. + const auto *CtorExpr = cast<CXXConstructExpr>(Operation); + Loc = CtorExpr->getLocation(); + + S.Diag(Loc, diag::warn_unsafe_buffer_usage_in_string_view); + if (IsRelatedToDecl) { + assert(!SuggestSuggestions && + "Variables blamed for unsafe buffer usage without suggestions!"); + S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam << Range; + } + } + void handleUnsafeVariableGroup(const VarDecl *Variable, const VariableGroupsManager &VarGrpMgr, FixItList &&Fixes, const Decl *D, diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-string-view.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-string-view.cpp new file mode 100644 index 0000000000000..1ef22f10eff34 --- /dev/null +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-string-view.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage -verify %s + +namespace std { + template <typename T> + class basic_string_view { + public: + basic_string_view(T*, int); + basic_string_view(T*); + }; + + using string_view = basic_string_view<char>; +} + +void test(char *ptr, int size) { + // CASE 1: Unsafe (Ptr + Size) -> Should Warn + std::string_view sv1(ptr, size); // expected-warning{{the two-parameter std::string_view construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + // CASE 2: Safe (Ptr only) -> Should NOT Warn + std::string_view sv2(ptr); +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
