diff options
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/lib/Analysis/ScanfFormatString.cpp | 44 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 14 | ||||
| -rw-r--r-- | clang/test/Sema/format-strings-scanf.c | 8 | 
3 files changed, 42 insertions, 24 deletions
diff --git a/clang/lib/Analysis/ScanfFormatString.cpp b/clang/lib/Analysis/ScanfFormatString.cpp index 493a3c8df28..61af1d67379 100644 --- a/clang/lib/Analysis/ScanfFormatString.cpp +++ b/clang/lib/Analysis/ScanfFormatString.cpp @@ -19,6 +19,7 @@ using clang::analyze_format_string::ArgTypeResult;  using clang::analyze_format_string::FormatStringHandler;  using clang::analyze_format_string::LengthModifier;  using clang::analyze_format_string::OptionalAmount; +using clang::analyze_format_string::ConversionSpecifier;  using clang::analyze_scanf::ScanfConversionSpecifier;  using clang::analyze_scanf::ScanfSpecifier; @@ -146,27 +147,28 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,    switch (*conversionPosition) {      default:        break; -    case '%': k = ScanfConversionSpecifier::PercentArg;   break; -    case 'A': k = ScanfConversionSpecifier::AArg; break; -    case 'E': k = ScanfConversionSpecifier::EArg; break; -    case 'F': k = ScanfConversionSpecifier::FArg; break; -    case 'G': k = ScanfConversionSpecifier::GArg; break; -    case 'X': k = ScanfConversionSpecifier::XArg; break; -    case 'a': k = ScanfConversionSpecifier::aArg; break; -    case 'd': k = ScanfConversionSpecifier::dArg; break; -    case 'e': k = ScanfConversionSpecifier::eArg; break; -    case 'f': k = ScanfConversionSpecifier::fArg; break; -    case 'g': k = ScanfConversionSpecifier::gArg; break; -    case 'i': k = ScanfConversionSpecifier::iArg; break; -    case 'n': k = ScanfConversionSpecifier::nArg; break; -    case 'c': k = ScanfConversionSpecifier::cArg; break; -    case 'C': k = ScanfConversionSpecifier::CArg; break; -    case 'S': k = ScanfConversionSpecifier::SArg; break; -    case '[': k = ScanfConversionSpecifier::ScanListArg; break; -    case 'u': k = ScanfConversionSpecifier::uArg; break; -    case 'x': k = ScanfConversionSpecifier::xArg; break; -    case 'o': k = ScanfConversionSpecifier::oArg; break; -    case 's': k = ScanfConversionSpecifier::sArg; break; +    case '%': k = ConversionSpecifier::PercentArg;   break; +    case 'A': k = ConversionSpecifier::AArg; break; +    case 'E': k = ConversionSpecifier::EArg; break; +    case 'F': k = ConversionSpecifier::FArg; break; +    case 'G': k = ConversionSpecifier::GArg; break; +    case 'X': k = ConversionSpecifier::XArg; break; +    case 'a': k = ConversionSpecifier::aArg; break; +    case 'd': k = ConversionSpecifier::dArg; break; +    case 'e': k = ConversionSpecifier::eArg; break; +    case 'f': k = ConversionSpecifier::fArg; break; +    case 'g': k = ConversionSpecifier::gArg; break; +    case 'i': k = ConversionSpecifier::iArg; break; +    case 'n': k = ConversionSpecifier::nArg; break; +    case 'c': k = ConversionSpecifier::cArg; break; +    case 'C': k = ConversionSpecifier::CArg; break; +    case 'S': k = ConversionSpecifier::SArg; break; +    case '[': k = ConversionSpecifier::ScanListArg; break; +    case 'u': k = ConversionSpecifier::uArg; break; +    case 'x': k = ConversionSpecifier::xArg; break; +    case 'o': k = ConversionSpecifier::oArg; break; +    case 's': k = ConversionSpecifier::sArg; break; +    case 'p': k = ConversionSpecifier::pArg; break;    }    ScanfConversionSpecifier CS(conversionPosition, k);    if (k == ScanfConversionSpecifier::ScanListArg) { diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 8846c25724e..2887a50d527 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -1701,9 +1701,17 @@ bool CheckScanfHandler::HandleScanfSpecifier(      CoveredArgs.set(argIndex);    } -  // FIXME: Check that the length modifier is valid with the given -  // conversion specifier. -   +  // Check the length modifier is valid with the given 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.    if (HasVAListArg)      return true; diff --git a/clang/test/Sema/format-strings-scanf.c b/clang/test/Sema/format-strings-scanf.c index 68552b3e241..42b6c03ffbf 100644 --- a/clang/test/Sema/format-strings-scanf.c +++ b/clang/test/Sema/format-strings-scanf.c @@ -2,6 +2,7 @@  typedef __typeof(sizeof(int)) size_t;  typedef struct _FILE FILE; +typedef __WCHAR_TYPE__ wchar_t;  int fscanf(FILE * restrict, 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%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 '#'}} +}  | 

