From: Ted Kremenek Date: Mon, 19 Jul 2010 21:25:57 +0000 (+0000) Subject: Hook up 'invalid conversion' warning for scanf format strings. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c09b6a59e02ae265fce51b8c11e2a045bcdaa888;p=clang Hook up 'invalid conversion' warning for scanf format strings. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@108750 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 78a754ad60..d3c33e62f1 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2936,7 +2936,7 @@ def warn_printf_insufficient_data_args : Warning< "more '%%' conversions than data arguments">, InGroup; def warn_printf_data_arg_not_used : Warning< "data argument not used by format string">, InGroup; -def warn_printf_invalid_conversion : Warning< +def warn_format_invalid_conversion : Warning< "invalid conversion specifier '%0'">, InGroup; def warn_printf_incomplete_specifier : Warning< "incomplete format specifier">, InGroup; diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index f1e501651e..f36a9ed938 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -1160,6 +1160,11 @@ public: void HandleNullChar(const char *nullCharacter); protected: + bool HandleInvalidConversionSpecifier(unsigned argIndex, SourceLocation Loc, + const char *startSpec, + unsigned specifierLen, + const char *csStart, unsigned csLen); + SourceRange getFormatStringRange(); CharSourceRange getSpecifierRange(const char *startSpecifier, unsigned specifierLen); @@ -1237,6 +1242,36 @@ void CheckFormatHandler::DoneProcessing() { } } +bool +CheckFormatHandler::HandleInvalidConversionSpecifier(unsigned argIndex, + SourceLocation Loc, + const char *startSpec, + unsigned specifierLen, + const char *csStart, + unsigned csLen) { + + bool keepGoing = true; + if (argIndex < NumDataArgs) { + // Consider the argument coverered, even though the specifier doesn't + // make sense. + CoveredArgs.set(argIndex); + } + else { + // If argIndex exceeds the number of data arguments we + // don't issue a warning because that is just a cascade of warnings (and + // they may have intended '%%' anyway). We don't want to continue processing + // the format string after this point, however, as we will like just get + // gibberish when trying to match arguments. + keepGoing = false; + } + + S.Diag(Loc, diag::warn_format_invalid_conversion) + << llvm::StringRef(csStart, csLen) + << getSpecifierRange(startSpec, specifierLen); + + return keepGoing; +} + //===--- CHECK: Printf format string checking ------------------------------===// namespace { @@ -1281,31 +1316,13 @@ bool CheckPrintfHandler::HandleInvalidPrintfConversionSpecifier( const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier, unsigned specifierLen) { - - unsigned argIndex = FS.getArgIndex(); - bool keepGoing = true; - if (argIndex < NumDataArgs) { - // Consider the argument coverered, even though the specifier doesn't - // make sense. - CoveredArgs.set(argIndex); - } - else { - // If argIndex exceeds the number of data arguments we - // don't issue a warning because that is just a cascade of warnings (and - // they may have intended '%%' anyway). We don't want to continue processing - // the format string after this point, however, as we will like just get - // gibberish when trying to match arguments. - keepGoing = false; - } - const analyze_printf::ConversionSpecifier &CS = - FS.getConversionSpecifier(); - SourceLocation Loc = getLocationOfByte(CS.getStart()); - S.Diag(Loc, diag::warn_printf_invalid_conversion) - << llvm::StringRef(CS.getStart(), CS.getLength()) - << getSpecifierRange(startSpecifier, specifierLen); + FS.getConversionSpecifier(); - return keepGoing; + return HandleInvalidConversionSpecifier(FS.getArgIndex(), + getLocationOfByte(CS.getStart()), + startSpecifier, specifierLen, + CS.getStart(), CS.getLength()); } bool CheckPrintfHandler::HandleAmount( @@ -1596,6 +1613,11 @@ public: bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS, const char *startSpecifier, unsigned specifierLen); + + bool HandleInvalidScanfConversionSpecifier( + const analyze_scanf::ScanfSpecifier &FS, + const char *startSpecifier, + unsigned specifierLen); void HandleIncompleteScanList(const char *start, const char *end); }; @@ -1607,6 +1629,20 @@ void CheckScanfHandler::HandleIncompleteScanList(const char *start, << getSpecifierRange(start, end - start); } +bool CheckScanfHandler::HandleInvalidScanfConversionSpecifier( + const analyze_scanf::ScanfSpecifier &FS, + const char *startSpecifier, + unsigned specifierLen) { + + const analyze_scanf::ConversionSpecifier &CS = + FS.getConversionSpecifier(); + + return HandleInvalidConversionSpecifier(FS.getArgIndex(), + getLocationOfByte(CS.getStart()), + startSpecifier, specifierLen, + CS.getStart(), CS.getLength()); +} + bool CheckScanfHandler::HandleScanfSpecifier( const analyze_scanf::ScanfSpecifier &FS, const char *startSpecifier, diff --git a/test/Sema/format-strings-scanf.c b/test/Sema/format-strings-scanf.c index ac53d66bf6..5d2a7a7a9b 100644 --- a/test/Sema/format-strings-scanf.c +++ b/test/Sema/format-strings-scanf.c @@ -15,4 +15,5 @@ void test(const char *s, int *i) { unsigned short s_x; scanf ("%" "hu" "\n", &s_x); // no-warning + scanf("%y", i); // expected-warning{{invalid conversion specifier 'y'}} }