[clang] [Clang][UnsafeBufferUsage] Warn about two-arg string_view constructors. (PR #180471)
Prajwal P J via cfe-commits
cfe-commits at lists.llvm.org
Tue Mar 3 01:41:11 PST 2026
https://github.com/pjalwadi updated https://github.com/llvm/llvm-project/pull/180471
>From 85658a17bd54a9c6162fddd122688e3694a75bc4 Mon Sep 17 00:00:00 2001
From: prajwal jalwadi <prajwaljalwadi at gmail.com>
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 | 35 ++++-
.../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, 285 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..fb014a6a8e5fa 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,29 @@ 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 at +1{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
+ //expected-warning at +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 at +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 at +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 at +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 at +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 at +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 at +1 {{the two-parameter std::string_view construction is unsafe}}
+ std::string_view d1("hi", get_size());
+}
More information about the cfe-commits
mailing list