mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
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:
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
|
||||
|
Reference in New Issue
Block a user