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:
parent
cf82f0d3d2
commit
43303de97e
16
manifest
16
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
|
||||
|
@ -1 +1 @@
|
||||
5cfe9545d478a2c500083613dd20e14b2ffce645
|
||||
417e777701bbf4bd67626d4ca3bc2c5d847f6cd0
|
75
src/parse.y
75
src/parse.y
@ -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). {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user