Fix for conditional memory allocation inside if-condition (#986)

* Add test cases for allocation inside if-condition

* Fix missed memory leak and false positive double free for allocation inside if-condition
This commit is contained in:
Björge Dijkstra 2017-10-26 19:11:00 +02:00 committed by Daniel Marjamäki
parent 76c3cef4d6
commit 94031ef11d
2 changed files with 50 additions and 0 deletions

View File

@ -325,6 +325,24 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
else if (Token::simpleMatch(tok, "if (")) { else if (Token::simpleMatch(tok, "if (")) {
// Parse function calls inside the condition // Parse function calls inside the condition
for (const Token *innerTok = tok->tokAt(2); innerTok; innerTok = innerTok->next()) { for (const Token *innerTok = tok->tokAt(2); innerTok; innerTok = innerTok->next()) {
if (Token::Match(innerTok, "%var% =")) {
// allocation?
if (Token::Match(innerTok->tokAt(2), "%type% (")) {
const Library::AllocFunc* f = _settings->library.alloc(innerTok->tokAt(2));
if (f && f->arg == -1) {
VarInfo::AllocInfo& varAlloc = alloctype[innerTok->varId()];
varAlloc.type = f->groupId;
varAlloc.status = VarInfo::ALLOC;
}
} else if (_tokenizer->isCPP() && Token::Match(innerTok->tokAt(2), "new !!(")) {
const Token* tok2 = innerTok->tokAt(2)->astOperand1();
bool arrayNew = (tok2 && (tok2->str() == "[" || (tok2->str() == "(" && tok2->astOperand1() && tok2->astOperand1()->str() == "[")));
VarInfo::AllocInfo& varAlloc = alloctype[innerTok->varId()];
varAlloc.type = arrayNew ? -2 : -1;
varAlloc.status = VarInfo::ALLOC;
}
}
if (innerTok->str() == ")") if (innerTok->str() == ")")
break; break;
if (innerTok->str() == "(" && innerTok->previous()->isName()) { if (innerTok->str() == "(" && innerTok->previous()->isName()) {

View File

@ -55,6 +55,7 @@ private:
TEST_CASE(assign11); // #3942: x = a(b(p)); TEST_CASE(assign11); // #3942: x = a(b(p));
TEST_CASE(assign12); // #4236: FP. bar(&x); TEST_CASE(assign12); // #4236: FP. bar(&x);
TEST_CASE(assign13); // #4237: FP. char*&ref=p; p=malloc(10); free(ref); TEST_CASE(assign13); // #4237: FP. char*&ref=p; p=malloc(10); free(ref);
TEST_CASE(assign14);
TEST_CASE(deallocuse1); TEST_CASE(deallocuse1);
TEST_CASE(deallocuse2); TEST_CASE(deallocuse2);
@ -70,6 +71,7 @@ private:
TEST_CASE(doublefree4); // #5451 - FP when exit is called TEST_CASE(doublefree4); // #5451 - FP when exit is called
TEST_CASE(doublefree5); // #5522 TEST_CASE(doublefree5); // #5522
TEST_CASE(doublefree6); // #7685 TEST_CASE(doublefree6); // #7685
TEST_CASE(doublefree7);
// exit // exit
TEST_CASE(exit1); TEST_CASE(exit1);
@ -269,6 +271,20 @@ private:
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
} }
void assign14() {
check("void f(int x) {\n"
" char *p;\n"
" if (x && (p = malloc(10))) { }"
"}");
ASSERT_EQUALS("[test.c:3]: (error) Memory leak: p\n", errout.str());
check("void f(int x) {\n"
" char *p;\n"
" if (x && (p = new char[10])) { }"
"}", true);
ASSERT_EQUALS("[test.cpp:3]: (error) Memory leak: p\n", errout.str());
}
void deallocuse1() { void deallocuse1() {
check("void f(char *p) {\n" check("void f(char *p) {\n"
" free(p);\n" " free(p);\n"
@ -857,6 +873,22 @@ private:
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
} }
void doublefree7() {
check("void f(char *p, int x) {\n"
" free(p);\n"
" if (x && (p = malloc(10)))\n"
" free(p);\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void f(char *p, int x) {\n"
" delete[] p;\n"
" if (x && (p = new char[10]))\n"
" delete[] p;\n"
"}");
ASSERT_EQUALS("", errout.str());
}
void exit1() { void exit1() {
check("void f() {\n" check("void f() {\n"
" char *p = malloc(10);\n" " char *p = malloc(10);\n"