From: drh <> Date: Tue, 18 Nov 2025 13:03:08 +0000 (+0000) Subject: Yet another attempt at controlling the parser stack size. X-Git-Tag: artiphishell~222^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d26ac414c8440047248158bd33b5b9bd7f20c8d8;p=thirdparty%2Fsqlite.git Yet another attempt at controlling the parser stack size. FossilOrigin-Name: cb19986dc6bc483df21e082e54a14cb6d7540b1734259e6d326d676908ac0172 --- diff --git a/doc/lemon.html b/doc/lemon.html index 965f305c04..63efa950d8 100644 --- a/doc/lemon.html +++ b/doc/lemon.html @@ -696,6 +696,7 @@ other than that, the order of directives in Lemon is arbitrary.

  • %right
  • %realloc
  • %stack_overflow +
  • %stack_resizer
  • %stack_size
  • %start_symbol
  • %syntax_error @@ -1203,7 +1204,8 @@ the wildcard token and some other token, the other token is always used. The wildcard token is only matched if there are no alternatives.

    -

    4.4.26 The %realloc and %free directives

    +

    4.4.26 The %realloc, %free, and +%stack_resizer directives

    The %realloc and %free directives defines function that allocate and free heap memory. The signatures of these functions @@ -1217,6 +1219,22 @@ parse stack space is exceeded. The initial parser stack size is specified by either %stack_size or the -DYYSTACKDEPTH compile-time flag. +

    The %stack_resizer directive defines a function that computes +the new size of the stack whenever it needs resizing. The function takes +two arguments: The old stack size, and the %extra_context value. The +function returns an integer which is the new stack size. If %stack_resizer +is not defined, then the stack size roughly doubles with each new allocation. +The %stack_resizer function is entirely optional. The parser works fine +without it. The %stack_resizer function merely gives the application more +control over the stack size, and offers an opportunity to raise warnings or +errors if the parser stack grows too large. + +

    If the %stack_resizer function returns an integer that is less than or +equal to its first parameter, then %stack_overflow is invoked and parsing +stops. + +

    The %stack_resizer function only works if %extra_context is also defined. +

    5.0 Error Processing

    diff --git a/manifest b/manifest index 94b2a3a9ee..26ff83bd7c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sincorrect\s"#line"\sgeneration\sin\sLemon. -D 2025-11-18T10:38:41.356 +C Yet\sanother\sattempt\sat\scontrolling\sthe\sparser\sstack\ssize. +D 2025-11-18T13:03:08.837 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -60,7 +60,7 @@ F doc/compile-for-unix.md c9dce1ddd4bf0d25efccc5c63eb047e78c01ce06a6ff29c73e0a8a F doc/compile-for-windows.md f9e74d74da88f384edd5809f825035e071608f00f7f39c0e448df7b3982f979c F doc/json-enhancements.md e356fc834781f1f1aa22ee300027a270b2c960122468499bf347bb123ce1ea4f F doc/jsonb.md acd77fc3a709f51242655ad7803510c886aa8304202fa9cf2abc5f5c4e9d7ae5 -F doc/lemon.html 89ea833a6f71773ab1a9063fbb7fb9b32147bc0b1057b53ecab94a3b30c0aef5 +F doc/lemon.html 60b3836301ac8555622523569fc5cd3bae5b7a8cd1abab545b6ec14800c90aec F doc/pager-invariants.txt 83aa3a4724b2d7970cc3f3461f0295c46d4fc19a835a5781cbb35cb52feb0577 F doc/tcl-extension-testing.md b88861804fc1eaf83249f8e206334189b61e150c360e1b80d0dcf91af82354f5 F doc/testrunner.md 5ee928637e03f136a25fef852c5ed975932e31927bd9b05a574424ae18c31019 @@ -720,7 +720,7 @@ F src/os_win.c a89b501fc195085c7d6c9eec7f5bd782625e94bb2a96b000f4d009703df1083f F src/os_win.h 4c247cdb6d407c75186c94a1e84d5a22cbae4adcec93fcae8d2bc1f956fd1f19 F src/pager.c a81461de271ac4886ad75b7ca2cca8157a48635820c4646cd2714acdc2c17e5f F src/pager.h 6137149346e6c8a3ddc1eeb40aee46381e9bc8b0fcc6dda8a1efde993c2275b8 -F src/parse.y 619c3e92a54686c5e47923688c4b9bf7ec534a4690db5677acc28b299c403250 +F src/parse.y f54dff6d07f337f9cea8cb3e28144e47877fd2f211fc3a5c5e238e456d51cc8a F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484 F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5 F src/pcache1.c 131ca0daf4e66b4608d2945ae76d6ed90de3f60539afbd5ef9ec65667a5f2fcd @@ -2101,8 +2101,8 @@ F tool/genfkey.README e550911fa984c8255ebed2ef97824125d83806eb5232582700de949edf F tool/genfkey.test b6afd7b825d797a1e1274f519ab5695373552ecad5cd373530c63533638a5a4f F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce F tool/index_usage.c f62a0c701b2c7ff2f3e21d206f093c123f222dbf07136a10ffd1ca15a5c706c5 -F tool/lemon.c 861099d4d328251c85a35cfe3da81e00e35a0708be5aab0e1c7feb157b9735e8 -F tool/lempar.c bdffd3b233a4e4e78056c9c01fadd2bb3fe902435abde3bce3d769fdf0d5cca2 +F tool/lemon.c acb9b4e4d6a9826d40163b1da71e049859c7230217c39a6a63dc81ed8d28c906 +F tool/lempar.c ff3c9b32cf36152616dd2bb78ea0fdd3ec6c0f2e76ec55f0d2b50dcb35122b46 F tool/libvers.c caafc3b689638a1d88d44bc5f526c2278760d9b9 F tool/loadfts.c 63412f9790e5e8538fbde0b4f6db154aaaf80f7a10a01e3c94d14b773a8dd5a6 F tool/logest.c c34e5944318415de513d29a6098df247a9618c96d83c38d4abd88641fe46e669 @@ -2166,8 +2166,11 @@ F tool/version-info.c 33d0390ef484b3b1cb685d59362be891ea162123cea181cb8e6d2cf6dd F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7 F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P ea48567ac54e4949a8b68977a58a5de7946e074ae8737133071d02f40ac97f34 -R 956e0d8d894da87712e963f1d74f3842 +P 5c0214df2c0a7470ac2edca0c483a3edd3c39ef0739688ab9a06e23882200360 +R 77442b17c4e08c97334e79ed87f9944e +T *branch * parser-stack-size +T *sym-parser-stack-size * +T -sym-trunk * U drh -Z 160fdfae770c78987ceedbc701266298 +Z df6b29f678f7d3bd6a12aec2b921e4cb # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.tags b/manifest.tags index bec971799f..e66df07e70 100644 --- a/manifest.tags +++ b/manifest.tags @@ -1,2 +1,2 @@ -branch trunk -tag trunk +branch parser-stack-size +tag parser-stack-size diff --git a/manifest.uuid b/manifest.uuid index 2a8ebfafeb..6e103a40ec 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5c0214df2c0a7470ac2edca0c483a3edd3c39ef0739688ab9a06e23882200360 +cb19986dc6bc483df21e082e54a14cb6d7540b1734259e6d326d676908ac0172 diff --git a/src/parse.y b/src/parse.y index 617eb7303b..1dd5d700be 100644 --- a/src/parse.y +++ b/src/parse.y @@ -22,8 +22,9 @@ } // Function used to enlarge the parser stack, if needed -%realloc parserStackRealloc -%free sqlite3_free +%stack_resizer parserStackResize +%realloc parserStackRealloc +%free sqlite3_free // All token codes are small integers with #defines that begin with "TK_" %token_prefix TK_ @@ -49,7 +50,7 @@ } } %stack_overflow { - sqlite3OomFault(pParse->db); + if( pParse->nErr==0 ) sqlite3OomFault(pParse->db); } // The name of the generated procedure that implements the parser @@ -586,6 +587,18 @@ cmd ::= select(X). { static void *parserStackRealloc(void *pOld, sqlite3_uint64 newSize){ return sqlite3FaultSim(700) ? 0 : sqlite3_realloc(pOld, newSize); } + + /* Determine how big to make the stack */ + static int parserStackResize(int oldSize, Parse *pParse){ + int newSize; + int limit; + limit = pParse->db->aLimit[SQLITE_LIMIT_EXPR_DEPTH]; + if( limit ) limit = limit*4 +100; + newSize = oldSize*2 + 100; + if( newSize>limit ) newSize = limit; + if( newSize<=oldSize ) sqlite3ErrorMsg(pParse, "Recursion limit"); + return newSize; + } } %ifndef SQLITE_OMIT_CTE diff --git a/tool/lemon.c b/tool/lemon.c index 7dc7052673..b88da9d287 100644 --- a/tool/lemon.c +++ b/tool/lemon.c @@ -494,6 +494,7 @@ struct lemon { char *filename; /* Name of the input file */ char *outname; /* Name of the current output file */ char *tokenprefix; /* A prefix added to token names in the .h file */ + char *resizeFunc; /* Function to compute new stack size */ char *reallocFunc; /* Function to use to allocate stack space */ char *freeFunc; /* Function to use to free stack space */ int nconflict; /* Number of parsing conflicts */ @@ -2638,6 +2639,9 @@ static void parseonetoken(struct pstate *psp) }else if( strcmp(x,"default_type")==0 ){ psp->declargslot = &(psp->gp->vartype); psp->insertLineMacro = 0; + }else if( strcmp(x,"stack_resizer")==0 ){ + psp->declargslot = &(psp->gp->resizeFunc); + psp->insertLineMacro = 0; }else if( strcmp(x,"realloc")==0 ){ psp->declargslot = &(psp->gp->reallocFunc); psp->insertLineMacro = 0; @@ -4407,6 +4411,13 @@ static void writeRuleText(FILE *out, struct rule *rp){ } } +/* +** Return true if the string is not NULL and not empty. +*/ +static int notnull(const char *z){ + return z && z[0]; +} + /* Generate C source code for the parser */ void ReportTable( @@ -4611,25 +4622,33 @@ void ReportTable( fprintf(out,"#define %sARG_FETCH\n",name); lineno++; fprintf(out,"#define %sARG_STORE\n",name); lineno++; } + fprintf(out, "#undef YYREALLOC\n"); lineno++; if( lemp->reallocFunc ){ fprintf(out,"#define YYREALLOC %s\n", lemp->reallocFunc); lineno++; }else{ fprintf(out,"#define YYREALLOC realloc\n"); lineno++; } + fprintf(out, "#undef YYFREE\n"); lineno++; if( lemp->freeFunc ){ fprintf(out,"#define YYFREE %s\n", lemp->freeFunc); lineno++; }else{ fprintf(out,"#define YYFREE free\n"); lineno++; } + fprintf(out, "#undef YYDYNSTACK\n"); lineno++; if( lemp->reallocFunc && lemp->freeFunc ){ fprintf(out,"#define YYDYNSTACK 1\n"); lineno++; }else{ fprintf(out,"#define YYDYNSTACK 0\n"); lineno++; } - if( lemp->ctx && lemp->ctx[0] ){ + fprintf(out, "#undef YYRESIZE\n"); lineno++; + if( notnull(lemp->ctx) ){ i = lemonStrlen(lemp->ctx); while( i>=1 && ISSPACE(lemp->ctx[i-1]) ) i--; while( i>=1 && (ISALNUM(lemp->ctx[i-1]) || lemp->ctx[i-1]=='_') ) i--; + if( notnull(lemp->resizeFunc) ){ + fprintf(out,"#define YYRESIZE %s\n", lemp->resizeFunc); lineno++; + } + fprintf(out,"#define %sCTX(P) ((P)->%s)\n",name,&lemp->ctx[i]); lineno++; fprintf(out,"#define %sCTX_SDECL %s;\n",name,lemp->ctx); lineno++; fprintf(out,"#define %sCTX_PDECL ,%s\n",name,lemp->ctx); lineno++; fprintf(out,"#define %sCTX_PARAM ,%s\n",name,&lemp->ctx[i]); lineno++; @@ -4647,10 +4666,13 @@ void ReportTable( if( mhflag ){ fprintf(out,"#endif\n"); lineno++; } + fprintf(out, "#undef YYERRORSYMBOL\n"); lineno++; + fprintf(out, "#undef YYERRSYMDT\n"); lineno++; if( lemp->errsym && lemp->errsym->useCnt ){ fprintf(out,"#define YYERRORSYMBOL %d\n",lemp->errsym->index); lineno++; fprintf(out,"#define YYERRSYMDT yy%d\n",lemp->errsym->dtnum); lineno++; } + fprintf(out,"#undef YYFALLBACK\n"); lineno++; if( lemp->has_fallback ){ fprintf(out,"#define YYFALLBACK 1\n"); lineno++; } diff --git a/tool/lempar.c b/tool/lempar.c index 74314efeaa..1bffbf6067 100644 --- a/tool/lempar.c +++ b/tool/lempar.c @@ -300,7 +300,12 @@ static int yyGrowStack(yyParser *p){ int idx; yyStackEntry *pNew; +#ifdef YYRESIZE + newSize = YYRESIZE(oldSize, ParseCTX(p)); + if( newSize<=oldSize ) return 1; +#else newSize = oldSize*2 + 100; +#endif idx = (int)(p->yytos - p->yystack); if( p->yystack==p->yystk0 ){ pNew = YYREALLOC(0, newSize*sizeof(pNew[0]));