Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | 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) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
93545861a70c190d67b0d1effdd8fe03 |
User & Date: | danielk1977 2008-09-10 14:45:58.000 |
Context
2008-09-10
| ||
17:53 | Fix some trivial cases where database corruption was causing an error code other than SQLITE_CORRUPT to be returned. (CVS 5690) (check-in: 89fda074f6 user: danielk1977 tags: trunk) | |
14:45 | 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) (check-in: 93545861a7 user: danielk1977 tags: trunk) | |
13:09 | Documentation updates: Describe recursion capabilities for the various callbacks. (CVS 5688) (check-in: edd80811d7 user: drh tags: trunk) | |
Changes
Changes to src/btree.c.
1 2 3 4 5 6 7 8 9 10 11 | /* ** 2004 April 6 ** ** 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. ** ************************************************************************* | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2004 April 6 ** ** 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. ** ************************************************************************* ** $Id: btree.c,v 1.510 2008/09/10 14:45:58 danielk1977 Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. ** Including a description of file format and an overview of operation. */ #include "btreeInt.h" |
︙ | ︙ | |||
934 935 936 937 938 939 940 941 942 943 944 945 946 947 | pBt = pPage->pBt; assert( pBt!=0 ); assert( pParent==0 || pParent->pBt==pBt ); assert( sqlite3_mutex_held(pBt->mutex) ); assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) ); assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) ); assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) ); if( pPage->pParent!=pParent && (pPage->pParent!=0 || pPage->isInit) ){ /* The parent page should never change unless the file is corrupt */ return SQLITE_CORRUPT_BKPT; } if( pPage->isInit ) return SQLITE_OK; if( pPage->pParent==0 && pParent!=0 ){ pPage->pParent = pParent; | > > > | 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 | pBt = pPage->pBt; assert( pBt!=0 ); assert( pParent==0 || pParent->pBt==pBt ); assert( sqlite3_mutex_held(pBt->mutex) ); assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) ); assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) ); assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) ); if( pPage==pParent ){ return SQLITE_CORRUPT_BKPT; } if( pPage->pParent!=pParent && (pPage->pParent!=0 || pPage->isInit) ){ /* The parent page should never change unless the file is corrupt */ return SQLITE_CORRUPT_BKPT; } if( pPage->isInit ) return SQLITE_OK; if( pPage->pParent==0 && pParent!=0 ){ pPage->pParent = pParent; |
︙ | ︙ | |||
1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 | BtShared *pBt, /* The database file */ Pgno pgno, /* Number of the page to get */ MemPage **ppPage, /* Write the page pointer here */ MemPage *pParent /* Parent of the page */ ){ int rc; assert( sqlite3_mutex_held(pBt->mutex) ); if( pgno==0 ){ return SQLITE_CORRUPT_BKPT; } rc = sqlite3BtreeGetPage(pBt, pgno, ppPage, 0); | > | > | > > > > > > > > | 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 | BtShared *pBt, /* The database file */ Pgno pgno, /* Number of the page to get */ MemPage **ppPage, /* Write the page pointer here */ MemPage *pParent /* Parent of the page */ ){ int rc; assert( sqlite3_mutex_held(pBt->mutex) ); assert( !pParent || pParent->isInit ); if( pgno==0 ){ return SQLITE_CORRUPT_BKPT; } rc = sqlite3BtreeGetPage(pBt, pgno, ppPage, 0); if( rc==SQLITE_OK ){ 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 ){ releasePage(*ppPage); *ppPage = 0; } } return rc; } /* ** Release a MemPage. This should be called once for each prior ** call to sqlite3BtreeGetPage. */ |
︙ | ︙ | |||
6178 6179 6180 6181 6182 6183 6184 | } rc = getAndInitPage(pBt, pgno, &pPage, pParent); if( rc ) goto cleardatabasepage_out; for(i=0; i<pPage->nCell; i++){ pCell = findCell(pPage, i); if( !pPage->leaf ){ | | | | 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 | } rc = getAndInitPage(pBt, pgno, &pPage, pParent); if( rc ) goto cleardatabasepage_out; for(i=0; i<pPage->nCell; i++){ pCell = findCell(pPage, i); if( !pPage->leaf ){ rc = clearDatabasePage(pBt, get4byte(pCell), pPage, 1); if( rc ) goto cleardatabasepage_out; } rc = clearCell(pPage, pCell); if( rc ) goto cleardatabasepage_out; } if( !pPage->leaf ){ rc = clearDatabasePage(pBt, get4byte(&pPage->aData[8]), pPage, 1); if( rc ) goto cleardatabasepage_out; } if( freePageFlag ){ rc = freePage(pPage); }else if( (rc = sqlite3PagerWrite(pPage->pDbPage))==0 ){ zeroPage(pPage, pPage->aData[0] | PTF_LEAF); } |
︙ | ︙ |
Added test/corruptB.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 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 |