forked from OSchip/llvm-project
Added notion of '*' specified format width/specifiers when checking
printf format strings. Added type checking to see if the matching width/precision argument was of type 'int'. Thanks to Anders Carlsson for reporting this missing feature. llvm-svn: 42933
This commit is contained in:
parent
e0ad9ea7cd
commit
41362cea7b
|
@ -313,10 +313,47 @@ Sema::CheckPrintfArguments(Expr *Fn,
|
|||
|
||||
// Seen '%'. Now processing a format conversion.
|
||||
switch (Str[StrIdx]) {
|
||||
// Handle dynamic precision specifier.
|
||||
case '*':
|
||||
if (Str[StrIdx-1] == '.') ++numConversions;
|
||||
// Handle dynamic precision or width specifier.
|
||||
case '*': {
|
||||
++numConversions;
|
||||
|
||||
if (!HasVAListArg && numConversions > numDataArgs) {
|
||||
|
||||
SourceLocation Loc =
|
||||
PP.AdvanceToTokenCharacter(Args[format_idx]->getLocStart(),
|
||||
StrIdx+1);
|
||||
|
||||
if (Str[StrIdx-1] == '.')
|
||||
Diag(Loc, diag::warn_printf_asterisk_precision_missing_arg,
|
||||
Fn->getSourceRange());
|
||||
else
|
||||
Diag(Loc, diag::warn_printf_asterisk_width_missing_arg,
|
||||
Fn->getSourceRange());
|
||||
|
||||
// Don't do any more checking. We'll just emit spurious errors.
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform type checking on width/precision specifier.
|
||||
Expr* E = Args[format_idx+numConversions];
|
||||
QualType T = E->getType().getCanonicalType();
|
||||
if (BuiltinType *BT = dyn_cast<BuiltinType>(T))
|
||||
if (BT->getKind() == BuiltinType::Int)
|
||||
break;
|
||||
|
||||
SourceLocation Loc =
|
||||
PP.AdvanceToTokenCharacter(Args[format_idx]->getLocStart(),
|
||||
StrIdx+1);
|
||||
|
||||
if (Str[StrIdx-1] == '.')
|
||||
Diag(Loc, diag::warn_printf_asterisk_precision_wrong_type,
|
||||
T.getAsString(), E->getSourceRange());
|
||||
else
|
||||
Diag(Loc, diag::warn_printf_asterisk_width_wrong_type,
|
||||
T.getAsString(), E->getSourceRange());
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Characters which can terminate a format conversion
|
||||
// (e.g. "%d"). Characters that specify length modifiers or
|
||||
|
@ -376,7 +413,7 @@ Sema::CheckPrintfArguments(Expr *Fn,
|
|||
LastConversionIdx+1);
|
||||
|
||||
Diag(Loc, diag::warn_printf_invalid_conversion,
|
||||
std::string(Str+LastConversionIdx, Str+StrIdx),
|
||||
std::string(Str+LastConversionIdx, Str+StrIdx),
|
||||
Fn->getSourceRange());
|
||||
|
||||
// This conversion is broken. Advance to the next format
|
||||
|
|
|
@ -789,6 +789,14 @@ DIAG(warn_printf_format_string_is_wide_literal, WARNING,
|
|||
"format string should not be a wide string")
|
||||
DIAG(warn_printf_format_string_contains_null_char, WARNING,
|
||||
"format string contains '\\0' within the string body")
|
||||
DIAG(warn_printf_asterisk_width_missing_arg, WARNING,
|
||||
"'*' specified field width is missing a matching 'int' argument")
|
||||
DIAG(warn_printf_asterisk_precision_missing_arg, WARNING,
|
||||
"'.*' specified field precision is missing a matching 'int' argument")
|
||||
DIAG(warn_printf_asterisk_width_wrong_type, WARNING,
|
||||
"field width should have type 'int', but argument has type '%0'")
|
||||
DIAG(warn_printf_asterisk_precision_wrong_type, WARNING,
|
||||
"field precision should have type 'int', but argument has type '%0'")
|
||||
|
||||
// CHECK: returning address/reference of stack memory
|
||||
DIAG(warn_ret_stack_addr, WARNING,
|
||||
|
|
|
@ -61,3 +61,11 @@ void check_wide_string(char* b, ...)
|
|||
printf(L"foo %d",2); // expected-warning {{should not be a wide string}}
|
||||
vasprintf(&b,L"bar %d",2); // expected-warning {{should not be a wide string}}
|
||||
}
|
||||
|
||||
void check_asterisk_precision_width(int x) {
|
||||
printf("%*d"); // expected-warning {{'*' specified field width is missing a matching 'int' argument}}
|
||||
printf("%.*d"); // expected-warning {{'.*' specified field precision is missing a matching 'int' argument}}
|
||||
printf("%*d",12,x); // no-warning
|
||||
printf("%*d","foo",x); // expected-warning {{field width should have type 'int', but argument has type 'char *'}}
|
||||
printf("%.*d","foo",x); // expected-warning {{field precision should have type 'int', but argument has type 'char *'}}
|
||||
}
|
Loading…
Reference in New Issue