]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Test cases and minor changes to make fts3 more robust in the face of a corrupt database.
authordan <dan@noemail.net>
Sat, 30 Oct 2010 15:21:13 +0000 (15:21 +0000)
committerdan <dan@noemail.net>
Sat, 30 Oct 2010 15:21:13 +0000 (15:21 +0000)
FossilOrigin-Name: b770290561f5450e4d985ca0050ef5eb01657c80

ext/fts3/fts3.c
ext/fts3/fts3_write.c
manifest
manifest.uuid
test/fts3corrupt.test
test/fts3corrupt2.test [new file with mode: 0644]

index bf760efe8e54435db87dd7d842977f0e2691029e..5fcb77fb559fa6be567f1b4d0ef6f48efbae3116 100644 (file)
@@ -1001,9 +1001,22 @@ static int fts3ScanInteriorNode(
 
   /* Skip over the 'height' varint that occurs at the start of every 
   ** interior node. Then load the blockid of the left-child of the b-tree
-  ** node into variable iChild.  */
+  ** node into variable iChild.  
+  **
+  ** Even if the data structure on disk is corrupted, this (reading two
+  ** varints from the buffer) does not risk an overread. If zNode is a
+  ** root node, then the buffer comes from a SELECT statement. SQLite does
+  ** not make this guarantee explicitly, but in practice there are always
+  ** either more than 20 bytes of allocated space following the nNode bytes of
+  ** contents, or two zero bytes. Or, if the node is read from the %_segments
+  ** table, then there are always 20 bytes of zeroed padding following the
+  ** nNode bytes of content (see sqlite3Fts3ReadBlock() for details).
+  */
   zCsr += sqlite3Fts3GetVarint(zCsr, &iChild);
   zCsr += sqlite3Fts3GetVarint(zCsr, &iChild);
+  if( zCsr>=zEnd ){
+    return SQLITE_CORRUPT;
+  }
   
   while( zCsr<zEnd && (piFirst || piLast) ){
     int cmp;                      /* memcmp() result */
@@ -1018,13 +1031,18 @@ static int fts3ScanInteriorNode(
     }
     isFirstTerm = 0;
     zCsr += sqlite3Fts3GetVarint32(zCsr, &nSuffix);
+    
+    if( nPrefix<0 || nSuffix<0 || &zCsr[nSuffix]>zEnd ){
+      rc = SQLITE_CORRUPT;
+      goto finish_scan;
+    }
     if( nPrefix+nSuffix>nAlloc ){
       char *zNew;
       nAlloc = (nPrefix+nSuffix) * 2;
       zNew = (char *)sqlite3_realloc(zBuffer, nAlloc);
       if( !zNew ){
-        sqlite3_free(zBuffer);
-        return SQLITE_NOMEM;
+        rc = SQLITE_NOMEM;
+        goto finish_scan;
       }
       zBuffer = zNew;
     }
@@ -1058,6 +1076,7 @@ static int fts3ScanInteriorNode(
   if( piFirst ) *piFirst = iChild;
   if( piLast ) *piLast = iChild;
 
+ finish_scan:
   sqlite3_free(zBuffer);
   return rc;
 }
index 4982c870422e7328f9db08bca2381968628c6707..2f4db406edd03bff893d8803e8b4d4e1b4c6f2af 100644 (file)
@@ -836,6 +836,7 @@ int sqlite3Fts3ReadBlock(
         rc = SQLITE_NOMEM;
       }else{
         rc = sqlite3_blob_read(p->pSegments, aByte, nByte, 0);
+        memset(&aByte[nByte], 0, FTS3_NODE_PADDING);
         if( rc!=SQLITE_OK ){
           sqlite3_free(aByte);
           aByte = 0;
@@ -1143,6 +1144,7 @@ int sqlite3Fts3SegReaderNew(
     pReader->aNode = (char *)&pReader[1];
     pReader->nNode = nRoot;
     memcpy(pReader->aNode, zRoot, nRoot);
+    memset(&pReader->aNode[nRoot], 0, FTS3_NODE_PADDING);
   }else{
     pReader->iCurrentBlock = iStartLeaf-1;
   }
index f0906b1e70bd0e86dd88458c84437ca30d860061..4588df43808837618917ce921d910436e004328a 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sextra\stest\scases\sand\schanges\sto\sfts3\sto\savoid\scrashing\son\sa\scorrupt\sdatabase.
-D 2010-10-29T18:45:11
+C Test\scases\sand\sminor\schanges\sto\smake\sfts3\smore\srobust\sin\sthe\sface\sof\sa\scorrupt\sdatabase.
+D 2010-10-30T15:21:13
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 2c8cefd962eca0147132c7cf9eaa4bb24c656f3f
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -61,7 +61,7 @@ F ext/fts2/mkfts2amal.tcl 974d5d438cb3f7c4a652639262f82418c1e4cff0
 F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
 F ext/fts3/README.tokenizers 998756696647400de63d5ba60e9655036cb966e9
 F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
-F ext/fts3/fts3.c e78273903ca271d90fe30f32832de18b730e5818
+F ext/fts3/fts3.c 48c37f640fb5837dcdbd04ef2d51ec40c8637503
 F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
 F ext/fts3/fts3Int.h 819bc2661c8f3b46221d146f1810dc6741819f55
 F ext/fts3/fts3_expr.c ee48b9278b8b2432a05a03320fbcacba151dbaa5
@@ -73,7 +73,7 @@ F ext/fts3/fts3_snippet.c 300c12b7f0a2a6ae0491bb2d00e2d5ff9c28f685
 F ext/fts3/fts3_tokenizer.c b4f2d01c24573852755bc92864816785dae39318
 F ext/fts3/fts3_tokenizer.h 13ffd9fcb397fec32a05ef5cd9e0fa659bf3dbd3
 F ext/fts3/fts3_tokenizer1.c 6e5cbaa588924ac578263a598e4fb9f5c9bb179d
-F ext/fts3/fts3_write.c f2f5caed5ebaff2f6f00724063b415a27b02269d
+F ext/fts3/fts3_write.c 01478ee63bb321f240bb5565d9e36e8641b33928
 F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9
 F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100
 F ext/icu/README.txt bf8461d8cdc6b8f514c080e4e10dc3b2bbdfefa9
@@ -431,7 +431,8 @@ F test/fts3ao.test b83f99f70e9eec85f27d75801a974b3f820e01f9
 F test/fts3atoken.test 25c2070e1e8755d414bf9c8200427b277a9f99fa
 F test/fts3b.test e93bbb653e52afde110ad53bbd793f14fe7a8984
 F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958
-F test/fts3corrupt.test 33136f735b072c30cb81506a778c553e1dbfee24
+F test/fts3corrupt.test d874ba27975aa8e5514bf58bf97b473404de0dbb
+F test/fts3corrupt2.test 6d96efae2f8a6af3eeaf283aba437e6d0e5447ba
 F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7
 F test/fts3d.test 95fb3c862cbc4297c93fceb9a635543744e9ef52
 F test/fts3defer.test eab4f24c8402fb4e1e6aad44bcdfbe5bf42160b2
@@ -880,7 +881,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P a4691563dd2b3e5e8474467b0c5c46fb26351b77
-R bff2ac7c319afc7951a784339e29e0c8
+P 252f0e457d3e33404df87d3e6c44ede61b78319c
+R d97d2b9a5a48009c2b60d357c8a6ddd6
 U dan
-Z 67ba15939e37c99dcbd00f2c2cfc47a0
+Z 94cd3ec190765a4d38e20b4294999730
index b5b162b12946cb0cd8e1acd7c785e8632e152176..b8253323102089a6fa57b91e4d6ee096c4069e5b 100644 (file)
@@ -1 +1 @@
-252f0e457d3e33404df87d3e6c44ede61b78319c
\ No newline at end of file
+b770290561f5450e4d985ca0050ef5eb01657c80
\ No newline at end of file
index 3c97d64f5fd9cd3f0d7de0db869ad2786a5311ad..c2889b8776473075e1d4018d8739e7f920c6ce69 100644 (file)
@@ -88,8 +88,48 @@ do_catchsql_test 3.2 {
 } {1 {database disk image is malformed}}
 
 
+do_execsql_test 4.0 {
+  DROP TABLE t1;
+  CREATE VIRTUAL TABLE t1 USING fts3;
+  INSERT INTO t1(t1) VALUES('nodesize=24');
+}
+do_test fts3corrupt-4.1 {
+  execsql BEGIN
+  foreach s {
+     "amxtvoo adqwroyhz auq aithtir avniqnuynvf axp ahibayfynig agbicpm"
+     "ajdtebs anteaxr aieynenwmd awpl alo akxcrwow aoxftge aoqvgul"
+     "amcfvdr auz apu aebelm ahuxyz aqc asyafdb agulvhvqu"
+     "apepwfyz azkhdvkw aenyelxzbk aslnitbyet aycdsdcpgr aqzzdbc agfi axnypydou"
+     "aaqrzzcm apcxdxo atumltzj aevvivo aodknoft aqoyytoz alobx apldt"
+  } {
+    execsql { INSERT INTO t1 VALUES($s) }
+  }
+  execsql COMMIT
+} {}
 
+do_catchsql_test 4.2 {
+  UPDATE t1_segdir SET root = X'FFFFFFFFFFFFFFFF';
+  SELECT rowid FROM t1 WHERE t1 MATCH 'world';
+} {1 {database disk image is malformed}}
+
+set    blob [binary format cca*cca*cca*cca*cca*cca*cca*cca*cca*cca*a* \
+  22 120 [string repeat a 120]  \
+  22 120 [string repeat b 120]  \
+  22 120 [string repeat c 120]  \
+  22 120 [string repeat d 120]  \
+  22 120 [string repeat e 120]  \
+  22 120 [string repeat f 120]  \
+  22 120 [string repeat g 120]  \
+  22 120 [string repeat h 120]  \
+  22 120 [string repeat i 120]  \
+  22 120 [string repeat j 120]  \
+  "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
+]
 
+do_catchsql_test 4.3 {
+  UPDATE t1_segdir SET root = $blob;
+  SELECT rowid FROM t1 WHERE t1 MATCH 'world';
+} {1 {database disk image is malformed}}
 
 finish_test
 
diff --git a/test/fts3corrupt2.test b/test/fts3corrupt2.test
new file mode 100644 (file)
index 0000000..78c7677
--- /dev/null
@@ -0,0 +1,110 @@
+# 2010 October 30
+#
+#    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.
+#
+#***********************************************************************
+# Test that the FTS3 extension does not crash when it encounters a
+# corrupt data structure on disk.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+# If SQLITE_ENABLE_FTS3 is not defined, omit this file.
+ifcapable !fts3 { finish_test ; return }
+
+set ::testprefix fts3corrupt2
+
+set data [list]
+lappend data {*}{
+   "amxtvoo adqwroyhz auq aithtir avniqnuynvf axp ahibayfynig agbicpm"
+   "ajdtebs anteaxr aieynenwmd awpl alo akxcrwow aoxftge aoqvgul"
+   "amcfvdr auz apu aebelm ahuxyz aqc asyafdb agulvhvqu"
+   "apepwfyz azkhdvkw aenyelxzbk aslnitbyet aycdsdcpgr aqzzdbc agfi axnypydou"
+   "aaqrzzcm apcxdxo atumltzj aevvivo aodknoft aqoyytoz alobx apldt"
+   "adjllxlhnmj aiuhvuj adwppceuht atvj azrsam ahkjqdhny audlqxr aotgcd"
+   "aira azflsceos awj auzbobfkc awmezplr aeh awec ahndxlmv"
+   "aydwnied alk auoap agihyqeix aymqxzajnl aydwnied aojkarx agbo"
+   "ahajsmcl anvx amdhjm aoptsj agugzjjm apkevm acnj acjg"
+   "amwtkw aogttbykvt aubwrfqnbjf ajow agsj aerkqzjdqst anenlvbalkn arfajzzgckx"
+   "adqqqofkmz amjpavjuhw aqgehgnb awvvxlbtqzn agstqko akmkzehyh atagzey agwja"
+   "amag ahe autkllywhr avnk atmt akn anvdh aixfrv"
+   "aqdyerbws avefykly awl azaduojgzo anxfsmw axpt abgbvk ati"
+   "attyqkwz aiweypiczul afy asitaqbczhh aitxisizpv auhviq aibql ajfqc"
+   "aylzprtmta aiuemihqrpi awluvgsw ampbuy axlifpzfqr aems aoaxwads apianfn"
+   "aodrkijelq acdb aaserrdxm aqyasgofqu aevvivo afi apmwu aeoqysl"
+   "amqnk ankaotm ayfy ajcupeeoc advcbukan aucahlwnyk adbfyo azqjpeant"
+   "afczpp asqrs ahslvda akhlf aiqgdp atyd aznuglxqbrg awirndrh"
+   "aqhiajp amxeazb asxuehg akod axvolvsp agcz asmovmohy acmqa"
+   "avvomv aafms ashuaec arevx audtq alrwqhjvao avgsgpg ajbrctpsel"
+   "atxoirr ayopboobqdu ajunntua arh aernimxid aipljda aglo aefk"
+   "aonxf acmnnkna abgviaswe aulvcbv axp apemgakpzo aibql acioaid"
+   "axo alrwqhjvao ayqounftdzl azmoakdyh apajze ajk artvy apxiamy"
+   "ayjafsraz addjj agsj asejtziqws acatvhegu aoxdjqblsvv aekdmmbs aaobe"
+   "abjjvzubkwt alczv ati awz auyxgcxeb aymjoym anqoukprtyt atwfhpmbooh"
+   "ajfqz aethlgir aclcx aowlyvetby aproqm afjlqtkv anebfy akzrcpfrrvw"
+   "aoledfotm aiwlfm aeejlaej anz abgbvk aktfn aayoh anpywgdvgz"
+   "acvmldguld asdvz aqb aeomsyzyu aggylhprbdz asrfkwz auipybpsn agsnszzfb"
+}
+
+do_test fts3corrupt2-1.0 {
+  execsql BEGIN
+  execsql { CREATE VIRTUAL TABLE t2 USING FTS3(a, b); }
+  execsql { INSERT INTO t2(t2) VALUES('nodesize=32') }
+  foreach d $data {
+    execsql { INSERT INTO t2 VALUES($d, $d) }
+  }
+  execsql COMMIT
+  execsql { SELECT count(*) FROM t2_segments }
+} {163}
+
+proc set_byte {blob byte val} {
+  binary format a*ca*                         \
+      [string range $blob 0 [expr $byte-1]]   \
+      $val                                    \
+      [string range $blob [expr $byte+1] end] \
+}
+
+set tn 0
+set c 256
+foreach {rowid sz blob} [
+  db eval {SELECT rowid, length(block), block FROM t2_segments}
+] {
+  incr tn
+  set c [expr (($c+255)%256)]
+  for {set i 0} {$i < $sz} {incr i} {
+    set b2 [set_byte $blob $i $c]
+    execsql { UPDATE t2_segments SET block = $b2 WHERE rowid = $rowid }
+    do_test fts3corrupt2-1.$tn.$i {
+      catchsql { SELECT * FROM t2 WHERE t2 MATCH 'a*' }
+      set {} {}
+    } {}
+  }
+  execsql { UPDATE t2_segments SET block = $blob WHERE rowid = $rowid }
+}
+
+foreach c {50 100 150 200 250} {
+  foreach {rowid sz blob} [
+    db eval {SELECT rowid, length(root), root FROM t2_segdir}
+  ] {
+    incr tn
+    for {set i 0} {$i < $sz} {incr i} {
+      set b2 [set_byte $blob $i $c]
+      execsql { UPDATE t2_segdir SET root = $b2 WHERE rowid = $rowid }
+      do_test fts3corrupt2-2.$c.$tn.$i {
+        catchsql { SELECT * FROM t2 WHERE t2 MATCH 'a*' }
+        set {} {}
+      } {}
+    }
+    execsql { UPDATE t2_segdir SET root = $blob WHERE rowid = $rowid }
+  }
+}
+
+
+
+
+
+
+finish_test