summaryrefslogtreecommitdiffstats
path: root/ext/recover
diff options
context:
space:
mode:
Diffstat (limited to 'ext/recover')
-rw-r--r--ext/recover/dbdata.c200
-rw-r--r--ext/recover/recover1.test15
-rw-r--r--ext/recover/recovercorrupt3.test549
-rw-r--r--ext/recover/recovercorrupt4.test64
4 files changed, 750 insertions, 78 deletions
diff --git a/ext/recover/dbdata.c b/ext/recover/dbdata.c
index ca63710..109aeef 100644
--- a/ext/recover/dbdata.c
+++ b/ext/recover/dbdata.c
@@ -88,6 +88,15 @@ typedef unsigned int u32;
typedef struct DbdataTable DbdataTable;
typedef struct DbdataCursor DbdataCursor;
+typedef struct DbdataBuffer DbdataBuffer;
+
+/*
+** Buffer type.
+*/
+struct DbdataBuffer {
+ u8 *aBuf;
+ sqlite3_int64 nBuf;
+};
/* Cursor object */
struct DbdataCursor {
@@ -104,7 +113,7 @@ struct DbdataCursor {
sqlite3_int64 iRowid;
/* Only for the sqlite_dbdata table */
- u8 *pRec; /* Buffer containing current record */
+ DbdataBuffer rec;
sqlite3_int64 nRec; /* Size of pRec[] in bytes */
sqlite3_int64 nHdr; /* Size of header in bytes */
int iField; /* Current field number */
@@ -150,6 +159,31 @@ struct DbdataTable {
")"
/*
+** Ensure the buffer passed as the first argument is at least nMin bytes
+** in size. If an error occurs while attempting to resize the buffer,
+** SQLITE_NOMEM is returned. Otherwise, SQLITE_OK.
+*/
+static int dbdataBufferSize(DbdataBuffer *pBuf, sqlite3_int64 nMin){
+ if( nMin>pBuf->nBuf ){
+ sqlite3_int64 nNew = nMin+16384;
+ u8 *aNew = (u8*)sqlite3_realloc64(pBuf->aBuf, nNew);
+
+ if( aNew==0 ) return SQLITE_NOMEM;
+ pBuf->aBuf = aNew;
+ pBuf->nBuf = nNew;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Release the allocation managed by buffer pBuf.
+*/
+static void dbdataBufferFree(DbdataBuffer *pBuf){
+ sqlite3_free(pBuf->aBuf);
+ memset(pBuf, 0, sizeof(*pBuf));
+}
+
+/*
** Connect to an sqlite_dbdata (pAux==0) or sqlite_dbptr (pAux!=0) virtual
** table.
*/
@@ -289,9 +323,9 @@ static void dbdataResetCursor(DbdataCursor *pCsr){
pCsr->iField = 0;
pCsr->bOnePage = 0;
sqlite3_free(pCsr->aPage);
- sqlite3_free(pCsr->pRec);
- pCsr->pRec = 0;
+ dbdataBufferFree(&pCsr->rec);
pCsr->aPage = 0;
+ pCsr->nRec = 0;
}
/*
@@ -433,63 +467,75 @@ static void dbdataValue(
u8 *pData,
sqlite3_int64 nData
){
- if( eType>=0 && dbdataValueBytes(eType)<=nData ){
- switch( eType ){
- case 0:
- case 10:
- case 11:
- sqlite3_result_null(pCtx);
- break;
-
- case 8:
- sqlite3_result_int(pCtx, 0);
- break;
- case 9:
- sqlite3_result_int(pCtx, 1);
- break;
-
- case 1: case 2: case 3: case 4: case 5: case 6: case 7: {
- sqlite3_uint64 v = (signed char)pData[0];
- pData++;
- switch( eType ){
- case 7:
- case 6: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2;
- case 5: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2;
- case 4: v = (v<<8) + pData[0]; pData++;
- case 3: v = (v<<8) + pData[0]; pData++;
- case 2: v = (v<<8) + pData[0]; pData++;
- }
-
- if( eType==7 ){
- double r;
- memcpy(&r, &v, sizeof(r));
- sqlite3_result_double(pCtx, r);
- }else{
- sqlite3_result_int64(pCtx, (sqlite3_int64)v);
+ if( eType>=0 ){
+ if( dbdataValueBytes(eType)<=nData ){
+ switch( eType ){
+ case 0:
+ case 10:
+ case 11:
+ sqlite3_result_null(pCtx);
+ break;
+
+ case 8:
+ sqlite3_result_int(pCtx, 0);
+ break;
+ case 9:
+ sqlite3_result_int(pCtx, 1);
+ break;
+
+ case 1: case 2: case 3: case 4: case 5: case 6: case 7: {
+ sqlite3_uint64 v = (signed char)pData[0];
+ pData++;
+ switch( eType ){
+ case 7:
+ case 6: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2;
+ case 5: v = (v<<16) + (pData[0]<<8) + pData[1]; pData += 2;
+ case 4: v = (v<<8) + pData[0]; pData++;
+ case 3: v = (v<<8) + pData[0]; pData++;
+ case 2: v = (v<<8) + pData[0]; pData++;
+ }
+
+ if( eType==7 ){
+ double r;
+ memcpy(&r, &v, sizeof(r));
+ sqlite3_result_double(pCtx, r);
+ }else{
+ sqlite3_result_int64(pCtx, (sqlite3_int64)v);
+ }
+ break;
}
- break;
- }
-
- default: {
- int n = ((eType-12) / 2);
- if( eType % 2 ){
- switch( enc ){
-#ifndef SQLITE_OMIT_UTF16
- case SQLITE_UTF16BE:
- sqlite3_result_text16be(pCtx, (void*)pData, n, SQLITE_TRANSIENT);
- break;
- case SQLITE_UTF16LE:
- sqlite3_result_text16le(pCtx, (void*)pData, n, SQLITE_TRANSIENT);
- break;
-#endif
- default:
- sqlite3_result_text(pCtx, (char*)pData, n, SQLITE_TRANSIENT);
- break;
+
+ default: {
+ int n = ((eType-12) / 2);
+ if( eType % 2 ){
+ switch( enc ){
+ #ifndef SQLITE_OMIT_UTF16
+ case SQLITE_UTF16BE:
+ sqlite3_result_text16be(pCtx, (void*)pData, n, SQLITE_TRANSIENT);
+ break;
+ case SQLITE_UTF16LE:
+ sqlite3_result_text16le(pCtx, (void*)pData, n, SQLITE_TRANSIENT);
+ break;
+ #endif
+ default:
+ sqlite3_result_text(pCtx, (char*)pData, n, SQLITE_TRANSIENT);
+ break;
+ }
+ }else{
+ sqlite3_result_blob(pCtx, pData, n, SQLITE_TRANSIENT);
}
- }else{
- sqlite3_result_blob(pCtx, pData, n, SQLITE_TRANSIENT);
}
}
+ }else{
+ if( eType==7 ){
+ sqlite3_result_double(pCtx, 0.0);
+ }else if( eType<7 ){
+ sqlite3_result_int(pCtx, 0);
+ }else if( eType%2 ){
+ sqlite3_result_text(pCtx, "", 0, SQLITE_STATIC);
+ }else{
+ sqlite3_result_blob(pCtx, "", 0, SQLITE_STATIC);
+ }
}
}
}
@@ -551,7 +597,8 @@ static int dbdataNext(sqlite3_vtab_cursor *pCursor){
}
}else{
/* If there is no record loaded, load it now. */
- if( pCsr->pRec==0 ){
+ assert( pCsr->rec.aBuf!=0 || pCsr->nRec==0 );
+ if( pCsr->nRec==0 ){
int bHasRowid = 0;
int nPointer = 0;
sqlite3_int64 nPayload = 0;
@@ -595,6 +642,7 @@ static int dbdataNext(sqlite3_vtab_cursor *pCursor){
}else{
iOff += dbdataGetVarintU32(&pCsr->aPage[iOff], &nPayload);
if( nPayload>0x7fffff00 ) nPayload &= 0x3fff;
+ if( nPayload==0 ) nPayload = 1;
}
/* If this is a leaf intkey cell, load the rowid */
@@ -629,13 +677,12 @@ static int dbdataNext(sqlite3_vtab_cursor *pCursor){
/* Allocate space for payload. And a bit more to catch small buffer
** overruns caused by attempting to read a varint or similar from
** near the end of a corrupt record. */
- pCsr->pRec = (u8*)sqlite3_malloc64(nPayload+DBDATA_PADDING_BYTES);
- if( pCsr->pRec==0 ) return SQLITE_NOMEM;
- memset(pCsr->pRec, 0, nPayload+DBDATA_PADDING_BYTES);
- pCsr->nRec = nPayload;
+ rc = dbdataBufferSize(&pCsr->rec, nPayload+DBDATA_PADDING_BYTES);
+ if( rc!=SQLITE_OK ) return rc;
+ assert( nPayload!=0 );
/* Load the nLocal bytes of payload */
- memcpy(pCsr->pRec, &pCsr->aPage[iOff], nLocal);
+ memcpy(pCsr->rec.aBuf, &pCsr->aPage[iOff], nLocal);
iOff += nLocal;
/* Load content from overflow pages */
@@ -653,19 +700,22 @@ static int dbdataNext(sqlite3_vtab_cursor *pCursor){
nCopy = U-4;
if( nCopy>nRem ) nCopy = nRem;
- memcpy(&pCsr->pRec[nPayload-nRem], &aOvfl[4], nCopy);
+ memcpy(&pCsr->rec.aBuf[nPayload-nRem], &aOvfl[4], nCopy);
nRem -= nCopy;
pgnoOvfl = get_uint32(aOvfl);
sqlite3_free(aOvfl);
}
+ nPayload -= nRem;
}
+ memset(&pCsr->rec.aBuf[nPayload], 0, DBDATA_PADDING_BYTES);
+ pCsr->nRec = nPayload;
- iHdr = dbdataGetVarintU32(pCsr->pRec, &nHdr);
+ iHdr = dbdataGetVarintU32(pCsr->rec.aBuf, &nHdr);
if( nHdr>nPayload ) nHdr = 0;
pCsr->nHdr = nHdr;
- pCsr->pHdrPtr = &pCsr->pRec[iHdr];
- pCsr->pPtr = &pCsr->pRec[pCsr->nHdr];
+ pCsr->pHdrPtr = &pCsr->rec.aBuf[iHdr];
+ pCsr->pPtr = &pCsr->rec.aBuf[pCsr->nHdr];
pCsr->iField = (bHasRowid ? -1 : 0);
}
}
@@ -673,7 +723,7 @@ static int dbdataNext(sqlite3_vtab_cursor *pCursor){
pCsr->iField++;
if( pCsr->iField>0 ){
sqlite3_int64 iType;
- if( pCsr->pHdrPtr>=&pCsr->pRec[pCsr->nRec]
+ if( pCsr->pHdrPtr>=&pCsr->rec.aBuf[pCsr->nRec]
|| pCsr->iField>=DBDATA_MX_FIELD
){
bNextPage = 1;
@@ -681,8 +731,8 @@ static int dbdataNext(sqlite3_vtab_cursor *pCursor){
int szField = 0;
pCsr->pHdrPtr += dbdataGetVarintU32(pCsr->pHdrPtr, &iType);
szField = dbdataValueBytes(iType);
- if( (pCsr->nRec - (pCsr->pPtr - pCsr->pRec))<szField ){
- pCsr->pPtr = &pCsr->pRec[pCsr->nRec];
+ if( (pCsr->nRec - (pCsr->pPtr - pCsr->rec.aBuf))<szField ){
+ pCsr->pPtr = &pCsr->rec.aBuf[pCsr->nRec];
}else{
pCsr->pPtr += szField;
}
@@ -692,20 +742,18 @@ static int dbdataNext(sqlite3_vtab_cursor *pCursor){
if( bNextPage ){
sqlite3_free(pCsr->aPage);
- sqlite3_free(pCsr->pRec);
pCsr->aPage = 0;
- pCsr->pRec = 0;
+ pCsr->nRec = 0;
if( pCsr->bOnePage ) return SQLITE_OK;
pCsr->iPgno++;
}else{
- if( pCsr->iField<0 || pCsr->pHdrPtr<&pCsr->pRec[pCsr->nHdr] ){
+ if( pCsr->iField<0 || pCsr->pHdrPtr<&pCsr->rec.aBuf[pCsr->nHdr] ){
return SQLITE_OK;
}
/* Advance to the next cell. The next iteration of the loop will load
** the record and so on. */
- sqlite3_free(pCsr->pRec);
- pCsr->pRec = 0;
+ pCsr->nRec = 0;
pCsr->iCell++;
}
}
@@ -895,12 +943,12 @@ static int dbdataColumn(
case DBDATA_COLUMN_VALUE: {
if( pCsr->iField<0 ){
sqlite3_result_int64(ctx, pCsr->iIntkey);
- }else if( &pCsr->pRec[pCsr->nRec] >= pCsr->pPtr ){
+ }else if( &pCsr->rec.aBuf[pCsr->nRec] >= pCsr->pPtr ){
sqlite3_int64 iType;
dbdataGetVarintU32(pCsr->pHdrPtr, &iType);
dbdataValue(
ctx, pCsr->enc, iType, pCsr->pPtr,
- &pCsr->pRec[pCsr->nRec] - pCsr->pPtr
+ &pCsr->rec.aBuf[pCsr->nRec] - pCsr->pPtr
);
}
break;
diff --git a/ext/recover/recover1.test b/ext/recover/recover1.test
index 070dd03..11a4378 100644
--- a/ext/recover/recover1.test
+++ b/ext/recover/recover1.test
@@ -342,7 +342,7 @@ foreach enc {utf8 utf16 utf16le utf16be} {
DELETE FROM sqlite_schema WHERE name='t1';
}
- proc my_sql_hook {sql} {
+ proc my_sql_hook2 {sql} {
if {[string match "INSERT INTO lostandfound*" $sql]} {
lappend ::script $sql
}
@@ -350,7 +350,7 @@ foreach enc {utf8 utf16 utf16le utf16be} {
}
do_test 18.$enc.2 {
set ::script [list]
- set R [sqlite3_recover_init_sql db main my_sql_hook]
+ set R [sqlite3_recover_init_sql db main my_sql_hook2]
$R config lostandfound lostandfound
$R run
$R finish
@@ -358,7 +358,18 @@ foreach enc {utf8 utf16 utf16le utf16be} {
} {{INSERT INTO lostandfound VALUES(2, 2, 2, 1, 'abc', 'def')}}
}
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 19.0 {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY, b TEXT);
+ INSERT INTO t1 VALUES(1, 'one');
+ INSERT INTO t1 VALUES(2, 'two');
+
+ ALTER TABLE t1 ADD COLUMN c NOT NULL DEFAULT 13;
+ INSERT INTO t1 VALUES(3, 'three', 'hello world');
+}
+do_recover_test 19.1
diff --git a/ext/recover/recovercorrupt3.test b/ext/recover/recovercorrupt3.test
new file mode 100644
index 0000000..9a7c2d0
--- /dev/null
+++ b/ext/recover/recovercorrupt3.test
@@ -0,0 +1,549 @@
+# 2024 May 1
+#
+# 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.
+#
+#***********************************************************************
+#
+
+source [file join [file dirname [info script]] recover_common.tcl]
+set testprefix recovercorrupt3
+
+#| 0: d5 d5 9b d5 d5 d5 d5 d5 d5 d5 d5 d5 d5 d5 d5 d5 ................
+#| 16: 04 00 00 00 1d 00 00 00 00 00 00 00 5f 5f 5f 5f ............____
+#| 32: 5f 5f 5f 5f 5f 5f 5f 5f 71 5f 5f 5f 02 02 02 02 ________q___....
+#| 48: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+#| 64: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+#| 80: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+#| 96: 02 02 02 02
+
+#-------------------------------------------------------------------------
+reset_db
+do_test 1.0 {
+ sqlite3 db {}
+ db deserialize [decode_hexdb {
+| size 3821 pagesize 1024 filename clusterfuzz-testcase-sql_recovery_fuzzer-5803962339885056
+| page 1 offset 0
+| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
+| 16: 10 00 01 01 00 40 20 20 00 00 00 01 00 00 00 02 .....@ ........
+| 32: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 04 ................
+| 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................
+| 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 ................
+| 96: 00 2e 7a 70 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 112: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 128: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 144: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 160: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 176: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 192: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 208: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 224: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 240: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 256: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 272: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 288: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 304: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 320: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 336: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 352: 02 02 02 02 a0 02 02 02 02 02 02 02 02 02 02 02 ................
+| 368: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 384: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 400: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 416: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 432: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 448: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 29 29 ..............))
+| 464: 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 ))))))))))))))))
+| 480: 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 ))))))))))))))))
+| 496: 29 29 29 dd dd dd dd dd dd dd dd dd dd dd dd dd ))).............
+| 512: dd dd dd dd dd dd dd dd dd 6e 69 d2 e9 e9 e9 d2 .........ni.....
+| 528: d2 d2 d2 d2 dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 544: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 560: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 576: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 592: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 608: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 624: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 640: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 656: dd dd dd dd dd dd dd da dd dd dd dd dd dd dd dd ................
+| 672: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 688: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 704: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 720: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 736: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 752: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 768: dd dd dd dd dd dd dd dd dd dd dd dd dd 29 29 29 .............)))
+| 784: 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 ))))))))))))))))
+| 800: 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 ))))))))))))))))
+| 816: 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 ))))))))))))))))
+| 832: 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 ))))))))))))))))
+| 848: 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 ))))))))))))))))
+| 864: 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 ))))))))))))))))
+| 880: 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 ))))))))))))))))
+| 896: 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 ))))))))))))))))
+| 912: 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 ))))))))))))))))
+| 928: 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 ))))))))))))))))
+| 944: 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 ))))))))))))))))
+| 960: 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 ))))))))))))))))
+| 976: 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 ))))))))))))))))
+| 992: 29 29 29 29 29 29 29 29 29 29 dd dd dd dd dd dd ))))))))))......
+| 1008: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| page 2 offset 1024
+| 0: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 16: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 32: dd dd 6e 69 d2 e9 e9 e9 d2 d2 d2 d2 d2 dd dd dd ..ni............
+| 48: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 64: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 80: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 96: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 112: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 128: dd dd dd dd dd dd 29 29 29 29 29 29 29 29 29 29 ......))))))))))
+| 144: 29 29 29 29 29 29 29 29 29 ad a5 29 29 29 29 00 )))))))))..)))).
+| 160: 75 9c 11 00 5b e5 64 28 7c ca 09 69 28 2d 69 00 u...[.d(|..i(-i.
+| 176: 85 88 6c 81 48 83 a0 93 c0 c0 82 8b 81 84 85 f9 ..l.H...........
+| 192: 88 7a 00 7f 00 96 40 7b 12 4b 84 75 a0 00 99 a0 .z....@..K.u....
+| 208: df a0 7e 81 c6 90 8f 7f 84 85 cc 84 82 90 88 60 ..~............`
+| 224: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
+| 240: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
+| 256: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
+| 272: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
+| 288: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 02 02 ................
+| 304: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 320: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 336: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 352: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 368: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 384: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 400: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 416: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 432: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 448: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 464: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 480: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 496: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 512: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 528: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 544: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 560: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 576: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 592: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 608: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 624: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 640: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 656: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 672: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 688: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 704: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 720: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 736: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 752: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 768: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 784: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 800: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 816: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 832: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 848: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 864: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 880: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 896: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 912: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 928: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 944: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 960: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 976: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 992: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 1008: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| page 3 offset 2048
+| 0: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 16: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 32: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 48: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 64: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 80: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 96: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 112: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 128: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 144: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 160: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 176: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 192: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 208: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 224: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 240: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 256: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 272: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 288: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 304: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 320: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 336: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 352: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 368: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 384: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 400: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 416: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 432: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 448: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 464: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 480: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 496: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 512: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 528: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 544: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 560: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 576: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 592: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 608: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 624: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 640: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 656: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 672: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 688: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 704: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 720: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 736: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 752: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 768: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 784: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 800: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 816: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 832: 02 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
+| 848: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
+| 864: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
+| 880: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
+| 896: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
+| 912: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
+| 928: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
+| 944: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
+| 960: 80 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 976: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 992: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 1008: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| page 4 offset 3072
+| 0: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 16: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 32: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 48: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 64: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 80: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 96: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 112: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 128: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 144: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 160: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 176: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 192: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 208: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 224: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 240: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 256: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 272: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 288: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 304: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 320: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 336: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 352: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 368: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 384: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 400: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 416: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 432: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 448: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 464: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 480: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 496: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 512: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 528: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 544: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 560: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 576: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 592: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 608: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 624: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 640: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 656: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 672: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 688: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 704: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 720: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 736: 5f 5f 5f 5f 5f 5f 5f 00 d5 fe fe fe 08 00 00 00 _______.........
+| end clusterfuzz-testcase-sql_recovery_fuzzer-5803962339885056
+}]} {}
+
+sqlite3_dbdata_init db
+do_execsql_test 1.1 {
+ PRAGMA writable_schema = 1;
+}
+
+do_test 1.2 {
+ set R [sqlite3_recover_init db main test.db2]
+ $R run
+ $R finish
+} {}
+
+#-------------------------------------------------------------------------
+reset_db
+do_test 2.0 {
+ sqlite3 db {}
+ db deserialize [decode_hexdb {
+| size 3821 pagesize 1024 filename clusterfuzz-testcase-sql_recovery_fuzzer-5803962339885056
+| page 1 offset 0
+| 0: 53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00 SQLite format 3.
+| 16: 04 00 01 01 00 40 20 20 00 00 00 01 00 00 00 02 .....@ ........
+| 32: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 04 ................
+| 48: 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 ................
+| 80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 ................
+| 96: 00 2e 7a 70 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 112: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 128: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 144: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 160: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 176: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 192: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 208: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 224: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 240: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 256: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 272: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 288: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 304: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 320: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 336: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 352: 02 02 02 02 a0 02 02 02 02 02 02 02 02 02 02 02 ................
+| 368: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 384: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 400: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 416: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 432: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 448: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 29 29 ..............))
+| 464: 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 ))))))))))))))))
+| 480: 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 ))))))))))))))))
+| 496: 29 29 29 dd dd dd dd dd dd dd dd dd dd dd dd dd ))).............
+| 512: dd dd dd dd dd dd dd dd dd 6e 69 d2 e9 e9 e9 d2 .........ni.....
+| 528: d2 d2 d2 d2 dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 544: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 560: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 576: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 592: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 608: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 624: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 640: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 656: dd dd dd dd dd dd dd da dd dd dd dd dd dd dd dd ................
+| 672: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 688: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 704: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 720: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 736: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 752: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 768: dd dd dd dd dd dd dd dd dd dd dd dd dd 29 29 29 .............)))
+| 784: 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 ))))))))))))))))
+| 800: 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 ))))))))))))))))
+| 816: 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 ))))))))))))))))
+| 832: 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 ))))))))))))))))
+| 848: 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 ))))))))))))))))
+| 864: 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 ))))))))))))))))
+| 880: 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 ))))))))))))))))
+| 896: 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 ))))))))))))))))
+| 912: 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 ))))))))))))))))
+| 928: 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 ))))))))))))))))
+| 944: 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 ))))))))))))))))
+| 960: 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 ))))))))))))))))
+| 976: 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 ))))))))))))))))
+| 992: 29 29 29 29 29 29 29 29 29 29 dd dd dd dd dd dd ))))))))))......
+| 1008: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| page 2 offset 1024
+| 0: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 16: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 32: dd dd 6e 69 d2 e9 e9 e9 d2 d2 d2 d2 d2 dd dd dd ..ni............
+| 48: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 64: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 80: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 96: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 112: dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd dd ................
+| 128: dd dd dd dd dd dd 29 29 29 29 29 29 29 29 29 29 ......))))))))))
+| 144: 29 29 29 29 29 29 29 29 29 ad a5 29 29 29 29 00 )))))))))..)))).
+| 160: 75 9c 11 00 5b e5 64 28 7c ca 09 69 28 2d 69 00 u...[.d(|..i(-i.
+| 176: 85 88 6c 81 48 83 a0 93 c0 c0 82 8b 81 84 85 f9 ..l.H...........
+| 192: 88 7a 00 7f 00 96 40 7b 12 4b 84 75 a0 00 99 a0 .z....@..K.u....
+| 208: df a0 7e 81 c6 90 8f 7f 84 85 cc 84 82 90 88 60 ..~............`
+| 224: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
+| 240: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
+| 256: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
+| 272: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
+| 288: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 02 02 ................
+| 304: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 320: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 336: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 352: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 368: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 384: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 400: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 416: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 432: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 448: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 464: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 480: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 496: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 512: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 528: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 544: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 560: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 576: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 592: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 608: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 624: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 640: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 656: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 672: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 688: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 704: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 720: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 736: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 752: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 768: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 784: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 800: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 816: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 832: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 848: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 864: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 880: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 896: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 912: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 928: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 944: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 960: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 976: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 992: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 1008: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| page 3 offset 2048
+| 0: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 16: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 32: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 48: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 64: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 80: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 96: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 112: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 128: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 144: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 160: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 176: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 192: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 208: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 224: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 240: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 256: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 272: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 288: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 304: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 320: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 336: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 352: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 368: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 384: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 400: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 416: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 432: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 448: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 464: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 480: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 496: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 512: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 528: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 544: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 560: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 576: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 592: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 608: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 624: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 640: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 656: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 672: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 688: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 704: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 720: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 736: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 752: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 768: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 784: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 800: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 816: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 832: 02 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
+| 848: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
+| 864: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
+| 880: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
+| 896: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
+| 912: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
+| 928: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
+| 944: 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ................
+| 960: 80 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 976: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 992: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 1008: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| page 4 offset 3072
+| 0: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 16: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 32: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 48: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 64: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 80: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 96: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 112: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 128: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 144: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 160: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 176: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 192: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 208: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 224: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 240: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 256: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 272: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 288: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 304: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 320: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 336: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 352: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 368: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 384: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 400: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 416: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 432: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 448: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 464: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 480: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 496: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 512: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 528: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 544: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 560: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 576: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 592: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 608: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 624: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 640: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 656: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 672: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 688: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 704: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 720: 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 ................
+| 736: 5f 5f 5f 5f 5f 5f 5f 00 d5 fe fe fe 08 00 00 00 _______.........
+| end clusterfuzz-testcase-sql_recovery_fuzzer-5803962339885056
+}]} {}
+
+sqlite3_dbdata_init db
+do_execsql_test 2.1 {
+ PRAGMA writable_schema = 1;
+}
+
+do_test 2.2 {
+ set R [sqlite3_recover_init db main test.db2]
+ $R run
+ $R finish
+} {}
+
+finish_test
+
diff --git a/ext/recover/recovercorrupt4.test b/ext/recover/recovercorrupt4.test
new file mode 100644
index 0000000..0ff0b50
--- /dev/null
+++ b/ext/recover/recovercorrupt4.test
@@ -0,0 +1,64 @@
+# 2024 May 15
+#
+# 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.
+#
+#***********************************************************************
+#
+
+source [file join [file dirname [info script]] recover_common.tcl]
+set testprefix recovercorrupt4
+
+database_may_be_corrupt
+
+if {[permutation]!="inmemory_journal"} {
+ # This test cannot be run with the inmemory_journal permutation, as it
+ # must open a truncated, corrupt, database file. With the inmemory_journal
+ # permutation, this fails (SQLITE_CORRUPT error) when the [sqlite3] wrapper
+ # executes "PRAGMA journal_mode = memory".
+ do_execsql_test 1.0 {
+ CREATE TABLE rows(indexed INTEGER NOT NULL, unindexed INTEGER NOT NULL, filler BLOB NOT NULL DEFAULT 13);
+ -- CREATE UNIQUE INDEX rows_index ON rows(indexed);
+ INSERT INTO rows(indexed, unindexed, filler) VALUES(1, 1, x'31');
+ INSERT INTO rows(indexed, unindexed, filler) VALUES(2, 2, x'32');
+ INSERT INTO rows(indexed, unindexed, filler) VALUES(4, 4, x'34');
+ INSERT INTO rows(indexed, unindexed, filler) VALUES(8, 8, randomblob(2048));
+ }
+
+ db close
+
+ do_test 1.1 {
+ set sz [expr [file size test.db] - 1024]
+ set fd [open test.db]
+ fconfigure $fd -encoding binary -translation binary
+
+ set data [read $fd $sz]
+ set fd2 [open test.db2 w]
+ fconfigure $fd2 -encoding binary -translation binary
+ puts -nonewline $fd2 $data
+ close $fd2
+ set {} {}
+ } {}
+
+ do_test 1.2 {
+ forcedelete test.db3
+ sqlite3 db test.db2
+ set R [sqlite3_recover_init db main test.db3]
+ $R run
+ $R finish
+ } {}
+
+ do_test 1.3 {
+ sqlite3 db test.db3
+ execsql {
+ SELECT indexed, unindexed FROM rows
+ }
+ } {1 1 2 2 4 4 8 8}
+}
+
+finish_test
+