1# 2014-01-20 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# 12 13set testdir [file dirname $argv0] 14source $testdir/tester.tcl 15set testprefix corruptI 16 17if {[permutation]=="mmap"} { 18 finish_test 19 return 20} 21 22# This module uses hard-coded offsets which do not work if the reserved_bytes 23# value is nonzero. 24if {[nonzero_reserved_bytes]} {finish_test; return;} 25 26database_may_be_corrupt 27 28# Initialize the database. 29# 30do_execsql_test 1.1 { 31 PRAGMA page_size=1024; 32 PRAGMA auto_vacuum=0; 33 CREATE TABLE t1(a); 34 CREATE INDEX i1 ON t1(a); 35 INSERT INTO t1 VALUES('abcdefghijklmnop'); 36} {} 37db close 38 39do_test 1.2 { 40 set offset [hexio_get_int [hexio_read test.db [expr 2*1024 + 8] 2]] 41 set off [expr 2*1024 + $offset + 1] 42 hexio_write test.db $off 7f06 43 sqlite3 db test.db 44 catchsql { SELECT * FROM t1 WHERE a = 10 } 45} {0 {}} 46 47do_test 1.3 { 48 db close 49 set offset [hexio_get_int [hexio_read test.db [expr 2*1024 + 8] 2]] 50 set off [expr 2*1024 + $offset + 1] 51 hexio_write test.db $off FFFF7f02 52 sqlite3 db test.db 53 catchsql { SELECT * FROM t1 WHERE a = 10 } 54} {1 {database disk image is malformed}} 55 56do_test 2.0 { 57 execsql { 58 CREATE TABLE r(x); 59 INSERT INTO r VALUES('ABCDEFGHIJK'); 60 CREATE INDEX r1 ON r(x); 61 } 62 set pg [db one {SELECT rootpage FROM sqlite_master WHERE name = 'r1'}] 63} {5} 64 65do_test 2.1 { 66 db close 67 set offset [hexio_get_int [hexio_read test.db [expr (5-1)*1024 + 8] 2]] 68 set off [expr (5-1)*1024 + $offset + 1] 69 hexio_write test.db $off FFFF0004 70 sqlite3 db test.db 71 catchsql { SELECT * FROM r WHERE x >= 10.0 } 72} {1 {database disk image is malformed}} 73 74do_test 2.2 { 75 catchsql { SELECT * FROM r WHERE x >= 10 } 76} {1 {database disk image is malformed}} 77 78if {[db one {SELECT sqlite_compileoption_used('ENABLE_OVERSIZE_CELL_CHECK')}]} { 79 # The following tests only work if OVERSIZE_CELL_CHECK is disabled 80} else { 81 reset_db 82 do_execsql_test 3.1 { 83 PRAGMA auto_vacuum=0; 84 PRAGMA page_size = 512; 85 CREATE TABLE t1(a INTEGER PRIMARY KEY, b); 86 WITH s(a, b) AS ( 87 SELECT 2, 'abcdefghij' 88 UNION ALL 89 SELECT a+2, b FROM s WHERe a < 40 90 ) 91 INSERT INTO t1 SELECT * FROM s; 92 } {} 93 94 do_test 3.2 { 95 hexio_write test.db [expr 512+3] 0054 96 db close 97 sqlite3 db test.db 98 execsql { INSERT INTO t1 VALUES(5, 'klmnopqrst') } 99 execsql { INSERT INTO t1 VALUES(7, 'klmnopqrst') } 100 } {} 101 102 db close 103 sqlite3 db test.db 104 do_catchsql_test 3.3 { 105 INSERT INTO t1 VALUES(9, 'klmnopqrst'); 106 } {1 {database disk image is malformed}} 107} ;# end-if !defined(ENABLE_OVERSIZE_CELL_CHECK) 108 109 110#------------------------------------------------------------------------- 111# Test that an assert() failure discovered by AFL corrupt database file 112# testing has been fixed. 113# 114reset_db 115do_execsql_test 4.0 { 116 PRAGMA page_size = 65536; 117 PRAGMA autovacuum = 0; 118 CREATE TABLE t1(a INTEGER PRIMARY KEY, b); 119 INSERT INTO t1 VALUES(-1, 'abcdefghij'); 120 INSERT INTO t1 VALUES(0, 'abcdefghij'); 121} 122 123set root [db one {SELECT rootpage FROM sqlite_master}] 124set offset [expr ($root-1) * 65536] 125 126ifcapable oversize_cell_check { 127 set res {1 {database disk image is malformed}} 128} else { 129 set res {0 {}} 130} 131do_test 4.1 { 132 db close 133 hexio_write test.db [expr $offset + 8 + 2] 0000 134 hexio_write test.db [expr $offset + 5] 0000 135 sqlite3 db test.db 136 catchsql { DELETE FROM t1 WHERE a=0 } 137} $res 138 139 140#------------------------------------------------------------------------- 141# Database properties: 142# 143# * Incremental vacuum mode. 144# * Database root table has a single leaf page. 145# * Free list consists of a single trunk page. 146# 147# The db is then corrupted by adding the root table leaf page as a free-list 148# leaf page (so that it is referenced twice). 149# 150# Then, a new table is created. The new root page is the current free-list 151# trunk. This means that the root table leaf page is made into the new 152# free list trunk, which corrupts its header. Then, when the new entry is 153# inserted into the root table, things would get chaotic. 154# 155reset_db 156do_test 5.0 { 157 execsql { 158 PRAGMA page_size = 512; 159 PRAGMA auto_vacuum = 2; 160 } 161 for {set i 3} {1} {incr i} { 162 execsql "CREATE TABLE t${i}(x)" 163 if {[db one {PRAGMA page_count}]>$i} break 164 } 165 set nPage [db one {PRAGMA page_count}] 166 execsql { 167 CREATE TABLE t100(x); 168 DROP TABLE t100; 169 } 170} {} 171 172do_execsql_test 5.1 { 173 PRAGMA page_count 174} [expr $nPage+1] 175 176do_test 5.2 { 177 # The last page of the db is now the only leaf of the sqlite_master table. 178 # Corrupt the db by adding it to the free-list as well (the second last 179 # page of the db is the free-list trunk). 180 db close 181 hexio_write test.db [expr 512*($nPage-1)] [ 182 format "%.8X%.8X%.8X" 0 1 [expr $nPage+1] 183 ] 184} {12} 185 186do_test 5.3 { 187 sqlite3 db test.db 188 catchsql { CREATE TABLE tx(x); } 189} {1 {database disk image is malformed}} 190 191 192#------------------------------------------------------------------------- 193# Set the payload size of a cell to just less than 2^32 bytes (not 194# possible in an uncorrupted db). Then try to delete the cell. At one 195# point this led to an integer overflow that caused an assert() to fail. 196# 197reset_db 198do_execsql_test 6.0 { 199 PRAGMA page_size = 512; 200 PRAGMA auto_vacuum=0; 201 CREATE TABLE t1(x); 202 INSERT INTO t1 VALUES(zeroblob(300)); 203 INSERT INTO t1 VALUES(zeroblob(600)); 204} {} 205do_test 6.1 { 206 db close 207 hexio_write test.db 616 8FFFFFFF7F02 208 sqlite3 db test.db 209 execsql { DELETE FROM t1 WHERE rowid=2 } 210} {} 211 212#------------------------------------------------------------------------- 213# See what happens if the sqlite_master entry associated with a PRIMARY 214# KEY or UNIQUE index is removed. 215# 216reset_db 217do_execsql_test 7.0 { 218 PRAGMA auto_vacuum=0; 219 CREATE TABLE t1(x PRIMARY KEY, y); 220 INSERT INTO t1 VALUES('a', 'A'); 221 INSERT INTO t1 VALUES('b', 'A'); 222 INSERT INTO t1 VALUES('c', 'A'); 223 SELECT name FROM sqlite_master; 224} {t1 sqlite_autoindex_t1_1} 225sqlite3_db_config db DEFENSIVE 0 226do_execsql_test 7.1 { 227 PRAGMA writable_schema = 1; 228 DELETE FROM sqlite_master WHERE name = 'sqlite_autoindex_t1_1'; 229} 230do_test 7.2 { 231 db close 232 sqlite3 db test.db 233 catchsql { UPDATE t1 SET x='d' AND y='D' WHERE rowid = 2 } 234} {1 {database disk image is malformed}} 235 236#------------------------------------------------------------------------- 237# At one point an assert() would fail if attempt was made to free page 1. 238# 239reset_db 240do_execsql_test 8.0 { 241 PRAGMA auto_vacuum=0; 242 CREATE TABLE t1(x); 243 INSERT INTO t1 VALUES(zeroblob(300)); 244 INSERT INTO t1 VALUES(zeroblob(300)); 245 INSERT INTO t1 VALUES(zeroblob(300)); 246 INSERT INTO t1 VALUES(zeroblob(300)); 247} {} 248 249do_test 8.1 { 250 db close 251 hexio_write test.db [expr 1024 + 8] 00000001 252 sqlite3 db test.db 253 catchsql { DELETE FROM t1 } 254} {1 {database disk image is malformed}} 255 256do_test 8.2 { 257 db close 258 sqlite3 db test.db 259 execsql { PRAGMA integrity_check } 260} {/.*in database main.*/} 261 262 263finish_test 264