Skip to content

Commit c628e8e

Browse files
[clang] Fix FP -Wformat in functions with 2+ attribute((format)) (#129954)
When defining functions with two or more format attributes, if the format strings don't have the same format family, there is a false positive warning that the incorrect kind of format string is being passed at forwarded format string call sites. This happens because we check that the format string family of each format attribute is compatible before we check that we're using the associated format parameter. The fix is to move the check down one scope, after we've established that we are checking the right parameter. Tests are updated to include a true negative and a true positive of this situation.
1 parent 81089f0 commit c628e8e

File tree

2 files changed

+32
-11
lines changed

2 files changed

+32
-11
lines changed

clang/lib/Sema/SemaChecking.cpp

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6149,18 +6149,19 @@ static StringLiteralCheckType checkFormatStringExpr(
61496149
if (!Sema::getFormatStringInfo(D, PVFormat->getFormatIdx(),
61506150
PVFormat->getFirstArg(), &CallerFSI))
61516151
continue;
6152-
// We also check if the formats are compatible.
6153-
// We can't pass a 'scanf' string to a 'printf' function.
6154-
if (Type != S.GetFormatStringType(PVFormat)) {
6155-
S.Diag(Args[format_idx]->getBeginLoc(),
6156-
diag::warn_format_string_type_incompatible)
6157-
<< PVFormat->getType()->getName()
6158-
<< S.GetFormatStringTypeName(Type);
6159-
if (!InFunctionCall) {
6160-
S.Diag(E->getBeginLoc(), diag::note_format_string_defined);
6152+
if (PV->getFunctionScopeIndex() == CallerFSI.FormatIdx) {
6153+
// We also check if the formats are compatible.
6154+
// We can't pass a 'scanf' string to a 'printf' function.
6155+
if (Type != S.GetFormatStringType(PVFormat)) {
6156+
S.Diag(Args[format_idx]->getBeginLoc(),
6157+
diag::warn_format_string_type_incompatible)
6158+
<< PVFormat->getType()->getName()
6159+
<< S.GetFormatStringTypeName(Type);
6160+
if (!InFunctionCall) {
6161+
S.Diag(E->getBeginLoc(), diag::note_format_string_defined);
6162+
}
6163+
return SLCT_UncheckedLiteral;
61616164
}
6162-
return SLCT_UncheckedLiteral;
6163-
} else if (PV->getFunctionScopeIndex() == CallerFSI.FormatIdx) {
61646165
// Lastly, check that argument passing kinds transition in a
61656166
// way that makes sense:
61666167
// from a caller with FAPK_VAList, allow FAPK_VAList

clang/test/Sema/format-strings.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,26 @@ void rdar8332221(va_list ap, int *x, long *y) {
496496
rdar8332221_vprintf_scanf("%", ap, "%d", x); // expected-warning{{incomplete format specifier}}
497497
}
498498

499+
void rdar8332221_vprintf_scanf(const char *p, va_list ap, const char *s, ...) {
500+
vprintf(p, ap);
501+
502+
va_list vs;
503+
va_start(vs, s);
504+
vscanf(s, vs);
505+
va_end(vs);
506+
}
507+
508+
__attribute__((__format__(__printf__, 1, 0)))
509+
__attribute__((__format__(__scanf__, 3, 4)))
510+
void vprintf_scanf_bad(const char *p, va_list ap, const char *s, ...) {
511+
vscanf(p, ap); // expected-warning{{passing 'printf' format string where 'scanf' format string is expected}}
512+
513+
va_list vs;
514+
va_start(vs, s);
515+
vprintf(s, vs); // expected-warning{{passing 'scanf' format string where 'printf' format string is expected}}
516+
va_end(vs);
517+
}
518+
499519
// PR8641
500520
void pr8641(void) {
501521
printf("%#x\n", 10);

0 commit comments

Comments
 (0)