mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-30 19:03:16 +03:00
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
This commit is contained in:
24
manifest
24
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
|
||||
|
@ -1 +1 @@
|
||||
5dcffa671f592ae9355628afa439ae9a2d26f0cd
|
||||
71effa59c98d167e6e4b269e59ad5f468e664ac1
|
19
src/vdbe.c
19
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
|
||||
|
@ -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 */
|
||||
|
@ -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*);
|
||||
|
@ -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;
|
||||
|
@ -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; i<pVdbeFunc->nAux; i++){
|
||||
struct AuxData *pAux = &pVdbeFunc->apAux[i];
|
||||
if( (i>31 || !(mask&(((u32)1)<<i))) && pAux->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<<pAux->iArg))))
|
||||
){
|
||||
if( pAux->xDelete ){
|
||||
pAux->xDelete(pAux->pAux);
|
||||
}
|
||||
pAux->pAux = 0;
|
||||
*pp = pAux->pNext;
|
||||
sqlite3DbFree(pVdbe->db, pAux);
|
||||
}else{
|
||||
pp= &pAux->pNext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
Reference in New Issue
Block a user