SQLite

Check-in [020968f8]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Fix a segfault that could occur if a non-empty in-memory database was the destination of a backup operation from a database with a smaller page size. Forum post 679b4de86e763d52.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 020968f857d7b90bab3525fc9d6b859a019f6a80422c3d5ffb88f5bdb8e02a11
User & Date: dan 2023-04-19 17:07:35
Original Comment: Fix a segfault that could occur if a non-empty in-memory database was the destination of a backup operation from a database with a smaller page size.
Context
2023-04-19
18:32
Remove unreachable legacy code. (check-in: e3e7fb87 user: drh tags: trunk)
17:13
Fix a segfault that could occur if a non-empty in-memory database was the destination of a backup operation from a database with a smaller page size. (check-in: d3724158 user: drh tags: branch-3.41)
17:07
Fix a segfault that could occur if a non-empty in-memory database was the destination of a backup operation from a database with a smaller page size. Forum post 679b4de86e763d52. (check-in: 020968f8 user: dan tags: trunk)
15:35
Do not remove pages from the cache of an in-memory database due to a failure to acquire the page due to it being larger than the maximum page size. Fix for forum post a19bb49140. (check-in: 982b3556 user: drh tags: trunk)
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/backup.c.

238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
  i64 iOff;

  assert( sqlite3BtreeGetReserveNoMutex(p->pSrc)>=0 );
  assert( p->bDestLocked );
  assert( !isFatalError(p->rc) );
  assert( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) );
  assert( zSrcData );

  /* Catch the case where the destination is an in-memory database and the
  ** page sizes of the source and destination differ. 
  */
  if( nSrcPgsz!=nDestPgsz && sqlite3PagerIsMemdb(pDestPager) ){
    rc = SQLITE_READONLY;
  }

  /* This loop runs once for each destination page spanned by the source 
  ** page. For each iteration, variable iOff is set to the byte offset
  ** of the destination page.
  */
  for(iOff=iEnd-(i64)nSrcPgsz; rc==SQLITE_OK && iOff<iEnd; iOff+=nDestPgsz){
    DbPage *pDestPg = 0;







<
<
<
<
|
<
<







238
239
240
241
242
243
244




245


246
247
248
249
250
251
252
  i64 iOff;

  assert( sqlite3BtreeGetReserveNoMutex(p->pSrc)>=0 );
  assert( p->bDestLocked );
  assert( !isFatalError(p->rc) );
  assert( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) );
  assert( zSrcData );




  assert( nSrcPgsz==nDestPgsz || sqlite3PagerIsMemdb(pDestPager)==0 );



  /* This loop runs once for each destination page spanned by the source 
  ** page. For each iteration, variable iOff is set to the byte offset
  ** of the destination page.
  */
  for(iOff=iEnd-(i64)nSrcPgsz; rc==SQLITE_OK && iOff<iEnd; iOff+=nDestPgsz){
    DbPage *pDestPg = 0;
377
378
379
380
381
382
383
384



385
386
387
388
389
390
391
    }

    /* 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));
    if( SQLITE_OK==rc && destMode==PAGER_JOURNALMODE_WAL && pgszSrc!=pgszDest ){



      rc = SQLITE_READONLY;
    }
  
    /* 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);







|
>
>
>







371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
    }

    /* 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));
    if( SQLITE_OK==rc 
     && (destMode==PAGER_JOURNALMODE_WAL || sqlite3PagerIsMemdb(pDestPager))
     && pgszSrc!=pgszDest 
    ){
      rc = SQLITE_READONLY;
    }
  
    /* 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);

Changes to test/backup.test.

973
974
975
976
977
978
979























980
981
#
do_test backup-11.1 {
  sqlite3 db1 :memory:
  sqlite3 db2 :memory:
  sqlite3_backup B db1 main db2 temp
  B finish
} {SQLITE_OK}
























finish_test







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
#
do_test backup-11.1 {
  sqlite3 db1 :memory:
  sqlite3 db2 :memory:
  sqlite3_backup B db1 main db2 temp
  B finish
} {SQLITE_OK}
db1 close
db2 close

#-------------------------------------------------------------------------
do_test backup-12.1 {
  sqlite3 db1 :memory:
  sqlite3 db2 :memory:
  db1 eval {
    PRAGMA page_size = 8192;
    CREATE TABLE t1(x);
  }
  db2 eval {
    PRAGMA page_size = 1024;
    CREATE TABLE t2(x);
  }

  sqlite3_backup B db1 main db2 temp
  B step 100
  B finish
} {SQLITE_READONLY}




finish_test