Annotation of embedaddon/sqlite3/test/corruptC.test, revision 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>