From 4bf96311af1148da2a1b1e38b0e66abc62cf8d97 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 30 Jan 2016 14:53:06 +0000 Subject: [PATCH] Take care to clear the subtype on VDBE registers when the value of the register is overwritten with new content. Fix for ticket [f45ac567eaa9f93]. FossilOrigin-Name: ec653cbcae74ecab4ec9df0548d5836e81dc5d14 --- manifest | 20 ++++++++++---------- manifest.uuid | 2 +- src/vdbe.c | 4 ++-- src/vdbeInt.h | 16 ++++++++++++++-- src/vdbeapi.c | 6 ++++-- src/vdbemem.c | 11 ++++++----- test/json103.test | 15 ++++++++++++++- 7 files changed, 51 insertions(+), 23 deletions(-) diff --git a/manifest b/manifest index c42504832e..04cad955de 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Output\ssubtype\sinformation\son\sregister\straces\sfor\sPRAGMA\svdbe_trace. -D 2016-01-30T14:17:10.486 +C Take\scare\sto\sclear\sthe\ssubtype\son\sVDBE\sregisters\swhen\sthe\svalue\sof\sthe\nregister\sis\soverwritten\swith\snew\scontent.\nFix\sfor\sticket\s[f45ac567eaa9f93]. +D 2016-01-30T14:53:06.723 F Makefile.in 027c1603f255390c43a426671055a31c0a65fdb4 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.msc 72b7858f02017611c3ac1ddc965251017fed0845 @@ -412,13 +412,13 @@ F src/update.c 17332f9fe818cbc0444c36a811800af8498af4c3 F src/utf.c 32d7f82aa921322f3e1c956f4b58f019ebd2c6b3 F src/util.c 72d40df0a52d3f30b462a15f0e094fcbade6dc82 F src/vacuum.c 2ddd5cad2a7b9cef7f9e431b8c7771634c6b1701 -F src/vdbe.c bd4d2cabbafe49bd8e04d7bf57d8e480393268d9 +F src/vdbe.c dadd57758548a100024ba6f353fadc4eb3c40262 F src/vdbe.h 7a733ea8aac1b77305a67698e784fa3484ee3337 -F src/vdbeInt.h 716df83ac45b70ff000b515040ea606d0cb5d0f3 -F src/vdbeapi.c ffae8f5af4570fbd548504e815e9fb7227f0822e +F src/vdbeInt.h 6c34fac6099bea72be4d6f95e39869e53543e555 +F src/vdbeapi.c 59412373ec89e075bd7b4c5e497527c8d2d9ad5b F src/vdbeaux.c 221631e40111b5efa96ea557c6e2e7f62fd32b2a F src/vdbeblob.c 37c3d11a753e403698c69e17383d282e1ae73e75 -F src/vdbemem.c b9181e77eca2a095929d46250daf85c8d2621fc0 +F src/vdbemem.c e0a3c3641efb3aec29cf3aaad8bc1a2d4c207e51 F src/vdbesort.c ef3c6d1f1a7d44cf67bb2bee59ea3d1fe5bad174 F src/vdbetrace.c f75c5455d8cf389ef86a8bfdfd3177e0e3692484 F src/vtab.c 320682cca733115b4cbe71320b5c5eeb1074ebde @@ -834,7 +834,7 @@ F test/jrnlmode2.test 81610545a4e6ed239ea8fa661891893385e23a1d F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa F test/json101.test f0178422b3a2418f423fd0d3caf3571c8d1b9863 F test/json102.test bf3fe7a706d30936a76a0f7a0375e1e8e73aff5a -F test/json103.test 923b288a0610ec86c0951778f7db19cbcca36ad1 +F test/json103.test c5f6b85e69de05f6b3195f9f9d5ce9cd179099a0 F test/keyword1.test 37ef6bba5d2ed5b07ecdd6810571de2956599dff F test/lastinsert.test 42e948fd6442f07d60acbd15d33fb86473e0ef63 F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200 @@ -1422,7 +1422,7 @@ F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 85c467041c9378cae3038756da815e9117ee8c7d -R 694b551c33162b646e920ddc57abdc60 +P 96b780209cc95c3f3769bb880591380d94bfe38d +R cda843daa207cb621eb4e573d679a633 U drh -Z fd54d0de297ea145965f78cad2cde9ad +Z e2b95eab505f3941b006aa1f7f82d1ae diff --git a/manifest.uuid b/manifest.uuid index 6041e7c246..da4d3ac28c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -96b780209cc95c3f3769bb880591380d94bfe38d \ No newline at end of file +ec653cbcae74ecab4ec9df0548d5836e81dc5d14 \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index ebb7e046fe..73c9d200b8 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -532,7 +532,7 @@ static Mem *out2Prerelease(Vdbe *p, VdbeOp *pOp){ assert( pOp->p2<=(p->nMem-p->nCursor) ); pOut = &p->aMem[pOp->p2]; memAboutToChange(p, pOut); - if( VdbeMemDynamic(pOut) ){ + if( VdbeMemDynamicOrSubtype(pOut) ){ return out2PrereleaseWithClear(pOut); }else{ pOut->flags = MEM_Int; @@ -2558,7 +2558,7 @@ case OP_Column: { assert( p2nHdrParsed ); assert( rc==SQLITE_OK ); assert( sqlite3VdbeCheckMemInvariants(pDest) ); - if( VdbeMemDynamic(pDest) ) sqlite3VdbeMemSetNull(pDest); + if( VdbeMemDynamicOrSubtype(pDest) ) sqlite3VdbeMemSetNull(pDest); assert( t==pC->aType[p2] ); pDest->enc = encoding; if( pC->szRow>=aOffset[p2+1] ){ diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 497beb87d5..72f8fdeac7 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -252,11 +252,25 @@ struct Mem { #define MEM_Ephem 0x1000 /* Mem.z points to an ephemeral string */ #define MEM_Agg 0x2000 /* Mem.z points to an agg function context */ #define MEM_Zero 0x4000 /* Mem.i contains count of 0s appended to blob */ +#define MEM_Subtype 0x8000 /* Mem.eSubtype might be non-zero */ #ifdef SQLITE_OMIT_INCRBLOB #undef MEM_Zero #define MEM_Zero 0x0000 #endif +/* Return TRUE if Mem X contains dynamically allocated content - anything +** that needs to be deallocated to avoid a leak. +*/ +#define VdbeMemDynamic(X) \ + (((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))!=0) + +/* Return TRUE if MEM x contains dynamically allocated content, or if +** x might have a non-zero subtype +*/ +#define VdbeMemDynamicOrSubtype(X) \ + (((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame|MEM_Subtype))!=0) + + /* ** Clear any existing type flags from a Mem and replace them with f */ @@ -472,8 +486,6 @@ int sqlite3VdbeMemNumerify(Mem*); void sqlite3VdbeMemCast(Mem*,u8,u8); int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,int,Mem*); void sqlite3VdbeMemRelease(Mem *p); -#define VdbeMemDynamic(X) \ - (((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))!=0) int sqlite3VdbeMemFinalize(Mem*, FuncDef*); const char *sqlite3OpcodeName(int); int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve); diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 4bc912b940..db86fe9ef5 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -369,8 +369,10 @@ void sqlite3_result_null(sqlite3_context *pCtx){ sqlite3VdbeMemSetNull(pCtx->pOut); } void sqlite3_result_subtype(sqlite3_context *pCtx, unsigned int eSubtype){ - assert( sqlite3_mutex_held(pCtx->pOut->db->mutex) ); - pCtx->pOut->eSubtype = eSubtype & 0xff; + Mem *pOut = pCtx->pOut; + assert( sqlite3_mutex_held(pOut->db->mutex) ); + pOut->eSubtype = eSubtype & 0xff; + pOut->flags |= MEM_Subtype; } void sqlite3_result_text( sqlite3_context *pCtx, diff --git a/src/vdbemem.c b/src/vdbemem.c index 0eeb59ef85..2dc91d5cdf 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -358,7 +358,7 @@ int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){ */ static SQLITE_NOINLINE void vdbeMemClearExternAndSetNull(Mem *p){ assert( p->db==0 || sqlite3_mutex_held(p->db->mutex) ); - assert( VdbeMemDynamic(p) ); + assert( VdbeMemDynamicOrSubtype(p) ); if( p->flags&MEM_Agg ){ sqlite3VdbeMemFinalize(p, p->u.pDef); assert( (p->flags & MEM_Agg)==0 ); @@ -376,6 +376,7 @@ static SQLITE_NOINLINE void vdbeMemClearExternAndSetNull(Mem *p){ pFrame->v->pDelFrame = pFrame; } p->flags = MEM_Null; + p->eSubtype = 0; } /* @@ -387,7 +388,7 @@ static SQLITE_NOINLINE void vdbeMemClearExternAndSetNull(Mem *p){ ** to be freed. */ static SQLITE_NOINLINE void vdbeMemClear(Mem *p){ - if( VdbeMemDynamic(p) ){ + if( VdbeMemDynamicOrSubtype(p) ){ vdbeMemClearExternAndSetNull(p); } if( p->szMalloc ){ @@ -409,7 +410,7 @@ static SQLITE_NOINLINE void vdbeMemClear(Mem *p){ */ void sqlite3VdbeMemRelease(Mem *p){ assert( sqlite3VdbeCheckMemInvariants(p) ); - if( VdbeMemDynamic(p) || p->szMalloc ){ + if( VdbeMemDynamicOrSubtype(p) || p->szMalloc ){ vdbeMemClear(p); } } @@ -648,7 +649,7 @@ void sqlite3VdbeMemInit(Mem *pMem, sqlite3 *db, u16 flags){ ** Use sqlite3VdbeMemRelease() to complete erase the Mem prior to abandoning it. */ void sqlite3VdbeMemSetNull(Mem *pMem){ - if( VdbeMemDynamic(pMem) ){ + if( VdbeMemDynamicOrSubtype(pMem) ){ vdbeMemClearExternAndSetNull(pMem); }else{ pMem->flags = MEM_Null; @@ -688,7 +689,7 @@ static SQLITE_NOINLINE void vdbeReleaseAndSetInt64(Mem *pMem, i64 val){ ** manifest type INTEGER. */ void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){ - if( VdbeMemDynamic(pMem) ){ + if( VdbeMemDynamicOrSubtype(pMem) ){ vdbeReleaseAndSetInt64(pMem, val); }else{ pMem->u.i = val; diff --git a/test/json103.test b/test/json103.test index 0f0241e6fc..d7d12e3378 100644 --- a/test/json103.test +++ b/test/json103.test @@ -60,6 +60,19 @@ do_execsql_test json103-220 { WHERE rowid<7 GROUP BY b ORDER BY b; } {0 {{"n3":3,"n6":6}} 1 {{"n1":1,"n4":4}} 2 {{"n2":2,"n5":5}}} - +# ticket https://www.sqlite.org/src/info/f45ac567eaa9f93c 2016-01-30 +# Invalid JSON generated by json_group_array() +# +# The underlying problem is a failure to reset Mem.eSubtype +# +do_execsql_test json103-300 { + DROP TABLE IF EXISTS t1; + CREATE TABLE t1(x); + INSERT INTO t1 VALUES(1),('abc'); + SELECT + json_group_array(x), + json_group_array(json_object('x',x)) + FROM t1; +} {{[1,"abc"]} {[{"x":1},{"x":"abc"}]}} finish_test