CheckAutoVar: Improved usage of AST and ValueFlow
This commit is contained in:
parent
481d800d5a
commit
4e578af603
|
@ -88,13 +88,27 @@ bool CheckAutoVariables::isAutoVar(const Token *tok)
|
|||
|
||||
bool CheckAutoVariables::isAutoVarArray(const Token *tok)
|
||||
{
|
||||
// Variable
|
||||
if (!tok)
|
||||
return false;
|
||||
|
||||
// &x[..]
|
||||
if (tok->str() == "&" && Token::simpleMatch(tok->astOperand1(), "[") && !tok->astOperand2())
|
||||
return isAutoVarArray(tok->astOperand1()->astOperand1());
|
||||
|
||||
// x+y
|
||||
if (tok->str() == "+")
|
||||
return isAutoVarArray(tok->astOperand1()) || isAutoVarArray(tok->astOperand2());
|
||||
|
||||
const Variable *var = tok->variable();
|
||||
if (var && var->isLocal() && !var->isStatic() && var->isArray() && !var->isPointer())
|
||||
if (!var)
|
||||
return false;
|
||||
|
||||
// Variable
|
||||
if (var->isLocal() && !var->isStatic() && var->isArray() && !var->isPointer())
|
||||
return true;
|
||||
|
||||
// ValueFlow
|
||||
if (var && var->isPointer()) {
|
||||
if (var->isPointer()) {
|
||||
for (std::list<ValueFlow::Value>::const_iterator it = tok->values.begin(); it != tok->values.end(); ++it) {
|
||||
const ValueFlow::Value &val = *it;
|
||||
if (val.tokvalue && isAutoVarArray(val.tokvalue))
|
||||
|
@ -221,10 +235,6 @@ void CheckAutoVariables::autoVariables()
|
|||
if (var1 && var1->isArgument() && var1->typeEndToken()->str() != "&")
|
||||
errorReturnAddressOfFunctionParameter(tok, varTok->str());
|
||||
}
|
||||
} else if (Token::Match(tok, "return & %var% [") &&
|
||||
Token::simpleMatch(tok->linkAt(3), "] ;") &&
|
||||
isAutoVarArray(tok->tokAt(2))) {
|
||||
errorReturnAddressToAutoVariable(tok);
|
||||
}
|
||||
// Invalid pointer deallocation
|
||||
else if ((Token::Match(tok, "%name% ( %var% ) ;") && _settings->library.dealloc(tok)) ||
|
||||
|
@ -260,10 +270,8 @@ void CheckAutoVariables::returnPointerToLocalArray()
|
|||
if (tok->previous() && tok->previous()->str() == "*") {
|
||||
for (const Token *tok2 = scope->classStart->next(); tok2 && tok2 != scope->classEnd; tok2 = tok2->next()) {
|
||||
// Return pointer to local array variable..
|
||||
if (Token::Match(tok2, "return %var% ;")) {
|
||||
if (isAutoVarArray(tok2->next())) {
|
||||
errorReturnPointerToLocalArray(tok2);
|
||||
}
|
||||
if (tok2 ->str() == "return" && isAutoVarArray(tok2->astOperand1())) {
|
||||
errorReturnPointerToLocalArray(tok2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,7 +79,6 @@ private:
|
|||
TEST_CASE(testautovar_return1);
|
||||
TEST_CASE(testautovar_return2);
|
||||
TEST_CASE(testautovar_return3);
|
||||
TEST_CASE(testautovar_return4); // ticket #3030
|
||||
TEST_CASE(testautovar_extern);
|
||||
TEST_CASE(testinvaliddealloc);
|
||||
TEST_CASE(testinvaliddealloc_C);
|
||||
|
@ -88,6 +87,9 @@ private:
|
|||
|
||||
TEST_CASE(returnLocalVariable1);
|
||||
TEST_CASE(returnLocalVariable2);
|
||||
TEST_CASE(returnLocalVariable3); // &x[0]
|
||||
TEST_CASE(returnLocalVariable4); // x+y
|
||||
TEST_CASE(returnLocalVariable5); // cast
|
||||
|
||||
// return reference..
|
||||
TEST_CASE(returnReference1);
|
||||
|
@ -464,23 +466,6 @@ private:
|
|||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void testautovar_return4() {
|
||||
// #3030
|
||||
check("char *foo()\n"
|
||||
"{\n"
|
||||
" char q[] = \"AAAAAAAAAAAA\";\n"
|
||||
" return &q[1];\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:4]: (error) Address of an auto-variable returned.\n", errout.str());
|
||||
|
||||
check("char *foo()\n"
|
||||
"{\n"
|
||||
" static char q[] = \"AAAAAAAAAAAA\";\n"
|
||||
" return &q[1];\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void testautovar_extern() {
|
||||
check("struct foo *f()\n"
|
||||
"{\n"
|
||||
|
@ -672,6 +657,40 @@ private:
|
|||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
|
||||
void returnLocalVariable3() { // &x[..]
|
||||
// #3030
|
||||
check("char *foo() {\n"
|
||||
" char q[] = \"AAAAAAAAAAAA\";\n"
|
||||
" return &q[1];\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:3]: (error) Pointer to local array variable returned.\n", errout.str());
|
||||
|
||||
check("char *foo()\n"
|
||||
"{\n"
|
||||
" static char q[] = \"AAAAAAAAAAAA\";\n"
|
||||
" return &q[1];\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void returnLocalVariable4() { // x+y
|
||||
check("char *foo() {\n"
|
||||
" char x[10] = {0};\n"
|
||||
" return x+5;\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:3]: (error) Pointer to local array variable returned.\n", errout.str());
|
||||
}
|
||||
|
||||
void returnLocalVariable5() { // cast
|
||||
check("char *foo() {\n"
|
||||
" int x[10] = {0};\n"
|
||||
" return (char *)x;\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:3]: (error) Pointer to local array variable returned.\n", errout.str());
|
||||
}
|
||||
|
||||
|
||||
void returnReference1() {
|
||||
check("std::string &foo()\n"
|
||||
"{\n"
|
||||
|
|
Loading…
Reference in New Issue