mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
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
This commit is contained in:
82
src/vdbe.c
82
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 <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';
|
||||
}
|
||||
|
Reference in New Issue
Block a user