Fixed #2969 (False positive: assign address of auto-var to function parameter, when function parameter is reassigned later)
This commit is contained in:
parent
003956e42e
commit
2b8b0c44b2
|
@ -99,27 +99,35 @@ void CheckAutoVariables::autoVariables()
|
||||||
{
|
{
|
||||||
const Variable * var = symbolDatabase->getVariableFromVarId(tok->tokAt(5)->varId());
|
const Variable * var = symbolDatabase->getVariableFromVarId(tok->tokAt(5)->varId());
|
||||||
if (var && (!var->isClass() || var->type()))
|
if (var && (!var->isClass() || var->type()))
|
||||||
errorAutoVariableAssignment(tok);
|
errorAutoVariableAssignment(tok, false);
|
||||||
}
|
}
|
||||||
else if (Token::Match(tok, "[;{}] %var% . %var% = & %var%"))
|
else if (Token::Match(tok, "[;{}] %var% . %var% = & %var%"))
|
||||||
{
|
{
|
||||||
const Variable * var1 = symbolDatabase->getVariableFromVarId(tok->tokAt(1)->varId());
|
// TODO: check if the parameter is only changed temporarily (#2969)
|
||||||
if (var1 && var1->isArgument() && Token::Match(var1->nameToken()->tokAt(-2), "%type% *"))
|
if (_settings->inconclusive)
|
||||||
{
|
{
|
||||||
const Variable * var2 = symbolDatabase->getVariableFromVarId(tok->tokAt(6)->varId());
|
const Variable * var1 = symbolDatabase->getVariableFromVarId(tok->tokAt(1)->varId());
|
||||||
if (var2 && var2->isLocal() && !var2->isStatic())
|
if (var1 && var1->isArgument() && Token::Match(var1->nameToken()->tokAt(-2), "%type% *"))
|
||||||
errorAutoVariableAssignment(tok);
|
{
|
||||||
|
const Variable * var2 = symbolDatabase->getVariableFromVarId(tok->tokAt(6)->varId());
|
||||||
|
if (var2 && var2->isLocal() && !var2->isStatic())
|
||||||
|
errorAutoVariableAssignment(tok, _settings->inconclusive);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tok = tok->tokAt(6);
|
tok = tok->tokAt(6);
|
||||||
}
|
}
|
||||||
else if (Token::Match(tok, "[;{}] %var% . %var% = %var% ;"))
|
else if (Token::Match(tok, "[;{}] %var% . %var% = %var% ;"))
|
||||||
{
|
{
|
||||||
const Variable * var1 = symbolDatabase->getVariableFromVarId(tok->tokAt(1)->varId());
|
// TODO: check if the parameter is only changed temporarily (#2969)
|
||||||
if (var1 && var1->isArgument() && Token::Match(var1->nameToken()->tokAt(-2), "%type% *"))
|
if (_settings->inconclusive)
|
||||||
{
|
{
|
||||||
const Variable * var2 = symbolDatabase->getVariableFromVarId(tok->tokAt(5)->varId());
|
const Variable * var1 = symbolDatabase->getVariableFromVarId(tok->tokAt(1)->varId());
|
||||||
if (var2 && var2->isLocal() && var2->isArray() && !var2->isStatic())
|
if (var1 && var1->isArgument() && Token::Match(var1->nameToken()->tokAt(-2), "%type% *"))
|
||||||
errorAutoVariableAssignment(tok);
|
{
|
||||||
|
const Variable * var2 = symbolDatabase->getVariableFromVarId(tok->tokAt(5)->varId());
|
||||||
|
if (var2 && var2->isLocal() && var2->isArray() && !var2->isStatic())
|
||||||
|
errorAutoVariableAssignment(tok, _settings->inconclusive);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tok = tok->tokAt(5);
|
tok = tok->tokAt(5);
|
||||||
}
|
}
|
||||||
|
@ -130,13 +138,13 @@ void CheckAutoVariables::autoVariables()
|
||||||
{
|
{
|
||||||
const Variable * var2 = symbolDatabase->getVariableFromVarId(tok->tokAt(4)->varId());
|
const Variable * var2 = symbolDatabase->getVariableFromVarId(tok->tokAt(4)->varId());
|
||||||
if (var2 && var2->isLocal() && var2->isArray() && !var2->isStatic())
|
if (var2 && var2->isLocal() && var2->isArray() && !var2->isStatic())
|
||||||
errorAutoVariableAssignment(tok);
|
errorAutoVariableAssignment(tok, false);
|
||||||
}
|
}
|
||||||
tok = tok->tokAt(4);
|
tok = tok->tokAt(4);
|
||||||
}
|
}
|
||||||
else if (Token::Match(tok, "[;{}] %var% [ %any% ] = & %var%") && errorAv(tok->tokAt(1), tok->tokAt(7)))
|
else if (Token::Match(tok, "[;{}] %var% [ %any% ] = & %var%") && errorAv(tok->tokAt(1), tok->tokAt(7)))
|
||||||
{
|
{
|
||||||
errorAutoVariableAssignment(tok);
|
errorAutoVariableAssignment(tok, false);
|
||||||
}
|
}
|
||||||
// Critical return
|
// Critical return
|
||||||
else if (Token::Match(tok, "return & %var% ;") && isAutoVar(tok->tokAt(2)->varId()))
|
else if (Token::Match(tok, "return & %var% ;") && isAutoVar(tok->tokAt(2)->varId()))
|
||||||
|
@ -220,14 +228,26 @@ void CheckAutoVariables::errorReturnPointerToLocalArray(const Token *tok)
|
||||||
reportError(tok, Severity::error, "returnLocalVariable", "Returning pointer to local array variable");
|
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)
|
||||||
{
|
{
|
||||||
reportError(tok, Severity::error, "autoVariables",
|
if (!inconclusive)
|
||||||
"Assigning address of local auto-variable to a function parameter.\n"
|
{
|
||||||
"Dangerous assignment - function parameter takes the address of a local "
|
reportError(tok, Severity::error, "autoVariables",
|
||||||
"auto-variable. Local auto-variables are reserved from the stack. And the "
|
"Assigning address of local auto-variable to a function parameter.\n"
|
||||||
"stack is freed when the function ends. So the pointer to a local variable "
|
"Dangerous assignment - function parameter takes the address of a local "
|
||||||
"is invalid after the function ends.");
|
"auto-variable. Local auto-variables are reserved from the stack. And the "
|
||||||
|
"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.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
|
@ -83,7 +83,7 @@ private:
|
||||||
|
|
||||||
void errorReturnAddressToAutoVariable(const Token *tok);
|
void errorReturnAddressToAutoVariable(const Token *tok);
|
||||||
void errorReturnPointerToLocalArray(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 errorReturnReference(const Token *tok);
|
||||||
void errorReturnTempReference(const Token *tok);
|
void errorReturnTempReference(const Token *tok);
|
||||||
void errorReturnAutocstr(const Token *tok);
|
void errorReturnAutocstr(const Token *tok);
|
||||||
|
@ -93,7 +93,7 @@ private:
|
||||||
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings)
|
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings)
|
||||||
{
|
{
|
||||||
CheckAutoVariables c(0,settings,errorLogger);
|
CheckAutoVariables c(0,settings,errorLogger);
|
||||||
c.errorAutoVariableAssignment(0);
|
c.errorAutoVariableAssignment(0, false);
|
||||||
c.errorReturnAddressToAutoVariable(0);
|
c.errorReturnAddressToAutoVariable(0);
|
||||||
c.errorReturnPointerToLocalArray(0);
|
c.errorReturnPointerToLocalArray(0);
|
||||||
c.errorReturnReference(0);
|
c.errorReturnReference(0);
|
||||||
|
|
|
@ -35,13 +35,13 @@ private:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void check(const char code[])
|
void check(const char code[], bool inconclusive=false)
|
||||||
{
|
{
|
||||||
// Clear the error buffer..
|
// Clear the error buffer..
|
||||||
errout.str("");
|
errout.str("");
|
||||||
|
|
||||||
Settings settings;
|
Settings settings;
|
||||||
settings.debugwarnings = true;
|
settings.inconclusive = inconclusive;
|
||||||
|
|
||||||
// Tokenize..
|
// Tokenize..
|
||||||
Tokenizer tokenizer(&settings, this);
|
Tokenizer tokenizer(&settings, this);
|
||||||
|
@ -183,8 +183,15 @@ private:
|
||||||
"{\n"
|
"{\n"
|
||||||
" char a;\n"
|
" char a;\n"
|
||||||
" ab->a = &a;\n"
|
" ab->a = &a;\n"
|
||||||
"}");
|
"}", false);
|
||||||
ASSERT_EQUALS("[test.cpp:3]: (error) Assigning address of local auto-variable to a function parameter.\n", errout.str());
|
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
|
void testautovar6() // ticket #2931
|
||||||
|
@ -193,8 +200,15 @@ private:
|
||||||
"{\n"
|
"{\n"
|
||||||
" char a[10];\n"
|
" char a[10];\n"
|
||||||
" x->str = a;\n"
|
" x->str = a;\n"
|
||||||
"}");
|
"}", false);
|
||||||
ASSERT_EQUALS("[test.cpp:3]: (error) Assigning address of local auto-variable to a function parameter.\n", errout.str());
|
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()
|
void testautovar_array1()
|
||||||
|
|
Loading…
Reference in New Issue