17df42abaSdan# 2014-01-20 27df42abaSdan# 37df42abaSdan# The author disclaims copyright to this source code. In place of 47df42abaSdan# a legal notice, here is a blessing: 57df42abaSdan# 67df42abaSdan# May you do good and not evil. 77df42abaSdan# May you find forgiveness for yourself and forgive others. 87df42abaSdan# May you share freely, never taking more than you give. 97df42abaSdan# 107df42abaSdan#*********************************************************************** 117df42abaSdan# 127df42abaSdan 137df42abaSdanset testdir [file dirname $argv0] 147df42abaSdansource $testdir/tester.tcl 157df42abaSdanset testprefix corruptH 167df42abaSdan 17*af3906a7Sdrh# This module uses hard-coded offsets which do not work if the reserved_bytes 18*af3906a7Sdrh# value is nonzero. 19*af3906a7Sdrhif {[nonzero_reserved_bytes]} {finish_test; return;} 20*af3906a7Sdrh 217df42abaSdandatabase_may_be_corrupt 227df42abaSdan 23f0ec2a5eSdan# The corruption migrations tested by the code in this file are not detected 24f0ec2a5eSdan# mmap mode. 25f0ec2a5eSdan# 26f0ec2a5eSdan# The reason is that in mmap mode, the different queries may use different 27f0ec2a5eSdan# PgHdr objects for the same page (same data, but different PgHdr container 28f0ec2a5eSdan# objects). And so the corruption is not detected. 29f0ec2a5eSdan# 30f0ec2a5eSdanif {[permutation]=="mmap"} { 31f0ec2a5eSdan finish_test 32f0ec2a5eSdan return 33f0ec2a5eSdan} 34f0ec2a5eSdan 357df42abaSdan# Initialize the database. 367df42abaSdan# 377df42abaSdando_execsql_test 1.1 { 387df42abaSdan PRAGMA page_size=1024; 397df42abaSdan 407df42abaSdan CREATE TABLE t1(a INTEGER PRIMARY KEY, b); 417df42abaSdan INSERT INTO t1 VALUES(1, 'one'); 427df42abaSdan INSERT INTO t1 VALUES(2, 'two'); 437df42abaSdan 447df42abaSdan CREATE TABLE t2(x); 457df42abaSdan INSERT INTO t2 VALUES(randomblob(200)); 467df42abaSdan INSERT INTO t2 SELECT randomblob(200) FROM t2; 477df42abaSdan INSERT INTO t2 SELECT randomblob(200) FROM t2; 487df42abaSdan INSERT INTO t2 SELECT randomblob(200) FROM t2; 497df42abaSdan INSERT INTO t2 SELECT randomblob(200) FROM t2; 507df42abaSdan INSERT INTO t2 SELECT randomblob(200) FROM t2; 517df42abaSdan INSERT INTO t2 SELECT randomblob(200) FROM t2; 527df42abaSdan} {} 537df42abaSdan 547df42abaSdan# Corrupt the file so that the root page of t1 is also linked into t2 as 557df42abaSdan# a leaf page. 567df42abaSdan# 577df42abaSdando_test 1.2 { 587df42abaSdan db eval { SELECT name, rootpage FROM sqlite_master } { 597df42abaSdan set r($name) $rootpage 607df42abaSdan } 617df42abaSdan db close 627df42abaSdan hexio_write test.db [expr {($r(t2)-1)*1024 + 11}] [format %.2X $r(t1)] 637df42abaSdan sqlite3 db test.db 647df42abaSdan} {} 657df42abaSdan 667df42abaSdando_test 1.3 { 677df42abaSdan db eval { PRAGMA secure_delete=1 } 687df42abaSdan list [catch { 697df42abaSdan db eval { SELECT * FROM t1 WHERE a IN (1, 2) } { 707df42abaSdan db eval { DELETE FROM t2 } 717df42abaSdan } 727df42abaSdan } msg] $msg 737df42abaSdan} {1 {database disk image is malformed}} 747df42abaSdan 757df42abaSdan#------------------------------------------------------------------------- 767df42abaSdanreset_db 777df42abaSdan 787df42abaSdan# Initialize the database. 797df42abaSdan# 807df42abaSdando_execsql_test 2.1 { 81abfe0346Sdan PRAGMA auto_vacuum=0; 827df42abaSdan PRAGMA page_size=1024; 837df42abaSdan 847df42abaSdan CREATE TABLE t1(a INTEGER PRIMARY KEY, b); 857df42abaSdan INSERT INTO t1 VALUES(1, 'one'); 867df42abaSdan INSERT INTO t1 VALUES(2, 'two'); 877df42abaSdan 887df42abaSdan CREATE TABLE t3(x); 897df42abaSdan 907df42abaSdan CREATE TABLE t2(x PRIMARY KEY) WITHOUT ROWID; 917df42abaSdan INSERT INTO t2 VALUES(randomblob(100)); 927df42abaSdan 937df42abaSdan DROP TABLE t3; 947df42abaSdan} {} 957df42abaSdan 967df42abaSdando_test 2.2 { 977df42abaSdan db eval { SELECT name, rootpage FROM sqlite_master } { 987df42abaSdan set r($name) $rootpage 997df42abaSdan } 1007df42abaSdan db close 1017df42abaSdan set fl [hexio_get_int [hexio_read test.db 32 4]] 1027df42abaSdan 1037df42abaSdan hexio_write test.db [expr {($fl-1) * 1024 + 0}] 00000000 1047df42abaSdan hexio_write test.db [expr {($fl-1) * 1024 + 4}] 00000001 1057df42abaSdan hexio_write test.db [expr {($fl-1) * 1024 + 8}] [format %.8X $r(t1)] 1067df42abaSdan hexio_write test.db 36 00000002 1077df42abaSdan 1087df42abaSdan sqlite3 db test.db 1097df42abaSdan} {} 1107df42abaSdan 111705a4875Sdan 112705a4875Sdan# The trick here is that the root page of the tree scanned by the outer 113705a4875Sdan# query is also currently on the free-list. So while the first seek on 114705a4875Sdan# the table (for a==1) works, by the time the second is attempted The 115705a4875Sdan# "INSERT INTO t2..." statements have recycled the root page of t1 and 116705a4875Sdan# used it as an index leaf. Normally, BtreeMovetoUnpacked() detects 117705a4875Sdan# that the PgHdr object associated with said root page does not match 118705a4875Sdan# the cursor (as it is now marked with PgHdr.intKey==0) and returns 119705a4875Sdan# SQLITE_CORRUPT. 120705a4875Sdan# 121705a4875Sdanset res23 {1 {database disk image is malformed}} 1227df42abaSdando_test 2.3 { 1237df42abaSdan list [catch { 124705a4875Sdan set res [list] 1257df42abaSdan db eval { SELECT * FROM t1 WHERE a IN (1, 2) } { 1267df42abaSdan db eval { 1277df42abaSdan INSERT INTO t2 SELECT randomblob(100) FROM t2; 1287df42abaSdan INSERT INTO t2 SELECT randomblob(100) FROM t2; 1297df42abaSdan INSERT INTO t2 SELECT randomblob(100) FROM t2; 1307df42abaSdan INSERT INTO t2 SELECT randomblob(100) FROM t2; 1317df42abaSdan INSERT INTO t2 SELECT randomblob(100) FROM t2; 1327df42abaSdan } 133705a4875Sdan lappend res $b 1347df42abaSdan } 135705a4875Sdan set res 1367df42abaSdan } msg] $msg 137705a4875Sdan} $res23 1387df42abaSdan 1397df42abaSdan#------------------------------------------------------------------------- 1407df42abaSdanreset_db 1417df42abaSdan 1427df42abaSdan# Initialize the database. 1437df42abaSdan# 1447df42abaSdando_execsql_test 3.1 { 1457df42abaSdan PRAGMA page_size=1024; 1467df42abaSdan 1477df42abaSdan CREATE TABLE t1(a INTEGER PRIMARY KEY, b); 1487df42abaSdan INSERT INTO t1 VALUES(1, 'one'); 1497df42abaSdan INSERT INTO t1 VALUES(2, 'two'); 1507df42abaSdan 1517df42abaSdan CREATE TABLE t2(c INTEGER PRAGMA KEY, d); 1527df42abaSdan INSERT INTO t2 VALUES(1, randomblob(1100)); 1537df42abaSdan} {} 1547df42abaSdan 1557df42abaSdando_test 3.2 { 1567df42abaSdan db eval { SELECT name, rootpage FROM sqlite_master } { 1577df42abaSdan set r($name) $rootpage 1587df42abaSdan } 1597df42abaSdan db close 1607df42abaSdan 1617df42abaSdan hexio_write test.db [expr {($r(t2)-1) * 1024 + 1020}] 00000002 1627df42abaSdan 1637df42abaSdan sqlite3 db test.db 1647df42abaSdan} {} 1657df42abaSdan 1667df42abaSdando_test 3.3 { 1677df42abaSdan list [catch { 1687df42abaSdan db eval { SELECT * FROM t1 WHERE a IN (1, 2) } { 1697df42abaSdan db eval { 1707df42abaSdan DELETE FROM t2 WHERE c=1; 1717df42abaSdan } 1727df42abaSdan } 1737df42abaSdan } msg] $msg 1747df42abaSdan} {1 {database disk image is malformed}} 1757df42abaSdan 1767df42abaSdanfinish_test 177