diff --git a/lib/checkio.cpp b/lib/checkio.cpp index d04550cfd..a0a547966 100644 --- a/lib/checkio.cpp +++ b/lib/checkio.cpp @@ -620,20 +620,34 @@ void CheckIO::checkWrongPrintfScanfArguments() case 'l': // Can be 'll' (long long int or unsigned long long int) or 'l' (long int or unsigned long int) // If the next character is the same (which makes 'hh' or 'll') then expect another alphabetical character if (i != formatString.end() && *(i+1) == *i) { - if (i+1 != formatString.end() && !isalpha(*(i+2))) { - std::string modifier; - modifier += *i; - modifier += *(i+1); - invalidLengthModifierError(tok, numFormat, modifier); + if (i+1 != formatString.end()) { + if (!isalpha(*(i+2))) { + std::string modifier; + modifier += *i; + modifier += *(i+1); + invalidLengthModifierError(tok, numFormat, modifier); + done = true; + } else { + specifier = *i++; + specifier += *i++; + } + } else { + done = true; } } else { - if (i != formatString.end() && !isalpha(*(i+1))) { - std::string modifier; - modifier += *i; - invalidLengthModifierError(tok, numFormat, modifier); + if (i != formatString.end()) { + if (!isalpha(*(i+1))) { + std::string modifier; + modifier += *i; + invalidLengthModifierError(tok, numFormat, modifier); + done = true; + } else { + specifier = *i++; + } + } else { + done = true; } } - done = true; break; case 'I': // Microsoft extension: I for size_t and ptrdiff_t, I32 for __int32, and I64 for __int64 if (i != formatString.end()) { @@ -659,8 +673,10 @@ void CheckIO::checkWrongPrintfScanfArguments() std::string modifier; modifier += *i; invalidLengthModifierError(tok, numFormat, modifier); + done = true; + } else { + specifier = *i++; } - done = true; break; default: done = true; diff --git a/test/testio.cpp b/test/testio.cpp index a5cb928d8..19939f383 100644 --- a/test/testio.cpp +++ b/test/testio.cpp @@ -717,7 +717,7 @@ private: // False positive tests check("void foo(signed char sc, unsigned char uc, short int si, unsigned short int usi) {\n" " printf(\"%hhx %hhd\", sc, uc);\n" - " printf(\"%hd %hi\", si, usi);\n" + " printf(\"%hd %hu\", si, usi);\n" "}"); ASSERT_EQUALS("", errout.str()); @@ -754,6 +754,25 @@ private: "[test.cpp:7]: (warning) 'z' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n" "[test.cpp:8]: (warning) 't' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n" "[test.cpp:9]: (warning) 'L' in format string (no. 1) is a length modifier and cannot be used without a conversion specifier.\n", errout.str()); + + check("void foo(unsigned int i) {\n" + " printf(\"%hd\", i);\n" + " printf(\"%hhd\", i);\n" + " printf(\"%ld\", i);\n" + " printf(\"%lld\", i);\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (warning) %hd in format string (no. 1) requires a signed integer given in the argument list.\n" + "[test.cpp:3]: (warning) %hhd in format string (no. 1) requires a signed integer given in the argument list.\n" + "[test.cpp:4]: (warning) %ld in format string (no. 1) requires a signed integer given in the argument list.\n" + "[test.cpp:5]: (warning) %lld in format string (no. 1) requires a signed integer given in the argument list.\n" , errout.str()); + + check("void foo(size_t s, ptrdiff_t p) {\n" + " printf(\"%zd\", s);\n" + " printf(\"%tu\", p);\n" + "}"); + ASSERT_EQUALS("[test.cpp:2]: (warning) %zd in format string (no. 1) requires a signed integer given in the argument list.\n" + "[test.cpp:3]: (warning) %tu in format string (no. 1) requires an unsigned integer given in the argument list.\n", errout.str()); + } void testMicrosoftPrintfArgument() {