Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix some trivial cases where database corruption was causing an error code other than SQLITE_CORRUPT to be returned. (CVS 5690) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
89fda074f6b4959c32f1083badba3c73 |
User & Date: | danielk1977 2008-09-10 17:53:36.000 |
Context
2008-09-11
| ||
10:29 | Fix a couple of problems with variable initializations picked up by stricter compilers. (CVS 5691) (check-in: f4293d1480 user: danielk1977 tags: trunk) | |
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) | |
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.511 2008/09/10 17:53:36 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" |
︙ | ︙ | |||
1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 | pPage->pDbPage = pDbPage; pPage->pBt = pBt; pPage->pgno = pgno; pPage->hdrOffset = pPage->pgno==1 ? 100 : 0; *ppPage = pPage; return SQLITE_OK; } /* ** Get a page from the pager and initialize it. This routine ** is just a convenience wrapper around separate calls to ** sqlite3BtreeGetPage() and sqlite3BtreeInitPage(). */ static int getAndInitPage( 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 ); | > > > > > > > > > > > | | 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 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 | pPage->pDbPage = pDbPage; pPage->pBt = pBt; pPage->pgno = pgno; pPage->hdrOffset = pPage->pgno==1 ? 100 : 0; *ppPage = pPage; return SQLITE_OK; } /* ** Return the size of the database file in pages. Or return -1 if ** there is any kind of error. */ static int pagerPagecount(Pager *pPager){ int rc; int nPage; rc = sqlite3PagerPagecount(pPager, &nPage); return (rc==SQLITE_OK?nPage:-1); } /* ** Get a page from the pager and initialize it. This routine ** is just a convenience wrapper around separate calls to ** sqlite3BtreeGetPage() and sqlite3BtreeInitPage(). */ static int getAndInitPage( 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 || pgno>pagerPagecount(pBt->pPager) ){ 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) ){ |
︙ | ︙ | |||
2025 2026 2027 2028 2029 2030 2031 | trans_begun: btreeIntegrity(p); sqlite3BtreeLeave(p); return rc; } | < < < < < < < < < < < | 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 | trans_begun: btreeIntegrity(p); sqlite3BtreeLeave(p); return rc; } #ifndef SQLITE_OMIT_AUTOVACUUM /* ** Set the pointer-map entries for all children of page pPage. Also, if ** pPage contains cells that point to overflow pages, set the pointer ** map entries for the overflow pages as well. |
︙ | ︙ | |||
3180 3181 3182 3183 3184 3185 3186 | nKey = (pPage->intKey ? 0 : pCur->info.nKey); if( skipKey ){ offset += nKey; } if( offset+amt > nKey+pCur->info.nData ){ /* Trying to read or write past the end of the data is an error */ | | | 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 | nKey = (pPage->intKey ? 0 : pCur->info.nKey); if( skipKey ){ offset += nKey; } if( offset+amt > nKey+pCur->info.nData ){ /* Trying to read or write past the end of the data is an error */ return SQLITE_CORRUPT_BKPT; } /* Check if data must be read/written to/from the btree page itself. */ if( offset<pCur->info.nLocal ){ int a = amt; if( a+offset>pCur->info.nLocal ){ a = pCur->info.nLocal - offset; |
︙ | ︙ |
Changes to test/corruptB.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 | # # 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. # | > > > > | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | # # 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. # # Also test that an SQLITE_CORRUPT error is returned if a B-Tree page # contains a (corrupt) reference to a page greater than the configured # maximum page number. # # $Id: corruptB.test,v 1.2 2008/09/10 17:53:36 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl do_test corruptB-1.1 { execsql { |
︙ | ︙ | |||
135 136 137 138 139 140 141 142 143 144 | 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 | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | 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}} #--------------------------------------------------------------------------- do_test corruptB-2.1.1 { db close file copy -force bak.db test.db hexio_write test.db [expr $offset+8] [hexio_render_int32 0x6FFFFFFF] } {4} do_test corruptB-2.1.2 { sqlite3 db test.db catchsql { SELECT * FROM t1 } } {1 {database disk image is malformed}} #--------------------------------------------------------------------------- # Corrupt the header-size field of a database record. # do_test corruptB-3.1.1 { db close file copy -force bak.db test.db sqlite3 db test.db set v [string repeat abcdefghij 200] execsql { CREATE TABLE t2(a); INSERT INTO t2 VALUES($v); } set t2_root [execsql {SELECT rootpage FROM sqlite_master WHERE name = 't2'}] set iPage [expr ($t2_root-1)*1024] set iCellarray [expr $iPage + 8] set iRecord [hexio_get_int [hexio_read test.db $iCellarray 2]] db close hexio_write test.db [expr $iPage+$iRecord+3] FF00 } {2} do_test corruptB-3.1.2 { sqlite3 db test.db catchsql { SELECT * FROM t2 } } {1 {database disk image is malformed}} finish_test |
Changes to test/fuzz3.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 | # #*********************************************************************** # This file implements regression tests for SQLite library. The focus # of this file is checking the libraries response to subtly corrupting # the database file by changing the values of pseudo-randomly selected # bytes. # | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # #*********************************************************************** # This file implements regression tests for SQLite library. The focus # of this file is checking the libraries response to subtly corrupting # the database file by changing the values of pseudo-randomly selected # bytes. # # $Id: fuzz3.test,v 1.2 2008/09/10 17:53:36 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl expr srand(123) |
︙ | ︙ | |||
119 120 121 122 123 124 125 | } {} set ::cksum [db_checksum] do_test fuzz3-2 { db_checksum } $::cksum | | | > < | 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 145 146 | } {} set ::cksum [db_checksum] do_test fuzz3-2 { db_checksum } $::cksum for {set ii 0} {$ii < 5000} {incr ii} { purge_pcache # Randomly modify a single byte of the database file somewhere within # the first 100KB of the file. set iNew [expr int(rand()*5*1024*256)] set iOld [modify_database $iNew] set iTest 0 foreach sql { {SELECT * FROM t2 ORDER BY d} {SELECT * FROM t1} {SELECT * FROM t2} {SELECT * FROM t1 ORDER BY a} {SELECT * FROM t1 WHERE a = (SELECT a FROM t1 WHERE rowid=25)} {SELECT * FROM t2 WHERE d = (SELECT d FROM t2 WHERE rowid=1)} {SELECT * FROM t2 WHERE d = (SELECT d FROM t2 WHERE rowid=50)} {PRAGMA integrity_check} } { do_test fuzz3-$ii.$iNew.[incr iTest] { foreach {rc msg} [catchsql $sql] {} |
︙ | ︙ |