diff options
author | drh <drh@noemail.net> | 2020-03-10 19:24:38 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2020-03-10 19:24:38 +0000 |
commit | e7375bfa727bfa12649897fd6a655f81b703f0db (patch) | |
tree | ceb8af56043e8a55900b807487cf3cbc0799e4cf /src | |
parent | 5cf1b611a20201aa141b258901cbfc2950e2037e (diff) | |
download | sqlite-e7375bfa727bfa12649897fd6a655f81b703f0db.tar.gz sqlite-e7375bfa727bfa12649897fd6a655f81b703f0db.zip |
Enhanced detection logic for preventing the use of static schema expressions
by code generating routines.
FossilOrigin-Name: 5f60b527b938c0778e8f725c635ce0dc5ed7a4e01fd6252aa2cdb64da2f625bc
Diffstat (limited to 'src')
-rw-r--r-- | src/build.c | 28 | ||||
-rw-r--r-- | src/expr.c | 52 | ||||
-rw-r--r-- | src/parse.y | 1 | ||||
-rw-r--r-- | src/sqliteInt.h | 34 | ||||
-rw-r--r-- | src/treeview.c | 8 |
5 files changed, 91 insertions, 32 deletions
diff --git a/src/build.c b/src/build.c index a7dc36ff5..73e4cea7c 100644 --- a/src/build.c +++ b/src/build.c @@ -2157,6 +2157,32 @@ int sqlite3ShadowTableName(sqlite3 *db, const char *zName){ } #endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */ +#ifdef SQLITE_DEBUG +/* +** Mark all nodes of an expression as EP_Immutable, indicating that +** they should not be changed. Expressions attached to a table or +** index definition are tagged this way to help ensure that we do +** not pass them into code generator routines by mistake. +*/ +static int markImmutableExprStep(Walker *pWalker, Expr *pExpr){ + ExprSetVVAProperty(pExpr, EP_Immutable); + return WRC_Continue; +} +static void markExprListImmutable(ExprList *pList){ + if( pList ){ + Walker w; + memset(&w, 0, sizeof(w)); + w.xExprCallback = markImmutableExprStep; + w.xSelectCallback = sqlite3SelectWalkNoop; + w.xSelectCallback2 = 0; + sqlite3WalkExprList(&w, pList); + } +} +#else +#define markExprListImmutable(X) /* no-op */ +#endif /* SQLITE_DEBUG */ + + /* ** This routine is called to report the final ")" that terminates ** a CREATE TABLE statement. @@ -2249,6 +2275,8 @@ void sqlite3EndTable( ** actually be used if PRAGMA writable_schema=ON is set. */ sqlite3ExprListDelete(db, p->pCheck); p->pCheck = 0; + }else{ + markExprListImmutable(p->pCheck); } } #endif /* !defined(SQLITE_OMIT_CHECK) */ diff --git a/src/expr.c b/src/expr.c index 6bbefc12f..03d58df32 100644 --- a/src/expr.c +++ b/src/expr.c @@ -42,7 +42,7 @@ char sqlite3TableColumnAffinity(Table *pTab, int iCol){ ** SELECT a AS b FROM t1 WHERE b; ** SELECT * FROM t1 WHERE (select a from t1); */ -char sqlite3ExprAffinity(Expr *pExpr){ +char sqlite3ExprAffinity(const Expr *pExpr){ int op; while( ExprHasProperty(pExpr, EP_Skip) ){ assert( pExpr->op==TK_COLLATE ); @@ -152,10 +152,10 @@ Expr *sqlite3ExprSkipCollateAndLikely(Expr *pExpr){ ** COLLATE operators take first precedence. Left operands take ** precedence over right operands. */ -CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){ +CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){ sqlite3 *db = pParse->db; CollSeq *pColl = 0; - Expr *p = pExpr; + const Expr *p = pExpr; while( p ){ int op = p->op; if( op==TK_REGISTER ) op = p->op2; @@ -224,7 +224,7 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr){ ** The sqlite3ExprCollSeq() routine works the same except that it ** returns NULL if there is no defined collation. */ -CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, Expr *pExpr){ +CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, const Expr *pExpr){ CollSeq *p = sqlite3ExprCollSeq(pParse, pExpr); if( p==0 ) p = pParse->db->pDfltColl; assert( p!=0 ); @@ -234,7 +234,7 @@ CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, Expr *pExpr){ /* ** Return TRUE if the two expressions have equivalent collating sequences. */ -int sqlite3ExprCollSeqMatch(Parse *pParse, Expr *pE1, Expr *pE2){ +int sqlite3ExprCollSeqMatch(Parse *pParse, const Expr *pE1, const Expr *pE2){ CollSeq *pColl1 = sqlite3ExprNNCollSeq(pParse, pE1); CollSeq *pColl2 = sqlite3ExprNNCollSeq(pParse, pE2); return sqlite3StrICmp(pColl1->zName, pColl2->zName)==0; @@ -245,7 +245,7 @@ int sqlite3ExprCollSeqMatch(Parse *pParse, Expr *pE1, Expr *pE2){ ** type affinity of the other operand. This routine returns the ** type affinity that should be used for the comparison operator. */ -char sqlite3CompareAffinity(Expr *pExpr, char aff2){ +char sqlite3CompareAffinity(const Expr *pExpr, char aff2){ char aff1 = sqlite3ExprAffinity(pExpr); if( aff1>SQLITE_AFF_NONE && aff2>SQLITE_AFF_NONE ){ /* Both sides of the comparison are columns. If one has numeric @@ -267,7 +267,7 @@ char sqlite3CompareAffinity(Expr *pExpr, char aff2){ ** pExpr is a comparison operator. Return the type affinity that should ** be applied to both operands prior to doing the comparison. */ -static char comparisonAffinity(Expr *pExpr){ +static char comparisonAffinity(const Expr *pExpr){ char aff; assert( pExpr->op==TK_EQ || pExpr->op==TK_IN || pExpr->op==TK_LT || pExpr->op==TK_GT || pExpr->op==TK_GE || pExpr->op==TK_LE || @@ -290,7 +290,7 @@ static char comparisonAffinity(Expr *pExpr){ ** if the index with affinity idx_affinity may be used to implement ** the comparison in pExpr. */ -int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity){ +int sqlite3IndexAffinityOk(const Expr *pExpr, char idx_affinity){ char aff = comparisonAffinity(pExpr); if( aff<SQLITE_AFF_TEXT ){ return 1; @@ -305,7 +305,11 @@ int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity){ ** Return the P5 value that should be used for a binary comparison ** opcode (OP_Eq, OP_Ge etc.) used to compare pExpr1 and pExpr2. */ -static u8 binaryCompareP5(Expr *pExpr1, Expr *pExpr2, int jumpIfNull){ +static u8 binaryCompareP5( + const Expr *pExpr1, /* Left operand */ + const Expr *pExpr2, /* Right operand */ + int jumpIfNull /* Extra flags added to P5 */ +){ u8 aff = (char)sqlite3ExprAffinity(pExpr2); aff = (u8)sqlite3CompareAffinity(pExpr1, aff) | (u8)jumpIfNull; return aff; @@ -325,8 +329,8 @@ static u8 binaryCompareP5(Expr *pExpr1, Expr *pExpr2, int jumpIfNull){ */ CollSeq *sqlite3BinaryCompareCollSeq( Parse *pParse, - Expr *pLeft, - Expr *pRight + const Expr *pLeft, + const Expr *pRight ){ CollSeq *pColl; assert( pLeft ); @@ -351,7 +355,7 @@ CollSeq *sqlite3BinaryCompareCollSeq( ** is reversed in the sqlite3BinaryCompareCollSeq() call so that the ** correct collating sequence is found. */ -CollSeq *sqlite3ExprCompareCollSeq(Parse *pParse, Expr *p){ +CollSeq *sqlite3ExprCompareCollSeq(Parse *pParse, const Expr *p){ if( ExprHasProperty(p, EP_Commuted) ){ return sqlite3BinaryCompareCollSeq(pParse, p->pRight, p->pLeft); }else{ @@ -594,6 +598,7 @@ static void codeVectorCompare( int addrDone = sqlite3VdbeMakeLabel(pParse); int isCommuted = ExprHasProperty(pExpr,EP_Commuted); + assert( !ExprHasVVAProperty(pExpr,EP_Immutable) ); if( pParse->nErr ) return; if( nLeft!=sqlite3ExprVectorSize(pRight) ){ sqlite3ErrorMsg(pParse, "row value misused"); @@ -1206,7 +1211,7 @@ static int dupedExprStructSize(Expr *p, int flags){ assert( !ExprHasProperty(p, EP_TokenOnly|EP_Reduced) ); assert( !ExprHasProperty(p, EP_FromJoin) ); assert( !ExprHasProperty(p, EP_MemToken) ); - assert( !ExprHasProperty(p, EP_NoReduce) ); + assert( !ExprHasVVAProperty(p, EP_NoReduce) ); if( p->pLeft || p->x.pList ){ nSize = EXPR_REDUCEDSIZE | EP_Reduced; }else{ @@ -1311,6 +1316,10 @@ static Expr *exprDup(sqlite3 *db, Expr *p, int dupFlags, u8 **pzBuffer){ pNew->flags &= ~(EP_Reduced|EP_TokenOnly|EP_Static|EP_MemToken); pNew->flags |= nStructSize & (EP_Reduced|EP_TokenOnly); pNew->flags |= staticFlag; + ExprClearVVAProperties(pNew); + if( dupFlags ){ + ExprSetVVAProperty(pNew, EP_Immutable); + } /* Copy the p->u.zToken string, if any. */ if( nToken ){ @@ -3171,6 +3180,7 @@ static void sqlite3ExprCodeIN( int addrTop; /* Top of the step-6 loop */ int iTab = 0; /* Index to use */ + assert( !ExprHasVVAProperty(pExpr,EP_Immutable) ); pLeft = pExpr->pLeft; if( sqlite3ExprCheckIN(pParse, pExpr) ) return; zAff = exprINAffinity(pParse, pExpr); @@ -3781,6 +3791,7 @@ expr_code_doover: if( pExpr==0 ){ op = TK_NULL; }else{ + assert( !ExprHasVVAProperty(pExpr,EP_Immutable) ); op = pExpr->op; } switch( op ){ @@ -4039,6 +4050,7 @@ expr_code_doover: tempX.op = TK_INTEGER; tempX.flags = EP_IntValue|EP_TokenOnly; tempX.u.iValue = 0; + ExprClearVVAProperties(&tempX); r1 = sqlite3ExprCodeTemp(pParse, &tempX, ®Free1); r2 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, ®Free2); sqlite3VdbeAddOp3(v, OP_Subtract, r2, r1, target); @@ -4115,11 +4127,8 @@ expr_code_doover: return sqlite3ExprCodeAtInit(pParse, pExpr, -1); } assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); - if( ExprHasProperty(pExpr, EP_TokenOnly) ){ - pFarg = 0; - }else{ - pFarg = pExpr->x.pList; - } + assert( !ExprHasProperty(pExpr, EP_TokenOnly) ); + pFarg = pExpr->x.pList; nFarg = pFarg ? pFarg->nExpr : 0; assert( !ExprHasProperty(pExpr, EP_IntValue) ); zId = pExpr->u.zToken; @@ -4573,6 +4582,7 @@ int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){ void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){ int inReg; + assert( pExpr==0 || !ExprHasVVAProperty(pExpr,EP_Immutable) ); assert( target>0 && target<=pParse->nMem ); inReg = sqlite3ExprCodeTarget(pParse, pExpr, target); assert( pParse->pVdbe!=0 || pParse->db->mallocFailed ); @@ -4790,6 +4800,7 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 ); if( NEVER(v==0) ) return; /* Existence of VDBE checked by caller */ if( NEVER(pExpr==0) ) return; /* No way this can happen */ + assert( !ExprHasVVAProperty(pExpr, EP_Immutable) ); op = pExpr->op; switch( op ){ case TK_AND: @@ -4931,6 +4942,7 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ assert( jumpIfNull==SQLITE_JUMPIFNULL || jumpIfNull==0 ); if( NEVER(v==0) ) return; /* Existence of VDBE checked by caller */ if( pExpr==0 ) return; + assert( !ExprHasVVAProperty(pExpr,EP_Immutable) ); /* The value of pExpr->op and op are related as follows: ** @@ -5214,7 +5226,7 @@ int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){ } if( (pA->flags & (EP_Distinct|EP_Commuted)) != (pB->flags & (EP_Distinct|EP_Commuted)) ) return 2; - if( (combinedFlags & EP_TokenOnly)==0 ){ + if( ALWAYS((combinedFlags & EP_TokenOnly)==0) ){ if( combinedFlags & EP_xIsSelect ) return 2; if( (combinedFlags & EP_FixedCol)==0 && sqlite3ExprCompare(pParse, pA->pLeft, pB->pLeft, iTab) ) return 2; @@ -5222,7 +5234,7 @@ int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){ if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2; if( pA->op!=TK_STRING && pA->op!=TK_TRUEFALSE - && (combinedFlags & EP_Reduced)==0 + && ALWAYS((combinedFlags & EP_Reduced)==0) ){ if( pA->iColumn!=pB->iColumn ) return 2; if( pA->op2!=pB->op2 ){ diff --git a/src/parse.y b/src/parse.y index c783c6969..c321daf19 100644 --- a/src/parse.y +++ b/src/parse.y @@ -965,6 +965,7 @@ idlist(A) ::= nm(Y). p->op = (u8)op; p->affExpr = 0; p->flags = EP_Leaf; + ExprClearVVAProperties(p); p->iAgg = -1; p->pLeft = p->pRight = 0; p->x.pList = 0; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index c338dabca..a5cf8d141 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2594,6 +2594,9 @@ struct Expr { ** TK_COLUMN: the value of p5 for OP_Column ** TK_AGG_FUNCTION: nesting depth ** TK_FUNCTION: NC_SelfRef flag if needs OP_PureFunc */ +#ifdef SQLITE_DEBUG + u8 vvaFlags; /* Verification flags. */ +#endif u32 flags; /* Various flags. EP_* See below */ union { char *zToken; /* Token value. Zero terminated and dequoted */ @@ -2668,7 +2671,7 @@ struct Expr { #define EP_TokenOnly 0x004000 /* Expr struct EXPR_TOKENONLYSIZE bytes only */ #define EP_Win 0x008000 /* Contains window functions */ #define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */ -#define EP_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */ + /* 0x020000 // available for reuse */ #define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */ #define EP_ConstFunc 0x080000 /* A SQLITE_FUNC_CONSTANT or _SLOCHNG function */ #define EP_CanBeNull 0x100000 /* Can be null despite NOT NULL constraint */ @@ -2682,6 +2685,7 @@ struct Expr { #define EP_IsTrue 0x10000000 /* Always has boolean value of TRUE */ #define EP_IsFalse 0x20000000 /* Always has boolean value of FALSE */ #define EP_FromDDL 0x40000000 /* Originates from sqlite_master */ + /* 0x80000000 // Available */ /* ** The EP_Propagate mask is a set of properties that automatically propagate @@ -2700,14 +2704,24 @@ struct Expr { #define ExprAlwaysTrue(E) (((E)->flags&(EP_FromJoin|EP_IsTrue))==EP_IsTrue) #define ExprAlwaysFalse(E) (((E)->flags&(EP_FromJoin|EP_IsFalse))==EP_IsFalse) + +/* Flags for use with Expr.vvaFlags +*/ +#define EP_NoReduce 0x01 /* Cannot EXPRDUP_REDUCE this Expr */ +#define EP_Immutable 0x02 /* Do not change this Expr node */ + /* The ExprSetVVAProperty() macro is used for Verification, Validation, ** and Accreditation only. It works like ExprSetProperty() during VVA ** processes but is a no-op for delivery. */ #ifdef SQLITE_DEBUG -# define ExprSetVVAProperty(E,P) (E)->flags|=(P) +# define ExprSetVVAProperty(E,P) (E)->vvaFlags|=(P) +# define ExprHasVVAProperty(E,P) (((E)->vvaFlags&(P))!=0) +# define ExprClearVVAProperties(E) (E)->vvaFlags = 0 #else # define ExprSetVVAProperty(E,P) +# define ExprHasVVAProperty(E,P) 0 +# define ExprClearVVAProperties(E) #endif /* @@ -4439,10 +4453,10 @@ int sqlite3VarintLen(u64 v); const char *sqlite3IndexAffinityStr(sqlite3*, Index*); void sqlite3TableAffinity(Vdbe*, Table*, int); -char sqlite3CompareAffinity(Expr *pExpr, char aff2); -int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity); +char sqlite3CompareAffinity(const Expr *pExpr, char aff2); +int sqlite3IndexAffinityOk(const Expr *pExpr, char idx_affinity); char sqlite3TableColumnAffinity(Table*,int); -char sqlite3ExprAffinity(Expr *pExpr); +char sqlite3ExprAffinity(const Expr *pExpr); int sqlite3Atoi64(const char*, i64*, int, u8); int sqlite3DecOrHexToI64(const char*, i64*); void sqlite3ErrorWithMsg(sqlite3*, int, const char*,...); @@ -4466,9 +4480,9 @@ CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int); int sqlite3IsBinary(const CollSeq*); CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName); void sqlite3SetTextEncoding(sqlite3 *db, u8); -CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr); -CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, Expr *pExpr); -int sqlite3ExprCollSeqMatch(Parse*,Expr*,Expr*); +CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr); +CollSeq *sqlite3ExprNNCollSeq(Parse *pParse, const Expr *pExpr); +int sqlite3ExprCollSeqMatch(Parse*,const Expr*,const Expr*); Expr *sqlite3ExprAddCollateToken(Parse *pParse, Expr*, const Token*, int); Expr *sqlite3ExprAddCollateString(Parse*,Expr*,const char*); Expr *sqlite3ExprSkipCollate(Expr*); @@ -4699,8 +4713,8 @@ char *sqlite3Normalize(Vdbe*, const char*); #endif int sqlite3Reprepare(Vdbe*); void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*); -CollSeq *sqlite3ExprCompareCollSeq(Parse*,Expr*); -CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *); +CollSeq *sqlite3ExprCompareCollSeq(Parse*,const Expr*); +CollSeq *sqlite3BinaryCompareCollSeq(Parse *, const Expr*, const Expr*); int sqlite3TempInMemory(const sqlite3*); const char *sqlite3JournalModename(int); #ifndef SQLITE_OMIT_WAL diff --git a/src/treeview.c b/src/treeview.c index 90a1d2dcc..2d9da5507 100644 --- a/src/treeview.c +++ b/src/treeview.c @@ -398,14 +398,14 @@ void sqlite3TreeViewWinFunc(TreeView *pView, const Window *pWin, u8 more){ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ const char *zBinOp = 0; /* Binary operator */ const char *zUniOp = 0; /* Unary operator */ - char zFlgs[60]; + char zFlgs[200]; pView = sqlite3TreeViewPush(pView, moreToFollow); if( pExpr==0 ){ sqlite3TreeViewLine(pView, "nil"); sqlite3TreeViewPop(pView); return; } - if( pExpr->flags || pExpr->affExpr ){ + if( pExpr->flags || pExpr->affExpr || pExpr->vvaFlags ){ StrAccum x; sqlite3StrAccumInit(&x, 0, zFlgs, sizeof(zFlgs), 0); sqlite3_str_appendf(&x, " fg.af=%x.%c", @@ -416,6 +416,9 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ if( ExprHasProperty(pExpr, EP_FromDDL) ){ sqlite3_str_appendf(&x, " DDL"); } + if( ExprHasVVAProperty(pExpr, EP_Immutable) ){ + sqlite3_str_appendf(&x, " IMMUTABLE"); + } sqlite3StrAccumFinish(&x); }else{ zFlgs[0] = 0; @@ -522,6 +525,7 @@ void sqlite3TreeViewExpr(TreeView *pView, const Expr *pExpr, u8 moreToFollow){ case TK_RSHIFT: zBinOp = "RSHIFT"; break; case TK_CONCAT: zBinOp = "CONCAT"; break; case TK_DOT: zBinOp = "DOT"; break; + case TK_LIMIT: zBinOp = "LIMIT"; break; case TK_UMINUS: zUniOp = "UMINUS"; break; case TK_UPLUS: zUniOp = "UPLUS"; break; |