Fixed #3373 (False posititive: incorrect %* handling in sscanf)

This commit is contained in:
Daniel Marjamäki 2011-12-02 17:09:32 +01:00
parent 6763e596b9
commit 9a84c5845a
4 changed files with 71 additions and 8 deletions

View File

@ -173,13 +173,22 @@ void CheckNullPointer::parseFunctionCall(const Token &tok, std::list<const Token
if (*i == '%') { if (*i == '%') {
percent = !percent; percent = !percent;
} else if (percent) { } else if (percent) {
percent = false;
bool _continue = false;
while (!std::isalpha(*i)) { while (!std::isalpha(*i)) {
if (*i == '*') if (*i == '*') {
argListTok = argListTok->nextArgument(); if (scan)
_continue = true;
else
argListTok = argListTok->nextArgument();
}
++i; ++i;
if (!argListTok || i == formatString.end()) if (!argListTok || i == formatString.end())
return; return;
} }
if (_continue)
continue;
if ((*i == 'n' || *i == 's' || scan) && (!scan || value == 0)) { if ((*i == 'n' || *i == 's' || scan) && (!scan || value == 0)) {
if ((value == 0 && argListTok->str() == "0") || (Token::Match(argListTok, "%var%") && argListTok->varId() > 0)) { if ((value == 0 && argListTok->str() == "0") || (Token::Match(argListTok, "%var%") && argListTok->varId() > 0)) {
@ -191,8 +200,6 @@ void CheckNullPointer::parseFunctionCall(const Token &tok, std::list<const Token
argListTok = argListTok->nextArgument(); // Find next argument argListTok = argListTok->nextArgument(); // Find next argument
if (!argListTok) if (!argListTok)
break; break;
percent = false;
} }
} }
} }

View File

@ -1285,6 +1285,7 @@ void CheckOther::checkWrongPrintfScanfArguments()
} }
// Count format string parameters.. // Count format string parameters..
bool scan = Token::Match(tok, "sscanf|fscanf|scanf");
unsigned int numFormat = 0; unsigned int numFormat = 0;
bool percent = false; bool percent = false;
for (std::string::iterator i = formatString.begin(); i != formatString.end(); ++i) { for (std::string::iterator i = formatString.begin(); i != formatString.end(); ++i) {
@ -1302,25 +1303,33 @@ void CheckOther::checkWrongPrintfScanfArguments()
if (i == formatString.end()) if (i == formatString.end())
break; break;
} else if (percent) { } else if (percent) {
percent = false;
bool _continue = false;
while (i != formatString.end() && !std::isalpha(*i)) { while (i != formatString.end() && !std::isalpha(*i)) {
if (*i == '*') if (*i == '*') {
numFormat++; if (scan)
_continue = true;
else
numFormat++;
}
++i; ++i;
} }
if (i == formatString.end()) if (i == formatString.end())
break; break;
if (_continue)
continue;
if (*i != 'm') // %m is a non-standard extension that requires no parameter if (*i != 'm') // %m is a non-standard extension that requires no parameter
numFormat++; numFormat++;
percent = false; // TODO: Perform type checks
} }
} }
// Count printf/scanf parameters.. // Count printf/scanf parameters..
unsigned int numFunction = 0; unsigned int numFunction = 0;
while (argListTok) { while (argListTok) {
// TODO: Perform type checks
numFunction++; numFunction++;
argListTok = argListTok->nextArgument(); // Find next argument argListTok = argListTok->nextArgument(); // Find next argument
} }

View File

@ -1587,6 +1587,11 @@ private:
" sscanf(dummy, \"%d%d\", foo(iVal), iVal);\n" " sscanf(dummy, \"%d%d\", foo(iVal), iVal);\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:3]: (error) Possible null pointer dereference: iVal\n", errout.str()); ASSERT_EQUALS("[test.cpp:3]: (error) Possible null pointer dereference: iVal\n", errout.str());
check("void f(char* dummy) {\n"
" sscanf(dummy, \"%*d%u\", 0);\n"
"}");
ASSERT_EQUALS("[test.cpp:2]: (error) Null pointer dereference\n", errout.str());
} }
void nullpointer_in_return() { void nullpointer_in_return() {

View File

@ -89,6 +89,7 @@ private:
TEST_CASE(testScanf2); TEST_CASE(testScanf2);
TEST_CASE(testScanf3); TEST_CASE(testScanf3);
TEST_CASE(testScanfArgument);
TEST_CASE(testPrintfArgument); TEST_CASE(testPrintfArgument);
TEST_CASE(trac1132); TEST_CASE(trac1132);
@ -1957,6 +1958,47 @@ private:
ASSERT_EQUALS("[test.cpp:7]: (warning) fscanf format string has 0 parameters but 1 are given\n", errout.str()); ASSERT_EQUALS("[test.cpp:7]: (warning) fscanf format string has 0 parameters but 1 are given\n", errout.str());
} }
void testScanfArgument() {
check("void foo() {\n"
" scanf(\"%1d\", &foo);\n"
" sscanf(bar, \"%1d\", &foo);\n"
" scanf(\"%1u%1u\", &foo, bar());\n"
" scanf(\"%*1x %1x %29s\", &count, KeyName);\n" // #3373
"}\n",
"test.cpp",
true
);
ASSERT_EQUALS("", errout.str());
check("void foo() {\n"
" scanf(\"\", &foo);\n"
" scanf(\"%1d\", &foo, &bar);\n"
" fscanf(bar, \"%1d\", &foo, &bar);\n"
" scanf(\"%*1x %1x %29s\", &count, KeyName, foo);\n"
"}\n",
"test.cpp",
true
);
ASSERT_EQUALS("[test.cpp:2]: (warning) scanf format string has 0 parameters but 1 are given\n"
"[test.cpp:3]: (warning) scanf format string has 1 parameters but 2 are given\n"
"[test.cpp:4]: (warning) fscanf format string has 1 parameters but 2 are given\n"
"[test.cpp:5]: (warning) scanf format string has 2 parameters but 3 are given\n", errout.str());
check("void foo() {\n"
" scanf(\"%1d\");\n"
" scanf(\"%1u%1u\", bar());\n"
" sscanf(bar, \"%1d%1d\", &foo);\n"
" scanf(\"%*1x %1x %29s\", &count);\n"
"}\n",
"test.cpp",
true
);
ASSERT_EQUALS("[test.cpp:2]: (error) scanf format string has 1 parameters but only 0 are given\n"
"[test.cpp:3]: (error) scanf format string has 2 parameters but only 1 are given\n"
"[test.cpp:4]: (error) sscanf format string has 2 parameters but only 1 are given\n"
"[test.cpp:5]: (error) scanf format string has 2 parameters but only 1 are given\n", errout.str());
}
void testPrintfArgument() { void testPrintfArgument() {
check("void foo() {\n" check("void foo() {\n"
" printf(\"%u\");\n" " printf(\"%u\");\n"