From: drh Date: Mon, 23 Dec 2019 02:18:49 +0000 (+0000) Subject: Enhance the sqlite3VdbeMemAboutToChange() shallow-copy validation mechanism X-Git-Tag: version-3.31.0~173 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=13d795026705020e58603a4005c99ad0fbfb73b2;p=thirdparty%2Fsqlite.git Enhance the sqlite3VdbeMemAboutToChange() shallow-copy validation mechanism by adding the new OP_ReleaseReg opcode to tell MemAboutToChange() that a range of registers is no longer needed so that the source register can be freely changed. This is a change to debugging and test builds only and does not impact release builds. Fix for ticket [c62c5e58524b204d] and [5ad2aa6921faa1ee]. The previous fix to ticket [5ad2aa6921faa1ee] is backed out by this change since this change is a better fix. FossilOrigin-Name: 36fdeb4f0a66970a35de688b617f90899c89cfdfab659f864df99aa7ebf854ea --- diff --git a/manifest b/manifest index d6d5fbd324..7b3bdf63e7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Change\sthe\scode\sgenerator\sfor\sthe\sIN\soperator\sso\sthat\sit\savoids\screating\nOP_Eq\sand\sOP_Ne\sopcode\swith\sthe\ssame\sP1\sand\sP3\sarguments.\s\sThis\senables\sus\nto\sback\sout\scheck-in\s[ddb17d92df194337]\sand\salso\sfix\sticket\s[188f912b51cd802]. -D 2019-12-22T23:48:36.594 +C Enhance\sthe\ssqlite3VdbeMemAboutToChange()\sshallow-copy\svalidation\smechanism\nby\sadding\sthe\snew\sOP_ReleaseReg\sopcode\sto\stell\sMemAboutToChange()\sthat\sa\nrange\sof\sregisters\sis\sno\slonger\sneeded\sso\sthat\sthe\ssource\sregister\scan\sbe\nfreely\schanged.\s\sThis\sis\sa\schange\sto\sdebugging\sand\stest\sbuilds\sonly\sand\ndoes\snot\simpact\srelease\sbuilds.\s\sFix\sfor\sticket\n[c62c5e58524b204d]\sand\s[5ad2aa6921faa1ee].\s\sThe\sprevious\sfix\sto\sticket\n[5ad2aa6921faa1ee]\sis\sbacked\sout\sby\sthis\schange\ssince\sthis\schange\sis\sa\sbetter\nfix. +D 2019-12-23T02:18:49.115 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -479,7 +479,7 @@ F src/date.c e1d8ac7102f3f283e63e13867acb0efa33861cf34f0faf4cdbaf9fa7a1eb7041 F src/dbpage.c 135eb3b5e74f9ef74bde5cec2571192c90c86984fa534c88bf4a055076fa19b7 F src/dbstat.c 6c407e549406c10fde9ac3987f6d734459205239ad370369bc5fcd683084a4fa F src/delete.c a5c59b9c0251cf7682bc52af0d64f09b1aefc6781a63592c8f1136f7b73c66e4 -F src/expr.c 210669714d4f9420b97d2577581ebad7a2da6e87b37b44f62ac67f44a41ca4ab +F src/expr.c 0f38befff4c3794ec051eee3e8a555f73559aab1aa506dd0abc63949358c9ebc F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 92a248ec0fa4ed8ab60c98d9b188ce173aaf218f32e7737ba77deb2a684f9847 F src/func.c ed33e38cd642058182a31a3f518f2e34f4bbe53aa483335705c153c4d3e50b12 @@ -599,11 +599,11 @@ F src/upsert.c b445315c8958d8f17ec3297d06842e61dacaad0633ccaec1e4e160de7e562212 F src/utf.c 2f0fac345c7660d5c5bd3df9e9d8d33d4c27f366bcfb09e07443064d751a0507 F src/util.c 2c92bc706bbdb1c45a25180291e7e05a56e297aa5dd7b2bcd2b1c47e8bb05b17 F src/vacuum.c 82dcec9e7b1afa980288718ad11bc499651c722d7b9f32933c4d694d91cb6ebf -F src/vdbe.c c1e35ead7ef20b5cfedd30c45b9b7eceb7fa88145bf46c11c528775318e78950 -F src/vdbe.h fdbc0a11e5768a702b46ce63286f60e22e71351a29bd98b3666405e1fccc7802 +F src/vdbe.c 979cb8e16e4aebd9f1838260902225c68e706f6ab92781fc119937907140cb89 +F src/vdbe.h 3f068f00b23aebf392df142312ab5874588371c6d83e60d953f6d6b6453491c5 F src/vdbeInt.h bd589b8b7273286858950717e0e1ec5c88b18af45079a3366dc1371865cea704 F src/vdbeapi.c 1252d80c548711e47a6d84dae88ed4e95d3fbb4e7bd0eaa1347299af7efddf02 -F src/vdbeaux.c 858bb43a9d98846cc23fa8c8d0970ada805dd75bc6a01b69e972da608f7f59b1 +F src/vdbeaux.c e041d20b5000abbd651f7d470c66eaa13e868f58a13c1a940b4d426c6d0d43b5 F src/vdbeblob.c 253ed82894924c362a7fa3079551d3554cd1cdace39aa833da77d3bc67e7c1b1 F src/vdbemem.c 2eb00a4d1a7d2c97510a4d1ccaf4e12c9143f2ced1c6b96b5eddc372183c9121 F src/vdbesort.c a3be032cc3fee0e3af31773af4a7a6f931b7230a34f53282ccf1d9a2a72343be @@ -1604,7 +1604,7 @@ F test/unique.test 93f8b2ef5ea51b9495f8d6493429b1fd0f465264 F test/unique2.test 3674e9f2a3f1fbbfd4772ac74b7a97090d0f77d2 F test/unixexcl.test d936ba2b06794018e136418addd59a2354eeae97 F test/unordered.test ffeea7747d5ba962a8009a20b7e53d68cbae05b063604c68702c5998eb50c981 -F test/update.test 127fc037887808a9ff2d6a7dd9e524c215c939d15f8878dd3ee0169ad50f7b19 +F test/update.test 6fdd76fdf3194fb10ee184b3b2999c61d10d2a0b825dbcaa2d08ff394f3e26e3 F test/update2.test 67455bc61fcbcf96923c45b3bc4f87bc72be7d67575ad35f134906148c7b06d3 F test/upsert1.test 0b740c8488fd2f5a06ac317c9913f7ef1eda8282f2db58b544b89480c51efab3 F test/upsert2.test 9c3cdbb1a890227f6504ce4b0e3de68f4cdfa16bb21d8641208a9239896c5a09 @@ -1852,7 +1852,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 89a9dad6330270a4c3b962f86a208088d2ea9883c7d291351a77f058e0ed8b0c -R 22f0b35f3db7fedb6dbdf818d6863c3f +P 9ab985a9c8160b905730678f40ed440a246cdec549c798bafefaed5abbc0437f +R 6c6b2e22daef2e006951b2518e920f13 U drh -Z ccb160bfdbbe5ddc520bc949ac9c71d3 +Z 39eb7f22f14aaa3d3fa5e8c0432689d5 diff --git a/manifest.uuid b/manifest.uuid index 219c11bcc4..0ac42976c8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9ab985a9c8160b905730678f40ed440a246cdec549c798bafefaed5abbc0437f \ No newline at end of file +36fdeb4f0a66970a35de688b617f90899c89cfdfab659f864df99aa7ebf854ea \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 8f7c798cc3..4593ebbc57 100644 --- a/src/expr.c +++ b/src/expr.c @@ -3680,7 +3680,7 @@ expr_code_doover: }else #endif /* SQLITE_OMIT_GENERATED_COLUMNS */ if( pCol->affinity==SQLITE_AFF_REAL ){ - sqlite3VdbeAddOp2(v, OP_Copy, iSrc, target); + sqlite3VdbeAddOp2(v, OP_SCopy, iSrc, target); sqlite3VdbeAddOp1(v, OP_RealAffinity, target); return target; }else{ @@ -4065,8 +4065,12 @@ expr_code_doover: sqlite3VdbeAddFunctionCall(pParse, constMask, r1, target, nFarg, pDef, pExpr->op2); } - if( nFarg && constMask==0 ){ - sqlite3ReleaseTempRange(pParse, r1, nFarg); + if( nFarg ){ + if( constMask==0 ){ + sqlite3ReleaseTempRange(pParse, r1, nFarg); + }else{ + sqlite3VdbeReleaseRegisters(pParse, r1, nFarg, constMask); + } } return target; } @@ -5707,8 +5711,11 @@ int sqlite3GetTempReg(Parse *pParse){ ** purpose. */ void sqlite3ReleaseTempReg(Parse *pParse, int iReg){ - if( iReg && pParse->nTempRegaTempReg) ){ - pParse->aTempReg[pParse->nTempReg++] = iReg; + if( iReg ){ + sqlite3VdbeReleaseRegisters(pParse, iReg, 1, 0); + if( pParse->nTempRegaTempReg) ){ + pParse->aTempReg[pParse->nTempReg++] = iReg; + } } } @@ -5734,6 +5741,7 @@ void sqlite3ReleaseTempRange(Parse *pParse, int iReg, int nReg){ sqlite3ReleaseTempReg(pParse, iReg); return; } + sqlite3VdbeReleaseRegisters(pParse, iReg, nReg, 0); if( nReg>pParse->nRangeReg ){ pParse->nRangeReg = nReg; pParse->iRangeReg = iReg; diff --git a/src/vdbe.c b/src/vdbe.c index 2b5686cd63..6bd38c684e 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -2130,16 +2130,31 @@ compare_op: /* Opcode: ElseNotEq * P2 * * * ** -** This opcode must immediately follow an OP_Lt or OP_Gt comparison operator. -** If result of an OP_Eq comparison on the same two operands -** would have be NULL or false (0), then then jump to P2. -** If the result of an OP_Eq comparison on the two previous operands -** would have been true (1), then fall through. +** This opcode must follow an OP_Lt or OP_Gt comparison operator. There +** can be zero or more OP_ReleaseReg opcodes intervening, but no other +** opcodes are allowed to occur between this instruction and the previous +** OP_Lt or OP_Gt. Furthermore, the prior OP_Lt or OP_Gt must have the +** SQLITE_STOREP2 bit set in the P5 field. +** +** If result of an OP_Eq comparison on the same two operands as the +** prior OP_Lt or OP_Gt would have been NULL or false (0), then then +** jump to P2. If the result of an OP_Eq comparison on the two previous +** operands would have been true (1), then fall through. */ case OP_ElseNotEq: { /* same as TK_ESCAPE, jump */ - assert( pOp>aOp ); - assert( pOp[-1].opcode==OP_Lt || pOp[-1].opcode==OP_Gt ); - assert( pOp[-1].p5 & SQLITE_STOREP2 ); + +#ifdef SQLITE_DEBUG + /* Verify the preconditions of this opcode - that it follows an OP_Lt or + ** OP_Gt with the SQLITE_STOREP2 flag set, with zero or more intervening + ** OP_ReleaseReg opcodes */ + int iAddr; + for(iAddr = (int)(pOp - aOp) - 1; ALWAYS(iAddr>=0); iAddr--){ + if( aOp[iAddr].opcode==OP_ReleaseReg ) continue; + assert( aOp[iAddr].opcode==OP_Lt || aOp[iAddr].opcode==OP_Gt ); + assert( aOp[iAddr].p5 & SQLITE_STOREP2 ); + break; + } +#endif /* SQLITE_DEBUG */ VdbeBranchTaken(iCompare!=0, 2); if( iCompare!=0 ) goto jump_to_p2; break; @@ -7685,6 +7700,53 @@ case OP_Abortable: { } #endif +#ifdef SQLITE_DEBUG +/* Opcode: ReleaseReg P1 P2 P3 * * +** Synopsis: release r[P1@P2] mask P3 +** +** Release registers from service. Any content that was in the +** the registers is unreliable after this opcode completes. +** +** The registers released will be the P2 registers starting at P1, +** except if bit ii of P3 set, then do not release register P1+ii. +** In other words, P3 is a mask of registers to preserve. +** +** Releasing a register clears the Mem.pScopyFrom pointer. That means +** that if the content of the released register was set using OP_SCopy, +** a change to the value of the source register for the OP_SCopy will no longer +** generate an assertion fault in sqlite3VdbeMemAboutToChange(). +** +** TODO: Released registers ought to also have their datatype set to +** MEM_Undefined so that any subsequent attempt to read the released +** register (before it is reinitialized) will generate an assertion fault. +** However, there are places in the code generator which release registers +** before their are used, under the (valid) assumption that the registers +** will not be reallocated for some other purpose before they are used and +** hence are safe to release. +** +** This opcode is only available in testing and debugging builds. It is +** not generated for release builds. The purpose of this opcode is to help +** validate the generated bytecode. This opcode does not actually contribute +** to computing an answer. +*/ +case OP_ReleaseReg: { + Mem *pMem; + int i; + u32 constMask; + assert( pOp->p1>0 ); + assert( pOp->p1+pOp->p2<=(p->nMem+1 - p->nCursor)+1 ); + pMem = &aMem[pOp->p1]; + constMask = pOp->p3; + for(i=0; ip2; i++, pMem++){ + if( (constMask & MASKBIT32(i))==0 ){ + pMem->pScopyFrom = 0; + /* MemSetTypeFlag(pMem, MEM_Undefined); // See the TODO */ + } + } + break; +} +#endif + /* Opcode: Noop * * * * * ** ** Do nothing. This instruction is often useful as a jump diff --git a/src/vdbe.h b/src/vdbe.h index 3214d5bce3..9b25452e2f 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -232,6 +232,11 @@ void sqlite3VdbeChangeP5(Vdbe*, u16 P5); void sqlite3VdbeJumpHere(Vdbe*, int addr); int sqlite3VdbeChangeToNoop(Vdbe*, int addr); int sqlite3VdbeDeletePriorOpcode(Vdbe*, u8 op); +#ifdef SQLITE_DEBUG + void sqlite3VdbeReleaseRegisters(Parse*,int addr, int n, u32 mask); +#else +# define sqlite3VdbeReleaseRegisters(P,A,N,M) +#endif void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N); void sqlite3VdbeAppendP4(Vdbe*, void *pP4, int p4type); void sqlite3VdbeSetP4KeyInfo(Parse*, Index*); diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 8b9488e9e7..ac52303d57 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -1186,6 +1186,29 @@ int sqlite3VdbeDeletePriorOpcode(Vdbe *p, u8 op){ } } +#ifdef SQLITE_DEBUG +/* +** Generate an OP_ReleaseReg opcode to indicate that a range of +** registers, except any identified by mask, are no longer in use. +*/ +void sqlite3VdbeReleaseRegisters(Parse *pParse, int iFirst, int N, u32 mask){ + assert( pParse->pVdbe ); + while( N>0 && (mask&1)!=0 ){ + mask >>= 1; + iFirst++; + N--; + } + while( N>0 && N<=32 && (mask & MASKBIT32(N-1))!=0 ){ + mask &= ~MASKBIT32(N-1); + N--; + } + if( N>0 ){ + sqlite3VdbeAddOp3(pParse->pVdbe, OP_ReleaseReg, iFirst, N, *(int*)&mask); + } +} +#endif /* SQLITE_DEBUG */ + + /* ** Change the value of the P4 operand for a specific instruction. ** This routine is useful when a large program is loaded from a diff --git a/test/update.test b/test/update.test index 8b96b6658b..2f36bdf2f7 100644 --- a/test/update.test +++ b/test/update.test @@ -672,4 +672,16 @@ do_execsql_test update-18.10 { SELECT * FROM t0; } {xyz 345 uvw 345} +# 2019-12-22 ticket c62c5e58524b204d +# This is really the same underlying problem as 5ad2aa6921faa1ee +# +reset_db +do_execsql_test update-18.20 { + PRAGMA encoding = 'utf16'; + CREATE TABLE t0(c0 TEXT); + CREATE INDEX i0 ON t0(0 LIKE COALESCE(c0, 0)); + INSERT INTO t0(c0) VALUES (0), (0); + SELECT * FROM t0; +} {0 0} + finish_test