Skip to content

Commit 007b5d3

Browse files
rikardfalkeborndanmar
authored andcommitted
Fix #9343 (memleak FP when return with cast) (#2162)
This was most likely introduced when the checks were changed to run on the full tokenlist instead of the simplified one. Take care to warn about cases where casts destroy the pointer, such as uint8_t f() { void* x = malloc(1); return (uint8_t)x; }
1 parent 049f647 commit 007b5d3

2 files changed

Lines changed: 57 additions & 6 deletions

File tree

lib/checkleakautovar.cpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -930,13 +930,21 @@ void CheckLeakAutoVar::ret(const Token *tok, const VarInfo &varInfo)
930930
if (var) {
931931
bool used = false;
932932
for (const Token *tok2 = tok; tok2; tok2 = tok2->next()) {
933-
if (tok2->str() == ";")
933+
if (tok2->str() == ";" || Token::simpleMatch(tok2, "return ;"))
934934
break;
935-
if (Token::Match(tok2, "return|(|{|, %varid% [});,]", varid)) {
936-
used = true;
937-
break;
938-
}
939-
if (Token::Match(tok2, "return|(|{|, & %varid% . %name% [});,]", varid)) {
935+
if (!Token::Match(tok2, "return|(|{|,"))
936+
continue;
937+
938+
tok2 = tok2->next();
939+
while (tok2 && tok2->isCast() && (tok2->valueType()->pointer || (tok2->valueType()->typeSize(*mSettings) >= mSettings->sizeof_pointer)))
940+
tok2 = tok2->astOperand2() ? tok2->astOperand2() : tok2->astOperand1();
941+
if (Token::Match(tok2, "%varid%", varid))
942+
tok2 = tok2->next();
943+
else if (Token::Match(tok2, "& %varid% . %name%", varid))
944+
tok2 = tok2->tokAt(4);
945+
else
946+
continue;
947+
if (Token::Match(tok2, "[});,]")) {
940948
used = true;
941949
break;
942950
}

test/testleakautovar.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ class TestLeakAutoVar : public TestFixture {
144144
TEST_CASE(return4);
145145
TEST_CASE(return5);
146146
TEST_CASE(return6); // #8282 return {p, p}
147+
TEST_CASE(return7); // #9343 return (uint8_t*)x
147148

148149
// General tests: variable type, allocation type, etc
149150
TEST_CASE(test1);
@@ -521,6 +522,16 @@ class TestLeakAutoVar : public TestFixture {
521522
" return p;\n"
522523
"}", true);
523524
ASSERT_EQUALS("", errout.str());
525+
526+
check("void f(void* p) {\n"
527+
" if (a) {\n"
528+
" free(p);\n"
529+
" return;\n"
530+
" }\n"
531+
" g(p);\n"
532+
" return;\n"
533+
"}");
534+
ASSERT_EQUALS("", errout.str());
524535
}
525536

526537
void deallocuse5() { // #4018
@@ -1694,6 +1705,38 @@ class TestLeakAutoVar : public TestFixture {
16941705
ASSERT_EQUALS("", errout.str());
16951706
}
16961707

1708+
void return7() { // #9343
1709+
check("uint8_t *f() {\n"
1710+
" void *x = malloc(1);\n"
1711+
" return (uint8_t *)x;\n"
1712+
"}", true);
1713+
ASSERT_EQUALS("", errout.str());
1714+
1715+
check("uint8_t f() {\n"
1716+
" void *x = malloc(1);\n"
1717+
" return (uint8_t)x;\n"
1718+
"}", true);
1719+
ASSERT_EQUALS("[test.cpp:3]: (error) Memory leak: x\n", errout.str());
1720+
1721+
check("void** f() {\n"
1722+
" void *x = malloc(1);\n"
1723+
" return (void**)x;\n"
1724+
"}", true);
1725+
ASSERT_EQUALS("", errout.str());
1726+
1727+
check("void* f() {\n"
1728+
" void *x = malloc(1);\n"
1729+
" return (long long)x;\n"
1730+
"}", true);
1731+
ASSERT_EQUALS("", errout.str());
1732+
1733+
check("void* f() {\n"
1734+
" void *x = malloc(1);\n"
1735+
" return (void*)(short)x;\n"
1736+
"}", true);
1737+
ASSERT_EQUALS("[test.cpp:3]: (error) Memory leak: x\n", errout.str());
1738+
}
1739+
16971740
void test1() { // 3809
16981741
check("void f(double*&p) {\n"
16991742
" p = malloc(0x100);\n"

0 commit comments

Comments
 (0)