/ Check-in [9b7a52e9]
Login

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

Overview
Comment:Fixed several more crashes due to corrupt db files. Added corruptC.test to soak.test. (CVS 5905)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 9b7a52e952c81e50611e04d2d79003b0ddc57ee5
User & Date: shane 2008-11-13 18:29:51
Context
2008-11-13
19:12
Fix a couple of memory leaks that may follow malloc failures. (CVS 5906) check-in: 4cf8a8e1 user: danielk1977 tags: trunk
18:29
Fixed several more crashes due to corrupt db files. Added corruptC.test to soak.test. (CVS 5905) check-in: 9b7a52e9 user: shane tags: trunk
18:20
Added support for -DSQLITE_NO_SYNC to os_win.c. (CVS 5904) check-in: 26493379 user: shane 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.535 2008/11/13 14:28:29 danielk1977 Exp $
           12  +** $Id: btree.c,v 1.536 2008/11/13 18:29:51 shane 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   
................................................................................
   730    730     cbrk = get2byte(&data[hdr+5]);
   731    731     memcpy(&temp[cbrk], &data[cbrk], usableSize - cbrk);
   732    732     cbrk = usableSize;
   733    733     for(i=0; i<nCell; i++){
   734    734       u8 *pAddr;     /* The i-th cell pointer */
   735    735       pAddr = &data[cellOffset + i*2];
   736    736       pc = get2byte(pAddr);
   737         -    if( pc>=pPage->pBt->usableSize ){
          737  +    if( pc>=usableSize ){
   738    738         return SQLITE_CORRUPT_BKPT;
   739    739       }
   740    740       size = cellSizePtr(pPage, &temp[pc]);
   741    741       cbrk -= size;
   742    742       if( cbrk<cellOffset+2*nCell || pc+size>usableSize ){
   743    743         return SQLITE_CORRUPT_BKPT;
   744    744       }
................................................................................
   831    831   ** Return a section of the pPage->aData to the freelist.
   832    832   ** The first byte of the new free block is pPage->aDisk[start]
   833    833   ** and the size of the block is "size" bytes.
   834    834   **
   835    835   ** Most of the effort here is involved in coalesing adjacent
   836    836   ** free blocks into a single big free block.
   837    837   */
   838         -static void freeSpace(MemPage *pPage, int start, int size){
          838  +static int freeSpace(MemPage *pPage, int start, int size){
   839    839     int addr, pbegin, hdr;
   840    840     unsigned char *data = pPage->aData;
   841    841   
   842    842     assert( pPage->pBt!=0 );
   843    843     assert( sqlite3PagerIswriteable(pPage->pDbPage) );
   844    844     assert( start>=pPage->hdrOffset+6+(pPage->leaf?0:4) );
   845    845     assert( (start + size)<=pPage->pBt->usableSize );
................................................................................
   853    853   #endif
   854    854   
   855    855     /* Add the space back into the linked list of freeblocks */
   856    856     hdr = pPage->hdrOffset;
   857    857     addr = hdr + 1;
   858    858     while( (pbegin = get2byte(&data[addr]))<start && pbegin>0 ){
   859    859       assert( pbegin<=pPage->pBt->usableSize-4 );
   860         -    assert( pbegin>addr );
          860  +    if( pbegin<=addr ) {
          861  +      return SQLITE_CORRUPT_BKPT;
          862  +    }
   861    863       addr = pbegin;
   862    864     }
   863         -  assert( pbegin<=pPage->pBt->usableSize-4 );
          865  +  if ( pbegin>pPage->pBt->usableSize-4 ) {
          866  +    return SQLITE_CORRUPT_BKPT;
          867  +  }
   864    868     assert( pbegin>addr || pbegin==0 );
   865    869     put2byte(&data[addr], start);
   866    870     put2byte(&data[start], pbegin);
   867    871     put2byte(&data[start+2], size);
   868    872     pPage->nFree += size;
   869    873   
   870    874     /* Coalesce adjacent free blocks */
................................................................................
   873    877       int pnext, psize;
   874    878       assert( pbegin>addr );
   875    879       assert( pbegin<=pPage->pBt->usableSize-4 );
   876    880       pnext = get2byte(&data[pbegin]);
   877    881       psize = get2byte(&data[pbegin+2]);
   878    882       if( pbegin + psize + 3 >= pnext && pnext>0 ){
   879    883         int frag = pnext - (pbegin+psize);
   880         -      assert( frag<=data[pPage->hdrOffset+7] );
          884  +      if( (frag<0) || (frag>data[pPage->hdrOffset+7]) ){
          885  +        return SQLITE_CORRUPT_BKPT;
          886  +      }
   881    887         data[pPage->hdrOffset+7] -= frag;
   882    888         put2byte(&data[pbegin], get2byte(&data[pnext]));
   883    889         put2byte(&data[pbegin+2], pnext+get2byte(&data[pnext+2])-pbegin);
   884    890       }else{
   885    891         addr = pbegin;
   886    892       }
   887    893     }
................................................................................
   890    896     if( data[hdr+1]==data[hdr+5] && data[hdr+2]==data[hdr+6] ){
   891    897       int top;
   892    898       pbegin = get2byte(&data[hdr+1]);
   893    899       memcpy(&data[hdr+1], &data[pbegin], 2);
   894    900       top = get2byte(&data[hdr+5]);
   895    901       put2byte(&data[hdr+5], top + get2byte(&data[pbegin+2]));
   896    902     }
          903  +  return SQLITE_OK;
   897    904   }
   898    905   
   899    906   /*
   900    907   ** Decode the flags byte (the first byte of the header) for a page
   901    908   ** and initialize fields of the MemPage structure accordingly.
   902    909   **
   903    910   ** Only the following combinations are supported.  Anything different
................................................................................
  4575   4582   ** "sz" must be the number of bytes in the cell.
  4576   4583   */
  4577   4584   static int dropCell(MemPage *pPage, int idx, int sz){
  4578   4585     int i;          /* Loop counter */
  4579   4586     int pc;         /* Offset to cell content of cell being deleted */
  4580   4587     u8 *data;       /* pPage->aData */
  4581   4588     u8 *ptr;        /* Used to move bytes around within data[] */
         4589  +  int rc;         /* The return code */
  4582   4590   
  4583   4591     assert( idx>=0 && idx<pPage->nCell );
  4584   4592     assert( sz==cellSize(pPage, idx) );
  4585   4593     assert( sqlite3PagerIswriteable(pPage->pDbPage) );
  4586   4594     assert( sqlite3_mutex_held(pPage->pBt->mutex) );
  4587   4595     data = pPage->aData;
  4588   4596     ptr = &data[pPage->cellOffset + 2*idx];
  4589   4597     pc = get2byte(ptr);
  4590         -  if ( pc<=10 || pc+sz>pPage->pBt->usableSize ) {
         4598  +  if ( (pc<pPage->hdrOffset+6+(pPage->leaf?0:4)) || (pc+sz>pPage->pBt->usableSize) ) {
  4591   4599       return SQLITE_CORRUPT_BKPT;
  4592   4600     }
  4593         -  freeSpace(pPage, pc, sz);
         4601  +  rc = freeSpace(pPage, pc, sz);
         4602  +  if( rc!=SQLITE_OK ){
         4603  +    return rc;
         4604  +  }
  4594   4605     for(i=idx+1; i<pPage->nCell; i++, ptr+=2){
  4595   4606       ptr[0] = ptr[2];
  4596   4607       ptr[1] = ptr[3];
  4597   4608     }
  4598   4609     pPage->nCell--;
  4599   4610     put2byte(&data[pPage->hdrOffset+3], pPage->nCell);
  4600   4611     pPage->nFree += 2;
................................................................................
  6047   6058                                      || !pCur->pagesShuffled );
  6048   6059         }
  6049   6060       }
  6050   6061       sqlite3BtreeReleaseTempCursor(&leafCur);
  6051   6062     }else{
  6052   6063       TRACE(("DELETE: table=%d delete from leaf %d\n",
  6053   6064          pCur->pgnoRoot, pPage->pgno));
  6054         -    dropCell(pPage, idx, cellSizePtr(pPage, pCell));
  6055         -    rc = balance(pCur, 0);
         6065  +    rc = dropCell(pPage, idx, cellSizePtr(pPage, pCell));
         6066  +    if( rc==SQLITE_OK ){
         6067  +      rc = balance(pCur, 0);
         6068  +    }
  6056   6069     }
  6057   6070     if( rc==SQLITE_OK ){
  6058   6071       moveToRoot(pCur);
  6059   6072     }
  6060   6073     return rc;
  6061   6074   }
  6062   6075   

Changes to src/build.c.

    18     18   **     CREATE INDEX
    19     19   **     DROP INDEX
    20     20   **     creating ID lists
    21     21   **     BEGIN TRANSACTION
    22     22   **     COMMIT
    23     23   **     ROLLBACK
    24     24   **
    25         -** $Id: build.c,v 1.501 2008/11/11 18:28:59 drh Exp $
           25  +** $Id: build.c,v 1.502 2008/11/13 18:29:51 shane Exp $
    26     26   */
    27     27   #include "sqliteInt.h"
    28     28   #include <ctype.h>
    29     29   
    30     30   /*
    31     31   ** This routine is called when a new SQL statement is beginning to
    32     32   ** be parsed.  Initialize the pParse structure as needed.
................................................................................
   666    666     Token *pName2,      /* The "yyy" in the name "xxx.yyy" */
   667    667     Token **pUnqual     /* Write the unqualified object name here */
   668    668   ){
   669    669     int iDb;                    /* Database holding the object */
   670    670     sqlite3 *db = pParse->db;
   671    671   
   672    672     if( pName2 && pName2->n>0 ){
   673         -    assert( !db->init.busy );
          673  +    if( db->init.busy ) {
          674  +      sqlite3ErrorMsg(pParse, "corrupt database");
          675  +      pParse->nErr++;
          676  +      return -1;
          677  +    }
   674    678       *pUnqual = pName2;
   675    679       iDb = sqlite3FindDb(db, pName1);
   676    680       if( iDb<0 ){
   677    681         sqlite3ErrorMsg(pParse, "unknown database %T", pName1);
   678    682         pParse->nErr++;
   679    683         return -1;
   680    684       }

Changes to src/vdbe.c.

    39     39   **
    40     40   ** Various scripts scan this source file in order to generate HTML
    41     41   ** documentation, headers files, or other derived files.  The formatting
    42     42   ** of the code in this file is, therefore, important.  See other comments
    43     43   ** in this file for details.  If in doubt, do not deviate from existing
    44     44   ** commenting and indentation practices when changing or adding code.
    45     45   **
    46         -** $Id: vdbe.c,v 1.786 2008/11/05 16:37:35 drh Exp $
           46  +** $Id: vdbe.c,v 1.787 2008/11/13 18:29:51 shane Exp $
    47     47   */
    48     48   #include "sqliteInt.h"
    49     49   #include <ctype.h>
    50     50   #include "vdbeInt.h"
    51     51   
    52     52   /*
    53     53   ** The following global variable is incremented every time a cursor
................................................................................
  2694   2694     }
  2695   2695     if( pOp->p5 ){
  2696   2696       assert( p2>0 );
  2697   2697       assert( p2<=p->nMem );
  2698   2698       pIn2 = &p->aMem[p2];
  2699   2699       sqlite3VdbeMemIntegerify(pIn2);
  2700   2700       p2 = pIn2->u.i;
  2701         -    assert( p2>=2 );
         2701  +    if( p2<2 ) {
         2702  +      rc = SQLITE_CORRUPT_BKPT;
         2703  +      goto abort_due_to_error;
         2704  +    }
  2702   2705     }
  2703   2706     assert( i>=0 );
  2704   2707     pCur = allocateCursor(p, i, &pOp[-1], iDb, 1);
  2705   2708     if( pCur==0 ) goto no_mem;
  2706   2709     pCur->nullRow = 1;
  2707   2710     rc = sqlite3BtreeCursor(pX, p2, wrFlag, pOp->p4.p, pCur->pCursor);
  2708   2711     if( pOp->p4type==P4_KEYINFO ){

Changes to test/corruptC.test.

    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.  It creates a base
    15     15   # data base file, then tests that single byte corruptions in 
    16     16   # increasingly larger quantities are handled gracefully.
    17     17   #
    18         -# $Id: corruptC.test,v 1.8 2008/11/12 18:21:36 danielk1977 Exp $
           18  +# $Id: corruptC.test,v 1.9 2008/11/13 18:29:51 shane Exp $
    19     19   
    20     20   catch {file delete -force test.db test.db-journal test.bu}
    21     21   
    22     22   set testdir [file dirname $argv0]
    23     23   source $testdir/tester.tcl
    24     24   
    25         -# Set a uniform random seed
    26         -expr srand(0)
    27         -
    28     25   # Construct a compact, dense database for testing.
    29     26   #
    30     27   do_test corruptC-1.1 {
    31     28     execsql {
    32     29       PRAGMA auto_vacuum = 0;
    33     30       BEGIN;
    34     31       CREATE TABLE t1(x,y);
................................................................................
    48     45   ifcapable {integrityck} {
    49     46     integrity_check corruptC-1.2
    50     47   }
    51     48   
    52     49   # Generate random integer
    53     50   #
    54     51   proc random {range} {
    55         -    return [expr {round(rand()*$range)}]
           52  +  return [expr {round(rand()*$range)}]
    56     53   }
    57     54   
    58     55   # Copy file $from into $to
    59     56   #
    60     57   proc copy_file {from to} {
    61         -  set f [open $from]
    62         -  fconfigure $f -translation binary
    63         -  set t [open $to w]
    64         -  fconfigure $t -translation binary
    65         -  puts -nonewline $t [read $f [file size $from]]
    66         -  close $t
    67         -  close $f
           58  +  file copy -force $from $to
    68     59   }
    69     60   
    70     61   # Setup for the tests.  Make a backup copy of the good database in test.bu.
    71     62   #
    72     63   db close
    73     64   copy_file test.db test.bu
    74     65   sqlite3 db test.db
    75     66   set fsize [file size test.db]
    76     67   
           68  +# Set a quasi-random random seed. 
           69  +if {[info exists SOAKTEST]} {
           70  +  # If we are doing SOAK tests, we want a different
           71  +  # random seed for each run.  Ideally we would like 
           72  +  # to use [clock clicks] or something like that here.
           73  +  set qseed [file mtime test.db]
           74  +} else {
           75  +  # If we are not doing soak tests,
           76  +  # make it repeatable.
           77  +  set qseed 0
           78  +}
           79  +expr srand($qseed)
           80  +
    77     81   #
    78         -# first test some specific corruption tests found from earlier runs
           82  +# First test some specific corruption tests found from earlier runs
           83  +# with specific seeds.
    79     84   #
    80     85   
    81     86   # test that a corrupt content offset size is handled (seed 5577)
    82     87   do_test corruptC-2.1 {
    83     88     db close
    84     89     copy_file test.bu test.db
    85     90   
................................................................................
   161    166     # insert corrupt byte(s)
   162    167     hexio_write test.db 619 [format %02x 0xe2]
   163    168     hexio_write test.db 3150 [format %02x 0xa8]
   164    169   
   165    170     sqlite3 db test.db
   166    171     catchsql {BEGIN; UPDATE t2 SET y='abcdef-uvwxyz'; ROLLBACK;}
   167    172   } {1 {database disk image is malformed}}
          173  +
          174  +# corruption (seed 178692)
          175  +do_test corruptC-2.7 {
          176  +  db close
          177  +  copy_file test.bu test.db
          178  +
          179  +  # insert corrupt byte(s)
          180  +  hexio_write test.db 3074 [format %02x 0xa0]
          181  +
          182  +  sqlite3 db test.db
          183  +  catchsql {BEGIN; UPDATE t2 SET y='abcdef-uvwxyz'; ROLLBACK;}
          184  +} {1 {database disk image is malformed}}
          185  +
          186  +# corruption (seed 179069)
          187  +do_test corruptC-2.8 {
          188  +  db close
          189  +  copy_file test.bu test.db
          190  +
          191  +  # insert corrupt byte(s)
          192  +  hexio_write test.db 1393 [format %02x 0x7d]
          193  +  hexio_write test.db 84 [format %02x 0x19]
          194  +  hexio_write test.db 3287 [format %02x 0x3b]
          195  +  hexio_write test.db 2564 [format %02x 0xed]
          196  +  hexio_write test.db 2139 [format %02x 0x55]
          197  +
          198  +  sqlite3 db test.db
          199  +  catchsql {BEGIN; DELETE FROM t1 WHERE x>13; ROLLBACK;}
          200  +} {1 {database disk image is malformed}}
          201  +
          202  +# corruption (seed 170434)
          203  +do_test corruptC-2.9 {
          204  +  db close
          205  +  copy_file test.bu test.db
          206  +
          207  +  # insert corrupt byte(s)
          208  +  hexio_write test.db 2095 [format %02x 0xd6]
          209  +
          210  +  sqlite3 db test.db
          211  +  catchsql {BEGIN; DELETE FROM t1 WHERE x>13; ROLLBACK;}
          212  +} {1 {database disk image is malformed}}
          213  +
          214  +# corruption (seed 186504)
          215  +do_test corruptC-2.10 {
          216  +  db close
          217  +  copy_file test.bu test.db
          218  +
          219  +  # insert corrupt byte(s)
          220  +  hexio_write test.db 3130 [format %02x 0x02]
          221  +  
          222  +  sqlite3 db test.db
          223  +  catchsql {BEGIN; UPDATE t2 SET y='abcdef-uvwxyz'; ROLLBACK;}
          224  +} {1 {database disk image is malformed}}
          225  +
          226  +# corruption (seed 1589)
          227  +do_test corruptC-2.11 {
          228  +  db close
          229  +  copy_file test.bu test.db
          230  +
          231  +  # insert corrupt byte(s)
          232  +  hexio_write test.db 55 [format %02x 0xa7]
          233  +  
          234  +  sqlite3 db test.db
          235  +  catchsql {BEGIN; CREATE TABLE t3 AS SELECT x,3 as y FROM t2 WHERE rowid%5!=0; ROLLBACK;}
          236  +} {1 {database disk image is malformed}}
          237  +
          238  +# corruption (seed 14166)
          239  +do_test corruptC-2.12 {
          240  +  db close
          241  +  copy_file test.bu test.db
          242  +
          243  +  # insert corrupt byte(s)
          244  +  hexio_write test.db 974 [format %02x 0x2e]
          245  +  
          246  +  sqlite3 db test.db
          247  +  catchsql {SELECT count(*) FROM sqlite_master;}
          248  +} {1 {malformed database schema (t1i1) - corrupt database}}
          249  +
          250  +# corruption (seed 218803)
          251  +do_test corruptC-2.13 {
          252  +  db close
          253  +  copy_file test.bu test.db
          254  +
          255  +  # insert corrupt byte(s)
          256  +  hexio_write test.db 102 [format %02x 0x12]
          257  +  
          258  +  sqlite3 db test.db
          259  +  catchsql {BEGIN; CREATE TABLE t3 AS SELECT x,3 as y FROM t2 WHERE rowid%5!=0; ROLLBACK;}
          260  +} {1 {database disk image is malformed}}
          261  +
   168    262   
   169    263   #
   170    264   # now test for a series of quasi-random seeds
   171         -#
   172         -for {set tn 0} {$tn<=1024} {incr tn 1} {
   173         -
   174         -  # Set a quasi-random random seed
   175         -  expr srand($tn)
          265  +for {set tn 0} {$tn<1024} {incr tn 1} {
   176    266   
   177    267     # setup for test
   178    268     db close
   179    269     copy_file test.bu test.db
   180    270     sqlite3 db test.db
   181    271   
   182    272     # Seek to a random location in the file, and write a random single byte
   183    273     # value.  Then do various operations on the file to make sure that
   184    274     # the database engine can handle the corruption gracefully.
   185    275     #
   186    276     set last 0
   187         -  for {set i 1} {$i<=1024 && !$last} {incr i 1} {
          277  +  for {set i 1} {$i<=512 && !$last} {incr i 1} {
   188    278   
   189    279       # insert random byte at random location
   190    280       db close
   191         -    hexio_write test.db [random $fsize] [format %02x [random 255]]
          281  +    set roffset [random $fsize]
          282  +    set rbyte [format %02x [random 255]]
          283  +
          284  +    # You can uncomment the following to have it trace
          285  +    # exactly how it's corrupting the file.  This is 
          286  +    # useful for generating the "seed specific" tests
          287  +    # above.
          288  +    # set rline "$roffset $rbyte"
          289  +    # puts stdout $rline
          290  +
          291  +    hexio_write test.db $roffset $rbyte
   192    292       sqlite3 db test.db
   193    293   
   194    294       # do a few random operations to make sure that if 
   195    295       # they error, they error gracefully instead of crashing.
   196         -    do_test corruptC-3.$tn.$i.1 {
          296  +    do_test corruptC-3.$tn.($qseed).$i.1 {
   197    297         catchsql {SELECT count(*) FROM sqlite_master}
   198    298         set x {}
   199    299       } {}
   200         -    do_test corruptC-3.$tn.$i.2 {
          300  +    do_test corruptC-3.$tn.($qseed).$i.2 {
   201    301         catchsql {SELECT count(*) FROM t1}
   202    302         set x {}
   203    303       } {}
   204         -    do_test corruptC-3.$tn.$i.3 {
          304  +    do_test corruptC-3.$tn.($qseed).$i.3 {
   205    305         catchsql {SELECT count(*) FROM t1 WHERE x>13}
   206    306         set x {}
   207    307       } {}
   208         -    do_test corruptC-3.$tn.$i.4 {
          308  +    do_test corruptC-3.$tn.($qseed).$i.4 {
   209    309         catchsql {SELECT count(*) FROM t2}
   210    310         set x {}
   211    311       } {}
   212         -    do_test corruptC-3.$tn.$i.5 {
          312  +    do_test corruptC-3.$tn.($qseed).$i.5 {
   213    313         catchsql {SELECT count(*) FROM t2 WHERE x<13}
   214    314         set x {}
   215    315       } {}
   216         -    do_test corruptC-3.$tn.$i.6 {
          316  +    do_test corruptC-3.$tn.($qseed).$i.6 {
   217    317         catchsql {BEGIN; UPDATE t1 SET y=1; ROLLBACK;}
   218    318         set x {}
   219    319       } {}
   220         -    do_test corruptC-3.$tn.$i.7 {
          320  +    do_test corruptC-3.$tn.($qseed).$i.7 {
   221    321         catchsql {BEGIN; UPDATE t2 SET y='abcdef-uvwxyz'; ROLLBACK;}
   222    322         set x {}
          323  +    } {}
          324  +    do_test corruptC-3.$tn.($qseed).$i.8 {
          325  +      catchsql {BEGIN; DELETE FROM t1 WHERE x>13; ROLLBACK;}
          326  +      set x {}
          327  +    } {}
          328  +    do_test corruptC-3.$tn.($qseed).$i.9 {
          329  +      catchsql {BEGIN; DELETE FROM t2 WHERE x<13; ROLLBACK;}
          330  +      set x {}
          331  +    } {}
          332  +    do_test corruptC-3.$tn.($qseed).$i.10 {
          333  +      catchsql {BEGIN; CREATE TABLE t3 AS SELECT x,3 as y FROM t2 WHERE rowid%5!=0; ROLLBACK;}
          334  +      set x {}
   223    335       } {}
   224    336   
   225    337       # check the integrity of the database.
   226    338       # once the corruption is detected, we can stop.
   227    339       ifcapable {integrityck} {
   228    340         set res [ catchsql {PRAGMA integrity_check} ]
   229    341         set ans [lindex $res 1]
................................................................................
   239    351         }
   240    352       }
   241    353   
   242    354       # Check that no page references were leaked.
   243    355       # TBD:  need to figure out why this doesn't work
   244    356       # work with ROLLBACKs...
   245    357       if {0} {
   246         -      do_test corruptC-3.$tn.$i.8 {
          358  +      do_test corruptC-3.$tn.($qseed).$i.11 {
   247    359           set bt [btree_from_db db]
   248    360           db_enter db
   249    361           array set stats [btree_pager_stats $bt]
   250    362           db_leave db
   251    363           set stats(ref)
   252    364         } {0}
   253    365       }

Changes to test/soak.test.

     7      7   #    May you find forgiveness for yourself and forgive others.
     8      8   #    May you share freely, never taking more than you give.
     9      9   #
    10     10   #***********************************************************************
    11     11   # This file is the driver for the "soak" tests. It is a peer of the
    12     12   # quick.test and all.test scripts.
    13     13   #
    14         -# $Id: soak.test,v 1.3 2008/07/12 14:52:20 drh Exp $
           14  +# $Id: soak.test,v 1.4 2008/11/13 18:29:51 shane Exp $
    15     15   
    16     16   set testdir [file dirname $argv0]
    17     17   source $testdir/tester.tcl
    18     18   rename finish_test really_finish_test
    19     19   proc finish_test {} {}
    20     20   
    21     21   # By default, guarantee that the tests will run for at least 1 hour.
................................................................................
    43     43   #
    44     44   # The general principle is to run those SQLite tests that use
    45     45   # pseudo-random data in some way over and over again for a very 
    46     46   # long time. The number of tests run depends on the value of 
    47     47   # global variable $TIMEOUT - tests are run for at least $TIMEOUT 
    48     48   # seconds.
    49     49   #
    50         -#   fuzz.test   (pseudo-random SQL statements)
    51         -#   trans.test  (pseudo-random changes to a database followed by rollbacks)
    52         -#
    53         -# fuzzy malloc?
           50  +#   fuzz.test     (pseudo-random SQL statements)
           51  +#   trans.test    (pseudo-random changes to a database followed by rollbacks)
           52  +#   fuzz_malloc.test
           53  +#   corruptC.test (pseudo-random corruption to a database)
    54     54   #
    55     55   # Many database changes maintaining some kind of invariant. 
    56     56   # Storing checksums etc.
    57     57   #
    58     58   
    59     59   # List of test files that are run by this file.
    60     60   #
    61     61   set SOAKTESTS {
    62     62     fuzz.test
    63     63     fuzz_malloc.test
    64     64     trans.test
           65  +  corruptC.test
    65     66   }
    66     67   
    67     68   set ISQUICK 1
    68     69   
    69     70   set soak_starttime  [clock seconds]
    70     71   set soak_finishtime [expr {$soak_starttime + $TIMEOUT}]
    71     72