mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
Fix for handling database files corrupted in such a was as to make a b-tree page a direct or indirect descendant of itself. (CVS 5689)
FossilOrigin-Name: 93545861a70c190d67b0d1effdd8fe038d28811c
This commit is contained in:
15
manifest
15
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Documentation\supdates:\s\sDescribe\srecursion\scapabilities\sfor\sthe\svarious\ncallbacks.\s(CVS\s5688)
|
C Fix\sfor\shandling\sdatabase\sfiles\scorrupted\sin\ssuch\sa\swas\sas\sto\smake\sa\sb-tree\spage\sa\sdirect\sor\sindirect\sdescendant\sof\sitself.\s(CVS\s5689)
|
||||||
D 2008-09-10T13:09:24
|
D 2008-09-10T14:45:58
|
||||||
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
||||||
F Makefile.in d15a7ebfe5e057a72a49805ffb302dbb601c8329
|
F Makefile.in d15a7ebfe5e057a72a49805ffb302dbb601c8329
|
||||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||||
@@ -99,7 +99,7 @@ F src/attach.c db3f4a60538733c1e4dcb9d0217a6e0d6ccd615b
|
|||||||
F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627
|
F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627
|
||||||
F src/bitvec.c 95c86bd18d8fedf0533f5af196192546e10a7e7d
|
F src/bitvec.c 95c86bd18d8fedf0533f5af196192546e10a7e7d
|
||||||
F src/btmutex.c 709cad2cdca0afd013f0f612363810e53f59ec53
|
F src/btmutex.c 709cad2cdca0afd013f0f612363810e53f59ec53
|
||||||
F src/btree.c 6ea37de364f483496f60e47c996b429a9f313d54
|
F src/btree.c 9e11a68fe66c751668e9fcd1b54c88d60f832b47
|
||||||
F src/btree.h 6371c5e599fab391a150c96afbc10062b276d107
|
F src/btree.h 6371c5e599fab391a150c96afbc10062b276d107
|
||||||
F src/btreeInt.h ab18c7b4980314e9e4b402e5dcde09f3c2545576
|
F src/btreeInt.h ab18c7b4980314e9e4b402e5dcde09f3c2545576
|
||||||
F src/build.c 160c71acca8f643f436ed6c1ee2f684c88df4dfe
|
F src/build.c 160c71acca8f643f436ed6c1ee2f684c88df4dfe
|
||||||
@@ -262,6 +262,7 @@ F test/corrupt7.test 7a3be79b93dba88ba8472d61b57cb6d7b66cb69e
|
|||||||
F test/corrupt8.test 9992ef7f67cefc576b92373f6bf5ab8775280f51
|
F test/corrupt8.test 9992ef7f67cefc576b92373f6bf5ab8775280f51
|
||||||
F test/corrupt9.test 794d284109c65c8f10a2b275479045e02d163bae
|
F test/corrupt9.test 794d284109c65c8f10a2b275479045e02d163bae
|
||||||
F test/corruptA.test 99e95620b980161cb3e79f06a884a4bb8ae265ff
|
F test/corruptA.test 99e95620b980161cb3e79f06a884a4bb8ae265ff
|
||||||
|
F test/corruptB.test 547c5f96a6c2b6d316f4b888c2d8186fc186579f
|
||||||
F test/crash.test 1b6ac8410689ff78028887f445062dc897c9ac89
|
F test/crash.test 1b6ac8410689ff78028887f445062dc897c9ac89
|
||||||
F test/crash2.test 5b14d4eb58b880e231361d3b609b216acda86651
|
F test/crash2.test 5b14d4eb58b880e231361d3b609b216acda86651
|
||||||
F test/crash3.test 776f9363554c029fcce71d9e6600fa0ba6359ce7
|
F test/crash3.test 776f9363554c029fcce71d9e6600fa0ba6359ce7
|
||||||
@@ -634,7 +635,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81
|
|||||||
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||||
F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1
|
F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1
|
||||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||||
P 099adfd31167a78d803e2992e5f50cf4e292dd43
|
P edd80811d702bc0d7a25199d193c04ea057df4de
|
||||||
R 7853a8a5ccb659e8bb6ea1c2c2871c9f
|
R 86a7c41a00b3787bf3d3b2cfbbdffc97
|
||||||
U drh
|
U danielk1977
|
||||||
Z d85bcb69ec2b69991a86141e52428a8c
|
Z 5931af1cdd92a17ee908521206422339
|
||||||
|
@@ -1 +1 @@
|
|||||||
edd80811d702bc0d7a25199d193c04ea057df4de
|
93545861a70c190d67b0d1effdd8fe038d28811c
|
23
src/btree.c
23
src/btree.c
@@ -9,7 +9,7 @@
|
|||||||
** May you share freely, never taking more than you give.
|
** May you share freely, never taking more than you give.
|
||||||
**
|
**
|
||||||
*************************************************************************
|
*************************************************************************
|
||||||
** $Id: btree.c,v 1.509 2008/09/05 05:02:47 danielk1977 Exp $
|
** $Id: btree.c,v 1.510 2008/09/10 14:45:58 danielk1977 Exp $
|
||||||
**
|
**
|
||||||
** This file implements a external (disk-based) database using BTrees.
|
** This file implements a external (disk-based) database using BTrees.
|
||||||
** See the header comment on "btreeInt.h" for additional information.
|
** See the header comment on "btreeInt.h" for additional information.
|
||||||
@@ -938,6 +938,9 @@ int sqlite3BtreeInitPage(
|
|||||||
assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) );
|
assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) );
|
||||||
assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) );
|
assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) );
|
||||||
assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) );
|
assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) );
|
||||||
|
if( pPage==pParent ){
|
||||||
|
return SQLITE_CORRUPT_BKPT;
|
||||||
|
}
|
||||||
if( pPage->pParent!=pParent && (pPage->pParent!=0 || pPage->isInit) ){
|
if( pPage->pParent!=pParent && (pPage->pParent!=0 || pPage->isInit) ){
|
||||||
/* The parent page should never change unless the file is corrupt */
|
/* The parent page should never change unless the file is corrupt */
|
||||||
return SQLITE_CORRUPT_BKPT;
|
return SQLITE_CORRUPT_BKPT;
|
||||||
@@ -1095,17 +1098,27 @@ static int getAndInitPage(
|
|||||||
){
|
){
|
||||||
int rc;
|
int rc;
|
||||||
assert( sqlite3_mutex_held(pBt->mutex) );
|
assert( sqlite3_mutex_held(pBt->mutex) );
|
||||||
|
assert( !pParent || pParent->isInit );
|
||||||
if( pgno==0 ){
|
if( pgno==0 ){
|
||||||
return SQLITE_CORRUPT_BKPT;
|
return SQLITE_CORRUPT_BKPT;
|
||||||
}
|
}
|
||||||
rc = sqlite3BtreeGetPage(pBt, pgno, ppPage, 0);
|
rc = sqlite3BtreeGetPage(pBt, pgno, ppPage, 0);
|
||||||
if( rc==SQLITE_OK && (*ppPage)->isInit==0 ){
|
if( rc==SQLITE_OK ){
|
||||||
rc = sqlite3BtreeInitPage(*ppPage, pParent);
|
if( (*ppPage)->isInit==0 ){
|
||||||
|
rc = sqlite3BtreeInitPage(*ppPage, pParent);
|
||||||
|
}else if( pParent && ((*ppPage)==pParent || (*ppPage)->pParent!=pParent) ){
|
||||||
|
/* This condition indicates a loop in the b-tree structure (the scenario
|
||||||
|
** where database corruption has caused a page to be a direct or
|
||||||
|
** indirect descendant of itself).
|
||||||
|
*/
|
||||||
|
rc = SQLITE_CORRUPT_BKPT;
|
||||||
|
}
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
releasePage(*ppPage);
|
releasePage(*ppPage);
|
||||||
*ppPage = 0;
|
*ppPage = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6182,14 +6195,14 @@ static int clearDatabasePage(
|
|||||||
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( !pPage->leaf ){
|
||||||
rc = clearDatabasePage(pBt, get4byte(pCell), pPage->pParent, 1);
|
rc = clearDatabasePage(pBt, get4byte(pCell), pPage, 1);
|
||||||
if( rc ) goto cleardatabasepage_out;
|
if( rc ) goto cleardatabasepage_out;
|
||||||
}
|
}
|
||||||
rc = clearCell(pPage, pCell);
|
rc = clearCell(pPage, pCell);
|
||||||
if( rc ) goto cleardatabasepage_out;
|
if( rc ) goto cleardatabasepage_out;
|
||||||
}
|
}
|
||||||
if( !pPage->leaf ){
|
if( !pPage->leaf ){
|
||||||
rc = clearDatabasePage(pBt, get4byte(&pPage->aData[8]), pPage->pParent, 1);
|
rc = clearDatabasePage(pBt, get4byte(&pPage->aData[8]), pPage, 1);
|
||||||
if( rc ) goto cleardatabasepage_out;
|
if( rc ) goto cleardatabasepage_out;
|
||||||
}
|
}
|
||||||
if( freePageFlag ){
|
if( freePageFlag ){
|
||||||
|
144
test/corruptB.test
Normal file
144
test/corruptB.test
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
# 2008 Sep 10
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
# This file implements tests to make sure SQLite does not crash or
|
||||||
|
# segfault if it sees a corrupt database file. It specifically focuses
|
||||||
|
# on loops in the B-Tree structure. A loop is formed in a B-Tree structure
|
||||||
|
# when there exists a page that is both an a descendent or ancestor of
|
||||||
|
# itself.
|
||||||
|
#
|
||||||
|
# $Id: corruptB.test,v 1.1 2008/09/10 14:45:58 danielk1977 Exp $
|
||||||
|
|
||||||
|
set testdir [file dirname $argv0]
|
||||||
|
source $testdir/tester.tcl
|
||||||
|
|
||||||
|
|
||||||
|
do_test corruptB-1.1 {
|
||||||
|
execsql {
|
||||||
|
PRAGMA auto_vacuum = 1;
|
||||||
|
CREATE TABLE t1(x);
|
||||||
|
INSERT INTO t1 VALUES(randomblob(200));
|
||||||
|
INSERT INTO t1 SELECT randomblob(200) FROM t1;
|
||||||
|
INSERT INTO t1 SELECT randomblob(200) FROM t1;
|
||||||
|
INSERT INTO t1 SELECT randomblob(200) FROM t1;
|
||||||
|
INSERT INTO t1 SELECT randomblob(200) FROM t1;
|
||||||
|
INSERT INTO t1 SELECT randomblob(200) FROM t1;
|
||||||
|
}
|
||||||
|
expr {[file size test.db] > (1024*9)}
|
||||||
|
} {1}
|
||||||
|
integrity_check corruptB-1.2
|
||||||
|
|
||||||
|
file copy -force test.db bak.db
|
||||||
|
|
||||||
|
# Set the right-child of a B-Tree rootpage to refer to the root-page itself.
|
||||||
|
#
|
||||||
|
do_test corruptB-1.3.1 {
|
||||||
|
set ::root [execsql {SELECT rootpage FROM sqlite_master}]
|
||||||
|
set ::offset [expr {($::root-1)*1024}]
|
||||||
|
hexio_write test.db [expr $offset+8] [hexio_render_int32 $::root]
|
||||||
|
} {4}
|
||||||
|
do_test corruptB-1.3.2 {
|
||||||
|
sqlite3 db test.db
|
||||||
|
catchsql { SELECT * FROM t1 }
|
||||||
|
} {1 {database disk image is malformed}}
|
||||||
|
|
||||||
|
# Set the left-child of a cell in a B-Tree rootpage to refer to the
|
||||||
|
# root-page itself.
|
||||||
|
#
|
||||||
|
do_test corruptB-1.4.1 {
|
||||||
|
db close
|
||||||
|
file copy -force bak.db test.db
|
||||||
|
set cell_offset [hexio_get_int [hexio_read test.db [expr $offset+12] 2]]
|
||||||
|
hexio_write test.db [expr $offset+$cell_offset] [hexio_render_int32 $::root]
|
||||||
|
} {4}
|
||||||
|
do_test corruptB-1.4.2 {
|
||||||
|
sqlite3 db test.db
|
||||||
|
catchsql { SELECT * FROM t1 }
|
||||||
|
} {1 {database disk image is malformed}}
|
||||||
|
|
||||||
|
# Now grow the table B-Tree so that it is more than 2 levels high.
|
||||||
|
#
|
||||||
|
do_test corruptB-1.5.1 {
|
||||||
|
db close
|
||||||
|
file copy -force bak.db test.db
|
||||||
|
sqlite3 db test.db
|
||||||
|
execsql {
|
||||||
|
INSERT INTO t1 SELECT randomblob(200) FROM t1;
|
||||||
|
INSERT INTO t1 SELECT randomblob(200) FROM t1;
|
||||||
|
INSERT INTO t1 SELECT randomblob(200) FROM t1;
|
||||||
|
INSERT INTO t1 SELECT randomblob(200) FROM t1;
|
||||||
|
INSERT INTO t1 SELECT randomblob(200) FROM t1;
|
||||||
|
INSERT INTO t1 SELECT randomblob(200) FROM t1;
|
||||||
|
INSERT INTO t1 SELECT randomblob(200) FROM t1;
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
|
||||||
|
file copy -force test.db bak.db
|
||||||
|
|
||||||
|
# Set the right-child pointer of the right-child of the root page to point
|
||||||
|
# back to the root page.
|
||||||
|
#
|
||||||
|
do_test corruptB-1.6.1 {
|
||||||
|
db close
|
||||||
|
set iRightChild [hexio_get_int [hexio_read test.db [expr $offset+8] 4]]
|
||||||
|
set c_offset [expr ($iRightChild-1)*1024]
|
||||||
|
hexio_write test.db [expr $c_offset+8] [hexio_render_int32 $::root]
|
||||||
|
} {4}
|
||||||
|
do_test corruptB-1.6.2 {
|
||||||
|
sqlite3 db test.db
|
||||||
|
catchsql { SELECT * FROM t1 }
|
||||||
|
} {1 {database disk image is malformed}}
|
||||||
|
|
||||||
|
# Set the left-child pointer of a cell of the right-child of the root page to
|
||||||
|
# point back to the root page.
|
||||||
|
#
|
||||||
|
do_test corruptB-1.7.1 {
|
||||||
|
db close
|
||||||
|
file copy -force bak.db test.db
|
||||||
|
set cell_offset [hexio_get_int [hexio_read test.db [expr $c_offset+12] 2]]
|
||||||
|
hexio_write test.db [expr $c_offset+$cell_offset] [hexio_render_int32 $::root]
|
||||||
|
} {4}
|
||||||
|
do_test corruptB-1.7.2 {
|
||||||
|
sqlite3 db test.db
|
||||||
|
catchsql { SELECT * FROM t1 }
|
||||||
|
} {1 {database disk image is malformed}}
|
||||||
|
|
||||||
|
do_test corruptB-1.8.1 {
|
||||||
|
db close
|
||||||
|
set cell_offset [hexio_get_int [hexio_read test.db [expr $offset+12] 2]]
|
||||||
|
set iLeftChild [
|
||||||
|
hexio_get_int [hexio_read test.db [expr $offset+$cell_offset] 4]
|
||||||
|
]
|
||||||
|
set c_offset [expr ($iLeftChild-1)*1024]
|
||||||
|
hexio_write test.db [expr $c_offset+8] [hexio_render_int32 $::root]
|
||||||
|
} {4}
|
||||||
|
do_test corruptB-1.8.2 {
|
||||||
|
sqlite3 db test.db
|
||||||
|
catchsql { SELECT * FROM t1 }
|
||||||
|
} {1 {database disk image is malformed}}
|
||||||
|
|
||||||
|
# Set the left-child pointer of a cell of the right-child of the root page to
|
||||||
|
# point back to the root page.
|
||||||
|
#
|
||||||
|
do_test corruptB-1.9.1 {
|
||||||
|
db close
|
||||||
|
file copy -force bak.db test.db
|
||||||
|
set cell_offset [hexio_get_int [hexio_read test.db [expr $c_offset+12] 2]]
|
||||||
|
hexio_write test.db [expr $c_offset+$cell_offset] [hexio_render_int32 $::root]
|
||||||
|
} {4}
|
||||||
|
do_test corruptB-1.9.2 {
|
||||||
|
sqlite3 db test.db
|
||||||
|
catchsql { SELECT * FROM t1 }
|
||||||
|
} {1 {database disk image is malformed}}
|
||||||
|
|
||||||
|
finish_test
|
||||||
|
|
Reference in New Issue
Block a user