diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 042199194..6827abae9 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -6413,6 +6413,7 @@ bool Tokenizer::simplifyKnownVariablesGetData(unsigned int varid, Token **_tok2, bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsigned int varid, const std::string &structname, std::string &value, unsigned int valueVarId, bool valueIsPointer, const Token * const valueToken, int indentlevel) const { const bool pointeralias(valueToken->isName() || Token::Match(valueToken, "& %name% [")); + const bool varIsGlobal = (indentlevel == 0); const bool printDebug = _settings->debugwarnings; if (_errorLogger && !list.getFiles().empty()) @@ -6491,12 +6492,9 @@ bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsign if (pointeralias && Token::Match(tok3, "do|for|while")) break; - // Stop if unknown function call is seen - // If the variable is a global or a member variable it might be + // Stop if unknown function call is seen and the variable is global: it might be // changed by the function call - // TODO: don't bail out if the variable is a local variable, - // then it can't be changed by the function call. - if (tok3->str() == ")" && tok3->link() && + if (varIsGlobal && tok3->str() == ")" && tok3->link() && Token::Match(tok3->link()->tokAt(-2), "[;{}] %name% (") && !Token::Match(tok3->link()->previous(), "if|for|while|switch|BOOST_FOREACH")) break; diff --git a/test/testmemleak.cpp b/test/testmemleak.cpp index c011ac67c..bb8c07104 100644 --- a/test/testmemleak.cpp +++ b/test/testmemleak.cpp @@ -369,6 +369,7 @@ private: TEST_CASE(trac3991); TEST_CASE(crash); TEST_CASE(trac7680); + TEST_CASE(trac7440); } std::string getcode(const char code[], const char varname[], bool classfunc=false) { @@ -4032,6 +4033,16 @@ private: "}"); ASSERT_EQUALS("", errout.str()); } + + void trac7440() { + check("int main(void) {\n" + " char* data = new char[100];\n" + " char** dataPtr = &data;\n" + " printf(\"test\");\n" + " delete [] *dataPtr;\n" + "}"); + ASSERT_EQUALS("", errout.str()); + } }; REGISTER_TEST(TestMemleakInFunction) diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index b2eadcf7c..fc3df9a40 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -193,6 +193,7 @@ private: TEST_CASE(simplifyKnownVariablesClassMember); // #2815 - value of class member may be changed by function call TEST_CASE(simplifyKnownVariablesFunctionCalls); // Function calls (don't assume pass by reference) TEST_CASE(simplifyKnownVariablesReturn); // 3500 - return + TEST_CASE(simplifyKnownVariablesPointerAliasFunctionCall); // #7440 TEST_CASE(simplifyExternC); TEST_CASE(simplifyKeyword); // #5842 - remove C99 static keyword between [] @@ -2879,6 +2880,22 @@ private: ASSERT_EQUALS("int a ( ) { return 123 ; }", tokenizeAndStringify(code,true)); } + void simplifyKnownVariablesPointerAliasFunctionCall() { // #7440 + const char code[] = "int main() {\n" + " char* data = new char[100];\n" + " char** dataPtr = &data;\n" + " printf(\"test\");\n" + " delete [] *dataPtr;\n" + "}"; + const char exp[] = "int main ( ) {\n" + "char * data ; data = new char [ 100 ] ;\n" + "char * * dataPtr ; dataPtr = & data ;\n" + "printf ( \"test\" ) ;\n" + "delete [ ] data ;\n" + "}"; + ASSERT_EQUALS(exp, tokenizeAndStringify(code, /*simplify=*/true)); + } + void simplifyKnownVariablesClassMember() { // Ticket #2815 {