diff --git a/manifest b/manifest index 4f54fd9f5d..a2529d2cb2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Change\ssome\sassert()\sstatements\sin\svdbe.c\sto\sensure\sthat\sa\smemory\scell\sused\sto\sstore\sa\sVdbeCursor\sobject\sis\snot\salso\sused\sfor\ssome\sother\spurpose. -D 2013-08-15T16:18:39.664 +C Fix\sa\scrash\sthat\scan\soccur\sfollowing\san\sOOM\sfault. +D 2013-08-15T18:43:21.395 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -283,7 +283,7 @@ F src/vdbeInt.h e9b7c6b165a31a4715c5aa97223d20d265515231 F src/vdbeapi.c 4d13580bd058b39623e8fcfc233b7df4b8191e8b F src/vdbeaux.c a6ea36a9dc714e1128a0173249a0532ddcab0489 F src/vdbeblob.c 5dc79627775bd9a9b494dd956e26297946417d69 -F src/vdbemem.c 7ec9a78d6d4b2d4ebb4d3fd9b706065146616019 +F src/vdbemem.c c08dd81009fd6708dbb961d8ec7f82549765d680 F src/vdbesort.c 3937e06b2a0e354500e17dc206ef4c35770a5017 F src/vdbetrace.c e7ec40e1999ff3c6414424365d5941178966dcbc F src/vtab.c 2e8b489db47e20ae36cd247932dc671c9ded0624 @@ -308,7 +308,7 @@ F test/analyze5.test 765c4e284aa69ca172772aa940946f55629bc8c4 F test/analyze6.test 19151da2c4e918905d2081b74ac5c4d47fc850ab F test/analyze7.test bb1409afc9e8629e414387ef048b8e0e3e0bdc4f F test/analyze8.test 093d15c1c888eed5034304a98c992f7360130b88 -F test/analyze9.test b018c837164ada65f4a80dadbbcdc89cb1fff362 +F test/analyze9.test 83e74db42a49bb185e05f3a44a5d65323aba8a40 F test/analyzeA.test 1a5c40079894847976d983ca39c707aaa44b6944 F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b @@ -651,7 +651,7 @@ F test/malloc6.test 2f039d9821927eacae43e1831f815e157659a151 F test/malloc7.test 7c68a32942858bc715284856c5507446bba88c3a F test/malloc8.test 9b7a3f8cb9cf0b12fff566e80a980b1767bd961d F test/malloc9.test 2307c6ee3703b0a21391f3ea92388b4b73f9105e -F test/mallocA.test 47006c8d70f29b030652e251cb9d35ba60289198 +F test/mallocA.test 71e4b57e640c017cf2833e51fe6e8e43e8575b73 F test/mallocAll.test 98f1be74bc9f49a858bc4f361fc58e26486798be F test/mallocB.test bc475ab850cda896142ab935bbfbc74c24e51ed6 F test/mallocC.test 3dffe16532f109293ce1ccecd0c31dca55ef08c4 @@ -1107,7 +1107,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 46fec9b1a1c4616df5a634dbf9235bd13408d3a9 -R e1ce93ce8d017990abe28f4c9f5b58f9 +P 71070c9fce86103f174220e07771df99b2e01405 +R fd0e4baaf9a9ffd0fe23644f24c090cf U dan -Z 9abc3408e2534a3305d7999552dece52 +Z 1c4d6e6edcc7281c470c7559e77faff9 diff --git a/manifest.uuid b/manifest.uuid index e48df0d900..f0c5e4a7e1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -71070c9fce86103f174220e07771df99b2e01405 \ No newline at end of file +9f80b2687012ab7c4d6d654fe19f40878bd78bd8 \ No newline at end of file diff --git a/src/vdbemem.c b/src/vdbemem.c index db3e6b262e..b75e86b035 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -1006,29 +1006,85 @@ sqlite3_value *sqlite3ValueNew(sqlite3 *db){ } /* -** Argument pCtx is actually a pointer to a database handle. Allocate and -** return an sqlite3_value object associated with this database handle. -** -** This function used as the xAlloc callback for valueFromExpr() when -** it is called by sqlite3ValueFromExpr(). +** Context object passed by sqlite3Stat4ProbeSetValue() through to +** valueNew(). See comments above valueNew() for details. */ -static sqlite3_value *valueNew(void *pCtx){ - return sqlite3ValueNew((sqlite3*)pCtx); +struct ValueNewStat4Ctx { + Parse *pParse; + Index *pIdx; + UnpackedRecord **ppRec; + int iVal; +}; + +/* +** Allocate and return a pointer to a new sqlite3_value object. If +** the second argument to this function is NULL, the object is allocated +** by calling sqlite3ValueNew(). +** +** Otherwise, if the second argument is non-zero, then this function is +** being called indirectly by sqlite3Stat4ProbeSetValue(). If it has not +** already been allocated, allocate the UnpackedRecord structure that +** that function will return to its caller here. Then return a pointer +** an sqlite3_value within the UnpackedRecord.a[] array. +*/ +static sqlite3_value *valueNew(sqlite3 *db, struct ValueNewStat4Ctx *p){ +#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_ENABLE_STAT3) + if( p ){ + UnpackedRecord *pRec = p->ppRec[0]; + + if( pRec==0 ){ + Index *pIdx = p->pIdx; /* Index being probed */ + int nByte; /* Bytes of space to allocate */ + int i; /* Counter variable */ + int nCol = pIdx->nColumn+1; /* Number of index columns including rowid */ + + nByte = sizeof(Mem) * nCol + sizeof(UnpackedRecord); + pRec = (UnpackedRecord*)sqlite3DbMallocZero(db, nByte); + if( pRec ){ + pRec->pKeyInfo = sqlite3IndexKeyinfo(p->pParse, pIdx); + if( pRec->pKeyInfo ){ + assert( pRec->pKeyInfo->nField+1==nCol ); + pRec->pKeyInfo->enc = ENC(db); + pRec->flags = UNPACKED_PREFIX_MATCH; + pRec->aMem = (Mem *)&pRec[1]; + for(i=0; iaMem[i].flags = MEM_Null; + pRec->aMem[i].type = SQLITE_NULL; + pRec->aMem[i].db = db; + } + }else{ + sqlite3DbFree(db, pRec); + pRec = 0; + } + } + if( pRec==0 ) return 0; + p->ppRec[0] = pRec; + } + + pRec->nField = p->iVal+1; + return &pRec->aMem[p->iVal]; + } +#endif + return sqlite3ValueNew(db); } /* -** This function is the same as sqlite3ValueFromExpr(), except that instead -** of allocating any required sqlite3_value object by calling -** sqlite3ValueNew(), it does so by calling the supplied xAlloc hook. +** Extract a value from the supplied expression in the manner described +** above sqlite3ValueFromExpr(). Allocate the sqlite3_value object +** using valueNew(). +** +** If pCtx is NULL and an error occurs after the sqlite3_value object +** has been allocated, it is freed before returning. Or, if pCtx is not +** NULL, it is assumed that the caller will free any allocated object +** in all cases. */ int valueFromExpr( - sqlite3 *db, /* The database connection */ - Expr *pExpr, /* The expression to evaluate */ - u8 enc, /* Encoding to use */ - u8 affinity, /* Affinity to use */ - sqlite3_value **ppVal, /* Write the new value here */ - sqlite3_value *(*xAlloc)(void*), /* Used to allocate new sqlite3_value */ - void *pAlloc /* Argument passed to xAlloc */ + sqlite3 *db, /* The database connection */ + Expr *pExpr, /* The expression to evaluate */ + u8 enc, /* Encoding to use */ + u8 affinity, /* Affinity to use */ + sqlite3_value **ppVal, /* Write the new value here */ + struct ValueNewStat4Ctx *pCtx /* Second argument for valueNew() */ ){ int op; char *zVal = 0; @@ -1064,7 +1120,7 @@ int valueFromExpr( } if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){ - pVal = xAlloc(pAlloc); + pVal = valueNew(db, pCtx); if( pVal==0 ) goto no_mem; if( ExprHasProperty(pExpr, EP_IntValue) ){ sqlite3VdbeMemSetInt64(pVal, (i64)pExpr->u.iValue*negInt); @@ -1100,7 +1156,7 @@ int valueFromExpr( sqlite3ValueApplyAffinity(pVal, affinity, enc); } }else if( op==TK_NULL ){ - pVal = xAlloc(pAlloc); + pVal = valueNew(db, pCtx); if( pVal==0 ) goto no_mem; } #ifndef SQLITE_OMIT_BLOB_LITERAL @@ -1108,7 +1164,7 @@ int valueFromExpr( int nVal; assert( pExpr->u.zToken[0]=='x' || pExpr->u.zToken[0]=='X' ); assert( pExpr->u.zToken[1]=='\'' ); - pVal = xAlloc(pAlloc); + pVal = valueNew(db, pCtx); if( !pVal ) goto no_mem; zVal = &pExpr->u.zToken[2]; nVal = sqlite3Strlen30(zVal)-1; @@ -1127,8 +1183,8 @@ int valueFromExpr( no_mem: db->mallocFailed = 1; sqlite3DbFree(db, zVal); - if( *ppVal==0 ) sqlite3ValueFree(pVal); - *ppVal = 0; + assert( *ppVal==0 ); + if( pCtx==0 ) sqlite3ValueFree(pVal); return SQLITE_NOMEM; } @@ -1149,7 +1205,7 @@ int sqlite3ValueFromExpr( u8 affinity, /* Affinity to use */ sqlite3_value **ppVal /* Write the new value here */ ){ - return valueFromExpr(db, pExpr, enc, affinity, ppVal, valueNew, (void*)db); + return valueFromExpr(db, pExpr, enc, affinity, ppVal, 0); } #if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_ENABLE_STAT3) @@ -1207,64 +1263,6 @@ void sqlite3AnalyzeFunctions(void){ } } -/* -** A pointer to an instance of this object is passed as the context -** pointer to valueNewStat4() (see below. -*/ -struct ValueNewStat4Ctx { - Parse *pParse; - Index *pIdx; - UnpackedRecord **ppRec; - int iVal; -}; - -/* -** This function is used as the xAlloc function with valueFromExpr() when -** it is called by sqlite3Stat4ProbeSetValue(). The argument points to -** an object of type ValueNewStat4Ctx (see above). -** -** If it has not already been allocated, this function allocates an -** UnpackedRecord structure and space for up to N values, where N is the -** number of columns in the index being probed. -*/ -static sqlite3_value *valueNewStat4(void *pCtx){ - struct ValueNewStat4Ctx *p = (struct ValueNewStat4Ctx*)pCtx; - UnpackedRecord *pRec = p->ppRec[0]; - - if( pRec==0 ){ - sqlite3 *db = p->pParse->db; /* Database handle */ - Index *pIdx = p->pIdx; /* Index being probed */ - int nByte; /* Bytes of space to allocate */ - int i; /* Counter variable */ - int nCol = pIdx->nColumn+1; /* Number of index columns including rowid */ - - nByte = sizeof(Mem) * nCol + sizeof(UnpackedRecord); - pRec = (UnpackedRecord*)sqlite3DbMallocZero(db, nByte); - if( pRec ){ - pRec->pKeyInfo = sqlite3IndexKeyinfo(p->pParse, pIdx); - if( pRec->pKeyInfo ){ - assert( pRec->pKeyInfo->nField+1==nCol ); - pRec->pKeyInfo->enc = ENC(db); - pRec->flags = UNPACKED_PREFIX_MATCH; - pRec->aMem = (Mem *)&pRec[1]; - for(i=0; iaMem[i].flags = MEM_Null; - pRec->aMem[i].type = SQLITE_NULL; - pRec->aMem[i].db = db; - } - }else{ - sqlite3DbFree(db, pRec); - pRec = 0; - } - } - if( pRec==0 ) return 0; - p->ppRec[0] = pRec; - } - - pRec->nField = p->iVal+1; - return &pRec->aMem[p->iVal]; -} - /* ** This function is used to allocate and populate UnpackedRecord ** structures intended to be compared against sample index keys stored @@ -1313,12 +1311,8 @@ int sqlite3Stat4ProbeSetValue( alloc.ppRec = ppRec; alloc.iVal = iVal; -#if 0 - if( iVal>0 ){ *pbOk = 0; return SQLITE_OK; } -#endif - if( !pExpr ){ - pVal = valueNewStat4((void*)&alloc); + pVal = valueNew(pParse->db, &alloc); if( pVal ){ sqlite3VdbeMemSetNull((Mem*)pVal); *pbOk = 1; @@ -1330,7 +1324,7 @@ int sqlite3Stat4ProbeSetValue( int iVar = pExpr->iColumn; sqlite3VdbeSetVarmask(pParse->pVdbe, iVar); if( (v = pParse->pReprepare) ){ - pVal = valueNewStat4((void*)&alloc); + pVal = valueNew(pParse->db, &alloc); if( pVal ){ rc = sqlite3VdbeMemCopy((Mem*)pVal, &v->aVar[iVal-1]); if( rc==SQLITE_OK ){ @@ -1345,9 +1339,7 @@ int sqlite3Stat4ProbeSetValue( } }else{ sqlite3 *db = pParse->db; - rc = valueFromExpr( - db, pExpr, ENC(db), affinity, &pVal, valueNewStat4, (void*)&alloc - ); + rc = valueFromExpr(db, pExpr, ENC(db), affinity, &pVal, &alloc); *pbOk = (pVal!=0); } diff --git a/test/analyze9.test b/test/analyze9.test index 08e8126b24..21b354792b 100644 --- a/test/analyze9.test +++ b/test/analyze9.test @@ -256,6 +256,30 @@ do_execsql_test 4.6 { ('34', '68', '102', '136', '170', '204', '238', '272') } {8} +reset_db +do_test 4.7 { + execsql { + BEGIN; + CREATE TABLE t1(o,t INTEGER PRIMARY KEY); + CREATE INDEX i1 ON t1(o); + } + for {set i 0} {$i<10000} {incr i [expr (($i<1000)?1:10)]} { + execsql { INSERT INTO t1 VALUES('x', $i) } + } + execsql { + COMMIT; + ANALYZE; + SELECT count(*) FROM sqlite_stat4; + } +} {8} +do_execsql_test 4.8 { + SELECT test_decode(sample) FROM sqlite_stat4; +} { + {x 211} {x 423} {x 635} {x 847} + {x 1590} {x 3710} {x 5830} {x 7950} +} + + #------------------------------------------------------------------------- # The following would cause a crash at one point. # diff --git a/test/mallocA.test b/test/mallocA.test index 89951276f8..1e05723e13 100644 --- a/test/mallocA.test +++ b/test/mallocA.test @@ -15,6 +15,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/malloc_common.tcl +set testprefix mallocA # Only run these tests if memory debugging is turned on. # @@ -40,7 +41,6 @@ db eval { db close copy_file test.db test.db.bu - do_malloc_test mallocA-1 -testdb test.db.bu -sqlbody { ANALYZE } @@ -53,6 +53,7 @@ do_malloc_test mallocA-1.2 -testdb test.db.bu -sqlbody { do_malloc_test mallocA-1.3 -testdb test.db.bu -sqlbody { ANALYZE main.t1 } + ifcapable reindex { do_malloc_test mallocA-2 -testdb test.db.bu -sqlbody { REINDEX; @@ -68,6 +69,35 @@ ifcapable reindex { } } +reset_db +sqlite3_db_config_lookaside db 0 0 0 +do_execsql_test 6-prep { + CREATE TABLE t1(a, b); + CREATE INDEX i1 ON t1(a, b); + INSERT INTO t1 VALUES('abc', 'w'); -- rowid=1 + INSERT INTO t1 VALUES('abc', 'x'); -- rowid=2 + INSERT INTO t1 VALUES('abc', 'y'); -- rowid=3 + INSERT INTO t1 VALUES('abc', 'z'); -- rowid=4 + + INSERT INTO t1 VALUES('def', 'w'); -- rowid=5 + INSERT INTO t1 VALUES('def', 'x'); -- rowid=6 + INSERT INTO t1 VALUES('def', 'y'); -- rowid=7 + INSERT INTO t1 VALUES('def', 'z'); -- rowid=8 + + ANALYZE; +} + +do_faultsim_test 6.1 -faults oom* -body { + execsql { SELECT rowid FROM t1 WHERE a='abc' AND b='x' } +} -test { + faultsim_test_result [list 0 2] +} +do_faultsim_test 6.2 -faults oom* -body { + execsql { SELECT rowid FROM t1 WHERE a='abc' AND b<'y' } +} -test { + faultsim_test_result [list 0 {1 2}] +} + # Ensure that no file descriptors were leaked. do_test malloc-99.X { catch {db close}