xref: /sqlite-3.40.0/test/corruptI.test (revision 2fc3a6cd)
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# Do not use a codec for tests in this file, as the database file is
23# manipulated directly using tcl scripts (using the [hexio_write] command).
24#
25do_not_use_codec
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
126do_test 4.1 {
127  db close
128  hexio_write test.db [expr $offset + 8 + 2] 0000
129  hexio_write test.db [expr $offset + 5] 0000
130  sqlite3 db test.db
131  execsql { DELETE FROM t1 WHERE a=0 }
132} {}
133
134
135#-------------------------------------------------------------------------
136# Database properties:
137#
138#   * Incremental vacuum mode.
139#   * Database root table has a single leaf page.
140#   * Free list consists of a single trunk page.
141#
142# The db is then corrupted by adding the root table leaf page as a free-list
143# leaf page (so that it is referenced twice).
144#
145# Then, a new table is created. The new root page is the current free-list
146# trunk. This means that the root table leaf page is made into the new
147# free list trunk, which corrupts its header. Then, when the new entry is
148# inserted into the root table, things would get chaotic.
149#
150reset_db
151do_test 5.0 {
152  execsql {
153    PRAGMA page_size = 512;
154    PRAGMA auto_vacuum = 2;
155  }
156  for {set i 3} {1} {incr i} {
157    execsql "CREATE TABLE t${i}(x)"
158    if {[db one {PRAGMA page_count}]>$i} break
159  }
160  set nPage [db one {PRAGMA page_count}]
161  execsql {
162    CREATE TABLE t100(x);
163    DROP TABLE t100;
164  }
165} {}
166
167do_execsql_test 5.1 {
168  PRAGMA page_count
169} [expr $nPage+1]
170
171do_test 5.2 {
172  # The last page of the db is now the only leaf of the sqlite_master table.
173  # Corrupt the db by adding it to the free-list as well (the second last
174  # page of the db is the free-list trunk).
175  db close
176  hexio_write test.db [expr 512*($nPage-1)] [
177    format "%.8X%.8X%.8X" 0 1 [expr $nPage+1]
178  ]
179} {12}
180
181do_test 5.3 {
182  sqlite3 db test.db
183  catchsql { CREATE TABLE tx(x); }
184} {1 {database disk image is malformed}}
185
186
187finish_test
188