From 007b5d3e8d6d83237d425fdddd0c40089dcab59b Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Fri, 20 Sep 2019 15:09:27 +0200 Subject: [PATCH] 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; } --- lib/checkleakautovar.cpp | 20 +++++++++++++------ test/testleakautovar.cpp | 43 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index c12011c92..264502acf 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -930,13 +930,21 @@ void CheckLeakAutoVar::ret(const Token *tok, const VarInfo &varInfo) if (var) { bool used = false; for (const Token *tok2 = tok; tok2; tok2 = tok2->next()) { - if (tok2->str() == ";") + if (tok2->str() == ";" || Token::simpleMatch(tok2, "return ;")) break; - if (Token::Match(tok2, "return|(|{|, %varid% [});,]", varid)) { - used = true; - break; - } - if (Token::Match(tok2, "return|(|{|, & %varid% . %name% [});,]", varid)) { + if (!Token::Match(tok2, "return|(|{|,")) + continue; + + tok2 = tok2->next(); + while (tok2 && tok2->isCast() && (tok2->valueType()->pointer || (tok2->valueType()->typeSize(*mSettings) >= mSettings->sizeof_pointer))) + tok2 = tok2->astOperand2() ? tok2->astOperand2() : tok2->astOperand1(); + if (Token::Match(tok2, "%varid%", varid)) + tok2 = tok2->next(); + else if (Token::Match(tok2, "& %varid% . %name%", varid)) + tok2 = tok2->tokAt(4); + else + continue; + if (Token::Match(tok2, "[});,]")) { used = true; break; } diff --git a/test/testleakautovar.cpp b/test/testleakautovar.cpp index 878e71c77..d0d738715 100644 --- a/test/testleakautovar.cpp +++ b/test/testleakautovar.cpp @@ -144,6 +144,7 @@ private: TEST_CASE(return4); TEST_CASE(return5); TEST_CASE(return6); // #8282 return {p, p} + TEST_CASE(return7); // #9343 return (uint8_t*)x // General tests: variable type, allocation type, etc TEST_CASE(test1); @@ -521,6 +522,16 @@ private: " return p;\n" "}", true); ASSERT_EQUALS("", errout.str()); + + check("void f(void* p) {\n" + " if (a) {\n" + " free(p);\n" + " return;\n" + " }\n" + " g(p);\n" + " return;\n" + "}"); + ASSERT_EQUALS("", errout.str()); } void deallocuse5() { // #4018 @@ -1694,6 +1705,38 @@ private: ASSERT_EQUALS("", errout.str()); } + void return7() { // #9343 + check("uint8_t *f() {\n" + " void *x = malloc(1);\n" + " return (uint8_t *)x;\n" + "}", true); + ASSERT_EQUALS("", errout.str()); + + check("uint8_t f() {\n" + " void *x = malloc(1);\n" + " return (uint8_t)x;\n" + "}", true); + ASSERT_EQUALS("[test.cpp:3]: (error) Memory leak: x\n", errout.str()); + + check("void** f() {\n" + " void *x = malloc(1);\n" + " return (void**)x;\n" + "}", true); + ASSERT_EQUALS("", errout.str()); + + check("void* f() {\n" + " void *x = malloc(1);\n" + " return (long long)x;\n" + "}", true); + ASSERT_EQUALS("", errout.str()); + + check("void* f() {\n" + " void *x = malloc(1);\n" + " return (void*)(short)x;\n" + "}", true); + ASSERT_EQUALS("[test.cpp:3]: (error) Memory leak: x\n", errout.str()); + } + void test1() { // 3809 check("void f(double*&p) {\n" " p = malloc(0x100);\n"