From: dan Date: Sat, 30 Oct 2010 15:21:13 +0000 (+0000) Subject: Test cases and minor changes to make fts3 more robust in the face of a corrupt database. X-Git-Tag: version-3.7.4~81 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=cfddb09e3bcbdc411ce76ad6067791e7d3da72ad;p=thirdparty%2Fsqlite.git Test cases and minor changes to make fts3 more robust in the face of a corrupt database. FossilOrigin-Name: b770290561f5450e4d985ca0050ef5eb01657c80 --- diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c index bf760efe8e..5fcb77fb55 100644 --- a/ext/fts3/fts3.c +++ b/ext/fts3/fts3.c @@ -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( zCsrzEnd ){ + 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; } diff --git a/ext/fts3/fts3_write.c b/ext/fts3/fts3_write.c index 4982c87042..2f4db406ed 100644 --- a/ext/fts3/fts3_write.c +++ b/ext/fts3/fts3_write.c @@ -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; } diff --git a/manifest b/manifest index f0906b1e70..4588df4380 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index b5b162b129..b825332310 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -252f0e457d3e33404df87d3e6c44ede61b78319c \ No newline at end of file +b770290561f5450e4d985ca0050ef5eb01657c80 \ No newline at end of file diff --git a/test/fts3corrupt.test b/test/fts3corrupt.test index 3c97d64f5f..c2889b8776 100644 --- a/test/fts3corrupt.test +++ b/test/fts3corrupt.test @@ -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 index 0000000000..78c76778f5 --- /dev/null +++ b/test/fts3corrupt2.test @@ -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