[clang] [clang][Sema] Accept gnu format attributes (PR #160255)
Xing Guo via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 23 02:01:19 PDT 2025
https://github.com/higuoxing updated https://github.com/llvm/llvm-project/pull/160255
>From a8494656c1f49dd599a8ea39002b47f02d56065c Mon Sep 17 00:00:00 2001
From: Xing Guo <higuoxing at gmail.com>
Date: Tue, 23 Sep 2025 15:58:10 +0800
Subject: [PATCH 1/6] [clang][Sema] Remove unused enum value:
FormatStringType::Syslog.
FormatStringType::Syslog is never instantiated, we can remove it safely.
---
clang/include/clang/Sema/Sema.h | 1 -
clang/lib/Sema/SemaChecking.cpp | 10 +++-------
2 files changed, 3 insertions(+), 8 deletions(-)
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index d017d1f829015..5edfc29d93781 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -503,7 +503,6 @@ enum class FormatStringType {
FreeBSDKPrintf,
OSTrace,
OSLog,
- Syslog,
Unknown
};
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 740b472b0eb16..d44765760acf8 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -6986,7 +6986,6 @@ bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args,
case FormatStringType::Kprintf:
case FormatStringType::FreeBSDKPrintf:
case FormatStringType::Printf:
- case FormatStringType::Syslog:
Diag(FormatLoc, diag::note_format_security_fixit)
<< FixItHint::CreateInsertion(FormatLoc, "\"%s\", ");
break;
@@ -9103,8 +9102,7 @@ static void CheckFormatString(
if (Type == FormatStringType::Printf || Type == FormatStringType::NSString ||
Type == FormatStringType::Kprintf ||
Type == FormatStringType::FreeBSDKPrintf ||
- Type == FormatStringType::OSLog || Type == FormatStringType::OSTrace ||
- Type == FormatStringType::Syslog) {
+ Type == FormatStringType::OSLog || Type == FormatStringType::OSTrace) {
bool IsObjC =
Type == FormatStringType::NSString || Type == FormatStringType::OSTrace;
if (ReferenceFormatString == nullptr) {
@@ -9140,8 +9138,7 @@ bool Sema::CheckFormatStringsCompatible(
if (Type != FormatStringType::Printf && Type != FormatStringType::NSString &&
Type != FormatStringType::Kprintf &&
Type != FormatStringType::FreeBSDKPrintf &&
- Type != FormatStringType::OSLog && Type != FormatStringType::OSTrace &&
- Type != FormatStringType::Syslog)
+ Type != FormatStringType::OSLog && Type != FormatStringType::OSTrace)
return true;
bool IsObjC =
@@ -9175,8 +9172,7 @@ bool Sema::ValidateFormatString(FormatStringType Type,
if (Type != FormatStringType::Printf && Type != FormatStringType::NSString &&
Type != FormatStringType::Kprintf &&
Type != FormatStringType::FreeBSDKPrintf &&
- Type != FormatStringType::OSLog && Type != FormatStringType::OSTrace &&
- Type != FormatStringType::Syslog)
+ Type != FormatStringType::OSLog && Type != FormatStringType::OSTrace)
return true;
FormatStringLiteral RefLit = Str;
>From 52732005f70d5a71dae091e80ced4017e440e386 Mon Sep 17 00:00:00 2001
From: Xing Guo <higuoxing at gmail.com>
Date: Tue, 23 Sep 2025 16:00:25 +0800
Subject: [PATCH 2/6] [clang][Sema] Accept gnu format attribtues.
This patch teaches clang accepts gnu_printf, gnu_scanf and gnu_strftime.
These attributes are aliases for printf, scanf and strftime.
Ref: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html
---
clang/lib/Sema/SemaChecking.cpp | 6 +++---
clang/lib/Sema/SemaDeclAttr.cpp | 4 ++--
clang/test/Sema/attr-format.c | 8 ++++++++
clang/test/Sema/format-strings-scanf.c | 2 ++
clang/test/Sema/format-strings.c | 3 +++
5 files changed, 18 insertions(+), 5 deletions(-)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index d44765760acf8..614a7ba36a623 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -6862,10 +6862,10 @@ StringRef Sema::GetFormatStringTypeName(FormatStringType FST) {
FormatStringType Sema::GetFormatStringType(StringRef Flavor) {
return llvm::StringSwitch<FormatStringType>(Flavor)
- .Case("scanf", FormatStringType::Scanf)
- .Cases("printf", "printf0", "syslog", FormatStringType::Printf)
+ .Cases("gnu_scanf", "scanf", FormatStringType::Scanf)
+ .Cases("gnu_printf", "printf", "printf0", "syslog", FormatStringType::Printf)
.Cases("NSString", "CFString", FormatStringType::NSString)
- .Case("strftime", FormatStringType::Strftime)
+ .Cases("gnu_strftime", "strftime", FormatStringType::Strftime)
.Case("strfmon", FormatStringType::Strfmon)
.Cases("kprintf", "cmn_err", "vcmn_err", "zcmn_err",
FormatStringType::Kprintf)
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index b876911384f6f..1f19931b74be6 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -3629,10 +3629,10 @@ static FormatAttrKind getFormatAttrKind(StringRef Format) {
// Check for formats that get handled specially.
.Case("NSString", NSStringFormat)
.Case("CFString", CFStringFormat)
- .Case("strftime", StrftimeFormat)
+ .Cases("gnu_strftime", "strftime", StrftimeFormat)
// Otherwise, check for supported formats.
- .Cases("scanf", "printf", "printf0", "strfmon", SupportedFormat)
+ .Cases("gnu_scanf", "scanf", "gnu_printf", "printf", "printf0", "strfmon", SupportedFormat)
.Cases("cmn_err", "vcmn_err", "zcmn_err", SupportedFormat)
.Cases("kprintf", "syslog", SupportedFormat) // OpenBSD.
.Case("freebsd_kprintf", SupportedFormat) // FreeBSD.
diff --git a/clang/test/Sema/attr-format.c b/clang/test/Sema/attr-format.c
index 5b9e4d02bbaf9..de6a99b15780e 100644
--- a/clang/test/Sema/attr-format.c
+++ b/clang/test/Sema/attr-format.c
@@ -106,3 +106,11 @@ void b2(const char *a, ...) __attribute__((format(syslog, 1, 1))); // expecte
void c2(const char *a, ...) __attribute__((format(syslog, 0, 2))); // expected-error {{'format' attribute parameter 2 is out of bounds}}
void d2(const char *a, int c) __attribute__((format(syslog, 1, 2))); // expected-warning {{GCC requires a function with the 'format' attribute to be variadic}}
void e2(char *str, int c, ...) __attribute__((format(syslog, 2, 3))); // expected-error {{format argument not a string type}}
+
+// gnu_printf
+// same as format(pritf(...))...
+void a2(const char *a, ...) __attribute__((format(gnu_printf, 1, 2))); // no-error
+void b2(const char *a, ...) __attribute__((format(gnu_printf, 1, 1))); // expected-error {{'format' attribute parameter 3 is out of bounds}}
+void c2(const char *a, ...) __attribute__((format(gnu_printf, 0, 2))); // expected-error {{'format' attribute parameter 2 is out of bounds}}
+void d2(const char *a, int c) __attribute__((format(gnu_printf, 1, 2))); // expected-warning {{GCC requires a function with the 'format' attribute to be variadic}}
+void e2(char *str, int c, ...) __attribute__((format(gnu_printf, 2, 3))); // expected-error {{format argument not a string type}}
diff --git a/clang/test/Sema/format-strings-scanf.c b/clang/test/Sema/format-strings-scanf.c
index d1f694f3595cf..22c1cce2f989b 100644
--- a/clang/test/Sema/format-strings-scanf.c
+++ b/clang/test/Sema/format-strings-scanf.c
@@ -30,6 +30,7 @@ int fscanf(FILE * restrict, const char * restrict, ...) ;
int scanf(const char * restrict, ...) ;
int sscanf(const char * restrict, const char * restrict, ...) ;
int my_scanf(const char * restrict, ...) __attribute__((__format__(__scanf__, 1, 2)));
+int my_gnu_scanf(const char * restrict, ...) __attribute__((__format__(gnu_scanf, 1, 2)));
int vscanf(const char * restrict, va_list);
int vfscanf(FILE * restrict, const char * restrict, va_list);
@@ -98,6 +99,7 @@ void test_variants(int *i, const char *s, ...) {
fscanf(f, "%ld", i); // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}}
sscanf(buf, "%ld", i); // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}}
my_scanf("%ld", i); // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}}
+ my_gnu_scanf("%ld", i); // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}}
va_list ap;
va_start(ap, s);
diff --git a/clang/test/Sema/format-strings.c b/clang/test/Sema/format-strings.c
index 4bff30c313c8f..4a2ee8900bb5a 100644
--- a/clang/test/Sema/format-strings.c
+++ b/clang/test/Sema/format-strings.c
@@ -679,6 +679,7 @@ void pr18905(void) {
void __attribute__((format(strfmon,1,2))) monformat(const char *fmt, ...);
void __attribute__((format(strftime,1,0))) dateformat(const char *fmt);
+void __attribute__((format(gnu_strftime,1,0))) gnu_dateformat(const char *fmt);
// Other formats
void test_other_formats(void) {
@@ -687,6 +688,8 @@ void test_other_formats(void) {
monformat(str); // expected-warning{{format string is not a string literal (potentially insecure)}}
dateformat(""); // expected-warning{{format string is empty}}
dateformat(str); // no-warning (using strftime non-literal is not unsafe)
+ gnu_dateformat(""); // expected-warning{{format string is empty}}
+ gnu_dateformat(str); // no-warning (using strftime non-literal is not unsafe)
}
// Do not warn about unused arguments coming from system headers.
>From 1850aa9453393524124e1cc26188489c3ac51c48 Mon Sep 17 00:00:00 2001
From: Xing Guo <higuoxing+github at gmail.com>
Date: Tue, 23 Sep 2025 16:30:03 +0800
Subject: [PATCH 3/6] Update clang/test/Sema/attr-format.c
Co-authored-by: Sirraide <aeternalmail at gmail.com>
---
clang/test/Sema/attr-format.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/test/Sema/attr-format.c b/clang/test/Sema/attr-format.c
index de6a99b15780e..820abd8ec527e 100644
--- a/clang/test/Sema/attr-format.c
+++ b/clang/test/Sema/attr-format.c
@@ -108,7 +108,7 @@ void d2(const char *a, int c) __attribute__((format(syslog, 1, 2))); // expecte
void e2(char *str, int c, ...) __attribute__((format(syslog, 2, 3))); // expected-error {{format argument not a string type}}
// gnu_printf
-// same as format(pritf(...))...
+// same as format(printf(...))...
void a2(const char *a, ...) __attribute__((format(gnu_printf, 1, 2))); // no-error
void b2(const char *a, ...) __attribute__((format(gnu_printf, 1, 1))); // expected-error {{'format' attribute parameter 3 is out of bounds}}
void c2(const char *a, ...) __attribute__((format(gnu_printf, 0, 2))); // expected-error {{'format' attribute parameter 2 is out of bounds}}
>From 31a4be797eab967f117ede033e6f6f78058faf19 Mon Sep 17 00:00:00 2001
From: Xing Guo <higuoxing at gmail.com>
Date: Tue, 23 Sep 2025 16:34:14 +0800
Subject: [PATCH 4/6] Add gnu_strfmon.
---
clang/lib/Sema/SemaChecking.cpp | 2 +-
clang/lib/Sema/SemaDeclAttr.cpp | 2 +-
clang/test/Sema/format-strings.c | 3 +++
3 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 614a7ba36a623..7c59ed38486bb 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -6866,7 +6866,7 @@ FormatStringType Sema::GetFormatStringType(StringRef Flavor) {
.Cases("gnu_printf", "printf", "printf0", "syslog", FormatStringType::Printf)
.Cases("NSString", "CFString", FormatStringType::NSString)
.Cases("gnu_strftime", "strftime", FormatStringType::Strftime)
- .Case("strfmon", FormatStringType::Strfmon)
+ .Cases("gnu_strfmon", "strfmon", FormatStringType::Strfmon)
.Cases("kprintf", "cmn_err", "vcmn_err", "zcmn_err",
FormatStringType::Kprintf)
.Case("freebsd_kprintf", FormatStringType::FreeBSDKPrintf)
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 1f19931b74be6..f311a5148acf1 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -3632,7 +3632,7 @@ static FormatAttrKind getFormatAttrKind(StringRef Format) {
.Cases("gnu_strftime", "strftime", StrftimeFormat)
// Otherwise, check for supported formats.
- .Cases("gnu_scanf", "scanf", "gnu_printf", "printf", "printf0", "strfmon", SupportedFormat)
+ .Cases("gnu_scanf", "scanf", "gnu_printf", "printf", "printf0", "gnu_strfmon", "strfmon", SupportedFormat)
.Cases("cmn_err", "vcmn_err", "zcmn_err", SupportedFormat)
.Cases("kprintf", "syslog", SupportedFormat) // OpenBSD.
.Case("freebsd_kprintf", SupportedFormat) // FreeBSD.
diff --git a/clang/test/Sema/format-strings.c b/clang/test/Sema/format-strings.c
index 4a2ee8900bb5a..103dd8ab5a85c 100644
--- a/clang/test/Sema/format-strings.c
+++ b/clang/test/Sema/format-strings.c
@@ -678,6 +678,7 @@ void pr18905(void) {
}
void __attribute__((format(strfmon,1,2))) monformat(const char *fmt, ...);
+void __attribute__((format(gnu_strfmon,1,2))) gnu_monformat(const char *fmt, ...);
void __attribute__((format(strftime,1,0))) dateformat(const char *fmt);
void __attribute__((format(gnu_strftime,1,0))) gnu_dateformat(const char *fmt);
@@ -686,6 +687,8 @@ void test_other_formats(void) {
char *str = "";
monformat("", 1); // expected-warning{{format string is empty}}
monformat(str); // expected-warning{{format string is not a string literal (potentially insecure)}}
+ gnu_monformat("", 1); // expected-warning{{format string is empty}}
+ gnu_monformat(str); // expected-warning{{format string is not a string literal (potentially insecure)}}
dateformat(""); // expected-warning{{format string is empty}}
dateformat(str); // no-warning (using strftime non-literal is not unsafe)
gnu_dateformat(""); // expected-warning{{format string is empty}}
>From dc12a9aa12600ff0cc73421c24cbd153e96c8e1f Mon Sep 17 00:00:00 2001
From: Xing Guo <higuoxing at gmail.com>
Date: Tue, 23 Sep 2025 16:55:36 +0800
Subject: [PATCH 5/6] Add release notes.
---
clang/docs/ReleaseNotes.rst | 3 +++
1 file changed, 3 insertions(+)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 70c82b090107a..07d0e09a74564 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -268,6 +268,9 @@ Attribute Changes in Clang
attribute, allowing the attribute to only be attached to the declaration. Prior, this would be
treated as an error where the definition and declaration would have differing types.
+- New format attributes ``gnu_printf``, ``gnu_scanf``, ``gnu_strftime`` and ``gnu_strfmon`` are added
+ as aliases for ``printf``, ``scanf``, ``strftime`` and ``strfmon``.
+
Improvements to Clang's diagnostics
-----------------------------------
- Added a separate diagnostic group ``-Wfunction-effect-redeclarations``, for the more pedantic
>From e8893ed1532e243340bfbd7e9e93a97c7e75a372 Mon Sep 17 00:00:00 2001
From: Xing Guo <higuoxing at gmail.com>
Date: Tue, 23 Sep 2025 16:57:59 +0800
Subject: [PATCH 6/6] Apply clang-format
---
clang/lib/Sema/SemaChecking.cpp | 3 ++-
clang/lib/Sema/SemaDeclAttr.cpp | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 7c59ed38486bb..08ba6c216193e 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -6863,7 +6863,8 @@ StringRef Sema::GetFormatStringTypeName(FormatStringType FST) {
FormatStringType Sema::GetFormatStringType(StringRef Flavor) {
return llvm::StringSwitch<FormatStringType>(Flavor)
.Cases("gnu_scanf", "scanf", FormatStringType::Scanf)
- .Cases("gnu_printf", "printf", "printf0", "syslog", FormatStringType::Printf)
+ .Cases("gnu_printf", "printf", "printf0", "syslog",
+ FormatStringType::Printf)
.Cases("NSString", "CFString", FormatStringType::NSString)
.Cases("gnu_strftime", "strftime", FormatStringType::Strftime)
.Cases("gnu_strfmon", "strfmon", FormatStringType::Strfmon)
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index f311a5148acf1..a8dfa4d7df2d5 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -3632,7 +3632,8 @@ static FormatAttrKind getFormatAttrKind(StringRef Format) {
.Cases("gnu_strftime", "strftime", StrftimeFormat)
// Otherwise, check for supported formats.
- .Cases("gnu_scanf", "scanf", "gnu_printf", "printf", "printf0", "gnu_strfmon", "strfmon", SupportedFormat)
+ .Cases("gnu_scanf", "scanf", "gnu_printf", "printf", "printf0",
+ "gnu_strfmon", "strfmon", SupportedFormat)
.Cases("cmn_err", "vcmn_err", "zcmn_err", SupportedFormat)
.Cases("kprintf", "syslog", SupportedFormat) // OpenBSD.
.Case("freebsd_kprintf", SupportedFormat) // FreeBSD.
More information about the cfe-commits
mailing list