From: drh Date: Mon, 30 Mar 2015 23:43:56 +0000 (+0000) Subject: Prevent a possible infinite loop when trying to DROP a table from X-Git-Tag: version-3.8.9~22 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=116f0be0244e2dc92d2a54b6a994f3a080d756ac;p=thirdparty%2Fsqlite.git Prevent a possible infinite loop when trying to DROP a table from a corrupt database. FossilOrigin-Name: 395bb3e677a6551b06ba96fc58c393132b93d1e8 --- diff --git a/manifest b/manifest index 98c814021d..830165f1d1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhancements\sto\sOSTRACE\susage\sin\sthe\sWin32\sVFS. -D 2015-03-27T18:20:25.776 +C Prevent\sa\spossible\sinfinite\sloop\swhen\strying\sto\sDROP\sa\stable\sfrom\na\scorrupt\sdatabase. +D 2015-03-30T23:43:56.191 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 88a3e6261286db378fdffa1124cad11b3c05f5bb F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -173,7 +173,7 @@ F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240 F src/backup.c ff743689c4d6c5cb55ad42ed9d174b2b3e71f1e3 F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79 -F src/btree.c 4f305e554d7d207375c3e29ab0335bd5a473a125 +F src/btree.c e565971caa0265d3cabc8b15d7017899a7814051 F src/btree.h 969adc948e89e449220ff0ff724c94bb2a52e9f1 F src/btreeInt.h 2bfefc01875d8da066504c233ec259fcb3b2ef72 F src/build.c 0419bba592c22f6d00e6d57a2ca7136720d02c1a @@ -433,6 +433,7 @@ F test/corruptF.test be9fde98e4c93648f1ba52b74e5318edc8f59fe4 F test/corruptG.test 1ab3bf97ee7bdba70e0ff3ba2320657df55d1804 F test/corruptH.test 5dd4fa98c6c1ed33b178f9e8a48c4fdd3cfc9067 F test/corruptI.test 221ad8b7f0a9ac6b80fc577e73b5ad8cdea31243 +F test/corruptJ.test 8f584eb97b88e7b160d03edfe2f814c64e56b4ac F test/cost.test 19d314526616ce4473eb4e4e450fcb94499ce318 F test/count.test 42a251178e32f617eda33f76236a7f79825a50b5 F test/coveridxscan.test cdb47d01acc4a634a34fd25abe85189e0d0f1e62 @@ -1247,7 +1248,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 0ec08ba8a0fa188146b071a489908332693ba59a -R 5fa56a67857aa9aa0bfe9c8eabbd7f2b -U mistachkin -Z 22e64f81a05ea0084d0b656c0478e6e9 +P ab5800291e1908b5b51d912feeacf748dc9be14b +R 7b7ce803eb05ad2f210c6eb94fdd8e1c +U drh +Z 53c46ef4969a0037acc3578044ba6e9e diff --git a/manifest.uuid b/manifest.uuid index 50a77b66aa..b562506b7f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ab5800291e1908b5b51d912feeacf748dc9be14b \ No newline at end of file +395bb3e677a6551b06ba96fc58c393132b93d1e8 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 52f29428f7..a4eae64025 100644 --- a/src/btree.c +++ b/src/btree.c @@ -7978,6 +7978,7 @@ static int clearDatabasePage( int i; int hdr; u16 szCell; + u8 hasChildren; assert( sqlite3_mutex_held(pBt->mutex) ); if( pgno>btreePagecount(pBt) ){ @@ -7986,17 +7987,19 @@ static int clearDatabasePage( rc = getAndInitPage(pBt, pgno, &pPage, 0); if( rc ) return rc; + hasChildren = !pPage->leaf; + pPage->leaf = 1; /* Block looping if the database is corrupt */ hdr = pPage->hdrOffset; for(i=0; inCell; i++){ pCell = findCell(pPage, i); - if( !pPage->leaf ){ + if( hasChildren ){ rc = clearDatabasePage(pBt, get4byte(pCell), 1, pnChange); if( rc ) goto cleardatabasepage_out; } rc = clearCell(pPage, pCell, &szCell); if( rc ) goto cleardatabasepage_out; } - if( !pPage->leaf ){ + if( hasChildren ){ rc = clearDatabasePage(pBt, get4byte(&pPage->aData[hdr+8]), 1, pnChange); if( rc ) goto cleardatabasepage_out; }else if( pnChange ){ diff --git a/test/corruptJ.test b/test/corruptJ.test new file mode 100644 index 0000000000..ec884cc9b4 --- /dev/null +++ b/test/corruptJ.test @@ -0,0 +1,80 @@ +# 2015-03-30 +# +# 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. +# +#*********************************************************************** +# +# Corruption consisting of a database page that thinks it is a child +# of itself. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix corruptJ + +if {[permutation]=="mmap"} { + finish_test + return +} + +# Do not use a codec for tests in this file, as the database file is +# manipulated directly using tcl scripts (using the [hexio_write] command). +# +do_not_use_codec +database_may_be_corrupt + +# Initialize the database. +# +do_execsql_test 1.1 { + PRAGMA page_size=1024; + PRAGMA auto_vacuum=0; + CREATE TABLE t1(a,b); + WITH RECURSIVE c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<10) + INSERT INTO t1(a,b) SELECT i, zeroblob(700) FROM c; +} {} +db close + +# Corrupt the root page of the t1 table such that the left-child pointer +# for the very first cell points back to the root. Then try to DROP the +# table. The clearDatabasePage() routine should not loop. +# +do_test 1.2 { + hexio_write test.db [expr {2*1024-2}] 02 + sqlite3 db test.db + catchsql { DROP TABLE t1 } +} {1 {database disk image is malformed}} + +# Similar test using a WITHOUT ROWID table +# +do_test 2.1 { + db close + forcedelete test.db + sqlite3 db test.db + db eval { + PRAGMA page_size=1024; + PRAGMA auto_vacuum=0; + CREATE TABLE t1(a,b,PRIMARY KEY(a,b)) WITHOUT ROWID; + WITH RECURSIVE c(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM c WHERE i<100) + INSERT INTO t1(a,b) SELECT i, zeroblob(200) FROM c; + } +} {} + +# The table is three levels deep. Corrupt the left child of an intermediate +# page so that it points back to the root page. +# +do_test 2.2 { + db close + hexio_read test.db [expr {9*1024+391}] 8 +} {00000008814D0401} +do_test 2.2b { + hexio_write test.db [expr {9*1024+391}] 00000002 + sqlite3 db test.db + catchsql { DROP TABLE t1 } +} {0 {}} + +finish_test