Fix 10158 FP memleak when pointer is stored in a sub-object (#3764)
This commit is contained in:
parent
11387cbb41
commit
94a1f76ec4
|
@ -758,6 +758,32 @@ void CheckMemoryLeakStructMember::checkStructVariable(const Variable * const var
|
||||||
|
|
||||||
// Check struct..
|
// Check struct..
|
||||||
int indentlevel2 = 0;
|
int indentlevel2 = 0;
|
||||||
|
|
||||||
|
auto deallocInFunction = [this](const Token* tok, int structid) -> bool {
|
||||||
|
// Calling non-function / function that doesn't deallocate?
|
||||||
|
if (CheckMemoryLeakInFunction::test_white_list(tok->str(), mSettings, mTokenizer->isCPP()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Check if the struct is used..
|
||||||
|
bool deallocated = false;
|
||||||
|
const Token* const end = tok->linkAt(1);
|
||||||
|
for (const Token* tok2 = tok; tok2 != end; tok2 = tok2->next()) {
|
||||||
|
if (Token::Match(tok2, "[(,] &| %varid% [,)]", structid)) {
|
||||||
|
/** @todo check if the function deallocates the memory */
|
||||||
|
deallocated = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Token::Match(tok2, "[(,] &| %varid% . %name% [,)]", structid)) {
|
||||||
|
/** @todo check if the function deallocates the memory */
|
||||||
|
deallocated = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return deallocated;
|
||||||
|
};
|
||||||
|
|
||||||
for (const Token *tok2 = variable->nameToken(); tok2 && tok2 != variable->scope()->bodyEnd; tok2 = tok2->next()) {
|
for (const Token *tok2 = variable->nameToken(); tok2 && tok2 != variable->scope()->bodyEnd; tok2 = tok2->next()) {
|
||||||
if (tok2->str() == "{")
|
if (tok2->str() == "{")
|
||||||
++indentlevel2;
|
++indentlevel2;
|
||||||
|
@ -867,7 +893,8 @@ void CheckMemoryLeakStructMember::checkStructVariable(const Variable * const var
|
||||||
// Returning from function without deallocating struct member?
|
// Returning from function without deallocating struct member?
|
||||||
if (!Token::Match(tok3, "return %varid% ;", structid) &&
|
if (!Token::Match(tok3, "return %varid% ;", structid) &&
|
||||||
!Token::Match(tok3, "return & %varid%", structid) &&
|
!Token::Match(tok3, "return & %varid%", structid) &&
|
||||||
!(Token::Match(tok3, "return %varid% . %var%", structid) && tok3->tokAt(3)->varId() == structmemberid)) {
|
!(Token::Match(tok3, "return %varid% . %var%", structid) && tok3->tokAt(3)->varId() == structmemberid) &&
|
||||||
|
!(Token::Match(tok3, "return %name% (") && tok3->astOperand1() && deallocInFunction(tok3->astOperand1(), structid))) {
|
||||||
memoryLeak(tok3, variable->name() + "." + tok2->strAt(2), Malloc);
|
memoryLeak(tok3, variable->name() + "." + tok2->strAt(2), Malloc);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -886,28 +913,7 @@ void CheckMemoryLeakStructMember::checkStructVariable(const Variable * const var
|
||||||
|
|
||||||
// using struct in a function call..
|
// using struct in a function call..
|
||||||
else if (Token::Match(tok3, "%name% (")) {
|
else if (Token::Match(tok3, "%name% (")) {
|
||||||
// Calling non-function / function that doesn't deallocate?
|
if (deallocInFunction(tok3, structid))
|
||||||
if (CheckMemoryLeakInFunction::test_white_list(tok3->str(), mSettings, mTokenizer->isCPP()))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Check if the struct is used..
|
|
||||||
bool deallocated = false;
|
|
||||||
const Token* const end4 = tok3->linkAt(1);
|
|
||||||
for (const Token *tok4 = tok3; tok4 != end4; tok4 = tok4->next()) {
|
|
||||||
if (Token::Match(tok4, "[(,] &| %varid% [,)]", structid)) {
|
|
||||||
/** @todo check if the function deallocates the memory */
|
|
||||||
deallocated = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Token::Match(tok4, "[(,] &| %varid% . %name% [,)]", structid)) {
|
|
||||||
/** @todo check if the function deallocates the memory */
|
|
||||||
deallocated = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (deallocated)
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1693,7 +1693,7 @@ private:
|
||||||
TEST_CASE(function2); // #2848: Taking address in function
|
TEST_CASE(function2); // #2848: Taking address in function
|
||||||
TEST_CASE(function3); // #3024: kernel list
|
TEST_CASE(function3); // #3024: kernel list
|
||||||
TEST_CASE(function4); // #3038: Deallocating in function
|
TEST_CASE(function4); // #3038: Deallocating in function
|
||||||
TEST_CASE(function5); // #10381, #10382
|
TEST_CASE(function5); // #10381, #10382, #10158
|
||||||
|
|
||||||
// Handle if-else
|
// Handle if-else
|
||||||
TEST_CASE(ifelse);
|
TEST_CASE(ifelse);
|
||||||
|
@ -1943,6 +1943,13 @@ private:
|
||||||
" return (nc_rpc)rpc;\n"
|
" return (nc_rpc)rpc;\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("T* f(const char *str) {\n" // #10158
|
||||||
|
" S* s = malloc(sizeof(S));\n"
|
||||||
|
" s->str = strdup(str);\n"
|
||||||
|
" return NewT(s);\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ifelse() {
|
void ifelse() {
|
||||||
|
|
Loading…
Reference in New Issue