From e958bb4aefd9266286bf900b4418b20c8ebdd04c Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 22 Oct 2002 15:04:34 +0000 Subject: [PATCH] Take care to track ephemeral strings in the VDBE and make copies of ephemeral strings that need to be preserved. Ticket #177. (CVS 769) FossilOrigin-Name: 562da534bbb605a8ce15824135b012ef2d86bbeb --- manifest | 12 ++++---- manifest.uuid | 2 +- src/vdbe.c | 82 ++++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 71 insertions(+), 25 deletions(-) diff --git a/manifest b/manifest index 788f2e06a1..9e3019ef56 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index 8aed6c306d..8412d8f232 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f50a177b4239bc7a83563ac9361e830ec04e81fb \ No newline at end of file +562da534bbb605a8ce15824135b012ef2d86bbeb \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index e22953595b..8254486931 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -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 @@ -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; itos--; 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'; }