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()); 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.");
}
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

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

View File

@ -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()