From dec193c1e5c74f94c85bb17748fcde7aecd7d4e5 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Mon, 18 Mar 2024 11:31:16 +0100 Subject: [PATCH] Fix #12492 fuzzing crash (stack overflow) in CheckLeakAutoVar::checkTokenInsideExpression() (#6123) --- lib/tokenlist.cpp | 13 +++++++++--- ...h-d6609399a4398aed92f5ac9e53aa0554d9f8bbd6 | 1 + test/testsimplifytypedef.cpp | 21 +++++++++++++++++++ test/testtokenize.cpp | 5 +++-- 4 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 test/cli/fuzz-crash/crash-d6609399a4398aed92f5ac9e53aa0554d9f8bbd6 diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index 3062451449a..5e9017eb487 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -492,6 +492,9 @@ static bool iscast(const Token *tok, bool cpp) if (Token::simpleMatch(tok->link(), ") ( )")) return false; + if (Token::Match(tok->link(), ") %assign%|,|...")) + return false; + if (tok->previous() && tok->previous()->isName() && tok->previous()->str() != "return" && (!cpp || !Token::Match(tok->previous(), "delete|throw"))) return false; @@ -1817,9 +1820,13 @@ void TokenList::validateAst(bool print) const tok = tok->link(); continue; } - if (tok->isCast() && tok->astOperand1() && tok->link()) { // skip casts (not part of the AST) - tok = tok->link(); - continue; + if (tok->isCast()) { + if (!tok->astOperand2() && precedes(tok->astOperand1(), tok)) + throw InternalError(tok, "AST broken: '" + tok->str() + "' has improper operand.", InternalError::AST); + if (tok->astOperand1() && tok->link()) { // skip casts (not part of the AST) + tok = tok->link(); + continue; + } } if (findLambdaEndToken(tok)) { // skip lambda captures diff --git a/test/cli/fuzz-crash/crash-d6609399a4398aed92f5ac9e53aa0554d9f8bbd6 b/test/cli/fuzz-crash/crash-d6609399a4398aed92f5ac9e53aa0554d9f8bbd6 new file mode 100644 index 00000000000..1563d4c95bd --- /dev/null +++ b/test/cli/fuzz-crash/crash-d6609399a4398aed92f5ac9e53aa0554d9f8bbd6 @@ -0,0 +1 @@ +_(){w((char)=e)} \ No newline at end of file diff --git a/test/testsimplifytypedef.cpp b/test/testsimplifytypedef.cpp index 0b9391af1a5..9c78f38dad8 100644 --- a/test/testsimplifytypedef.cpp +++ b/test/testsimplifytypedef.cpp @@ -214,6 +214,7 @@ class TestSimplifyTypedef : public TestFixture { TEST_CASE(simplifyTypedef147); TEST_CASE(simplifyTypedef148); TEST_CASE(simplifyTypedef149); + TEST_CASE(simplifyTypedef150); TEST_CASE(simplifyTypedefFunction1); TEST_CASE(simplifyTypedefFunction2); // ticket #1685 @@ -3513,6 +3514,26 @@ class TestSimplifyTypedef : public TestFixture { ASSERT_EQUALS("namespace N { enum E { } ; } void g ( int ) ; void f ( ) { g ( sizeof ( enum N :: E ) ) ; }", tok(code)); } + void simplifyTypedef150() { // #12475 + const char* code{}, *exp{}; + code = "struct S {\n" + " std::vector const& h(int);\n" + "};\n" + "typedef std::vector const& (S::* func_t)(int);\n" + "void g(func_t, int);\n" + "void f() {\n" + " g(func_t(&S::h), 5);\n" + "}\n"; + exp = "struct S { " + "const std :: vector < int > & h ( int ) ; " + "} ; " + "void g ( const std :: vector < int > & ( S :: * ) ( int ) , int ) ; " + "void f ( ) { " + "g ( const std :: vector < int > & ( S :: * ( & S :: h ) ) ( int ) , 5 ) ; " // TODO: don't generate invalid code + "}"; + ASSERT_EQUALS(exp, tok(code)); + } + void simplifyTypedefFunction1() { { const char code[] = "typedef void (*my_func)();\n" diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 73e50c4bc33..f54c6afd3eb 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -6532,7 +6532,7 @@ class TestTokenizer : public TestFixture { ASSERT_EQUALS("constdelete=", testAst("int f() const = delete;")); ASSERT_EQUALS("", testAst("extern unsigned f(const char *);")); ASSERT_EQUALS("charformat*...,", testAst("extern void f(const char *format, ...);")); - ASSERT_EQUALS("int((void,", testAst("extern int for_each_commit_graft(int (*)(int*), void *);")); + ASSERT_EQUALS("int(int(void,", testAst("extern int for_each_commit_graft(int (*)(int*), void *);")); ASSERT_EQUALS("for;;(", testAst("for (;;) {}")); ASSERT_EQUALS("xsizeofvoid(=", testAst("x=sizeof(void*)")); ASSERT_EQUALS("abc{d{,{(=", testAst("a = b({ c{}, d{} });")); @@ -6540,6 +6540,7 @@ class TestTokenizer : public TestFixture { ASSERT_EQUALS("x{( forbc;;(", testAst("x({ for(a;b;c){} });")); ASSERT_EQUALS("PT.(", testAst("P->~T();")); // <- The "T" token::function() will be a destructor ASSERT_EQUALS("double&(4[", testAst("void f(double(&)[4]) {}")); + ASSERT_EQUALS("voidu*", testAst("int* g ( void* (f) (void*), void* u);")); // #12475 } void asttemplate() { // uninstantiated templates will have <,>,etc.. @@ -6556,7 +6557,7 @@ class TestTokenizer : public TestFixture { ASSERT_EQUALS("xfts(=", testAst("; auto x = f(ts...);")); - ASSERT_EQUALS("da((new= ifd(", testAst("template \n" // #10199 + ASSERT_EQUALS("dae(new= ifd(", testAst("template \n" // #10199 "void c(b... e) {\n" " a d = new a((e)...);\n" " if (d) {}\n"