Fixed #2969 (False positive: assign address of auto-var to function parameter, when function parameter is reassigned later)

This commit is contained in:
Daniel Marjamäki 2011-08-09 18:24:39 +02:00
parent 003956e42e
commit 2b8b0c44b2
3 changed files with 62 additions and 28 deletions

View File

@ -99,27 +99,35 @@ void CheckAutoVariables::autoVariables()
{
const Variable * var = symbolDatabase->getVariableFromVarId(tok->tokAt(5)->varId());
if (var && (!var->isClass() || var->type()))
errorAutoVariableAssignment(tok);
errorAutoVariableAssignment(tok, false);
}
else if (Token::Match(tok, "[;{}] %var% . %var% = & %var%"))
{
// TODO: check if the parameter is only changed temporarily (#2969)
if (_settings->inconclusive)
{
const Variable * var1 = symbolDatabase->getVariableFromVarId(tok->tokAt(1)->varId());
if (var1 && var1->isArgument() && Token::Match(var1->nameToken()->tokAt(-2), "%type% *"))
{
const Variable * var2 = symbolDatabase->getVariableFromVarId(tok->tokAt(6)->varId());
if (var2 && var2->isLocal() && !var2->isStatic())
errorAutoVariableAssignment(tok);
errorAutoVariableAssignment(tok, _settings->inconclusive);
}
}
tok = tok->tokAt(6);
}
else if (Token::Match(tok, "[;{}] %var% . %var% = %var% ;"))
{
// TODO: check if the parameter is only changed temporarily (#2969)
if (_settings->inconclusive)
{
const Variable * var1 = symbolDatabase->getVariableFromVarId(tok->tokAt(1)->varId());
if (var1 && var1->isArgument() && Token::Match(var1->nameToken()->tokAt(-2), "%type% *"))
{
const Variable * var2 = symbolDatabase->getVariableFromVarId(tok->tokAt(5)->varId());
if (var2 && var2->isLocal() && var2->isArray() && !var2->isStatic())
errorAutoVariableAssignment(tok);
errorAutoVariableAssignment(tok, _settings->inconclusive);
}
}
tok = tok->tokAt(5);
}
@ -130,13 +138,13 @@ void CheckAutoVariables::autoVariables()
{
const Variable * var2 = symbolDatabase->getVariableFromVarId(tok->tokAt(4)->varId());
if (var2 && var2->isLocal() && var2->isArray() && !var2->isStatic())
errorAutoVariableAssignment(tok);
errorAutoVariableAssignment(tok, false);
}
tok = tok->tokAt(4);
}
else if (Token::Match(tok, "[;{}] %var% [ %any% ] = & %var%") && errorAv(tok->tokAt(1), tok->tokAt(7)))
{
errorAutoVariableAssignment(tok);
errorAutoVariableAssignment(tok, false);
}
// Critical return
else if (Token::Match(tok, "return & %var% ;") && isAutoVar(tok->tokAt(2)->varId()))
@ -220,7 +228,9 @@ void CheckAutoVariables::errorReturnPointerToLocalArray(const Token *tok)
reportError(tok, Severity::error, "returnLocalVariable", "Returning pointer to local array variable");
}
void CheckAutoVariables::errorAutoVariableAssignment(const Token *tok)
void CheckAutoVariables::errorAutoVariableAssignment(const Token *tok, bool inconclusive)
{
if (!inconclusive)
{
reportError(tok, Severity::error, "autoVariables",
"Assigning address of local auto-variable to a function parameter.\n"
@ -229,6 +239,16 @@ void CheckAutoVariables::errorAutoVariableAssignment(const Token *tok)
"stack is freed when the function ends. So the pointer to a local variable "
"is invalid after the function ends.");
}
else
{
reportInconclusiveError(tok, Severity::error, "autoVariables",
"Inconclusive: Assigning address of local auto-variable to a function parameter.\n"
"Inconclusive: function parameter takes the address of a local auto-variable. "
"Local auto-variables are reserved from the stack. And the stack is freed when "
"the function ends. The address is invalid after the function ends and it "
"might 'leak' from the function through the parameter.");
}
}
//---------------------------------------------------------------------------

View File

@ -83,7 +83,7 @@ private:
void errorReturnAddressToAutoVariable(const Token *tok);
void errorReturnPointerToLocalArray(const Token *tok);
void errorAutoVariableAssignment(const Token *tok);
void errorAutoVariableAssignment(const Token *tok, bool inconclusive);
void errorReturnReference(const Token *tok);
void errorReturnTempReference(const Token *tok);
void errorReturnAutocstr(const Token *tok);
@ -93,7 +93,7 @@ private:
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings)
{
CheckAutoVariables c(0,settings,errorLogger);
c.errorAutoVariableAssignment(0);
c.errorAutoVariableAssignment(0, false);
c.errorReturnAddressToAutoVariable(0);
c.errorReturnPointerToLocalArray(0);
c.errorReturnReference(0);

View File

@ -35,13 +35,13 @@ private:
void check(const char code[])
void check(const char code[], bool inconclusive=false)
{
// Clear the error buffer..
errout.str("");
Settings settings;
settings.debugwarnings = true;
settings.inconclusive = inconclusive;
// Tokenize..
Tokenizer tokenizer(&settings, this);
@ -183,8 +183,15 @@ private:
"{\n"
" char a;\n"
" ab->a = &a;\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Assigning address of local auto-variable to a function parameter.\n", errout.str());
"}", false);
ASSERT_EQUALS("", errout.str());
check("void foo(struct AB *ab)\n"
"{\n"
" char a;\n"
" ab->a = &a;\n"
"}", true);
ASSERT_EQUALS("[test.cpp:3]: (error) Inconclusive: Assigning address of local auto-variable to a function parameter.\n", errout.str());
}
void testautovar6() // ticket #2931
@ -193,8 +200,15 @@ private:
"{\n"
" char a[10];\n"
" x->str = a;\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Assigning address of local auto-variable to a function parameter.\n", errout.str());
"}", false);
ASSERT_EQUALS("", errout.str());
check("void foo(struct X *x)\n"
"{\n"
" char a[10];\n"
" x->str = a;\n"
"}", true);
ASSERT_EQUALS("[test.cpp:3]: (error) Inconclusive: Assigning address of local auto-variable to a function parameter.\n", errout.str());
}
void testautovar_array1()