diff --git a/manifest b/manifest index 03d04cbf6e..ba1303f3ae 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fixed\scrash\sduring\san\sUPDATE\swhen\sfree\scell\ssize\sis\scorrupt.\s(CVS\s5887) -D 2008-11-11T22:18:20 +C Fixed\sa\sfew\smore\scrashes\swhen\sdealing\swith\scorrupt\sdb\sfiles.\s(CVS\s5888) +D 2008-11-12T04:55:34 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in 48172b58e444a9725ec482e0c022a564749acab4 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -99,7 +99,7 @@ F src/attach.c 208881c87160d9e2c73a46cf86116c5a6d66f9d7 F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627 F src/bitvec.c 9e922b2577b7e46d8f95349bca6a52f7674d7582 F src/btmutex.c 3a90096c3080b9057dc570b8e16e46511e1c788a -F src/btree.c 9794c9eee5c315a5076aafe56dc1739727a99419 +F src/btree.c 5406b753fbab8b3ff36cc1378d3f8fe329b667c0 F src/btree.h 179c3ea813780df78a289a8f5130db18e6d4616e F src/btreeInt.h e38e9b2b285f40f5bc0a6664f630d4a141622f16 F src/build.c 98a6884d47c3cc12faeb2e9a926018d3a7382133 @@ -265,7 +265,7 @@ F test/corrupt8.test 9992ef7f67cefc576b92373f6bf5ab8775280f51 F test/corrupt9.test 794d284109c65c8f10a2b275479045e02d163bae F test/corruptA.test 99e95620b980161cb3e79f06a884a4bb8ae265ff F test/corruptB.test 505331779fe7a96fe38ecbb817f19c63bc27d171 -F test/corruptC.test b872e806a65d8d1ec670cb93ea7f24efb695971a +F test/corruptC.test 98785fda64661720f2c96a3afab91f1acf4831f5 F test/crash.test 1b6ac8410689ff78028887f445062dc897c9ac89 F test/crash2.test 5b14d4eb58b880e231361d3b609b216acda86651 F test/crash3.test 776f9363554c029fcce71d9e6600fa0ba6359ce7 @@ -655,7 +655,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e -P 99d4172ed6825c7efb6cbb28eb00d98323a13954 -R 24c609efd12ad0665f130881447ef341 +P ec18667e2d2826a27f2c052ba3790ab5b8cf0bc4 +R 3fd6e153359a94e15331a1a8034f2f9f U shane -Z fc2c6a9f24438ffffb0cff4c39242351 +Z 22bcacde70b802d010600360fc6793f1 diff --git a/manifest.uuid b/manifest.uuid index 696c5d3a9e..fd051d607d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ec18667e2d2826a27f2c052ba3790ab5b8cf0bc4 \ No newline at end of file +f8bb34e40917e55696376d2def932a41ad43d0ae \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 2519a3f2e0..3c5f9f076a 100644 --- a/src/btree.c +++ b/src/btree.c @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree.c,v 1.531 2008/11/11 22:18:20 shane Exp $ +** $Id: btree.c,v 1.532 2008/11/12 04:55:34 shane Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. @@ -702,7 +702,7 @@ static int ptrmapPutOvfl(MemPage *pPage, int iCell){ ** big FreeBlk that occurs in between the header and cell ** pointer array and the cell content area. */ -static void defragmentPage(MemPage *pPage){ +static int defragmentPage(MemPage *pPage){ int i; /* Loop counter */ int pc; /* Address of a i-th cell */ int addr; /* Offset of first byte after cell pointer array */ @@ -734,9 +734,14 @@ static void defragmentPage(MemPage *pPage){ u8 *pAddr; /* The i-th cell pointer */ pAddr = &data[cellOffset + i*2]; pc = get2byte(pAddr); - assert( pcpBt->usableSize ); + if (pc >= pPage->pBt->usableSize) { + return SQLITE_CORRUPT_BKPT; + } size = cellSizePtr(pPage, &temp[pc]); cbrk -= size; + if ((cbrk < cellOffset+2*nCell) || (cbrk+size>pPage->pBt->usableSize)) { + return SQLITE_CORRUPT_BKPT; + } memcpy(&data[cbrk], &temp[pc], size); put2byte(pAddr, cbrk); } @@ -747,6 +752,7 @@ static void defragmentPage(MemPage *pPage){ data[hdr+7] = 0; addr = cellOffset+2*nCell; memset(&data[addr], 0, cbrk-addr); + return SQLITE_OK; } /* @@ -4558,7 +4564,7 @@ static int fillInCell( ** ** "sz" must be the number of bytes in the cell. */ -static void dropCell(MemPage *pPage, int idx, int sz){ +static int dropCell(MemPage *pPage, int idx, int sz){ int i; /* Loop counter */ int pc; /* Offset to cell content of cell being deleted */ u8 *data; /* pPage->aData */ @@ -4570,9 +4576,10 @@ static void dropCell(MemPage *pPage, int idx, int sz){ assert( sqlite3_mutex_held(pPage->pBt->mutex) ); data = pPage->aData; ptr = &data[pPage->cellOffset + 2*idx]; - /* mask the cell offset to ensure a corrupt db does not result in a crash */ - pc = pPage->maskPage & get2byte(ptr); - assert( pc>10 && pc+sz<=pPage->pBt->usableSize ); + pc = get2byte(ptr); + if ( pc<=10 || pc+sz>pPage->pBt->usableSize ) { + return SQLITE_CORRUPT_BKPT; + } freeSpace(pPage, pc, sz); for(i=idx+1; inCell; i++, ptr+=2){ ptr[0] = ptr[2]; @@ -4581,6 +4588,7 @@ static void dropCell(MemPage *pPage, int idx, int sz){ pPage->nCell--; put2byte(&data[pPage->hdrOffset+3], pPage->nCell); pPage->nFree += 2; + return SQLITE_OK; } /* @@ -4644,15 +4652,19 @@ static int insertCell( end = cellOffset + 2*pPage->nCell + 2; ins = cellOffset + 2*i; if( end > top - sz ){ - defragmentPage(pPage); + rc = defragmentPage(pPage); + if( rc!=SQLITE_OK ){ + return rc; + } top = get2byte(&data[hdr+5]); assert( end + sz <= top ); } idx = allocateSpace(pPage, sz); assert( idx>0 ); assert( end <= get2byte(&data[hdr+5]) ); - if (idx+sz > pPage->pBt->usableSize) + if (idx+sz > pPage->pBt->usableSize) { return SQLITE_CORRUPT_BKPT; + } pPage->nCell++; pPage->nFree -= 2; memcpy(&data[idx+nSkip], pCell+nSkip, sz-nSkip); @@ -5814,7 +5826,10 @@ int sqlite3BtreeInsert( szOld = cellSizePtr(pPage, oldCell); rc = clearCell(pPage, oldCell); if( rc ) goto end_insert; - dropCell(pPage, idx, szOld); + rc = dropCell(pPage, idx, szOld); + if( rc!=SQLITE_OK ) { + goto end_insert; + } }else if( loc<0 && pPage->nCell>0 ){ assert( pPage->leaf ); idx = ++pCur->aiIdx[pCur->iPage]; @@ -6717,7 +6732,7 @@ static int checkTreePage( BtShared *pBt; int usableSize; char zContext[100]; - char *hit; + char *hit = 0; sqlite3_snprintf(sizeof(zContext), zContext, "Page %d: ", iPage); @@ -6807,7 +6822,7 @@ static int checkTreePage( if (contentOffset > usableSize) { checkAppendMsg(pCheck, 0, "Corruption detected in header on page %d",iPage,0); - contentOffset = usableSize; /* try to keep going */ + goto check_page_abort; } memset(hit+contentOffset, 0, usableSize-contentOffset); memset(hit, 1, contentOffset); @@ -6854,7 +6869,8 @@ static int checkTreePage( cnt, data[hdr+7], iPage); } } - sqlite3PageFree(hit); +check_page_abort: + if (hit) sqlite3PageFree(hit); releasePage(pPage); return depth+1; diff --git a/test/corruptC.test b/test/corruptC.test index 3c9f0ba038..8c5a56ccba 100644 --- a/test/corruptC.test +++ b/test/corruptC.test @@ -15,7 +15,7 @@ # data base file, then tests that single byte corruptions in # increasingly larger quantities are handled gracefully. # -# $Id: corruptC.test,v 1.4 2008/11/11 22:18:20 shane Exp $ +# $Id: corruptC.test,v 1.5 2008/11/12 04:55:34 shane Exp $ catch {file delete -force test.db test.db-journal test.bu} @@ -39,7 +39,7 @@ do_test corruptC-1.1 { INSERT OR IGNORE INTO t1 SELECT x*11,y FROM t1; INSERT OR IGNORE INTO t1 SELECT x*13,y FROM t1; CREATE INDEX t1i1 ON t1(x); - CREATE TABLE t2 AS SELECT x,2 FROM t1 WHERE rowid%5!=0; + CREATE TABLE t2 AS SELECT x,2 as y FROM t1 WHERE rowid%5!=0; COMMIT; } } {} @@ -88,8 +88,7 @@ do_test corruptC-2.1 { sqlite3 db test.db catchsql {PRAGMA integrity_check} } {0 {{*** in database main *** -Corruption detected in header on page 3 -Multiple uses for byte 604 of page 3}}} +Corruption detected in header on page 3}}} # test that a corrupt content offset size is handled (seed 5649) do_test corruptC-2.2 { @@ -110,7 +109,7 @@ do_test corruptC-2.2 { sqlite3 db test.db catchsql {UPDATE t1 SET y=1} -} {0 {}} +} {1 {database disk image is malformed}} # test that a corrupt free cell size is handled (seed 13329) do_test corruptC-2.3 { @@ -122,7 +121,51 @@ do_test corruptC-2.3 { sqlite3 db test.db catchsql {UPDATE t1 SET y=1} -} {0 {database disk image is malformed}} +} {1 {database disk image is malformed}} + +# test that a corrupt free cell size is handled (seed 169571) +do_test corruptC-2.4 { + db close + copy_file test.bu test.db + + # insert corrupt byte(s) + hexio_write test.db 3119 [format %02x 0xdf] + + sqlite3 db test.db + catchsql {UPDATE t2 SET y='abcdef-uvwxyz'} +} {1 {database disk image is malformed}} + +# test that a corrupt free cell size is handled (seed 169571) +do_test corruptC-2.5 { + db close + copy_file test.bu test.db + + # insert corrupt byte(s) + hexio_write test.db 3119 [format %02x 0xdf] + hexio_write test.db 4073 [format %02x 0xbf] + + sqlite3 db test.db + catchsql {BEGIN; UPDATE t2 SET y='abcdef-uvwxyz'; ROLLBACK;} + catchsql {PRAGMA integrity_check} +} {0 {{*** in database main *** +On tree page 4 cell 49: invalid page number 1006653561 +Corruption detected in cell 49 on page 4 +Corruption detected in cell 710 on page 4 +Multiple uses for byte 116 of page 4 +Fragmented space is 0 byte reported as 21 on page 4}}} + +# test that a corrupt free cell size is handled (seed 169595) +do_test corruptC-2.6 { + db close + copy_file test.bu test.db + + # insert corrupt byte(s) + hexio_write test.db 619 [format %02x 0xe2] + hexio_write test.db 3150 [format %02x 0xa8] + + sqlite3 db test.db + catchsql {BEGIN; UPDATE t2 SET y='abcdef-uvwxyz'; ROLLBACK;} +} {1 {database disk image is malformed}} # # now test for a series of quasi-random seeds @@ -176,7 +219,7 @@ for {set tn 0} {$tn<=1024} {incr tn 1} { set x {} } {} do_test corruptC-3.$tn.$i.7 { - catchsql {BEGIN; UPDATE t2 SET y=2; ROLLBACK;} + catchsql {BEGIN; UPDATE t2 SET y='abcdef-uvwxyz'; ROLLBACK;} set x {} } {}