Skip to content

Commit 94a1f76

Browse files
Fix 10158 FP memleak when pointer is stored in a sub-object (#3764)
1 parent 11387cb commit 94a1f76

2 files changed

Lines changed: 37 additions & 24 deletions

File tree

lib/checkmemoryleak.cpp

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,32 @@ void CheckMemoryLeakStructMember::checkStructVariable(const Variable * const var
758758

759759
// Check struct..
760760
int indentlevel2 = 0;
761+
762+
auto deallocInFunction = [this](const Token* tok, int structid) -> bool {
763+
// Calling non-function / function that doesn't deallocate?
764+
if (CheckMemoryLeakInFunction::test_white_list(tok->str(), mSettings, mTokenizer->isCPP()))
765+
return false;
766+
767+
// Check if the struct is used..
768+
bool deallocated = false;
769+
const Token* const end = tok->linkAt(1);
770+
for (const Token* tok2 = tok; tok2 != end; tok2 = tok2->next()) {
771+
if (Token::Match(tok2, "[(,] &| %varid% [,)]", structid)) {
772+
/** @todo check if the function deallocates the memory */
773+
deallocated = true;
774+
break;
775+
}
776+
777+
if (Token::Match(tok2, "[(,] &| %varid% . %name% [,)]", structid)) {
778+
/** @todo check if the function deallocates the memory */
779+
deallocated = true;
780+
break;
781+
}
782+
};
783+
784+
return deallocated;
785+
};
786+
761787
for (const Token *tok2 = variable->nameToken(); tok2 && tok2 != variable->scope()->bodyEnd; tok2 = tok2->next()) {
762788
if (tok2->str() == "{")
763789
++indentlevel2;
@@ -867,7 +893,8 @@ void CheckMemoryLeakStructMember::checkStructVariable(const Variable * const var
867893
// Returning from function without deallocating struct member?
868894
if (!Token::Match(tok3, "return %varid% ;", structid) &&
869895
!Token::Match(tok3, "return & %varid%", structid) &&
870-
!(Token::Match(tok3, "return %varid% . %var%", structid) && tok3->tokAt(3)->varId() == structmemberid)) {
896+
!(Token::Match(tok3, "return %varid% . %var%", structid) && tok3->tokAt(3)->varId() == structmemberid) &&
897+
!(Token::Match(tok3, "return %name% (") && tok3->astOperand1() && deallocInFunction(tok3->astOperand1(), structid))) {
871898
memoryLeak(tok3, variable->name() + "." + tok2->strAt(2), Malloc);
872899
}
873900
break;
@@ -886,28 +913,7 @@ void CheckMemoryLeakStructMember::checkStructVariable(const Variable * const var
886913

887914
// using struct in a function call..
888915
else if (Token::Match(tok3, "%name% (")) {
889-
// Calling non-function / function that doesn't deallocate?
890-
if (CheckMemoryLeakInFunction::test_white_list(tok3->str(), mSettings, mTokenizer->isCPP()))
891-
continue;
892-
893-
// Check if the struct is used..
894-
bool deallocated = false;
895-
const Token* const end4 = tok3->linkAt(1);
896-
for (const Token *tok4 = tok3; tok4 != end4; tok4 = tok4->next()) {
897-
if (Token::Match(tok4, "[(,] &| %varid% [,)]", structid)) {
898-
/** @todo check if the function deallocates the memory */
899-
deallocated = true;
900-
break;
901-
}
902-
903-
if (Token::Match(tok4, "[(,] &| %varid% . %name% [,)]", structid)) {
904-
/** @todo check if the function deallocates the memory */
905-
deallocated = true;
906-
break;
907-
}
908-
}
909-
910-
if (deallocated)
916+
if (deallocInFunction(tok3, structid))
911917
break;
912918
}
913919
}

test/testmemleak.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1693,7 +1693,7 @@ class TestMemleakStructMember : public TestFixture {
16931693
TEST_CASE(function2); // #2848: Taking address in function
16941694
TEST_CASE(function3); // #3024: kernel list
16951695
TEST_CASE(function4); // #3038: Deallocating in function
1696-
TEST_CASE(function5); // #10381, #10382
1696+
TEST_CASE(function5); // #10381, #10382, #10158
16971697

16981698
// Handle if-else
16991699
TEST_CASE(ifelse);
@@ -1943,6 +1943,13 @@ class TestMemleakStructMember : public TestFixture {
19431943
" return (nc_rpc)rpc;\n"
19441944
"}");
19451945
ASSERT_EQUALS("", errout.str());
1946+
1947+
check("T* f(const char *str) {\n" // #10158
1948+
" S* s = malloc(sizeof(S));\n"
1949+
" s->str = strdup(str);\n"
1950+
" return NewT(s);\n"
1951+
"}\n");
1952+
ASSERT_EQUALS("", errout.str());
19461953
}
19471954

19481955
void ifelse() {

0 commit comments

Comments
 (0)