]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Take care to track ephemeral strings in the VDBE and make copies of ephemeral
authordrh <drh@noemail.net>
Tue, 22 Oct 2002 15:04:34 +0000 (15:04 +0000)
committerdrh <drh@noemail.net>
Tue, 22 Oct 2002 15:04:34 +0000 (15:04 +0000)
strings that need to be preserved.  Ticket #177. (CVS 769)

FossilOrigin-Name: 562da534bbb605a8ce15824135b012ef2d86bbeb

manifest
manifest.uuid
src/vdbe.c

index 788f2e06a13a2f1749aa64367f30c9284c9ea810..9e3019ef5612d855b08022063999132343aae7fe 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Rework\sthe\schanges\sfor\sticket\s#176\s(check-ins\s(760)\sand\s(761))\sto\sbe\nmore\sconsistent\swith\sthe\srest\sof\sthe\ssource\scode.\s(CVS\s768)
-D 2002-10-20T18:19:45
+C Take\scare\sto\strack\sephemeral\sstrings\sin\sthe\sVDBE\sand\smake\scopies\sof\sephemeral\nstrings\sthat\sneed\sto\sbe\spreserved.\s\sTicket\s#177.\s(CVS\s769)
+D 2002-10-22T15:04:34
 F Makefile.in d6c9a85c2a5e696843201d090dcf8bf2f8716f2a
 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@@ -52,7 +52,7 @@ F src/tokenize.c 62c98842447effe92eba9622bb2f9a2a8a4b97ad
 F src/trigger.c 5ba917fc226b96065108da28186c2efaec53e481
 F src/update.c 881e4c8e7c786545da4fd2d95da19252b2e31137
 F src/util.c ca7650ef2cc2d50241e48029fca109a3016144ee
-F src/vdbe.c 4144effb953f1f25eb451dba85e69f0c34e3b788
+F src/vdbe.c b5d25c18f306cdb1da145dd555b056057920521f
 F src/vdbe.h b7584044223104ba7896a7f87b66daebdd6022ba
 F src/where.c 8ff2acfcb9bb15a057512bd6207b259feed57a2c
 F test/all.test efd958d048c70a3247997c482f0b33561f7759f0
@@ -149,7 +149,7 @@ F www/speed.tcl a20a792738475b68756ea7a19321600f23d1d803
 F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098
 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
-P 395ab5fac201a37d6eca833ffd6f58ac8a0121a2
-R 839af7b0330753291020e1f24ae79a14
+P f50a177b4239bc7a83563ac9361e830ec04e81fb
+R 51ce3b0413b1dc8a7f5705e4ce1ca408
 U drh
-Z 224ddb64edfd2ea0e4f95e777cac97ff
+Z c497ca5b513d571220d0f770a2a71d04
index 8aed6c306d764c4cfa1157c7ca25d6bee57c4bfb..8412d8f23233d82f1c2b1c5073f2131286b4d1ae 100644 (file)
@@ -1 +1 @@
-f50a177b4239bc7a83563ac9361e830ec04e81fb
\ No newline at end of file
+562da534bbb605a8ce15824135b012ef2d86bbeb
\ No newline at end of file
index e22953595b257d3234d1a1b24192baec6bb3c0a9..82544869310be8b4e27c9d7aa2f3a5794badd123 100644 (file)
@@ -36,7 +36,7 @@
 ** in this file for details.  If in doubt, do not deviate from existing
 ** commenting and indentation practices when changing or adding code.
 **
-** $Id: vdbe.c,v 1.180 2002/10/19 20:16:38 drh Exp $
+** $Id: vdbe.c,v 1.181 2002/10/22 15:04:34 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -152,8 +152,9 @@ typedef struct Mem Mem;
 #define STK_Str       0x0002   /* Value is a string */
 #define STK_Int       0x0004   /* Value is an integer */
 #define STK_Real      0x0008   /* Value is a real number */
-#define STK_Dyn       0x0010   /* Need to call sqliteFree() on zStack[*] */
+#define STK_Dyn       0x0010   /* Need to call sqliteFree() on zStack[] */
 #define STK_Static    0x0020   /* zStack[] points to a static string */
+#define STK_Ephem     0x0040   /* zStack[] points to an ephemeral string */
 
 /* The following STK_ value appears only in AggElem.aMem.s.flag fields.
 ** It indicates that the corresponding AggElem.aMem.z points to a
@@ -798,6 +799,31 @@ static int hardStringify(Vdbe *p, int i){
   return 0;
 }
 
+/*
+** An ephemeral string value (signified by the STK_Ephem flag) contains
+** a pointer to a dynamically allocated string where some other entity
+** is responsible for deallocating that string.  Because the stack entry
+** does not control the string, it might be deleted without the stack
+** entry knowing it.
+**
+** This routine converts an ephemeral string into a dynamically allocated
+** string that the stack entry itself controls.  In other words, it
+** converts an STK_Ephem string into an STK_Dyn string.
+*/
+#define Deephemeralize(P,I) \
+   if( ((P)->aStack[I].flags&STK_Ephem)!=0 && hardDeephem(P,I) ){ goto no_mem;}
+static int hardDeephem(Vdbe *p, int i){
+  Stack *pStack = &p->aStack[i];
+  char **pzStack = &p->zStack[i];
+  char *z;
+  assert( (pStack->flags & STK_Ephem)!=0 );
+  z = sqliteMalloc( pStack->n );
+  if( z==0 ) return 1;
+  memcpy(z, *pzStack, pStack->n);
+  *pzStack = z;
+  return 0;
+}
+
 /*
 ** Release the memory associated with the given stack level
 */
@@ -805,7 +831,7 @@ static int hardStringify(Vdbe *p, int i){
 static void hardRelease(Vdbe *p, int i){
   sqliteFree(p->zStack[i]);
   p->zStack[i] = 0;
-  p->aStack[i].flags &= ~(STK_Str|STK_Dyn|STK_Static);
+  p->aStack[i].flags &= ~(STK_Str|STK_Dyn|STK_Static|STK_Ephem);
 }
 
 /*
@@ -1577,18 +1603,21 @@ case OP_Dup: {
   VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
   memcpy(&aStack[j], &aStack[i], sizeof(aStack[i])-NBFS);
   if( aStack[j].flags & STK_Str ){
-    if( pOp->p2 || (aStack[j].flags & STK_Static)!=0 ){
+    int isStatic = (aStack[j].flags & STK_Static)!=0;
+    if( pOp->p2 || isStatic ){
       zStack[j] = zStack[i];
       aStack[j].flags &= ~STK_Dyn;
+      if( !isStatic ) aStack[j].flags |= STK_Ephem;
     }else if( aStack[i].n<=NBFS ){
       memcpy(aStack[j].z, zStack[i], aStack[j].n);
       zStack[j] = aStack[j].z;
-      aStack[j].flags &= ~(STK_Static|STK_Dyn);
+      aStack[j].flags &= ~(STK_Static|STK_Dyn|STK_Ephem);
     }else{
       zStack[j] = sqliteMalloc( aStack[j].n );
       if( zStack[j]==0 ) goto no_mem;
       memcpy(zStack[j], zStack[i], aStack[j].n);
-      aStack[j].flags &= ~STK_Static;
+      aStack[j].flags &= ~(STK_Static|STK_Ephem);
+      aStack[j].flags |= STK_Dyn;
     }
   }
   break;
@@ -1613,8 +1642,11 @@ case OP_Pull: {
   VERIFY( if( from<0 ) goto not_enough_stack; )
   ts = aStack[from];
   tz = zStack[from];
+  Deephemeralize(p, to);
   for(i=from; i<to; i++){
+    Deephemeralize(p, i);
     aStack[i] = aStack[i+1];
+    assert( (aStack[i].flags & STK_Ephem)==0 );
     if( aStack[i].flags & (STK_Dyn|STK_Static) ){
       zStack[i] = zStack[i+1];
     }else{
@@ -1622,6 +1654,7 @@ case OP_Pull: {
     }
   }
   aStack[to] = ts;
+  assert( (aStack[to].flags & STK_Ephem)==0 );
   if( aStack[to].flags & (STK_Dyn|STK_Static) ){
     zStack[to] = tz;
   }else{
@@ -1644,13 +1677,14 @@ case OP_Push: {
   if( aStack[to].flags & STK_Dyn ){
     sqliteFree(zStack[to]);
   }
+  Deephemeralize(p, from);
   aStack[to] = aStack[from];
-  if( aStack[to].flags & (STK_Dyn|STK_Static) ){
+  if( aStack[to].flags & (STK_Dyn|STK_Static|STK_Ephem) ){
     zStack[to] = zStack[from];
   }else{
     zStack[to] = aStack[to].z;
   }
-  aStack[from].flags &= ~STK_Dyn;
+  aStack[from].flags = 0;
   p->tos--;
   break;
 }
@@ -2896,7 +2930,7 @@ case OP_IncrKey: {
 
   VERIFY( if( tos<0 ) goto bad_instruction );
   if( Stringify(p, tos) ) goto no_mem;
-  if( aStack[tos].flags & STK_Static ){
+  if( aStack[tos].flags & (STK_Static|STK_Ephem) ){
     /* CANT HAPPEN.  The IncrKey opcode is only applied to keys
     ** generated by MakeKey or MakeIdxKey and the results of those
     ** operands are always dynamic strings.
@@ -3806,7 +3840,7 @@ case OP_Column: {
   if( amt==0 ){
     aStack[tos].flags = STK_Null;
   }else if( zRec ){
-    aStack[tos].flags = STK_Str | STK_Static;
+    aStack[tos].flags = STK_Str | STK_Ephem;
     aStack[tos].n = amt;
     zStack[tos] = &zRec[offset];
   }else{
@@ -4770,6 +4804,7 @@ case OP_MemStore: {
   int tos = p->tos;
   char *zOld;
   Mem *pMem;
+  int flags;
   VERIFY( if( tos<0 ) goto not_enough_stack; )
   if( i>=p->nMem ){
     int nOld = p->nMem;
@@ -4791,19 +4826,23 @@ case OP_MemStore: {
     }
   }
   pMem = &p->aMem[i];
-  if( pMem->s.flags & STK_Dyn ){
+  flags = pMem->s.flags;
+  if( flags & STK_Dyn ){
     zOld = pMem->z;
   }else{
     zOld = 0;
   }
   pMem->s = aStack[tos];
-  if( pMem->s.flags & (STK_Static|STK_Dyn) ){
-    if( pOp->p2==0 && (pMem->s.flags & STK_Dyn)!=0 ){
+  flags = pMem->s.flags;
+  if( flags & (STK_Static|STK_Dyn|STK_Ephem) ){
+    if( (flags & STK_Static)!=0 || (pOp->p2 && (flags & STK_Dyn)!=0) ){
+      pMem->z = zStack[tos];
+    }else if( flags & STK_Str ){
       pMem->z = sqliteMalloc( pMem->s.n );
       if( pMem->z==0 ) goto no_mem;
       memcpy(pMem->z, zStack[tos], pMem->s.n);
-    }else{
-      pMem->z = zStack[tos];
+      pMem->s.flags |= STK_Dyn;
+      pMem->s.flags &= ~(STK_Static|STK_Ephem);
     }
   }else{
     pMem->z = pMem->s.z;
@@ -4834,7 +4873,7 @@ case OP_MemLoad: {
   memcpy(&aStack[tos], &p->aMem[i].s, sizeof(aStack[tos])-NBFS);;
   if( aStack[tos].flags & STK_Str ){
     zStack[tos] = p->aMem[i].z;
-    aStack[tos].flags |= STK_Static;
+    aStack[tos].flags |= STK_Ephem;
     aStack[tos].flags &= ~STK_Dyn;
   }
   break;
@@ -4988,6 +5027,7 @@ case OP_AggSet: {
     }else{
       zOld = 0;
     }
+    Deephemeralize(p, tos);
     pMem->s = aStack[tos];
     if( pMem->s.flags & STK_Dyn ){
       pMem->z = zStack[tos];
@@ -5021,6 +5061,7 @@ case OP_AggGet: {
     aStack[tos] = pMem->s;
     zStack[tos] = pMem->z;
     aStack[tos].flags &= ~STK_Dyn;
+    aStack[tos].flags |= STK_Ephem;
   }
   break;
 }
@@ -5070,7 +5111,7 @@ case OP_AggNext: {
       aMem[i].s = ctx.s;
       aMem[i].z = ctx.z;
       if( (aMem[i].s.flags & STK_Str) &&
-              (aMem[i].s.flags & (STK_Dyn|STK_Static))==0 ){
+              (aMem[i].s.flags & (STK_Dyn|STK_Static|STK_Ephem))==0 ){
         aMem[i].z = aMem[i].s.z;
       }
       nErr += ctx.isError;
@@ -5185,7 +5226,7 @@ case OP_SetNext: {
   VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
   zStack[tos] = sqliteHashKey(pSet->prev);
   aStack[tos].n = sqliteHashKeysize(pSet->prev);
-  aStack[tos].flags = STK_Str | STK_Static;
+  aStack[tos].flags = STK_Str | STK_Ephem;
   break;
 }
 
@@ -5234,8 +5275,13 @@ default: {
           zBuf[0] = ' ';
           if( aStack[i].flags & STK_Dyn ){
             zBuf[1] = 'z';
+            assert( (aStack[i].flags & (STK_Static|STK_Ephem))==0 );
           }else if( aStack[i].flags & STK_Static ){
             zBuf[1] = 't';
+            assert( (aStack[i].flags & (STK_Dyn|STK_Ephem))==0 );
+          }else if( aStack[i].flags & STK_Ephem ){
+            zBuf[1] = 'e';
+            assert( (aStack[i].flags & (STK_Static|STK_Dyn))==0 );
           }else{
             zBuf[1] = 's';
           }