From: drh <> Date: Wed, 31 Mar 2021 13:31:33 +0000 (+0000) Subject: Defer deletion of expressions that are optimized out by the AND optimizer X-Git-Tag: version-3.36.0~277 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b3ad4e611854dd5f4ad26378c4cfccf9f0c858dd;p=thirdparty%2Fsqlite.git Defer deletion of expressions that are optimized out by the AND optimizer in the sqlite3ExprAnd() routine until the corresponding Parse object is deleted. This avoids a dangling pointer in AggInfo if sqlite3ExprAnd() is invoked by the push-down optimization. The dangling pointer appears to be harmless in release builds, only showing up in debug builds. Problem found by dbsqlfuzz. FossilOrigin-Name: c36b43589abd9f62a709bdb47b8748e0c1e8743487a3d83d1eb35eb06b65d763 --- diff --git a/manifest b/manifest index 345eb10e6d..1970e0d540 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Ensure\sthat\snegative\snumbers\smay\snot\sbe\sused\sin\sframe\soffset\sclauses\seven\sif\sthey\sare\sinitially\stext\svalue.\se.g.\s(RANGE\sBETWEEN\s'-1'\sPRECEDING\s...). -D 2021-03-31T11:31:19.995 +C Defer\sdeletion\sof\sexpressions\sthat\sare\soptimized\sout\sby\sthe\sAND\soptimizer\nin\sthe\ssqlite3ExprAnd()\sroutine\suntil\sthe\scorresponding\sParse\sobject\sis\ndeleted.\s\sThis\savoids\sa\sdangling\spointer\sin\sAggInfo\sif\ssqlite3ExprAnd()\nis\sinvoked\sby\sthe\spush-down\soptimization.\s\sThe\sdangling\spointer\sappears\nto\sbe\sharmless\sin\srelease\sbuilds,\sonly\sshowing\sup\sin\sdebug\sbuilds.\nProblem\sfound\sby\sdbsqlfuzz. +D 2021-03-31T13:31:33.513 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -494,7 +494,7 @@ F src/date.c e0632f335952b32401482d099321bbf12716b29d6e72836b53ae49683ebae4bf F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a F src/dbstat.c 3aa79fc3aed7ce906e4ea6c10e85d657299e304f6049861fe300053ac57de36c F src/delete.c 73f57a9a183532c344a3135cf8f2a5589376e39183e0b5f562d6b61b2af0f4d8 -F src/expr.c 1a63403c5b06f762efc74f88ba59ea1ff58c9897bc74b36561ac4e259083e61e +F src/expr.c 1bf346b7efbe37f62aab7079fdc9ee1aa13e9bea29dbb161f9e7036db9df24e2 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c e9063648396c58778f77583a678342fe4a9bc82436bf23c5f9f444f2df0fdaa4 F src/func.c 479f6929be027eb0210cbdde9d3529c012facf082d64a6b854a9415940761e5e @@ -547,7 +547,7 @@ F src/shell.c.in dcce260883836c9b58847505fbccce8d5546af925046f7dacd9443e922ece03 F src/sqlite.h.in 3426a080ea1f222a73e3bd91e7eacbd30570a0117c03d42c6dde606f33e5e318 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 61b38c073d5e1e96a3d45271b257aef27d0d13da2bea5347692ae579475cd95e -F src/sqliteInt.h 109a1489293798c2aa84b4ee3cbe311994e6ecb9f1cd15e8ec3eec92655c8f67 +F src/sqliteInt.h c5cfae5891a6e643116f66f63769bcffeba89ca51f6278732da710eb0cf092b6 F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -1337,7 +1337,7 @@ F test/securedel2.test 2d54c28e46eb1fd6902089958b20b1b056c6f1c5 F test/select1.test 3d23f66bf9ba77570acfe2ca5f1540ece17037cc64ab1a00efec9758ac29c268 F test/select2.test 352480e0e9c66eda9c3044e412abdf5be0215b56 F test/select3.test c49fbb758903f3718e2de5aa4655eda4838131cbea24a86db908f8b6889aa68c -F test/select4.test e8a2502e3623f3058871030599a48abb35789d2244d5b380ecf3696873fdd4a4 +F test/select4.test f0684d3da3bccacbe2a1ebadf6fb49d9df6f53acb4c6ebc228a88d0d6054cc7b F test/select5.test df9ec0d218cedceb4fe7b63262025b547b50a55e59148c6f40b60ca25f1d4546 F test/select6.test 319d45e414cdd321bf17cfacedaf19e3935ad64dac357c53f1492338c6e9b801 F test/select7.test f659f231489349e8c5734e610803d7654207318f @@ -1911,7 +1911,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 3039bcaff95bb5d096c80b5eefdaeda6abd1d1337e829f32fd28a968f663f481 -R 7b19f4193fff66a2a9516f68b5ccb188 -U dan -Z 82b60d1644919097b1f10e4e15aa5fcc +P 8b681b274dd01c3e0f76d5bbddcbb2450c6d9475b9cfa0db961a3ab5edf51db1 +R 1913f072c7bc3e67445edd5a42763229 +U drh +Z 097b16b038df82ff66ede32b1c1f045a diff --git a/manifest.uuid b/manifest.uuid index 2d9053d242..219a63fbbb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8b681b274dd01c3e0f76d5bbddcbb2450c6d9475b9cfa0db961a3ab5edf51db1 \ No newline at end of file +c36b43589abd9f62a709bdb47b8748e0c1e8743487a3d83d1eb35eb06b65d763 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index a780fac112..ac0f4073f1 100644 --- a/src/expr.c +++ b/src/expr.c @@ -968,8 +968,8 @@ Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){ }else if( (ExprAlwaysFalse(pLeft) || ExprAlwaysFalse(pRight)) && !IN_RENAME_OBJECT ){ - sqlite3ExprDelete(db, pLeft); - sqlite3ExprDelete(db, pRight); + sqlite3ExprDeferredDelete(pParse, pLeft); + sqlite3ExprDeferredDelete(pParse, pRight); return sqlite3Expr(db, TK_INTEGER, "0"); }else{ return sqlite3PExpr(pParse, TK_AND, pLeft, pRight); @@ -1166,6 +1166,22 @@ void sqlite3ExprDelete(sqlite3 *db, Expr *p){ if( p ) sqlite3ExprDeleteNN(db, p); } + +/* +** Arrange to cause pExpr to be deleted when the pParse is deleted. +** This is similar to sqlite3ExprDelete() except that the delete is +** deferred untilthe pParse is deleted. +** +** The pExpr might be deleted immediately on an OOM error. +** +** The deferred delete is (currently) implemented by adding the +** pExpr to the pParse->pConstExpr list with a register number of 0. +*/ +void sqlite3ExprDeferredDelete(Parse *pParse, Expr *pExpr){ + pParse->pConstExpr = + sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr); +} + /* Invoke sqlite3RenameExprUnmap() and sqlite3ExprDelete() on the ** expression. */ @@ -5821,8 +5837,7 @@ static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){ pExpr = sqlite3ExprDup(db, pExpr, 0); if( pExpr ){ pAggInfo->aCol[iAgg].pCExpr = pExpr; - pParse->pConstExpr = - sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr); + sqlite3ExprDeferredDelete(pParse, pExpr); } } }else{ @@ -5831,8 +5846,7 @@ static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){ pExpr = sqlite3ExprDup(db, pExpr, 0); if( pExpr ){ pAggInfo->aFunc[iAgg].pFExpr = pExpr; - pParse->pConstExpr = - sqlite3ExprListAppend(pParse, pParse->pConstExpr, pExpr); + sqlite3ExprDeferredDelete(pParse, pExpr); } } } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 09a692d1b5..fcc50e1576 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -4287,6 +4287,7 @@ Expr *sqlite3ExprFunction(Parse*,ExprList*, Token*, int); void sqlite3ExprFunctionUsable(Parse*,Expr*,FuncDef*); void sqlite3ExprAssignVarNumber(Parse*, Expr*, u32); void sqlite3ExprDelete(sqlite3*, Expr*); +void sqlite3ExprDeferredDelete(Parse*, Expr*); void sqlite3ExprUnmapAndDelete(Parse*, Expr*); ExprList *sqlite3ExprListAppend(Parse*,ExprList*,Expr*); ExprList *sqlite3ExprListAppendVector(Parse*,ExprList*,IdList*,Expr*); diff --git a/test/select4.test b/test/select4.test index 6dbfd4d0a1..d49708ece8 100644 --- a/test/select4.test +++ b/test/select4.test @@ -1025,5 +1025,19 @@ do_execsql_test select4-18.3 { WHERE abs(z1.aa)=z2.aa AND z1.aa=123; } {123} +# 2021-03-31 Fix an assert() problem in the logic at the end of sqlite3Select() +# that validates AggInfo. The checks to ensure that AggInfo.aCol[].pCExpr +# references a valid expression was looking at an expression that had been +# deleted by the truth optimization in sqlite3ExprAnd() which was invoked by +# the push-down optimization. This is harmless in delivery builds, as that code +# only runs with SQLITE_DEBUG. But it should still be fixed. The problem +# was discovered by dbsqlfuzz (crash-dece7b67a3552ed7e571a7bda903afd1f7bd9b21) +# +reset_db +do_execsql_test select4-19.1 { + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(99); + SELECT sum((SELECT 1 FROM (SELECT 2 WHERE x IS NULL) WHERE 0)) FROM t1; +} {{}} finish_test