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:
parent
8d1fd19cc6
commit
1ced94be43
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue