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

View File

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