Format string checking: selectively ignore implicit casts to 'int'

when checking if the format specifier matches the type of the data
argument and the length modifier indicates the data type is 'char' or
'short'.

llvm-svn: 94992
This commit is contained in:
Ted Kremenek 2010-02-01 19:28:15 +00:00
parent 973f2eb0cd
commit cd83106151
2 changed files with 22 additions and 6 deletions

View File

@ -1280,14 +1280,25 @@ CheckPrintfHandler::HandleFormatSpecifier(const analyze_printf::FormatSpecifier
// format specifier.
const Expr *Ex = getDataArg(NumConversions);
const analyze_printf::ArgTypeResult &ATR = FS.getArgType(S.Context);
if (const QualType *T = ATR.getSpecificType()) {
if (!MatchType(*T, Ex->getType(), true)) {
S.Diag(getLocationOfByte(CS.getStart()),
diag::warn_printf_conversion_argument_type_mismatch)
<< *T << Ex->getType()
<< getFormatSpecifierRange(startSpecifier, specifierLen)
<< Ex->getSourceRange();
// Check if we didn't match because of an implicit cast from a 'char'
// or 'short' to an 'int'. This is done because printf is a varargs
// function.
bool hasError = true;
if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Ex))
if (ICE->getType() == S.Context.IntTy) {
Ex = ICE->getSubExpr();
hasError = !MatchType(*T, Ex->getType(), true);
}
if (hasError)
S.Diag(getLocationOfByte(CS.getStart()),
diag::warn_printf_conversion_argument_type_mismatch)
<< *T << Ex->getType()
<< getFormatSpecifierRange(startSpecifier, specifierLen)
<< Ex->getSourceRange();
}
return true;
}

View File

@ -162,6 +162,11 @@ void test10(int x, float f, int i, long long lli) {
printf("%.", x); // expected-warning{{incomplete format specifier}}
printf("%f", 4); // expected-warning{{conversion specifies type 'double' but the argument has type 'int'}}
printf("%qd", lli);
printf("hhX %hhX", (unsigned char)10); // no-warning
printf("llX %llX", (long long) 10); // no-warning
// This is fine, because there is an implicit conversion to an int.
printf("%d", (unsigned char) 10); // no-warning
printf("%d", (long long) 10); // expected-warning{{conversion specifies type 'int' but the argument has type 'long long'}}
}
typedef struct __aslclient *aslclient;