Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,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``. (#GH16219)

Improvements to Clang's diagnostics
-----------------------------------
- Added a separate diagnostic group ``-Wfunction-effect-redeclarations``, for the more pedantic
Expand Down
1 change: 0 additions & 1 deletion clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,6 @@ enum class FormatStringType {
FreeBSDKPrintf,
OSTrace,
OSLog,
Syslog,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is not really explained. It feels like a drive by fix, which we usually discourage.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I fixed it by a separate commit. When merging this PR, commits are squashed and I forget to write a commit message for this change. Shall I revert this part of change?

Unknown
};

Expand Down
19 changes: 8 additions & 11 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6866,11 +6866,12 @@ 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)
.Case("strfmon", FormatStringType::Strfmon)
.Cases("gnu_strftime", "strftime", FormatStringType::Strftime)
.Cases("gnu_strfmon", "strfmon", FormatStringType::Strfmon)
.Cases("kprintf", "cmn_err", "vcmn_err", "zcmn_err",
FormatStringType::Kprintf)
.Case("freebsd_kprintf", FormatStringType::FreeBSDKPrintf)
Expand Down Expand Up @@ -6990,7 +6991,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;
Expand Down Expand Up @@ -9120,8 +9120,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) {
Expand Down Expand Up @@ -9157,8 +9156,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 =
Expand Down Expand Up @@ -9192,8 +9190,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;
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3629,10 +3629,11 @@ 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",
"gnu_strfmon", "strfmon", SupportedFormat)
.Cases("cmn_err", "vcmn_err", "zcmn_err", SupportedFormat)
.Cases("kprintf", "syslog", SupportedFormat) // OpenBSD.
.Case("freebsd_kprintf", SupportedFormat) // FreeBSD.
Expand Down
8 changes: 8 additions & 0 deletions clang/test/Sema/attr-format.c
Original file line number Diff line number Diff line change
Expand Up @@ -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(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}}
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}}
2 changes: 2 additions & 0 deletions clang/test/Sema/format-strings-scanf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
6 changes: 6 additions & 0 deletions clang/test/Sema/format-strings.c
Original file line number Diff line number Diff line change
Expand Up @@ -678,15 +678,21 @@ 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);

// Other formats
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}}
gnu_dateformat(str); // no-warning (using strftime non-literal is not unsafe)
}

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