Skip to content

Commit c5ded52

Browse files
higuoxingSirraide
andauthored
[clang][Sema] Accept gnu format attributes (#160255)
This patch teaches clang accepts gnu_printf, gnu_scanf, gnu_strftime and gnu_strfmon. These attributes are aliases for printf, scanf, strftime and strfmon. Ref: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html Fixes: #16219 --------- Co-authored-by: Sirraide <aeternalmail@gmail.com>
1 parent 1d46071 commit c5ded52

File tree

7 files changed

+30
-14
lines changed

7 files changed

+30
-14
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,9 @@ Attribute Changes in Clang
272272
attribute, allowing the attribute to only be attached to the declaration. Prior, this would be
273273
treated as an error where the definition and declaration would have differing types.
274274

275+
- New format attributes ``gnu_printf``, ``gnu_scanf``, ``gnu_strftime`` and ``gnu_strfmon`` are added
276+
as aliases for ``printf``, ``scanf``, ``strftime`` and ``strfmon``. (#GH16219)
277+
275278
Improvements to Clang's diagnostics
276279
-----------------------------------
277280
- Added a separate diagnostic group ``-Wfunction-effect-redeclarations``, for the more pedantic

clang/include/clang/Sema/Sema.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,6 @@ enum class FormatStringType {
503503
FreeBSDKPrintf,
504504
OSTrace,
505505
OSLog,
506-
Syslog,
507506
Unknown
508507
};
509508

clang/lib/Sema/SemaChecking.cpp

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6866,11 +6866,12 @@ StringRef Sema::GetFormatStringTypeName(FormatStringType FST) {
68666866

68676867
FormatStringType Sema::GetFormatStringType(StringRef Flavor) {
68686868
return llvm::StringSwitch<FormatStringType>(Flavor)
6869-
.Case("scanf", FormatStringType::Scanf)
6870-
.Cases("printf", "printf0", "syslog", FormatStringType::Printf)
6869+
.Cases("gnu_scanf", "scanf", FormatStringType::Scanf)
6870+
.Cases("gnu_printf", "printf", "printf0", "syslog",
6871+
FormatStringType::Printf)
68716872
.Cases("NSString", "CFString", FormatStringType::NSString)
6872-
.Case("strftime", FormatStringType::Strftime)
6873-
.Case("strfmon", FormatStringType::Strfmon)
6873+
.Cases("gnu_strftime", "strftime", FormatStringType::Strftime)
6874+
.Cases("gnu_strfmon", "strfmon", FormatStringType::Strfmon)
68746875
.Cases("kprintf", "cmn_err", "vcmn_err", "zcmn_err",
68756876
FormatStringType::Kprintf)
68766877
.Case("freebsd_kprintf", FormatStringType::FreeBSDKPrintf)
@@ -6990,7 +6991,6 @@ bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args,
69906991
case FormatStringType::Kprintf:
69916992
case FormatStringType::FreeBSDKPrintf:
69926993
case FormatStringType::Printf:
6993-
case FormatStringType::Syslog:
69946994
Diag(FormatLoc, diag::note_format_security_fixit)
69956995
<< FixItHint::CreateInsertion(FormatLoc, "\"%s\", ");
69966996
break;
@@ -9120,8 +9120,7 @@ static void CheckFormatString(
91209120
if (Type == FormatStringType::Printf || Type == FormatStringType::NSString ||
91219121
Type == FormatStringType::Kprintf ||
91229122
Type == FormatStringType::FreeBSDKPrintf ||
9123-
Type == FormatStringType::OSLog || Type == FormatStringType::OSTrace ||
9124-
Type == FormatStringType::Syslog) {
9123+
Type == FormatStringType::OSLog || Type == FormatStringType::OSTrace) {
91259124
bool IsObjC =
91269125
Type == FormatStringType::NSString || Type == FormatStringType::OSTrace;
91279126
if (ReferenceFormatString == nullptr) {
@@ -9157,8 +9156,7 @@ bool Sema::CheckFormatStringsCompatible(
91579156
if (Type != FormatStringType::Printf && Type != FormatStringType::NSString &&
91589157
Type != FormatStringType::Kprintf &&
91599158
Type != FormatStringType::FreeBSDKPrintf &&
9160-
Type != FormatStringType::OSLog && Type != FormatStringType::OSTrace &&
9161-
Type != FormatStringType::Syslog)
9159+
Type != FormatStringType::OSLog && Type != FormatStringType::OSTrace)
91629160
return true;
91639161

91649162
bool IsObjC =
@@ -9192,8 +9190,7 @@ bool Sema::ValidateFormatString(FormatStringType Type,
91929190
if (Type != FormatStringType::Printf && Type != FormatStringType::NSString &&
91939191
Type != FormatStringType::Kprintf &&
91949192
Type != FormatStringType::FreeBSDKPrintf &&
9195-
Type != FormatStringType::OSLog && Type != FormatStringType::OSTrace &&
9196-
Type != FormatStringType::Syslog)
9193+
Type != FormatStringType::OSLog && Type != FormatStringType::OSTrace)
91979194
return true;
91989195

91999196
FormatStringLiteral RefLit = Str;

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3629,10 +3629,11 @@ static FormatAttrKind getFormatAttrKind(StringRef Format) {
36293629
// Check for formats that get handled specially.
36303630
.Case("NSString", NSStringFormat)
36313631
.Case("CFString", CFStringFormat)
3632-
.Case("strftime", StrftimeFormat)
3632+
.Cases("gnu_strftime", "strftime", StrftimeFormat)
36333633

36343634
// Otherwise, check for supported formats.
3635-
.Cases("scanf", "printf", "printf0", "strfmon", SupportedFormat)
3635+
.Cases("gnu_scanf", "scanf", "gnu_printf", "printf", "printf0",
3636+
"gnu_strfmon", "strfmon", SupportedFormat)
36363637
.Cases("cmn_err", "vcmn_err", "zcmn_err", SupportedFormat)
36373638
.Cases("kprintf", "syslog", SupportedFormat) // OpenBSD.
36383639
.Case("freebsd_kprintf", SupportedFormat) // FreeBSD.

clang/test/Sema/attr-format.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,11 @@ void b2(const char *a, ...) __attribute__((format(syslog, 1, 1))); // expecte
106106
void c2(const char *a, ...) __attribute__((format(syslog, 0, 2))); // expected-error {{'format' attribute parameter 2 is out of bounds}}
107107
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}}
108108
void e2(char *str, int c, ...) __attribute__((format(syslog, 2, 3))); // expected-error {{format argument not a string type}}
109+
110+
// gnu_printf
111+
// same as format(printf(...))...
112+
void a2(const char *a, ...) __attribute__((format(gnu_printf, 1, 2))); // no-error
113+
void b2(const char *a, ...) __attribute__((format(gnu_printf, 1, 1))); // expected-error {{'format' attribute parameter 3 is out of bounds}}
114+
void c2(const char *a, ...) __attribute__((format(gnu_printf, 0, 2))); // expected-error {{'format' attribute parameter 2 is out of bounds}}
115+
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}}
116+
void e2(char *str, int c, ...) __attribute__((format(gnu_printf, 2, 3))); // expected-error {{format argument not a string type}}

clang/test/Sema/format-strings-scanf.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ int fscanf(FILE * restrict, const char * restrict, ...) ;
3030
int scanf(const char * restrict, ...) ;
3131
int sscanf(const char * restrict, const char * restrict, ...) ;
3232
int my_scanf(const char * restrict, ...) __attribute__((__format__(__scanf__, 1, 2)));
33+
int my_gnu_scanf(const char * restrict, ...) __attribute__((__format__(gnu_scanf, 1, 2)));
3334

3435
int vscanf(const char * restrict, va_list);
3536
int vfscanf(FILE * restrict, const char * restrict, va_list);
@@ -98,6 +99,7 @@ void test_variants(int *i, const char *s, ...) {
9899
fscanf(f, "%ld", i); // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}}
99100
sscanf(buf, "%ld", i); // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}}
100101
my_scanf("%ld", i); // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}}
102+
my_gnu_scanf("%ld", i); // expected-warning{{format specifies type 'long *' but the argument has type 'int *'}}
101103

102104
va_list ap;
103105
va_start(ap, s);

clang/test/Sema/format-strings.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,15 +678,21 @@ void pr18905(void) {
678678
}
679679

680680
void __attribute__((format(strfmon,1,2))) monformat(const char *fmt, ...);
681+
void __attribute__((format(gnu_strfmon,1,2))) gnu_monformat(const char *fmt, ...);
681682
void __attribute__((format(strftime,1,0))) dateformat(const char *fmt);
683+
void __attribute__((format(gnu_strftime,1,0))) gnu_dateformat(const char *fmt);
682684

683685
// Other formats
684686
void test_other_formats(void) {
685687
char *str = "";
686688
monformat("", 1); // expected-warning{{format string is empty}}
687689
monformat(str); // expected-warning{{format string is not a string literal (potentially insecure)}}
690+
gnu_monformat("", 1); // expected-warning{{format string is empty}}
691+
gnu_monformat(str); // expected-warning{{format string is not a string literal (potentially insecure)}}
688692
dateformat(""); // expected-warning{{format string is empty}}
689693
dateformat(str); // no-warning (using strftime non-literal is not unsafe)
694+
gnu_dateformat(""); // expected-warning{{format string is empty}}
695+
gnu_dateformat(str); // no-warning (using strftime non-literal is not unsafe)
690696
}
691697

692698
// Do not warn about unused arguments coming from system headers.

0 commit comments

Comments
 (0)