If there is no data available for a field in a corrupted record, but the type is available, have the recovery extension substitute 0, 0.0, '' or X'' instead of a NULL value.
FossilOrigin-Name: 78051359256c7e56a0aad5706bacbad5447b25ebef8088a6194886728d6deab4
(cherry picked from commit b856e0e76cef615da9cd1075f6dde9d0a85a010a)
Fix a problem causing the recovery extension to use excessive memory and CPU time in some cases.
FossilOrigin-Name: bc394acb6e6bcaccd17d8afe559d743799c0cb8d7aec709306181673a35dcb86
(cherry picked from commit 89282ca576e7b2bbfc1e4cd3642f5ddb02fac80a)
Bug: 336833464
Change-Id: Idfb69a8adeb23eb5b6a3f30736cc4f40be3ca1fe
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/deps/sqlite/+/5541666
Reviewed-by: Evan Stade <[email protected]>
Commit-Queue: Nathan Memmott <[email protected]>
diff --git a/amalgamation/shell/shell.c b/amalgamation/shell/shell.c
index 5230da9..078c2f1 100644
--- a/amalgamation/shell/shell.c
+++ b/amalgamation/shell/shell.c
@@ -14347,6 +14347,15 @@
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 {
@@ -14363,7 +14372,7 @@
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 */
@@ -14409,6 +14418,31 @@
")"
/*
+** 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.
*/
@@ -14548,8 +14582,7 @@
pCsr->iField = 0;
pCsr->bOnePage = 0;
sqlite3_free(pCsr->aPage);
- sqlite3_free(pCsr->pRec);
- pCsr->pRec = 0;
+ dbdataBufferFree(&pCsr->rec);
pCsr->aPage = 0;
}
@@ -14692,62 +14725,74 @@
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);
- }
- 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;
+ 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++;
}
- }else{
- sqlite3_result_blob(pCtx, pData, n, SQLITE_TRANSIENT);
+
+ if( eType==7 ){
+ double r;
+ memcpy(&r, &v, sizeof(r));
+ sqlite3_result_double(pCtx, r);
+ }else{
+ sqlite3_result_int64(pCtx, (sqlite3_int64)v);
+ }
+ 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{
+ 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);
}
}
}
@@ -14810,7 +14855,7 @@
}
}else{
/* If there is no record loaded, load it now. */
- if( pCsr->pRec==0 ){
+ if( pCsr->nRec==0 ){
int bHasRowid = 0;
int nPointer = 0;
sqlite3_int64 nPayload = 0;
@@ -14854,6 +14899,7 @@
}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 */
@@ -14888,13 +14934,12 @@
/* 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 */
@@ -14912,19 +14957,22 @@
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);
}
}
@@ -14932,7 +14980,7 @@
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;
@@ -14940,8 +14988,8 @@
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;
}
@@ -14951,20 +14999,18 @@
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++;
}
}
@@ -15154,12 +15200,12 @@
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/amalgamation/sqlite3.c b/amalgamation/sqlite3.c
index e7f7b27..7878abf 100644
--- a/amalgamation/sqlite3.c
+++ b/amalgamation/sqlite3.c
@@ -18,7 +18,7 @@
** separate file. This file contains only code for the core SQLite library.
**
** The content in this amalgamation comes from Fossil check-in
-** c0b03aa071b8b0936237d880e5c46eef604a with changes in files:
+** a58bd3cd7e0eae429f4b0aa288be7cc7783b with changes in files:
**
** manifest.uuid
*/
@@ -463,7 +463,7 @@
*/
#define SQLITE_VERSION "3.45.2"
#define SQLITE_VERSION_NUMBER 3045002
-#define SQLITE_SOURCE_ID "2024-03-12 11:06:23 c0b03aa071b8b0936237d880e5c46eef604af4ef77d91f73984b3253267ab149"
+#define SQLITE_SOURCE_ID "2024-03-12 11:06:23 a58bd3cd7e0eae429f4b0aa288be7cc7783b9798674bc0e4adde311f23a3e3cd"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -258507,6 +258507,15 @@
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 {
@@ -258523,7 +258532,7 @@
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 */
@@ -258569,6 +258578,31 @@
")"
/*
+** 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.
*/
@@ -258708,8 +258742,7 @@
pCsr->iField = 0;
pCsr->bOnePage = 0;
sqlite3_free(pCsr->aPage);
- sqlite3_free(pCsr->pRec);
- pCsr->pRec = 0;
+ dbdataBufferFree(&pCsr->rec);
pCsr->aPage = 0;
}
@@ -258852,62 +258885,74 @@
u8 *pData,
sqlite3_int64 nData
){
- if( eType>=0 && dbdataValueBytes(eType)<=nData ){
- switch( eType ){
- case 0:
- case 10:
- case 11:
- sqlite3_result_null(pCtx);
- break;
+ 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 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;
- }
-
- 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;
+ 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++;
}
- }else{
- sqlite3_result_blob(pCtx, pData, n, SQLITE_TRANSIENT);
+
+ if( eType==7 ){
+ double r;
+ memcpy(&r, &v, sizeof(r));
+ sqlite3_result_double(pCtx, r);
+ }else{
+ sqlite3_result_int64(pCtx, (sqlite3_int64)v);
+ }
+ 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{
+ 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);
}
}
}
@@ -258970,7 +259015,7 @@
}
}else{
/* If there is no record loaded, load it now. */
- if( pCsr->pRec==0 ){
+ if( pCsr->nRec==0 ){
int bHasRowid = 0;
int nPointer = 0;
sqlite3_int64 nPayload = 0;
@@ -259014,6 +259059,7 @@
}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 */
@@ -259048,13 +259094,12 @@
/* 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 */
@@ -259072,19 +259117,22 @@
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);
}
}
@@ -259092,7 +259140,7 @@
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;
@@ -259100,8 +259148,8 @@
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;
}
@@ -259111,20 +259159,18 @@
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++;
}
}
@@ -259314,12 +259360,12 @@
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/amalgamation/sqlite3.h b/amalgamation/sqlite3.h
index afe3715..8ace9da 100644
--- a/amalgamation/sqlite3.h
+++ b/amalgamation/sqlite3.h
@@ -148,7 +148,7 @@
*/
#define SQLITE_VERSION "3.45.2"
#define SQLITE_VERSION_NUMBER 3045002
-#define SQLITE_SOURCE_ID "2024-03-12 11:06:23 c0b03aa071b8b0936237d880e5c46eef604af4ef77d91f73984b3253267ab149"
+#define SQLITE_SOURCE_ID "2024-03-12 11:06:23 a58bd3cd7e0eae429f4b0aa288be7cc7783b9798674bc0e4adde311f23a3e3cd"
/*
** CAPI3REF: Run-Time Library Version Numbers
diff --git a/amalgamation_dev/shell/shell.c b/amalgamation_dev/shell/shell.c
index 5230da9..078c2f1 100644
--- a/amalgamation_dev/shell/shell.c
+++ b/amalgamation_dev/shell/shell.c
@@ -14347,6 +14347,15 @@
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 {
@@ -14363,7 +14372,7 @@
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 */
@@ -14409,6 +14418,31 @@
")"
/*
+** 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.
*/
@@ -14548,8 +14582,7 @@
pCsr->iField = 0;
pCsr->bOnePage = 0;
sqlite3_free(pCsr->aPage);
- sqlite3_free(pCsr->pRec);
- pCsr->pRec = 0;
+ dbdataBufferFree(&pCsr->rec);
pCsr->aPage = 0;
}
@@ -14692,62 +14725,74 @@
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);
- }
- 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;
+ 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++;
}
- }else{
- sqlite3_result_blob(pCtx, pData, n, SQLITE_TRANSIENT);
+
+ if( eType==7 ){
+ double r;
+ memcpy(&r, &v, sizeof(r));
+ sqlite3_result_double(pCtx, r);
+ }else{
+ sqlite3_result_int64(pCtx, (sqlite3_int64)v);
+ }
+ 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{
+ 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);
}
}
}
@@ -14810,7 +14855,7 @@
}
}else{
/* If there is no record loaded, load it now. */
- if( pCsr->pRec==0 ){
+ if( pCsr->nRec==0 ){
int bHasRowid = 0;
int nPointer = 0;
sqlite3_int64 nPayload = 0;
@@ -14854,6 +14899,7 @@
}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 */
@@ -14888,13 +14934,12 @@
/* 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 */
@@ -14912,19 +14957,22 @@
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);
}
}
@@ -14932,7 +14980,7 @@
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;
@@ -14940,8 +14988,8 @@
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;
}
@@ -14951,20 +14999,18 @@
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++;
}
}
@@ -15154,12 +15200,12 @@
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/amalgamation_dev/sqlite3.c b/amalgamation_dev/sqlite3.c
index 1583c4f..b1e0e62 100644
--- a/amalgamation_dev/sqlite3.c
+++ b/amalgamation_dev/sqlite3.c
@@ -18,7 +18,7 @@
** separate file. This file contains only code for the core SQLite library.
**
** The content in this amalgamation comes from Fossil check-in
-** c0b03aa071b8b0936237d880e5c46eef604a with changes in files:
+** a58bd3cd7e0eae429f4b0aa288be7cc7783b with changes in files:
**
** manifest.uuid
*/
@@ -463,7 +463,7 @@
*/
#define SQLITE_VERSION "3.45.2"
#define SQLITE_VERSION_NUMBER 3045002
-#define SQLITE_SOURCE_ID "2024-03-12 11:06:23 c0b03aa071b8b0936237d880e5c46eef604af4ef77d91f73984b3253267ab149"
+#define SQLITE_SOURCE_ID "2024-03-12 11:06:23 a58bd3cd7e0eae429f4b0aa288be7cc7783b9798674bc0e4adde311f23a3e3cd"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -259026,6 +259026,15 @@
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 {
@@ -259042,7 +259051,7 @@
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 */
@@ -259088,6 +259097,31 @@
")"
/*
+** 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.
*/
@@ -259227,8 +259261,7 @@
pCsr->iField = 0;
pCsr->bOnePage = 0;
sqlite3_free(pCsr->aPage);
- sqlite3_free(pCsr->pRec);
- pCsr->pRec = 0;
+ dbdataBufferFree(&pCsr->rec);
pCsr->aPage = 0;
}
@@ -259371,62 +259404,74 @@
u8 *pData,
sqlite3_int64 nData
){
- if( eType>=0 && dbdataValueBytes(eType)<=nData ){
- switch( eType ){
- case 0:
- case 10:
- case 11:
- sqlite3_result_null(pCtx);
- break;
+ 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 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;
- }
-
- 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;
+ 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++;
}
- }else{
- sqlite3_result_blob(pCtx, pData, n, SQLITE_TRANSIENT);
+
+ if( eType==7 ){
+ double r;
+ memcpy(&r, &v, sizeof(r));
+ sqlite3_result_double(pCtx, r);
+ }else{
+ sqlite3_result_int64(pCtx, (sqlite3_int64)v);
+ }
+ 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{
+ 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);
}
}
}
@@ -259489,7 +259534,7 @@
}
}else{
/* If there is no record loaded, load it now. */
- if( pCsr->pRec==0 ){
+ if( pCsr->nRec==0 ){
int bHasRowid = 0;
int nPointer = 0;
sqlite3_int64 nPayload = 0;
@@ -259533,6 +259578,7 @@
}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 */
@@ -259567,13 +259613,12 @@
/* 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 */
@@ -259591,19 +259636,22 @@
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);
}
}
@@ -259611,7 +259659,7 @@
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;
@@ -259619,8 +259667,8 @@
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;
}
@@ -259630,20 +259678,18 @@
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++;
}
}
@@ -259833,12 +259879,12 @@
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/amalgamation_dev/sqlite3.h b/amalgamation_dev/sqlite3.h
index afe3715..8ace9da 100644
--- a/amalgamation_dev/sqlite3.h
+++ b/amalgamation_dev/sqlite3.h
@@ -148,7 +148,7 @@
*/
#define SQLITE_VERSION "3.45.2"
#define SQLITE_VERSION_NUMBER 3045002
-#define SQLITE_SOURCE_ID "2024-03-12 11:06:23 c0b03aa071b8b0936237d880e5c46eef604af4ef77d91f73984b3253267ab149"
+#define SQLITE_SOURCE_ID "2024-03-12 11:06:23 a58bd3cd7e0eae429f4b0aa288be7cc7783b9798674bc0e4adde311f23a3e3cd"
/*
** CAPI3REF: Run-Time Library Version Numbers
diff --git a/ext/recover/dbdata.c b/ext/recover/dbdata.c
index ca63710..a999f1a 100644
--- a/ext/recover/dbdata.c
+++ b/ext/recover/dbdata.c
@@ -88,6 +88,15 @@
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 @@
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 @@
")"
/*
+** 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,8 +323,7 @@
pCsr->iField = 0;
pCsr->bOnePage = 0;
sqlite3_free(pCsr->aPage);
- sqlite3_free(pCsr->pRec);
- pCsr->pRec = 0;
+ dbdataBufferFree(&pCsr->rec);
pCsr->aPage = 0;
}
@@ -433,62 +466,74 @@
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);
- }
- 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;
+ 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++;
}
- }else{
- sqlite3_result_blob(pCtx, pData, n, SQLITE_TRANSIENT);
+
+ if( eType==7 ){
+ double r;
+ memcpy(&r, &v, sizeof(r));
+ sqlite3_result_double(pCtx, r);
+ }else{
+ sqlite3_result_int64(pCtx, (sqlite3_int64)v);
+ }
+ 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{
+ 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 +596,7 @@
}
}else{
/* If there is no record loaded, load it now. */
- if( pCsr->pRec==0 ){
+ if( pCsr->nRec==0 ){
int bHasRowid = 0;
int nPointer = 0;
sqlite3_int64 nPayload = 0;
@@ -595,6 +640,7 @@
}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 +675,12 @@
/* 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 +698,22 @@
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 +721,7 @@
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 +729,8 @@
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 +740,18 @@
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 +941,12 @@
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 @@
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 @@
}
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 @@
} {{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 [email protected]....
+| 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 [email protected]....
+| 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..53d691f
--- /dev/null
+++ b/ext/recover/recovercorrupt4.test
@@ -0,0 +1,58 @@
+# 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
+
+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
+
diff --git a/manifest b/manifest
index 00e29d8..8bf017a 100644
--- a/manifest
+++ b/manifest
@@ -467,8 +467,8 @@
F ext/rbu/sqlite3rbu.c d4ddf8f0e93772556e452a6c2814063cf47efb760a0834391a9d0cd9859fa4b9
F ext/rbu/sqlite3rbu.h 9d923eb135c5d04aa6afd7c39ca47b0d1d0707c100e02f19fdde6a494e414304
F ext/rbu/test_rbu.c ee6ede75147bc081fe9bc3931e6b206277418d14d3fbceea6fdc6216d9b47055
-F ext/recover/dbdata.c d2e00d3cac74319c9c6def2e56ab2146b4f4ba5d820ab275e8da24e9766c247e
-F ext/recover/recover1.test c484d01502239f11b61f23c1cee9f5dd19fa17617f8974e42e74d64639c524cf
+F ext/recover/dbdata.c 0a943861ec096de375097e0aaff07b480a002eab9b01fecd3f9e828faf4ef624
+F ext/recover/recover1.test e16d78e94183562abff569967b18b7c77451d7044365516cd0fe14713a284851
F ext/recover/recover_common.tcl a61306c1eb45c0c3fc45652c35b2d4ec19729e340bdf65a272ce4c229cefd85a
F ext/recover/recoverbuild.test c74170e0f7b02456af41838afeb5353fdb985a48cc2331d661bbabbca7c6b8e3
F ext/recover/recoverclobber.test 3ba6c0c373c5c63d17e82eced64c05c57ccaf26c1abe1ca7141334022a79f32e