Merge pull request #154 from simartin/ticket_4900
Fixed #4900 (error wrongPrintfScanfArgNum doesn't support positional parameters)
This commit is contained in:
commit
1409461e4f
|
@ -502,6 +502,7 @@ void CheckIO::checkWrongPrintfScanfArguments()
|
|||
unsigned int numFormat = 0;
|
||||
bool percent = false;
|
||||
const Token* argListTok2 = argListTok;
|
||||
std::set<unsigned int> parameterPositionsUsed;
|
||||
for (std::string::iterator i = formatString.begin(); i != formatString.end(); ++i) {
|
||||
if (*i == '%') {
|
||||
percent = !percent;
|
||||
|
@ -523,6 +524,7 @@ void CheckIO::checkWrongPrintfScanfArguments()
|
|||
|
||||
bool _continue = false;
|
||||
std::string width;
|
||||
unsigned int parameterPosition = 0; bool hasParameterPosition = false;
|
||||
while (i != formatString.end() && *i != ']' && !std::isalpha(*i)) {
|
||||
if (*i == '*') {
|
||||
if (scan)
|
||||
|
@ -532,8 +534,13 @@ void CheckIO::checkWrongPrintfScanfArguments()
|
|||
if (argListTok)
|
||||
argListTok = argListTok->nextArgument();
|
||||
}
|
||||
} else if (std::isdigit(*i))
|
||||
} else if (std::isdigit(*i)) {
|
||||
width += *i;
|
||||
} else if (*i == '$') {
|
||||
parameterPosition = static_cast<unsigned int>(std::atoi(width.c_str()));
|
||||
hasParameterPosition = true;
|
||||
width.clear();
|
||||
}
|
||||
++i;
|
||||
}
|
||||
if (i == formatString.end())
|
||||
|
@ -542,7 +549,15 @@ void CheckIO::checkWrongPrintfScanfArguments()
|
|||
continue;
|
||||
|
||||
if (scan || *i != 'm') { // %m is a non-standard extension that requires no parameter on print functions.
|
||||
numFormat++;
|
||||
++numFormat;
|
||||
|
||||
// Handle parameter positions (POSIX extension) - Ticket #4900
|
||||
if(hasParameterPosition) {
|
||||
if(parameterPositionsUsed.find(parameterPosition) == parameterPositionsUsed.end())
|
||||
parameterPositionsUsed.insert(parameterPosition);
|
||||
else // Parameter already referenced, hence don't consider it a new format
|
||||
--numFormat;
|
||||
}
|
||||
|
||||
// Perform type checks
|
||||
if (argListTok && Token::Match(argListTok->next(), "[,)]")) { // We can currently only check the type of arguments matching this simple pattern.
|
||||
|
@ -718,6 +733,12 @@ void CheckIO::checkWrongPrintfScanfArguments()
|
|||
numFunction++;
|
||||
argListTok2 = argListTok2->nextArgument(); // Find next argument
|
||||
}
|
||||
|
||||
// Check that all parameter positions reference an actual parameter
|
||||
for(std::set<unsigned int>::const_iterator it = parameterPositionsUsed.begin() ; it != parameterPositionsUsed.end() ; ++it) {
|
||||
if((*it == 0) || (*it > numFormat))
|
||||
wrongPrintfScanfPosixParameterPositionError(tok, tok->str(), *it, numFormat);
|
||||
}
|
||||
|
||||
// Mismatching number of parameters => warning
|
||||
if (numFormat != numFunction)
|
||||
|
@ -747,6 +768,21 @@ void CheckIO::wrongPrintfScanfArgumentsError(const Token* tok,
|
|||
reportError(tok, severity, "wrongPrintfScanfArgNum", errmsg.str());
|
||||
}
|
||||
|
||||
void CheckIO::wrongPrintfScanfPosixParameterPositionError(const Token* tok, const std::string& functionName,
|
||||
unsigned int index, unsigned int numFunction)
|
||||
{
|
||||
if (!_settings->isEnabled("style"))
|
||||
return;
|
||||
std::ostringstream errmsg;
|
||||
errmsg << functionName << ": ";
|
||||
if(index == 0) {
|
||||
errmsg << "parameter positions start at 1, not 0";
|
||||
} else {
|
||||
errmsg << "referencing parameter " << index << " while " << numFunction << " arguments given";
|
||||
}
|
||||
reportError(tok, Severity::warning, "wrongPrintfScanfParameterError", errmsg.str());
|
||||
}
|
||||
|
||||
void CheckIO::invalidScanfArgTypeError(const Token* tok, const std::string &functionName, unsigned int numFormat)
|
||||
{
|
||||
std::ostringstream errmsg;
|
||||
|
|
|
@ -82,6 +82,8 @@ private:
|
|||
const std::string &function,
|
||||
unsigned int numFormat,
|
||||
unsigned int numFunction);
|
||||
void wrongPrintfScanfPosixParameterPositionError(const Token* tok, const std::string& functionName,
|
||||
unsigned int index, unsigned int numFunction);
|
||||
void invalidScanfArgTypeError(const Token* tok, const std::string &functionName, unsigned int numFormat);
|
||||
void invalidPrintfArgTypeError_s(const Token* tok, unsigned int numFormat);
|
||||
void invalidPrintfArgTypeError_n(const Token* tok, unsigned int numFormat);
|
||||
|
|
|
@ -46,6 +46,7 @@ private:
|
|||
|
||||
TEST_CASE(testScanfArgument);
|
||||
TEST_CASE(testPrintfArgument);
|
||||
TEST_CASE(testPosixPrintfScanfParameterPosition); // #4900
|
||||
|
||||
TEST_CASE(testMicrosoftPrintfArgument); // ticket #4902
|
||||
|
||||
|
@ -780,6 +781,30 @@ private:
|
|||
|
||||
}
|
||||
|
||||
void testPosixPrintfScanfParameterPosition() { // #4900 - No support for parameters in format strings
|
||||
check("void foo() {"
|
||||
" int bar;"
|
||||
" printf(\"%1$d\", 1);"
|
||||
" printf(\"%1$d, %d, %1$d\", 1, 2);"
|
||||
" scanf(\"%1$d\", &bar);"
|
||||
"}");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("void foo() {\n"
|
||||
" int bar;\n"
|
||||
" printf(\"%1$d\");\n"
|
||||
" printf(\"%1$d, %d, %4$d\", 1, 2, 3);\n"
|
||||
" scanf(\"%2$d\", &bar);\n"
|
||||
" printf(\"%0$f\", 0.0);\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:3]: (error) printf format string has 1 parameters but only 0 are given.\n"
|
||||
"[test.cpp:4]: (warning) printf: referencing parameter 4 while 3 arguments given\n"
|
||||
"[test.cpp:5]: (warning) scanf: referencing parameter 2 while 1 arguments given\n"
|
||||
"[test.cpp:6]: (warning) printf: parameter positions start at 1, not 0\n"
|
||||
"", errout.str());
|
||||
}
|
||||
|
||||
|
||||
void testMicrosoftPrintfArgument() {
|
||||
check("void foo() {\n"
|
||||
" size_t s;\n"
|
||||
|
|
Loading…
Reference in New Issue