Check for functions calls in sizeof calculations (#1111)
* Check for functions calls in sizeof calculations * Use seperate message and id for sizeofFunction * Check for overloads * Using decltype with a function should not be an error * Fix warning * Fix false positives when running pass the close paren * Fix test error * Try to fix more false positives * Traverse using astOperand2 * Only check first argument * Update fixes from feedback from PR
This commit is contained in:
parent
1110cd0c57
commit
166e4cafcd
|
@ -317,6 +317,46 @@ void CheckSizeof::sizeofCalculationError(const Token *tok, bool inconclusive)
|
||||||
"sizeofCalculation", "Found calculation inside sizeof().", CWE682, inconclusive);
|
"sizeofCalculation", "Found calculation inside sizeof().", CWE682, inconclusive);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void CheckSizeof::sizeofFunction()
|
||||||
|
{
|
||||||
|
if (!_settings->isEnabled(Settings::WARNING))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
|
||||||
|
if (Token::simpleMatch(tok, "sizeof (")) {
|
||||||
|
|
||||||
|
// ignore if the `sizeof` result is cast to void inside a macro, i.e. the calculation is
|
||||||
|
// expected to be parsed but skipped, such as in a disabled custom ASSERT() macro
|
||||||
|
if (tok->isExpandedMacro() && tok->previous()) {
|
||||||
|
const Token *cast_end = (tok->previous()->str() == "(") ? tok->previous() : tok;
|
||||||
|
if (Token::simpleMatch(cast_end->tokAt(-3), "( void )") ||
|
||||||
|
Token::simpleMatch(cast_end->previous(), "static_cast<void>")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const Token *argument = tok->next()->astOperand2()) {
|
||||||
|
const Token *checkToken = argument->previous();
|
||||||
|
if (checkToken->tokType() == Token::eName)
|
||||||
|
break;
|
||||||
|
const Function * fun = checkToken->function();
|
||||||
|
// Dont report error if the function is overloaded
|
||||||
|
if (fun && fun->nestedIn->functionMap.count(checkToken->str()) == 1) {
|
||||||
|
sizeofFunctionError(tok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckSizeof::sizeofFunctionError(const Token *tok)
|
||||||
|
{
|
||||||
|
reportError(tok, Severity::warning,
|
||||||
|
"sizeofFunctionCall", "Found function call inside sizeof().", CWE682, false);
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Check for code like sizeof()*sizeof() or sizeof(ptr)/value
|
// Check for code like sizeof()*sizeof() or sizeof(ptr)/value
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
|
@ -56,6 +56,7 @@ public:
|
||||||
// Checks
|
// Checks
|
||||||
checkSizeof.sizeofsizeof();
|
checkSizeof.sizeofsizeof();
|
||||||
checkSizeof.sizeofCalculation();
|
checkSizeof.sizeofCalculation();
|
||||||
|
checkSizeof.sizeofFunction();
|
||||||
checkSizeof.suspiciousSizeofCalculation();
|
checkSizeof.suspiciousSizeofCalculation();
|
||||||
checkSizeof.checkSizeofForArrayParameter();
|
checkSizeof.checkSizeofForArrayParameter();
|
||||||
checkSizeof.checkSizeofForPointerSize();
|
checkSizeof.checkSizeofForPointerSize();
|
||||||
|
@ -73,6 +74,9 @@ public:
|
||||||
/** @brief %Check for calculations inside sizeof */
|
/** @brief %Check for calculations inside sizeof */
|
||||||
void sizeofCalculation();
|
void sizeofCalculation();
|
||||||
|
|
||||||
|
/** @brief %Check for function call inside sizeof */
|
||||||
|
void sizeofFunction();
|
||||||
|
|
||||||
/** @brief %Check for suspicious calculations with sizeof results */
|
/** @brief %Check for suspicious calculations with sizeof results */
|
||||||
void suspiciousSizeofCalculation();
|
void suspiciousSizeofCalculation();
|
||||||
|
|
||||||
|
@ -92,6 +96,7 @@ private:
|
||||||
// Error messages..
|
// Error messages..
|
||||||
void sizeofsizeofError(const Token* tok);
|
void sizeofsizeofError(const Token* tok);
|
||||||
void sizeofCalculationError(const Token* tok, bool inconclusive);
|
void sizeofCalculationError(const Token* tok, bool inconclusive);
|
||||||
|
void sizeofFunctionError(const Token* tok);
|
||||||
void multiplySizeofError(const Token* tok);
|
void multiplySizeofError(const Token* tok);
|
||||||
void divideSizeofError(const Token* tok);
|
void divideSizeofError(const Token* tok);
|
||||||
void sizeofForArrayParameterError(const Token* tok);
|
void sizeofForArrayParameterError(const Token* tok);
|
||||||
|
@ -111,6 +116,7 @@ private:
|
||||||
c.sizeofForNumericParameterError(nullptr);
|
c.sizeofForNumericParameterError(nullptr);
|
||||||
c.sizeofsizeofError(nullptr);
|
c.sizeofsizeofError(nullptr);
|
||||||
c.sizeofCalculationError(nullptr, false);
|
c.sizeofCalculationError(nullptr, false);
|
||||||
|
c.sizeofFunctionError(nullptr);
|
||||||
c.multiplySizeofError(nullptr);
|
c.multiplySizeofError(nullptr);
|
||||||
c.divideSizeofError(nullptr);
|
c.divideSizeofError(nullptr);
|
||||||
c.sizeofVoidError(nullptr);
|
c.sizeofVoidError(nullptr);
|
||||||
|
@ -129,6 +135,7 @@ private:
|
||||||
"- using sizeof(pointer) instead of the size of pointed data\n"
|
"- using sizeof(pointer) instead of the size of pointed data\n"
|
||||||
"- look for 'sizeof sizeof ..'\n"
|
"- look for 'sizeof sizeof ..'\n"
|
||||||
"- look for calculations inside sizeof()\n"
|
"- look for calculations inside sizeof()\n"
|
||||||
|
"- look for function calls inside sizeof()\n"
|
||||||
"- look for suspicious calculations with sizeof()\n"
|
"- look for suspicious calculations with sizeof()\n"
|
||||||
"- using 'sizeof(void)' which is undefined\n";
|
"- using 'sizeof(void)' which is undefined\n";
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@ private:
|
||||||
|
|
||||||
TEST_CASE(sizeofsizeof);
|
TEST_CASE(sizeofsizeof);
|
||||||
TEST_CASE(sizeofCalculation);
|
TEST_CASE(sizeofCalculation);
|
||||||
|
TEST_CASE(sizeofFunction);
|
||||||
TEST_CASE(checkPointerSizeof);
|
TEST_CASE(checkPointerSizeof);
|
||||||
TEST_CASE(checkPointerSizeofStruct);
|
TEST_CASE(checkPointerSizeofStruct);
|
||||||
TEST_CASE(sizeofDivisionMemset);
|
TEST_CASE(sizeofDivisionMemset);
|
||||||
|
@ -162,6 +163,67 @@ private:
|
||||||
"[test.cpp:5]: (warning, inconclusive) Found calculation inside sizeof().\n", errout.str());
|
"[test.cpp:5]: (warning, inconclusive) Found calculation inside sizeof().\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sizeofFunction() {
|
||||||
|
check("class Foo\n"
|
||||||
|
"{\n"
|
||||||
|
" int bar() { return 1; };\n"
|
||||||
|
"}\n"
|
||||||
|
"Foo f;int a=sizeof(f.bar());");
|
||||||
|
ASSERT_EQUALS("[test.cpp:5]: (warning) Found function call inside sizeof().\n", errout.str());
|
||||||
|
|
||||||
|
check("class Foo\n"
|
||||||
|
"{\n"
|
||||||
|
" int bar() { return 1; };\n"
|
||||||
|
" int bar() const { return 1; };\n"
|
||||||
|
"}\n"
|
||||||
|
"Foo f;int a=sizeof(f.bar());");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("class Foo\n"
|
||||||
|
"{\n"
|
||||||
|
" int bar() { return 1; };\n"
|
||||||
|
"}\n"
|
||||||
|
"Foo * fp;int a=sizeof(fp->bar());");
|
||||||
|
ASSERT_EQUALS("[test.cpp:5]: (warning) Found function call inside sizeof().\n", errout.str());
|
||||||
|
|
||||||
|
check("int a=sizeof(foo());");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("int foo() { return 1; }; int a=sizeof(foo());");
|
||||||
|
ASSERT_EQUALS("[test.cpp:1]: (warning) Found function call inside sizeof().\n", errout.str());
|
||||||
|
|
||||||
|
check("int foo() { return 1; }; sizeof(decltype(foo()));");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("int foo(int) { return 1; }; int a=sizeof(foo(0))");
|
||||||
|
ASSERT_EQUALS("[test.cpp:1]: (warning) Found function call inside sizeof().\n", errout.str());
|
||||||
|
|
||||||
|
check("char * buf; int a=sizeof(*buf);");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("int a=sizeof(foo())");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("int foo(int) { return 1; }; char buf[1024]; int a=sizeof(buf), foo(0)");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("template<class T>\n"
|
||||||
|
"struct A\n"
|
||||||
|
"{\n"
|
||||||
|
" static B f(const B &);\n"
|
||||||
|
" static A f(const A &);\n"
|
||||||
|
" static A &g();\n"
|
||||||
|
" static T &h();\n"
|
||||||
|
"\n"
|
||||||
|
" enum {\n"
|
||||||
|
" X = sizeof(f(g() >> h())) == sizeof(A),\n"
|
||||||
|
" Y = sizeof(f(g() << h())) == sizeof(A),\n"
|
||||||
|
" Z = X & Y\n"
|
||||||
|
" };\n"
|
||||||
|
"};\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
void sizeofForArrayParameter() {
|
void sizeofForArrayParameter() {
|
||||||
check("void f() {\n"
|
check("void f() {\n"
|
||||||
" int a[10];\n"
|
" int a[10];\n"
|
||||||
|
|
Loading…
Reference in New Issue