[clang] [Clang][Sema] Add fortify warnings for strlcpy (PR #221325)
Venkatesh Srinivasan via cfe-commits
cfe-commits at lists.llvm.org
Wed Sep 9 12:56:47 PDT 2026
https://github.com/venk-ks updated https://github.com/llvm/llvm-project/pull/221325
>From 7e0e9c6281d2f472783b460ec02e02ad78fd5134 Mon Sep 17 00:00:00 2001
From: Venkatesh Srinivasan <venk at google.com>
Date: Fri, 4 Sep 2026 19:33:15 +0000
Subject: [PATCH 1/2] [Clang][Sema] Add fortify warnings for strlcpy
Add `-Wfortify-source` diagnostics for `strlcpy` and `__builtin_strlcpy`
when the size argument exceeds the destination buffer size.
This is directly analogous to the previous PR for `strlcat` (#220341).
Also update `clang/test/Sema/warn-strlcpycat-size.c` and
`clang/test/Sema/builtins.c` to expect the `-Wfortify-source` warnings
where test calls pass sizes larger than the destination buffer capacity.
Part of #142230
Assisted-by: Gemini
---
clang/docs/ReleaseNotes.md | 6 +++---
clang/include/clang/Basic/Builtins.td | 1 +
clang/lib/AST/Decl.cpp | 3 +++
clang/lib/Sema/SemaChecking.cpp | 4 +++-
clang/test/Sema/builtins.c | 5 +++--
clang/test/Sema/warn-fortify-source.c | 6 ++++++
clang/test/Sema/warn-strlcpycat-size.c | 9 ++++++---
7 files changed, 25 insertions(+), 9 deletions(-)
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index b11e1d28a8b8f..7d354158fd204 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -232,7 +232,7 @@ features cannot lower the translation-unit ABI level;
- Clang now allows GNU computed `goto` extension in `constexpr` functions, matching the relaxed
`constexpr` function body rules introduced in C++23.
-- Added support for the `__builtin_strlcat` builtin.
+- Added support for the `__builtin_strlcat` and `__builtin_strlcpy` builtins.
### New Compiler Flags
@@ -269,8 +269,8 @@ features cannot lower the translation-unit ABI level;
### Improvements to Clang's diagnostics
-- `-Wfortify-source` now diagnoses when `strlcat` or `__builtin_strlcat` is called with a size
- argument larger than the destination buffer.
+- `-Wfortify-source` now diagnoses when `strlcat`, `__builtin_strlcat`, `strlcpy`, or
+ `__builtin_strlcpy` is called with a size argument larger than the destination buffer.
- The `cannot overload a member function` diagnostic now describes the previous
declaration first, matching the order in which the declarations appear in the
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index dc457d4b6ddc8..d148cb4b9101e 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -3912,6 +3912,7 @@ def SigLongJmp : GNULibBuiltin<"setjmp.h"> {
def StrlCpy : GNULibBuiltin<"string.h"> {
let Spellings = ["strlcpy"];
let Prototype = "size_t(char*, char const*, size_t)";
+ let AddBuiltinPrefixedAlias = 1;
}
def StrlCat : GNULibBuiltin<"string.h"> {
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index a620e9f211ca6..d1d296dd60d14 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -4640,6 +4640,7 @@ unsigned FunctionDecl::getMemoryFunctionKind() const {
case Builtin::BImemmove:
return Builtin::BImemmove;
+ case Builtin::BI__builtin_strlcpy:
case Builtin::BIstrlcpy:
case Builtin::BI__builtin___strlcpy_chk:
return Builtin::BIstrlcpy;
@@ -4726,6 +4727,8 @@ unsigned FunctionDecl::getMemoryFunctionKind() const {
return Builtin::BIbcopy;
if (FnInfo->isStr("strlcat"))
return Builtin::BIstrlcat;
+ if (FnInfo->isStr("strlcpy"))
+ return Builtin::BIstrlcpy;
} else if (isInStdNamespace()) {
if (FnInfo->isStr("free"))
return Builtin::BIfree;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index f0a1a529841b2..340729b2439c3 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -1452,7 +1452,9 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
case Builtin::BIstpncpy:
case Builtin::BI__builtin_stpncpy:
case Builtin::BIstrlcat:
- case Builtin::BI__builtin_strlcat: {
+ case Builtin::BI__builtin_strlcat:
+ case Builtin::BIstrlcpy:
+ case Builtin::BI__builtin_strlcpy: {
// Whether these functions overflow depends on the runtime strlen of the
// string, not just the buffer size, so emitting the "always overflow"
// diagnostic isn't quite right. We should still diagnose passing a buffer
diff --git a/clang/test/Sema/builtins.c b/clang/test/Sema/builtins.c
index 5a474909d37e9..e7bf5a43b6b0a 100644
--- a/clang/test/Sema/builtins.c
+++ b/clang/test/Sema/builtins.c
@@ -222,8 +222,9 @@ void Test19(void)
static char b[40];
static char buf[20];
- strlcpy(buf, b, sizeof(b)); // expected-warning {{size argument in 'strlcpy' call appears to be size of the source; expected the size of the destination}} \\
- // expected-note {{change size argument to be the size of the destination}}
+ strlcpy(buf, b, sizeof(b)); // expected-warning {{size argument in 'strlcpy' call appears to be size of the source; expected the size of the destination}} \
+ // expected-note {{change size argument to be the size of the destination}} \
+ // expected-warning {{'strlcpy' size argument is too large; destination buffer has size 20, but size argument is 40}}
__builtin___strlcpy_chk(buf, b, sizeof(b), __builtin_object_size(buf, 0)); // expected-warning {{size argument in '__builtin___strlcpy_chk' call appears to be size of the source; expected the size of the destination}} \
// expected-note {{change size argument to be the size of the destination}} \
// expected-warning {{'strlcpy' will always overflow; destination buffer has size 20, but size argument is 40}}
diff --git a/clang/test/Sema/warn-fortify-source.c b/clang/test/Sema/warn-fortify-source.c
index 77f7e0750e816..8339efddc5b3e 100644
--- a/clang/test/Sema/warn-fortify-source.c
+++ b/clang/test/Sema/warn-fortify-source.c
@@ -75,6 +75,12 @@ void call_strlcat(void) {
__builtin_strlcat(s1, s2, 20); // expected-warning {{'strlcat' size argument is too large; destination buffer has size 10, but size argument is 20}}
}
+void call_strlcpy(void) {
+ char s1[10], s2[20];
+ __builtin_strlcpy(s2, s1, 20);
+ __builtin_strlcpy(s1, s2, 20); // expected-warning {{'strlcpy' size argument is too large; destination buffer has size 10, but size argument is 20}}
+}
+
void call_strcpy(void) {
const char *const src = "abcd";
char dst[4];
diff --git a/clang/test/Sema/warn-strlcpycat-size.c b/clang/test/Sema/warn-strlcpycat-size.c
index c471665e8b672..821b0804d42d3 100644
--- a/clang/test/Sema/warn-strlcpycat-size.c
+++ b/clang/test/Sema/warn-strlcpycat-size.c
@@ -19,12 +19,14 @@ int x;
void f(void)
{
strlcpy(s1, s2, sizeof(s1)); // no warning
- strlcpy(s1, s2, sizeof(s2)); // expected-warning {{size argument in 'strlcpy' call appears to be size of the source; expected the size of the destination}} expected-note {{change size argument to be the size of the destination}}
+ strlcpy(s1, s2, sizeof(s2)); // expected-warning {{size argument in 'strlcpy' call appears to be size of the source; expected the size of the destination}} expected-note {{change size argument to be the size of the destination}} \
+ // expected-warning {{'strlcpy' size argument is too large; destination buffer has size 100, but size argument is 200}}
strlcpy(s1, s3, strlen(s3)+1); // expected-warning {{size argument in 'strlcpy' call appears to be size of the source; expected the size of the destination}} expected-note {{change size argument to be the size of the destination}}
strlcat(s2, s3, sizeof(s3)); // expected-warning {{size argument in 'strlcat' call appears to be size of the source; expected the size of the destination}} expected-note {{change size argument to be the size of the destination}}
strlcpy(s4.f1, s2, sizeof(s2)); // expected-warning {{size argument in 'strlcpy' call appears to be size of the source; expected the size of the destination}} expected-note {{change size argument to be the size of the destination}}
strlcpy((*s5)->f2[x], s2, sizeof(s2)); // expected-warning {{size argument in 'strlcpy' call appears to be size of the source; expected the size of the destination}} expected-note {{change size argument to be the size of the destination}}
- strlcpy(s1+3, s2, sizeof(s2)); // expected-warning {{size argument in 'strlcpy' call appears to be size of the source; expected the size of the destination}}
+ strlcpy(s1+3, s2, sizeof(s2)); // expected-warning {{size argument in 'strlcpy' call appears to be size of the source; expected the size of the destination}} \
+ // expected-warning {{'strlcpy' size argument is too large; destination buffer has size 97, but size argument is 200}}
}
// Don't issue FIXIT for flexible arrays.
@@ -43,7 +45,8 @@ void size_1(void) {
char z[1];
char str[] = "hi";
- strlcpy(z, str, sizeof(str)); // expected-warning {{size argument in 'strlcpy' call appears to be size of the source; expected the size of the destination}}
+ strlcpy(z, str, sizeof(str)); // expected-warning {{size argument in 'strlcpy' call appears to be size of the source; expected the size of the destination}} \
+ // expected-warning {{'strlcpy' size argument is too large; destination buffer has size 1, but size argument is 3}}
}
// Support VLAs.
>From eda7d142de53bf111b7e45967379d9c434495c33 Mon Sep 17 00:00:00 2001
From: Venkatesh Srinivasan <venk at google.com>
Date: Wed, 9 Sep 2026 19:56:32 +0000
Subject: [PATCH 2/2] [NFC] Re-trigger CI
More information about the cfe-commits
mailing list