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 <[email protected]>
Date: Fri, 4 Sep 2026 19:33:15 +0000
Subject: [PATCH] [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.

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to