Change the MEM_Dyn flag so that it means that Mem.xDel exists and must be

used to free the string or blob.  Add tighter invariant checks on Mem.

FossilOrigin-Name: 44e1c33767cae3bf2cbd2238831fe67197009b43
This commit is contained in:
drh 2014-03-01 18:13:23 +00:00
parent 75fd054201
commit c91b2fd310
7 changed files with 59 additions and 40 deletions

View File

@ -1,5 +1,5 @@
C Factor\sthe\sMem\sinvariant\schecker\sinto\sa\sseparate\sprocedure\s(rather\sthan\sa\nmacro)\sso\sthat\sit\scan\sbe\smore\seasily\sextended.
D 2014-03-01T16:24:44.768
C Change\sthe\sMEM_Dyn\sflag\sso\sthat\sit\smeans\sthat\sMem.xDel\sexists\sand\smust\sbe\nused\sto\sfree\sthe\sstring\sor\sblob.\s\sAdd\stighter\sinvariant\schecks\son\sMem.
D 2014-03-01T18:13:23.744
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -274,16 +274,16 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/tokenize.c 6da2de6e12218ccb0aea5184b56727d011f4bee7
F src/trigger.c a80036fcbd992729adc7cd34a875d59a71fa10cc
F src/update.c 5b3e74a03b3811e586b4f2b4cbd7c49f01c93115
F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
F src/utf.c 6dc9ec9f1b3db43ae8ba0365377f11df1ee4c01c
F src/util.c c46c90459ef9bdc0c6c73803cf4c55425b4771cf
F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
F src/vdbe.c 9abaa1ebb8b98e33121ea1aade1022fdc195b464
F src/vdbe.c cbed4957185bfee7e585dce208d8ec4cd87179c2
F src/vdbe.h 147027d6e8e667a63e87177a38e2b42c71fdacf8
F src/vdbeInt.h a82d5ab4fd8138bdff7de4a267ea5c04e4cbb370
F src/vdbeInt.h d55cab859abb2c6656911497ae74eba9dcf34e28
F src/vdbeapi.c 5bc41aaea448a7fc250902c418f1795859be3820
F src/vdbeaux.c 2f97cd756e2704b06006b398ce468f0bcc006055
F src/vdbeaux.c 89a0ad3b2ecdbe71cf827a1f99d0ae51eccd6cce
F src/vdbeblob.c d939997de046b8fcc607cfee4248f3d33dbcca50
F src/vdbemem.c 8c84ec056c7934cef359f4d49fa32b856eeffd88
F src/vdbemem.c 868a498a670c08344a594a9d5903a3ff330916a7
F src/vdbesort.c 9d83601f9d6243fe70dd0169a2820c5ddfd48147
F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767
F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
@ -1152,7 +1152,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
P 4aeb3ae435c78070232fef21a147fde4e1c5cd31
R c42d4082e634170a16f76850fb72106d
P 354699d50e7d251504a7b3d6fbec9e5bcf99557f
R 0950c7cf1a1151e6071aa7a5599d1f4e
U drh
Z e1bae2e998058d57d79a76345aaf3403
Z c9678592d0817ad1269cd44af9e6bf96

View File

@ -1 +1 @@
354699d50e7d251504a7b3d6fbec9e5bcf99557f
44e1c33767cae3bf2cbd2238831fe67197009b43

View File

@ -317,7 +317,7 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
sqlite3VdbeMemRelease(pMem);
pMem->flags &= ~(MEM_Static|MEM_Dyn|MEM_Ephem);
pMem->enc = desiredEnc;
pMem->flags |= (MEM_Term|MEM_Dyn);
pMem->flags |= (MEM_Term);
pMem->z = (char*)zOut;
pMem->zMalloc = pMem->z;
@ -445,7 +445,6 @@ char *sqlite3Utf16to8(sqlite3 *db, const void *z, int nByte, u8 enc){
}
assert( (m.flags & MEM_Term)!=0 || db->mallocFailed );
assert( (m.flags & MEM_Str)!=0 || db->mallocFailed );
assert( (m.flags & MEM_Dyn)!=0 || db->mallocFailed );
assert( m.z || db->mallocFailed );
return m.z;
}

View File

@ -152,7 +152,7 @@ int sqlite3_found_count = 0;
**
** This routine converts an ephemeral string into a dynamically allocated
** string that the register itself controls. In other words, it
** converts an MEM_Ephem string into an MEM_Dyn string.
** converts an MEM_Ephem string into a string with P.z==P.zMalloc.
*/
#define Deephemeralize(P) \
if( ((P)->flags&MEM_Ephem)!=0 \
@ -716,7 +716,7 @@ check_for_interrupt:
case OP_Gosub: { /* jump */
assert( pOp->p1>0 && pOp->p1<=(p->nMem-p->nCursor) );
pIn1 = &aMem[pOp->p1];
assert( (pIn1->flags & MEM_Dyn)==0 );
assert( VdbeMemDynamic(pIn1)==0 );
memAboutToChange(p, pIn1);
pIn1->flags = MEM_Int;
pIn1->u.i = pc;
@ -789,7 +789,7 @@ case OP_EndCoroutine: { /* in1 */
case OP_Yield: { /* in1, jump */
int pcDest;
pIn1 = &aMem[pOp->p1];
assert( (pIn1->flags & MEM_Dyn)==0 );
assert( VdbeMemDynamic(pIn1)==0 );
pIn1->flags = MEM_Int;
pcDest = (int)pIn1->u.i;
pIn1->u.i = pc;
@ -962,10 +962,9 @@ case OP_String8: { /* same as TK_STRING, out2-prerelease */
if( rc==SQLITE_TOOBIG ) goto too_big;
if( SQLITE_OK!=sqlite3VdbeChangeEncoding(pOut, encoding) ) goto no_mem;
assert( pOut->zMalloc==pOut->z );
assert( pOut->flags & MEM_Dyn );
assert( VdbeMemDynamic(pOut)==0 );
pOut->zMalloc = 0;
pOut->flags |= MEM_Static;
pOut->flags &= ~MEM_Dyn;
if( pOp->p4type==P4_DYNAMIC ){
sqlite3DbFree(db, pOp->p4.z);
}
@ -1101,14 +1100,16 @@ case OP_Move: {
assert( pIn1<=&aMem[(p->nMem-p->nCursor)] );
assert( memIsValid(pIn1) );
memAboutToChange(p, pOut);
VdbeMemRelease(pOut);
zMalloc = pOut->zMalloc;
pOut->zMalloc = 0;
sqlite3VdbeMemMove(pOut, pIn1);
memcpy(pOut, pIn1, sizeof(Mem));
#ifdef SQLITE_DEBUG
if( pOut->pScopyFrom>=&aMem[p1] && pOut->pScopyFrom<&aMem[p1+pOp->p3] ){
pOut->pScopyFrom += p1 - pOp->p2;
}
#endif
pIn1->flags = MEM_Undefined;
pIn1->xDel = 0;
pIn1->zMalloc = zMalloc;
REGISTER_TRACE(p2++, pOut);
pIn1++;
@ -1285,10 +1286,10 @@ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */
if( nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){
goto too_big;
}
MemSetTypeFlag(pOut, MEM_Str);
if( sqlite3VdbeMemGrow(pOut, (int)nByte+2, pOut==pIn2) ){
goto no_mem;
}
MemSetTypeFlag(pOut, MEM_Str);
if( pOut!=pIn2 ){
memcpy(pOut->z, pIn2->z, pIn2->n);
}
@ -2501,8 +2502,8 @@ case OP_Column: {
** This prevents a memory copy. */
if( sMem.zMalloc ){
assert( sMem.z==sMem.zMalloc );
assert( !(pDest->flags & MEM_Dyn) );
assert( !(pDest->flags & (MEM_Blob|MEM_Str)) || pDest->z==sMem.z );
assert( VdbeMemDynamic(pDest)==0 );
assert( (pDest->flags & (MEM_Blob|MEM_Str))==0 || pDest->z==sMem.z );
pDest->flags &= ~(MEM_Ephem|MEM_Static);
pDest->flags |= MEM_Term;
pDest->z = sMem.z;
@ -2685,7 +2686,7 @@ case OP_MakeRecord: {
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
pOut->n = (int)nByte;
pOut->flags = MEM_Blob | MEM_Dyn;
pOut->flags = MEM_Blob;
pOut->xDel = 0;
if( nZero ){
pOut->u.nZero = nZero;

View File

@ -208,7 +208,7 @@ struct Mem {
** string is \000 or \u0000 terminated
*/
#define MEM_Term 0x0200 /* String rep is nul terminated */
#define MEM_Dyn 0x0400 /* Need to call sqliteFree() on Mem.z */
#define MEM_Dyn 0x0400 /* Need to call Mem.xDel() on Mem.z */
#define MEM_Static 0x0800 /* Mem.z points to a static string */
#define MEM_Ephem 0x1000 /* Mem.z points to an ephemeral string */
#define MEM_Agg 0x2000 /* Mem.z points to an agg function context */

View File

@ -1414,7 +1414,7 @@ int sqlite3VdbeList(
assert( p->db->mallocFailed );
return SQLITE_ERROR;
}
pMem->flags = MEM_Dyn|MEM_Str|MEM_Term;
pMem->flags = MEM_Str|MEM_Term;
zP4 = displayP4(pOp, pMem->z, 32);
if( zP4!=pMem->z ){
sqlite3VdbeMemSetStr(pMem, zP4, -1, SQLITE_UTF8, 0);
@ -1431,7 +1431,7 @@ int sqlite3VdbeList(
assert( p->db->mallocFailed );
return SQLITE_ERROR;
}
pMem->flags = MEM_Dyn|MEM_Str|MEM_Term;
pMem->flags = MEM_Str|MEM_Term;
pMem->n = 2;
sqlite3_snprintf(3, pMem->z, "%.2x", pOp->p5); /* P5 */
pMem->memType = MEM_Str;
@ -1443,7 +1443,7 @@ int sqlite3VdbeList(
assert( p->db->mallocFailed );
return SQLITE_ERROR;
}
pMem->flags = MEM_Dyn|MEM_Str|MEM_Term;
pMem->flags = MEM_Str|MEM_Term;
pMem->n = displayComment(pOp, zP4, pMem->z, 500);
pMem->memType = MEM_Str;
pMem->enc = SQLITE_UTF8;

View File

@ -26,11 +26,29 @@
** this: assert( sqlite3VdbeCheckMemInvariants(pMem) );
*/
int sqlite3VdbeCheckMemInvariants(Mem *p){
assert(
(((p)->zMalloc && (p)->zMalloc==(p)->z) ? 1 : 0) +
((((p)->flags&MEM_Dyn)&&(p)->xDel) ? 1 : 0) +
(((p)->flags&MEM_Ephem) ? 1 : 0) +
(((p)->flags&MEM_Static) ? 1 : 0) <= 1 );
/* The MEM_Dyn bit is set if and only if Mem.xDel is a non-NULL destructor
** function for Mem.z
*/
assert( (p->flags & MEM_Dyn)==0 || p->xDel!=0 );
assert( (p->flags & MEM_Dyn)!=0 || p->xDel==0 );
/* If p holds a string or blob, the Mem.z must point to exactly
** one of the following:
**
** (1) Memory in Mem.zMalloc and managed by the Mem object
** (2) Memory to be freed using Mem.xDel
** (3) An ephermal string or blob
** (4) A static string or blob
*/
if( (p->flags & (MEM_Str|MEM_Blob)) && p->z!=0 ){
assert(
((p->z==p->zMalloc)? 1 : 0) +
((p->flags&MEM_Dyn)!=0 ? 1 : 0) +
((p->flags&MEM_Ephem)!=0 ? 1 : 0) +
((p->flags&MEM_Static)!=0 ? 1 : 0) == 1
);
}
return 1;
}
#endif
@ -103,7 +121,7 @@ int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n);
}
if( pMem->zMalloc==0 ){
sqlite3VdbeMemRelease(pMem);
VdbeMemRelease(pMem);
pMem->flags = MEM_Null;
return SQLITE_NOMEM;
}
@ -112,13 +130,13 @@ int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
if( pMem->z && bPreserve && pMem->z!=pMem->zMalloc ){
memcpy(pMem->zMalloc, pMem->z, pMem->n);
}
if( (pMem->flags&MEM_Dyn)!=0 && pMem->xDel ){
assert( pMem->xDel!=SQLITE_DYNAMIC );
if( (pMem->flags&MEM_Dyn)!=0 ){
assert( pMem->xDel!=0 && pMem->xDel!=SQLITE_DYNAMIC );
pMem->xDel((void *)(pMem->z));
}
pMem->z = pMem->zMalloc;
pMem->flags &= ~(MEM_Ephem|MEM_Static);
pMem->flags &= ~(MEM_Dyn|MEM_Ephem|MEM_Static);
pMem->xDel = 0;
return SQLITE_OK;
}
@ -287,9 +305,9 @@ void sqlite3VdbeMemReleaseExternal(Mem *p){
sqlite3VdbeMemFinalize(p, p->u.pDef);
assert( (p->flags & MEM_Agg)==0 );
sqlite3VdbeMemRelease(p);
}else if( p->flags&MEM_Dyn && p->xDel ){
}else if( p->flags&MEM_Dyn ){
assert( (p->flags&MEM_RowSet)==0 );
assert( p->xDel!=SQLITE_DYNAMIC );
assert( p->xDel!=SQLITE_DYNAMIC && p->xDel!=0 );
p->xDel((void *)p->z);
p->xDel = 0;
}else if( p->flags&MEM_RowSet ){
@ -643,6 +661,7 @@ int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){
VdbeMemRelease(pTo);
memcpy(pTo, pFrom, MEMCELLSIZE);
pTo->flags &= ~MEM_Dyn;
pTo->xDel = 0;
if( pTo->flags&(MEM_Str|MEM_Blob) ){
if( 0==(pFrom->flags&MEM_Static) ){
@ -922,7 +941,7 @@ int sqlite3VdbeMemFromBtree(
pMem->z = &zData[offset];
pMem->flags = MEM_Blob|MEM_Ephem;
}else if( SQLITE_OK==(rc = sqlite3VdbeMemGrow(pMem, amt+2, 0)) ){
pMem->flags = MEM_Blob|MEM_Dyn|MEM_Term;
pMem->flags = MEM_Blob|MEM_Term;
pMem->enc = 0;
pMem->memType = MEM_Blob;
if( key ){