From defbd9dade8a135ebc79c14efafe1a22c0f99c94 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 1 Mar 2014 14:45:18 +0000 Subject: [PATCH 1/4] Add extra assert() statements trying to catch a Mem object in an inconsistent state. FossilOrigin-Name: 4aeb3ae435c78070232fef21a147fde4e1c5cd31 --- manifest | 21 ++++++++++++--------- manifest.uuid | 2 +- src/vdbe.c | 4 ++++ src/vdbeInt.h | 18 ++++++++++++++++++ src/vdbeaux.c | 1 + src/vdbemem.c | 8 ++------ 6 files changed, 38 insertions(+), 16 deletions(-) diff --git a/manifest b/manifest index 3686379a18..8fbb26ce51 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C In\sthe\scommand-line\sshell\sadd\sthe\s(undocumented\sand\sunsupported)\s".eqp"\ncommand\sand\s-eqp\scommand-line\soption,\sto\scause\sEXPLAIN\sQUERY\sPLAN\sto\sbe\nrun\son\seach\sSQL\sstatement\sas\sit\sis\sevaluated.\s\sIntended\suse\sis\sfor\sanalysis\nof\sthe\squery\splanner. -D 2014-02-28T20:47:24.221 +C Add\sextra\sassert()\sstatements\strying\sto\scatch\sa\sMem\sobject\sin\san\sinconsistent\nstate. +D 2014-03-01T14:45:18.939 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -277,13 +277,13 @@ F src/update.c 5b3e74a03b3811e586b4f2b4cbd7c49f01c93115 F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269 F src/util.c c46c90459ef9bdc0c6c73803cf4c55425b4771cf F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179 -F src/vdbe.c 6c8f28911e702151c8ef03c568db5a066d3a85d4 +F src/vdbe.c e9eda47b8d8410d35840589daf8f3177efa04478 F src/vdbe.h 147027d6e8e667a63e87177a38e2b42c71fdacf8 -F src/vdbeInt.h 5286af9067cabdb8ba57b87c0c988a931be6c6c8 +F src/vdbeInt.h fa0cadb90633d260f0c7d21f68a2ec5b1c6900e2 F src/vdbeapi.c 5bc41aaea448a7fc250902c418f1795859be3820 -F src/vdbeaux.c 8b8eeb3cd89e4b3d4f40186344915b49b7c1c0f7 +F src/vdbeaux.c 087e7c75643157a903c9794294f4ff45cec28e7e F src/vdbeblob.c d939997de046b8fcc607cfee4248f3d33dbcca50 -F src/vdbemem.c 06603e8e9d2f3247b68c6bbe4bd37fb6721b5bda +F src/vdbemem.c 7db453561091f0ed8fc7c96ee635cc612334025f F src/vdbesort.c 9d83601f9d6243fe70dd0169a2820c5ddfd48147 F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767 F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd @@ -1152,7 +1152,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff -P 0a3579d9b9d2a60bb85a9811bc7936edb88debae -R 195e6e751f71ffa9e9cfd28d6f8e532d +P e6ecf7337658624d664e1e71ba3fc527fd6578c1 +R ac78e315b388dc3aeb5c2c8983219f64 +T *branch * enhanced-mem-check +T *sym-enhanced-mem-check * +T -sym-trunk * U drh -Z d48791979092ee78fb00c8a21c663b3b +Z 099f8256c2a0fcf00ebef2162229fe0b diff --git a/manifest.uuid b/manifest.uuid index 6108cf5bed..aa3e8c1f3c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e6ecf7337658624d664e1e71ba3fc527fd6578c1 \ No newline at end of file +4aeb3ae435c78070232fef21a147fde4e1c5cd31 \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index 5ab0127658..cca69092a2 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -600,18 +600,21 @@ int sqlite3VdbeExec( assert( pOp->p1>0 ); assert( pOp->p1<=(p->nMem-p->nCursor) ); assert( memIsValid(&aMem[pOp->p1]) ); + assert( memSanity1(&aMem[pOp->p1]) ); REGISTER_TRACE(pOp->p1, &aMem[pOp->p1]); } if( (pOp->opflags & OPFLG_IN2)!=0 ){ assert( pOp->p2>0 ); assert( pOp->p2<=(p->nMem-p->nCursor) ); assert( memIsValid(&aMem[pOp->p2]) ); + assert( memSanity1(&aMem[pOp->p2]) ); REGISTER_TRACE(pOp->p2, &aMem[pOp->p2]); } if( (pOp->opflags & OPFLG_IN3)!=0 ){ assert( pOp->p3>0 ); assert( pOp->p3<=(p->nMem-p->nCursor) ); assert( memIsValid(&aMem[pOp->p3]) ); + assert( memSanity1(&aMem[pOp->p3]) ); REGISTER_TRACE(pOp->p3, &aMem[pOp->p3]); } if( (pOp->opflags & OPFLG_OUT2)!=0 ){ @@ -2460,6 +2463,7 @@ case OP_Column: { */ assert( p2nHdrParsed ); assert( rc==SQLITE_OK ); + assert( memSanity1(pDest) ); if( pC->szRow>=aOffset[p2+1] ){ /* This is the common case where the desired content fits on the original ** page - where the content is not on an overflow page */ diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 88c072adec..56ea39ffc3 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -232,6 +232,24 @@ struct Mem { #define memIsValid(M) ((M)->flags & MEM_Undefined)==0 #endif +/* +** A sanity check on a Mem object and especially the Mem.z field. +** This check says that no more than one of the following may be true: +** (1) Mem.z comes from Mem.zMalloc +** (2) Mem.z has a destructor Mem.xDel +** (3) Mem.z is an ephemeral string +** (4) Mem.z is a static string +** +** Use only inside of an assert() as follows: assert( memSanify(pMem) ); +*/ +#ifdef SQLITE_DEBUG +#define memSanity1(p) \ + ((((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 ) +#endif + /* ** Each auxilliary data pointer stored by a user defined function ** implementation calling sqlite3_set_auxdata() is stored in an instance diff --git a/src/vdbeaux.c b/src/vdbeaux.c index ef70f8ae3f..c22003f461 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -1220,6 +1220,7 @@ static void releaseMemArray(Mem *p, int N){ } for(pEnd=&p[N]; pz is discarded. */ int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){ - assert( 1 >= - ((pMem->zMalloc && pMem->zMalloc==pMem->z) ? 1 : 0) + - (((pMem->flags&MEM_Dyn)&&pMem->xDel) ? 1 : 0) + - ((pMem->flags&MEM_Ephem) ? 1 : 0) + - ((pMem->flags&MEM_Static) ? 1 : 0) - ); + assert( memSanity1(pMem) ); assert( (pMem->flags&MEM_RowSet)==0 ); /* If the bPreserve flag is set to true, then the memory cell must already @@ -292,6 +287,7 @@ void sqlite3VdbeMemReleaseExternal(Mem *p){ ** (Mem.memType==MEM_Str). */ void sqlite3VdbeMemRelease(Mem *p){ + assert( memSanity1(p) ); VdbeMemRelease(p); if( p->zMalloc ){ sqlite3DbFree(p->db, p->zMalloc); From 75fd054201c0ba287252bd53b6fd60067fc2c409 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 1 Mar 2014 16:24:44 +0000 Subject: [PATCH 2/4] Factor the Mem invariant checker into a separate procedure (rather than a macro) so that it can be more easily extended. FossilOrigin-Name: 354699d50e7d251504a7b3d6fbec9e5bcf99557f --- manifest | 21 +++++++++------------ manifest.uuid | 2 +- src/vdbe.c | 8 ++++---- src/vdbeInt.h | 19 +------------------ src/vdbeaux.c | 2 +- src/vdbemem.c | 22 ++++++++++++++++++++-- 6 files changed, 36 insertions(+), 38 deletions(-) diff --git a/manifest b/manifest index 8fbb26ce51..75bec54679 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sextra\sassert()\sstatements\strying\sto\scatch\sa\sMem\sobject\sin\san\sinconsistent\nstate. -D 2014-03-01T14:45:18.939 +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 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -277,13 +277,13 @@ F src/update.c 5b3e74a03b3811e586b4f2b4cbd7c49f01c93115 F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269 F src/util.c c46c90459ef9bdc0c6c73803cf4c55425b4771cf F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179 -F src/vdbe.c e9eda47b8d8410d35840589daf8f3177efa04478 +F src/vdbe.c 9abaa1ebb8b98e33121ea1aade1022fdc195b464 F src/vdbe.h 147027d6e8e667a63e87177a38e2b42c71fdacf8 -F src/vdbeInt.h fa0cadb90633d260f0c7d21f68a2ec5b1c6900e2 +F src/vdbeInt.h a82d5ab4fd8138bdff7de4a267ea5c04e4cbb370 F src/vdbeapi.c 5bc41aaea448a7fc250902c418f1795859be3820 -F src/vdbeaux.c 087e7c75643157a903c9794294f4ff45cec28e7e +F src/vdbeaux.c 2f97cd756e2704b06006b398ce468f0bcc006055 F src/vdbeblob.c d939997de046b8fcc607cfee4248f3d33dbcca50 -F src/vdbemem.c 7db453561091f0ed8fc7c96ee635cc612334025f +F src/vdbemem.c 8c84ec056c7934cef359f4d49fa32b856eeffd88 F src/vdbesort.c 9d83601f9d6243fe70dd0169a2820c5ddfd48147 F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767 F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd @@ -1152,10 +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 e6ecf7337658624d664e1e71ba3fc527fd6578c1 -R ac78e315b388dc3aeb5c2c8983219f64 -T *branch * enhanced-mem-check -T *sym-enhanced-mem-check * -T -sym-trunk * +P 4aeb3ae435c78070232fef21a147fde4e1c5cd31 +R c42d4082e634170a16f76850fb72106d U drh -Z 099f8256c2a0fcf00ebef2162229fe0b +Z e1bae2e998058d57d79a76345aaf3403 diff --git a/manifest.uuid b/manifest.uuid index aa3e8c1f3c..7b0fa50ebd 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4aeb3ae435c78070232fef21a147fde4e1c5cd31 \ No newline at end of file +354699d50e7d251504a7b3d6fbec9e5bcf99557f \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index cca69092a2..c8e837b81b 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -600,21 +600,21 @@ int sqlite3VdbeExec( assert( pOp->p1>0 ); assert( pOp->p1<=(p->nMem-p->nCursor) ); assert( memIsValid(&aMem[pOp->p1]) ); - assert( memSanity1(&aMem[pOp->p1]) ); + assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p1]) ); REGISTER_TRACE(pOp->p1, &aMem[pOp->p1]); } if( (pOp->opflags & OPFLG_IN2)!=0 ){ assert( pOp->p2>0 ); assert( pOp->p2<=(p->nMem-p->nCursor) ); assert( memIsValid(&aMem[pOp->p2]) ); - assert( memSanity1(&aMem[pOp->p2]) ); + assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p2]) ); REGISTER_TRACE(pOp->p2, &aMem[pOp->p2]); } if( (pOp->opflags & OPFLG_IN3)!=0 ){ assert( pOp->p3>0 ); assert( pOp->p3<=(p->nMem-p->nCursor) ); assert( memIsValid(&aMem[pOp->p3]) ); - assert( memSanity1(&aMem[pOp->p3]) ); + assert( sqlite3VdbeCheckMemInvariants(&aMem[pOp->p3]) ); REGISTER_TRACE(pOp->p3, &aMem[pOp->p3]); } if( (pOp->opflags & OPFLG_OUT2)!=0 ){ @@ -2463,7 +2463,7 @@ case OP_Column: { */ assert( p2nHdrParsed ); assert( rc==SQLITE_OK ); - assert( memSanity1(pDest) ); + assert( sqlite3VdbeCheckMemInvariants(pDest) ); if( pC->szRow>=aOffset[p2+1] ){ /* This is the common case where the desired content fits on the original ** page - where the content is not on an overflow page */ diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 56ea39ffc3..047a4f2697 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -232,24 +232,6 @@ struct Mem { #define memIsValid(M) ((M)->flags & MEM_Undefined)==0 #endif -/* -** A sanity check on a Mem object and especially the Mem.z field. -** This check says that no more than one of the following may be true: -** (1) Mem.z comes from Mem.zMalloc -** (2) Mem.z has a destructor Mem.xDel -** (3) Mem.z is an ephemeral string -** (4) Mem.z is a static string -** -** Use only inside of an assert() as follows: assert( memSanify(pMem) ); -*/ -#ifdef SQLITE_DEBUG -#define memSanity1(p) \ - ((((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 ) -#endif - /* ** Each auxilliary data pointer stored by a user defined function ** implementation calling sqlite3_set_auxdata() is stored in an instance @@ -474,6 +456,7 @@ int sqlite3VdbeSorterCompare(const VdbeCursor *, Mem *, int, int *); #ifdef SQLITE_DEBUG void sqlite3VdbeMemAboutToChange(Vdbe*,Mem*); +int sqlite3VdbeCheckMemInvariants(Mem*); #endif #ifndef SQLITE_OMIT_FOREIGN_KEY diff --git a/src/vdbeaux.c b/src/vdbeaux.c index c22003f461..4a541e0d48 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -1220,7 +1220,7 @@ static void releaseMemArray(Mem *p, int N){ } for(pEnd=&p[N]; pzMalloc && (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 ); + return 1; +} +#endif + + /* ** If pMem is an object with a valid string representation, this routine ** ensures the internal encoding for the string representation is @@ -67,7 +85,7 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ ** in pMem->z is discarded. */ int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){ - assert( memSanity1(pMem) ); + assert( sqlite3VdbeCheckMemInvariants(pMem) ); assert( (pMem->flags&MEM_RowSet)==0 ); /* If the bPreserve flag is set to true, then the memory cell must already @@ -287,7 +305,7 @@ void sqlite3VdbeMemReleaseExternal(Mem *p){ ** (Mem.memType==MEM_Str). */ void sqlite3VdbeMemRelease(Mem *p){ - assert( memSanity1(p) ); + assert( sqlite3VdbeCheckMemInvariants(p) ); VdbeMemRelease(p); if( p->zMalloc ){ sqlite3DbFree(p->db, p->zMalloc); From c91b2fd310e4138b1a36c3f3c418a21a6c2ae895 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 1 Mar 2014 18:13:23 +0000 Subject: [PATCH 3/4] 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 --- manifest | 20 ++++++++++---------- manifest.uuid | 2 +- src/utf.c | 3 +-- src/vdbe.c | 23 ++++++++++++----------- src/vdbeInt.h | 2 +- src/vdbeaux.c | 6 +++--- src/vdbemem.c | 43 +++++++++++++++++++++++++++++++------------ 7 files changed, 59 insertions(+), 40 deletions(-) diff --git a/manifest b/manifest index 75bec54679..5a221fb21d 100644 --- a/manifest +++ b/manifest @@ -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 diff --git a/manifest.uuid b/manifest.uuid index 7b0fa50ebd..764bf41b7a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -354699d50e7d251504a7b3d6fbec9e5bcf99557f \ No newline at end of file +44e1c33767cae3bf2cbd2238831fe67197009b43 \ No newline at end of file diff --git a/src/utf.c b/src/utf.c index ecb3ea03b8..96b679fff4 100644 --- a/src/utf.c +++ b/src/utf.c @@ -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; } diff --git a/src/vdbe.c b/src/vdbe.c index c8e837b81b..8e5a3da00f 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -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; diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 047a4f2697..c16baff685 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -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 */ diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 4a541e0d48..39be964093 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -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; diff --git a/src/vdbemem.c b/src/vdbemem.c index 532cd58d9e..3c9412a700 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -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 ){ From fbf0f0e1f636718d7c6541b5e2d88a4710bc98fc Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 3 Mar 2014 14:20:30 +0000 Subject: [PATCH 4/4] Fix a segfault that can occur following an OOM error. FossilOrigin-Name: 7fdd378d54754a3ffdc01c6c0a66cf6d5899a495 --- manifest | 15 +++++++-------- manifest.uuid | 2 +- src/where.c | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index e3e4bab9d6..86c4f75cc8 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Change\sthe\sMEM_Dyn\sflag\sso\sthat\sit\smeans\sthat\sMem.xDel\sexists\sand\smust\s\nbe\sused\sto\sfree\sthe\sstring\sor\sblob.\sAdd\stighter\sinvariant\schecks\son\sMem. -D 2014-03-03T00:12:39.825 +C Fix\sa\ssegfault\sthat\scan\soccur\sfollowing\san\sOOM\serror. +D 2014-03-03T14:20:30.542 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 2ef13430cd359f7b361bb863504e227b25cc7f81 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -290,7 +290,7 @@ F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd F src/wal.c 76e7fc6de229bea8b30bb2539110f03a494dc3a8 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 11edb74d587bc87b33ca96a5173e3ec1b8389e45 -F src/where.c 6042e1a377cf7dc72c10493269ed75e276275cd8 +F src/where.c e4b57d81d2a5fece518c1419f047f0803483f90c F src/whereInt.h 921f935af8b684ffb49705610bda7284db1db138 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -1152,8 +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 e6ecf7337658624d664e1e71ba3fc527fd6578c1 44e1c33767cae3bf2cbd2238831fe67197009b43 -R 0950c7cf1a1151e6071aa7a5599d1f4e -T +closed 44e1c33767cae3bf2cbd2238831fe67197009b43 -U drh -Z 4d8fd5c0a86772bcec65a15ca628db9f +P e3f6c61e0333d4d237dcd2ba2e404f0a91ee5069 +R eaec45cec313455580b422d7721ccfeb +U dan +Z 0f4ad0e1bfa9fac79dc39c1726a86e9b diff --git a/manifest.uuid b/manifest.uuid index eadf23b042..e37ef738a9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e3f6c61e0333d4d237dcd2ba2e404f0a91ee5069 \ No newline at end of file +7fdd378d54754a3ffdc01c6c0a66cf6d5899a495 \ No newline at end of file diff --git a/src/where.c b/src/where.c index a5dd7b59e7..f13d2b5044 100644 --- a/src/where.c +++ b/src/where.c @@ -5870,7 +5870,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ ** the co-routine into OP_SCopy of result contained in a register. ** OP_Rowid becomes OP_Null. */ - if( pTabItem->viaCoroutine ){ + if( pTabItem->viaCoroutine && !db->mallocFailed ){ last = sqlite3VdbeCurrentAddr(v); k = pLevel->addrBody; pOp = sqlite3VdbeGetOp(v, k);