diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 9f35c0128..d516d0189 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -2292,6 +2292,13 @@ void CheckOther::checkDoubleFree() closeDirVariables.clear(); } + // If this scope is a "for" or "while" loop, give up on trying to figure + // out the flow of execution and just clear the set of previously freed variables + else if (tok->str() == "}" && tok->link() && tok->link()->previous() && tok->link()->previous()->link() && + Token::Match(tok->link()->previous()->link()->previous(), "while|for")) { + freedVariables.clear(); + closeDirVariables.clear(); + } // If a variable is passed to a function, remove it from the set of previously freed variables else if (Token::Match(tok, "%var% (") && !Token::Match(tok, "printf|sprintf|snprintf|fprintf")) { diff --git a/test/testother.cpp b/test/testother.cpp index 40b354d81..95d5848a8 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -5087,6 +5087,51 @@ private: "}" ); ASSERT_EQUALS("", errout.str()); + + check( + "void foo(int y)\n" + "{\n" + " char * x = NULL;\n" + " while(1) {\n" + " x = new char[100];\n" + " if (y++ > 100)\n" + " break;\n" + " delete[] x;\n" + " }\n" + " delete[] x;\n" + "}" + ); + ASSERT_EQUALS("", errout.str()); + + check( + "void foo(int y)\n" + "{\n" + " char * x = NULL;\n" + " for (;;) {\n" + " x = new char[100];\n" + " if (y++ > 100)\n" + " break;\n" + " delete[] x;\n" + " }\n" + " delete[] x;\n" + "}" + ); + ASSERT_EQUALS("", errout.str()); + + check( + "void foo(int y)\n" + "{\n" + " char * x = NULL;\n" + " do {\n" + " x = new char[100];\n" + " if (y++ > 100)\n" + " break;\n" + " delete[] x;\n" + " } while (1);\n" + " delete[] x;\n" + "}" + ); + ASSERT_EQUALS("", errout.str()); } };