Check for smart pointer release (#1206)
This commit is contained in:
parent
02fde2025b
commit
067d82f0ea
|
@ -193,6 +193,19 @@ static bool isVarUsedInTree(const Token *tok, unsigned int varid)
|
||||||
return isVarUsedInTree(tok->astOperand1(), varid) || isVarUsedInTree(tok->astOperand2(), varid);
|
return isVarUsedInTree(tok->astOperand1(), varid) || isVarUsedInTree(tok->astOperand2(), varid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isPointerReleased(const Token *startToken, const Token *endToken, unsigned int varid)
|
||||||
|
{
|
||||||
|
for (const Token *tok = startToken; tok && tok != endToken; tok = tok->next()) {
|
||||||
|
if (tok->varId() != varid)
|
||||||
|
continue;
|
||||||
|
if(Token::Match(tok, "%var% . release ( )"))
|
||||||
|
return true;
|
||||||
|
if(Token::Match(tok, "%var% ="))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void CheckLeakAutoVar::checkScope(const Token * const startToken,
|
void CheckLeakAutoVar::checkScope(const Token * const startToken,
|
||||||
VarInfo *varInfo,
|
VarInfo *varInfo,
|
||||||
std::set<unsigned int> notzero)
|
std::set<unsigned int> notzero)
|
||||||
|
@ -565,6 +578,12 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
|
||||||
if (!Token::Match(typeEndTok, "> %var% {|( %var% ,|)|}"))
|
if (!Token::Match(typeEndTok, "> %var% {|( %var% ,|)|}"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
tok = typeEndTok->linkAt(2);
|
||||||
|
|
||||||
|
unsigned varid = typeEndTok->next()->varId();
|
||||||
|
if(isPointerReleased(typeEndTok->tokAt(2), endToken, varid))
|
||||||
|
continue;
|
||||||
|
|
||||||
bool arrayDelete = false;
|
bool arrayDelete = false;
|
||||||
if (Token::findsimplematch(ftok->next(), "[ ]", typeEndTok))
|
if (Token::findsimplematch(ftok->next(), "[ ]", typeEndTok))
|
||||||
arrayDelete = true;
|
arrayDelete = true;
|
||||||
|
|
|
@ -109,6 +109,7 @@ private:
|
||||||
TEST_CASE(mismatchAllocDealloc);
|
TEST_CASE(mismatchAllocDealloc);
|
||||||
|
|
||||||
TEST_CASE(smartPointerDeleter);
|
TEST_CASE(smartPointerDeleter);
|
||||||
|
TEST_CASE(smartPointerRelease);
|
||||||
|
|
||||||
// Execution reaches a 'return'
|
// Execution reaches a 'return'
|
||||||
TEST_CASE(return1);
|
TEST_CASE(return1);
|
||||||
|
@ -1253,6 +1254,22 @@ private:
|
||||||
"}\n", true);
|
"}\n", true);
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
void smartPointerRelease() {
|
||||||
|
check("void f() {\n"
|
||||||
|
" int * i = new int;\n"
|
||||||
|
" std::unique_ptr<int> x(i);\n"
|
||||||
|
" x.release();\n"
|
||||||
|
" delete i;\n"
|
||||||
|
"}\n", true);
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("void f() {\n"
|
||||||
|
" int * i = new int;\n"
|
||||||
|
" std::unique_ptr<int> x(i);\n"
|
||||||
|
" x.release();\n"
|
||||||
|
"}\n", true);
|
||||||
|
ASSERT_EQUALS("[test.cpp:5]: (error) Memory leak: i\n", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
void return1() {
|
void return1() {
|
||||||
check("int f() {\n"
|
check("int f() {\n"
|
||||||
|
|
Loading…
Reference in New Issue