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
This commit is contained in:
parent
4799488e16
commit
13d7950267
20
manifest
20
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
|
||||
|
@ -1 +1 @@
|
||||
9ab985a9c8160b905730678f40ed440a246cdec549c798bafefaed5abbc0437f
|
||||
36fdeb4f0a66970a35de688b617f90899c89cfdfab659f864df99aa7ebf854ea
|
18
src/expr.c
18
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->nTempReg<ArraySize(pParse->aTempReg) ){
|
||||
pParse->aTempReg[pParse->nTempReg++] = iReg;
|
||||
if( iReg ){
|
||||
sqlite3VdbeReleaseRegisters(pParse, iReg, 1, 0);
|
||||
if( pParse->nTempReg<ArraySize(pParse->aTempReg) ){
|
||||
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;
|
||||
|
78
src/vdbe.c
78
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; i<pOp->p2; 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
|
||||
|
@ -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*);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user