11013148bSdrh# 2008 July 9 21013148bSdrh# 31013148bSdrh# The author disclaims copyright to this source code. In place of 41013148bSdrh# a legal notice, here is a blessing: 51013148bSdrh# 61013148bSdrh# May you do good and not evil. 71013148bSdrh# May you find forgiveness for yourself and forgive others. 81013148bSdrh# May you share freely, never taking more than you give. 91013148bSdrh# 101013148bSdrh#*********************************************************************** 111013148bSdrh# This file implements regression tests for SQLite library. 121013148bSdrh# 131013148bSdrh# This file implements tests to make sure SQLite does not crash or 141013148bSdrh# segfault if it sees a corrupt database file. It specifically focuses 15e71169baSshane# on corruption in the form of duplicate entries on the freelist. 161013148bSdrh# 17e71169baSshane# $Id: corrupt9.test,v 1.3 2009/06/04 02:47:04 shane Exp $ 181013148bSdrh 191013148bSdrhset testdir [file dirname $argv0] 201013148bSdrhsource $testdir/tester.tcl 211013148bSdrh 2268928b6cSdan# Do not use a codec for tests in this file, as the database file is 2368928b6cSdan# manipulated directly using tcl scripts (using the [hexio_write] command). 2468928b6cSdan# 2568928b6cSdando_not_use_codec 2668928b6cSdan 27*09fe6143Sdrh# These tests deal with corrupt database files 28*09fe6143Sdrh# 29*09fe6143Sdrhdatabase_may_be_corrupt 30*09fe6143Sdrh 311013148bSdrh# We must have the page_size pragma for these tests to work. 321013148bSdrh# 331013148bSdrhifcapable !pager_pragmas { 341013148bSdrh finish_test 351013148bSdrh return 361013148bSdrh} 371013148bSdrh 381013148bSdrh# Return the offset to the first (trunk) page of the freelist. Return 391013148bSdrh# zero of the freelist is empty. 401013148bSdrh# 411013148bSdrhproc freelist_trunk_offset {filename} { 421013148bSdrh if {[hexio_read $filename 36 4]==0} {return 0} 431013148bSdrh set pgno [hexio_get_int [hexio_read $filename 32 4]] 441013148bSdrh return [expr {($pgno-1)*[hexio_get_int [hexio_read $filename 16 2]]}] 451013148bSdrh} 461013148bSdrh 471013148bSdrh# This procedure looks at the first trunk page of the freelist and 481013148bSdrh# corrupts that page by overwriting up to N entries with duplicates 491013148bSdrh# of the first entry. 501013148bSdrh# 511013148bSdrhproc corrupt_freelist {filename N} { 521013148bSdrh set offset [freelist_trunk_offset $filename] 531013148bSdrh if {$offset==0} {error "Freelist is empty"} 541013148bSdrh set cnt [hexio_get_int [hexio_read $filename [expr {$offset+4}] 4]] 551013148bSdrh set pgno [hexio_read $filename [expr {$offset+8}] 4] 561013148bSdrh for {set i 12} {$N>0 && $i<8+4*$cnt} {incr i 4; incr N -1} { 571013148bSdrh hexio_write $filename [expr {$offset+$i}] $pgno 581013148bSdrh } 591013148bSdrh} 601013148bSdrh 611013148bSdrh# Create a database to work with. Make sure there are plenty of 621013148bSdrh# entries on the freelist. 631013148bSdrh# 641013148bSdrhdo_test corrupt9-1.1 { 651013148bSdrh execsql { 667830cd41Sdrh PRAGMA auto_vacuum=NONE; 671013148bSdrh PRAGMA page_size=1024; 681013148bSdrh CREATE TABLE t1(x); 691013148bSdrh INSERT INTO t1(x) VALUES(1); 701013148bSdrh INSERT INTO t1(x) VALUES(2); 711013148bSdrh INSERT INTO t1(x) SELECT x+2 FROM t1; 721013148bSdrh INSERT INTO t1(x) SELECT x+4 FROM t1; 731013148bSdrh INSERT INTO t1(x) SELECT x+8 FROM t1; 741013148bSdrh INSERT INTO t1(x) SELECT x+16 FROM t1; 751013148bSdrh INSERT INTO t1(x) SELECT x+32 FROM t1; 761013148bSdrh INSERT INTO t1(x) SELECT x+64 FROM t1; 771013148bSdrh INSERT INTO t1(x) SELECT x+128 FROM t1; 781013148bSdrh INSERT INTO t1(x) SELECT x+256 FROM t1; 791013148bSdrh CREATE TABLE t2(a,b); 801013148bSdrh INSERT INTO t2 SELECT x, x*x FROM t1; 811013148bSdrh CREATE INDEX i1 ON t1(x); 821013148bSdrh CREATE INDEX i2 ON t2(b,a); 831013148bSdrh DROP INDEX i2; 841013148bSdrh } 851013148bSdrh expr {[file size test.db]>1024*24} 861013148bSdrh} {1} 871013148bSdrhintegrity_check corrupt9-1.2 881013148bSdrh 891013148bSdrh# Corrupt the freelist by adding duplicate entries to the freelist. 901013148bSdrh# Make sure the corruption is detected. 911013148bSdrh# 921013148bSdrhdb close 93fda06befSmistachkinforcecopy test.db test.db-template 941013148bSdrh 951013148bSdrhcorrupt_freelist test.db 1 961013148bSdrhsqlite3 db test.db 971013148bSdrhdo_test corrupt9-2.1 { 981013148bSdrh set x [db eval {PRAGMA integrity_check}] 991013148bSdrh expr {$x!="ok"} 1001013148bSdrh} {1} 1011013148bSdrhdo_test corrupt9-2.2 { 1021013148bSdrh catchsql { 1031013148bSdrh CREATE INDEX i2 ON t2(b,a); 1041013148bSdrh REINDEX; 1051013148bSdrh } 1061013148bSdrh} {1 {database disk image is malformed}} 1071013148bSdrh 1081013148bSdrh 1091013148bSdrhdb close 110fda06befSmistachkinforcecopy test.db-template test.db 1111013148bSdrhcorrupt_freelist test.db 2 1121013148bSdrhsqlite3 db test.db 1131013148bSdrhdo_test corrupt9-3.1 { 1141013148bSdrh set x [db eval {PRAGMA integrity_check}] 1151013148bSdrh expr {$x!="ok"} 1161013148bSdrh} {1} 1171013148bSdrhdo_test corrupt9-3.2 { 1181013148bSdrh catchsql { 1191013148bSdrh CREATE INDEX i2 ON t2(b,a); 1201013148bSdrh REINDEX; 1211013148bSdrh } 1221013148bSdrh} {1 {database disk image is malformed}} 1231013148bSdrh 1241013148bSdrhdb close 125fda06befSmistachkinforcecopy test.db-template test.db 1261013148bSdrhcorrupt_freelist test.db 3 1271013148bSdrhsqlite3 db test.db 1281013148bSdrhdo_test corrupt9-4.1 { 1291013148bSdrh set x [db eval {PRAGMA integrity_check}] 1301013148bSdrh expr {$x!="ok"} 1311013148bSdrh} {1} 1321013148bSdrhdo_test corrupt9-4.2 { 1331013148bSdrh catchsql { 1341013148bSdrh CREATE INDEX i2 ON t2(b,a); 1351013148bSdrh REINDEX; 1361013148bSdrh } 1371013148bSdrh} {1 {database disk image is malformed}} 1381013148bSdrh 1391013148bSdrh 1401013148bSdrhfinish_test 141