Annotation of embedaddon/sqlite3/test/corruptC.test, revision 1.1.1.1

1.1       misho       1: # 2004 August 30
                      2: #
                      3: # The author disclaims copyright to this source code.  In place of
                      4: # a legal notice, here is a blessing:
                      5: #
                      6: #    May you do good and not evil.
                      7: #    May you find forgiveness for yourself and forgive others.
                      8: #    May you share freely, never taking more than you give.
                      9: #
                     10: #***********************************************************************
                     11: # This file implements regression tests for SQLite library.
                     12: #
                     13: # This file implements tests to make sure SQLite does not crash or
                     14: # segfault if it sees a corrupt database file.  It creates a base
                     15: # data base file, then tests that single byte corruptions in 
                     16: # increasingly larger quantities are handled gracefully.
                     17: #
                     18: # $Id: corruptC.test,v 1.14 2009/07/11 06:55:34 danielk1977 Exp $
                     19: 
                     20: catch {forcedelete test.db test.db-journal test.bu}
                     21: 
                     22: set testdir [file dirname $argv0]
                     23: source $testdir/tester.tcl
                     24: 
                     25: # Do not use a codec for tests in this file, as the database file is
                     26: # manipulated directly using tcl scripts (using the [hexio_write] command).
                     27: #
                     28: do_not_use_codec
                     29: 
                     30: # Construct a compact, dense database for testing.
                     31: #
                     32: do_test corruptC-1.1 {
                     33:   execsql {
                     34:     PRAGMA auto_vacuum = 0;
                     35:     PRAGMA legacy_file_format=1;
                     36:     BEGIN;
                     37:     CREATE TABLE t1(x,y);
                     38:     INSERT INTO t1 VALUES(1,1);
                     39:     INSERT OR IGNORE INTO t1 SELECT x*2,y FROM t1;
                     40:     INSERT OR IGNORE INTO t1 SELECT x*3,y FROM t1;
                     41:     INSERT OR IGNORE INTO t1 SELECT x*5,y FROM t1;
                     42:     INSERT OR IGNORE INTO t1 SELECT x*7,y FROM t1;
                     43:     INSERT OR IGNORE INTO t1 SELECT x*11,y FROM t1;
                     44:     INSERT OR IGNORE INTO t1 SELECT x*13,y FROM t1;
                     45:     CREATE INDEX t1i1 ON t1(x);
                     46:     CREATE TABLE t2 AS SELECT x,2 as y FROM t1 WHERE rowid%5!=0;
                     47:     COMMIT;
                     48:   }
                     49: } {}
                     50: 
                     51: ifcapable {integrityck} {
                     52:   integrity_check corruptC-1.2
                     53: }
                     54: 
                     55: # Generate random integer
                     56: #
                     57: proc random {range} {
                     58:   return [expr {round(rand()*$range)}]
                     59: }
                     60: 
                     61: # Setup for the tests.  Make a backup copy of the good database in test.bu.
                     62: #
                     63: db close
                     64: forcecopy test.db test.bu
                     65: sqlite3 db test.db
                     66: set fsize [file size test.db]
                     67: 
                     68: # Set a quasi-random random seed. 
                     69: if {[info exists ::G(issoak)]} {
                     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: 
                     81: #
                     82: # First test some specific corruption tests found from earlier runs
                     83: # with specific seeds.
                     84: #
                     85: 
                     86: # test that a corrupt content offset size is handled (seed 5577)
                     87: do_test corruptC-2.1 {
                     88:   db close
                     89:   forcecopy test.bu test.db
                     90: 
                     91:   # insert corrupt byte(s)
                     92:   hexio_write test.db 2053 [format %02x 0x04]
                     93: 
                     94:   sqlite3 db test.db
                     95:   catchsql {PRAGMA integrity_check}
                     96: } {1 {database disk image is malformed}}
                     97: 
                     98: # test that a corrupt content offset size is handled (seed 5649)
                     99: do_test corruptC-2.2 {
                    100:   db close
                    101:   forcecopy test.bu test.db
                    102: 
                    103:   # insert corrupt byte(s)
                    104:   hexio_write test.db 27   [format %02x 0x08]
                    105:   hexio_write test.db 233  [format %02x 0x6a]
                    106:   hexio_write test.db 328  [format %02x 0x67]
                    107:   hexio_write test.db 750  [format %02x 0x1f]
                    108:   hexio_write test.db 1132 [format %02x 0x52]
                    109:   hexio_write test.db 1133 [format %02x 0x84]
                    110:   hexio_write test.db 1220 [format %02x 0x01]
                    111:   hexio_write test.db 3688 [format %02x 0xc1]
                    112:   hexio_write test.db 3714 [format %02x 0x58]
                    113:   hexio_write test.db 3746 [format %02x 0x9a]
                    114: 
                    115:   sqlite3 db test.db
                    116:   catchsql {UPDATE t1 SET y=1}
                    117: } {1 {database disk image is malformed}}
                    118: 
                    119: # test that a corrupt free cell size is handled (seed 13329)
                    120: do_test corruptC-2.3 {
                    121:   db close
                    122:   forcecopy test.bu test.db
                    123: 
                    124:   # insert corrupt byte(s)
                    125:   hexio_write test.db 1094 [format %02x 0x76]
                    126: 
                    127:   sqlite3 db test.db
                    128:   catchsql {UPDATE t1 SET y=1}
                    129: } {1 {database disk image is malformed}}
                    130: 
                    131: # test that a corrupt free cell size is handled (seed 169571)
                    132: do_test corruptC-2.4 {
                    133:   db close
                    134:   forcecopy test.bu test.db
                    135: 
                    136:   # insert corrupt byte(s)
                    137:   hexio_write test.db 3119 [format %02x 0xdf]
                    138: 
                    139:   sqlite3 db test.db
                    140:   catchsql {UPDATE t2 SET y='abcdef-uvwxyz'}
                    141: } {1 {database disk image is malformed}}
                    142: 
                    143: # test that a corrupt free cell size is handled (seed 169571)
                    144: do_test corruptC-2.5 {
                    145:   db close
                    146:   forcecopy test.bu test.db
                    147: 
                    148:   # insert corrupt byte(s)
                    149:   hexio_write test.db 3119 [format %02x 0xdf]
                    150:   hexio_write test.db 4073 [format %02x 0xbf]
                    151: 
                    152:   sqlite3 db test.db
                    153:   catchsql {BEGIN; UPDATE t2 SET y='abcdef-uvwxyz'; ROLLBACK;}
                    154:   catchsql {PRAGMA integrity_check}
                    155: } {0 {{*** in database main ***
                    156: Page 4: btreeInitPage() returns error code 11}}}
                    157: 
                    158: # {0 {{*** in database main ***
                    159: # Corruption detected in cell 710 on page 4
                    160: # Multiple uses for byte 661 of page 4
                    161: # Fragmented space is 249 byte reported as 21 on page 4}}}
                    162: 
                    163: # test that a corrupt free cell size is handled (seed 169595)
                    164: do_test corruptC-2.6 {
                    165:   db close
                    166:   forcecopy test.bu test.db
                    167: 
                    168:   # insert corrupt byte(s)
                    169:   hexio_write test.db 619 [format %02x 0xe2]
                    170:   hexio_write test.db 3150 [format %02x 0xa8]
                    171: 
                    172:   sqlite3 db test.db
                    173:   catchsql {BEGIN; UPDATE t2 SET y='abcdef-uvwxyz'; ROLLBACK;}
                    174: } {1 {database disk image is malformed}}
                    175: 
                    176: # corruption (seed 178692)
                    177: do_test corruptC-2.7 {
                    178:   db close
                    179:   forcecopy test.bu test.db
                    180: 
                    181:   # insert corrupt byte(s)
                    182:   hexio_write test.db 3074 [format %02x 0xa0]
                    183: 
                    184:   sqlite3 db test.db
                    185:   catchsql {BEGIN; UPDATE t2 SET y='abcdef-uvwxyz'; ROLLBACK;}
                    186: } {1 {database disk image is malformed}}
                    187: 
                    188: # corruption (seed 179069)
                    189: do_test corruptC-2.8 {
                    190:   db close
                    191:   forcecopy test.bu test.db
                    192: 
                    193:   # insert corrupt byte(s)
                    194:   hexio_write test.db 1393 [format %02x 0x7d]
                    195:   hexio_write test.db 84 [format %02x 0x19]
                    196:   hexio_write test.db 3287 [format %02x 0x3b]
                    197:   hexio_write test.db 2564 [format %02x 0xed]
                    198:   hexio_write test.db 2139 [format %02x 0x55]
                    199: 
                    200:   sqlite3 db test.db
                    201:   catchsql {BEGIN; DELETE FROM t1 WHERE x>13; ROLLBACK;}
                    202: } {1 {database disk image is malformed}}
                    203: 
                    204: # corruption (seed 170434)
                    205: do_test corruptC-2.9 {
                    206:   db close
                    207:   forcecopy test.bu test.db
                    208: 
                    209:   # insert corrupt byte(s)
                    210:   hexio_write test.db 2095 [format %02x 0xd6]
                    211: 
                    212:   sqlite3 db test.db
                    213:   catchsql {BEGIN; DELETE FROM t1 WHERE x>13; ROLLBACK;}
                    214: } {1 {database disk image is malformed}}
                    215: 
                    216: # corruption (seed 186504)
                    217: do_test corruptC-2.10 {
                    218:   db close
                    219:   forcecopy test.bu test.db
                    220: 
                    221:   # insert corrupt byte(s)
                    222:   hexio_write test.db 3130 [format %02x 0x02]
                    223:   
                    224:   sqlite3 db test.db
                    225:   catchsql {BEGIN; UPDATE t2 SET y='abcdef-uvwxyz'; ROLLBACK;}
                    226: } {1 {database disk image is malformed}}
                    227: 
                    228: # corruption (seed 1589)
                    229: do_test corruptC-2.11 {
                    230:   db close
                    231:   forcecopy test.bu test.db
                    232: 
                    233:   # insert corrupt byte(s)
                    234:   hexio_write test.db 55 [format %02x 0xa7]
                    235:   
                    236:   sqlite3 db test.db
                    237:   catchsql {BEGIN; CREATE TABLE t3 AS SELECT x,3 as y FROM t2 WHERE rowid%5!=0; ROLLBACK;}
                    238: } {1 {database disk image is malformed}}
                    239: 
                    240: # corruption (seed 14166)
                    241: do_test corruptC-2.12 {
                    242:   db close
                    243:   forcecopy test.bu test.db
                    244: 
                    245:   # insert corrupt byte(s)
                    246:   hexio_write test.db 974 [format %02x 0x2e]
                    247:   
                    248:   sqlite3 db test.db
                    249:   catchsql {SELECT count(*) FROM sqlite_master;}
                    250: } {1 {malformed database schema (t1i1) - corrupt database}}
                    251: 
                    252: # corruption (seed 218803)
                    253: do_test corruptC-2.13 {
                    254:   db close
                    255:   forcecopy test.bu test.db
                    256: 
                    257:   # insert corrupt byte(s)
                    258:   hexio_write test.db 102 [format %02x 0x12]
                    259:   
                    260:   sqlite3 db test.db
                    261:   catchsql {BEGIN; CREATE TABLE t3 AS SELECT x,3 as y FROM t2 WHERE rowid%5!=0; ROLLBACK;}
                    262: } {1 {database disk image is malformed}}
                    263: 
                    264: do_test corruptC-2.14 {
                    265:   db close
                    266:   forcecopy test.bu test.db
                    267: 
                    268:   sqlite3 db test.db
                    269:   set blob [string repeat abcdefghij 10000]
                    270:   execsql { INSERT INTO t1 VALUES (1, $blob) }
                    271: 
                    272:   sqlite3 db test.db
                    273:   set filesize [file size test.db]
                    274:   hexio_write test.db [expr $filesize-2048] 00000001
                    275:   catchsql {DELETE FROM t1 WHERE rowid = (SELECT max(rowid) FROM t1)}
                    276: } {1 {database disk image is malformed}}
                    277: 
                    278: # At one point this particular corrupt database was causing a buffer
                    279: # overread. Which caused a crash in a run of all.test once.
                    280: #
                    281: do_test corruptC-2.15 {
                    282:   db close
                    283:   forcecopy test.bu test.db
                    284:   hexio_write test.db 986 b9
                    285:   sqlite3 db test.db
                    286:   catchsql {SELECT count(*) FROM sqlite_master;}
                    287: } {1 {malformed database schema (t1i1) - no such table: main.t1}}
                    288: 
                    289: #
                    290: # Now test for a series of quasi-random seeds.
                    291: # We loop over the entire file size and touch
                    292: # each byte at least once.
                    293: for {set tn 0} {$tn<$fsize} {incr tn 1} {
                    294: 
                    295:   # setup for test
                    296:   db close
                    297:   forcecopy test.bu test.db
                    298:   sqlite3 db test.db
                    299: 
                    300:   # Seek to a random location in the file, and write a random single byte
                    301:   # value.  Then do various operations on the file to make sure that
                    302:   # the database engine can handle the corruption gracefully.
                    303:   #
                    304:   set last 0
                    305:   for {set i 1} {$i<=512 && !$last} {incr i 1} {
                    306: 
                    307:     db close
                    308:     if {$i==1} {
                    309:       # on the first corrupt value, use location $tn
                    310:       # this ensures that we touch each location in the 
                    311:       # file at least once.
                    312:       set roffset $tn
                    313:     } else { 
                    314:       # insert random byte at random location
                    315:       set roffset [random $fsize]
                    316:     }
                    317:     set rbyte [format %02x [random 255]]
                    318: 
                    319:     # You can uncomment the following to have it trace
                    320:     # exactly how it's corrupting the file.  This is 
                    321:     # useful for generating the "seed specific" tests
                    322:     # above.
                    323:     # set rline "$roffset $rbyte"
                    324:     # puts stdout $rline
                    325: 
                    326:     hexio_write test.db $roffset $rbyte
                    327:     sqlite3 db test.db
                    328: 
                    329:     # do a few random operations to make sure that if 
                    330:     # they error, they error gracefully instead of crashing.
                    331:     do_test corruptC-3.$tn.($qseed).$i.1 {
                    332:       catchsql {SELECT count(*) FROM sqlite_master}
                    333:       set x {}
                    334:     } {}
                    335:     do_test corruptC-3.$tn.($qseed).$i.2 {
                    336:       catchsql {SELECT count(*) FROM t1}
                    337:       set x {}
                    338:     } {}
                    339:     do_test corruptC-3.$tn.($qseed).$i.3 {
                    340:       catchsql {SELECT count(*) FROM t1 WHERE x>13}
                    341:       set x {}
                    342:     } {}
                    343:     do_test corruptC-3.$tn.($qseed).$i.4 {
                    344:       catchsql {SELECT count(*) FROM t2}
                    345:       set x {}
                    346:     } {}
                    347:     do_test corruptC-3.$tn.($qseed).$i.5 {
                    348:       catchsql {SELECT count(*) FROM t2 WHERE x<13}
                    349:       set x {}
                    350:     } {}
                    351:     do_test corruptC-3.$tn.($qseed).$i.6 {
                    352:       catchsql {BEGIN; UPDATE t1 SET y=1; ROLLBACK;}
                    353:       set x {}
                    354:     } {}
                    355:     do_test corruptC-3.$tn.($qseed).$i.7 {
                    356:       catchsql {BEGIN; UPDATE t2 SET y='abcdef-uvwxyz'; ROLLBACK;}
                    357:       set x {}
                    358:     } {}
                    359:     do_test corruptC-3.$tn.($qseed).$i.8 {
                    360:       catchsql {BEGIN; DELETE FROM t1 WHERE x>13; ROLLBACK;}
                    361:       set x {}
                    362:     } {}
                    363:     do_test corruptC-3.$tn.($qseed).$i.9 {
                    364:       catchsql {BEGIN; DELETE FROM t2 WHERE x<13; ROLLBACK;}
                    365:       set x {}
                    366:     } {}
                    367:     do_test corruptC-3.$tn.($qseed).$i.10 {
                    368:       catchsql {BEGIN; CREATE TABLE t3 AS SELECT x,3 as y FROM t2 WHERE rowid%5!=0; ROLLBACK;}
                    369:       set x {}
                    370:     } {}
                    371: 
                    372:     # check the integrity of the database.
                    373:     # once the corruption is detected, we can stop.
                    374:     ifcapable {integrityck} {
                    375:       set res [ catchsql {PRAGMA integrity_check} ]
                    376:       set ans [lindex $res 1]
                    377:       if { [ string compare $ans "ok" ] != 0 } {
                    378:         set last -1
                    379:       }
                    380:     }
                    381:     # if we are not capable of doing an integrity check,
                    382:     # stop after corrupting 5 bytes.
                    383:     ifcapable {!integrityck} {
                    384:       if { $i > 5 } {
                    385:         set last -1
                    386:       }
                    387:     }
                    388: 
                    389:     # Check that no page references were leaked.
                    390:     # TBD:  need to figure out why this doesn't work
                    391:     # work with ROLLBACKs...
                    392:     if {0} {
                    393:       do_test corruptC-3.$tn.($qseed).$i.11 {
                    394:         set bt [btree_from_db db]
                    395:         db_enter db
                    396:         array set stats [btree_pager_stats $bt]
                    397:         db_leave db
                    398:         set stats(ref)
                    399:       } {0}
                    400:     }
                    401:   }
                    402:   # end for i
                    403: 
                    404: }
                    405: # end for tn
                    406: 
                    407: finish_test

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>