diff --git a/lib/checkleakautovar.cpp b/lib/checkleakautovar.cpp index 6e6036f6b..fd6246b4d 100644 --- a/lib/checkleakautovar.cpp +++ b/lib/checkleakautovar.cpp @@ -1051,7 +1051,7 @@ void CheckLeakAutoVar::ret(const Token *tok, VarInfo &varInfo, const bool isEndO // don't warn if we leave an inner scope if (isEndOfScope && var->scope() && tok != var->scope()->bodyEnd) continue; - bool used = false; + enum class PtrUsage { NONE, DEREF, PTR } used = PtrUsage::NONE; for (const Token *tok2 = tok; tok2; tok2 = tok2->next()) { if (tok2->str() == ";") break; @@ -1068,19 +1068,25 @@ void CheckLeakAutoVar::ret(const Token *tok, VarInfo &varInfo, const bool isEndO tok2 = tok3->next(); else if (Token::Match(tok3, "& %varid% . %name%", varid)) tok2 = tok3->tokAt(4); + else if (Token::simpleMatch(tok3, "*")) + tok2 = tok3; else continue; - if (Token::Match(tok2, "[});,+[]")) { - used = true; + if (Token::Match(tok2, "[});,+]")) { + used = PtrUsage::PTR; + break; + } + if (Token::Match(tok2, "[|.|*")) { + used = PtrUsage::DEREF; break; } } // return deallocated pointer - if (used && it->second.status == VarInfo::DEALLOC) + if (used != PtrUsage::NONE && it->second.status == VarInfo::DEALLOC) deallocReturnError(tok, it->second.allocTok, var->name()); - else if (!used && !it->second.managed() && !var->isReference()) { + else if (used != PtrUsage::PTR && !it->second.managed() && !var->isReference()) { const auto use = possibleUsage.find(varid); if (use == possibleUsage.end()) { leakError(tok, var->name(), it->second.type); diff --git a/test/testleakautovar.cpp b/test/testleakautovar.cpp index 42f2416f1..e5f5005e5 100644 --- a/test/testleakautovar.cpp +++ b/test/testleakautovar.cpp @@ -194,6 +194,7 @@ private: TEST_CASE(return7); // #9343 return (uint8_t*)x TEST_CASE(return8); TEST_CASE(return9); + TEST_CASE(return10); // General tests: variable type, allocation type, etc TEST_CASE(test1); @@ -2392,6 +2393,30 @@ private: ASSERT_EQUALS("", errout.str()); } + void return10() { + check("char f() {\n" // #11758 + " char* p = (char*)malloc(1);\n" + " p[0] = 'x';\n" + " return p[0];\n" + "}"); + ASSERT_EQUALS("[test.c:4]: (error) Memory leak: p\n", errout.str()); + + check("struct S { int f(); };\n" // #11746 + "int g() {\n" + " S* s = new S;\n" + " delete s;\n" + " return s->f();\n" + "}", true); + ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:5]: (error) Returning/dereferencing 's' after it is deallocated / released\n", errout.str()); + + check("int f() {\n" + " int* p = new int(3);\n" + " delete p;\n" + " return *p;\n" + "}", true); + ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:4]: (error) Returning/dereferencing 'p' after it is deallocated / released\n", errout.str()); + } + void test1() { check("void f(double*&p) {\n" // 3809 " p = malloc(0x100);\n"