<li><tt><a href='#pright'>%right</a></tt>
<li><tt><a href='#reallc'>%realloc</a></tt>
<li><tt><a href='#stack_overflow'>%stack_overflow</a></tt>
-<li><tt><a href='#reallc'>%stack_resizer</a></tt>
+<li><tt><a href='#reallc'>%stack_size_limit</a></tt>
<li><tt><a href='#stack_size'>%stack_size</a></tt>
<li><tt><a href='#start_symbol'>%start_symbol</a></tt>
<li><tt><a href='#syntax_error'>%syntax_error</a></tt>
<a id='reallc'></a>
<h4>4.4.26 The <tt>%realloc</tt>, <tt>%free</tt>, and
-<tt>%stack_resizer</tt> directives</h4>
+<tt>%stack_size_limit</tt> directives</h4>
<p>The <tt>%realloc</tt> and <tt>%free</tt> directives defines function
that allocate and free heap memory. The signatures of these functions
is specified by either <tt>%stack_size</tt> or the
-DYYSTACKDEPTH compile-time flag.
-<p>The <tt>%stack_resizer</tt> 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.
-
-<p>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.
-
-<p>The %stack_resizer function only works if %extra_context is also defined.
+<p>The <tt>%stack_size_limit</tt> directive defines a function that returns
+the maximum allowed parser stack size. If this diretive does not exist,
+no size limit is enforced. The function takes a single argument which
+is the %extra_context value or "0" if %extra_context is not defined.
+The function should return an integer that is the maximum
+number of parser stack entries. If more stack space
+than this is needed, the %stack_overflow code is invoked.
<a id='errors'></a>
<h2>5.0 Error Processing</h2>
-C Yet\sanother\sattempt\sat\scontrolling\sthe\sparser\sstack\ssize.
-D 2025-11-18T13:03:08.837
+C Add\sthe\sSQLITE_LIMIT_PARSER_DEPTH\svalue\sfor\ssqlite3_limit().\s\sThis\sisn't\nsomething\sthat\smany\sapplications\swill\sneed,\sbut\sit\sis\suseful\sfor\stesting.
+D 2025-11-18T14:48:33.193
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F doc/compile-for-windows.md f9e74d74da88f384edd5809f825035e071608f00f7f39c0e448df7b3982f979c
F doc/json-enhancements.md e356fc834781f1f1aa22ee300027a270b2c960122468499bf347bb123ce1ea4f
F doc/jsonb.md acd77fc3a709f51242655ad7803510c886aa8304202fa9cf2abc5f5c4e9d7ae5
-F doc/lemon.html 60b3836301ac8555622523569fc5cd3bae5b7a8cd1abab545b6ec14800c90aec
+F doc/lemon.html b4a2ce0ad754bf8ea46fe146bfe6134388748a0a1bcc8292847a52a75307ad4d
F doc/pager-invariants.txt 83aa3a4724b2d7970cc3f3461f0295c46d4fc19a835a5781cbb35cb52feb0577
F doc/tcl-extension-testing.md b88861804fc1eaf83249f8e206334189b61e150c360e1b80d0dcf91af82354f5
F doc/testrunner.md 5ee928637e03f136a25fef852c5ed975932e31927bd9b05a574424ae18c31019
F src/json.c fb031340edee159c07ad37dbe668ffe945ed86f525b0eb3822e4a67cbc498a72
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
F src/loadext.c 4747f72084dc80520a2d23e5bb0bc0760672208a81a2b115ce0b657acd65edf4
-F src/main.c eaf5215917b7e8b34ddea013524287f6d5021ba0fc70202e7602e225ef0d16bf
+F src/main.c c99e86fd7dc6c8c2c0f67395562e3300bca2780b845db9bdc2bdac6acf13c6aa
F src/malloc.c 410e570b30c26cc36e3372577df50f7a96ee3eed5b2b161c6b6b48773c650c5e
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
F src/os_win.h 4c247cdb6d407c75186c94a1e84d5a22cbae4adcec93fcae8d2bc1f956fd1f19
F src/pager.c a81461de271ac4886ad75b7ca2cca8157a48635820c4646cd2714acdc2c17e5f
F src/pager.h 6137149346e6c8a3ddc1eeb40aee46381e9bc8b0fcc6dda8a1efde993c2275b8
-F src/parse.y f54dff6d07f337f9cea8cb3e28144e47877fd2f211fc3a5c5e238e456d51cc8a
+F src/parse.y 6706ff4cfe15194279c8da5acf2b0d1e5845ca945c976398bb4cbe0e188e0744
F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484
F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
F src/pcache1.c 131ca0daf4e66b4608d2945ae76d6ed90de3f60539afbd5ef9ec65667a5f2fcd
F src/resolve.c 5616fbcf3b833c7c705b24371828215ad0925d0c0073216c4f153348d5753f0a
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
F src/select.c ba9cd07ffa3277883c1986085f6ddc4320f4d35d5f212ab58df79a7ecc1a576a
-F src/shell.c.in ceb0a9cc008ac82d8d2e6ef353db14a54bc40dfd60a8cfbb6bc98d071f538761
-F src/sqlite.h.in 667dff873941366da98da3200cf757ac05dfb62ea785e6642e33dd586ae5285c
+F src/shell.c.in 2e4d5dc7978fbf586f590cdc9a30dbf01398bb81159f846293f840f016d218ec
+F src/sqlite.h.in f1363321ca55cc2feaa289e9fe6dfb08102a28c54edf005564711a2348b06eef
F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
F src/sqlite3ext.h 5d5330f5f8461f5ce74960436ddcfa53ecd09c2b8b23901e22ae38aec3243998
-F src/sqliteInt.h 88f7fc9ce1630d9a5f7e0a8e1f3287cdc63882fba985c18e7eee1b9f457f59aa
-F src/sqliteLimit.h fe70bd8983e5d317a264f2ea97473b359faf3ebb0827877a76813f5cf0cdc364
+F src/sqliteInt.h e53f8c6f9a809206b8db9524d294c29e21d0c07bea5114121980bbef30333c6b
+F src/sqliteLimit.h 0a5516b4ec192a205c541e05f67009028a9451dc6678aae4cf8e68596903c246
F src/status.c 7565d63a79aa2f326339a24a0461a60096d0bd2bce711fefb50b5c89335f3592
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
F src/tclsqlite.c 3c604c49e6cf4211960a9ddb9505280fd22cde32175f40884c641c0f5a286036
F src/tclsqlite.h 614b3780a62522bc9f8f2b9fb22689e8009958e7aa77e572d0f3149050af348a
-F src/test1.c 5d061afe479c7364842e0170be7220dea13389575fa6030d30b3e20bec4e1f75
+F src/test1.c 0e71fbcb484a271564e98e0158192c28c24f5521594218c3ba48bcb4cf634f91
F src/test2.c 62f0830958f9075692c29c6de51b495ae8969e1bef85f239ffcd9ba5fb44a5ff
F src/test3.c 432646f581d8af1bb495e58fc98234380250954f5d5535e507fc785eccc3987a
F src/test4.c 0ac87fc13cdb334ab3a71823f99b6c32a6bebe5d603cd6a71d84c823d43a25a0
F test/misc2.test a1a3573cc02662becd967766021d6f16c54684d56df5f227481c7ef0d9df0bd0
F test/misc3.test 651b88bca19b8ff6a7b6af73dae00c3fd5b3ea5bee0c0d1d91abd4c4b4748718
F test/misc4.test 10cd6addb2fa9093df4751a1b92b50440175dd5468a6ec84d0386e78f087db0e
-F test/misc5.test 02fcaf4d42405be02ec975e946270a50b0282dac98c78303ade0d1392839d2b8
+F test/misc5.test 0a5d7604e197f10ee471280bfcaaf8229f9d8e2eebfef2c8853222cbc1ea9cd5
F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91
F test/misc7.test d595599972ec0b436985f0f02f243b68500ffc977b9b3194ec66c0866cfddcab
F test/misc8.test 08d2380bc435486b12161521f225043ac2be26f02471c2c1ea4cac0b1548edbd
F tool/genfkey.test b6afd7b825d797a1e1274f519ab5695373552ecad5cd373530c63533638a5a4f
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
F tool/index_usage.c f62a0c701b2c7ff2f3e21d206f093c123f222dbf07136a10ffd1ca15a5c706c5
-F tool/lemon.c acb9b4e4d6a9826d40163b1da71e049859c7230217c39a6a63dc81ed8d28c906
-F tool/lempar.c ff3c9b32cf36152616dd2bb78ea0fdd3ec6c0f2e76ec55f0d2b50dcb35122b46
+F tool/lemon.c 4150f2020d453cfa46b6fa45542e59b923ad7eab063fb4ca20777995622cab0b
+F tool/lempar.c 25aea31b33bbd15f0f7324c796e160c602f2a1d4e3f6f87d6d4fb25d77eaf54a
F tool/libvers.c caafc3b689638a1d88d44bc5f526c2278760d9b9
F tool/loadfts.c 63412f9790e5e8538fbde0b4f6db154aaaf80f7a10a01e3c94d14b773a8dd5a6
F tool/logest.c c34e5944318415de513d29a6098df247a9618c96d83c38d4abd88641fe46e669
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 5c0214df2c0a7470ac2edca0c483a3edd3c39ef0739688ab9a06e23882200360
-R 77442b17c4e08c97334e79ed87f9944e
-T *branch * parser-stack-size
-T *sym-parser-stack-size *
-T -sym-trunk *
+P cb19986dc6bc483df21e082e54a14cb6d7540b1734259e6d326d676908ac0172
+R 7eda36c539b846b8b7294d534ccca677
U drh
-Z df6b29f678f7d3bd6a12aec2b921e4cb
+Z 033a2ffcce1aafa9ea403459cb7996b3
# Remove this line to create a well-formed Fossil manifest.
-cb19986dc6bc483df21e082e54a14cb6d7540b1734259e6d326d676908ac0172
+8f0b07f36159225c476f756f8f9b35c75783bc8bed43b578f4d1055fa800ecc9
SQLITE_MAX_VARIABLE_NUMBER, /* IMP: R-38091-32352 */
SQLITE_MAX_TRIGGER_DEPTH,
SQLITE_MAX_WORKER_THREADS,
+ SQLITE_MAX_PARSER_DEPTH,
};
/*
assert( aHardLimit[SQLITE_LIMIT_SQL_LENGTH]==SQLITE_MAX_SQL_LENGTH );
assert( aHardLimit[SQLITE_LIMIT_COLUMN]==SQLITE_MAX_COLUMN );
assert( aHardLimit[SQLITE_LIMIT_EXPR_DEPTH]==SQLITE_MAX_EXPR_DEPTH );
+ assert( aHardLimit[SQLITE_LIMIT_PARSER_DEPTH]==SQLITE_MAX_PARSER_DEPTH );
assert( aHardLimit[SQLITE_LIMIT_COMPOUND_SELECT]==SQLITE_MAX_COMPOUND_SELECT);
assert( aHardLimit[SQLITE_LIMIT_VDBE_OP]==SQLITE_MAX_VDBE_OP );
assert( aHardLimit[SQLITE_LIMIT_FUNCTION_ARG]==SQLITE_MAX_FUNCTION_ARG );
assert( aHardLimit[SQLITE_LIMIT_VARIABLE_NUMBER]==SQLITE_MAX_VARIABLE_NUMBER);
assert( aHardLimit[SQLITE_LIMIT_TRIGGER_DEPTH]==SQLITE_MAX_TRIGGER_DEPTH );
assert( aHardLimit[SQLITE_LIMIT_WORKER_THREADS]==SQLITE_MAX_WORKER_THREADS );
- assert( SQLITE_LIMIT_WORKER_THREADS==(SQLITE_N_LIMIT-1) );
+ assert( SQLITE_LIMIT_PARSER_DEPTH==(SQLITE_N_LIMIT-1) );
if( limitId<0 || limitId>=SQLITE_N_LIMIT ){
}
// Function used to enlarge the parser stack, if needed
-%stack_resizer parserStackResize
-%realloc parserStackRealloc
-%free sqlite3_free
+%stack_size_limit parserStackSizeLimit
+%realloc parserStackRealloc
+%free sqlite3_free
// All token codes are small integers with #defines that begin with "TK_"
%token_prefix TK_
}
}
%stack_overflow {
- if( pParse->nErr==0 ) sqlite3OomFault(pParse->db);
+ if( pParse->nErr==0 ) sqlite3ErrorMsg(pParse, "Recursion limit");
}
// The name of the generated procedure that implements the parser
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;
+ /* Return an integer that is the maximum allowed stack size */
+ static int parserStackSizeLimit(Parse *pParse){
+ return pParse->db->aLimit[SQLITE_LIMIT_PARSER_DEPTH];
}
}
{ "sql_length", SQLITE_LIMIT_SQL_LENGTH },
{ "column", SQLITE_LIMIT_COLUMN },
{ "expr_depth", SQLITE_LIMIT_EXPR_DEPTH },
+ { "parser_depth", SQLITE_LIMIT_PARSER_DEPTH },
{ "compound_select", SQLITE_LIMIT_COMPOUND_SELECT },
{ "vdbe_op", SQLITE_LIMIT_VDBE_OP },
{ "function_arg", SQLITE_LIMIT_FUNCTION_ARG },
** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(<dt>SQLITE_LIMIT_EXPR_DEPTH</dt>
** <dd>The maximum depth of the parse tree on any expression.</dd>)^
**
+** [[SQLITE_LIMIT_PARSER_DEPTH]] ^(<dt>SQLITE_LIMIT_PARSER_DEPTH</dt>
+** <dd>The maximum depth of the LALR(1) parser stack used to analyze
+** input SQL statements.</dd>)^
+**
** [[SQLITE_LIMIT_COMPOUND_SELECT]] ^(<dt>SQLITE_LIMIT_COMPOUND_SELECT</dt>
** <dd>The maximum number of terms in a compound SELECT statement.</dd>)^
**
#define SQLITE_LIMIT_VARIABLE_NUMBER 9
#define SQLITE_LIMIT_TRIGGER_DEPTH 10
#define SQLITE_LIMIT_WORKER_THREADS 11
+#define SQLITE_LIMIT_PARSER_DEPTH 12
/*
** CAPI3REF: Prepare Flags
** The number of different kinds of things that can be limited
** using the sqlite3_limit() interface.
*/
-#define SQLITE_N_LIMIT (SQLITE_LIMIT_WORKER_THREADS+1)
+#define SQLITE_N_LIMIT (SQLITE_LIMIT_PARSER_DEPTH+1)
/*
** Lookaside malloc is a set of fixed-size buffers that can be used
#endif
/*
-** The maximum depth of an expression tree. This is limited to
-** some extent by SQLITE_MAX_SQL_LENGTH. But sometime you might
-** want to place more severe limits on the complexity of an
-** expression. A value of 0 means that there is no limit.
+** The maximum depth of an expression tree. The expression tree depth
+** is also limited indirectly by SQLITE_MAX_SQL_LENGTH and by
+** SQLITE_MAX_PARSER_DEPTH. Reducing the maximum complexity of
+** expressions can help prevent excess memory usage by hostile SQL.
+**
+** A value of 0 for this compile-time option causes all expression
+** depth limiting code to be omitted.
*/
#ifndef SQLITE_MAX_EXPR_DEPTH
# define SQLITE_MAX_EXPR_DEPTH 1000
#endif
+/*
+** The maximum depth of the LALR(1) stack used in the parser that
+** interprets SQL inputs. The parser stack depth can also be limited
+** indirectly by SQLITE_MAX_SQL_LENGTH. Limiting the parser stack
+** depth can help prevent excess memory usage and excess CPU stack
+** usage when processing hostile SQL.
+**
+** Prior to version 3.45.0 (2024-01-15), the parser stack was
+** hard-coded to 100 entries, and that worked fine for almost all
+** applications. So the upper bound on this limit need not be large.
+*/
+#ifndef SQLITE_MAX_PARSER_DEPTH
+# define SQLITE_MAX_PARSER_DEPTH 2500
+#endif
+
/*
** The maximum number of terms in a compound SELECT statement.
** The code generator for compound SELECT statements does one
{ "SQLITE_LIMIT_SQL_LENGTH", SQLITE_LIMIT_SQL_LENGTH },
{ "SQLITE_LIMIT_COLUMN", SQLITE_LIMIT_COLUMN },
{ "SQLITE_LIMIT_EXPR_DEPTH", SQLITE_LIMIT_EXPR_DEPTH },
+ { "SQLITE_LIMIT_PARSER_DEPTH", SQLITE_LIMIT_PARSER_DEPTH },
{ "SQLITE_LIMIT_COMPOUND_SELECT", SQLITE_LIMIT_COMPOUND_SELECT },
{ "SQLITE_LIMIT_VDBE_OP", SQLITE_LIMIT_VDBE_OP },
{ "SQLITE_LIMIT_FUNCTION_ARG", SQLITE_LIMIT_FUNCTION_ARG },
/* Out of range test cases */
{ "SQLITE_LIMIT_TOOSMALL", -1, },
- { "SQLITE_LIMIT_TOOBIG", SQLITE_LIMIT_WORKER_THREADS+1 },
+ { "SQLITE_LIMIT_TOOBIG", SQLITE_LIMIT_PARSER_DEPTH+1 },
};
int i, id = 0;
int val;
}
append sql "0$tail); SELECT * FROM t1;"
catchsql $sql
-} {0 900}
+} {1 {Recursion limit}}
# Parser stack overflow is silently ignored when it occurs while parsing the
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 *stackSizeLimit; /* Function to return the stack size limit */
char *reallocFunc; /* Function to use to allocate stack space */
char *freeFunc; /* Function to use to free stack space */
int nconflict; /* Number of parsing conflicts */
}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);
+ }else if( strcmp(x,"stack_size_limit")==0 ){
+ psp->declargslot = &(psp->gp->stackSizeLimit);
psp->insertLineMacro = 0;
}else if( strcmp(x,"realloc")==0 ){
psp->declargslot = &(psp->gp->reallocFunc);
}else{
fprintf(out,"#define YYDYNSTACK 0\n"); lineno++;
}
- fprintf(out, "#undef YYRESIZE\n"); lineno++;
+ fprintf(out, "#undef YYSIZELIMIT\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++;
+ if( notnull(lemp->stackSizeLimit) ){
+ fprintf(out,"#define YYSIZELIMIT %s\n", lemp->stackSizeLimit); 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_STORE yypParser->%s=%s;\n",
name,&lemp->ctx[i],&lemp->ctx[i]); lineno++;
}else{
+ fprintf(out,"#define %sCTX(P) 0\n",name); lineno++;
fprintf(out,"#define %sCTX_SDECL\n",name); lineno++;
fprintf(out,"#define %sCTX_PDECL\n",name); lineno++;
fprintf(out,"#define %sCTX_PARAM\n",name); lineno++;
int newSize;
int idx;
yyStackEntry *pNew;
+#ifdef YYSIZELIMIT
+ int nLimit = YYSIZELIMIT(ParseCTX(p));
+#endif
-#ifdef YYRESIZE
- newSize = YYRESIZE(oldSize, ParseCTX(p));
- if( newSize<=oldSize ) return 1;
-#else
newSize = oldSize*2 + 100;
+#ifdef YYSIZELIMIT
+ if( newSize>nLimit ){
+ newSize = nLimit;
+ if( newSize<=oldSize ) return 1;
+ }
#endif
idx = (int)(p->yytos - p->yystack);
if( p->yystack==p->yystk0 ){