1b9ee4939Sdrh# 2007 Sept 7 2b9ee4939Sdrh# 3b9ee4939Sdrh# The author disclaims copyright to this source code. In place of 4b9ee4939Sdrh# a legal notice, here is a blessing: 5b9ee4939Sdrh# 6b9ee4939Sdrh# May you do good and not evil. 7b9ee4939Sdrh# May you find forgiveness for yourself and forgive others. 8b9ee4939Sdrh# May you share freely, never taking more than you give. 9b9ee4939Sdrh# 10b9ee4939Sdrh#*********************************************************************** 11b9ee4939Sdrh# This file implements regression tests for SQLite library. 12b9ee4939Sdrh# 13b9ee4939Sdrh# This file implements tests to make sure SQLite does not crash or 14b9ee4939Sdrh# segfault if it sees a corrupt database file. 15b9ee4939Sdrh# 16b9ee4939Sdrh 17b9ee4939Sdrhset testdir [file dirname $argv0] 18b9ee4939Sdrhsource $testdir/tester.tcl 195b482a98Sdanset testprefix corrupt4 20b9ee4939Sdrh 21af3906a7Sdrh# This module uses hard-coded offsets which do not work if the reserved_bytes 22af3906a7Sdrh# value is nonzero. 23af3906a7Sdrhif {[nonzero_reserved_bytes]} {finish_test; return;} 2468928b6cSdan 2509fe6143Sdrh# These tests deal with corrupt database files 2609fe6143Sdrh# 2709fe6143Sdrhdatabase_may_be_corrupt 2809fe6143Sdrh 29b9ee4939Sdrh# We must have the page_size pragma for these tests to work. 30b9ee4939Sdrh# 31b9ee4939Sdrhifcapable !pager_pragmas { 32b9ee4939Sdrh finish_test 33b9ee4939Sdrh return 34b9ee4939Sdrh} 35b9ee4939Sdrh 36b9ee4939Sdrh# Create a database with a freelist containing at least two pages. 37b9ee4939Sdrh# 38b9ee4939Sdrhdo_test corrupt4-1.1 { 39b9ee4939Sdrh set bigstring [string repeat 0123456789 200] 40b9ee4939Sdrh execsql { 41b9ee4939Sdrh PRAGMA auto_vacuum=OFF; 42b9ee4939Sdrh PRAGMA page_size=1024; 43b9ee4939Sdrh CREATE TABLE t1(x); 44b9ee4939Sdrh INSERT INTO t1 VALUES($bigstring); 45b9ee4939Sdrh CREATE TABLE t2(y); 46b9ee4939Sdrh INSERT INTO t2 VALUES(1); 47b9ee4939Sdrh DROP TABLE t1; 48b9ee4939Sdrh } 49b9ee4939Sdrh file size test.db 50b9ee4939Sdrh} [expr {1024*4}] 51b9ee4939Sdrh 52b9ee4939Sdrh# Verify that there are two pages on the freelist. 53b9ee4939Sdrh# 54b9ee4939Sdrhdo_test corrupt4-1.2 { 55b9ee4939Sdrh execsql {PRAGMA freelist_count} 56b9ee4939Sdrh} {2} 57b9ee4939Sdrh 58b9ee4939Sdrh# Get the page number for the trunk of the freelist. 59b9ee4939Sdrh# 60b9ee4939Sdrhset trunkpgno [hexio_get_int [hexio_read test.db 32 4]] 61b9ee4939Sdrhset baseaddr [expr {($trunkpgno-1)*1024}] 62b9ee4939Sdrh 63b9ee4939Sdrh# Verify that the trunk of the freelist has exactly one 64b9ee4939Sdrh# leaf. 65b9ee4939Sdrh# 66b9ee4939Sdrhdo_test corrupt4-1.3 { 67b9ee4939Sdrh hexio_get_int [hexio_read test.db [expr {$::baseaddr+4}] 4] 68b9ee4939Sdrh} {1} 69b9ee4939Sdrh 70b9ee4939Sdrh# Insert a negative number as the number of leaves on the trunk. 71b9ee4939Sdrh# Then try to add a new element to the freelist. 72b9ee4939Sdrh# 73b9ee4939Sdrhdo_test corrupt4-1.4 { 74b9ee4939Sdrh hexio_write test.db [expr {$::baseaddr+4}] [hexio_render_int32 -100000000] 75b9ee4939Sdrh db close 76b9ee4939Sdrh sqlite3 db test.db 77b9ee4939Sdrh catchsql { 78b9ee4939Sdrh DROP TABLE t2 79b9ee4939Sdrh } 80b9ee4939Sdrh} {1 {database disk image is malformed}} 81b9ee4939Sdrh 825b482a98Sdan#------------------------------------------------------------------------- 835b482a98Sdan 845b482a98Sdanreset_db 855b482a98Sdando_execsql_test 2.0 { 865b482a98Sdan PRAGMA page_size = 512; 875b482a98Sdan CREATE TABLE t1(a, b, c); 885b482a98Sdan} 895b482a98Sdan 905b482a98Sdan# Create a database with a schema so large that the root of the 915b482a98Sdan# sqlite_schema table is the grandparent of its leaves. 925b482a98Sdan# 935b482a98Sdanset nView 1000 945b482a98Sdando_test 2.1 { 955b482a98Sdan execsql BEGIN 965b482a98Sdan for {set ii 0} {$ii<$nView} {incr ii} { 975b482a98Sdan execsql " CREATE VIEW v$ii AS SELECT a, b, c FROM t1 " 985b482a98Sdan } 995b482a98Sdan execsql COMMIT 1005b482a98Sdan} {} 1015b482a98Sdandb close 1025b482a98Sdan 1035b482a98Sdanproc get2byte {fd offset} { 1045b482a98Sdan seek $fd $offset 1055b482a98Sdan set bin [read $fd 2] 1065b482a98Sdan binary scan $bin S val 1075b482a98Sdan set val 1085b482a98Sdan} 1095b482a98Sdanproc get4byte {fd offset} { 1105b482a98Sdan seek $fd $offset 1115b482a98Sdan set bin [read $fd 4] 1125b482a98Sdan binary scan $bin I val 1135b482a98Sdan set val 1145b482a98Sdan} 1155b482a98Sdanproc put4byte {fd offset val} { 1165b482a98Sdan seek $fd $offset 1175b482a98Sdan set bin [binary format I $val] 1185b482a98Sdan puts -nonewline $fd $bin 1195b482a98Sdan} 1205b482a98Sdan 1215b482a98Sdan# Page 1 is now the grandparent of its leaves. Corrupt the database by setting 1225b482a98Sdan# the second rightmost child page number of page 1 to 1. 1235b482a98Sdan# 1245b482a98Sdanset fd [open test.db r+] 1255b482a98Sdanfconfigure $fd -encoding binary -translation binary 1265b482a98Sdanset nChild [get2byte $fd 103] 1275b482a98Sdanset offChild [get2byte $fd [expr 100+12+($nChild-2)*2]] 1285b482a98Sdanset pgnoChild [get4byte $fd $offChild] 1295b482a98Sdanput4byte $fd $offChild 1 1305b482a98Sdanclose $fd 1315b482a98Sdan 132*99bd5525Slarrybrif {![info exists ::G(perm:presql)]} { 1335b482a98Sdan sqlite3 db test.db 134*99bd5525Slarrybr 1355b482a98Sdan do_catchsql_test 2.2 { 1365b482a98Sdan PRAGMA writable_schema = 1; 1375b482a98Sdan SELECT * FROM sqlite_schema; 1385b482a98Sdan } {1 {database disk image is malformed}} 1395b482a98Sdan 1405b482a98Sdan do_test 2.3 { 1415b482a98Sdan list [catch { 1425b482a98Sdan for {set ii $nView} {$ii<$nView*2} {incr ii} { 1435b482a98Sdan execsql "INSERT INTO sqlite_master VALUES(1, 2, 3, 4, 5)" 1445b482a98Sdan } 1455b482a98Sdan } msg] $msg 1465b482a98Sdan } {1 {database disk image is malformed}} 147*99bd5525Slarrybr} 1485b482a98Sdan 149b9ee4939Sdrhfinish_test 150