From: dan Date: Wed, 29 Apr 2026 19:14:54 +0000 (+0000) Subject: Fix a crash that could occur if the destination database of a backup is X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;ds=inline;p=thirdparty%2Fsqlite.git Fix a crash that could occur if the destination database of a backup is replaced using sqlite3_deserialize() between the call to sqlite3_backup_init() and the first call to sqlite3_backup_step(). Forum post [forum:15d82885e2 | 15d82885e2]. FossilOrigin-Name: 1f940357f7bb160b583ac5b08ff4e32a9fef353255d032c5a18bcb04416c0f0b --- diff --git a/manifest b/manifest index a04e53a9b5..123547996d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Attempt\sto\salign\sinstances\sof\sthe\ssqlite3_mutex\sobject\sat\s128-byte\sboundaries\nto\sprevent\sfalse-sharing\sin\smulti-core\smachines.\sSee\sthe\sdiscussion\sat\sand\naround\s[forum:/forumpost/2026-03-25T23:15:03Z|forum\spost\s2026-03-25T23:15:03Z]. -D 2026-04-28T15:12:40.363 +C Fix\sa\scrash\sthat\scould\soccur\sif\sthe\sdestination\sdatabase\sof\sa\sbackup\sis\nreplaced\susing\ssqlite3_deserialize()\sbetween\sthe\scall\sto\ssqlite3_backup_init()\nand\sthe\sfirst\scall\sto\ssqlite3_backup_step().\sForum\spost\s[forum:15d82885e2\s|\s15d82885e2]. +D 2026-04-29T19:14:54.013 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -672,7 +672,7 @@ F src/alter.c 7d7ddbdc189f0e0c686e32ee170abdddc95c11f2089e40df4ffcee88f5334826 F src/analyze.c 03bcfc083fc0cccaa9ded93604e1d4244ea245c17285d463ef6a60425fcb247d F src/attach.c c58278c7d2d954785591c4fde81669ec3e4d52f348c453b028a19ae8adf4f338 F src/auth.c ebec42df26b34a62b6750d30d9c2c03554a1c522020182476f7729a439fef04f -F src/backup.c 5c97e8023aab1ce14a42387eb3ae00ba5a0644569e3476f38661fa6f824c3523 +F src/backup.c 95b97c120676e66b5479cd1d512aaf12ab653f7e68f404ccb79f17bf2d37910d F src/bitvec.c e242d4496774dfc88fa278177dd23b607dce369ccafb3f61b41638eea2c9b399 F src/btmutex.c 30dada73a819a1ef5b7583786370dce1842e12e1ad941e4d05ac29695528daea F src/btree.c 216ffbe197e330118a2999adc7d3f09b0e2eeb163df8746ba9a2b27fed3d4335 @@ -1424,7 +1424,7 @@ F test/malloctraceviewer.tcl 3e3ddf11e30d2b20f53aa16aa6615082fb24a100bea61cca721 F test/manydb.test 28385ae2087967aa05c38624cec7d96ec74feb3e F test/mem5.test c6460fba403c5703141348cd90de1c294188c68f F test/memdb.test c1f2a343ad14398d5d6debda6ea33e80d0dafcc7 -F test/memdb1.test 916093ae5ad097660a742890a9986d1f217a620ac95efb64884041ee4c408603 +F test/memdb1.test f89ca9b1c1f2482b1098614259106576dcace8b78ccd6d7cdb24edfa836fc05e F test/memdb2.test 4ba1fc09e2f51df80d148a540e4a3fa66d0462e91167b27497084de4d1f6b5b4 F test/memjournal.test 70f3a00c7f84ee2978ad14e831231caa1e7f23915a2c54b4f775a021d5740c6c F test/memjournal2.test dbc2c5cb5f7b38950f4f6dc3e73fcecf0fcbed3fc32c7ce913bba164d288da1e @@ -2203,8 +2203,8 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P d64a1dbe0fb2d9286806d833a3146b21d5bf1636a650d5a64cf163c7f2356e98 -R e7f5576deb3afe7b12491989f716c8e2 -U drh -Z 8f2b29d8666e7ca0a228448a291e99d6 +P 1786fcd5b4ee6cd9b4780f3687dfaec5b90ef0476e0da266a94e069b98e70514 +R 5b43b2d170e39f26e9627eaaeadf5925 +U dan +Z efb7538193cd694216b53a7535e0ddd9 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 33b63b5768..88f3ef2906 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1786fcd5b4ee6cd9b4780f3687dfaec5b90ef0476e0da266a94e069b98e70514 +1f940357f7bb160b583ac5b08ff4e32a9fef353255d032c5a18bcb04416c0f0b diff --git a/src/backup.c b/src/backup.c index 22615d1499..ecd569dbc7 100644 --- a/src/backup.c +++ b/src/backup.c @@ -20,13 +20,13 @@ */ struct sqlite3_backup { sqlite3* pDestDb; /* Destination database handle */ - Btree *pDest; /* Destination b-tree file */ + Db *pDest; /* Destination db file */ u32 iDestSchema; /* Original schema cookie in destination */ int bDestLocked; /* True once a write-transaction is open on pDest */ Pgno iNext; /* Page number of the next source page to copy */ sqlite3* pSrcDb; /* Source database handle */ - Btree *pSrc; /* Source b-tree file */ + Db *pSrc; /* Source db file */ int rc; /* Backup process error code */ @@ -79,7 +79,7 @@ struct sqlite3_backup { ** function. If an error occurs while doing so, return 0 and write an ** error message to pErrorDb. */ -static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){ +static Db *findDatabase(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){ int i = sqlite3FindDbName(pDb, zDb); if( i==1 ){ @@ -102,7 +102,7 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){ return 0; } - return pDb->aDb[i].pBt; + return &pDb->aDb[i]; } /* @@ -110,9 +110,9 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){ ** of the source. */ static int setDestPgsz(sqlite3_backup *p){ - int rc; - rc = sqlite3BtreeSetPageSize(p->pDest,sqlite3BtreeGetPageSize(p->pSrc),0,0); - return rc; + return sqlite3BtreeSetPageSize(p->pDest->pBt, + sqlite3BtreeGetPageSize(p->pSrc->pBt), 0, 0 + ); } /* @@ -181,15 +181,15 @@ sqlite3_backup *sqlite3_backup_init( /* If the allocation succeeded, populate the new object. */ if( p ){ - p->pSrc = findBtree(pDestDb, pSrcDb, zSrcDb); - p->pDest = findBtree(pDestDb, pDestDb, zDestDb); + p->pSrc = findDatabase(pDestDb, pSrcDb, zSrcDb); + p->pDest = findDatabase(pDestDb, pDestDb, zDestDb); p->pDestDb = pDestDb; p->pSrcDb = pSrcDb; p->iNext = 1; p->isAttached = 0; if( 0==p->pSrc || 0==p->pDest - || checkReadTransaction(pDestDb, p->pDest)!=SQLITE_OK + || checkReadTransaction(pDestDb, p->pDest->pBt)!=SQLITE_OK ){ /* One (or both) of the named databases did not exist or an OOM ** error was hit. Or there is a transaction open on the destination @@ -201,7 +201,7 @@ sqlite3_backup *sqlite3_backup_init( } } if( p ){ - p->pSrc->nBackup++; + p->pSrc->pBt->nBackup++; } sqlite3_mutex_leave(pDestDb->mutex); @@ -229,18 +229,18 @@ static int backupOnePage( const u8 *zSrcData, /* Source database page data */ int bUpdate /* True for an update, false otherwise */ ){ - Pager * const pDestPager = sqlite3BtreePager(p->pDest); - const int nSrcPgsz = sqlite3BtreeGetPageSize(p->pSrc); - int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest); + Pager * const pDestPager = sqlite3BtreePager(p->pDest->pBt); + const int nSrcPgsz = sqlite3BtreeGetPageSize(p->pSrc->pBt); + int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest->pBt); const int nCopy = MIN(nSrcPgsz, nDestPgsz); const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz; int rc = SQLITE_OK; i64 iOff; - assert( sqlite3BtreeGetReserveNoMutex(p->pSrc)>=0 ); + assert( sqlite3BtreeGetReserveNoMutex(p->pSrc->pBt)>=0 ); assert( p->bDestLocked ); assert( !isFatalError(p->rc) ); - assert( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ); + assert( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt->pBt) ); assert( zSrcData ); assert( nSrcPgsz==nDestPgsz || sqlite3PagerIsMemdb(pDestPager)==0 ); @@ -251,7 +251,7 @@ static int backupOnePage( for(iOff=iEnd-(i64)nSrcPgsz; rc==SQLITE_OK && iOffpDest->pBt) ) continue; + if( iDest==PENDING_BYTE_PAGE(p->pDest->pBt->pBt) ) continue; if( SQLITE_OK==(rc = sqlite3PagerGet(pDestPager, iDest, &pDestPg, 0)) && SQLITE_OK==(rc = sqlite3PagerWrite(pDestPg)) ){ @@ -269,7 +269,7 @@ static int backupOnePage( memcpy(zOut, zIn, nCopy); ((u8 *)sqlite3PagerGetExtra(pDestPg))[0] = 0; if( iOff==0 && bUpdate==0 ){ - sqlite3Put4byte(&zOut[28], sqlite3BtreeLastPage(p->pSrc)); + sqlite3Put4byte(&zOut[28], sqlite3BtreeLastPage(p->pSrc->pBt)); } } sqlite3PagerUnref(pDestPg); @@ -301,8 +301,8 @@ static int backupTruncateFile(sqlite3_file *pFile, i64 iSize){ */ static void attachBackupObject(sqlite3_backup *p){ sqlite3_backup **pp; - assert( sqlite3BtreeHoldsMutex(p->pSrc) ); - pp = sqlite3PagerBackupPtr(sqlite3BtreePager(p->pSrc)); + assert( sqlite3BtreeHoldsMutex(p->pSrc->pBt) ); + pp = sqlite3PagerBackupPtr(sqlite3BtreePager(p->pSrc->pBt)); p->pNext = *pp; *pp = p; p->isAttached = 1; @@ -316,20 +316,22 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){ int destMode; /* Destination journal mode */ int pgszSrc = 0; /* Source page size */ int pgszDest = 0; /* Destination page size */ + Btree *pDest = p->pDest->pBt; + Btree *pSrc = p->pSrc->pBt; #ifdef SQLITE_ENABLE_API_ARMOR if( p==0 ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(p->pSrcDb->mutex); - sqlite3BtreeEnter(p->pSrc); + sqlite3BtreeEnter(pSrc); if( p->pDestDb ){ sqlite3_mutex_enter(p->pDestDb->mutex); } rc = p->rc; if( !isFatalError(rc) ){ - Pager * const pSrcPager = sqlite3BtreePager(p->pSrc); /* Source pager */ - Pager * const pDestPager = sqlite3BtreePager(p->pDest); /* Dest pager */ + Pager * const pSrcPager = sqlite3BtreePager(pSrc); /* Source pager */ + Pager * const pDestPager = sqlite3BtreePager(pDest); /* Dest pager */ int ii; /* Iterator variable */ int nSrcPage = -1; /* Size of source db in pages */ int bCloseTrans = 0; /* True if src db requires unlocking */ @@ -337,7 +339,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){ /* If the source pager is currently in a write-transaction, return ** SQLITE_BUSY immediately. */ - if( p->pDestDb && p->pSrc->pBt->inTransaction==TRANS_WRITE ){ + if( p->pDestDb && pSrc->pBt->inTransaction==TRANS_WRITE ){ rc = SQLITE_BUSY; }else{ rc = SQLITE_OK; @@ -347,8 +349,8 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){ ** one now. If a transaction is opened here, then it will be closed ** before this function exits. */ - if( rc==SQLITE_OK && SQLITE_TXN_NONE==sqlite3BtreeTxnState(p->pSrc) ){ - rc = sqlite3BtreeBeginTrans(p->pSrc, 0, 0); + if( rc==SQLITE_OK && SQLITE_TXN_NONE==sqlite3BtreeTxnState(pSrc) ){ + rc = sqlite3BtreeBeginTrans(pSrc, 0, 0); bCloseTrans = 1; } @@ -364,7 +366,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){ /* Lock the destination database, if it is not locked already. */ if( SQLITE_OK==rc && p->bDestLocked==0 - && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2, + && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(pDest, 2, (int*)&p->iDestSchema)) ){ p->bDestLocked = 1; @@ -372,9 +374,9 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){ /* Do not allow backup if the destination database is in WAL mode ** and the page sizes are different between source and destination */ - pgszSrc = sqlite3BtreeGetPageSize(p->pSrc); - pgszDest = sqlite3BtreeGetPageSize(p->pDest); - destMode = sqlite3PagerGetJournalMode(sqlite3BtreePager(p->pDest)); + pgszSrc = sqlite3BtreeGetPageSize(pSrc); + pgszDest = sqlite3BtreeGetPageSize(pDest); + destMode = sqlite3PagerGetJournalMode(sqlite3BtreePager(pDest)); if( SQLITE_OK==rc && (destMode==PAGER_JOURNALMODE_WAL || sqlite3PagerIsMemdb(pDestPager)) && pgszSrc!=pgszDest @@ -385,11 +387,11 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){ /* Now that there is a read-lock on the source database, query the ** source pager for the number of pages in the database. */ - nSrcPage = (int)sqlite3BtreeLastPage(p->pSrc); + nSrcPage = (int)sqlite3BtreeLastPage(pSrc); assert( nSrcPage>=0 ); for(ii=0; (nPage<0 || iiiNext<=(Pgno)nSrcPage && !rc; ii++){ const Pgno iSrcPg = p->iNext; /* Source page number */ - if( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ){ + if( iSrcPg!=PENDING_BYTE_PAGE(pSrc->pBt) ){ DbPage *pSrcPg; /* Source page object */ rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg,PAGER_GET_READONLY); if( rc==SQLITE_OK ){ @@ -416,18 +418,18 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){ */ if( rc==SQLITE_DONE ){ if( nSrcPage==0 ){ - rc = sqlite3BtreeNewDb(p->pDest); + rc = sqlite3BtreeNewDb(pDest); nSrcPage = 1; } if( rc==SQLITE_OK || rc==SQLITE_DONE ){ - rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1); + rc = sqlite3BtreeUpdateMeta(pDest,1,p->iDestSchema+1); } if( rc==SQLITE_OK ){ if( p->pDestDb ){ sqlite3ResetAllSchemasOfConnection(p->pDestDb); } if( destMode==PAGER_JOURNALMODE_WAL ){ - rc = sqlite3BtreeSetVersion(p->pDest, 2); + rc = sqlite3BtreeSetVersion(pDest, 2); } } if( rc==SQLITE_OK ){ @@ -444,12 +446,12 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){ ** journalled by PagerCommitPhaseOne() before they are destroyed ** by the file truncation. */ - assert( pgszSrc==sqlite3BtreeGetPageSize(p->pSrc) ); - assert( pgszDest==sqlite3BtreeGetPageSize(p->pDest) ); + assert( pgszSrc==sqlite3BtreeGetPageSize(pSrc) ); + assert( pgszDest==sqlite3BtreeGetPageSize(pDest) ); if( pgszSrcpDest->pBt) ){ + if( nDestTruncate==(int)PENDING_BYTE_PAGE(pDest->pBt) ){ nDestTruncate--; } }else{ @@ -477,7 +479,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){ assert( pFile ); assert( nDestTruncate==0 || (i64)nDestTruncate*(i64)pgszDest >= iSize || ( - nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1) + nDestTruncate==(int)(PENDING_BYTE_PAGE(pDest->pBt)-1) && iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest )); @@ -489,7 +491,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){ ** journal file. */ sqlite3PagerPagecount(pDestPager, &nDstPage); for(iPg=nDestTruncate; rc==SQLITE_OK && iPg<=(Pgno)nDstPage; iPg++){ - if( iPg!=PENDING_BYTE_PAGE(p->pDest->pBt) ){ + if( iPg!=PENDING_BYTE_PAGE(pDest->pBt) ){ DbPage *pPg; rc = sqlite3PagerGet(pDestPager, iPg, &pPg, 0); if( rc==SQLITE_OK ){ @@ -533,7 +535,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){ /* Finish committing the transaction to the destination database. */ if( SQLITE_OK==rc - && SQLITE_OK==(rc = sqlite3BtreeCommitPhaseTwo(p->pDest, 0)) + && SQLITE_OK==(rc = sqlite3BtreeCommitPhaseTwo(pDest, 0)) ){ rc = SQLITE_DONE; } @@ -547,8 +549,8 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){ */ if( bCloseTrans ){ TESTONLY( int rc2 ); - TESTONLY( rc2 = ) sqlite3BtreeCommitPhaseOne(p->pSrc, 0); - TESTONLY( rc2 |= ) sqlite3BtreeCommitPhaseTwo(p->pSrc, 0); + TESTONLY( rc2 = ) sqlite3BtreeCommitPhaseOne(pSrc, 0); + TESTONLY( rc2 |= ) sqlite3BtreeCommitPhaseTwo(pSrc, 0); assert( rc2==SQLITE_OK ); } @@ -560,7 +562,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){ if( p->pDestDb ){ sqlite3_mutex_leave(p->pDestDb->mutex); } - sqlite3BtreeLeave(p->pSrc); + sqlite3BtreeLeave(pSrc); sqlite3_mutex_leave(p->pSrcDb->mutex); return rc; } @@ -577,17 +579,17 @@ int sqlite3_backup_finish(sqlite3_backup *p){ if( p==0 ) return SQLITE_OK; pSrcDb = p->pSrcDb; sqlite3_mutex_enter(pSrcDb->mutex); - sqlite3BtreeEnter(p->pSrc); + sqlite3BtreeEnter(p->pSrc->pBt); if( p->pDestDb ){ sqlite3_mutex_enter(p->pDestDb->mutex); } /* Detach this backup from the source pager. */ if( p->pDestDb ){ - p->pSrc->nBackup--; + p->pSrc->pBt->nBackup--; } if( p->isAttached ){ - pp = sqlite3PagerBackupPtr(sqlite3BtreePager(p->pSrc)); + pp = sqlite3PagerBackupPtr(sqlite3BtreePager(p->pSrc->pBt)); assert( pp!=0 ); while( *pp!=p ){ pp = &(*pp)->pNext; @@ -597,7 +599,7 @@ int sqlite3_backup_finish(sqlite3_backup *p){ } /* If a transaction is still open on the Btree, roll it back. */ - sqlite3BtreeRollback(p->pDest, SQLITE_OK, 0); + sqlite3BtreeRollback(p->pDest->pBt, SQLITE_OK, 0); /* Set the error code of the destination database handle. */ rc = (p->rc==SQLITE_DONE) ? SQLITE_OK : p->rc; @@ -607,7 +609,7 @@ int sqlite3_backup_finish(sqlite3_backup *p){ /* Exit the mutexes and free the backup context structure. */ sqlite3LeaveMutexAndCloseZombie(p->pDestDb); } - sqlite3BtreeLeave(p->pSrc); + sqlite3BtreeLeave(p->pSrc->pBt); if( p->pDestDb ){ /* EVIDENCE-OF: R-64852-21591 The sqlite3_backup object is created by a ** call to sqlite3_backup_init() and is destroyed by a call to @@ -665,7 +667,7 @@ static SQLITE_NOINLINE void backupUpdate( ){ assert( p!=0 ); do{ - assert( sqlite3_mutex_held(p->pSrc->pBt->mutex) ); + assert( sqlite3_mutex_held(p->pSrc->pBt->pBt->mutex) ); if( !isFatalError(p->rc) && iPageiNext ){ /* The backup process p has already copied page iPage. But now it ** has been modified by a transaction on the source pager. Copy @@ -701,7 +703,7 @@ void sqlite3BackupUpdate(sqlite3_backup *pBackup, Pgno iPage, const u8 *aData){ void sqlite3BackupRestart(sqlite3_backup *pBackup){ sqlite3_backup *p; /* Iterator variable */ for(p=pBackup; p; p=p->pNext){ - assert( sqlite3_mutex_held(p->pSrc->pBt->mutex) ); + assert( sqlite3_mutex_held(p->pSrc->pBt->pBt->mutex) ); p->iNext = 1; } } @@ -719,6 +721,8 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ int rc; sqlite3_file *pFd; /* File descriptor for database pTo */ sqlite3_backup b; + Db dbDest; + Db dbSrc; sqlite3BtreeEnter(pTo); sqlite3BtreeEnter(pFrom); @@ -737,9 +741,13 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ ** from this function, not directly by the user. */ memset(&b, 0, sizeof(b)); + memset(&dbDest, 0, sizeof(dbDest)); + memset(&dbSrc, 0, sizeof(dbSrc)); + dbDest.pBt = pTo; + dbSrc.pBt = pFrom; b.pSrcDb = pFrom->db; - b.pSrc = pFrom; - b.pDest = pTo; + b.pSrc = &dbSrc; + b.pDest = &dbDest; b.iNext = 1; /* 0x7FFFFFFF is the hard limit for the number of pages in a database @@ -755,7 +763,7 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ if( rc==SQLITE_OK ){ pTo->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED; }else{ - sqlite3PagerClearCache(sqlite3BtreePager(b.pDest)); + sqlite3PagerClearCache(sqlite3BtreePager(pTo)); } assert( sqlite3BtreeTxnState(pTo)!=SQLITE_TXN_WRITE ); diff --git a/test/memdb1.test b/test/memdb1.test index 0c752ca50a..e1ae571d81 100644 --- a/test/memdb1.test +++ b/test/memdb1.test @@ -317,4 +317,27 @@ do_test 1020 { set res } {1 {unable to set MEMDB content}} +#------------------------------------------------------------------------- +# Check that things work if the destination database of a backup is +# overwritten using sqlite3_deserialize() between sqlite3_backup_init() +# and the first call to sqlite3_backup_step(). Forum post 15d82885e2. +# +reset_db +do_execsql_test 1100 { + CREATE TABLE t(x); + INSERT INTO t VALUES(1),(2); +} + +set blob [db serialize main] + +forcedelete test.db2 +sqlite3 db2 test.db2 +do_test 1110 { + set seen 0 + sqlite3_backup B db2 main db main + db2 deserialize main $blob + B step 2 + B finish +} {SQLITE_OK} + finish_test