From: dan Date: Thu, 18 Jul 2013 17:12:08 +0000 (+0000) Subject: Ensure that all auxiliary data registered by calls to sqlite3_set_auxdata() is destro... X-Git-Tag: version-3.8.0~79^2~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0c5477997b82bfd4b952414faf9733377d0248f7;p=thirdparty%2Fsqlite.git Ensure that all auxiliary data registered by calls to sqlite3_set_auxdata() is destroyed when the VM is halted. Partial fix for [406d3b2ef9]. FossilOrigin-Name: 71effa59c98d167e6e4b269e59ad5f468e664ac1 --- diff --git a/manifest b/manifest index 7bd39ba9a8..6dd3418d1d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\s8-byte\salignment\sproblem\sin\sthe\squery\splanner\sthat\smight\scause\nproblems\son\ssparc\swhen\scompiled\swith\s-m32. -D 2013-07-18T14:50:56.888 +C Ensure\sthat\sall\sauxiliary\sdata\sregistered\sby\scalls\sto\ssqlite3_set_auxdata()\sis\sdestroyed\swhen\sthe\sVM\sis\shalted.\sPartial\sfix\sfor\s[406d3b2ef9]. +D 2013-07-18T17:12:08.417 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -277,11 +277,11 @@ F src/update.c 8e76c3d03e4b7b21cb250bd2df0c05e12993e577 F src/utf.c 8d819e2e5104a430fc2005f018db14347c95a38f F src/util.c f566b5138099a2df8533b190d0dcc74b7dfbe0c9 F src/vacuum.c d9c5759f4c5a438bb43c2086f72c5d2edabc36c8 -F src/vdbe.c 420ebf1d551a76406cbbe0adc52d22d45aac039a -F src/vdbe.h b52887278cb173e66188da84dfab216bea61119d -F src/vdbeInt.h 5e666c971c555c7977714b0e34cb8d4b20282557 -F src/vdbeapi.c c88222946d657984bdaf394604cb58ed1d641460 -F src/vdbeaux.c 1633408f6dea06129441c5e2f22b2a5ce30fe97e +F src/vdbe.c 7fab3ee5adbcf841fad9db65308ac5dc36c4e0be +F src/vdbe.h f380af2a7fab32ba8a8b05bf042497636afec66d +F src/vdbeInt.h e9b7c6b165a31a4715c5aa97223d20d265515231 +F src/vdbeapi.c 4d13580bd058b39623e8fcfc233b7df4b8191e8b +F src/vdbeaux.c c01594ecf5a78ef41a721f3465152bb91883a942 F src/vdbeblob.c 5dc79627775bd9a9b494dd956e26297946417d69 F src/vdbemem.c 833005f1cbbf447289f1973dba2a0c2228c7b8ab F src/vdbesort.c 3937e06b2a0e354500e17dc206ef4c35770a5017 @@ -556,7 +556,7 @@ F test/fts4merge4.test c19c85ca1faa7b6d536832b49c12e1867235f584 F test/fts4noti.test aed33ba44808852dcb24bf70fa132e7bf530f057 F test/fts4unicode.test c8ac44217bf6c17812b03eaafa6c06995ad304c2 F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d -F test/func.test b0fc34fdc36897769651975a2b0a606312753643 +F test/func.test 9161beda516d6006d31e6ea6119579286512f751 F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f F test/func3.test 001021e5b88bd02a3b365a5c5fd8f6f49d39744a F test/fuzz-oss1.test 4912e528ec9cf2f42134456933659d371c9e0d74 @@ -1103,7 +1103,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 7acc8cd32d593a473c9e9adaf323220a7a46480a -R 17b8abd2c5b717cffa3f1d157b1c3142 -U drh -Z 8aedb025f873aeef3a714ef3251c3e91 +P 5dcffa671f592ae9355628afa439ae9a2d26f0cd +R 5f8d56aac1f51039dd4e137aed108558 +U dan +Z e317751ba4c386bb8e1c47226cf1f704 diff --git a/manifest.uuid b/manifest.uuid index fc61fbc2f7..8e33f834ce 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5dcffa671f592ae9355628afa439ae9a2d26f0cd \ No newline at end of file +71effa59c98d167e6e4b269e59ad5f468e664ac1 \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index 2e60361e89..c568d51fa5 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -1420,19 +1420,14 @@ case OP_Function: { REGISTER_TRACE(pOp->p2+i, pArg); } - assert( pOp->p4type==P4_FUNCDEF || pOp->p4type==P4_VDBEFUNC ); - if( pOp->p4type==P4_FUNCDEF ){ - ctx.pFunc = pOp->p4.pFunc; - ctx.pVdbeFunc = 0; - }else{ - ctx.pVdbeFunc = (VdbeFunc*)pOp->p4.pVdbeFunc; - ctx.pFunc = ctx.pVdbeFunc->pFunc; - } - + assert( pOp->p4type==P4_FUNCDEF ); + ctx.pFunc = pOp->p4.pFunc; ctx.s.flags = MEM_Null; ctx.s.db = db; ctx.s.xDel = 0; ctx.s.zMalloc = 0; + ctx.iOp = pc; + ctx.pVdbe = p; /* The output cell may already have a buffer allocated. Move ** the pointer to ctx.s so in case the user-function can use @@ -1455,11 +1450,7 @@ case OP_Function: { /* If any auxiliary data functions have been called by this user function, ** immediately call the destructor for any non-static values. */ - if( ctx.pVdbeFunc ){ - sqlite3VdbeDeleteAuxData(ctx.pVdbeFunc, pOp->p1); - pOp->p4.pVdbeFunc = ctx.pVdbeFunc; - pOp->p4type = P4_VDBEFUNC; - } + sqlite3VdbeDeleteAuxData(ppc, pc, pOp->p1); if( db->mallocFailed ){ /* Even though a malloc() has failed, the implementation of the diff --git a/src/vdbe.h b/src/vdbe.h index fa7b31b727..4c2e76d562 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -30,7 +30,6 @@ typedef struct Vdbe Vdbe; ** The names of the following types declared in vdbeInt.h are required ** for the VdbeOp definition. */ -typedef struct VdbeFunc VdbeFunc; typedef struct Mem Mem; typedef struct SubProgram SubProgram; @@ -54,7 +53,6 @@ struct VdbeOp { i64 *pI64; /* Used when p4type is P4_INT64 */ double *pReal; /* Used when p4type is P4_REAL */ FuncDef *pFunc; /* Used when p4type is P4_FUNCDEF */ - VdbeFunc *pVdbeFunc; /* Used when p4type is P4_VDBEFUNC */ CollSeq *pColl; /* Used when p4type is P4_COLLSEQ */ Mem *pMem; /* Used when p4type is P4_MEM */ VTable *pVtab; /* Used when p4type is P4_VTAB */ @@ -108,7 +106,6 @@ typedef struct VdbeOpList VdbeOpList; #define P4_COLLSEQ (-4) /* P4 is a pointer to a CollSeq structure */ #define P4_FUNCDEF (-5) /* P4 is a pointer to a FuncDef structure */ #define P4_KEYINFO (-6) /* P4 is a pointer to a KeyInfo structure */ -#define P4_VDBEFUNC (-7) /* P4 is a pointer to a VdbeFunc structure */ #define P4_MEM (-8) /* P4 is a pointer to a Mem* structure */ #define P4_TRANSIENT 0 /* P4 is a pointer to a transient string */ #define P4_VTAB (-10) /* P4 is a pointer to an sqlite3_vtab structure */ diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 11c34fd524..9ee82b4ea0 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -44,6 +44,9 @@ typedef struct VdbeSorter VdbeSorter; /* Opaque type used by the explainer */ typedef struct Explain Explain; +/* Elements of the linked list at Vdbe.pAuxData */ +typedef struct AuxData AuxData; + /* ** A cursor is a pointer into a single BTree within a database file. ** The cursor can seek to a BTree entry with a particular key, or @@ -230,23 +233,19 @@ struct Mem { #define memIsValid(M) ((M)->flags & MEM_Invalid)==0 #endif - -/* A VdbeFunc is just a FuncDef (defined in sqliteInt.h) that contains -** additional information about auxiliary information bound to arguments -** of the function. This is used to implement the sqlite3_get_auxdata() -** and sqlite3_set_auxdata() APIs. The "auxdata" is some auxiliary data -** that can be associated with a constant argument to a function. This -** allows functions such as "regexp" to compile their constant regular -** expression argument once and reused the compiled code for multiple -** invocations. +/* +** Each auxilliary data pointer stored by a user defined function +** implementation calling sqlite3_set_auxdata() is stored in an instance +** of this structure. All such structures associated with a single VM +** are stored in a linked list headed at Vdbe.pAuxData. All are destroyed +** when the VM is halted (if not before). */ -struct VdbeFunc { - FuncDef *pFunc; /* The definition of the function */ - int nAux; /* Number of entries allocated for apAux[] */ - struct AuxData { - void *pAux; /* Aux data for the i-th argument */ - void (*xDelete)(void *); /* Destructor for the aux data */ - } apAux[1]; /* One slot for each function argument */ +struct AuxData { + int iOp; /* Instruction number of OP_Function opcode */ + int iArg; /* Index of function argument. */ + void *pAux; /* Aux data pointer */ + void (*xDelete)(void *); /* Destructor for the aux data */ + AuxData *pNext; /* Next element in list */ }; /* @@ -264,12 +263,13 @@ struct VdbeFunc { */ struct sqlite3_context { FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */ - VdbeFunc *pVdbeFunc; /* Auxilary data, if created. */ Mem s; /* The return value is stored here */ Mem *pMem; /* Memory cell used to store aggregate context */ CollSeq *pColl; /* Collating sequence */ int isError; /* Error code returned by the function. */ int skipFlag; /* Skip skip accumulator loading if true */ + int iOp; /* Instruction number of OP_Function */ + Vdbe *pVdbe; /* The VM that owns this context */ }; /* @@ -368,6 +368,7 @@ struct Vdbe { SubProgram *pProgram; /* Linked list of all sub-programs used by VM */ int nOnceFlag; /* Size of array aOnceFlag[] */ u8 *aOnceFlag; /* Flags for OP_Once */ + AuxData *pAuxData; /* Linked list of auxdata allocations */ }; /* @@ -391,7 +392,7 @@ u32 sqlite3VdbeSerialTypeLen(u32); u32 sqlite3VdbeSerialType(Mem*, int); u32 sqlite3VdbeSerialPut(unsigned char*, int, Mem*, int); u32 sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*); -void sqlite3VdbeDeleteAuxData(VdbeFunc*, int); +void sqlite3VdbeDeleteAuxData(Vdbe*, int, int); int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *); int sqlite3VdbeIdxKeyCompare(VdbeCursor*,UnpackedRecord*,int*); diff --git a/src/vdbeapi.c b/src/vdbeapi.c index ad3eea13a7..7c9db9beec 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -584,14 +584,14 @@ void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){ ** the user-function defined by pCtx. */ void *sqlite3_get_auxdata(sqlite3_context *pCtx, int iArg){ - VdbeFunc *pVdbeFunc; + AuxData *pAuxData; assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); - pVdbeFunc = pCtx->pVdbeFunc; - if( !pVdbeFunc || iArg>=pVdbeFunc->nAux || iArg<0 ){ - return 0; + for(pAuxData=pCtx->pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){ + if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break; } - return pVdbeFunc->apAux[iArg].pAux; + + return (pAuxData ? pAuxData->pAux : 0); } /* @@ -605,29 +605,26 @@ void sqlite3_set_auxdata( void *pAux, void (*xDelete)(void*) ){ - struct AuxData *pAuxData; - VdbeFunc *pVdbeFunc; - if( iArg<0 ) goto failed; + AuxData *pAuxData; + Vdbe *pVdbe = pCtx->pVdbe; assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); - pVdbeFunc = pCtx->pVdbeFunc; - if( !pVdbeFunc || pVdbeFunc->nAux<=iArg ){ - int nAux = (pVdbeFunc ? pVdbeFunc->nAux : 0); - int nMalloc = sizeof(VdbeFunc) + sizeof(struct AuxData)*iArg; - pVdbeFunc = sqlite3DbRealloc(pCtx->s.db, pVdbeFunc, nMalloc); - if( !pVdbeFunc ){ - goto failed; - } - pCtx->pVdbeFunc = pVdbeFunc; - memset(&pVdbeFunc->apAux[nAux], 0, sizeof(struct AuxData)*(iArg+1-nAux)); - pVdbeFunc->nAux = iArg+1; - pVdbeFunc->pFunc = pCtx->pFunc; - } + if( iArg<0 ) goto failed; - pAuxData = &pVdbeFunc->apAux[iArg]; - if( pAuxData->pAux && pAuxData->xDelete ){ + for(pAuxData=pVdbe->pAuxData; pAuxData; pAuxData=pAuxData->pNext){ + if( pAuxData->iOp==pCtx->iOp && pAuxData->iArg==iArg ) break; + } + if( pAuxData==0 ){ + pAuxData = sqlite3DbMallocZero(pVdbe->db, sizeof(AuxData)); + if( !pAuxData ) goto failed; + pAuxData->iOp = pCtx->iOp; + pAuxData->iArg = iArg; + pAuxData->pNext = pVdbe->pAuxData; + pVdbe->pAuxData = pAuxData; + }else if( pAuxData->xDelete ){ pAuxData->xDelete(pAuxData->pAux); } + pAuxData->pAux = pAux; pAuxData->xDelete = xDelete; return; diff --git a/src/vdbeaux.c b/src/vdbeaux.c index dfdf7800a4..f54685cb71 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -612,13 +612,6 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){ if( db->pnBytesFreed==0 ) sqlite3_free(p4); break; } - case P4_VDBEFUNC: { - VdbeFunc *pVdbeFunc = (VdbeFunc *)p4; - freeEphemeralFunction(db, pVdbeFunc->pFunc); - if( db->pnBytesFreed==0 ) sqlite3VdbeDeleteAuxData(pVdbeFunc, 0); - sqlite3DbFree(db, pVdbeFunc); - break; - } case P4_FUNCDEF: { freeEphemeralFunction(db, (FuncDef*)p4); break; @@ -1648,6 +1641,10 @@ static void closeAllCursors(Vdbe *p){ p->pDelFrame = pDel->pParent; sqlite3VdbeFrameDelete(pDel); } + + /* Delete any auxdata allocations made by the VM */ + sqlite3VdbeDeleteAuxData(p, -1, 0); + assert( p->pAuxData==0 ); } /* @@ -2446,20 +2443,35 @@ int sqlite3VdbeFinalize(Vdbe *p){ } /* -** Call the destructor for each auxdata entry in pVdbeFunc for which -** the corresponding bit in mask is clear. Auxdata entries beyond 31 -** are always destroyed. To destroy all auxdata entries, call this -** routine with mask==0. +** If parameter iOp is less than zero, then invoke the destructor for +** all auxiliary data pointers currently cached by the VM passed as +** the first argument. +** +** Or, if iOp is greater than or equal to zero, then the destructor is +** only invoked for those auxiliary data pointers created by the user +** function invoked by the OP_Function opcode at instruction iOp of +** VM pVdbe, and only then if: +** +** * the associated function parameter is the 32nd or later (counting +** from left to right), or +** +** * the corresponding bit in argument mask is clear (where the first +** function parameter corrsponds to bit 0 etc.). */ -void sqlite3VdbeDeleteAuxData(VdbeFunc *pVdbeFunc, int mask){ - int i; - for(i=0; inAux; i++){ - struct AuxData *pAux = &pVdbeFunc->apAux[i]; - if( (i>31 || !(mask&(((u32)1)<pAux ){ +void sqlite3VdbeDeleteAuxData(Vdbe *pVdbe, int iOp, int mask){ + AuxData **pp = &pVdbe->pAuxData; + while( *pp ){ + AuxData *pAux = *pp; + if( (iOp<0) + || (pAux->iOp==iOp && (pAux->iArg>31 || !(mask & ((u32)1<iArg)))) + ){ if( pAux->xDelete ){ pAux->xDelete(pAux->pAux); } - pAux->pAux = 0; + *pp = pAux->pNext; + sqlite3DbFree(pVdbe->db, pAux); + }else{ + pp= &pAux->pNext; } } } diff --git a/test/func.test b/test/func.test index 4ab7688461..06f9f41d01 100644 --- a/test/func.test +++ b/test/func.test @@ -682,6 +682,32 @@ do_test func-13.7 { lappend res [sqlite3_finalize $STMT] } {{0 0} {1 0} SQLITE_OK} +# Test that auxiliary data is discarded when a statement is reset. +do_execsql_test 13.8.1 { + SELECT test_auxdata('constant') FROM t4; +} {0 1} +do_execsql_test 13.8.2 { + SELECT test_auxdata('constant') FROM t4; +} {0 1} +db cache flush +do_execsql_test 13.8.3 { + SELECT test_auxdata('constant') FROM t4; +} {0 1} +set V "one" +do_execsql_test 13.8.4 { + SELECT test_auxdata($V), $V FROM t4; +} {0 one 1 one} +set V "two" +do_execsql_test 13.8.5 { + SELECT test_auxdata($V), $V FROM t4; +} {0 two 1 two} +db cache flush +set V "three" +do_execsql_test 2.3 { + SELECT test_auxdata($V), $V FROM t4; +} {0 three 1 three} + + # Make sure that a function with a very long name is rejected do_test func-14.1 { catch {