https://github.com/pjalwadi updated https://github.com/llvm/llvm-project/pull/180471
>From d565dfefebb4056b61f9fca88acb34232a3633fa 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/include/clang/Basic/DiagnosticGroups.td | 2 + .../clang/Basic/DiagnosticSemaKinds.td | 6 +- clang/lib/Analysis/UnsafeBufferUsage.cpp | 131 ++++++++++++++++++ clang/lib/Sema/AnalysisBasedWarnings.cpp | 34 ++++- .../warn-unsafe-buffer-usage-field-attr.cpp | 2 +- ...ffer-usage-in-container-span-construct.cpp | 124 ++++++++--------- .../warn-unsafe-buffer-usage-string-view.cpp | 44 ++++++ 10 files changed, 284 insertions(+), 67 deletions(-) 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 668097236fe97..ce7c7cc260f55 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -279,6 +279,9 @@ Improvements to Clang's diagnostics - Clang now emits ``-Wsizeof-pointer-memaccess`` when snprintf/vsnprintf use the sizeof the destination buffer(dynamically allocated) in the len parameter(#GH162366) +- ``-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/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index f5b6a4a9bfa73..e55f4d6fc06d6 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -1903,3 +1903,5 @@ def TrivialAutoVarInit : DiagGroup<"trivial-auto-var-init">; // A warning for options that enable a feature that is not yet complete def ExperimentalOption : DiagGroup<"experimental-option">; + +def UnsafeBufferUsageInStringView : DiagGroup<"unsafe-buffer-usage-in-string-view">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index ef0e29af0f224..4c83d7de910f9 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -13635,8 +13635,12 @@ def note_unsafe_buffer_variable_fixit_together : Note< def note_safe_buffer_usage_suggestions_disabled : Note< "pass -fsafe-buffer-usage-suggestions to receive code hardening suggestions">; 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">, + "the two-parameter %0 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">, + InGroup<UnsafeBufferUsageInStringView>, 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..32b7b5aa084de 100644 --- a/clang/lib/Analysis/UnsafeBufferUsage.cpp +++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -699,6 +699,71 @@ static bool isSafeSpanTwoParamConstruct(const CXXConstructExpr &Node, return isPtrBufferSafe(Arg0, Arg1, Ctx); } +static bool isSafeStringViewTwoParamConstruct(const CXXConstructExpr &Node, + ASTContext &Ctx) { + const Expr *Arg0 = Node.getArg(0)->IgnoreParenImpCasts(); + const Expr *Arg1 = Node.getArg(1)->IgnoreParenImpCasts(); + + // Pattern 1: String Literals + if (const auto *SL = dyn_cast<StringLiteral>(Arg0)) { + if (auto ArgSize = Arg1->getIntegerConstantExpr(Ctx)) { + if (llvm::APSInt::compareValues( + llvm::APSInt::getUnsigned(SL->getLength()), *ArgSize) >= 0) + return true; + return false; // Explicitly unsafe if size > length + } + } + + // Pattern 2: Constant Arrays + if (const auto *CAT = Ctx.getAsConstantArrayType(Arg0->getType())) { + if (auto ArgSize = Arg1->getIntegerConstantExpr(Ctx)) { + if (llvm::APSInt::compareValues(llvm::APSInt(CAT->getSize(), true), + *ArgSize) >= 0) + return true; + return false; // Explicitly unsafe if size > ArraySize + } + } + + // Pattern 3: Zero length + if (auto Val = Arg1->getIntegerConstantExpr(Ctx)) { + if (Val->isZero()) + return true; + } + + // Pattern 4: string_view(it, it) - Only safe if it's .begin() and .end() of + // the SAME object + auto GetContainerObj = [](const Expr *E) -> const Expr * { + E = E->IgnoreParenImpCasts(); + if (const auto *MCE = dyn_cast<CXXMemberCallExpr>(E)) { + const auto *MD = MCE->getMethodDecl(); + if (MD && (MD->getName() == "begin" || MD->getName() == "end")) + return MCE->getImplicitObjectArgument()->IgnoreParenImpCasts(); + } + return nullptr; + }; + + const Expr *Obj0 = GetContainerObj(Arg0); + const Expr *Obj1 = GetContainerObj(Arg1); + + if (Obj0 && Obj1) { + const auto *DRE0 = dyn_cast<DeclRefExpr>(Obj0); + const auto *DRE1 = dyn_cast<DeclRefExpr>(Obj1); + + // If both are references to variables, they MUST point to the same + // declaration. + if (DRE0 && DRE1) { + if (DRE0->getDecl()->getCanonicalDecl() == + DRE1->getDecl()->getCanonicalDecl()) + return true; + } + + // If they aren't both DeclRefExprs or don't match, we DO NOT return true. + // This ensures v1.begin(), v2.end() triggers a warning. + } + + return false; // Default to unsafe +} + static bool isSafeArraySubscript(const ArraySubscriptExpr &Node, const ASTContext &Ctx, const bool IgnoreStaticSizedArrays) { @@ -1805,6 +1870,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 || isSafeStringViewTwoParamConstruct(*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 +3083,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 4d3b90201ddd9..e81b0fff27e97 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -2555,12 +2555,18 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler { 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(); + Range = CtorExpr->getSourceRange(); + + // Get the name of the container (usually std::span) + StringRef ContainerName = "std::span"; + if (auto *TD = CtorExpr->getConstructor()->getParent()) + ContainerName = TD->getName(); + + // FIX: Pass the container name to fill the %0 parameter + S.Diag(Loc, diag::warn_unsafe_buffer_usage_in_container) << ContainerName; - S.Diag(Loc, diag::warn_unsafe_buffer_usage_in_container); if (IsRelatedToDecl) { assert(!SuggestSuggestions && "Variables blamed for unsafe buffer usage without suggestions!"); @@ -2568,6 +2574,28 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler { } } + void handleUnsafeOperationInStringView(const Stmt *Operation, + bool IsRelatedToDecl, + ASTContext &Ctx) override { + // Extracting location: prioritize the specific location of the constructor + SourceLocation Loc = Operation->getBeginLoc(); + SourceRange Range = Operation->getSourceRange(); + + if (const auto *CtorExpr = dyn_cast<CXXConstructExpr>(Operation)) { + Loc = CtorExpr->getLocation(); + } + + // 1. Emit the primary warning for string_view + S.Diag(Loc, diag::warn_unsafe_buffer_usage_in_container) << "std::string_view"; + + // 2. If a specific variable is 'blamed', emit the note + if (IsRelatedToDecl) { + // MsgParam 0 is "unsafe operation" + // Range helps the IDE underline the whole expression + S.Diag(Loc, diag::note_unsafe_buffer_operation) << 0 << Range; + } + } + void handleUnsafeVariableGroup(const VarDecl *Variable, const VariableGroupsManager &VarGrpMgr, FixItList &&Fixes, const Decl *D, diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-field-attr.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-field-attr.cpp index 1636c948da075..47c53092d26b2 100644 --- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-field-attr.cpp +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-field-attr.cpp @@ -78,7 +78,7 @@ void test_writes_from_span(std::span<int> sp) { } void test_reads_to_span(A a, A b) { - //expected-warning@+1{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + //expected-warning@+1{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} std::span<int> sp {a.ptr, a.sz}; //expected-warning{{field 'ptr' prone to unsafe buffer manipulation}} // expected-warning@+1 3{{field 'ptr' prone to unsafe buffer manipulation}} diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-in-container-span-construct.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-in-container-span-construct.cpp index 1e7855517207e..771fe5f8cc538 100644 --- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-in-container-span-construct.cpp +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-in-container-span-construct.cpp @@ -78,23 +78,23 @@ namespace irrelevant_constructors { namespace construct_wt_ptr_size { std::span<int> warnVarInit(int *p) { - std::span<int> S{p, 10}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - std::span<int> S1(p, 10); // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - std::span<int> S2 = std::span{p, 10}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - std::span<int> S3 = std::span(p, 10); // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - std::span<int> S4 = std::span<int>{p, 10}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - std::span<int> S5 = std::span<int>(p, 10); // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - std::span<int> S6 = {p, 10}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - auto S7 = std::span<int>{p, 10}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - auto S8 = std::span<int>(p, 10); // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - const auto &S9 = std::span<int>{p, 10}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - auto &&S10 = std::span<int>(p, 10); // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<int> S{p, 10}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<int> S1(p, 10); // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<int> S2 = std::span{p, 10}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<int> S3 = std::span(p, 10); // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<int> S4 = std::span<int>{p, 10}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<int> S5 = std::span<int>(p, 10); // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<int> S6 = {p, 10}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + auto S7 = std::span<int>{p, 10}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + auto S8 = std::span<int>(p, 10); // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + const auto &S9 = std::span<int>{p, 10}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + auto &&S10 = std::span<int>(p, 10); // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} #define Ten 10 - std::span S11 = std::span<int>{p, Ten}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span S11 = std::span<int>{p, Ten}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - if (auto X = std::span<int>{p, Ten}; S10.data()) { // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + if (auto X = std::span<int>{p, Ten}; S10.data()) { // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} } auto X = warnVarInit(p); // function return is fine @@ -105,15 +105,15 @@ namespace construct_wt_ptr_size { void foo(const T &, const T &&, T); std::span<int> warnTemp(int *p) { - foo(std::span<int>{p, 10}, // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - std::move(std::span<int>{p, 10}), // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - std::span<int>{p, 10}); // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + foo(std::span<int>{p, 10}, // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::move(std::span<int>{p, 10}), // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<int>{p, 10}); // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - std::span<int> Arr[1] = {std::span<int>{p, 10}}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<int> Arr[1] = {std::span<int>{p, 10}}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - if (std::span<int>{p, 10}.data()) { // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + if (std::span<int>{p, 10}.data()) { // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} } - return std::span<int>{p, 10}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + return std::span<int>{p, 10}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} } // addressof method defined outside std namespace. @@ -131,22 +131,22 @@ namespace construct_wt_ptr_size { typedef int TenInts_t[10]; TenInts_t Arr2; - S = std::span{&X, 2}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - S = std::span{std::addressof(X), 2}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + S = std::span{&X, 2}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + S = std::span{std::addressof(X), 2}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} // Warn when a non std method also named addressof - S = std::span{addressof(X), 1}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + S = std::span{addressof(X), 1}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} S = std::span{new int[10], 10}; // no-warning S = std::span{new int[n], n}; // no-warning S = std::span{new int, 1}; // no-warning - S = std::span{new int, X}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - S = std::span{new int[n--], n--}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - S = std::span{new int[10], 11}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - S = std::span{new int[10], 9}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} // not smart enough to tell its safe - S = std::span{new int[10], Y}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} // not smart enough to tell its safe + S = std::span{new int, X}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + S = std::span{new int[n--], n--}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + S = std::span{new int[10], 11}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + S = std::span{new int[10], 9}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} // not smart enough to tell its safe + S = std::span{new int[10], Y}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} // not smart enough to tell its safe S = std::span{Arr, 10}; // no-warning S = std::span{Arr2, 10}; // no-warning - S = std::span{Arr, Y}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} // not smart enough to tell its safe + S = std::span{Arr, Y}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} // not smart enough to tell its safe S = std::span{p, 0}; // no-warning } } // namespace construct_wt_ptr_size @@ -155,19 +155,19 @@ namespace construct_wt_begin_end { class It {}; std::span<int> warnVarInit(It &First, It &Last) { - std::span<int> S{First, Last}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - std::span<int> S1(First, Last); // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - std::span<int> S2 = std::span<int>{First, Last}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - std::span<int> S3 = std::span<int>(First, Last); // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - std::span<int> S4 = std::span<int>{First, Last}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - std::span<int> S5 = std::span<int>(First, Last); // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - std::span<int> S6 = {First, Last}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - auto S7 = std::span<int>{First, Last}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - auto S8 = std::span<int>(First, Last); // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - const auto &S9 = std::span<int>{First, Last}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - auto &&S10 = std::span<int>(First, Last); // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - - if (auto X = std::span<int>{First, Last}; S10.data()) { // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<int> S{First, Last}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<int> S1(First, Last); // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<int> S2 = std::span<int>{First, Last}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<int> S3 = std::span<int>(First, Last); // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<int> S4 = std::span<int>{First, Last}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<int> S5 = std::span<int>(First, Last); // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<int> S6 = {First, Last}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + auto S7 = std::span<int>{First, Last}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + auto S8 = std::span<int>(First, Last); // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + const auto &S9 = std::span<int>{First, Last}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + auto &&S10 = std::span<int>(First, Last); // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + + if (auto X = std::span<int>{First, Last}; S10.data()) { // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} } auto X = warnVarInit(First, Last); // function return is fine @@ -178,15 +178,15 @@ namespace construct_wt_begin_end { void foo(const T &, const T &&, T); std::span<int> warnTemp(It &First, It &Last) { - foo(std::span<int>{First, Last}, // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - std::move(std::span<int>{First, Last}), // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - std::span<int>{First, Last}); // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + foo(std::span<int>{First, Last}, // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::move(std::span<int>{First, Last}), // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<int>{First, Last}); // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - std::span<int> Arr[1] = {std::span<int>{First, Last}}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<int> Arr[1] = {std::span<int>{First, Last}}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - if (std::span<int>{First, Last}.data()) { // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + if (std::span<int>{First, Last}.data()) { // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} } - return std::span<int>{First, Last}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + return std::span<int>{First, Last}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} } } // namespace construct_wt_begin_end @@ -211,20 +211,20 @@ namespace test_alloc_size_attr { } void unsafe(int x, int y) { - std::span<char>{(char *)my_alloc(10), 11}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - std::span<char>{(char *)my_alloc(x * y), x + y}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - std::span<int>{(int *)my_alloc(x), x}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - std::span<char>{(char *)my_alloc2(x, y), x + y}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<char>{(char *)my_alloc(10), 11}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<char>{(char *)my_alloc(x * y), x + y}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<int>{(int *)my_alloc(x), x}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<char>{(char *)my_alloc2(x, y), x + y}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} } void unsupport(int x, int y, int z) { // Casting to `T*` where sizeof(T) > 1 is not supported yet: - std::span<int>{(int *)my_alloc2(x, y), x * y}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - std::span<long>{(long *)my_alloc(10 * sizeof(long)), 10}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - std::span<long>{(long *)my_alloc2(x, sizeof(long)), x}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - std::span<long>{(long *)my_alloc2(x, sizeof(long)), x}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<int>{(int *)my_alloc2(x, y), x * y}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<long>{(long *)my_alloc(10 * sizeof(long)), 10}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<long>{(long *)my_alloc2(x, sizeof(long)), x}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<long>{(long *)my_alloc2(x, sizeof(long)), x}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} // The expression is too complicated: - std::span<char>{(char *)my_alloc(x + y + z), z + y + x}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<char>{(char *)my_alloc(x + y + z), z + y + x}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} } } @@ -255,14 +255,14 @@ struct HoldsStdSpanAndInitializedInCtor { std::span<char> Span{Ptr, Size}; // no-warning (this code is unreachable) HoldsStdSpanAndInitializedInCtor(char* P, unsigned S) - : Span(P, S) // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + : Span(P, S) // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} {} }; struct HoldsStdSpanAndNotInitializedInCtor { char* Ptr; unsigned Size; - std::span<char> Span{Ptr, Size}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<char> Span{Ptr, Size}; // expected-warning{{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} HoldsStdSpanAndNotInitializedInCtor(char* P, unsigned S) : Ptr(P), Size(S) @@ -283,12 +283,12 @@ namespace test_begin_end { void unsafe_cases(std::span<int> Sp, std::array<int, 10> Arr, std::string Str, std::initializer_list<Object> Il, Object Obj) { - std::span<int>{Obj.begin(), Obj.end()}; // expected-warning {{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - std::span<int>{Sp.end(), Sp.begin()}; // expected-warning {{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} - std::span<int>{Sp.begin(), Arr.end()}; // expected-warning {{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<int>{Obj.begin(), Obj.end()}; // expected-warning {{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<int>{Sp.end(), Sp.begin()}; // expected-warning {{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<int>{Sp.begin(), Arr.end()}; // expected-warning {{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} } void unsupport_cases(std::array<Object, 10> Arr) { - std::span<int>{Arr[0].begin(), Arr[0].end()}; // expected-warning {{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} + std::span<int>{Arr[0].begin(), Arr[0].end()}; // expected-warning {{the two-parameter span construction is unsafe as it can introduce mismatch between buffer size and the bound information}} } } 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..f63986b3f2554 --- /dev/null +++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-string-view.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage-in-container -verify %s + +namespace std { + typedef __SIZE_TYPE__ size_t; + template <typename T> class basic_string_view { + public: + basic_string_view(const T *, size_t); + template <typename It> basic_string_view(It, It); + }; + typedef basic_string_view<char> string_view; + typedef basic_string_view<wchar_t> wstring_view; + template <typename T> class vector { public: T* begin(); T* end(); }; +} + +typedef std::size_t size_t; + +void test_final_coverage() { + std::vector<char> v1, v2; + + // 1. Iterator Pairs + std::string_view it_ok(v1.begin(), v1.end()); // no-warning + // expected-warning@+1 {{the two-parameter std::string_view construction is unsafe}} + std::string_view it_bad(v1.begin(), v2.end()); + + // 2. Character Types + std::string_view s1("hi", 2); // no-warning + // expected-warning@+1 {{the two-parameter std::string_view construction is unsafe}} + std::string_view s2("hi", 3); + + std::wstring_view w1(L"hi", 2); // no-warning + // expected-warning@+1 {{the two-parameter std::string_view construction is unsafe}} + std::wstring_view w2(L"hi", 3); + + // 3. Arrays + char arr[5]; + std::string_view a1(arr, 5); // no-warning + // expected-warning@+1 {{the two-parameter std::string_view construction is unsafe}} + std::string_view a2(arr, 6); + + // 4. Dynamic/Unknown + extern size_t get_size(); + // expected-warning@+1 {{the two-parameter std::string_view construction is unsafe}} + std::string_view d1("hi", get_size()); +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
