1 2# 2007 Aug 13 3# 4# The author disclaims copyright to this source code. In place of 5# a legal notice, here is a blessing: 6# 7# May you do good and not evil. 8# May you find forgiveness for yourself and forgive others. 9# May you share freely, never taking more than you give. 10# 11#*********************************************************************** 12# 13# This file tests aspects of recovery from a malloc() failure 14# in a CREATE INDEX statement. 15# 16# $Id: crash5.test,v 1.3 2008/07/12 14:52:20 drh Exp $ 17 18set testdir [file dirname $argv0] 19source $testdir/tester.tcl 20 21# Only run these tests if memory debugging is turned on. 22# 23ifcapable !memdebug||!crashtest||!memorymanage { 24 puts "Skipping crash5 tests: not compiled with -DSQLITE_MEMDEBUG..." 25 finish_test 26 return 27} 28 29db close 30 31for {set ii 0} {$ii < 10} {incr ii} { 32 for {set jj 50} {$jj < 100} {incr jj} { 33 34 # Set up the database so that it is an auto-vacuum database 35 # containing a single table (root page 3) with a single row. 36 # The row has an overflow page (page 4). 37 file delete -force test.db test.db-journal 38 sqlite3 db test.db 39 set c [string repeat 3 1500] 40 db eval { 41 pragma auto_vacuum = 1; 42 CREATE TABLE t1(a, b, c); 43 INSERT INTO t1 VALUES('1111111111', '2222222222', $c); 44 } 45 db close 46 47 do_test crash5-$ii.$jj.1 { 48 crashsql -delay 1 -file test.db-journal -seed $ii -tclbody [join [list \ 49 [list set iFail $jj] { 50 sqlite3_crashparams 0 [file join [pwd] test.db-journal] 51 52 # Begin a transaction and evaluate a "CREATE INDEX" statement 53 # with the iFail'th malloc() set to fail. This operation will 54 # have to move the current contents of page 4 (the overflow 55 # page) to make room for the new root page. The bug is that 56 # if malloc() fails at a particular point in sqlite3PagerMovepage(), 57 # sqlite mistakenly thinks that the page being moved (page 4) has 58 # been safely synced into the journal. If the page is written 59 # to later in the transaction, it may be written out to the database 60 # before the relevant part of the journal has been synced. 61 # 62 db eval BEGIN 63 sqlite3_memdebug_fail $iFail -repeat 0 64 catch {db eval { CREATE UNIQUE INDEX i1 ON t1(a); }} msg 65 # puts "$n $msg ac=[sqlite3_get_autocommit db]" 66 67 # If the transaction is still active (it may not be if the malloc() 68 # failure occured in the OS layer), write to the database. Make sure 69 # page 4 is among those written. 70 # 71 if {![sqlite3_get_autocommit db]} { 72 db eval { 73 DELETE FROM t1; -- This will put page 4 on the free list. 74 INSERT INTO t1 VALUES('111111111', '2222222222', '33333333'); 75 INSERT INTO t1 SELECT * FROM t1; -- 2 76 INSERT INTO t1 SELECT * FROM t1; -- 4 77 INSERT INTO t1 SELECT * FROM t1; -- 8 78 INSERT INTO t1 SELECT * FROM t1; -- 16 79 INSERT INTO t1 SELECT * FROM t1; -- 32 80 INSERT INTO t1 SELECT * FROM t1 WHERE rowid%2; -- 48 81 } 82 } 83 84 # If the right malloc() failed during the 'CREATE INDEX' above and 85 # the transaction was not rolled back, then the sqlite cache now 86 # has a dirty page 4 that it incorrectly believes is already safely 87 # in the synced part of the journal file. When 88 # sqlite3_release_memory() is called sqlite tries to free memory 89 # by writing page 4 out to the db file. If it crashes later on, 90 # before syncing the journal... Corruption! 91 # 92 sqlite3_crashparams 1 [file join [pwd] test.db-journal] 93 sqlite3_release_memory 8092 94 }]] {} 95 expr 1 96 } {1} 97 98 sqlite3 db test.db 99 do_test crash5-$ii.$jj.2 { 100 db eval {pragma integrity_check} 101 } {ok} 102 do_test crash5-$ii.$jj.3 { 103 db eval {SELECT * FROM t1} 104 } [list 1111111111 2222222222 $::c] 105 db close 106 } 107} 108 109 110finish_test 111