CheckAutoVar: Improved usage of AST and ValueFlow

This commit is contained in:
Daniel Marjamäki 2015-11-15 14:48:13 +01:00
parent 481d800d5a
commit 4e578af603
2 changed files with 56 additions and 29 deletions

View File

@ -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);
}
}
}

View File

@ -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"