]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Enhance the sqlite3VdbeMemAboutToChange() shallow-copy validation mechanism
authordrh <drh@noemail.net>
Mon, 23 Dec 2019 02:18:49 +0000 (02:18 +0000)
committerdrh <drh@noemail.net>
Mon, 23 Dec 2019 02:18:49 +0000 (02:18 +0000)
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

manifest
manifest.uuid
src/expr.c
src/vdbe.c
src/vdbe.h
src/vdbeaux.c
test/update.test

index d6d5fbd3246f6d79e41fbcd214b96ab0308b910e..7b3bdf63e708f22c1c0ced3cba5eb4150c6453af 100644 (file)
--- 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
index 219c11bcc4010e34cc95e7776605584e1fe3aa93..0ac42976c81e283321457b79537c01a0dbbe1ba2 100644 (file)
@@ -1 +1 @@
-9ab985a9c8160b905730678f40ed440a246cdec549c798bafefaed5abbc0437f
\ No newline at end of file
+36fdeb4f0a66970a35de688b617f90899c89cfdfab659f864df99aa7ebf854ea
\ No newline at end of file
index 8f7c798cc3d3ce6fab5cb595361e5e96918ad8bc..4593ebbc57f8b2a7c71681a252bb91526a7589a5 100644 (file)
@@ -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;
index 2b5686cd63073a109cf4a55c76d9d6f32e4bb0c9..6bd38c684e1eea98a33e2948b3b08576713b3c71 100644 (file)
@@ -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
index 3214d5bce36819fb2f50e2bf64fe717ed53e916f..9b25452e2f2b80d15152ced8974fec60415b07d0 100644 (file)
@@ -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*);
index 8b9488e9e79791b6027ac39a665e6449e06bbe51..ac52303d57f0cee01ca8a248de55421ed8bd7caa 100644 (file)
@@ -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
index 8b96b6658bd8fe3e2eb42e06ed12702cee6cb4be..2f36bdf2f74c642034c3ba3d07eebbf1fae4fba4 100644 (file)
@@ -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