[clang] [-Wunsafe-buffer-usage] Allow strerror for %s in printf-like calls (PR #175208)
Hans Wennborg via cfe-commits
cfe-commits at lists.llvm.org
Fri Jan 9 13:59:48 PST 2026
https://github.com/zmodem updated https://github.com/llvm/llvm-project/pull/175208
>From 39dcae4284d0d83ce236f3c2be24e0b71a3da294 Mon Sep 17 00:00:00 2001
From: Hans Wennborg <hans at chromium.org>
Date: Fri, 9 Jan 2026 18:23:57 +0100
Subject: [PATCH 1/4] [-Wunsafe-buffer-usage] Allow strerror for %s in
printf-like calls
Passing strerror(errno) to printf of printf-like logging functions is a
common pattern, and strerror() returns a null-terminated string.
Follow-up to #173096
---
clang/lib/Analysis/UnsafeBufferUsage.cpp | 5 +++++
.../test/SemaCXX/warn-unsafe-buffer-usage-libc-functions.cpp | 4 ++++
2 files changed, 9 insertions(+)
diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index 7c0eaa2e589f5..4614a586565cb 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -771,6 +771,11 @@ static bool isNullTermPointer(const Expr *Ptr, ASTContext &Ctx) {
if (MD->getName() == "c_str" && RD->getName() == "basic_string")
return true;
}
+ if (auto *CE = dyn_cast<CallExpr>(Ptr->IgnoreParenImpCasts())) {
+ const FunctionDecl *F = CE->getDirectCallee();
+ if (F && F->getName() == "strerror")
+ return true;
+ }
return false;
}
diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-libc-functions.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-libc-functions.cpp
index d824463ad9618..fe9bc7c809c96 100644
--- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-libc-functions.cpp
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-libc-functions.cpp
@@ -298,6 +298,10 @@ void test_format_attr(char * Str, std::string StdStr) {
myprintf("hello %s", Str); // expected-warning{{function 'myprintf' is unsafe}} \
expected-note{{string argument is not guaranteed to be null-terminated}}
+ extern int errno;
+ extern char *strerror(int errnum);
+ myprintf("errno: %s", strerror(errno));
+
myprintf_2("hello", 0, Str);
myprintf_2("hello %s", 0, StdStr.c_str());
myprintf_2("hello %s", 0, Str); // expected-warning{{function 'myprintf_2' is unsafe}} \
>From 2ed05acd7836aced4b83b4b09180eeca8dec444d Mon Sep 17 00:00:00 2001
From: Hans Wennborg <hans at chromium.org>
Date: Fri, 9 Jan 2026 19:52:18 +0100
Subject: [PATCH 2/4] try not to crash
---
clang/lib/Analysis/UnsafeBufferUsage.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index 4614a586565cb..0631c76c2b8d4 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -773,7 +773,7 @@ static bool isNullTermPointer(const Expr *Ptr, ASTContext &Ctx) {
}
if (auto *CE = dyn_cast<CallExpr>(Ptr->IgnoreParenImpCasts())) {
const FunctionDecl *F = CE->getDirectCallee();
- if (F && F->getName() == "strerror")
+ if (F && F->getIdentifier() && F->getName() == "strerror")
return true;
}
return false;
>From 28fb8761393853390c4142191e4ba6c6df44602f Mon Sep 17 00:00:00 2001
From: Hans Wennborg <hans at chromium.org>
Date: Fri, 9 Jan 2026 22:48:59 +0100
Subject: [PATCH 3/4] use a StringSet
---
clang/lib/Analysis/UnsafeBufferUsage.cpp | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index 0631c76c2b8d4..46cbcbaa96990 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -771,9 +771,14 @@ static bool isNullTermPointer(const Expr *Ptr, ASTContext &Ctx) {
if (MD->getName() == "c_str" && RD->getName() == "basic_string")
return true;
}
+
+ // Functions known to return properly null terminated strings.
+ static const llvm::StringSet<> NullTermFunctions = {
+ "strerror"
+ };
if (auto *CE = dyn_cast<CallExpr>(Ptr->IgnoreParenImpCasts())) {
const FunctionDecl *F = CE->getDirectCallee();
- if (F && F->getIdentifier() && F->getName() == "strerror")
+ if (F && F->getIdentifier() && NullTermFunctions.contains(F->getName()))
return true;
}
return false;
>From 6eec7884b8978439f0172f14b908c47df2dcf6c5 Mon Sep 17 00:00:00 2001
From: Hans Wennborg <hans at chromium.org>
Date: Fri, 9 Jan 2026 22:59:36 +0100
Subject: [PATCH 4/4] format
---
clang/lib/Analysis/UnsafeBufferUsage.cpp | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index 46cbcbaa96990..c7a5988445aa1 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -773,9 +773,7 @@ static bool isNullTermPointer(const Expr *Ptr, ASTContext &Ctx) {
}
// Functions known to return properly null terminated strings.
- static const llvm::StringSet<> NullTermFunctions = {
- "strerror"
- };
+ static const llvm::StringSet<> NullTermFunctions = {"strerror"};
if (auto *CE = dyn_cast<CallExpr>(Ptr->IgnoreParenImpCasts())) {
const FunctionDecl *F = CE->getDirectCallee();
if (F && F->getIdentifier() && NullTermFunctions.contains(F->getName()))
More information about the cfe-commits
mailing list