Fix #11019 FN memleak with redundant pointer op / #7705 FN: Memory leak not detected on struct member (#4126)

* Fix #11019 FN memleak with redundant pointer op

* Style

* Fix #7705 FN: Memory leak not detected on struct member
This commit is contained in:
chrchr-github 2022-05-23 23:21:36 +02:00 committed by GitHub
parent 8d1fd19cc6
commit 1ced94be43
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 49 additions and 6 deletions

View File

@ -725,7 +725,7 @@ void CheckMemoryLeakStructMember::check()
const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase(); const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase();
for (const Variable* var : symbolDatabase->variableList()) { for (const Variable* var : symbolDatabase->variableList()) {
if (!var || !var->isLocal() || var->isStatic() || var->isReference()) if (!var || (!var->isLocal() && !(var->isArgument() && var->scope())) || var->isStatic() || var->isReference())
continue; continue;
if (var->typeEndToken()->isStandardType()) if (var->typeEndToken()->isStandardType())
continue; continue;
@ -789,7 +789,26 @@ void CheckMemoryLeakStructMember::checkStructVariable(const Variable * const var
return deallocated; return deallocated;
}; };
for (const Token *tok2 = variable->nameToken(); tok2 && tok2 != variable->scope()->bodyEnd; tok2 = tok2->next()) { // return { memberTok, rhsTok }
auto isMemberAssignment = [](const Token* varTok, int varId) -> std::pair<const Token*, const Token*> {
if (varTok->varId() != varId)
return {};
const Token* top = varTok->astTop();
if (!Token::simpleMatch(top, "="))
return {};
const Token* dot = top->astOperand1();
while (dot && dot->str() != ".")
dot = dot->astOperand1();
if (!dot)
return {};
return { dot->astOperand2(), top->next() };
};
std::pair<const Token*, const Token*> assignToks;
const Token* tokStart = variable->nameToken();
if (variable->isArgument() && variable->scope())
tokStart = variable->scope()->bodyStart->next();
for (const Token *tok2 = tokStart; tok2 && tok2 != variable->scope()->bodyEnd; tok2 = tok2->next()) {
if (tok2->str() == "{") if (tok2->str() == "{")
++indentlevel2; ++indentlevel2;
@ -805,12 +824,12 @@ void CheckMemoryLeakStructMember::checkStructVariable(const Variable * const var
break; break;
// Struct member is allocated => check if it is also properly deallocated.. // Struct member is allocated => check if it is also properly deallocated..
else if (Token::Match(tok2->previous(), "[;{}] %varid% . %var% =", variable->declarationId())) { else if ((assignToks = isMemberAssignment(tok2, variable->declarationId())).first) {
if (getAllocationType(tok2->tokAt(4), tok2->tokAt(2)->varId()) == AllocType::No) if (getAllocationType(assignToks.second, assignToks.first->varId()) == AllocType::No)
continue; continue;
const int structid(variable->declarationId()); const int structid(variable->declarationId());
const int structmemberid(tok2->tokAt(2)->varId()); const int structmemberid(assignToks.first->varId());
// This struct member is allocated.. check that it is deallocated // This struct member is allocated.. check that it is deallocated
int indentlevel3 = indentlevel2; int indentlevel3 = indentlevel2;

View File

@ -1708,6 +1708,7 @@ private:
TEST_CASE(assign1); TEST_CASE(assign1);
TEST_CASE(assign2); TEST_CASE(assign2);
TEST_CASE(assign3); TEST_CASE(assign3);
TEST_CASE(assign4); // #11019
// Failed allocation // Failed allocation
TEST_CASE(failedAllocation); TEST_CASE(failedAllocation);
@ -1887,6 +1888,29 @@ private:
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
} }
void assign4() {
check("struct S { int a, b, c; };\n" // #11019
"void f() {\n"
" struct S s;\n"
" *&s.a = open(\"xx.log\", O_RDONLY);\n"
" ((s).b) = open(\"xx.log\", O_RDONLY);\n"
" (&s)->c = open(\"xx.log\", O_RDONLY);\n"
"}\n", false);
ASSERT_EQUALS("[test.c:7]: (error) Memory leak: s.a\n"
"[test.c:7]: (error) Memory leak: s.b\n"
"[test.c:7]: (error) Memory leak: s.c\n",
errout.str());
check("struct S { int *p, *q; };\n" // #7705
"void f(S s) {\n"
" s.p = new int[10];\n"
" s.q = malloc(40);\n"
"}\n");
ASSERT_EQUALS("[test.cpp:5]: (error) Memory leak: s.p\n"
"[test.cpp:5]: (error) Memory leak: s.q\n",
errout.str());
}
void failedAllocation() { void failedAllocation() {
check("static struct ABC * foo()\n" check("static struct ABC * foo()\n"
"{\n" "{\n"
@ -2137,7 +2161,7 @@ private:
" ((f)->realm) = strdup(realm);\n" " ((f)->realm) = strdup(realm);\n"
" if(f->realm == NULL) {}\n" " if(f->realm == NULL) {}\n"
"}", false); "}", false);
TODO_ASSERT_EQUALS("[test.c:6]: (error) Memory leak: f.realm\n", "", errout.str()); ASSERT_EQUALS("[test.c:6]: (error) Memory leak: f.realm\n", errout.str());
} }
void customAllocation() { // #4770 void customAllocation() { // #4770