xref: /sqlite-3.40.0/test/corrupt9.test (revision 09fe6143)
11013148bSdrh# 2008 July 9
21013148bSdrh#
31013148bSdrh# The author disclaims copyright to this source code.  In place of
41013148bSdrh# a legal notice, here is a blessing:
51013148bSdrh#
61013148bSdrh#    May you do good and not evil.
71013148bSdrh#    May you find forgiveness for yourself and forgive others.
81013148bSdrh#    May you share freely, never taking more than you give.
91013148bSdrh#
101013148bSdrh#***********************************************************************
111013148bSdrh# This file implements regression tests for SQLite library.
121013148bSdrh#
131013148bSdrh# This file implements tests to make sure SQLite does not crash or
141013148bSdrh# segfault if it sees a corrupt database file.  It specifically focuses
15e71169baSshane# on corruption in the form of duplicate entries on the freelist.
161013148bSdrh#
17e71169baSshane# $Id: corrupt9.test,v 1.3 2009/06/04 02:47:04 shane Exp $
181013148bSdrh
191013148bSdrhset testdir [file dirname $argv0]
201013148bSdrhsource $testdir/tester.tcl
211013148bSdrh
2268928b6cSdan# Do not use a codec for tests in this file, as the database file is
2368928b6cSdan# manipulated directly using tcl scripts (using the [hexio_write] command).
2468928b6cSdan#
2568928b6cSdando_not_use_codec
2668928b6cSdan
27*09fe6143Sdrh# These tests deal with corrupt database files
28*09fe6143Sdrh#
29*09fe6143Sdrhdatabase_may_be_corrupt
30*09fe6143Sdrh
311013148bSdrh# We must have the page_size pragma for these tests to work.
321013148bSdrh#
331013148bSdrhifcapable !pager_pragmas {
341013148bSdrh  finish_test
351013148bSdrh  return
361013148bSdrh}
371013148bSdrh
381013148bSdrh# Return the offset to the first (trunk) page of the freelist.  Return
391013148bSdrh# zero of the freelist is empty.
401013148bSdrh#
411013148bSdrhproc freelist_trunk_offset {filename} {
421013148bSdrh  if {[hexio_read $filename 36 4]==0} {return 0}
431013148bSdrh  set pgno [hexio_get_int [hexio_read $filename 32 4]]
441013148bSdrh  return [expr {($pgno-1)*[hexio_get_int [hexio_read $filename 16 2]]}]
451013148bSdrh}
461013148bSdrh
471013148bSdrh# This procedure looks at the first trunk page of the freelist and
481013148bSdrh# corrupts that page by overwriting up to N entries with duplicates
491013148bSdrh# of the first entry.
501013148bSdrh#
511013148bSdrhproc corrupt_freelist {filename N} {
521013148bSdrh  set offset [freelist_trunk_offset $filename]
531013148bSdrh  if {$offset==0} {error "Freelist is empty"}
541013148bSdrh  set cnt [hexio_get_int [hexio_read $filename [expr {$offset+4}] 4]]
551013148bSdrh  set pgno [hexio_read $filename [expr {$offset+8}] 4]
561013148bSdrh  for {set i 12} {$N>0 && $i<8+4*$cnt} {incr i 4; incr N -1} {
571013148bSdrh    hexio_write $filename [expr {$offset+$i}] $pgno
581013148bSdrh  }
591013148bSdrh}
601013148bSdrh
611013148bSdrh# Create a database to work with.  Make sure there are plenty of
621013148bSdrh# entries on the freelist.
631013148bSdrh#
641013148bSdrhdo_test corrupt9-1.1 {
651013148bSdrh  execsql {
667830cd41Sdrh    PRAGMA auto_vacuum=NONE;
671013148bSdrh    PRAGMA page_size=1024;
681013148bSdrh    CREATE TABLE t1(x);
691013148bSdrh    INSERT INTO t1(x) VALUES(1);
701013148bSdrh    INSERT INTO t1(x) VALUES(2);
711013148bSdrh    INSERT INTO t1(x) SELECT x+2 FROM t1;
721013148bSdrh    INSERT INTO t1(x) SELECT x+4 FROM t1;
731013148bSdrh    INSERT INTO t1(x) SELECT x+8 FROM t1;
741013148bSdrh    INSERT INTO t1(x) SELECT x+16 FROM t1;
751013148bSdrh    INSERT INTO t1(x) SELECT x+32 FROM t1;
761013148bSdrh    INSERT INTO t1(x) SELECT x+64 FROM t1;
771013148bSdrh    INSERT INTO t1(x) SELECT x+128 FROM t1;
781013148bSdrh    INSERT INTO t1(x) SELECT x+256 FROM t1;
791013148bSdrh    CREATE TABLE t2(a,b);
801013148bSdrh    INSERT INTO t2 SELECT x, x*x FROM t1;
811013148bSdrh    CREATE INDEX i1 ON t1(x);
821013148bSdrh    CREATE INDEX i2 ON t2(b,a);
831013148bSdrh    DROP INDEX i2;
841013148bSdrh  }
851013148bSdrh  expr {[file size test.db]>1024*24}
861013148bSdrh} {1}
871013148bSdrhintegrity_check corrupt9-1.2
881013148bSdrh
891013148bSdrh# Corrupt the freelist by adding duplicate entries to the freelist.
901013148bSdrh# Make sure the corruption is detected.
911013148bSdrh#
921013148bSdrhdb close
93fda06befSmistachkinforcecopy test.db test.db-template
941013148bSdrh
951013148bSdrhcorrupt_freelist test.db 1
961013148bSdrhsqlite3 db test.db
971013148bSdrhdo_test corrupt9-2.1 {
981013148bSdrh  set x [db eval {PRAGMA integrity_check}]
991013148bSdrh  expr {$x!="ok"}
1001013148bSdrh} {1}
1011013148bSdrhdo_test corrupt9-2.2 {
1021013148bSdrh  catchsql {
1031013148bSdrh    CREATE INDEX i2 ON t2(b,a);
1041013148bSdrh    REINDEX;
1051013148bSdrh  }
1061013148bSdrh} {1 {database disk image is malformed}}
1071013148bSdrh
1081013148bSdrh
1091013148bSdrhdb close
110fda06befSmistachkinforcecopy test.db-template test.db
1111013148bSdrhcorrupt_freelist test.db 2
1121013148bSdrhsqlite3 db test.db
1131013148bSdrhdo_test corrupt9-3.1 {
1141013148bSdrh  set x [db eval {PRAGMA integrity_check}]
1151013148bSdrh  expr {$x!="ok"}
1161013148bSdrh} {1}
1171013148bSdrhdo_test corrupt9-3.2 {
1181013148bSdrh  catchsql {
1191013148bSdrh    CREATE INDEX i2 ON t2(b,a);
1201013148bSdrh    REINDEX;
1211013148bSdrh  }
1221013148bSdrh} {1 {database disk image is malformed}}
1231013148bSdrh
1241013148bSdrhdb close
125fda06befSmistachkinforcecopy test.db-template test.db
1261013148bSdrhcorrupt_freelist test.db 3
1271013148bSdrhsqlite3 db test.db
1281013148bSdrhdo_test corrupt9-4.1 {
1291013148bSdrh  set x [db eval {PRAGMA integrity_check}]
1301013148bSdrh  expr {$x!="ok"}
1311013148bSdrh} {1}
1321013148bSdrhdo_test corrupt9-4.2 {
1331013148bSdrh  catchsql {
1341013148bSdrh    CREATE INDEX i2 ON t2(b,a);
1351013148bSdrh    REINDEX;
1361013148bSdrh  }
1371013148bSdrh} {1 {database disk image is malformed}}
1381013148bSdrh
1391013148bSdrh
1401013148bSdrhfinish_test
141