Hookup checking for invalid length modifiers in scanf format strings.

llvm-svn: 108907
This commit is contained in:
Ted Kremenek 2010-07-20 20:04:47 +00:00
parent ea28f83a5f
commit 4407ea4948
3 changed files with 42 additions and 24 deletions

View File

@ -19,6 +19,7 @@ using clang::analyze_format_string::ArgTypeResult;
using clang::analyze_format_string::FormatStringHandler; using clang::analyze_format_string::FormatStringHandler;
using clang::analyze_format_string::LengthModifier; using clang::analyze_format_string::LengthModifier;
using clang::analyze_format_string::OptionalAmount; using clang::analyze_format_string::OptionalAmount;
using clang::analyze_format_string::ConversionSpecifier;
using clang::analyze_scanf::ScanfConversionSpecifier; using clang::analyze_scanf::ScanfConversionSpecifier;
using clang::analyze_scanf::ScanfSpecifier; using clang::analyze_scanf::ScanfSpecifier;
@ -146,27 +147,28 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
switch (*conversionPosition) { switch (*conversionPosition) {
default: default:
break; break;
case '%': k = ScanfConversionSpecifier::PercentArg; break; case '%': k = ConversionSpecifier::PercentArg; break;
case 'A': k = ScanfConversionSpecifier::AArg; break; case 'A': k = ConversionSpecifier::AArg; break;
case 'E': k = ScanfConversionSpecifier::EArg; break; case 'E': k = ConversionSpecifier::EArg; break;
case 'F': k = ScanfConversionSpecifier::FArg; break; case 'F': k = ConversionSpecifier::FArg; break;
case 'G': k = ScanfConversionSpecifier::GArg; break; case 'G': k = ConversionSpecifier::GArg; break;
case 'X': k = ScanfConversionSpecifier::XArg; break; case 'X': k = ConversionSpecifier::XArg; break;
case 'a': k = ScanfConversionSpecifier::aArg; break; case 'a': k = ConversionSpecifier::aArg; break;
case 'd': k = ScanfConversionSpecifier::dArg; break; case 'd': k = ConversionSpecifier::dArg; break;
case 'e': k = ScanfConversionSpecifier::eArg; break; case 'e': k = ConversionSpecifier::eArg; break;
case 'f': k = ScanfConversionSpecifier::fArg; break; case 'f': k = ConversionSpecifier::fArg; break;
case 'g': k = ScanfConversionSpecifier::gArg; break; case 'g': k = ConversionSpecifier::gArg; break;
case 'i': k = ScanfConversionSpecifier::iArg; break; case 'i': k = ConversionSpecifier::iArg; break;
case 'n': k = ScanfConversionSpecifier::nArg; break; case 'n': k = ConversionSpecifier::nArg; break;
case 'c': k = ScanfConversionSpecifier::cArg; break; case 'c': k = ConversionSpecifier::cArg; break;
case 'C': k = ScanfConversionSpecifier::CArg; break; case 'C': k = ConversionSpecifier::CArg; break;
case 'S': k = ScanfConversionSpecifier::SArg; break; case 'S': k = ConversionSpecifier::SArg; break;
case '[': k = ScanfConversionSpecifier::ScanListArg; break; case '[': k = ConversionSpecifier::ScanListArg; break;
case 'u': k = ScanfConversionSpecifier::uArg; break; case 'u': k = ConversionSpecifier::uArg; break;
case 'x': k = ScanfConversionSpecifier::xArg; break; case 'x': k = ConversionSpecifier::xArg; break;
case 'o': k = ScanfConversionSpecifier::oArg; break; case 'o': k = ConversionSpecifier::oArg; break;
case 's': k = ScanfConversionSpecifier::sArg; break; case 's': k = ConversionSpecifier::sArg; break;
case 'p': k = ConversionSpecifier::pArg; break;
} }
ScanfConversionSpecifier CS(conversionPosition, k); ScanfConversionSpecifier CS(conversionPosition, k);
if (k == ScanfConversionSpecifier::ScanListArg) { if (k == ScanfConversionSpecifier::ScanListArg) {

View File

@ -1701,8 +1701,16 @@ bool CheckScanfHandler::HandleScanfSpecifier(
CoveredArgs.set(argIndex); CoveredArgs.set(argIndex);
} }
// FIXME: Check that the length modifier is valid with the given // Check the length modifier is valid with the given conversion specifier.
// conversion specifier. const LengthModifier &LM = FS.getLengthModifier();
if (!FS.hasValidLengthModifier()) {
S.Diag(getLocationOfByte(LM.getStart()),
diag::warn_format_nonsensical_length)
<< LM.toString() << CS.toString()
<< getSpecifierRange(startSpecifier, specifierLen)
<< FixItHint::CreateRemoval(getSpecifierRange(LM.getStart(),
LM.getLength()));
}
// The remaining checks depend on the data arguments. // The remaining checks depend on the data arguments.
if (HasVAListArg) if (HasVAListArg)

View File

@ -2,6 +2,7 @@
typedef __typeof(sizeof(int)) size_t; typedef __typeof(sizeof(int)) size_t;
typedef struct _FILE FILE; typedef struct _FILE FILE;
typedef __WCHAR_TYPE__ wchar_t;
int fscanf(FILE * restrict, const char * restrict, ...) ; int fscanf(FILE * restrict, const char * restrict, ...) ;
int scanf(const char * restrict, ...) ; int scanf(const char * restrict, ...) ;
@ -24,3 +25,10 @@ void test(const char *s, int *i) {
scanf("%*d", i); // // expected-warning{{data argument not used by format string}} scanf("%*d", i); // // expected-warning{{data argument not used by format string}}
scanf("%*d%1$d", i); // no-warning scanf("%*d%1$d", i); // no-warning
} }
void bad_length_modifiers(char *s, void *p, wchar_t *ws, long double *ld) {
scanf("%hhs", "foo"); // expected-warning{{length modifier 'hh' results in undefined behavior or no effect with 's' conversion specifier}}
scanf("%1$zp", p); // expected-warning{{length modifier 'z' results in undefined behavior or no effect with 'p' conversion specifier}}
scanf("%ls", ws); // no-warning
scanf("%#.2Lf", ld); // expected-warning{{invalid conversion specifier '#'}}
}