Added scanf check. Modified patch submitted by Eric Sesterhenn

This commit is contained in:
Daniel Marjamäki 2010-08-14 15:15:12 +02:00
parent 0d8b74e538
commit 5846630fa9
3 changed files with 90 additions and 0 deletions

View File

@ -431,6 +431,51 @@ void CheckOther::invalidFunctionUsage()
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void CheckOther::invalidScanf()
{
if (!_settings->_checkCodingStyle)
return;
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
{
const Token *formatToken = 0;
if (Token::Match(tok, "scanf|vscanf ( %str% ,"))
formatToken = tok->tokAt(2);
else if (Token::Match(tok, "fscanf|vfscanf ( %var% , %str% ,"))
formatToken = tok->tokAt(4);
else
continue;
bool format = false;
// scan the string backwards, so we dont need to keep states
const std::string &formatstr(formatToken->str());
for (unsigned int i = 1; i < formatstr.length(); i++)
{
if (formatstr[i] == '%')
format = !format;
else if (!format)
continue;
else if (std::isdigit(formatstr[i]))
{
format = false;
}
else if (std::isalpha(formatstr[i]))
{
invalidScanfError(tok);
format = false;
}
}
}
}
void CheckOther::invalidScanfError(const Token *tok)
{
reportError(tok, Severity::style,
"invalidscanf", "scanf without field width limits can crash with huge input data");
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Check for unsigned divisions // Check for unsigned divisions

View File

@ -82,6 +82,7 @@ public:
checkOther.checkZeroDivision(); checkOther.checkZeroDivision();
checkOther.checkMathFunctions(); checkOther.checkMathFunctions();
checkOther.checkFflushOnInputStream(); checkOther.checkFflushOnInputStream();
checkOther.invalidScanf();
checkOther.nullConstantDereference(); checkOther.nullConstantDereference();
@ -184,6 +185,10 @@ public:
void sizeofCalculation(); void sizeofCalculation();
void sizeofCalculationError(const Token *tok); void sizeofCalculationError(const Token *tok);
/** @brief scanf can crash if width specifiers are not used */
void invalidScanf();
void invalidScanfError(const Token *tok);
/** @brief %Check for assigning to the same variable twice in a switch statement*/ /** @brief %Check for assigning to the same variable twice in a switch statement*/
void checkRedundantAssignmentInSwitch(); void checkRedundantAssignmentInSwitch();
@ -246,6 +251,7 @@ public:
sizeofCalculationError(0); sizeofCalculationError(0);
emptyCatchBlockError(0); emptyCatchBlockError(0);
redundantAssignmentInSwitchError(0, "varname"); redundantAssignmentInSwitchError(0, "varname");
invalidScanfError(0);
// optimisations // optimisations
postIncrementError(0, "varname", true); postIncrementError(0, "varname", true);
@ -273,6 +279,7 @@ public:
"* redundant if\n" "* redundant if\n"
"* bad usage of the function 'strtol'\n" "* bad usage of the function 'strtol'\n"
"* [[CheckUnsignedDivision|unsigned division]]\n" "* [[CheckUnsignedDivision|unsigned division]]\n"
"* Dangerous usage of 'scanf'\n"
"* unused struct member\n" "* unused struct member\n"
"* passing parameter by value\n" "* passing parameter by value\n"
"* [[IncompleteStatement|Incomplete statement]]\n" "* [[IncompleteStatement|Incomplete statement]]\n"

View File

@ -103,6 +103,9 @@ private:
TEST_CASE(emptyCatchBlock); TEST_CASE(emptyCatchBlock);
TEST_CASE(switchRedundantAssignmentTest); TEST_CASE(switchRedundantAssignmentTest);
TEST_CASE(testScanf1);
TEST_CASE(testScanf2);
} }
void check(const char code[]) void check(const char code[])
@ -133,6 +136,7 @@ private:
checkOther.checkMathFunctions(); checkOther.checkMathFunctions();
checkOther.checkEmptyStringTest(); checkOther.checkEmptyStringTest();
checkOther.checkFflushOnInputStream(); checkOther.checkFflushOnInputStream();
checkOther.invalidScanf();
} }
@ -3007,6 +3011,40 @@ private:
"}\n"); "}\n");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
} }
void testScanf1()
{
check("#include <stdio.h>\n"
"int main(int argc, char **argv)\n"
"{\n"
" int a, b;\n"
" FILE *file = fopen(\"test\", \"r\");\n"
" b = fscanf(file, \"aa %ds\", &a);\n"
" c = scanf(\"aa %ds\", &a);\n"
" b = fscanf(file, \"aa%%ds\", &a);\n"
" fclose(file);\n"
" return b;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:6]: (style) scanf without field width limits can crash with huge input data\n"
"[test.cpp:7]: (style) scanf without field width limits can crash with huge input data\n", errout.str());
}
void testScanf2()
{
check("#include <stdio.h>\n"
"int main(int argc, char **argv)\n"
"{\n"
" int a, b;\n"
" FILE *file = fopen(\"test\", \"r\");\n"
" b = fscanf(file, \"aa%%%ds\", &a);\n"
" c = scanf(\"aa %%%ds\", &a);\n"
" b = fscanf(file, \"aa%%ds\", &a);\n"
" fclose(file);\n"
" return b;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:6]: (style) scanf without field width limits can crash with huge input data\n"
"[test.cpp:7]: (style) scanf without field width limits can crash with huge input data\n", errout.str());
}
}; };
REGISTER_TEST(TestOther) REGISTER_TEST(TestOther)