Author: Venkatesh Srinivasan
Date: 2026-09-04T09:50:14-07:00
New Revision: c8fbd8226a3717c1f9de8c0270b6f4d57f046f1e

URL: 
https://github.com/llvm/llvm-project/commit/c8fbd8226a3717c1f9de8c0270b6f4d57f046f1e
DIFF: 
https://github.com/llvm/llvm-project/commit/c8fbd8226a3717c1f9de8c0270b6f4d57f046f1e.diff

LOG: [Clang][Sema] Add fortify warnings for strlcat (#220341)

Add `-Wfortify-source` diagnostics for `strlcat` and `__builtin_strlcat`
when the size argument exceeds the destination buffer size.

Also add `-Wno-fortify-source` to `clang/test/Analysis/cstring-syntax.c`
to prevent the new compiler diagnostic from interfering with static
analyzer checks on intentionally underflowing test expressions.

Part of #142230

Assisted-by: Gemini

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.md
    clang/include/clang/Basic/Builtins.td
    clang/lib/AST/Decl.cpp
    clang/lib/Sema/SemaChecking.cpp
    clang/test/Analysis/cstring-syntax.c
    clang/test/Sema/builtins.c
    clang/test/Sema/warn-fortify-source.c

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index ca5c63fbaa17d..b11e1d28a8b8f 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -232,6 +232,8 @@ 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.
+
 ### New Compiler Flags
 
 - New option `-fdefined-pointer-subtraction` added to preserve stable semantics
@@ -267,6 +269,9 @@ 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.
+
 - The `cannot overload a member function` diagnostic now describes the previous
   declaration first, matching the order in which the declarations appear in the
   source. (#GH219803)

diff  --git a/clang/include/clang/Basic/Builtins.td 
b/clang/include/clang/Basic/Builtins.td
index fe6f41fe00345..dc457d4b6ddc8 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -3917,6 +3917,7 @@ def StrlCpy : GNULibBuiltin<"string.h"> {
 def StrlCat : GNULibBuiltin<"string.h"> {
   let Spellings = ["strlcat"];
   let Prototype = "size_t(char*, char const*, size_t)";
+  let AddBuiltinPrefixedAlias = 1;
 }
 
 def ObjcMsgSend : ObjCLibBuiltin<"objc_message.h"> {

diff  --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 03eb04d53cdf4..a620e9f211ca6 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -4644,6 +4644,7 @@ unsigned FunctionDecl::getMemoryFunctionKind() const {
   case Builtin::BI__builtin___strlcpy_chk:
     return Builtin::BIstrlcpy;
 
+  case Builtin::BI__builtin_strlcat:
   case Builtin::BIstrlcat:
   case Builtin::BI__builtin___strlcat_chk:
     return Builtin::BIstrlcat;
@@ -4723,6 +4724,8 @@ unsigned FunctionDecl::getMemoryFunctionKind() const {
         return Builtin::BIbzero;
       if (FnInfo->isStr("bcopy"))
         return Builtin::BIbcopy;
+      if (FnInfo->isStr("strlcat"))
+        return Builtin::BIstrlcat;
     } 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 564369da4ddea..f0a1a529841b2 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -1450,7 +1450,9 @@ void 
Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
   case Builtin::BIstrncpy:
   case Builtin::BI__builtin_strncpy:
   case Builtin::BIstpncpy:
-  case Builtin::BI__builtin_stpncpy: {
+  case Builtin::BI__builtin_stpncpy:
+  case Builtin::BIstrlcat:
+  case Builtin::BI__builtin_strlcat: {
     // 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/Analysis/cstring-syntax.c 
b/clang/test/Analysis/cstring-syntax.c
index 8ac971fe24127..e992d3f809336 100644
--- a/clang/test/Analysis/cstring-syntax.c
+++ b/clang/test/Analysis/cstring-syntax.c
@@ -1,18 +1,19 @@
 // RUN: %clang_analyze_cc1 -analyzer-checker=unix.cstring.BadSizeArg -verify 
%s\
 // RUN:                    -Wno-strncat-size -Wno-sizeof-pointer-memaccess     
\
-// RUN:                    -Wno-strlcpy-strlcat-size -Wno-sizeof-array-argument
+// RUN:                    -Wno-strlcpy-strlcat-size 
-Wno-sizeof-array-argument\
+// RUN:                    -Wno-fortify-source
 // RUN: %clang_analyze_cc1 -analyzer-checker=unix.cstring.BadSizeArg -verify 
%s\
 // RUN:                    -Wno-strncat-size -Wno-sizeof-pointer-memaccess     
\
 // RUN:                    -Wno-strlcpy-strlcat-size 
-Wno-sizeof-array-argument\
-// RUN:                    -triple armv7-a15-linux
+// RUN:                    -Wno-fortify-source -triple armv7-a15-linux
 // RUN: %clang_analyze_cc1 -analyzer-checker=unix.cstring.BadSizeArg -verify 
%s\
 // RUN:                    -Wno-strncat-size -Wno-sizeof-pointer-memaccess     
\
 // RUN:                    -Wno-strlcpy-strlcat-size 
-Wno-sizeof-array-argument\
-// RUN:                    -triple aarch64_be-none-linux-gnu
+// RUN:                    -Wno-fortify-source -triple 
aarch64_be-none-linux-gnu
 // RUN: %clang_analyze_cc1 -analyzer-checker=unix.cstring.BadSizeArg -verify 
%s\
 // RUN:                    -Wno-strncat-size -Wno-sizeof-pointer-memaccess     
\
 // RUN:                    -Wno-strlcpy-strlcat-size 
-Wno-sizeof-array-argument\
-// RUN:                    -triple i386-apple-darwin10
+// RUN:                    -Wno-fortify-source -triple i386-apple-darwin10
 
 typedef __SIZE_TYPE__ size_t;
 char  *strncat(char *, const char *, size_t);

diff  --git a/clang/test/Sema/builtins.c b/clang/test/Sema/builtins.c
index b669ee68cdd95..5a474909d37e9 100644
--- a/clang/test/Sema/builtins.c
+++ b/clang/test/Sema/builtins.c
@@ -229,7 +229,8 @@ void Test19(void)
                                    // expected-warning {{'strlcpy' will always 
overflow; destination buffer has size 20, but size argument is 40}}
 
         strlcat(buf, b, sizeof(b)); // 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}}
+                                    // expected-note {{change size argument to 
be the size of the destination}} \
+                                    // expected-warning {{'strlcat' size 
argument is too large; destination buffer has size 20, but size argument is 40}}
 
         __builtin___strlcat_chk(buf, b, sizeof(b), __builtin_object_size(buf, 
0)); // expected-warning {{size argument in '__builtin___strlcat_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}} 
\

diff  --git a/clang/test/Sema/warn-fortify-source.c 
b/clang/test/Sema/warn-fortify-source.c
index 0a6c44f59af9e..77f7e0750e816 100644
--- a/clang/test/Sema/warn-fortify-source.c
+++ b/clang/test/Sema/warn-fortify-source.c
@@ -69,6 +69,12 @@ void call_stpncpy(void) {
   __builtin_stpncpy(s1, s2, 20); // expected-warning {{'stpncpy' size argument 
is too large; destination buffer has size 10, but size argument is 20}}
 }
 
+void call_strlcat(void) {
+  char s1[10], s2[20];
+  __builtin_strlcat(s2, s1, 20);
+  __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_strcpy(void) {
   const char *const src = "abcd";
   char dst[4];


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

Reply via email to