Visitar URL original
Add test case that reveals infinite loop in AST traversal · nablaa/cppcheck@f8a76c4 · GitHub
Skip to content

Commit f8a76c4

Browse files
committed
Add test case that reveals infinite loop in AST traversal
The following code causes cppcheck execution to hang: void f1() { if (1) new X * [0](); else new Y * [0](); } void f2() { for (int i = 0;; i++) ; } When analyzing the hang with GDB, the following can be seen: (gdb) bt #0 0x00000000008eff0b in Token::astTop (this=0xc3c060) at lib/token.h:881 #1 0x00000000008ef7ec in createAstAtToken (tok=0xc3b930, cpp=0x1) at lib/tokenlist.cpp:949 cppcheck-opensource#2 0x00000000008efd3c in TokenList::createAst (this=0x7fffffffbf00) at lib/tokenlist.cpp:1004 cppcheck-opensource#3 0x000000000089c234 in Tokenizer::tokenize (this=0x7fffffffbf00, code=..., FileName=0xc36038 "temp.cc", configuration="", noSymbolDB_AST=0x0) at lib/tokenize.cpp:1728 cppcheck-opensource#4 0x00000000007c8b62 in CppCheck::checkFile (this=0x7fffffffcf50, code="void f1()\n{\nif (1)\nnew X * [0]();\nelse\nnew Y * [0]();\n}\n\nvoid f2()\n{\nfor (int i = 0;; i++) ;\n}\n", FileName=0xc36038 "temp.cc", checksums=std::__debug::set with 0 elements, internalErrorFound=@0x7fffffffc46b: 0x0) at lib/cppcheck.cpp:337 cppcheck-opensource#5 0x00000000007c78da in CppCheck::processFile (this=0x7fffffffcf50, filename="temp.cc", fileStream=...) at lib/cppcheck.cpp:239 cppcheck-opensource#6 0x00000000007c6348 in CppCheck::check (this=0x7fffffffcf50, path="temp.cc") at lib/cppcheck.cpp:70 cppcheck-opensource#7 0x00000000006a51ef in CppCheckExecutor::check_internal (this=0x7fffffffd9f0, cppcheck=..., argv=0x7fffffffdba8) at cli/cppcheckexecutor.cpp:810 cppcheck-opensource#8 0x00000000006a3d7b in CppCheckExecutor::check (this=0x7fffffffd9f0, argc=0x2, argv=0x7fffffffdba8) at cli/cppcheckexecutor.cpp:183 cppcheck-opensource#9 0x00000000006ac591 in main (argc=0x2, argv=0x7fffffffdba8) at cli/main.cpp:136 The code in question is (lib/token.h:881): const Token *astTop() const { const Token *ret = this; while (ret->_astParent) ret = ret->_astParent; return ret; } It looks like there is some kind of loop in AST: (gdb) p ret (gdb) p ret->_astParent $2 = (Token *) 0xc3ba10 (gdb) p ret->_astParent->_astParent $3 = (Token *) 0xc3be70 (gdb) p ret->_astParent->_astParent->_astParent $4 = (Token *) 0xc3ba10 Using Git bisect revealed that the following commit introduced the problem: ca1f19b This commit adds a testcase that reveals this problem. I.e. when running "make test", the execution hangs.
1 parent 6cf2582 commit f8a76c4

1 file changed

Lines changed: 15 additions & 0 deletions

File tree

‎test/testtokenize.cpp‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ class TestTokenizer : public TestFixture {
6868
TEST_CASE(tokenize31); // #3503 (Wrong handling of member function taking function pointer as argument)
6969
TEST_CASE(tokenize32); // #5884 (fsanitize=undefined: left shift of negative value -10000 in lib/templatesimplifier.cpp:852:46)
7070
TEST_CASE(tokenize33); // #5780 Various crashes on valid template code
71+
TEST_CASE(tokenize34); // infinite loop while traversing AST
7172

7273
TEST_CASE(syntax_case_default);
7374
TEST_CASE(simplifyFileAndLineMacro); // tokenize "return - __LINE__;"
@@ -816,6 +817,20 @@ class TestTokenizer : public TestFixture {
816817
tokenizeAndStringify(code, true);
817818
}
818819

820+
// Infinite loop when traversing AST
821+
void tokenize34() {
822+
const char code[] = "void f1() {\n"
823+
"if (1)\n"
824+
"new X * [0]();\n"
825+
"else\n"
826+
"new Y * [0]();\n"
827+
"}\n"
828+
"void f2() {\n"
829+
"for (int i = 0;; i++) ;\n"
830+
"}\n";
831+
tokenizeAndStringify(code);
832+
}
833+
819834
void syntax_case_default() { // correct syntax
820835
tokenizeAndStringify("void f() {switch (n) { case 0: z(); break;}}");
821836
ASSERT_EQUALS("", errout.str());

0 commit comments

Comments
 (0)