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;
|
unsigned int numFormat = 0;
|
||||||
bool percent = false;
|
bool percent = false;
|
||||||
const Token* argListTok2 = argListTok;
|
const Token* argListTok2 = argListTok;
|
||||||
|
std::set<unsigned int> parameterPositionsUsed;
|
||||||
for (std::string::iterator i = formatString.begin(); i != formatString.end(); ++i) {
|
for (std::string::iterator i = formatString.begin(); i != formatString.end(); ++i) {
|
||||||
if (*i == '%') {
|
if (*i == '%') {
|
||||||
percent = !percent;
|
percent = !percent;
|
||||||
|
@ -523,6 +524,7 @@ void CheckIO::checkWrongPrintfScanfArguments()
|
||||||
|
|
||||||
bool _continue = false;
|
bool _continue = false;
|
||||||
std::string width;
|
std::string width;
|
||||||
|
unsigned int parameterPosition = 0; bool hasParameterPosition = false;
|
||||||
while (i != formatString.end() && *i != ']' && !std::isalpha(*i)) {
|
while (i != formatString.end() && *i != ']' && !std::isalpha(*i)) {
|
||||||
if (*i == '*') {
|
if (*i == '*') {
|
||||||
if (scan)
|
if (scan)
|
||||||
|
@ -532,8 +534,13 @@ void CheckIO::checkWrongPrintfScanfArguments()
|
||||||
if (argListTok)
|
if (argListTok)
|
||||||
argListTok = argListTok->nextArgument();
|
argListTok = argListTok->nextArgument();
|
||||||
}
|
}
|
||||||
} else if (std::isdigit(*i))
|
} else if (std::isdigit(*i)) {
|
||||||
width += *i;
|
width += *i;
|
||||||
|
} else if (*i == '$') {
|
||||||
|
parameterPosition = static_cast<unsigned int>(std::atoi(width.c_str()));
|
||||||
|
hasParameterPosition = true;
|
||||||
|
width.clear();
|
||||||
|
}
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
if (i == formatString.end())
|
if (i == formatString.end())
|
||||||
|
@ -542,7 +549,15 @@ void CheckIO::checkWrongPrintfScanfArguments()
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (scan || *i != 'm') { // %m is a non-standard extension that requires no parameter on print functions.
|
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
|
// Perform type checks
|
||||||
if (argListTok && Token::Match(argListTok->next(), "[,)]")) { // We can currently only check the type of arguments matching this simple pattern.
|
if (argListTok && Token::Match(argListTok->next(), "[,)]")) { // We can currently only check the type of arguments matching this simple pattern.
|
||||||
|
@ -719,6 +734,12 @@ void CheckIO::checkWrongPrintfScanfArguments()
|
||||||
argListTok2 = argListTok2->nextArgument(); // Find next argument
|
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
|
// Mismatching number of parameters => warning
|
||||||
if (numFormat != numFunction)
|
if (numFormat != numFunction)
|
||||||
wrongPrintfScanfArgumentsError(tok, tok->str(), numFormat, numFunction);
|
wrongPrintfScanfArgumentsError(tok, tok->str(), numFormat, numFunction);
|
||||||
|
@ -747,6 +768,21 @@ void CheckIO::wrongPrintfScanfArgumentsError(const Token* tok,
|
||||||
reportError(tok, severity, "wrongPrintfScanfArgNum", errmsg.str());
|
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)
|
void CheckIO::invalidScanfArgTypeError(const Token* tok, const std::string &functionName, unsigned int numFormat)
|
||||||
{
|
{
|
||||||
std::ostringstream errmsg;
|
std::ostringstream errmsg;
|
||||||
|
|
|
@ -82,6 +82,8 @@ private:
|
||||||
const std::string &function,
|
const std::string &function,
|
||||||
unsigned int numFormat,
|
unsigned int numFormat,
|
||||||
unsigned int numFunction);
|
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 invalidScanfArgTypeError(const Token* tok, const std::string &functionName, unsigned int numFormat);
|
||||||
void invalidPrintfArgTypeError_s(const Token* tok, unsigned int numFormat);
|
void invalidPrintfArgTypeError_s(const Token* tok, unsigned int numFormat);
|
||||||
void invalidPrintfArgTypeError_n(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(testScanfArgument);
|
||||||
TEST_CASE(testPrintfArgument);
|
TEST_CASE(testPrintfArgument);
|
||||||
|
TEST_CASE(testPosixPrintfScanfParameterPosition); // #4900
|
||||||
|
|
||||||
TEST_CASE(testMicrosoftPrintfArgument); // ticket #4902
|
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() {
|
void testMicrosoftPrintfArgument() {
|
||||||
check("void foo() {\n"
|
check("void foo() {\n"
|
||||||
" size_t s;\n"
|
" size_t s;\n"
|
||||||
|
|
Loading…
Reference in New Issue