blob: 63e81eacac04711c9102855d92ab1263f6e3ea3f [file] [log] [blame]
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Darwin Huang <huangdarwin@chromium.org>
Date: Wed, 17 Jul 2019 15:22:41 -0700
Subject: [PATCH 3/8] Fix ASSERT memIsValid hit
Backports https://www.sqlite.org/src/info/7ef7b23cbb1b9ace
Bug: 984699
---
third_party/sqlite/patched/src/expr.c | 75 ++++++++++---------
third_party/sqlite/patched/test/check.test | 29 +++++++
.../sqlite/patched/test/checkfault.test | 41 ++++++++++
3 files changed, 108 insertions(+), 37 deletions(-)
create mode 100644 third_party/sqlite/patched/test/checkfault.test
diff --git a/third_party/sqlite/patched/src/expr.c b/third_party/sqlite/patched/src/expr.c
index e958c88a6523..88e5baec85ef 100644
--- a/third_party/sqlite/patched/src/expr.c
+++ b/third_party/sqlite/patched/src/expr.c
@@ -1083,16 +1083,6 @@ static int exprStructSize(Expr *p){
return EXPR_FULLSIZE;
}
-/*
-** Copy the complete content of an Expr node, taking care not to read
-** past the end of the structure for a reduced-size version of the source
-** Expr.
-*/
-static void exprNodeCopy(Expr *pDest, Expr *pSrc){
- memset(pDest, 0, sizeof(Expr));
- memcpy(pDest, pSrc, exprStructSize(pSrc));
-}
-
/*
** The dupedExpr*Size() routines each return the number of bytes required
** to store a copy of an expression or expression tree. They differ in
@@ -4044,6 +4034,8 @@ expr_code_doover:
Expr opCompare; /* The X==Ei expression */
Expr *pX; /* The X expression */
Expr *pTest = 0; /* X==Ei (form A) or just Ei (form B) */
+ Expr *pDel = 0;
+ sqlite3 *db = pParse->db;
assert( !ExprHasProperty(pExpr, EP_xIsSelect) && pExpr->x.pList );
assert(pExpr->x.pList->nExpr > 0);
@@ -4052,13 +4044,17 @@ expr_code_doover:
nExpr = pEList->nExpr;
endLabel = sqlite3VdbeMakeLabel(pParse);
if( (pX = pExpr->pLeft)!=0 ){
- exprNodeCopy(&tempX, pX);
+ pDel = sqlite3ExprDup(db, pX, 0);
+ if( db->mallocFailed ){
+ sqlite3ExprDelete(db, pDel);
+ break;
+ }
testcase( pX->op==TK_COLUMN );
- exprToRegister(&tempX, exprCodeVector(pParse, &tempX, &regFree1));
+ exprToRegister(pDel, exprCodeVector(pParse, pDel, &regFree1));
testcase( regFree1==0 );
memset(&opCompare, 0, sizeof(opCompare));
opCompare.op = TK_EQ;
- opCompare.pLeft = &tempX;
+ opCompare.pLeft = pDel;
pTest = &opCompare;
/* Ticket b351d95f9cd5ef17e9d9dbae18f5ca8611190001:
** The value in regFree1 might get SCopy-ed into the file result.
@@ -4086,6 +4082,7 @@ expr_code_doover:
}else{
sqlite3VdbeAddOp2(v, OP_Null, 0, target);
}
+ sqlite3ExprDelete(db, pDel);
sqlite3VdbeResolveLabel(v, endLabel);
break;
}
@@ -4367,40 +4364,44 @@ static void exprCodeBetween(
void (*xJump)(Parse*,Expr*,int,int), /* Action to take */
int jumpIfNull /* Take the jump if the BETWEEN is NULL */
){
- Expr exprAnd; /* The AND operator in x>=y AND x<=z */
+ Expr exprAnd; /* The AND operator in x>=y AND x<=z */
Expr compLeft; /* The x>=y term */
Expr compRight; /* The x<=z term */
- Expr exprX; /* The x subexpression */
int regFree1 = 0; /* Temporary use register */
+ Expr *pDel = 0;
+ sqlite3 *db = pParse->db;
memset(&compLeft, 0, sizeof(Expr));
memset(&compRight, 0, sizeof(Expr));
memset(&exprAnd, 0, sizeof(Expr));
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
- exprNodeCopy(&exprX, pExpr->pLeft);
- exprAnd.op = TK_AND;
- exprAnd.pLeft = &compLeft;
- exprAnd.pRight = &compRight;
- compLeft.op = TK_GE;
- compLeft.pLeft = &exprX;
- compLeft.pRight = pExpr->x.pList->a[0].pExpr;
- compRight.op = TK_LE;
- compRight.pLeft = &exprX;
- compRight.pRight = pExpr->x.pList->a[1].pExpr;
- exprToRegister(&exprX, exprCodeVector(pParse, &exprX, &regFree1));
- if( xJump ){
- xJump(pParse, &exprAnd, dest, jumpIfNull);
- }else{
- /* Mark the expression is being from the ON or USING clause of a join
- ** so that the sqlite3ExprCodeTarget() routine will not attempt to move
- ** it into the Parse.pConstExpr list. We should use a new bit for this,
- ** for clarity, but we are out of bits in the Expr.flags field so we
- ** have to reuse the EP_FromJoin bit. Bummer. */
- exprX.flags |= EP_FromJoin;
- sqlite3ExprCodeTarget(pParse, &exprAnd, dest);
+ pDel = sqlite3ExprDup(db, pExpr->pLeft, 0);
+ if( db->mallocFailed==0 ){
+ exprAnd.op = TK_AND;
+ exprAnd.pLeft = &compLeft;
+ exprAnd.pRight = &compRight;
+ compLeft.op = TK_GE;
+ compLeft.pLeft = pDel;
+ compLeft.pRight = pExpr->x.pList->a[0].pExpr;
+ compRight.op = TK_LE;
+ compRight.pLeft = pDel;
+ compRight.pRight = pExpr->x.pList->a[1].pExpr;
+ exprToRegister(pDel, exprCodeVector(pParse, pDel, &regFree1));
+ if( xJump ){
+ xJump(pParse, &exprAnd, dest, jumpIfNull);
+ }else{
+ /* Mark the expression is being from the ON or USING clause of a join
+ ** so that the sqlite3ExprCodeTarget() routine will not attempt to move
+ ** it into the Parse.pConstExpr list. We should use a new bit for this,
+ ** for clarity, but we are out of bits in the Expr.flags field so we
+ ** have to reuse the EP_FromJoin bit. Bummer. */
+ pDel->flags |= EP_FromJoin;
+ sqlite3ExprCodeTarget(pParse, &exprAnd, dest);
+ }
+ sqlite3ReleaseTempReg(pParse, regFree1);
}
- sqlite3ReleaseTempReg(pParse, regFree1);
+ sqlite3ExprDelete(db, pDel);
/* Ensure adequate test coverage */
testcase( xJump==sqlite3ExprIfTrue && jumpIfNull==0 && regFree1==0 );
diff --git a/third_party/sqlite/patched/test/check.test b/third_party/sqlite/patched/test/check.test
index 4042b6d96ed8..a0ab615fa76e 100644
--- a/third_party/sqlite/patched/test/check.test
+++ b/third_party/sqlite/patched/test/check.test
@@ -495,4 +495,33 @@ do_execsql_test 10.1 {
PRAGMA integrity_check;
} {ok}
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 11.0 {
+ CREATE TABLE t1 (Col0 CHECK(1 COLLATE BINARY BETWEEN 1 AND 1) ) ;
+}
+do_execsql_test 11.1 {
+ INSERT INTO t1 VALUES (NULL);
+}
+do_execsql_test 11.2 {
+ INSERT INTO t1 VALUES (NULL);
+}
+
+do_execsql_test 11.3 {
+ CREATE TABLE t2(b, a CHECK(
+ CASE 'abc' COLLATE nocase WHEN a THEN 1 ELSE 0 END)
+ );
+}
+do_execsql_test 11.4 {
+ INSERT INTO t2(a) VALUES('abc');
+}
+do_execsql_test 11.5 {
+ INSERT INTO t2(b, a) VALUES(1, 'abc'||'');
+}
+do_execsql_test 11.6 {
+ INSERT INTO t2(b, a) VALUES(2, 'abc');
+}
+
+finish_test
+
finish_test
diff --git a/third_party/sqlite/patched/test/checkfault.test b/third_party/sqlite/patched/test/checkfault.test
new file mode 100644
index 000000000000..126e68751b28
--- /dev/null
+++ b/third_party/sqlite/patched/test/checkfault.test
@@ -0,0 +1,41 @@
+# 2019 July 17
+#
+# The author disclaims copyright to this source code. In place of
+# a legal notice, here is a blessing:
+#
+# May you do good and not evil.
+# May you find forgiveness for yourself and forgive others.
+# May you share freely, never taking more than you give.
+#
+#***********************************************************************
+#
+# This file contains fault-injection test cases for the
+# sqlite3_db_cacheflush API.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix cffault
+source $testdir/malloc_common.tcl
+
+do_execsql_test 1.0 {
+ CREATE TABLE t1 (Col0 CHECK(1 COLLATE BINARY BETWEEN 1 AND 1) ) ;
+ CREATE TABLE t2(b, a CHECK(
+ CASE 'abc' COLLATE nocase WHEN a THEN 1 ELSE 0 END)
+ );
+}
+
+do_faultsim_test 1.1 -faults oom* -body {
+ execsql { INSERT INTO t1 VALUES ('ABCDEFG') }
+} -test {
+ faultsim_test_result {0 {}}
+}
+
+do_faultsim_test 1.2 -faults oom* -body {
+ execsql { INSERT INTO t2(a) VALUES('abc') }
+} -test {
+ faultsim_test_result {0 {}}
+}
+
+
+finish_test
\ No newline at end of file
--
2.20.1 (Apple Git-117)