[clang] Add a fortify warning for literal strcpy overflow (PR #190448)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Apr 4 00:17:49 PDT 2026
https://github.com/Pppp1116 created https://github.com/llvm/llvm-project/pull/190448
None
>From 62726850715f8d97ba74858638345433c3ba8d43 Mon Sep 17 00:00:00 2001
From: Pppp1116 <pcaiadoguerreiro at gmail.com>
Date: Sat, 4 Apr 2026 08:06:21 +0100
Subject: [PATCH] Add a fortify warning for literal strcpy overflow
---
clang/include/clang/Basic/DiagnosticSemaKinds.td | 4 ++++
clang/lib/Sema/SemaChecking.cpp | 16 ++++++++++++++++
.../Sema/warn-fortify-literal-copy-overflow.c | 10 ++++++++++
3 files changed, 30 insertions(+)
create mode 100644 clang/test/Sema/warn-fortify-literal-copy-overflow.c
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index eddf9c50033e1..086a88eba6e1b 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -965,6 +965,10 @@ def warn_fortify_strlen_overflow: Warning<
" but the source string has length %2 (including NUL byte)">,
InGroup<FortifySource>;
+def warn_fortify_literal_copy_too_large : Warning<
+ "copying %0 bytes into buffer of size %1 (including null terminator)">,
+ InGroup<FortifySource>;
+
def subst_format_overflow : TextSubstitution<
"'%0' will always overflow; destination buffer has size %1,"
" but format string expands to at least %2">;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index de8b965144971..974607648b939 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -1247,6 +1247,7 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
std::optional<llvm::APSInt> DestinationSize;
unsigned DiagID = 0;
bool IsChkVariant = false;
+ bool UseLiteralCopyOverflowDiag = false;
auto GetFunctionName = [&]() {
std::string FunctionNameStr =
@@ -1276,6 +1277,10 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
DiagID = diag::warn_fortify_strlen_overflow;
SourceSize = ComputeStrLenArgument(1);
DestinationSize = ComputeSizeArgument(0);
+ UseLiteralCopyOverflowDiag =
+ (BuiltinID == Builtin::BI__builtin_strcpy ||
+ BuiltinID == Builtin::BIstrcpy) &&
+ isa<StringLiteral>(TheCall->getArg(1)->IgnoreParenCasts());
break;
}
@@ -1286,6 +1291,9 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
SourceSize = ComputeStrLenArgument(1);
DestinationSize = ComputeExplicitObjectSizeArgument(2);
IsChkVariant = true;
+ UseLiteralCopyOverflowDiag =
+ BuiltinID == Builtin::BI__builtin___strcpy_chk &&
+ isa<StringLiteral>(TheCall->getArg(1)->IgnoreParenCasts());
break;
}
@@ -1470,6 +1478,14 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
SmallString<16> SourceStr;
DestinationSize->toString(DestinationStr, /*Radix=*/10);
SourceSize->toString(SourceStr, /*Radix=*/10);
+
+ if (UseLiteralCopyOverflowDiag) {
+ DiagRuntimeBehavior(TheCall->getBeginLoc(), TheCall,
+ PDiag(diag::warn_fortify_literal_copy_too_large)
+ << SourceStr << DestinationStr);
+ return;
+ }
+
DiagRuntimeBehavior(TheCall->getBeginLoc(), TheCall,
PDiag(DiagID)
<< FunctionName << DestinationStr << SourceStr);
diff --git a/clang/test/Sema/warn-fortify-literal-copy-overflow.c b/clang/test/Sema/warn-fortify-literal-copy-overflow.c
new file mode 100644
index 0000000000000..c3e96dbae217c
--- /dev/null
+++ b/clang/test/Sema/warn-fortify-literal-copy-overflow.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fsyntax-only -Wfortify-source -verify %s
+
+char *strcpy(char *, const char *);
+
+void literal_strcpy_overflow(void) {
+ char buf[4];
+ char ok[5];
+ strcpy(buf, "abcd"); // expected-warning{{copying 5 bytes into buffer of size 4 (including null terminator)}}
+ strcpy(ok, "abcd");
+}
More information about the cfe-commits
mailing list