aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2020-03-10 19:24:38 +0000
committerdrh <drh@noemail.net>2020-03-10 19:24:38 +0000
commite7375bfa727bfa12649897fd6a655f81b703f0db (patch)
treeceb8af56043e8a55900b807487cf3cbc0799e4cf /src
parent5cf1b611a20201aa141b258901cbfc2950e2037e (diff)
downloadsqlite-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.c28
-rw-r--r--src/expr.c52
-rw-r--r--src/parse.y1
-rw-r--r--src/sqliteInt.h34
-rw-r--r--src/treeview.c8
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, &regFree1);
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree2);
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;