Added scanf check. Modified patch submitted by Eric Sesterhenn
This commit is contained in:
parent
0d8b74e538
commit
5846630fa9
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue