/ Check-in [3151dab9]
Login

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

Overview
Comment:Remove an assert ("assert( subpage>0 )") from btree.c that may not be true for a corrupt database. Also add comments and other assert() statements to btree.c function moveToRoot(). (CVS 6886)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 3151dab9c78106217ec80ebadc666dfd11b42029
User & Date: danielk1977 2009-07-13 09:41:45
Context
2009-07-13
11:22
In sqlite3PagerWrite(), do not set the PGHDR_NEED_SYNC flag on a page if an IO error occured while attempting to journal it. (CVS 6887) check-in: b9be365d user: danielk1977 tags: trunk
09:41
Remove an assert ("assert( subpage>0 )") from btree.c that may not be true for a corrupt database. Also add comments and other assert() statements to btree.c function moveToRoot(). (CVS 6886) check-in: 3151dab9 user: danielk1977 tags: trunk
07:30
Remove a case from BtreeMovetoUnpacked() that is unreachable as of (6881). (CVS 6885) check-in: 39ce2097 user: danielk1977 tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/btree.c.

     5      5   ** a legal notice, here is a blessing:
     6      6   **
     7      7   **    May you do good and not evil.
     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12         -** $Id: btree.c,v 1.683 2009/07/13 07:30:53 danielk1977 Exp $
           12  +** $Id: btree.c,v 1.684 2009/07/13 09:41:45 danielk1977 Exp $
    13     13   **
    14     14   ** This file implements a external (disk-based) database using BTrees.
    15     15   ** See the header comment on "btreeInt.h" for additional information.
    16     16   ** Including a description of file format and an overview of operation.
    17     17   */
    18     18   #include "btreeInt.h"
    19     19   
................................................................................
  3970   3970     releasePage(pCur->apPage[pCur->iPage]);
  3971   3971     pCur->iPage--;
  3972   3972     pCur->info.nSize = 0;
  3973   3973     pCur->validNKey = 0;
  3974   3974   }
  3975   3975   
  3976   3976   /*
  3977         -** Move the cursor to the root page
         3977  +** Move the cursor to point to the root page of its b-tree structure.
         3978  +**
         3979  +** If the table has a virtual root page, then the cursor is moved to point
         3980  +** to the virtual root page instead of the actual root page. A table has a
         3981  +** virtual root page when the actual root page contains no cells and a 
         3982  +** single child page. This can only happen with the table rooted at page 1.
         3983  +**
         3984  +** If the b-tree structure is empty, the cursor state is set to 
         3985  +** CURSOR_INVALID. Otherwise, the cursor is set to point to the first
         3986  +** cell located on the root (or virtual root) page and the cursor state
         3987  +** is set to CURSOR_VALID.
         3988  +**
         3989  +** If this function returns successfully, it may be assumed that the
         3990  +** page-header flags indicate that the [virtual] root-page is the expected 
         3991  +** kind of b-tree page (i.e. if when opening the cursor the caller did not
         3992  +** specify a KeyInfo structure the flags byte is set to 0x05 or 0x0D,
         3993  +** indicating a table b-tree, or if the caller did specify a KeyInfo 
         3994  +** structure the flags byte is set to 0x02 or 0x0A, indicating an index
         3995  +** b-tree).
  3978   3996   */
  3979   3997   static int moveToRoot(BtCursor *pCur){
  3980   3998     MemPage *pRoot;
  3981   3999     int rc = SQLITE_OK;
  3982   4000     Btree *p = pCur->pBtree;
  3983   4001     BtShared *pBt = p->pBt;
  3984   4002   
  3985   4003     assert( cursorHoldsMutex(pCur) );
  3986   4004     assert( CURSOR_INVALID < CURSOR_REQUIRESEEK );
  3987   4005     assert( CURSOR_VALID   < CURSOR_REQUIRESEEK );
  3988   4006     assert( CURSOR_FAULT   > CURSOR_REQUIRESEEK );
  3989   4007     if( pCur->eState>=CURSOR_REQUIRESEEK ){
  3990   4008       if( pCur->eState==CURSOR_FAULT ){
         4009  +      assert( pCur->skip!=SQLITE_OK );
  3991   4010         return pCur->skip;
  3992   4011       }
  3993   4012       sqlite3BtreeClearCursor(pCur);
  3994   4013     }
  3995   4014   
  3996   4015     if( pCur->iPage>=0 ){
  3997   4016       int i;
................................................................................
  4014   4033       ** return an SQLITE_CORRUPT error.  */
  4015   4034       assert( pCur->apPage[0]->intKey==1 || pCur->apPage[0]->intKey==0 );
  4016   4035       if( (pCur->pKeyInfo==0)!=pCur->apPage[0]->intKey ){
  4017   4036         return SQLITE_CORRUPT_BKPT;
  4018   4037       }
  4019   4038     }
  4020   4039   
         4040  +  /* Assert that the root page is of the correct type. This must be the
         4041  +  ** case as the call to this function that loaded the root-page (either
         4042  +  ** this call or a previous invocation) would have detected corruption 
         4043  +  ** if the assumption were not true, and it is not possible for the flags 
         4044  +  ** byte to have been modified while this cursor is holding a reference
         4045  +  ** to the page.  */
  4021   4046     pRoot = pCur->apPage[0];
  4022   4047     assert( pRoot->pgno==pCur->pgnoRoot );
         4048  +  assert( pRoot->isInit && (pCur->pKeyInfo==0)==pRoot->intKey );
         4049  +
  4023   4050     pCur->aiIdx[0] = 0;
  4024   4051     pCur->info.nSize = 0;
  4025   4052     pCur->atLast = 0;
  4026   4053     pCur->validNKey = 0;
  4027   4054   
  4028   4055     if( pRoot->nCell==0 && !pRoot->leaf ){
  4029   4056       Pgno subpage;
  4030   4057       if( pRoot->pgno!=1 ) return SQLITE_CORRUPT_BKPT;
  4031         -    assert( pRoot->pgno==1 );
  4032   4058       subpage = get4byte(&pRoot->aData[pRoot->hdrOffset+8]);
  4033         -    assert( subpage>0 );
  4034   4059       pCur->eState = CURSOR_VALID;
  4035   4060       rc = moveToChild(pCur, subpage);
  4036   4061     }else{
  4037   4062       pCur->eState = ((pRoot->nCell>0)?CURSOR_VALID:CURSOR_INVALID);
  4038   4063     }
  4039   4064     return rc;
  4040   4065   }
................................................................................
  6414   6439       return rc;
  6415   6440     }
  6416   6441     assert( pCur->eState==CURSOR_VALID || (pCur->eState==CURSOR_INVALID && loc) );
  6417   6442   
  6418   6443     pPage = pCur->apPage[pCur->iPage];
  6419   6444     assert( pPage->intKey || nKey>=0 );
  6420   6445     assert( pPage->leaf || !pPage->intKey );
         6446  +
  6421   6447     TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n",
  6422   6448             pCur->pgnoRoot, nKey, nData, pPage->pgno,
  6423   6449             loc==0 ? "overwrite" : "new entry"));
  6424   6450     assert( pPage->isInit );
  6425   6451     allocateTempSpace(pBt);
  6426   6452     newCell = pBt->pTmpSpace;
  6427   6453     if( newCell==0 ) return SQLITE_NOMEM;

Changes to test/corrupt.test.

     9      9   #
    10     10   #***********************************************************************
    11     11   # This file implements regression tests for SQLite library.
    12     12   #
    13     13   # This file implements tests to make sure SQLite does not crash or
    14     14   # segfault if it sees a corrupt database file.
    15     15   #
    16         -# $Id: corrupt.test,v 1.11 2009/07/11 17:39:42 danielk1977 Exp $
           16  +# $Id: corrupt.test,v 1.12 2009/07/13 09:41:45 danielk1977 Exp $
    17     17   
    18     18   catch {file delete -force test.db test.db-journal test.bu}
    19     19   
    20     20   set testdir [file dirname $argv0]
    21     21   source $testdir/tester.tcl
    22     22   
    23     23   # Construct a large database for testing.
................................................................................
   202    202     # This will fail, as the block modified the database image so that the
   203    203     # child page of the deleted cell is from a table (intkey) b-tree, not an
   204    204     # index b-tree as expected. At one point this was causing an assert()
   205    205     # to fail.
   206    206     catchsql { DELETE FROM t1 WHERE rowid = 3 }
   207    207   } {1 {database disk image is malformed}}
   208    208   
          209  +do_test corrupt-5.1 {
          210  +  db close
          211  +  file delete -force test.db test.db-journal
          212  +  sqlite3 db test.db
          213  +
          214  +  execsql { PRAGMA page_size = 1024 }
          215  +  set ct "CREATE TABLE t1(c0 "
          216  +  set i 0
          217  +  while {[string length $ct] < 950} { append ct ", c[incr i]" }
          218  +  append ct ")"
          219  +  execsql $ct
          220  +} {}
          221  +
          222  +do_test corrupt-5.2 {
          223  +  db close
          224  +  hexio_write test.db 108 00000000 
          225  +  sqlite3 db test.db
          226  +  catchsql { SELECT * FROM sqlite_master }
          227  +} {1 {database disk image is malformed}}
          228  +
   209    229   finish_test