From 6b783ec950d2a0fa153fc4c7a1d09748e2f06560 Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 18 Nov 2025 02:24:46 +0000 Subject: [PATCH] Pervent the parser stack from growing to be larger than 100 plus four times the SQLITE_LIMIT_EXPR_DEPTH setting. FossilOrigin-Name: 5728129e5432500550096e2a1350897881f0379b49b60faf49481c505b1eb323 --- doc/lemon.html | 33 ++++++++++++++++++++++++--------- manifest | 23 +++++++++++++---------- manifest.tags | 4 ++-- manifest.uuid | 2 +- src/parse.y | 19 ++++++++++++++----- tool/lemon.c | 39 +++++++++++++++++++++++---------------- tool/lempar.c | 4 ++-- 7 files changed, 79 insertions(+), 45 deletions(-) diff --git a/doc/lemon.html b/doc/lemon.html index 965f305c04..f4f7468fe9 100644 --- a/doc/lemon.html +++ b/doc/lemon.html @@ -695,6 +695,7 @@ other than that, the order of directives in Lemon is arbitrary.

  • %parse_failure
  • %right
  • %realloc +
  • %reallocx
  • %stack_overflow
  • %stack_size
  • %start_symbol @@ -1203,15 +1204,29 @@ 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

    - -

    The %realloc and %free directives defines function -that allocate and free heap memory. The signatures of these functions -should be the same as the realloc() and free() functions from the standard -C library. - -

    If both of these functions are defined -then these functions are used to allocate and free +

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

    + +

    The %realloc, %reallocx, and %free +directives defines function that allocate and free heap memory. +The signatures of th3 %realloc and %free are the same as +realloc() and free() functions from the standard C library. +The %reallocx function has the same semantics as %realloc but +takes four parameters instead of two: +

      +
    1. A pointer to the space to be reallocated, or NULL for a new allocation, +
    2. The number of elements to allocate, +
    3. The size of each element, +
    4. The %extra parameter. +
    +The extra parameters of %reallocx can be used, for example, to monitor +the parser stack size and raise an error if it exceeds application-defined +limits. +If both %reallocx and %realloc are defined, then %reallocx is used +and %realloc is ignored. + +

    If %free is defined and one of %realloc and %reallocx is +defined then the functions are used to allocate and free memory for supplemental parser stack space, if the initial parse stack space is exceeded. The initial parser stack size is specified by either %stack_size or the diff --git a/manifest b/manifest index ad44d17d28..e934034337 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sapi.oo1=0\sflag\sto\sext/wasm/GNUmakefile\sto\sstrip\sout\sthe\ssqlite3.oo1\spieces\sfrom\sthe\sbuild.\sPart\sof\sthe\songoing\sresponse\sto\s[forum:4b7d45433731d2e0|forum\spost\s4b7d45433731d2e0]. -D 2025-11-17T23:55:41.172 +C Pervent\sthe\sparser\sstack\sfrom\sgrowing\sto\sbe\slarger\sthan\s100\splus\sfour\stimes\nthe\sSQLITE_LIMIT_EXPR_DEPTH\ssetting. +D 2025-11-18T02:24:46.688 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 0e4b854b5ca0cf3600fec4da454197f651e8a0d411a90653703e75474486ad31 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 04c6c7278939e3c6307ed3c6ed7482d2928e692560dbe8e57f524851a934e25c 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 8f6c122e5727cb0e5f302b8efc91489b1947a8d98206d7a1b1cfc0ed685b6e7c -F tool/lempar.c bdffd3b233a4e4e78056c9c01fadd2bb3fe902435abde3bce3d769fdf0d5cca2 +F tool/lemon.c fda0511d71764674919872a1457d2f86a7d48b13bfcf98741955c1b217a84570 +F tool/lempar.c a59c5474bdd148ca4c61f2977c7ce6b49e99c48a333b6d48fc7ceacf2292b43a 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 6621737cc05cbf8ff5f576775a8a3c64f666b56d42939968ebb55d72a835646b -R f725b34e8d754de05251b176eb359cd6 -U stephan -Z c71a6e355b45027ea5bfc35ef83fb8b3 +P ea48567ac54e4949a8b68977a58a5de7946e074ae8737133071d02f40ac97f34 +R 94faba231c7b1fe01c357a8fbebddcb3 +T *branch * parser-recursion-limit +T *sym-parser-recursion-limit * +T -sym-trunk * +U drh +Z ef6a72fd333d3e7f2a3d9cd4902c91e6 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.tags b/manifest.tags index bec971799f..e9611298bc 100644 --- a/manifest.tags +++ b/manifest.tags @@ -1,2 +1,2 @@ -branch trunk -tag trunk +branch parser-recursion-limit +tag parser-recursion-limit diff --git a/manifest.uuid b/manifest.uuid index a38149056e..714d764112 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ea48567ac54e4949a8b68977a58a5de7946e074ae8737133071d02f40ac97f34 +5728129e5432500550096e2a1350897881f0379b49b60faf49481c505b1eb323 diff --git a/src/parse.y b/src/parse.y index 617eb7303b..52a292104d 100644 --- a/src/parse.y +++ b/src/parse.y @@ -22,8 +22,8 @@ } // Function used to enlarge the parser stack, if needed -%realloc parserStackRealloc -%free sqlite3_free +%reallocx parserStackRealloc +%free sqlite3_free // All token codes are small integers with #defines that begin with "TK_" %token_prefix TK_ @@ -49,7 +49,7 @@ } } %stack_overflow { - sqlite3OomFault(pParse->db); + if( pParse->nErr==0 ) sqlite3OomFault(pParse->db); } // The name of the generated procedure that implements the parser @@ -583,8 +583,17 @@ cmd ::= select(X). { ** sqlite3_realloc() that includes a call to sqlite3FaultSim() to facilitate ** testing. */ - static void *parserStackRealloc(void *pOld, sqlite3_uint64 newSize){ - return sqlite3FaultSim(700) ? 0 : sqlite3_realloc(pOld, newSize); + static void *parserStackRealloc( + void *pOld, /* Old allocation, or NULL to get a new one */ + int newCount, /* Number of elements */ + int unitSize, /* Size of each element */ + Parse *pParse /* Parsing context */ + ){ + if( sqlite3FaultSim(700) ) return 0; + if( newCount > pParse->db->aLimit[SQLITE_LIMIT_EXPR_DEPTH]*4+100 ){ + sqlite3ErrorMsg(pParse, "Recursion limit reached"); + } + return sqlite3_realloc64(pOld, newCount*unitSize); } } diff --git a/tool/lemon.c b/tool/lemon.c index 324dda0c5f..bf86c6382b 100644 --- a/tool/lemon.c +++ b/tool/lemon.c @@ -495,6 +495,7 @@ struct lemon { char *outname; /* Name of the current output file */ char *tokenprefix; /* A prefix added to token names in the .h file */ char *reallocFunc; /* Function to use to allocate stack space */ + char *reallocFuncEx; /* Alternative realloc() with context pointer */ char *freeFunc; /* Function to use to free stack space */ int nconflict; /* Number of parsing conflicts */ int nactiontab; /* Number of entries in the yy_action[] table */ @@ -2641,6 +2642,9 @@ static void parseonetoken(struct pstate *psp) }else if( strcmp(x,"realloc")==0 ){ psp->declargslot = &(psp->gp->reallocFunc); psp->insertLineMacro = 0; + }else if( strcmp(x,"reallocx")==0 ){ + psp->declargslot = &(psp->gp->reallocFuncEx); + psp->insertLineMacro = 0; }else if( strcmp(x,"free")==0 ){ psp->declargslot = &(psp->gp->freeFunc); psp->insertLineMacro = 0; @@ -4414,7 +4418,7 @@ void ReportTable( int mhflag, /* Output in makeheaders format if true */ int sqlFlag /* Generate the *.sql file too */ ){ - FILE *out, *in, *sql; + FILE *out, *in; int lineno; struct state *stp; struct action *ap; @@ -4439,18 +4443,10 @@ void ReportTable( in = tplt_open(lemp); if( in==0 ) return; - out = file_open(lemp,".c","wb"); - if( out==0 ){ - fclose(in); - return; - } - if( sqlFlag==0 ){ - sql = 0; - }else{ - sql = file_open(lemp, ".sql", "wb"); + if( sqlFlag ){ + FILE *sql = file_open(lemp, ".sql", "wb"); if( sql==0 ){ fclose(in); - fclose(out); return; } fprintf(sql, @@ -4515,6 +4511,12 @@ void ReportTable( } } fprintf(sql, "COMMIT;\n"); + fclose(sql); + } + out = file_open(lemp,".c","wb"); + if( out==0 ){ + fclose(in); + return; } lineno = 1; @@ -4612,17 +4614,21 @@ void ReportTable( fprintf(out,"#define %sARG_FETCH\n",name); lineno++; fprintf(out,"#define %sARG_STORE\n",name); lineno++; } - if( lemp->reallocFunc ){ - fprintf(out,"#define YYREALLOC %s\n", lemp->reallocFunc); lineno++; + if( lemp->reallocFuncEx ){ + fprintf(out,"#define YYREALLOC(A,B,C,D) %s(A,B,C,D)\n", + lemp->reallocFuncEx); lineno++; + }else if( lemp->reallocFunc ){ + fprintf(out,"#define YYREALLOC(A,B,C,D) %s(A,B*C)\n", + lemp->reallocFunc); lineno++; }else{ - fprintf(out,"#define YYREALLOC realloc\n"); lineno++; + fprintf(out,"#define YYREALLOC(A,B,C,D) realloc(A,B*C)\n"); lineno++; } if( lemp->freeFunc ){ fprintf(out,"#define YYFREE %s\n", lemp->freeFunc); lineno++; }else{ fprintf(out,"#define YYFREE free\n"); lineno++; } - if( lemp->reallocFunc && lemp->freeFunc ){ + if( (lemp->reallocFunc || lemp->reallocFuncEx) && lemp->freeFunc ){ fprintf(out,"#define YYDYNSTACK 1\n"); lineno++; }else{ fprintf(out,"#define YYDYNSTACK 0\n"); lineno++; @@ -4634,6 +4640,7 @@ void ReportTable( 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++; + fprintf(out,"#define %sCTX_FIELD %s\n",name,&lemp->ctx[i]); lineno++; fprintf(out,"#define %sCTX_FETCH %s=yypParser->%s;\n", name,lemp->ctx,&lemp->ctx[i]); lineno++; fprintf(out,"#define %sCTX_STORE yypParser->%s=%s;\n", @@ -4642,6 +4649,7 @@ void ReportTable( fprintf(out,"#define %sCTX_SDECL\n",name); lineno++; fprintf(out,"#define %sCTX_PDECL\n",name); lineno++; fprintf(out,"#define %sCTX_PARAM\n",name); lineno++; + fprintf(out,"#define %sCTX_FIELD yyhwm\n", name); lineno++; fprintf(out,"#define %sCTX_FETCH\n",name); lineno++; fprintf(out,"#define %sCTX_STORE\n",name); lineno++; } @@ -5103,7 +5111,6 @@ void ReportTable( acttab_free(pActtab); fclose(in); fclose(out); - if( sql ) fclose(sql); return; } diff --git a/tool/lempar.c b/tool/lempar.c index 74314efeaa..7140767f76 100644 --- a/tool/lempar.c +++ b/tool/lempar.c @@ -303,11 +303,11 @@ static int yyGrowStack(yyParser *p){ newSize = oldSize*2 + 100; idx = (int)(p->yytos - p->yystack); if( p->yystack==p->yystk0 ){ - pNew = YYREALLOC(0, newSize*sizeof(pNew[0])); + pNew = YYREALLOC(0,newSize,sizeof(pNew[0]), p->ParseCTX_FIELD); if( pNew==0 ) return 1; memcpy(pNew, p->yystack, oldSize*sizeof(pNew[0])); }else{ - pNew = YYREALLOC(p->yystack, newSize*sizeof(pNew[0])); + pNew = YYREALLOC(p->yystack,newSize,sizeof(pNew[0]),p->ParseCTX_FIELD); if( pNew==0 ) return 1; } p->yystack = pNew; -- 2.47.3