]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add test cases to test the libraries handling of corrupt wal-index headers.
authordan <dan@noemail.net>
Thu, 6 May 2010 11:32:09 +0000 (11:32 +0000)
committerdan <dan@noemail.net>
Thu, 6 May 2010 11:32:09 +0000 (11:32 +0000)
FossilOrigin-Name: 9465b267d420120c050bbe4f143ac824146a9e4a

manifest
manifest.uuid
src/wal.c
test/wal2.test [new file with mode: 0644]
test/walfault.test

index 4405e02f41376f93458487ad483934c990f31786..12e762b0caee01e9551fb8235abb79c976e4bc79 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\stests\sfor\shandling\serrors\sreturned\sby\sxShm\sVFS\smethods.
-D 2010-05-06T07:43:58
+C Add\stest\scases\sto\stest\sthe\slibraries\shandling\sof\scorrupt\swal-index\sheaders.
+D 2010-05-06T11:32:09
 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
 F Makefile.in d83a0ffef3dcbfb08b410a6c6dd6c009ec9167fb
 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -222,7 +222,7 @@ F src/vdbeblob.c 5327132a42a91e8b7acfb60b9d2c3b1c5c863e0e
 F src/vdbemem.c 2a82f455f6ca6f78b59fb312f96054c04ae0ead1
 F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
 F src/vtab.c a0f8a40274e4261696ef57aa806de2776ab72cda
-F src/wal.c 65a29bce101f417ca59b33f64a003b16dc993616
+F src/wal.c 2db3bd804def9c18008c99408a81cd6eafc12a99
 F src/wal.h b4c42014b5fa3b4e6244ac8c65de7ff67adeb27c
 F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
 F src/where.c 75fee9e255b62f773fcadd1d1f25b6f63ac7a356
@@ -760,9 +760,10 @@ F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5
 F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
 F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d
 F test/wal.test f0b331017a12a31dd4bbb20aee9c179fbfdd5921
+F test/wal2.test cf110b3231c7282439bef62daebcf81a993b62c9
 F test/walbak.test a0e45187c7d8928df035dfea29b99b016b21ca3c
 F test/walcrash.test f6d5fb2bb108876f04848720a488065d9deef69f
-F test/walfault.test 3b62e7d2ca93f1e926953b2998361fee193a1fb7
+F test/walfault.test 2d6e00e07ae4287d6ae552589bcc8532697d8173
 F test/walhook.test a1c375ae791d5d7d511c166159729230791c574d
 F test/walmode.test bac6f06544a8554588a1543def996bbe2fc41792
 F test/walslow.test d21625e2e99e11c032ce949e8a94661576548933
@@ -810,7 +811,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P 1b14195e05fe5551992a39246ec3bcf6a33bbfac
-R 247944e575aec0054be286769ecb9238
+P fbbcacb137e8f5246b88ad09331236aaa1900f60
+R c23cc19ecc9b2f6c130b1979d4249711
 U dan
-Z 914dd1e720da590c7d1ff592008c385f
+Z 7712493005da602cd936a05bd6144f71
index 03d18cba13fab16d35d787ba9d98dd4985534cc6..f114d972826d63e8f59a1f5ab8103dea53cbbb62 100644 (file)
@@ -1 +1 @@
-fbbcacb137e8f5246b88ad09331236aaa1900f60
\ No newline at end of file
+9465b267d420120c050bbe4f143ac824146a9e4a
\ No newline at end of file
index 0a3657c3b5984a2f0334fb7c8a7949a615f63d9c..9bc1660adad16c1e0fa0a41141624812565a4f8b 100644 (file)
--- a/src/wal.c
+++ b/src/wal.c
@@ -694,10 +694,8 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){
   nByte = sizeof(WalIterator) + (nSegment-1)*sizeof(struct WalSegment) + 512;
   p = (WalIterator *)sqlite3_malloc(nByte);
   if( !p ){
-    return SQLITE_NOMEM;
-  }
-
-  if( p ){
+    rc = SQLITE_NOMEM;
+  }else{
     memset(p, 0, nByte);
     p->nSegment = nSegment;
 
@@ -718,7 +716,7 @@ static int walIteratorInit(Wal *pWal, WalIterator **pp){
   }
 
   *pp = p;
-  return SQLITE_OK;
+  return rc;
 }
 
 /* 
diff --git a/test/wal2.test b/test/wal2.test
new file mode 100644 (file)
index 0000000..ddb8021
--- /dev/null
@@ -0,0 +1,239 @@
+# 2010 May 5
+#
+# The author disclaims copyright to this source code.  In place of
+# a legal notice, here is a blessing:
+#
+#    May you do good and not evil.
+#    May you find forgiveness for yourself and forgive others.
+#    May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library.  The
+# focus of this file is testing the operation of the library in
+# "PRAGMA journal_mode=WAL" mode.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+source $testdir/lock_common.tcl
+ifcapable !wal {finish_test ; return }
+
+proc set_tvfs_hdr {file args} {
+  if {[llength $args]>1} {
+    return -code error {wrong # args: should be "set_tvfs_hdr fileName ?val?"}
+  }
+
+  set blob [tvfs shm $file]
+  if {[llength $args]} {
+    set blob [binary format i8a* [lindex $args 0] [string range $blob 32 end]]
+    tvfs shm $file $blob
+  }
+
+  binary scan $blob i8 ints
+  return $ints
+}
+
+proc incr_tvfs_hdr {file idx incrval} {
+  set ints [set_tvfs_hdr $file]
+  set v [lindex $ints $idx]
+  incr v $incrval
+  lset ints $idx $v
+  set_tvfs_hdr $file $ints
+}
+
+
+#-------------------------------------------------------------------------
+# Test case wal2-1.*:
+#
+# Set up a small database containing a single table. The database is not
+# checkpointed during the test - all content resides in the log file.
+#
+# Two connections are established to the database file - a writer ([db])
+# and a reader ([db2]). For each of the 8 integer fields in the wal-index
+# header (6 fields and 2 checksum values), do the following:
+#
+#   1. Modify the database using the writer.
+#
+#   2. Attempt to read the database using the reader. Before the reader
+#      has a chance to snapshot the wal-index header, increment one
+#      of the the integer fields (so that the reader ends up with a corrupted
+#      header).
+#
+#   3. Check that the reader recovers the wal-index and reads the correct
+#      database content.
+#
+do_test wal2-1.0 {
+  proc tvfs_cb {method args} { return SQLITE_OK }
+  testvfs tvfs tvfs_cb
+
+  sqlite3 db  test.db -vfs tvfs
+  sqlite3 db2 test.db -vfs tvfs
+
+  execsql {
+    PRAGMA journal_mode = WAL;
+    CREATE TABLE t1(a);
+  } db2
+  execsql {
+    INSERT INTO t1 VALUES(1);
+    INSERT INTO t1 VALUES(2);
+    INSERT INTO t1 VALUES(3);
+    INSERT INTO t1 VALUES(4);
+    SELECT count(a), sum(a) FROM t1;
+  }
+} {4 10}
+do_test wal2-1.1 {
+  execsql { SELECT count(a), sum(a) FROM t1 } db2
+} {4 10}
+
+foreach {tn iInsert res wal_index_hdr_mod wal_locks} {
+         2    5   {5 15}    0             {READ RECOVER READ UNLOCK}
+         3    6   {6 21}    1             {READ RECOVER READ UNLOCK}
+         4    7   {7 28}    2             {READ RECOVER READ UNLOCK}
+         5    8   {8 36}    3             {READ RECOVER READ UNLOCK}
+         6    9   {9 45}    4             {READ RECOVER READ UNLOCK}
+         7   10   {10 55}   5             {READ RECOVER READ UNLOCK}
+         8   11   {11 66}   6             {READ RECOVER READ UNLOCK}
+         9   12   {12 78}   7             {READ RECOVER READ UNLOCK}
+        10   13   {13 91}   -1            {READ UNLOCK}
+} {
+
+  do_test wal2-1.$tn.1 {
+    execsql { INSERT INTO t1 VALUES($iInsert) }
+
+    set ::locks [list]
+    set ::cb_done 0
+
+    proc tvfs_cb {method args} {
+      if {$::cb_done == 0 && $method == "xShmGet"} {
+        set ::cb_done 1
+        if {$::wal_index_hdr_mod >= 0} {
+          incr_tvfs_hdr [lindex $args 0] $::wal_index_hdr_mod 1
+        }
+      }
+
+      if {$method == "xShmLock"} { lappend ::locks [lindex $args 2] }
+      return SQLITE_OK
+    }
+
+    execsql { SELECT count(a), sum(a) FROM t1 } db2
+  } $res
+
+  do_test wal2-1.$tn.2 {
+    set ::locks
+  } $wal_locks
+}
+db close
+db2 close
+tvfs delete
+file delete -force test.db test.db-wal test.db-journal
+
+#-------------------------------------------------------------------------
+# This test case is very similar to the previous one, except, after
+# the reader reads the corrupt wal-index header, but before it has
+# a chance to re-read it under the cover of the RECOVER lock, the
+# wal-index header is replaced with a valid, but out-of-date, header.
+#
+# Because the header checksum looks Ok, the reader does not run recovery,
+# it simply drops back to a READ lock and proceeds. But because the
+# header is out-of-date, the reader reads the out-of-date snapshot.
+#
+# After this, the header is corrupted again and the reader is allowed
+# to run recovery. This time, it sees an up-to-date snapshot of the
+# database file.
+#
+do_test wal2-2.0 {
+
+  testvfs tvfs tvfs_cb
+  proc tvfs_cb {method args} {
+    if {$method == "xShmOpen"} { set ::shm_file [lindex $args 0] }
+    return SQLITE_OK
+  }
+
+  sqlite3 db  test.db -vfs tvfs
+  sqlite3 db2 test.db -vfs tvfs
+
+  execsql {
+    PRAGMA journal_mode = WAL;
+    CREATE TABLE t1(a);
+  } db2
+  execsql {
+    INSERT INTO t1 VALUES(1);
+    INSERT INTO t1 VALUES(2);
+    INSERT INTO t1 VALUES(3);
+    INSERT INTO t1 VALUES(4);
+    SELECT count(a), sum(a) FROM t1;
+  }
+} {4 10}
+do_test wal2-2.1 {
+  execsql { SELECT count(a), sum(a) FROM t1 } db2
+} {4 10}
+
+foreach {tn iInsert res0 res1 wal_index_hdr_mod} {
+         2    5   {4 10}   {5 15}    0
+         3    6   {5 15}   {6 21}    1
+         4    7   {6 21}   {7 28}    2
+         5    8   {7 28}   {8 36}    3
+         6    9   {8 36}   {9 45}    4
+         7   10   {9 45}   {10 55}   5
+         8   11   {10 55}  {11 66}   6
+         9   12   {11 66}  {12 78}   7
+} {
+  do_test wal2-1.$tn.1 {
+    set oldhdr [set_tvfs_hdr $::shm_file]
+    execsql { INSERT INTO t1 VALUES($iInsert) }
+    execsql { SELECT count(a), sum(a) FROM t1 }
+  } $res1
+
+  do_test wal2-2.$tn.2 {
+    set ::locks [list]
+    set ::cb_done 0
+    proc tvfs_cb {method args} {
+      if {$::cb_done == 0 && $method == "xShmGet"} {
+        set ::cb_done 1
+        if {$::wal_index_hdr_mod >= 0} {
+          incr_tvfs_hdr $::shm_file $::wal_index_hdr_mod 1
+        }
+      }
+      if {$method == "xShmLock"} {
+        set lock [lindex $args 2]
+        lappend ::locks $lock
+        if {$lock == "RECOVER"} {
+          set_tvfs_hdr $::shm_file $::oldhdr
+        }
+      }
+      return SQLITE_OK
+    }
+
+    execsql { SELECT count(a), sum(a) FROM t1 } db2
+  } $res0
+
+  do_test wal2-2.$tn.3 {
+    set ::locks
+  } {READ RECOVER READ UNLOCK}
+
+  do_test wal2-2.$tn.4 {
+    set ::locks [list]
+    set ::cb_done 0
+    proc tvfs_cb {method args} {
+      if {$::cb_done == 0 && $method == "xShmGet"} {
+        set ::cb_done 1
+        if {$::wal_index_hdr_mod >= 0} {
+          incr_tvfs_hdr $::shm_file $::wal_index_hdr_mod 1
+        }
+      }
+      if {$method == "xShmLock"} {
+        set lock [lindex $args 2]
+        lappend ::locks $lock
+      }
+      return SQLITE_OK
+    }
+
+    execsql { SELECT count(a), sum(a) FROM t1 } db2
+  } $res1
+}
+db close
+db2 close
+tvfs delete
+file delete -force test.db test.db-wal test.db-journal
+
+finish_test
index 5bc78eb9dd3b58f58cffb092cd00c5bfc5d320e4..8702af5d828aba7194cea8ec6bb1e58bff3cb2d6 100644 (file)
@@ -52,6 +52,16 @@ do_malloc_test walfault-oom-2 -tclprep {
   SELECT count(*) FROM x;
 }
 
+do_ioerr_test walfault-ioerr-1 -sqlprep {
+  PRAGMA auto_vacuum = 1;
+  PRAGMA journal_mode = WAL;
+  CREATE TABLE abc(a PRIMARY KEY);
+  INSERT INTO abc VALUES(randomblob(1500));
+} -sqlbody {
+  DELETE FROM abc;
+  PRAGMA wal_checkpoint;
+}
+
 # A [testvfs] callback for the VFS created by [do_shmfault_test]. This
 # callback injects SQLITE_IOERR faults into methods for which an entry
 # in array ::shmfault_ioerr_methods is defined. For example, to enable
@@ -196,7 +206,6 @@ do_shmfault_test walfault-shm-3 -methods xShmSize -tclprep {
   if {[file exists test.db-wal]==0} {error "Failed to create WAL file!"}
 
   sqlite3 db test.db -vfs shmfault
-breakpoint
 } -sqlbody {
   SELECT count(*) FROM t1;
 }