More agressive use of /*A-overwrites-X*/ in the parser. Fix an off-by-one

error in parser stack overflow detection.

FossilOrigin-Name: 417e777701bbf4bd67626d4ca3bc2c5d847f6cd0
This commit is contained in:
drh 2016-02-17 12:34:03 +00:00
parent cf82f0d3d2
commit 43303de97e
5 changed files with 60 additions and 48 deletions

View File

@ -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

View File

@ -1 +1 @@
5cfe9545d478a2c500083613dd20e14b2ffce645
417e777701bbf4bd67626d4ca3bc2c5d847f6cd0

View 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,11 +1420,11 @@ 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).

View 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);

View 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;
}