Fix 10158 FP memleak when pointer is stored in a sub-object (#3764)

This commit is contained in:
chrchr-github 2022-02-02 13:13:12 +01:00 committed by GitHub
parent 11387cbb41
commit 94a1f76ec4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 37 additions and 24 deletions

View File

@ -758,6 +758,32 @@ void CheckMemoryLeakStructMember::checkStructVariable(const Variable * const var
// Check struct..
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()) {
if (tok2->str() == "{")
++indentlevel2;
@ -867,7 +893,8 @@ void CheckMemoryLeakStructMember::checkStructVariable(const Variable * const var
// Returning from function without deallocating struct member?
if (!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);
}
break;
@ -886,28 +913,7 @@ void CheckMemoryLeakStructMember::checkStructVariable(const Variable * const var
// using struct in a function call..
else if (Token::Match(tok3, "%name% (")) {
// Calling non-function / function that doesn't deallocate?
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)
if (deallocInFunction(tok3, structid))
break;
}
}

View File

@ -1693,7 +1693,7 @@ private:
TEST_CASE(function2); // #2848: Taking address in function
TEST_CASE(function3); // #3024: kernel list
TEST_CASE(function4); // #3038: Deallocating in function
TEST_CASE(function5); // #10381, #10382
TEST_CASE(function5); // #10381, #10382, #10158
// Handle if-else
TEST_CASE(ifelse);
@ -1943,6 +1943,13 @@ private:
" return (nc_rpc)rpc;\n"
"}");
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() {