]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
More agressive use of /*A-overwrites-X*/ in the parser. Fix an off-by-one parser-performance
authordrh <drh@noemail.net>
Wed, 17 Feb 2016 12:34:03 +0000 (12:34 +0000)
committerdrh <drh@noemail.net>
Wed, 17 Feb 2016 12:34:03 +0000 (12:34 +0000)
error in parser stack overflow detection.

FossilOrigin-Name: 417e777701bbf4bd67626d4ca3bc2c5d847f6cd0

manifest
manifest.uuid
src/parse.y
tool/lemon.c
tool/lempar.c

index c34c4dda4bfdf9d286ec78de751e2a6933fa4d68..1da9e5e200b64444dcf6fb6dd95c0cc07f54af5c 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Enhance\sLemon\sso\sthat\sif\sreduce\scode\scontains\sa\scomment\sof\sthe\sform\n"/*A-overwrites-X*/"\sthen\sa\sLHS\slabel\sA\sis\sallowed\sto\soverwrite\sthe\nRHS\slabel\sX.
-D 2016-02-17T04:33:10.506
+C More\sagressive\suse\sof\s/*A-overwrites-X*/\sin\sthe\sparser.\s\sFix\san\soff-by-one\nerror\sin\sparser\sstack\soverflow\sdetection.
+D 2016-02-17T12:34:03.961
 F Makefile.in 4e90dc1521879022aa9479268a4cd141d1771142
 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
 F Makefile.msc 30f075dc4f27a07abb76088946b2944178d85347
@@ -337,7 +337,7 @@ F src/os_win.c f0d7aa603eb6262143d7169a222aea07c4fca91d
 F src/os_win.h eb7a47aa17b26b77eb97e4823f20a00b8bda12ca
 F src/pager.c 6812f3803951774b56abded396171e1c12b0b003
 F src/pager.h f3eb324a3ff2408b28bab7e81c1c55c13720f865
-F src/parse.y 8c2f7e7e12cb03ddeaa204463198978aab2dcde9
+F src/parse.y c3ce2c4a7cbf0b699239be6b2a945c5cb51875e2
 F src/pcache.c 647bb53a86b7bbcf55ad88089b3ea5a9170b90df
 F src/pcache.h 4d0ccaad264d360981ec5e6a2b596d6e85242545
 F src/pcache1.c 72f644dc9e1468c72922eff5904048427b817051
@@ -1378,8 +1378,8 @@ F tool/fuzzershell.c 94019b185caceffc9f7c7b678a6489e42bc2aefa
 F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4
 F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5
 F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
-F tool/lemon.c 31a7325a4407fa35af7e5913b67517debae8181b
-F tool/lempar.c c7dde8fae568759a1a136b1acf35c4084864d035
+F tool/lemon.c 251f5c3f21b553240cbdd42dd187a51bb2372cd3
+F tool/lempar.c 5f626c741e034da827b4224d0c68eaf6d8fcc72c
 F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
 F tool/logest.c eef612f8adf4d0993dafed0416064cf50d5d33c6
 F tool/mkautoconfamal.sh c78caa3214f25dc28ea157b5a82abb311f209906
@@ -1427,7 +1427,7 @@ F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh a98af506df552f3b3c0d904f94e4cdc4e1a6d598
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P ef95a7d6490e33a9af4bc7b4b622de7328742ca7
-R f9d92e1ecf92fd9298e3c4ee80590b18
+P 5cfe9545d478a2c500083613dd20e14b2ffce645
+R d924bff2a49f13e938a4912c2ba811f7
 U drh
-Z 42e27a9e216e6c463abe3b883471bdc4
+Z be09b78429c9c8eaf29c2a1ea6a1c05b
index 2c12f2f200c5416371fad7c6d7e36081232f0b32..329508012e8ee6106ea1460ed21d3bfdccd0221c 100644 (file)
@@ -1 +1 @@
-5cfe9545d478a2c500083613dd20e14b2ffce645
\ No newline at end of file
+417e777701bbf4bd67626d4ca3bc2c5d847f6cd0
\ No newline at end of file
index f1060305eef3714ecbcc353c7cc733f8a7767a81..e7e0d1d95393b0259316837aa0e2a887e0e0a111 100644 (file)
@@ -302,7 +302,7 @@ ccons ::= DEFAULT MINUS(A) term(X).      {
 }
 ccons ::= DEFAULT id(X).              {
   ExprSpan v;
-  spanExpr(&v, pParse, TK_STRING, &X);
+  spanExpr(&v, pParse, TK_STRING, X);
   sqlite3AddDefaultValue(pParse,&v);
 }
 
@@ -490,6 +490,9 @@ multiselect_op(A) ::= EXCEPT|INTERSECT(OP).  {A = @OP; /*A-overwrites-OP*/}
 %endif SQLITE_OMIT_COMPOUND_SELECT
 oneselect(A) ::= SELECT(S) distinct(D) selcollist(W) from(X) where_opt(Y)
                  groupby_opt(P) having_opt(Q) orderby_opt(Z) limit_opt(L). {
+#if SELECTTRACE_ENABLED
+  Token s = S; /*A-overwrites-S*/
+#endif
   A = sqlite3SelectNew(pParse,W,X,Y,P,Q,Z,D,L.pLimit,L.pOffset);
 #if SELECTTRACE_ENABLED
   /* Populate the Select.zSelName[] string that is used to help with
@@ -502,7 +505,7 @@ oneselect(A) ::= SELECT(S) distinct(D) selcollist(W) from(X) where_opt(Y)
   ** is an integer that is incremented with each SELECT statement seen.
   */
   if( A!=0 ){
-    const char *z = S.z+6;
+    const char *z = s.z+6;
     int i;
     sqlite3_snprintf(sizeof(A->zSelName), A->zSelName, "#%d",
                      ++pParse->nSelect);
@@ -852,18 +855,19 @@ idlist(A) ::= nm(Y).
   ** new Expr to populate pOut.  Set the span of pOut to be the identifier
   ** that created the expression.
   */
-  static void spanExpr(ExprSpan *pOut, Parse *pParse, int op, Token *pValue){
-    pOut->pExpr = sqlite3PExpr(pParse, op, 0, 0, pValue);
-    pOut->zStart = pValue->z;
-    pOut->zEnd = &pValue->z[pValue->n];
+  static void spanExpr(ExprSpan *pOut, Parse *pParse, int op, Token t){
+    pOut->pExpr = sqlite3PExpr(pParse, op, 0, 0, &t);
+    pOut->zStart = t.z;
+    pOut->zEnd = &t.z[t.n];
   }
 }
 
 expr(A) ::= term(A).
-expr(A) ::= LP(B) expr(X) RP(E). {A.pExpr = X.pExpr; spanSet(&A,&B,&E);}
-term(A) ::= NULL(X).             {spanExpr(&A, pParse, @X, &X);}
-expr(A) ::= id(X).               {spanExpr(&A, pParse, TK_ID, &X);}
-expr(A) ::= JOIN_KW(X).          {spanExpr(&A, pParse, TK_ID, &X);}
+expr(A) ::= LP(B) expr(X) RP(E).
+            {spanSet(&A,&B,&E); /*A-overwrites-B*/  A.pExpr = X.pExpr;}
+term(A) ::= NULL(X).        {spanExpr(&A,pParse,@X,X);/*A-overwrites-X*/}
+expr(A) ::= id(X).          {spanExpr(&A,pParse,TK_ID,X); /*A-overwrites-X*/}
+expr(A) ::= JOIN_KW(X).     {spanExpr(&A,pParse,TK_ID,X); /*A-overwrites-X*/}
 expr(A) ::= nm(X) DOT nm(Y). {
   Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);
   Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &Y);
@@ -878,25 +882,26 @@ expr(A) ::= nm(X) DOT nm(Y) DOT nm(Z). {
   spanSet(&A,&X,&Z); /*A-overwrites-X*/
   A.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp4, 0);
 }
-term(A) ::= INTEGER|FLOAT|BLOB(X).  {spanExpr(&A, pParse, @X, &X);}
-term(A) ::= STRING(X).              {spanExpr(&A, pParse, @X, &X);}
+term(A) ::= INTEGER|FLOAT|BLOB(X). {spanExpr(&A,pParse,@X,X);/*A-overwrites-X*/}
+term(A) ::= STRING(X).             {spanExpr(&A,pParse,@X,X);/*A-overwrites-X*/}
 expr(A) ::= VARIABLE(X).     {
-  if( X.n>=2 && X.z[0]=='#' && sqlite3Isdigit(X.z[1]) ){
+  Token t = X; /*A-overwrites-X*/
+  if( t.n>=2 && t.z[0]=='#' && sqlite3Isdigit(t.z[1]) ){
     /* When doing a nested parse, one can include terms in an expression
     ** that look like this:   #1 #2 ...  These terms refer to registers
     ** in the virtual machine.  #N is the N-th register. */
+    spanSet(&A, &t, &t);
     if( pParse->nested==0 ){
-      sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &X);
+      sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t);
       A.pExpr = 0;
     }else{
-      A.pExpr = sqlite3PExpr(pParse, TK_REGISTER, 0, 0, &X);
-      if( A.pExpr ) sqlite3GetInt32(&X.z[1], &A.pExpr->iTable);
+      A.pExpr = sqlite3PExpr(pParse, TK_REGISTER, 0, 0, &t);
+      if( A.pExpr ) sqlite3GetInt32(&t.z[1], &A.pExpr->iTable);
     }
   }else{
-    spanExpr(&A, pParse, TK_VARIABLE, &X);
+    spanExpr(&A, pParse, TK_VARIABLE, t);
     sqlite3ExprAssignVarNumber(pParse, A.pExpr);
   }
-  spanSet(&A, &X, &X);
 }
 expr(A) ::= expr(A) COLLATE ids(C). {
   A.pExpr = sqlite3ExprAddCollateToken(pParse, A.pExpr, &C, 1);
@@ -904,8 +909,8 @@ expr(A) ::= expr(A) COLLATE ids(C). {
 }
 %ifndef SQLITE_OMIT_CAST
 expr(A) ::= CAST(X) LP expr(E) AS typetoken(T) RP(Y). {
+  spanSet(&A,&X,&Y); /*A-overwrites-X*/
   A.pExpr = sqlite3PExpr(pParse, TK_CAST, E.pExpr, 0, &T);
-  spanSet(&A,&X,&Y);
 }
 %endif  SQLITE_OMIT_CAST
 expr(A) ::= id(X) LP distinct(D) exprlist(Y) RP(E). {
@@ -1041,20 +1046,22 @@ expr(A) ::= expr(A) IS NOT expr(Y). {
     ExprSpan *pOperand,    /* The operand */
     Token *pPreOp         /* The operand token for setting the span */
   ){
-    pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0, 0);
     pOut->zStart = pPreOp->z;
+    pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0, 0);
     pOut->zEnd = pOperand->zEnd;
   }
 }
 
 
 
-expr(A) ::= NOT(B) expr(X).    {spanUnaryPrefix(&A,pParse,@B,&X,&B);}
-expr(A) ::= BITNOT(B) expr(X). {spanUnaryPrefix(&A,pParse,@B,&X,&B);}
+expr(A) ::= NOT(B) expr(X).  
+              {spanUnaryPrefix(&A,pParse,@B,&X,&B);/*A-overwrites-B*/}
+expr(A) ::= BITNOT(B) expr(X).
+              {spanUnaryPrefix(&A,pParse,@B,&X,&B);/*A-overwrites-B*/}
 expr(A) ::= MINUS(B) expr(X). [BITNOT]
-                               {spanUnaryPrefix(&A,pParse,TK_UMINUS,&X,&B);}
+              {spanUnaryPrefix(&A,pParse,TK_UMINUS,&X,&B);/*A-overwrites-B*/}
 expr(A) ::= PLUS(B) expr(X). [BITNOT]
-                               {spanUnaryPrefix(&A,pParse,TK_UPLUS,&X,&B);}
+              {spanUnaryPrefix(&A,pParse,TK_UPLUS,&X,&B);/*A-overwrites-B*/}
 
 %type between_op {int}
 between_op(A) ::= BETWEEN.     {A = 0;}
@@ -1127,6 +1134,7 @@ expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
     A.zEnd = &E.z[E.n];
   }
   expr(A) ::= LP(B) select(X) RP(E). {
+    spanSet(&A,&B,&E); /*A-overwrites-B*/
     A.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0);
     if( A.pExpr ){
       A.pExpr->x.pSelect = X;
@@ -1135,8 +1143,6 @@ expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
     }else{
       sqlite3SelectDelete(pParse->db, X);
     }
-    A.zStart = B.z;
-    A.zEnd = &E.z[E.n];
   }
   expr(A) ::= expr(A) in_op(N) LP select(Y) RP(E).  [IN] {
     A.pExpr = sqlite3PExpr(pParse, TK_IN, A.pExpr, 0, 0);
@@ -1164,7 +1170,9 @@ expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
     A.zEnd = Z.z ? &Z.z[Z.n] : &Y.z[Y.n];
   }
   expr(A) ::= EXISTS(B) LP select(Y) RP(E). {
-    Expr *p = A.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0);
+    Expr *p;
+    spanSet(&A,&B,&E); /*A-overwrites-B*/
+    p = A.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0);
     if( p ){
       p->x.pSelect = Y;
       ExprSetProperty(p, EP_xIsSelect|EP_Subquery);
@@ -1172,13 +1180,12 @@ expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
     }else{
       sqlite3SelectDelete(pParse->db, Y);
     }
-    A.zStart = B.z;
-    A.zEnd = &E.z[E.n];
   }
 %endif SQLITE_OMIT_SUBQUERY
 
 /* CASE expressions */
 expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
+  spanSet(&A,&C,&E);  /*A-overwrites-C*/
   A.pExpr = sqlite3PExpr(pParse, TK_CASE, X, 0, 0);
   if( A.pExpr ){
     A.pExpr->x.pList = Z ? sqlite3ExprListAppend(pParse,Y,Z) : Y;
@@ -1187,8 +1194,6 @@ expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
     sqlite3ExprListDelete(pParse->db, Y);
     sqlite3ExprDelete(pParse->db, Z);
   }
-  A.zStart = C.z;
-  A.zEnd = &E.z[E.n];
 }
 %type case_exprlist {ExprList*}
 %destructor case_exprlist {sqlite3ExprListDelete(pParse->db, $$);}
@@ -1415,19 +1420,19 @@ tridxby ::= NOT INDEXED. {
 // UPDATE 
 trigger_cmd(A) ::=
    UPDATE orconf(R) trnm(X) tridxby SET setlist(Y) where_opt(Z).  
-   { A = sqlite3TriggerUpdateStep(pParse->db, &X, Y, Z, R); }
+   {A = sqlite3TriggerUpdateStep(pParse->db, &X, Y, Z, R);}
 
 // INSERT
 trigger_cmd(A) ::= insert_cmd(R) INTO trnm(X) idlist_opt(F) select(S).
-               {A = sqlite3TriggerInsertStep(pParse->db, &X, F, S, R);}
+   {A = sqlite3TriggerInsertStep(pParse->db, &X, F, S, R);/*A-overwrites-R*/}
 
 // DELETE
 trigger_cmd(A) ::= DELETE FROM trnm(X) tridxby where_opt(Y).
-               {A = sqlite3TriggerDeleteStep(pParse->db, &X, Y);}
+   {A = sqlite3TriggerDeleteStep(pParse->db, &X, Y);}
 
 // SELECT
 trigger_cmd(A) ::= select(X).
-               {A = sqlite3TriggerSelectStep(pParse->db, X); /*A-overwrites-X*/}
+   {A = sqlite3TriggerSelectStep(pParse->db, X); /*A-overwrites-X*/}
 
 // The special RAISE expression that may occur in trigger programs
 expr(A) ::= RAISE(X) LP IGNORE RP(Y).  {
index 1058d14ae6354c9b0e9e76625140e6a1f07f38c4..cefdf801746a68e17366e8156438ac637f833473 100644 (file)
@@ -3477,6 +3477,7 @@ PRIVATE int translate_code(struct lemon *lemp, struct rule *rp){
   char *cp, *xp;
   int i;
   int rc = 0;            /* True if yylhsminor is used */
+  int dontUseRhs0 = 0;   /* If true, use of left-most RHS label is illegal */
   const char *zSkip = 0; /* The zOvwrt comment within rp->code, or NULL */
   char lhsused = 0;      /* True if the LHS element has been used */
   char lhsdirect;        /* True if LHS writes directly into stack */
@@ -3549,6 +3550,7 @@ PRIVATE int translate_code(struct lemon *lemp, struct rule *rp){
     if( cp==zSkip ){
       append_str(zOvwrt,0,0,0);
       cp += lemonStrlen(zOvwrt)-1;
+      dontUseRhs0 = 1;
       continue;
     }
     if( ISALPHA(*cp) && (cp==rp->code || (!ISALNUM(cp[-1]) && cp[-1]!='_')) ){
@@ -3563,7 +3565,12 @@ PRIVATE int translate_code(struct lemon *lemp, struct rule *rp){
       }else{
         for(i=0; i<rp->nrhs; i++){
           if( rp->rhsalias[i] && strcmp(cp,rp->rhsalias[i])==0 ){
-            if( cp!=rp->code && cp[-1]=='@' ){
+            if( i==0 && dontUseRhs0 ){
+              ErrorMsg(lemp->filename,rp->ruleline,
+                 "Label %s used after '%s'.",
+                 rp->rhsalias[0], zOvwrt);
+              lemp->errorcnt++;
+            }else if( cp!=rp->code && cp[-1]=='@' ){
               /* If the argument is of the form @X then substituted
               ** the token number of X, not the value of X */
               append_str("yymsp[%d].major",-1,i-rp->nrhs+1,0);
index 1d76779b5ee5e0e82c37efecbe538a5a168552f9..f7cb097c34a889bbda420686b7acb05b28591abc 100644 (file)
@@ -637,14 +637,14 @@ static void yy_reduce(
     }
 #endif
 #if YYSTACKDEPTH>0 
-    if( yypParser->yyidx>=YYSTACKDEPTH ){
+    if( yypParser->yyidx>=YYSTACKDEPTH-1 ){
       yyStackOverflow(yypParser);
       return;
     }
 #else
-    if( yypParser->yyidx>=yypParser->yystksz ){
+    if( yypParser->yyidx>=yypParser->yystksz-1 ){
       yyGrowStack(yypParser);
-      if( yypParser->yyidx>=yypParser->yystksz ){
+      if( yypParser->yyidx>=yypParser->yystksz-1 ){
         yyStackOverflow(yypParser);
         return;
       }