1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Prevent a possible infinite loop when trying to DROP a table from

a corrupt database.

FossilOrigin-Name: 395bb3e677a6551b06ba96fc58c393132b93d1e8
This commit is contained in:
drh
2015-03-30 23:43:56 +00:00
parent ad1e55e55a
commit 116f0be024
4 changed files with 94 additions and 10 deletions

View File

@@ -1,5 +1,5 @@
C Enhancements\sto\sOSTRACE\susage\sin\sthe\sWin32\sVFS. C Prevent\sa\spossible\sinfinite\sloop\swhen\strying\sto\sDROP\sa\stable\sfrom\na\scorrupt\sdatabase.
D 2015-03-27T18:20:25.776 D 2015-03-30T23:43:56.191
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 88a3e6261286db378fdffa1124cad11b3c05f5bb F Makefile.in 88a3e6261286db378fdffa1124cad11b3c05f5bb
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -173,7 +173,7 @@ F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240
F src/backup.c ff743689c4d6c5cb55ad42ed9d174b2b3e71f1e3 F src/backup.c ff743689c4d6c5cb55ad42ed9d174b2b3e71f1e3
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79 F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79
F src/btree.c 4f305e554d7d207375c3e29ab0335bd5a473a125 F src/btree.c e565971caa0265d3cabc8b15d7017899a7814051
F src/btree.h 969adc948e89e449220ff0ff724c94bb2a52e9f1 F src/btree.h 969adc948e89e449220ff0ff724c94bb2a52e9f1
F src/btreeInt.h 2bfefc01875d8da066504c233ec259fcb3b2ef72 F src/btreeInt.h 2bfefc01875d8da066504c233ec259fcb3b2ef72
F src/build.c 0419bba592c22f6d00e6d57a2ca7136720d02c1a F src/build.c 0419bba592c22f6d00e6d57a2ca7136720d02c1a
@@ -433,6 +433,7 @@ F test/corruptF.test be9fde98e4c93648f1ba52b74e5318edc8f59fe4
F test/corruptG.test 1ab3bf97ee7bdba70e0ff3ba2320657df55d1804 F test/corruptG.test 1ab3bf97ee7bdba70e0ff3ba2320657df55d1804
F test/corruptH.test 5dd4fa98c6c1ed33b178f9e8a48c4fdd3cfc9067 F test/corruptH.test 5dd4fa98c6c1ed33b178f9e8a48c4fdd3cfc9067
F test/corruptI.test 221ad8b7f0a9ac6b80fc577e73b5ad8cdea31243 F test/corruptI.test 221ad8b7f0a9ac6b80fc577e73b5ad8cdea31243
F test/corruptJ.test 8f584eb97b88e7b160d03edfe2f814c64e56b4ac
F test/cost.test 19d314526616ce4473eb4e4e450fcb94499ce318 F test/cost.test 19d314526616ce4473eb4e4e450fcb94499ce318
F test/count.test 42a251178e32f617eda33f76236a7f79825a50b5 F test/count.test 42a251178e32f617eda33f76236a7f79825a50b5
F test/coveridxscan.test cdb47d01acc4a634a34fd25abe85189e0d0f1e62 F test/coveridxscan.test cdb47d01acc4a634a34fd25abe85189e0d0f1e62
@@ -1247,7 +1248,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P 0ec08ba8a0fa188146b071a489908332693ba59a P ab5800291e1908b5b51d912feeacf748dc9be14b
R 5fa56a67857aa9aa0bfe9c8eabbd7f2b R 7b7ce803eb05ad2f210c6eb94fdd8e1c
U mistachkin U drh
Z 22e64f81a05ea0084d0b656c0478e6e9 Z 53c46ef4969a0037acc3578044ba6e9e

View File

@@ -1 +1 @@
ab5800291e1908b5b51d912feeacf748dc9be14b 395bb3e677a6551b06ba96fc58c393132b93d1e8

View File

@@ -7978,6 +7978,7 @@ static int clearDatabasePage(
int i; int i;
int hdr; int hdr;
u16 szCell; u16 szCell;
u8 hasChildren;
assert( sqlite3_mutex_held(pBt->mutex) ); assert( sqlite3_mutex_held(pBt->mutex) );
if( pgno>btreePagecount(pBt) ){ if( pgno>btreePagecount(pBt) ){
@@ -7986,17 +7987,19 @@ static int clearDatabasePage(
rc = getAndInitPage(pBt, pgno, &pPage, 0); rc = getAndInitPage(pBt, pgno, &pPage, 0);
if( rc ) return rc; if( rc ) return rc;
hasChildren = !pPage->leaf;
pPage->leaf = 1; /* Block looping if the database is corrupt */
hdr = pPage->hdrOffset; hdr = pPage->hdrOffset;
for(i=0; i<pPage->nCell; i++){ for(i=0; i<pPage->nCell; i++){
pCell = findCell(pPage, i); pCell = findCell(pPage, i);
if( !pPage->leaf ){ if( hasChildren ){
rc = clearDatabasePage(pBt, get4byte(pCell), 1, pnChange); rc = clearDatabasePage(pBt, get4byte(pCell), 1, pnChange);
if( rc ) goto cleardatabasepage_out; if( rc ) goto cleardatabasepage_out;
} }
rc = clearCell(pPage, pCell, &szCell); rc = clearCell(pPage, pCell, &szCell);
if( rc ) goto cleardatabasepage_out; if( rc ) goto cleardatabasepage_out;
} }
if( !pPage->leaf ){ if( hasChildren ){
rc = clearDatabasePage(pBt, get4byte(&pPage->aData[hdr+8]), 1, pnChange); rc = clearDatabasePage(pBt, get4byte(&pPage->aData[hdr+8]), 1, pnChange);
if( rc ) goto cleardatabasepage_out; if( rc ) goto cleardatabasepage_out;
}else if( pnChange ){ }else if( pnChange ){

80
test/corruptJ.test Normal file
View File

@@ -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