From 84fdc088534d51fe9216ba7ebfabf3a6875f51a7 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Thu, 26 Jan 2023 20:12:39 +0100 Subject: [PATCH] Fix #11515 internalAstError with chain of ternary operators (#4742) --- lib/tokenlist.cpp | 4 +- test/testtokenize.cpp | 182 +++++++++++++++++++++++++++++------------- 2 files changed, 129 insertions(+), 57 deletions(-) diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index afb35ecb7..4cc7ce3b6 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -42,7 +42,7 @@ // How many compileExpression recursions are allowed? // For practical code this could be endless. But in some special torture test // there needs to be a limit. -static const int AST_MAX_DEPTH = 100; +static const int AST_MAX_DEPTH = 150; TokenList::TokenList(const Settings* settings) : @@ -739,6 +739,8 @@ static void compileBinOp(Token *&tok, AST_state& state, void (*f)(Token *&tok, A state.depth++; if (tok && state.depth <= AST_MAX_DEPTH) f(tok, state); + if (state.depth > AST_MAX_DEPTH) + throw InternalError(tok, "maximum AST depth exceeded", InternalError::AST); state.depth--; } diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 93fe73d81..2887352e2 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -6022,63 +6022,133 @@ private: void astexpr2() { // limit for large expressions // #7724 - wrong AST causes hang // Ideally a proper AST is created for this code. - const char code[] = "const char * a(int type) {\n" - " return (\n" - " (type == 1) ? \"\"\n" - " : (type == 2) ? \"\"\n" - " : (type == 3) ? \"\"\n" - " : (type == 4) ? \"\"\n" - " : (type == 5) ? \"\"\n" - " : (type == 6) ? \"\"\n" - " : (type == 7) ? \"\"\n" - " : (type == 8) ? \"\"\n" - " : (type == 9) ? \"\"\n" - " : (type == 10) ? \"\"\n" - " : (type == 11) ? \"\"\n" - " : (type == 12) ? \"\"\n" - " : (type == 13) ? \"\"\n" - " : (type == 14) ? \"\"\n" - " : (type == 15) ? \"\"\n" - " : (type == 16) ? \"\"\n" - " : (type == 17) ? \"\"\n" - " : (type == 18) ? \"\"\n" - " : (type == 19) ? \"\"\n" - " : (type == 20) ? \"\"\n" - " : (type == 21) ? \"\"\n" - " : (type == 22) ? \"\"\n" - " : (type == 23) ? \"\"\n" - " : (type == 24) ? \"\"\n" - " : (type == 25) ? \"\"\n" - " : (type == 26) ? \"\"\n" - " : (type == 27) ? \"\"\n" - " : (type == 28) ? \"\"\n" - " : (type == 29) ? \"\"\n" - " : (type == 30) ? \"\"\n" - " : (type == 31) ? \"\"\n" - " : (type == 32) ? \"\"\n" - " : (type == 33) ? \"\"\n" - " : (type == 34) ? \"\"\n" - " : (type == 35) ? \"\"\n" - " : (type == 36) ? \"\"\n" - " : (type == 37) ? \"\"\n" - " : (type == 38) ? \"\"\n" - " : (type == 39) ? \"\"\n" - " : (type == 40) ? \"\"\n" - " : (type == 41) ? \"\"\n" - " : (type == 42) ? \"\"\n" - " : (type == 43) ? \"\"\n" - " : (type == 44) ? \"\"\n" - " : (type == 45) ? \"\"\n" - " : (type == 46) ? \"\"\n" - " : (type == 47) ? \"\"\n" - " : (type == 48) ? \"\"\n" - " : (type == 49) ? \"\"\n" - " : (type == 50) ? \"\"\n" - " : (type == 51) ? \"\"\n" - " : \"\");\n" - "}\n"; + const char* code = "const char * a(int type) {\n" + " return (\n" + " (type == 1) ? \"\"\n" + " : (type == 2) ? \"\"\n" + " : (type == 3) ? \"\"\n" + " : (type == 4) ? \"\"\n" + " : (type == 5) ? \"\"\n" + " : (type == 6) ? \"\"\n" + " : (type == 7) ? \"\"\n" + " : (type == 8) ? \"\"\n" + " : (type == 9) ? \"\"\n" + " : (type == 10) ? \"\"\n" + " : (type == 11) ? \"\"\n" + " : (type == 12) ? \"\"\n" + " : (type == 13) ? \"\"\n" + " : (type == 14) ? \"\"\n" + " : (type == 15) ? \"\"\n" + " : (type == 16) ? \"\"\n" + " : (type == 17) ? \"\"\n" + " : (type == 18) ? \"\"\n" + " : (type == 19) ? \"\"\n" + " : (type == 20) ? \"\"\n" + " : (type == 21) ? \"\"\n" + " : (type == 22) ? \"\"\n" + " : (type == 23) ? \"\"\n" + " : (type == 24) ? \"\"\n" + " : (type == 25) ? \"\"\n" + " : (type == 26) ? \"\"\n" + " : (type == 27) ? \"\"\n" + " : (type == 28) ? \"\"\n" + " : (type == 29) ? \"\"\n" + " : (type == 30) ? \"\"\n" + " : (type == 31) ? \"\"\n" + " : (type == 32) ? \"\"\n" + " : (type == 33) ? \"\"\n" + " : (type == 34) ? \"\"\n" + " : (type == 35) ? \"\"\n" + " : (type == 36) ? \"\"\n" + " : (type == 37) ? \"\"\n" + " : (type == 38) ? \"\"\n" + " : (type == 39) ? \"\"\n" + " : (type == 40) ? \"\"\n" + " : (type == 41) ? \"\"\n" + " : (type == 42) ? \"\"\n" + " : (type == 43) ? \"\"\n" + " : (type == 44) ? \"\"\n" + " : (type == 45) ? \"\"\n" + " : (type == 46) ? \"\"\n" + " : (type == 47) ? \"\"\n" + " : (type == 48) ? \"\"\n" + " : (type == 49) ? \"\"\n" + " : (type == 50) ? \"\"\n" + " : (type == 51) ? \"\"\n" + " : \"\");\n" + "}\n"; // Ensure that the AST is validated for the simplified token list TODO_ASSERT_THROW(tokenizeAndStringify(code), InternalError); // this should not crash/hang + + code = "template\n" // #11515 + "struct ConstCTZ {\n" + " static constexpr uint32_t value =\n" + " (kInput & (uint64_t(1) << 0)) ? 0 :\n" + " (kInput & (uint64_t(1) << 1)) ? 1 :\n" + " (kInput & (uint64_t(1) << 2)) ? 2 :\n" + " (kInput & (uint64_t(1) << 3)) ? 3 :\n" + " (kInput & (uint64_t(1) << 4)) ? 4 :\n" + " (kInput & (uint64_t(1) << 5)) ? 5 :\n" + " (kInput & (uint64_t(1) << 6)) ? 6 :\n" + " (kInput & (uint64_t(1) << 7)) ? 7 :\n" + " (kInput & (uint64_t(1) << 8)) ? 8 :\n" + " (kInput & (uint64_t(1) << 9)) ? 9 :\n" + " (kInput & (uint64_t(1) << 10)) ? 10 :\n" + " (kInput & (uint64_t(1) << 11)) ? 11 :\n" + " (kInput & (uint64_t(1) << 12)) ? 12 :\n" + " (kInput & (uint64_t(1) << 13)) ? 13 :\n" + " (kInput & (uint64_t(1) << 14)) ? 14 :\n" + " (kInput & (uint64_t(1) << 15)) ? 15 :\n" + " (kInput & (uint64_t(1) << 16)) ? 16 :\n" + " (kInput & (uint64_t(1) << 17)) ? 17 :\n" + " (kInput & (uint64_t(1) << 18)) ? 18 :\n" + " (kInput & (uint64_t(1) << 19)) ? 19 :\n" + " (kInput & (uint64_t(1) << 20)) ? 20 :\n" + " (kInput & (uint64_t(1) << 21)) ? 21 :\n" + " (kInput & (uint64_t(1) << 22)) ? 22 :\n" + " (kInput & (uint64_t(1) << 23)) ? 23 :\n" + " (kInput & (uint64_t(1) << 24)) ? 24 :\n" + " (kInput & (uint64_t(1) << 25)) ? 25 :\n" + " (kInput & (uint64_t(1) << 26)) ? 26 :\n" + " (kInput & (uint64_t(1) << 27)) ? 27 :\n" + " (kInput & (uint64_t(1) << 28)) ? 28 :\n" + " (kInput & (uint64_t(1) << 29)) ? 29 :\n" + " (kInput & (uint64_t(1) << 30)) ? 30 :\n" + " (kInput & (uint64_t(1) << 31)) ? 31 :\n" + " (kInput & (uint64_t(1) << 32)) ? 32 :\n" + " (kInput & (uint64_t(1) << 33)) ? 33 :\n" + " (kInput & (uint64_t(1) << 34)) ? 34 :\n" + " (kInput & (uint64_t(1) << 35)) ? 35 :\n" + " (kInput & (uint64_t(1) << 36)) ? 36 :\n" + " (kInput & (uint64_t(1) << 37)) ? 37 :\n" + " (kInput & (uint64_t(1) << 38)) ? 38 :\n" + " (kInput & (uint64_t(1) << 39)) ? 39 :\n" + " (kInput & (uint64_t(1) << 40)) ? 40 :\n" + " (kInput & (uint64_t(1) << 41)) ? 41 :\n" + " (kInput & (uint64_t(1) << 42)) ? 42 :\n" + " (kInput & (uint64_t(1) << 43)) ? 43 :\n" + " (kInput & (uint64_t(1) << 44)) ? 44 :\n" + " (kInput & (uint64_t(1) << 45)) ? 45 :\n" + " (kInput & (uint64_t(1) << 46)) ? 46 :\n" + " (kInput & (uint64_t(1) << 47)) ? 47 :\n" + " (kInput & (uint64_t(1) << 48)) ? 48 :\n" + " (kInput & (uint64_t(1) << 49)) ? 49 :\n" + " (kInput & (uint64_t(1) << 50)) ? 50 :\n" + " (kInput & (uint64_t(1) << 51)) ? 51 :\n" + " (kInput & (uint64_t(1) << 52)) ? 52 :\n" + " (kInput & (uint64_t(1) << 53)) ? 53 :\n" + " (kInput & (uint64_t(1) << 54)) ? 54 :\n" + " (kInput & (uint64_t(1) << 55)) ? 55 :\n" + " (kInput & (uint64_t(1) << 56)) ? 56 :\n" + " (kInput & (uint64_t(1) << 57)) ? 57 :\n" + " (kInput & (uint64_t(1) << 58)) ? 58 :\n" + " (kInput & (uint64_t(1) << 59)) ? 59 :\n" + " (kInput & (uint64_t(1) << 60)) ? 60 :\n" + " (kInput & (uint64_t(1) << 61)) ? 61 :\n" + " (kInput & (uint64_t(1) << 62)) ? 62 :\n" + " (kInput & (uint64_t(1) << 63)) ? 63 : 64;\n" + "};\n"; + ASSERT_NO_THROW(tokenizeAndStringify(code)); } void astnewdelete() { @@ -6631,7 +6701,7 @@ private: preprocessor.preprocess(fin, filedata, configurations, emptyString, settings0.includePaths); const std::string code = preprocessor.getcode(filedata, emptyString, emptyString); - tokenizeAndStringify(code.c_str()); // just survive... + ASSERT_THROW(tokenizeAndStringify(code.c_str()), InternalError); } #define isStartOfExecutableScope(offset, code) isStartOfExecutableScope_(offset, code, __FILE__, __LINE__)