/ Check-in [11e58f5b]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Enhanced detection of problems on the freelist and on overflow list in PRAGMA integrity_check.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256:11e58f5b37d99848978007d834d187c262d904eb9d58924742e028d7cb324e64
User & Date: drh 2018-07-20 13:39:28
Context
2018-07-20
15:44
New checks in PRAGMA integrity_check to validate the autovacuum settings in the header. check-in: a4663f09 user: drh tags: trunk
13:39
Enhanced detection of problems on the freelist and on overflow list in PRAGMA integrity_check. check-in: 11e58f5b user: drh tags: trunk
2018-07-19
15:27
Avoid a branch in the commit logic that is unreachable when compiled without SQLITE_ENABLE_BATCH_ATOMIC_WRITE. check-in: 271b8980 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/btree.c.

9333
9334
9335
9336
9337
9338
9339
9340
9341
9342
9343
9344
9345
9346
9347
9348
....
9389
9390
9391
9392
9393
9394
9395
9396
9397
9398
9399
9400
9401
9402
9403
9404
9405
9406

9407
9408
9409
9410
9411
9412
9413
....
9443
9444
9445
9446
9447
9448
9449
9450
9451
9452
9453



9454
9455
9456
9457
9458
9459
9460
** reference to the page, add an error message to pCheck->zErrMsg.
** Return 1 if there are 2 or more references to the page and 0 if
** if this is the first reference to the page.
**
** Also check that the page number is in bounds.
*/
static int checkRef(IntegrityCk *pCheck, Pgno iPage){
  if( iPage==0 ) return 1;
  if( iPage>pCheck->nPage ){
    checkAppendMsg(pCheck, "invalid page number %d", iPage);
    return 1;
  }
  if( getPageReferenced(pCheck, iPage) ){
    checkAppendMsg(pCheck, "2nd reference to page %d", iPage);
    return 1;
  }
................................................................................
  IntegrityCk *pCheck,  /* Integrity checking context */
  int isFreeList,       /* True for a freelist.  False for overflow page list */
  int iPage,            /* Page number for first page in the list */
  int N                 /* Expected number of pages in the list */
){
  int i;
  int expected = N;
  int iFirst = iPage;
  while( N-- > 0 && pCheck->mxErr ){
    DbPage *pOvflPage;
    unsigned char *pOvflData;
    if( iPage<1 ){
      checkAppendMsg(pCheck,
         "%d of %d pages missing from overflow list starting at %d",
          N+1, expected, iFirst);
      break;
    }
    if( checkRef(pCheck, iPage) ) break;

    if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage, 0) ){
      checkAppendMsg(pCheck, "failed to get page %d", iPage);
      break;
    }
    pOvflData = (unsigned char *)sqlite3PagerGetData(pOvflPage);
    if( isFreeList ){
      int n = get4byte(&pOvflData[4]);
................................................................................
        i = get4byte(pOvflData);
        checkPtrmap(pCheck, i, PTRMAP_OVERFLOW2, iPage);
      }
    }
#endif
    iPage = get4byte(pOvflData);
    sqlite3PagerUnref(pOvflPage);

    if( isFreeList && N<(iPage!=0) ){
      checkAppendMsg(pCheck, "free-page count in header is too small");
    }



  }
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */

/*
** An implementation of a min-heap.
**







<
|







 







|
|


<
<
<
<
<
<

>







 







|
|
|
<
>
>
>







9333
9334
9335
9336
9337
9338
9339

9340
9341
9342
9343
9344
9345
9346
9347
....
9388
9389
9390
9391
9392
9393
9394
9395
9396
9397
9398






9399
9400
9401
9402
9403
9404
9405
9406
9407
....
9437
9438
9439
9440
9441
9442
9443
9444
9445
9446

9447
9448
9449
9450
9451
9452
9453
9454
9455
9456
** reference to the page, add an error message to pCheck->zErrMsg.
** Return 1 if there are 2 or more references to the page and 0 if
** if this is the first reference to the page.
**
** Also check that the page number is in bounds.
*/
static int checkRef(IntegrityCk *pCheck, Pgno iPage){

  if( iPage>pCheck->nPage || iPage==0 ){
    checkAppendMsg(pCheck, "invalid page number %d", iPage);
    return 1;
  }
  if( getPageReferenced(pCheck, iPage) ){
    checkAppendMsg(pCheck, "2nd reference to page %d", iPage);
    return 1;
  }
................................................................................
  IntegrityCk *pCheck,  /* Integrity checking context */
  int isFreeList,       /* True for a freelist.  False for overflow page list */
  int iPage,            /* Page number for first page in the list */
  int N                 /* Expected number of pages in the list */
){
  int i;
  int expected = N;
  int nErrAtStart = pCheck->nErr;
  while( iPage!=0 && pCheck->mxErr ){
    DbPage *pOvflPage;
    unsigned char *pOvflData;






    if( checkRef(pCheck, iPage) ) break;
    N--;
    if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage, 0) ){
      checkAppendMsg(pCheck, "failed to get page %d", iPage);
      break;
    }
    pOvflData = (unsigned char *)sqlite3PagerGetData(pOvflPage);
    if( isFreeList ){
      int n = get4byte(&pOvflData[4]);
................................................................................
        i = get4byte(pOvflData);
        checkPtrmap(pCheck, i, PTRMAP_OVERFLOW2, iPage);
      }
    }
#endif
    iPage = get4byte(pOvflData);
    sqlite3PagerUnref(pOvflPage);
  }
  if( N && nErrAtStart==pCheck->nErr ){
    checkAppendMsg(pCheck,

      "%s is %d but should be %d",
      isFreeList ? "size" : "overflow list length",
      expected-N, expected);
  }
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */

/*
** An implementation of a min-heap.
**

Changes to test/corrupt2.test.

587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
  sqlite3 db test.db
  execsql { PRAGMA freelist_count }
} {2}

do_execsql_test 14.3 {
  PRAGMA integrity_check;
} {{*** in database main ***
Main freelist: free-page count in header is too small}}

# Use 2 of the free pages on the free-list.
#
do_execsql_test 14.4 {
  INSERT INTO t1 VALUES(randomblob(2500));
  PRAGMA freelist_count;
} {0}

do_execsql_test 14.5 {
  PRAGMA integrity_check;
} {{*** in database main ***
Page 3 is never used}}


finish_test

finish_test







|











|





587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
  sqlite3 db test.db
  execsql { PRAGMA freelist_count }
} {2}

do_execsql_test 14.3 {
  PRAGMA integrity_check;
} {{*** in database main ***
Main freelist: size is 3 but should be 2}}

# Use 2 of the free pages on the free-list.
#
do_execsql_test 14.4 {
  INSERT INTO t1 VALUES(randomblob(2500));
  PRAGMA freelist_count;
} {0}

do_execsql_test 14.5 {
  PRAGMA integrity_check;
} {{*** in database main ***
Main freelist: size is 1 but should be 0}}


finish_test

finish_test

Changes to test/corrupt3.test.

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
...
107
108
109
110
111
112
113
114
115
116
117
do_test corrupt3-1.5 {
  hexio_get_int [hexio_read test.db 2048 4]
} 0      ;# First chained overflow is 0

integrity_check corrupt3-1.6

# Make the overflow chain loop back on itself.   See if the
# corruption is detected.   (Actually, the last pointer in
# an overflow chain is ignored, so this is not an error.)
#
do_test corrupt3-1.7 {
  db close
  hexio_write test.db 2048 [hexio_render_int32 3]
  sqlite3 db test.db
  catchsql {
    SELECT x FROM t1
  }
} [list 0 $bigstring]


integrity_check corrupt3-1.8




# Change the pointer for the first page of the overflow
# change to be a non-existant page.
#
do_test corrupt3-1.9 {
  db close
  hexio_write test.db 2044 [hexio_render_int32 4]
................................................................................
  }
} [list 1 {database disk image is malformed}]
do_test corrupt3-1.12 {
  catchsql {
    PRAGMA integrity_check
  }
} {0 {{*** in database main ***
On tree page 2 cell 0: 1 of 1 pages missing from overflow list starting at 0
Page 3 is never used}}}

finish_test







|
<









>
>
|
>
>
>







 







|



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
...
111
112
113
114
115
116
117
118
119
120
121
do_test corrupt3-1.5 {
  hexio_get_int [hexio_read test.db 2048 4]
} 0      ;# First chained overflow is 0

integrity_check corrupt3-1.6

# Make the overflow chain loop back on itself.   See if the
# corruption is detected.

#
do_test corrupt3-1.7 {
  db close
  hexio_write test.db 2048 [hexio_render_int32 3]
  sqlite3 db test.db
  catchsql {
    SELECT x FROM t1
  }
} [list 0 $bigstring]
do_test corrupt3-1.8 {
  catchsql {
    PRAGMA integrity_check
  }
} {0 {{*** in database main ***
On tree page 2 cell 0: 2nd reference to page 3}}}

# Change the pointer for the first page of the overflow
# change to be a non-existant page.
#
do_test corrupt3-1.9 {
  db close
  hexio_write test.db 2044 [hexio_render_int32 4]
................................................................................
  }
} [list 1 {database disk image is malformed}]
do_test corrupt3-1.12 {
  catchsql {
    PRAGMA integrity_check
  }
} {0 {{*** in database main ***
On tree page 2 cell 0: overflow list length is 0 but should be 1
Page 3 is never used}}}

finish_test