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 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 <[email protected]> Date: Wed, 9 Sep 2026 19:56:32 +0000 Subject: [PATCH 2/2] [NFC] Re-trigger CI _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
