Index: src/delete.c ================================================================== --- src/delete.c +++ src/delete.c @@ -796,12 +796,12 @@ if( piPartIdxLabel ){ if( pIdx->pPartIdxWhere ){ *piPartIdxLabel = sqlite3VdbeMakeLabel(v); pParse->iPartIdxTab = iDataCur; sqlite3ExprCachePush(pParse); - sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, - SQLITE_JUMPIFNULL); + sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, + SQLITE_JUMPIFNULL); }else{ *piPartIdxLabel = 0; } } nCol = (prefixOnly && pIdx->uniqNotNull) ? pIdx->nKeyCol : pIdx->nColumn; Index: src/expr.c ================================================================== --- src/expr.c +++ src/expr.c @@ -3699,10 +3699,25 @@ } } sqlite3ReleaseTempReg(pParse, regFree1); sqlite3ReleaseTempReg(pParse, regFree2); } + +/* +** Like sqlite3ExprIfFalse() except that a copy is made of pExpr before +** code generation, and that copy is deleted after code generation. This +** ensures that the original pExpr is unchanged. +*/ +void sqlite3ExprIfFalseDup(Parse *pParse, Expr *pExpr, int dest,int jumpIfNull){ + sqlite3 *db = pParse->db; + Expr *pCopy = sqlite3ExprDup(db, pExpr, 0); + if( db->mallocFailed==0 ){ + sqlite3ExprIfFalse(pParse, pCopy, dest, jumpIfNull); + } + sqlite3ExprDelete(db, pCopy); +} + /* ** Do a deep comparison of two expression trees. Return 0 if the two ** expressions are completely identical. Return 1 if they differ only ** by a COLLATE operator at the top level. Return 2 if there are differences Index: src/insert.c ================================================================== --- src/insert.c +++ src/insert.c @@ -1379,12 +1379,12 @@ /* Skip partial indices for which the WHERE clause is not true */ if( pIdx->pPartIdxWhere ){ sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[ix]); pParse->ckBase = regNewData+1; - sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, addrUniqueOk, - SQLITE_JUMPIFNULL); + sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, addrUniqueOk, + SQLITE_JUMPIFNULL); pParse->ckBase = 0; } /* Create a record for this index entry as it should appear after ** the insert or update. Store that record in the aRegIdx[ix] register Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -3324,10 +3324,11 @@ int sqlite3ExprCodeExprList(Parse*, ExprList*, int, u8); #define SQLITE_ECEL_DUP 0x01 /* Deep, not shallow copies */ #define SQLITE_ECEL_FACTOR 0x02 /* Factor out constant terms */ void sqlite3ExprIfTrue(Parse*, Expr*, int, int); void sqlite3ExprIfFalse(Parse*, Expr*, int, int); +void sqlite3ExprIfFalseDup(Parse*, Expr*, int, int); Table *sqlite3FindTable(sqlite3*,const char*, const char*); Table *sqlite3LocateTable(Parse*,int isView,const char*, const char*); Table *sqlite3LocateTableItem(Parse*,int isView,struct SrcList_item *); Index *sqlite3FindIndex(sqlite3*,const char*, const char*); void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*); Index: test/index6.test ================================================================== --- test/index6.test +++ test/index6.test @@ -324,7 +324,26 @@ } { 1 one value 1 2 two {} {} 3 three value 3 } + +# 2015-06-11. Assertion fault found by AFL +# +do_execsql_test index6-9.1 { + CREATE TABLE t9(a int, b int, c int); + CREATE INDEX t9ca ON t9(c,a) WHERE a in (10,12,20); + INSERT INTO t9 VALUES(1,1,9),(10,2,35),(11,15,82),(20,19,5),(NULL,7,3); + UPDATE t9 SET b=c WHERE a in (10,12,20); + SELECT a,b,c,'|' FROM t9 ORDER BY a; +} {{} 7 3 | 1 1 9 | 10 35 35 | 11 15 82 | 20 5 5 |} +do_execsql_test index6-9.2 { + DROP TABLE t9; + CREATE TABLE t9(a int, b int, c int, PRIMARY KEY(a)) WITHOUT ROWID; + CREATE INDEX t9ca ON t9(c,a) WHERE a in (10,12,20); + INSERT INTO t9 VALUES(1,1,9),(10,2,35),(11,15,82),(20,19,5); + UPDATE t9 SET b=c WHERE a in (10,12,20); + SELECT a,b,c,'|' FROM t9 ORDER BY a; +} {1 1 9 | 10 35 35 | 11 15 82 | 20 5 5 |} + finish_test