@@ -146,6 +146,8 @@ Field QueryFuzzer::getRandomField(int type)
146146
147147Field QueryFuzzer::fuzzField (Field field)
148148{
149+ checkIterationLimit ();
150+
149151 const auto type = field.getType ();
150152
151153 int type_index = -1 ;
@@ -363,6 +365,8 @@ void QueryFuzzer::fuzzOrderByList(IAST * ast, const size_t nproj)
363365 return ;
364366 }
365367
368+ checkIterationLimit ();
369+
366370 auto * list = assert_cast<ASTExpressionList *>(ast);
367371
368372 // / Permute list
@@ -414,6 +418,8 @@ void QueryFuzzer::fuzzColumnLikeExpressionList(IAST * ast)
414418 return ;
415419 }
416420
421+ checkIterationLimit ();
422+
417423 auto * impl = assert_cast<ASTExpressionList *>(ast);
418424
419425 // / Permute list
@@ -477,6 +483,8 @@ void QueryFuzzer::fuzzNullsAction(NullsAction & action)
477483
478484void QueryFuzzer::fuzzWindowFrame (ASTWindowDefinition & def)
479485{
486+ checkIterationLimit ();
487+
480488 switch (fuzz_rand () % 40 )
481489 {
482490 case 0 : {
@@ -624,6 +632,8 @@ void QueryFuzzer::fuzzColumnDeclaration(ASTColumnDeclaration & column)
624632
625633DataTypePtr QueryFuzzer::fuzzDataType (DataTypePtr type)
626634{
635+ checkIterationLimit ();
636+
627637 // / Do not replace Array/Tuple/etc. with not Array/Tuple too often.
628638 const auto * type_array = typeid_cast<const DataTypeArray *>(type.get ());
629639 if (type_array && fuzz_rand () % 4 != 0 )
@@ -699,6 +709,8 @@ DataTypePtr QueryFuzzer::fuzzDataType(DataTypePtr type)
699709
700710DataTypePtr QueryFuzzer::getRandomType ()
701711{
712+ checkIterationLimit ();
713+
702714 static const std::vector<TypeIndex> & random_types
703715 = {TypeIndex::UInt8, TypeIndex::UInt16, TypeIndex::UInt32, TypeIndex::UInt64, TypeIndex::UInt128,
704716 TypeIndex::UInt256, TypeIndex::Int8, TypeIndex::Int16, TypeIndex::Int32, TypeIndex::Int64,
@@ -935,6 +947,8 @@ void QueryFuzzer::notifyQueryFailed(ASTPtr ast)
935947
936948ASTPtr QueryFuzzer::fuzzLiteralUnderExpressionList (ASTPtr child)
937949{
950+ checkIterationLimit ();
951+
938952 const auto * l = child->as <ASTLiteral>();
939953 chassert (l);
940954 const auto type = l->value .getType ();
@@ -1073,6 +1087,13 @@ struct ScopedIncrement
10731087 ~ScopedIncrement () { --counter; }
10741088};
10751089
1090+ void QueryFuzzer::checkIterationLimit ()
1091+ {
1092+ if (++iteration_count > iteration_limit)
1093+ throw Exception (ErrorCodes::TOO_DEEP_RECURSION,
1094+ " AST complexity limit exceeded while fuzzing ({})" , iteration_count);
1095+ }
1096+
10761097static const Strings comparison_comparators
10771098 = {" equals" , " notEquals" , " greater" , " greaterOrEquals" , " less" , " lessOrEquals" , " isNotDistinctFrom" };
10781099
@@ -1504,6 +1525,8 @@ void QueryFuzzer::fuzz(ASTPtr & ast)
15041525 if (!ast)
15051526 return ;
15061527
1528+ checkIterationLimit ();
1529+
15071530 // Check for exceeding max depth.
15081531 ScopedIncrement depth_increment (current_ast_depth);
15091532 if (current_ast_depth > 500 )
@@ -1528,7 +1551,7 @@ void QueryFuzzer::fuzz(ASTPtr & ast)
15281551 current_ast_depth,
15291552 debug_visited_nodes.size (),
15301553 (*debug_top_ast)->dumpTree ());
1531- assert ( false );
1554+ std::abort ( );
15321555 }
15331556
15341557 // The fuzzing.
@@ -2169,6 +2192,7 @@ void QueryFuzzer::collectFuzzInfoRecurse(ASTPtr ast)
21692192void QueryFuzzer::fuzzMain (ASTPtr & ast)
21702193{
21712194 current_ast_depth = 0 ;
2195+ iteration_count = 0 ;
21722196 debug_visited_nodes.clear ();
21732197 debug_top_ast = *
21742198
0 commit comments