Skip to content

Commit 94031ef

Browse files
bjddanmar
authored andcommitted
Fix for conditional memory allocation inside if-condition (danmar#986)
* Add test cases for allocation inside if-condition * Fix missed memory leak and false positive double free for allocation inside if-condition
1 parent 76c3cef commit 94031ef

File tree

2 files changed

+50
-0
lines changed

2 files changed

+50
-0
lines changed

lib/checkleakautovar.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,24 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
325325
else if (Token::simpleMatch(tok, "if (")) {
326326
// Parse function calls inside the condition
327327
for (const Token *innerTok = tok->tokAt(2); innerTok; innerTok = innerTok->next()) {
328+
if (Token::Match(innerTok, "%var% =")) {
329+
// allocation?
330+
if (Token::Match(innerTok->tokAt(2), "%type% (")) {
331+
const Library::AllocFunc* f = _settings->library.alloc(innerTok->tokAt(2));
332+
if (f && f->arg == -1) {
333+
VarInfo::AllocInfo& varAlloc = alloctype[innerTok->varId()];
334+
varAlloc.type = f->groupId;
335+
varAlloc.status = VarInfo::ALLOC;
336+
}
337+
} else if (_tokenizer->isCPP() && Token::Match(innerTok->tokAt(2), "new !!(")) {
338+
const Token* tok2 = innerTok->tokAt(2)->astOperand1();
339+
bool arrayNew = (tok2 && (tok2->str() == "[" || (tok2->str() == "(" && tok2->astOperand1() && tok2->astOperand1()->str() == "[")));
340+
VarInfo::AllocInfo& varAlloc = alloctype[innerTok->varId()];
341+
varAlloc.type = arrayNew ? -2 : -1;
342+
varAlloc.status = VarInfo::ALLOC;
343+
}
344+
}
345+
328346
if (innerTok->str() == ")")
329347
break;
330348
if (innerTok->str() == "(" && innerTok->previous()->isName()) {

test/testleakautovar.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ class TestLeakAutoVar : public TestFixture {
5555
TEST_CASE(assign11); // #3942: x = a(b(p));
5656
TEST_CASE(assign12); // #4236: FP. bar(&x);
5757
TEST_CASE(assign13); // #4237: FP. char*&ref=p; p=malloc(10); free(ref);
58+
TEST_CASE(assign14);
5859

5960
TEST_CASE(deallocuse1);
6061
TEST_CASE(deallocuse2);
@@ -70,6 +71,7 @@ class TestLeakAutoVar : public TestFixture {
7071
TEST_CASE(doublefree4); // #5451 - FP when exit is called
7172
TEST_CASE(doublefree5); // #5522
7273
TEST_CASE(doublefree6); // #7685
74+
TEST_CASE(doublefree7);
7375

7476
// exit
7577
TEST_CASE(exit1);
@@ -269,6 +271,20 @@ class TestLeakAutoVar : public TestFixture {
269271
ASSERT_EQUALS("", errout.str());
270272
}
271273

274+
void assign14() {
275+
check("void f(int x) {\n"
276+
" char *p;\n"
277+
" if (x && (p = malloc(10))) { }"
278+
"}");
279+
ASSERT_EQUALS("[test.c:3]: (error) Memory leak: p\n", errout.str());
280+
281+
check("void f(int x) {\n"
282+
" char *p;\n"
283+
" if (x && (p = new char[10])) { }"
284+
"}", true);
285+
ASSERT_EQUALS("[test.cpp:3]: (error) Memory leak: p\n", errout.str());
286+
}
287+
272288
void deallocuse1() {
273289
check("void f(char *p) {\n"
274290
" free(p);\n"
@@ -857,6 +873,22 @@ class TestLeakAutoVar : public TestFixture {
857873
ASSERT_EQUALS("", errout.str());
858874
}
859875

876+
void doublefree7() {
877+
check("void f(char *p, int x) {\n"
878+
" free(p);\n"
879+
" if (x && (p = malloc(10)))\n"
880+
" free(p);\n"
881+
"}");
882+
ASSERT_EQUALS("", errout.str());
883+
884+
check("void f(char *p, int x) {\n"
885+
" delete[] p;\n"
886+
" if (x && (p = new char[10]))\n"
887+
" delete[] p;\n"
888+
"}");
889+
ASSERT_EQUALS("", errout.str());
890+
}
891+
860892
void exit1() {
861893
check("void f() {\n"
862894
" char *p = malloc(10);\n"

0 commit comments

Comments
 (0)