Skip to content

Commit

Permalink
[Sema] Consider all format_arg attributes.
Browse files Browse the repository at this point in the history
If a function has multiple format_arg attributes, clang only considers
the first it finds (because AttributeLists are in reverse order, not
necessarily the textually first) and ignores all others.

Loop over all FormatArgAttr to print warnings for all declared
format_arg attributes.

For instance, libintl's ngettext (select plural or singular version of
format string) has two __format_arg__ attributes.

Differential Revision: https://reviews.llvm.org/D48734

llvm-svn: 336239
  • Loading branch information
Meinersbur committed Jul 4, 2018
1 parent aeeac6d commit f18adbb
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 6 deletions.
21 changes: 15 additions & 6 deletions clang/lib/Sema/SemaChecking.cpp
Expand Up @@ -5518,13 +5518,22 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
case Stmt::CXXMemberCallExprClass: {
const CallExpr *CE = cast<CallExpr>(E);
if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(CE->getCalleeDecl())) {
if (const FormatArgAttr *FA = ND->getAttr<FormatArgAttr>()) {
bool IsFirst = true;
StringLiteralCheckType CommonResult;
for (const auto *FA : ND->specific_attrs<FormatArgAttr>()) {
const Expr *Arg = CE->getArg(FA->getFormatIdx().getASTIndex());
return checkFormatStringExpr(S, Arg, Args,
HasVAListArg, format_idx, firstDataArg,
Type, CallType, InFunctionCall,
CheckedVarArgs, UncoveredArg, Offset);
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
StringLiteralCheckType Result = checkFormatStringExpr(
S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type,
CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset);
if (IsFirst) {
CommonResult = Result;
IsFirst = false;
}
}
if (!IsFirst)
return CommonResult;

if (const auto *FD = dyn_cast<FunctionDecl>(ND)) {
unsigned BuiltinID = FD->getBuiltinID();
if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString ||
BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) {
Expand Down
17 changes: 17 additions & 0 deletions clang/test/Sema/attr-format_arg.c
Expand Up @@ -4,10 +4,27 @@ int printf(const char *, ...);

const char* f(const char *s) __attribute__((format_arg(1)));

const char *h(const char *msg1, const char *msg2)
__attribute__((__format_arg__(1))) __attribute__((__format_arg__(2)));

void g(const char *s) {
printf("%d", 123);
printf("%d %d", 123); // expected-warning{{more '%' conversions than data arguments}}

printf(f("%d"), 123);
printf(f("%d %d"), 123); // expected-warning{{more '%' conversions than data arguments}}

printf(h(
"", // expected-warning {{format string is empty}}
"" // expected-warning {{format string is empty}}
), 123);
printf(h(
"%d",
"" // expected-warning {{format string is empty}}
), 123);
printf(h(
"", // expected-warning {{format string is empty}}
"%d"
), 123);
printf(h("%d", "%d"), 123);
}

0 comments on commit f18adbb

Please sign in to comment.