xref: /sqlite-3.40.0/test/corrupt4.test (revision 99bd5525)
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