mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-05 15:55:57 +03:00
Enhance the log messages produced in some cases if database corruption is
encountered by an SQLITE_DEBUG build. FossilOrigin-Name: 23a3128083834b5fc80adf45448f7dc65587c52761fb3c9483b80313b369406f
This commit is contained in:
91
src/btree.c
91
src/btree.c
@@ -112,6 +112,31 @@ int sqlite3_enable_shared_cache(int enable){
|
||||
#define hasReadConflicts(a, b) 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Implementation of the SQLITE_CORRUPT_PAGE() macro. Takes a single
|
||||
** (MemPage*) as an argument. The (MemPage*) must not be NULL.
|
||||
**
|
||||
** If SQLITE_DEBUG is not defined, then this macro is equivalent to
|
||||
** SQLITE_CORRUPT_BKPT. Or, if SQLITE_DEBUG is set, then the log message
|
||||
** normally produced as a side-effect of SQLITE_CORRUPT_BKPT is augmented
|
||||
** with the page number and filename associated with the (MemPage*).
|
||||
*/
|
||||
#ifdef SQLITE_DEBUG
|
||||
int corruptPageError(int lineno, MemPage *p){
|
||||
char *zMsg = sqlite3_mprintf("database corruption page %d of %s",
|
||||
(int)p->pgno, sqlite3PagerFilename(p->pBt->pPager, 0)
|
||||
);
|
||||
if( zMsg ){
|
||||
sqlite3ReportError(SQLITE_CORRUPT, lineno, zMsg);
|
||||
}
|
||||
sqlite3_free(zMsg);
|
||||
return SQLITE_CORRUPT_BKPT;
|
||||
}
|
||||
# define SQLITE_CORRUPT_PAGE(pMemPage) corruptPageError(__LINE__, pMemPage)
|
||||
#else
|
||||
# define SQLITE_CORRUPT_PAGE(pMemPage) SQLITE_CORRUPT_PGNO(pMemPage->pgno)
|
||||
#endif
|
||||
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
|
||||
#ifdef SQLITE_DEBUG
|
||||
@@ -1400,7 +1425,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
|
||||
int sz = get2byte(&data[iFree+2]);
|
||||
int top = get2byte(&data[hdr+5]);
|
||||
if( top>=iFree ){
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
if( iFree2 ){
|
||||
assert( iFree+sz<=iFree2 ); /* Verified by pageFindSlot() */
|
||||
@@ -1434,13 +1459,13 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
|
||||
** if PRAGMA cell_size_check=ON.
|
||||
*/
|
||||
if( pc<iCellFirst || pc>iCellLast ){
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
assert( pc>=iCellFirst && pc<=iCellLast );
|
||||
size = pPage->xCellSize(pPage, &src[pc]);
|
||||
cbrk -= size;
|
||||
if( cbrk<iCellFirst || pc+size>usableSize ){
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
assert( cbrk+size<=usableSize && cbrk>=iCellFirst );
|
||||
testcase( cbrk+size==usableSize );
|
||||
@@ -1460,7 +1485,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
|
||||
|
||||
defragment_out:
|
||||
if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
assert( cbrk>=iCellFirst );
|
||||
put2byte(&data[hdr+5], cbrk);
|
||||
@@ -1504,7 +1529,7 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
|
||||
testcase( x==4 );
|
||||
testcase( x==3 );
|
||||
if( size+pc > usableSize ){
|
||||
*pRc = SQLITE_CORRUPT_PGNO(pPg->pgno);
|
||||
*pRc = SQLITE_CORRUPT_PAGE(pPg);
|
||||
return 0;
|
||||
}else if( x<4 ){
|
||||
/* EVIDENCE-OF: R-11498-58022 In a well-formed b-tree page, the total
|
||||
@@ -1527,7 +1552,7 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
|
||||
if( pc<iAddr+size ) break;
|
||||
}
|
||||
if( pc ){
|
||||
*pRc = SQLITE_CORRUPT_PGNO(pPg->pgno);
|
||||
*pRc = SQLITE_CORRUPT_PAGE(pPg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1575,7 +1600,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
|
||||
if( top==0 && pPage->pBt->usableSize==65536 ){
|
||||
top = 65536;
|
||||
}else{
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1665,12 +1690,12 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
|
||||
while( (iFreeBlk = get2byte(&data[iPtr]))<iStart ){
|
||||
if( iFreeBlk<iPtr+4 ){
|
||||
if( iFreeBlk==0 ) break;
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
iPtr = iFreeBlk;
|
||||
}
|
||||
if( iFreeBlk>pPage->pBt->usableSize-4 ){
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
assert( iFreeBlk>iPtr || iFreeBlk==0 );
|
||||
|
||||
@@ -1682,10 +1707,10 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
|
||||
*/
|
||||
if( iFreeBlk && iEnd+3>=iFreeBlk ){
|
||||
nFrag = iFreeBlk - iEnd;
|
||||
if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PAGE(pPage);
|
||||
iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]);
|
||||
if( iEnd > pPage->pBt->usableSize ){
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
iSize = iEnd - iStart;
|
||||
iFreeBlk = get2byte(&data[iFreeBlk]);
|
||||
@@ -1698,13 +1723,13 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
|
||||
if( iPtr>hdr+1 ){
|
||||
int iPtrEnd = iPtr + get2byte(&data[iPtr+2]);
|
||||
if( iPtrEnd+3>=iStart ){
|
||||
if( iPtrEnd>iStart ) return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
if( iPtrEnd>iStart ) return SQLITE_CORRUPT_PAGE(pPage);
|
||||
nFrag += iStart - iPtrEnd;
|
||||
iSize = iEnd - iPtr;
|
||||
iStart = iPtr;
|
||||
}
|
||||
}
|
||||
if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PAGE(pPage);
|
||||
data[hdr+7] -= nFrag;
|
||||
}
|
||||
x = get2byte(&data[hdr+5]);
|
||||
@@ -1712,7 +1737,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
|
||||
/* The new freeblock is at the beginning of the cell content area,
|
||||
** so just extend the cell content area rather than create another
|
||||
** freelist entry */
|
||||
if( iStart<x || iPtr!=hdr+1 ) return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
if( iStart<x || iPtr!=hdr+1 ) return SQLITE_CORRUPT_PAGE(pPage);
|
||||
put2byte(&data[hdr+1], iFreeBlk);
|
||||
put2byte(&data[hdr+5], iEnd);
|
||||
}else{
|
||||
@@ -1785,7 +1810,7 @@ static int decodeFlags(MemPage *pPage, int flagByte){
|
||||
}else{
|
||||
/* EVIDENCE-OF: R-47608-56469 Any other value for the b-tree page type is
|
||||
** an error. */
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
pPage->max1bytePayload = pBt->max1bytePayload;
|
||||
return SQLITE_OK;
|
||||
@@ -1826,7 +1851,7 @@ static int btreeInitPage(MemPage *pPage){
|
||||
/* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating
|
||||
** the b-tree page type. */
|
||||
if( decodeFlags(pPage, data[hdr]) ){
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
assert( pBt->pageSize>=512 && pBt->pageSize<=65536 );
|
||||
pPage->maskPage = (u16)(pBt->pageSize - 1);
|
||||
@@ -1845,7 +1870,7 @@ static int btreeInitPage(MemPage *pPage){
|
||||
pPage->nCell = get2byte(&data[hdr+3]);
|
||||
if( pPage->nCell>MX_CELL(pBt) ){
|
||||
/* To many cells for a single page. The page must be corrupt */
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
testcase( pPage->nCell==MX_CELL(pBt) );
|
||||
/* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only
|
||||
@@ -1873,12 +1898,12 @@ static int btreeInitPage(MemPage *pPage){
|
||||
testcase( pc==iCellFirst );
|
||||
testcase( pc==iCellLast );
|
||||
if( pc<iCellFirst || pc>iCellLast ){
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
sz = pPage->xCellSize(pPage, &data[pc]);
|
||||
testcase( pc+sz==usableSize );
|
||||
if( pc+sz>usableSize ){
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
}
|
||||
if( !pPage->leaf ) iCellLast++;
|
||||
@@ -1896,12 +1921,12 @@ static int btreeInitPage(MemPage *pPage){
|
||||
/* EVIDENCE-OF: R-55530-52930 In a well-formed b-tree page, there will
|
||||
** always be at least one cell before the first freeblock.
|
||||
*/
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
while( 1 ){
|
||||
if( pc>iCellLast ){
|
||||
/* Freeblock off the end of the page */
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
next = get2byte(&data[pc]);
|
||||
size = get2byte(&data[pc+2]);
|
||||
@@ -1911,11 +1936,11 @@ static int btreeInitPage(MemPage *pPage){
|
||||
}
|
||||
if( next>0 ){
|
||||
/* Freeblock not in ascending order */
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
if( pc+size>(unsigned int)usableSize ){
|
||||
/* Last freeblock extends past page end */
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1927,7 +1952,7 @@ static int btreeInitPage(MemPage *pPage){
|
||||
** area, according to the page header, lies within the page.
|
||||
*/
|
||||
if( nFree>usableSize ){
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
pPage->nFree = (u16)(nFree - iCellFirst);
|
||||
pPage->isInit = 1;
|
||||
@@ -3458,7 +3483,7 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
|
||||
if( eType==PTRMAP_OVERFLOW2 ){
|
||||
/* The pointer is always the first 4 bytes of the page in this case. */
|
||||
if( get4byte(pPage->aData)!=iFrom ){
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
put4byte(pPage->aData, iTo);
|
||||
}else{
|
||||
@@ -3477,7 +3502,7 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
|
||||
pPage->xParseCell(pPage, pCell, &info);
|
||||
if( info.nLocal<info.nPayload ){
|
||||
if( pCell+info.nSize > pPage->aData+pPage->pBt->usableSize ){
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
if( iFrom==get4byte(pCell+info.nSize-4) ){
|
||||
put4byte(pCell+info.nSize-4, iTo);
|
||||
@@ -3495,7 +3520,7 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
|
||||
if( i==nCell ){
|
||||
if( eType!=PTRMAP_BTREE ||
|
||||
get4byte(&pPage->aData[pPage->hdrOffset+8])!=iFrom ){
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
put4byte(&pPage->aData[pPage->hdrOffset+8], iTo);
|
||||
}
|
||||
@@ -4593,7 +4618,7 @@ static int accessPayload(
|
||||
** &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize]
|
||||
** but is recast into its current form to avoid integer overflow problems
|
||||
*/
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
|
||||
/* Check if data must be read/written to/from the btree page itself. */
|
||||
@@ -4741,7 +4766,7 @@ static int accessPayload(
|
||||
|
||||
if( rc==SQLITE_OK && amt>0 ){
|
||||
/* Overflow chain ends prematurely */
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -5019,7 +5044,7 @@ static int moveToRoot(BtCursor *pCur){
|
||||
** (or the freelist). */
|
||||
assert( pRoot->intKey==1 || pRoot->intKey==0 );
|
||||
if( pRoot->isInit==0 || (pCur->pKeyInfo==0)!=pRoot->intKey ){
|
||||
return SQLITE_CORRUPT_PGNO(pCur->pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pCur->pPage);
|
||||
}
|
||||
|
||||
skip_init:
|
||||
@@ -5292,7 +5317,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
if( pPage->intKeyLeaf ){
|
||||
while( 0x80 <= *(pCell++) ){
|
||||
if( pCell>=pPage->aDataEnd ){
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5366,7 +5391,7 @@ int sqlite3BtreeMovetoUnpacked(
|
||||
testcase( nCell==1 ); /* Invalid key size: 0x80 0x80 0x01 */
|
||||
testcase( nCell==2 ); /* Minimum legal index key size */
|
||||
if( nCell<2 ){
|
||||
rc = SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
rc = SQLITE_CORRUPT_PAGE(pPage);
|
||||
goto moveto_finish;
|
||||
}
|
||||
pCellKey = sqlite3Malloc( nCell+18 );
|
||||
@@ -6169,7 +6194,7 @@ static int clearCell(
|
||||
}
|
||||
if( pCell+pInfo->nSize-1 > pPage->aData+pPage->maskPage ){
|
||||
/* Cell extends past end of page */
|
||||
return SQLITE_CORRUPT_PGNO(pPage->pgno);
|
||||
return SQLITE_CORRUPT_PAGE(pPage);
|
||||
}
|
||||
ovflPgno = get4byte(pCell + pInfo->nSize - 4);
|
||||
pBt = pPage->pBt;
|
||||
|
Reference in New Issue
Block a user