1From 29cc811975af684969da4f057b6107fff4d6487f Mon Sep 17 00:00:00 2001 2From: MartinChoo <214582617@qq.com> 3Date: Wed, 23 Jul 2025 17:41:39 +0800 4Subject: [PATCH 05/12] Enhance dfx ability, report corruption and check pages 5 6--- 7 ext/misc/cksumvfs.c | 916 ++++++++++++++++++++++++++++++++++++++++++++ 8 src/sqlite3.c | 818 ++++++++++++++++++++++++++++++++++----- 9 2 files changed, 1634 insertions(+), 100 deletions(-) 10 create mode 100644 ext/misc/cksumvfs.c 11 12diff --git a/ext/misc/cksumvfs.c b/ext/misc/cksumvfs.c 13new file mode 100644 14index 0000000..6f4c55c 15--- /dev/null 16+++ b/ext/misc/cksumvfs.c 17@@ -0,0 +1,916 @@ 18+/* 19+** 2020-04-20 20+** 21+** The author disclaims copyright to this source code. In place of 22+** a legal notice, here is a blessing: 23+** 24+** May you do good and not evil. 25+** May you find forgiveness for yourself and forgive others. 26+** May you share freely, never taking more than you give. 27+** 28+****************************************************************************** 29+** 30+** This file implements a VFS shim that writes a checksum on each page 31+** of an SQLite database file. When reading pages, the checksum is verified 32+** and an error is raised if the checksum is incorrect. 33+** 34+** COMPILING 35+** 36+** This extension requires SQLite 3.32.0 or later. It uses the 37+** sqlite3_database_file_object() interface which was added in 38+** version 3.32.0, so it will not link with an earlier version of 39+** SQLite. 40+** 41+** To build this extension as a separately loaded shared library or 42+** DLL, use compiler command-lines similar to the following: 43+** 44+** (linux) gcc -fPIC -shared cksumvfs.c -o cksumvfs.so 45+** (mac) clang -fPIC -dynamiclib cksumvfs.c -o cksumvfs.dylib 46+** (windows) cl cksumvfs.c -link -dll -out:cksumvfs.dll 47+** 48+** You may want to add additional compiler options, of course, 49+** according to the needs of your project. 50+** 51+** If you want to statically link this extension with your product, 52+** then compile it like any other C-language module but add the 53+** "-DSQLITE_CKSUMVFS_STATIC" option so that this module knows that 54+** it is being statically linked rather than dynamically linked 55+** 56+** LOADING 57+** 58+** To load this extension as a shared library, you first have to 59+** bring up a dummy SQLite database connection to use as the argument 60+** to the sqlite3_load_extension() API call. Then you invoke the 61+** sqlite3_load_extension() API and shutdown the dummy database 62+** connection. All subsequent database connections that are opened 63+** will include this extension. For example: 64+** 65+** sqlite3 *db; 66+** sqlite3_open(":memory:", &db); 67+** sqlite3_load_extension(db, "./cksumvfs"); 68+** sqlite3_close(db); 69+** 70+** If this extension is compiled with -DSQLITE_CKSUMVFS_STATIC and 71+** statically linked against the application, initialize it using 72+** a single API call as follows: 73+** 74+** sqlite3_register_cksumvfs(); 75+** 76+** Cksumvfs is a VFS Shim. When loaded, "cksmvfs" becomes the new 77+** default VFS and it uses the prior default VFS as the next VFS 78+** down in the stack. This is normally what you want. However, in 79+** complex situations where multiple VFS shims are being loaded, 80+** it might be important to ensure that cksumvfs is loaded in the 81+** correct order so that it sequences itself into the default VFS 82+** Shim stack in the right order. 83+** 84+** USING 85+** 86+** Open database connections using the sqlite3_open() or 87+** sqlite3_open_v2() interfaces, as normal. Ordinary database files 88+** (without a checksum) will operate normally. Databases with 89+** checksums will return an SQLITE_IOERR_DATA error if a page is 90+** encountered that contains an invalid checksum. 91+** 92+** Checksumming only works on databases that have a reserve-bytes 93+** value of exactly 8. The default value for reserve-bytes is 0. 94+** Hence, newly created database files will omit the checksum by 95+** default. To create a database that includes a checksum, change 96+** the reserve-bytes value to 8 by runing: 97+** 98+** int n = 8; 99+** sqlite3_file_control(db, 0, SQLITE_FCNTL_RESERVE_BYTES, &n); 100+** 101+** If you do this immediately after creating a new database file, 102+** before anything else has been written into the file, then that 103+** might be all that you need to do. Otherwise, the API call 104+** above should be followed by: 105+** 106+** sqlite3_exec(db, "VACUUM", 0, 0, 0); 107+** 108+** It never hurts to run the VACUUM, even if you don't need it. 109+** If the database is in WAL mode, you should shutdown and 110+** reopen all database connections before continuing. 111+** 112+** From the CLI, use the ".filectrl reserve_bytes 8" command, 113+** followed by "VACUUM;". 114+** 115+** Note that SQLite allows the number of reserve-bytes to be 116+** increased but not decreased. So if a database file already 117+** has a reserve-bytes value greater than 8, there is no way to 118+** activate checksumming on that database, other than to dump 119+** and restore the database file. Note also that other extensions 120+** might also make use of the reserve-bytes. Checksumming will 121+** be incompatible with those other extensions. 122+** 123+** VERIFICATION OF CHECKSUMS 124+** 125+** If any checksum is incorrect, the "PRAGMA quick_check" command 126+** will find it. To verify that checksums are actually enabled 127+** and running, use the following query: 128+** 129+** SELECT count(*), verify_checksum(data) 130+** FROM sqlite_dbpage 131+** GROUP BY 2; 132+** 133+** There are three possible outputs form the verify_checksum() 134+** function: 1, 0, and NULL. 1 is returned if the checksum is 135+** correct. 0 is returned if the checksum is incorrect. NULL 136+** is returned if the page is unreadable. If checksumming is 137+** enabled, the read will fail if the checksum is wrong, so the 138+** usual result from verify_checksum() on a bad checksum is NULL. 139+** 140+** If everything is OK, the query above should return a single 141+** row where the second column is 1. Any other result indicates 142+** either that there is a checksum error, or checksum validation 143+** is disabled. 144+** 145+** CONTROLLING CHECKSUM VERIFICATION 146+** 147+** The cksumvfs extension implements a new PRAGMA statement that can 148+** be used to disable, re-enable, or query the status of checksum 149+** verification: 150+** 151+** PRAGMA checksum_verification; -- query status 152+** PRAGMA checksum_verification=OFF; -- disable verification 153+** PRAGMA checksum_verification=ON; -- re-enable verification 154+** 155+** The "checksum_verification" pragma will return "1" (true) or "0" 156+** (false) if checksum verification is enabled or disabled, respectively. 157+** "Verification" in this context means the feature that causes 158+** SQLITE_IOERR_DATA errors if a checksum mismatch is detected while 159+** reading. Checksums are always kept up-to-date as long as the 160+** reserve-bytes value of the database is 8, regardless of the setting 161+** of this pragma. Checksum verification can be disabled (for example) 162+** to do forensic analysis of a database that has previously reported 163+** a checksum error. 164+** 165+** The "checksum_verification" pragma will always respond with "0" if 166+** the database file does not have a reserve-bytes value of 8. The 167+** pragma will return no rows at all if the cksumvfs extension is 168+** not loaded. 169+** 170+** IMPLEMENTATION NOTES 171+** 172+** The checksum is stored in the last 8 bytes of each page. This 173+** module only operates if the "bytes of reserved space on each page" 174+** value at offset 20 the SQLite database header is exactly 8. If 175+** the reserved-space value is not 8, this module is a no-op. 176+*/ 177+#if defined(SQLITE_AMALGAMATION) && !defined(SQLITE_CKSUMVFS_STATIC) 178+# define SQLITE_CKSUMVFS_STATIC 179+#endif 180+#ifdef SQLITE_CKSUMVFS_STATIC 181+# include "sqlite3.h" 182+#else 183+# include "sqlite3ext.h" 184+ SQLITE_EXTENSION_INIT1 185+#endif 186+#include <string.h> 187+#include <assert.h> 188+ 189+// export the symbols 190+#ifdef SQLITE_EXPORT_SYMBOLS 191+#if defined(__GNUC__) 192+# define EXPORT_SYMBOLS __attribute__ ((visibility ("default"))) 193+#elif defined(_MSC_VER) 194+# define EXPORT_SYMBOLS __declspec(dllexport) 195+#else 196+# define EXPORT_SYMBOLS 197+#endif 198+#endif 199+ 200+/* 201+** Forward declaration of objects used by this utility 202+*/ 203+typedef struct sqlite3_vfs CksmVfs; 204+typedef struct CksmFile CksmFile; 205+ 206+/* 207+** Useful datatype abbreviations 208+*/ 209+#if !defined(SQLITE_AMALGAMATION) 210+ typedef unsigned char u8; 211+ typedef unsigned int u32; 212+#endif 213+ 214+/* Access to a lower-level VFS that (might) implement dynamic loading, 215+** access to randomness, etc. 216+*/ 217+#define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData)) 218+#define ORIGFILE(p) ((sqlite3_file*)(((CksmFile*)(p))+1)) 219+ 220+/* An open file */ 221+struct CksmFile { 222+ sqlite3_file base; /* IO methods */ 223+ const char *zFName; /* Original name of the file */ 224+ char computeCksm; /* True to compute checksums. 225+ ** Always true if reserve size is 8. */ 226+ char verifyCksm; /* True to verify checksums */ 227+ char isWal; /* True if processing a WAL file */ 228+ char inCkpt; /* Currently doing a checkpoint */ 229+ CksmFile *pPartner; /* Ptr from WAL to main-db, or from main-db to WAL */ 230+}; 231+ 232+/* 233+** Methods for CksmFile 234+*/ 235+static int cksmClose(sqlite3_file*); 236+static int cksmRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); 237+static int cksmWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst); 238+static int cksmTruncate(sqlite3_file*, sqlite3_int64 size); 239+static int cksmSync(sqlite3_file*, int flags); 240+static int cksmFileSize(sqlite3_file*, sqlite3_int64 *pSize); 241+static int cksmLock(sqlite3_file*, int); 242+static int cksmUnlock(sqlite3_file*, int); 243+static int cksmCheckReservedLock(sqlite3_file*, int *pResOut); 244+static int cksmFileControl(sqlite3_file*, int op, void *pArg); 245+static int cksmSectorSize(sqlite3_file*); 246+static int cksmDeviceCharacteristics(sqlite3_file*); 247+static int cksmShmMap(sqlite3_file*, int iPg, int pgsz, int, void volatile**); 248+static int cksmShmLock(sqlite3_file*, int offset, int n, int flags); 249+static void cksmShmBarrier(sqlite3_file*); 250+static int cksmShmUnmap(sqlite3_file*, int deleteFlag); 251+static int cksmFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp); 252+static int cksmUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void *p); 253+ 254+/* 255+** Methods for CksmVfs 256+*/ 257+static int cksmOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *); 258+static int cksmDelete(sqlite3_vfs*, const char *zName, int syncDir); 259+static int cksmAccess(sqlite3_vfs*, const char *zName, int flags, int *); 260+static int cksmFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut); 261+static void *cksmDlOpen(sqlite3_vfs*, const char *zFilename); 262+static void cksmDlError(sqlite3_vfs*, int nByte, char *zErrMsg); 263+static void (*cksmDlSym(sqlite3_vfs *pVfs, void *p, const char*zSym))(void); 264+static void cksmDlClose(sqlite3_vfs*, void*); 265+static int cksmRandomness(sqlite3_vfs*, int nByte, char *zOut); 266+static int cksmSleep(sqlite3_vfs*, int microseconds); 267+static int cksmCurrentTime(sqlite3_vfs*, double*); 268+static int cksmGetLastError(sqlite3_vfs*, int, char *); 269+static int cksmCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*); 270+static int cksmSetSystemCall(sqlite3_vfs*, const char*,sqlite3_syscall_ptr); 271+static sqlite3_syscall_ptr cksmGetSystemCall(sqlite3_vfs*, const char *z); 272+static const char *cksmNextSystemCall(sqlite3_vfs*, const char *zName); 273+ 274+static sqlite3_vfs cksm_vfs = { 275+ 3, /* iVersion (set when registered) */ 276+ 0, /* szOsFile (set when registered) */ 277+ 1024, /* mxPathname */ 278+ 0, /* pNext */ 279+ "cksmvfs", /* zName */ 280+ 0, /* pAppData (set when registered) */ 281+ cksmOpen, /* xOpen */ 282+ cksmDelete, /* xDelete */ 283+ cksmAccess, /* xAccess */ 284+ cksmFullPathname, /* xFullPathname */ 285+ cksmDlOpen, /* xDlOpen */ 286+ cksmDlError, /* xDlError */ 287+ cksmDlSym, /* xDlSym */ 288+ cksmDlClose, /* xDlClose */ 289+ cksmRandomness, /* xRandomness */ 290+ cksmSleep, /* xSleep */ 291+ cksmCurrentTime, /* xCurrentTime */ 292+ cksmGetLastError, /* xGetLastError */ 293+ cksmCurrentTimeInt64, /* xCurrentTimeInt64 */ 294+ cksmSetSystemCall, /* xSetSystemCall */ 295+ cksmGetSystemCall, /* xGetSystemCall */ 296+ cksmNextSystemCall /* xNextSystemCall */ 297+}; 298+ 299+static const sqlite3_io_methods cksm_io_methods = { 300+ 3, /* iVersion */ 301+ cksmClose, /* xClose */ 302+ cksmRead, /* xRead */ 303+ cksmWrite, /* xWrite */ 304+ cksmTruncate, /* xTruncate */ 305+ cksmSync, /* xSync */ 306+ cksmFileSize, /* xFileSize */ 307+ cksmLock, /* xLock */ 308+ cksmUnlock, /* xUnlock */ 309+ cksmCheckReservedLock, /* xCheckReservedLock */ 310+ cksmFileControl, /* xFileControl */ 311+ cksmSectorSize, /* xSectorSize */ 312+ cksmDeviceCharacteristics, /* xDeviceCharacteristics */ 313+ cksmShmMap, /* xShmMap */ 314+ cksmShmLock, /* xShmLock */ 315+ cksmShmBarrier, /* xShmBarrier */ 316+ cksmShmUnmap, /* xShmUnmap */ 317+ cksmFetch, /* xFetch */ 318+ cksmUnfetch /* xUnfetch */ 319+}; 320+ 321+/* Do byte swapping on a unsigned 32-bit integer */ 322+#define BYTESWAP32(x) ( \ 323+ (((x)&0x000000FF)<<24) + (((x)&0x0000FF00)<<8) \ 324+ + (((x)&0x00FF0000)>>8) + (((x)&0xFF000000)>>24) \ 325+) 326+ 327+/* Compute a checksum on a buffer */ 328+static void cksmCompute( 329+ u8 *a, /* Content to be checksummed */ 330+ int nByte, /* Bytes of content in a[]. Must be a multiple of 8. */ 331+ u8 *aOut /* OUT: Final 8-byte checksum value output */ 332+){ 333+ u32 s1 = 0, s2 = 0; 334+ u32 *aData = (u32*)a; 335+ u32 *aEnd = (u32*)&a[nByte]; 336+ u32 x = 1; 337+ 338+ assert( nByte>=8 ); 339+ assert( (nByte&0x00000007)==0 ); 340+ assert( nByte<=65536 ); 341+ 342+ if( 1 == *(u8*)&x ){ 343+ /* Little-endian */ 344+ do { 345+ s1 += *aData++ + s2; 346+ s2 += *aData++ + s1; 347+ }while( aData<aEnd ); 348+ }else{ 349+ /* Big-endian */ 350+ do { 351+ s1 += BYTESWAP32(aData[0]) + s2; 352+ s2 += BYTESWAP32(aData[1]) + s1; 353+ aData += 2; 354+ }while( aData<aEnd ); 355+ s1 = BYTESWAP32(s1); 356+ s2 = BYTESWAP32(s2); 357+ } 358+ memcpy(aOut, &s1, 4); 359+ memcpy(aOut+4, &s2, 4); 360+} 361+ 362+/* 363+** SQL function: verify_checksum(BLOB) 364+** 365+** Return 0 or 1 if the checksum is invalid or valid. Or return 366+** NULL if the input is not a BLOB that is the right size for a 367+** database page. 368+*/ 369+static void cksmVerifyFunc( 370+ sqlite3_context *context, 371+ int argc, 372+ sqlite3_value **argv 373+){ 374+ int nByte; 375+ u8 *data; 376+ u8 cksum[8]; 377+ data = (u8*)sqlite3_value_blob(argv[0]); 378+ if( data==0 ) return; 379+ if( sqlite3_value_type(argv[0])!=SQLITE_BLOB ) return; 380+ nByte = sqlite3_value_bytes(argv[0]); 381+ if( nByte<512 || nByte>65536 || (nByte & (nByte-1))!=0 ) return; 382+ cksmCompute(data, nByte-8, cksum); 383+ sqlite3_result_int(context, memcmp(data+nByte-8,cksum,8)==0); 384+} 385+ 386+#ifdef SQLITE_CKSUMVFS_INIT_FUNCNAME 387+/* 388+** SQL function: initialize_cksumvfs(SCHEMANAME) 389+** 390+** This SQL functions (whose name is actually determined at compile-time 391+** by the value of the SQLITE_CKSUMVFS_INIT_FUNCNAME macro) invokes: 392+** 393+** sqlite3_file_control(db, SCHEMANAME, SQLITE_FCNTL_RESERVE_BYTE, &n); 394+** 395+** In order to set the reserve bytes value to 8, so that cksumvfs will 396+** operation. This feature is provided (if and only if the 397+** SQLITE_CKSUMVFS_INIT_FUNCNAME compile-time option is set to a string 398+** which is the name of the SQL function) so as to provide the ability 399+** to invoke the file-control in programming languages that lack 400+** direct access to the sqlite3_file_control() interface (ex: Java). 401+** 402+** This interface is undocumented, apart from this comment. Usage 403+** example: 404+** 405+** 1. Compile with -DSQLITE_CKSUMVFS_INIT_FUNCNAME="ckvfs_init" 406+** 2. Run: "SELECT cksum_init('main'); VACUUM;" 407+*/ 408+static void cksmInitFunc( 409+ sqlite3_context *context, 410+ int argc, 411+ sqlite3_value **argv 412+){ 413+ int nByte = 8; 414+ const char *zSchemaName = (const char*)sqlite3_value_text(argv[0]); 415+ sqlite3 *db = sqlite3_context_db_handle(context); 416+ sqlite3_file_control(db, zSchemaName, SQLITE_FCNTL_RESERVE_BYTES, &nByte); 417+ /* Return NULL */ 418+} 419+#endif /* SQLITE_CKSUMBFS_INIT_FUNCNAME */ 420+ 421+/* 422+** Close a cksm-file. 423+*/ 424+static int cksmClose(sqlite3_file *pFile){ 425+ CksmFile *p = (CksmFile *)pFile; 426+ if( p->pPartner ){ 427+ assert( p->pPartner->pPartner==p ); 428+ p->pPartner->pPartner = 0; 429+ p->pPartner = 0; 430+ } 431+ pFile = ORIGFILE(pFile); 432+ return pFile->pMethods->xClose(pFile); 433+} 434+ 435+/* 436+** Set the computeCkSm and verifyCksm flags, if they need to be 437+** changed. 438+*/ 439+static void cksmSetFlags(CksmFile *p, int hasCorrectReserveSize){ 440+ if( hasCorrectReserveSize!=p->computeCksm ){ 441+ p->computeCksm = p->verifyCksm = hasCorrectReserveSize; 442+ if( p->pPartner ){ 443+ p->pPartner->verifyCksm = hasCorrectReserveSize; 444+ p->pPartner->computeCksm = hasCorrectReserveSize; 445+ } 446+ } 447+} 448+ 449+static void EncodeReservedBytesIntoBase16(const u8 *reserved, int len, char *encodeStr, int maxLen){ 450+ static const char baseCode[] = "0123456789ABCDEF"; 451+ for(int i=0; i<len && (2*i<maxLen-1); i++){ 452+ *encodeStr++ = baseCode[(reserved[i] >> 4) & 0x0F]; 453+ *encodeStr++ = baseCode[reserved[i] & 0x0F]; 454+ } 455+ *encodeStr = '0'; 456+} 457+ 458+/* 459+** Read data from a cksm-file. 460+*/ 461+static int cksmRead( 462+ sqlite3_file *pFile, 463+ void *zBuf, 464+ int iAmt, 465+ sqlite_int64 iOfst 466+){ 467+ int rc; 468+ CksmFile *p = (CksmFile *)pFile; 469+ pFile = ORIGFILE(pFile); 470+ rc = pFile->pMethods->xRead(pFile, zBuf, iAmt, iOfst); 471+ if( rc==SQLITE_OK ){ 472+ if( iOfst==0 && iAmt>=100 && ( 473+ memcmp(zBuf,"SQLite format 3",16)==0 || memcmp(zBuf,"ZV-",3)==0 474+ )){ 475+ u8 *d = (u8*)zBuf; 476+ char hasCorrectReserveSize = (d[20]==8); 477+ cksmSetFlags(p, hasCorrectReserveSize); 478+ } 479+ /* Verify the checksum if 480+ ** (1) the size indicates that we are dealing with a complete 481+ ** database page, only support pageSize:4K 482+ ** (2) checksum verification is enabled 483+ ** (3) we are not in the middle of checkpoint 484+ */ 485+ if( iAmt==4096 /* (1) */ 486+ && p->verifyCksm /* (2) */ 487+ && !p->inCkpt /* (3) */ 488+ ){ 489+ u8 cksum[8]; 490+ cksmCompute((u8*)zBuf, iAmt-8, cksum); 491+ if( memcmp((u8*)zBuf+iAmt-8, cksum, 8)!=0 ){ 492+ char expect[18] = {0}; 493+ char actual[18] = {0}; 494+ EncodeReservedBytesIntoBase16((u8 *)zBuf+iAmt-8, 8, expect, 18); 495+ EncodeReservedBytesIntoBase16(cksum, 8, actual, 18); 496+ sqlite3_log(SQLITE_IOERR_DATA, "checksum fault offset %lld of \"%s\", amt:%d, expect:%s, actual:%s", 497+ iOfst, p->zFName, iAmt, expect, actual); 498+ rc = SQLITE_IOERR_DATA; 499+ } 500+ } 501+ } 502+ return rc; 503+} 504+ 505+/* 506+** Write data to a cksm-file. 507+*/ 508+static int cksmWrite( 509+ sqlite3_file *pFile, 510+ const void *zBuf, 511+ int iAmt, 512+ sqlite_int64 iOfst 513+){ 514+ CksmFile *p = (CksmFile *)pFile; 515+ pFile = ORIGFILE(pFile); 516+ if( iOfst==0 && iAmt>=100 && ( 517+ memcmp(zBuf,"SQLite format 3",16)==0 || memcmp(zBuf,"ZV-",3)==0 518+ )){ 519+ u8 *d = (u8*)zBuf; 520+ char hasCorrectReserveSize = (d[20]==8); 521+ cksmSetFlags(p, hasCorrectReserveSize); 522+ } 523+ /* If the write size is appropriate for a database page and if 524+ ** checksums where ever enabled, then it will be safe to compute 525+ ** the checksums. The reserve byte size might have increased, but 526+ ** it will never decrease. And because it cannot decrease, the 527+ ** checksum will not overwrite anything. 528+ */ 529+ if( iAmt==4096 530+ && p->computeCksm 531+ && !p->inCkpt 532+ ){ 533+ cksmCompute((u8*)zBuf, iAmt-8, ((u8*)zBuf)+iAmt-8); 534+ } 535+ return pFile->pMethods->xWrite(pFile, zBuf, iAmt, iOfst); 536+} 537+ 538+/* 539+** Truncate a cksm-file. 540+*/ 541+static int cksmTruncate(sqlite3_file *pFile, sqlite_int64 size){ 542+ pFile = ORIGFILE(pFile); 543+ return pFile->pMethods->xTruncate(pFile, size); 544+} 545+ 546+/* 547+** Sync a cksm-file. 548+*/ 549+static int cksmSync(sqlite3_file *pFile, int flags){ 550+ pFile = ORIGFILE(pFile); 551+ return pFile->pMethods->xSync(pFile, flags); 552+} 553+ 554+/* 555+** Return the current file-size of a cksm-file. 556+*/ 557+static int cksmFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){ 558+ CksmFile *p = (CksmFile *)pFile; 559+ pFile = ORIGFILE(p); 560+ return pFile->pMethods->xFileSize(pFile, pSize); 561+} 562+ 563+/* 564+** Lock a cksm-file. 565+*/ 566+static int cksmLock(sqlite3_file *pFile, int eLock){ 567+ pFile = ORIGFILE(pFile); 568+ return pFile->pMethods->xLock(pFile, eLock); 569+} 570+ 571+/* 572+** Unlock a cksm-file. 573+*/ 574+static int cksmUnlock(sqlite3_file *pFile, int eLock){ 575+ pFile = ORIGFILE(pFile); 576+ return pFile->pMethods->xUnlock(pFile, eLock); 577+} 578+ 579+/* 580+** Check if another file-handle holds a RESERVED lock on a cksm-file. 581+*/ 582+static int cksmCheckReservedLock(sqlite3_file *pFile, int *pResOut){ 583+ pFile = ORIGFILE(pFile); 584+ return pFile->pMethods->xCheckReservedLock(pFile, pResOut); 585+} 586+ 587+/* 588+** File control method. For custom operations on a cksm-file. 589+*/ 590+static int cksmFileControl(sqlite3_file *pFile, int op, void *pArg){ 591+ int rc; 592+ CksmFile *p = (CksmFile*)pFile; 593+ pFile = ORIGFILE(pFile); 594+ if( op==SQLITE_FCNTL_PRAGMA ){ 595+ char **azArg = (char**)pArg; 596+ assert( azArg[1]!=0 ); 597+ if( sqlite3_stricmp(azArg[1],"checksum_verification")==0 ){ 598+ char *zArg = azArg[2]; 599+ if( zArg!=0 ){ 600+ if( (zArg[0]>='1' && zArg[0]<='9') 601+ || sqlite3_strlike("enable%",zArg,0)==0 602+ || sqlite3_stricmp("yes",zArg)==0 603+ || sqlite3_stricmp("on",zArg)==0 604+ ){ 605+ p->verifyCksm = p->computeCksm; 606+ }else{ 607+ p->verifyCksm = 0; 608+ } 609+ if( p->pPartner ) p->pPartner->verifyCksm = p->verifyCksm; 610+ } 611+ azArg[0] = sqlite3_mprintf("%d",p->verifyCksm); 612+ return SQLITE_OK; 613+ }else if( p->computeCksm && azArg[2]!=0 614+ && sqlite3_stricmp(azArg[1], "page_size")==0 ){ 615+ /* Do not allow page size changes on a checksum database */ 616+ return SQLITE_OK; 617+ } 618+ }else if( op==SQLITE_FCNTL_CKPT_START || op==SQLITE_FCNTL_CKPT_DONE ){ 619+ p->inCkpt = op==SQLITE_FCNTL_CKPT_START; 620+ if( p->pPartner ) p->pPartner->inCkpt = p->inCkpt; 621+ }else if( op==SQLITE_FCNTL_CKSM_FILE ){ 622+ /* This VFS needs to obtain a pointer to the corresponding database 623+ ** file handle from within xOpen() calls to open wal files. To do this, 624+ ** it uses the sqlite3_database_file_object() API to obtain a pointer 625+ ** to the file-handle used by SQLite to access the db file. This is 626+ ** fine if cksmvfs happens to be the top-level VFS, but not if there 627+ ** are one or more wrapper VFS. To handle this case, this file-control 628+ ** is used to extract the cksmvfs file-handle from any wrapper file 629+ ** handle. */ 630+ sqlite3_file **ppFile = (sqlite3_file**)pArg; 631+ *ppFile = (sqlite3_file*)p; 632+ return SQLITE_OK; 633+ } 634+ rc = pFile->pMethods->xFileControl(pFile, op, pArg); 635+ if( rc==SQLITE_OK && op==SQLITE_FCNTL_VFSNAME ){ 636+ *(char**)pArg = sqlite3_mprintf("cksm/%z", *(char**)pArg); 637+ } 638+ return rc; 639+} 640+ 641+/* 642+** Return the sector-size in bytes for a cksm-file. 643+*/ 644+static int cksmSectorSize(sqlite3_file *pFile){ 645+ pFile = ORIGFILE(pFile); 646+ return pFile->pMethods->xSectorSize(pFile); 647+} 648+ 649+/* 650+** Return the device characteristic flags supported by a cksm-file. 651+*/ 652+static int cksmDeviceCharacteristics(sqlite3_file *pFile){ 653+ pFile = ORIGFILE(pFile); 654+ return pFile->pMethods->xDeviceCharacteristics(pFile); 655+} 656+ 657+/* Create a shared memory file mapping */ 658+static int cksmShmMap( 659+ sqlite3_file *pFile, 660+ int iPg, 661+ int pgsz, 662+ int bExtend, 663+ void volatile **pp 664+){ 665+ pFile = ORIGFILE(pFile); 666+ return pFile->pMethods->xShmMap(pFile,iPg,pgsz,bExtend,pp); 667+} 668+ 669+/* Perform locking on a shared-memory segment */ 670+static int cksmShmLock(sqlite3_file *pFile, int offset, int n, int flags){ 671+ pFile = ORIGFILE(pFile); 672+ return pFile->pMethods->xShmLock(pFile,offset,n,flags); 673+} 674+ 675+/* Memory barrier operation on shared memory */ 676+static void cksmShmBarrier(sqlite3_file *pFile){ 677+ pFile = ORIGFILE(pFile); 678+ pFile->pMethods->xShmBarrier(pFile); 679+} 680+ 681+/* Unmap a shared memory segment */ 682+static int cksmShmUnmap(sqlite3_file *pFile, int deleteFlag){ 683+ pFile = ORIGFILE(pFile); 684+ return pFile->pMethods->xShmUnmap(pFile,deleteFlag); 685+} 686+ 687+/* Fetch a page of a memory-mapped file */ 688+static int cksmFetch( 689+ sqlite3_file *pFile, 690+ sqlite3_int64 iOfst, 691+ int iAmt, 692+ void **pp 693+){ 694+ CksmFile *p = (CksmFile *)pFile; 695+ if( p->computeCksm ){ 696+ *pp = 0; 697+ return SQLITE_OK; 698+ } 699+ pFile = ORIGFILE(pFile); 700+ if( pFile->pMethods->iVersion>2 && pFile->pMethods->xFetch ){ 701+ return pFile->pMethods->xFetch(pFile, iOfst, iAmt, pp); 702+ } 703+ *pp = 0; 704+ return SQLITE_OK; 705+} 706+ 707+/* Release a memory-mapped page */ 708+static int cksmUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *pPage){ 709+ pFile = ORIGFILE(pFile); 710+ if( pFile->pMethods->iVersion>2 && pFile->pMethods->xUnfetch ){ 711+ return pFile->pMethods->xUnfetch(pFile, iOfst, pPage); 712+ } 713+ return SQLITE_OK; 714+} 715+ 716+/* 717+** Open a cksm file handle. 718+*/ 719+static int cksmOpen( 720+ sqlite3_vfs *pVfs, 721+ const char *zName, 722+ sqlite3_file *pFile, 723+ int flags, 724+ int *pOutFlags 725+){ 726+ CksmFile *p; 727+ sqlite3_file *pSubFile; 728+ sqlite3_vfs *pSubVfs; 729+ int rc; 730+ pSubVfs = ORIGVFS(pVfs); 731+ if( (flags & (SQLITE_OPEN_MAIN_DB|SQLITE_OPEN_WAL))==0 ){ 732+ return pSubVfs->xOpen(pSubVfs, zName, pFile, flags, pOutFlags); 733+ } 734+ p = (CksmFile*)pFile; 735+ memset(p, 0, sizeof(*p)); 736+ pSubFile = ORIGFILE(pFile); 737+ pFile->pMethods = &cksm_io_methods; 738+ rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags); 739+ if( rc ) goto cksm_open_done; 740+ if( flags & SQLITE_OPEN_WAL ){ 741+ sqlite3_file *pDb = sqlite3_database_file_object(zName); 742+ rc = pDb->pMethods->xFileControl(pDb, SQLITE_FCNTL_CKSM_FILE, (void*)&pDb); 743+ assert( rc==SQLITE_OK ); 744+ p->pPartner = (CksmFile*)pDb; 745+ assert( p->pPartner->pPartner==0 ); 746+ p->pPartner->pPartner = p; 747+ p->isWal = 1; 748+ p->computeCksm = p->pPartner->computeCksm; 749+ }else{ 750+ p->isWal = 0; 751+ p->computeCksm = 0; 752+ } 753+ p->zFName = zName; 754+cksm_open_done: 755+ if( rc ) pFile->pMethods = 0; 756+ return rc; 757+} 758+ 759+/* 760+** All other VFS methods are pass-thrus. 761+*/ 762+static int cksmDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ 763+ return ORIGVFS(pVfs)->xDelete(ORIGVFS(pVfs), zPath, dirSync); 764+} 765+static int cksmAccess( 766+ sqlite3_vfs *pVfs, 767+ const char *zPath, 768+ int flags, 769+ int *pResOut 770+){ 771+ return ORIGVFS(pVfs)->xAccess(ORIGVFS(pVfs), zPath, flags, pResOut); 772+} 773+static int cksmFullPathname( 774+ sqlite3_vfs *pVfs, 775+ const char *zPath, 776+ int nOut, 777+ char *zOut 778+){ 779+ return ORIGVFS(pVfs)->xFullPathname(ORIGVFS(pVfs),zPath,nOut,zOut); 780+} 781+static void *cksmDlOpen(sqlite3_vfs *pVfs, const char *zPath){ 782+ return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath); 783+} 784+static void cksmDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){ 785+ ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg); 786+} 787+static void (*cksmDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){ 788+ return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym); 789+} 790+static void cksmDlClose(sqlite3_vfs *pVfs, void *pHandle){ 791+ ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle); 792+} 793+static int cksmRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){ 794+ return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut); 795+} 796+static int cksmSleep(sqlite3_vfs *pVfs, int nMicro){ 797+ return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicro); 798+} 799+static int cksmCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ 800+ return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut); 801+} 802+static int cksmGetLastError(sqlite3_vfs *pVfs, int a, char *b){ 803+ return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b); 804+} 805+static int cksmCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *p){ 806+ sqlite3_vfs *pOrig = ORIGVFS(pVfs); 807+ int rc; 808+ assert( pOrig->iVersion>=2 ); 809+ if( pOrig->xCurrentTimeInt64 ){ 810+ rc = pOrig->xCurrentTimeInt64(pOrig, p); 811+ }else{ 812+ double r; 813+ rc = pOrig->xCurrentTime(pOrig, &r); 814+ *p = (sqlite3_int64)(r*86400000.0); 815+ } 816+ return rc; 817+} 818+static int cksmSetSystemCall( 819+ sqlite3_vfs *pVfs, 820+ const char *zName, 821+ sqlite3_syscall_ptr pCall 822+){ 823+ return ORIGVFS(pVfs)->xSetSystemCall(ORIGVFS(pVfs),zName,pCall); 824+} 825+static sqlite3_syscall_ptr cksmGetSystemCall( 826+ sqlite3_vfs *pVfs, 827+ const char *zName 828+){ 829+ return ORIGVFS(pVfs)->xGetSystemCall(ORIGVFS(pVfs),zName); 830+} 831+static const char *cksmNextSystemCall(sqlite3_vfs *pVfs, const char *zName){ 832+ return ORIGVFS(pVfs)->xNextSystemCall(ORIGVFS(pVfs), zName); 833+} 834+ 835+/* Register the verify_checksum() SQL function. 836+*/ 837+static int cksmRegisterFunc( 838+ sqlite3 *db, 839+ char **pzErrMsg, 840+ const sqlite3_api_routines *pApi 841+){ 842+ int rc; 843+ if( db==0 ) return SQLITE_OK; 844+ rc = sqlite3_create_function(db, "verify_checksum", 1, 845+ SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_DETERMINISTIC, 846+ 0, cksmVerifyFunc, 0, 0); 847+#ifdef SQLITE_CKSUMVFS_INIT_FUNCNAME 848+ (void)sqlite3_create_function(db, SQLITE_CKSUMVFS_INIT_FUNCNAME, 1, 849+ SQLITE_UTF8|SQLITE_DIRECTONLY, 850+ 0, cksmInitFunc, 0, 0); 851+#endif 852+ return rc; 853+} 854+ 855+/* 856+** Register the cksum VFS as the default VFS for the system. 857+** Also make arrangements to automatically register the "verify_checksum()" 858+** SQL function on each new database connection. 859+*/ 860+static int cksmRegisterVfs(void){ 861+ int rc = SQLITE_OK; 862+ sqlite3_vfs *pOrig; 863+ if( sqlite3_vfs_find("cksmvfs")!=0 ) return SQLITE_OK; 864+ pOrig = sqlite3_vfs_find(0); 865+ if( pOrig==0 ) return SQLITE_ERROR; 866+ cksm_vfs.iVersion = pOrig->iVersion; 867+ cksm_vfs.pAppData = pOrig; 868+ cksm_vfs.szOsFile = pOrig->szOsFile + sizeof(CksmFile); 869+ rc = sqlite3_vfs_register(&cksm_vfs, 1); 870+ if( rc==SQLITE_OK ){ 871+ rc = sqlite3_auto_extension((void(*)(void))cksmRegisterFunc); 872+ } 873+ return rc; 874+} 875+ 876+#if defined(SQLITE_CKSUMVFS_STATIC) 877+/* This variant of the initializer runs when the extension is 878+** statically linked. 879+*/ 880+int sqlite3_register_cksumvfs(const char *NotUsed){ 881+ (void)NotUsed; 882+ return cksmRegisterVfs(); 883+} 884+int sqlite3_unregister_cksumvfs(void){ 885+ if( sqlite3_vfs_find("cksmvfs") ){ 886+ sqlite3_vfs_unregister(&cksm_vfs); 887+ sqlite3_cancel_auto_extension((void(*)(void))cksmRegisterFunc); 888+ } 889+ return SQLITE_OK; 890+} 891+#endif /* defined(SQLITE_CKSUMVFS_STATIC */ 892+ 893+#if !defined(SQLITE_CKSUMVFS_STATIC) 894+/* This variant of the initializer function is used when the 895+** extension is shared library to be loaded at run-time. 896+*/ 897+#ifdef _WIN32 898+__declspec(dllexport) 899+#endif 900+/* 901+** This routine is called by sqlite3_load_extension() when the 902+** extension is first loaded. 903+***/ 904+int sqlite3_cksumvfs_init( 905+ sqlite3 *db, 906+ char **pzErrMsg, 907+ const sqlite3_api_routines *pApi 908+){ 909+ int rc; 910+ SQLITE_EXTENSION_INIT2(pApi); 911+ (void)pzErrMsg; /* not used */ 912+ rc = cksmRegisterFunc(db, 0, 0); 913+ if( rc==SQLITE_OK ){ 914+ rc = cksmRegisterVfs(); 915+ } 916+ if( rc==SQLITE_OK ) rc = SQLITE_OK_LOAD_PERMANENTLY; 917+ return rc; 918+} 919+#endif /* !defined(SQLITE_CKSUMVFS_STATIC) */ 920+ 921+#ifdef SQLITE_CKSUMVFS_STATIC 922+struct sqlite3_api_routines_cksumvfs { 923+ int (*register_cksumvfs)(const char *); 924+ int (*unregister_cksumvfs)(); 925+}; 926+typedef struct sqlite3_api_routines_cksumvfs sqlite3_api_routines_cksumvfs; 927+static const sqlite3_api_routines_cksumvfs sqlite3CksumvfsApis = { 928+ sqlite3_register_cksumvfs, 929+ sqlite3_unregister_cksumvfs 930+}; 931+ 932+EXPORT_SYMBOLS const sqlite3_api_routines_cksumvfs *sqlite3_export_cksumvfs_symbols = &sqlite3CksumvfsApis; 933+#endif 934diff --git a/src/sqlite3.c b/src/sqlite3.c 935index dc09c3c..e7e8b3c 100644 936--- a/src/sqlite3.c 937+++ b/src/sqlite3.c 938@@ -2472,6 +2472,21 @@ struct sqlite3_mem_methods { 939 ** is compiled without -DSQLITE_ALLOW_ROWID_IN_VIEW (which is the usual and 940 ** recommended case) then the integer is always filled with zero, regardless 941 ** if its initial value. 942+** 943+** [[SQLITE_CONFIG_CORRUPTION]] <dt>SQLITE_CONFIG_CORRUPTION</dt> 944+** <dd> The SQLITE_CONFIG_CORRUPTION option is used to configure the SQLite 945+** global [ corruption error]. 946+** (^The SQLITE_CONFIG_CORRUPTION option takes two arguments: a pointer to a 947+** function with a call signature of void(*)(void*,const void*), 948+** and a pointer to void. ^If the function pointer is not NULL, it is 949+** invoked to process each data corruption event. ^If the 950+** function pointer is NULL, no=op will do when corruption detect. 951+** ^The void pointer that is the second argument to SQLITE_CONFIG_CORRUPTION is 952+** passed through as the first parameter to the application-defined corruption 953+** function whenever that function is invoked. ^The second parameter to 954+** the corruption function is a corruption message after formatting via [sqlite3_snprintf()]. 955+** In a multi-threaded application, the application-defined corruption 956+** function must be threadsafe. </dd> 957 ** </dl> 958 */ 959 #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ 960@@ -2504,6 +2519,7 @@ struct sqlite3_mem_methods { 961 #define SQLITE_CONFIG_SORTERREF_SIZE 28 /* int nByte */ 962 #define SQLITE_CONFIG_MEMDB_MAXSIZE 29 /* sqlite3_int64 */ 963 #define SQLITE_CONFIG_ROWID_IN_VIEW 30 /* int* */ 964+#define SQLITE_CONFIG_CORRUPTION 40 /* xCorruption */ 965 #define SQLITE_CONFIG_ENABLE_ICU 41 /* boolean */ 966 967 /* 968@@ -20211,6 +20227,8 @@ struct Sqlite3Config { 969 int iOnceResetThreshold; /* When to reset OP_Once counters */ 970 u32 szSorterRef; /* Min size in bytes to use sorter-refs */ 971 unsigned int iPrngSeed; /* Alternative fixed seed for the PRNG */ 972+ void (*xCorruption)(void *, const void *); 973+ void *pCorruptionArg; 974 /* vvvv--- must be last ---vvv */ 975 #ifdef SQLITE_DEBUG 976 sqlite3_int64 aTune[SQLITE_NTUNE]; /* Tuning parameters */ 977@@ -20475,6 +20493,57 @@ SQLITE_PRIVATE Window *sqlite3WindowAssemble(Parse*, Window*, ExprList*, ExprLis 978 } \ 979 } 980 981+#define SQLITE_PRINT_CORRUPT_SIZE (SQLITE_PRINT_BUF_SIZE * 2) 982+ 983+#define SQLITE_CORRUPT_CONTEXT(N,P,T,O,S,M,R) \ 984+ { .nPage=(N), .pgno=(P), .type=(T), \ 985+ .zoneRange={(O),(S)}, .zMsg=(M), .reservedArgs=(R) } 986+ 987+typedef struct { 988+ int offset; 989+ size_t size; 990+}sqlite3CorruptRange; 991+ 992+typedef enum { 993+ CORRUPT_TYPE_PAGE_BTREE_LEAF, 994+ CORRUPT_TYPE_PAGE_BTREE_INTERIOR, 995+ CORRUPT_TYPE_PAGE_INDEX_LEAF, 996+ CORRUPT_TYPE_PAGE_INDEX_INTERIOR, 997+ CORRUPT_TYPE_PAGE_OVERFLOW, 998+ CORRUPT_TYPE_PAGE_PTR_MAP, 999+ CORRUPT_TYPE_PAGE_FREE_LIST, 1000+ CORRUPT_TYPE_FRAME_WAL, 1001+ CORRUPT_TYPE_ENTRY_JOURNAL, 1002+ CORRUPT_TYPE_VDBE, 1003+ CORRUPT_TYPE_FILE_HEADER, 1004+ CORRUPT_TYPE_UNKOWN, 1005+} CorruptType; 1006+ 1007+typedef struct { 1008+ size_t nPage; /* Number of pages */ 1009+ unsigned int pgno; /* Page number for corrupted page */ 1010+ CorruptType type; 1011+ sqlite3CorruptRange zoneRange; 1012+ const char *zMsg; 1013+ void *reservedArgs; 1014+}sqlite3CorruptContext; 1015+ 1016+// Encode buffer with base16, return size after encode 1017+static size_t sqlite3base16Encode(const unsigned char *buffer, size_t bufSize, char *encodeBuf, size_t encodeBufSize) 1018+{ 1019+ if (buffer == NULL || bufSize == 0 || encodeBuf == NULL || encodeBufSize == 0) { 1020+ return 0; 1021+ } 1022+ static const char base16Code[] = "0123456789ABCDEF"; 1023+ size_t i = 0; 1024+ for (; i < bufSize && (i * 2 < encodeBufSize - 1); i++) { 1025+ *encodeBuf++ = base16Code[(buffer[i] >> 4) & 0x0F]; 1026+ *encodeBuf++ = base16Code[buffer[i] & 0x0F]; 1027+ } 1028+ *encodeBuf = '\0'; 1029+ return i * 2; 1030+} 1031+ 1032 /* 1033 ** The SQLITE_*_BKPT macros are substitutes for the error codes with 1034 ** the same name but without the _BKPT suffix. These macros invoke 1035@@ -20483,10 +20552,11 @@ SQLITE_PRIVATE Window *sqlite3WindowAssemble(Parse*, Window*, ExprList*, ExprLis 1036 ** to set a debugger breakpoint. 1037 */ 1038 SQLITE_PRIVATE int sqlite3ReportError(int iErr, int lineno, const char *zType); 1039-SQLITE_PRIVATE int sqlite3CorruptError(int); 1040+SQLITE_PRIVATE int sqlite3CorruptError(int lineno, sqlite3CorruptContext *context); 1041 SQLITE_PRIVATE int sqlite3MisuseError(int); 1042 SQLITE_PRIVATE int sqlite3CantopenError(int); 1043-#define SQLITE_CORRUPT_BKPT sqlite3CorruptError(__LINE__) 1044+#define SQLITE_CORRUPT_REPORT(context) sqlite3CorruptError(__LINE__,(context)) 1045+#define SQLITE_CORRUPT_BKPT sqlite3CorruptError(__LINE__,NULL) 1046 #define SQLITE_MISUSE_BKPT sqlite3MisuseError(__LINE__) 1047 #define SQLITE_CANTOPEN_BKPT sqlite3CantopenError(__LINE__) 1048 #ifdef SQLITE_DEBUG 1049@@ -20498,12 +20568,13 @@ SQLITE_PRIVATE int sqlite3IoerrnomemError(int); 1050 # define SQLITE_NOMEM_BKPT SQLITE_NOMEM 1051 # define SQLITE_IOERR_NOMEM_BKPT SQLITE_IOERR_NOMEM 1052 #endif 1053-#if defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_CORRUPT_PGNO) 1054+#if (defined(SQLITE_DEBUG) || defined(SQLITE_ENABLE_CORRUPT_PGNO)) 1055 SQLITE_PRIVATE int sqlite3CorruptPgnoError(int,Pgno); 1056-# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptPgnoError(__LINE__,(P)) 1057+# define SQLITE_CORRUPT_PGNO(P,context) sqlite3CorruptPgnoError(__LINE__,(P)) 1058 #else 1059-# define SQLITE_CORRUPT_PGNO(P) sqlite3CorruptError(__LINE__) 1060+# define SQLITE_CORRUPT_PGNO(P,context) sqlite3CorruptError(__LINE__,(context)) 1061 #endif 1062+# define SQLITE_CORRUPT_REPORT_PGNO(context) SQLITE_CORRUPT_PGNO((context)->pgno,(context)) 1063 1064 /* 1065 ** FTS3 and FTS4 both require virtual table support 1066@@ -22946,6 +23017,8 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = { 1067 0x7ffffffe, /* iOnceResetThreshold */ 1068 SQLITE_DEFAULT_SORTERREF_SIZE, /* szSorterRef */ 1069 0, /* iPrngSeed */ 1070+ 0, /* xCorruption */ 1071+ 0, /* pCorruptionArg */ 1072 #ifdef SQLITE_DEBUG 1073 {0,0,0,0,0,0}, /* aTune */ 1074 #endif 1075@@ -58312,21 +58385,80 @@ static int jrnlBufferSize(Pager *pPager){ 1076 ** and debugging only. 1077 */ 1078 #ifdef SQLITE_CHECK_PAGES 1079-/* 1080-** Return a 32-bit hash of the page data for pPage. 1081-*/ 1082-static u32 pager_datahash(int nByte, unsigned char *pData){ 1083+#ifndef SQLITE_MIN_CHECK_PAGE_SIZE 1084+#define SQLITE_MIN_CHECK_PAGE_SIZE 4096 1085+#endif 1086+#if defined (__arm__) || defined (__aarch64__) 1087+#include <arm_neon.h> 1088+u32 deep_fast_hash_arm(void *src, int srcLen){ 1089+ uint16_t chunkSize = srcLen/4; 1090+ uint8_t *u8p_src = (uint8_t *)src; 1091+ uint16x8_t m_prime = vdupq_n_u16(44497); 1092+ uint16x8_t m_res0 = vdupq_n_u16(0); 1093+ uint16x8_t m_res1 = vdupq_n_u16(0); 1094+ uint16x8_t m_res2 = vdupq_n_u16(0); 1095+ uint16x8_t m_res3 = vdupq_n_u16(0); 1096+ uint16x8_t m_res4 = vdupq_n_u16(0); 1097+ uint16x8_t m_res5 = vdupq_n_u16(0); 1098+ uint16x8_t m_res6 = vdupq_n_u16(0); 1099+ uint16x8_t m_res7 = vdupq_n_u16(0); 1100+ 1101+ for(int i=0; i<chunkSize;){ 1102+ m_res0 = vmlaq_u16(vld1q_u16((uint16_t *)u8p_src) , m_res0, m_prime); 1103+ m_res1 = vmlaq_u16(vld1q_u16((uint16_t *)(u8p_src + chunkSize)) , m_res1, m_prime); 1104+ m_res2 = vmlaq_u16(vld1q_u16((uint16_t *)(u8p_src + 2*chunkSize)) , m_res2, m_prime); 1105+ m_res3 = vmlaq_u16(vld1q_u16((uint16_t *)(u8p_src + 3*chunkSize)) , m_res3, m_prime); 1106+ u8p_src += 16; 1107+ i += 16; 1108+ 1109+ m_res4 = vmlaq_u16(vld1q_u16((uint16_t *)u8p_src) , m_res4, m_prime); 1110+ m_res5 = vmlaq_u16(vld1q_u16((uint16_t *)(u8p_src + chunkSize)) , m_res5, m_prime); 1111+ m_res6 = vmlaq_u16(vld1q_u16((uint16_t *)(u8p_src + 2*chunkSize)) , m_res6, m_prime); 1112+ m_res7 = vmlaq_u16(vld1q_u16((uint16_t *)(u8p_src + 3*chunkSize)) , m_res7, m_prime); 1113+ u8p_src += 16; 1114+ i += 16; 1115+ } 1116+ m_res0 = vaddq_u16(m_res0, m_res1); 1117+ m_res2 = vaddq_u16(m_res2, m_res3); 1118+ m_res4 = vaddq_u16(m_res4, m_res5); 1119+ m_res6 = vaddq_u16(m_res6, m_res7); 1120+ m_res0 = vaddq_u16(m_res0, m_res2); 1121+ m_res4 = vaddq_u16(m_res4, m_res6); 1122+ m_res0 = vaddq_u16(m_res0, m_res4); 1123+ 1124+ uint32_t result[4]; 1125+ vst1q_u16((uint16_t *)result, m_res0); 1126+ 1127+ return result[0] + result[1] + result[2] + result[3]; 1128+} 1129+#else 1130+u32 sqlite_orig(void *src, int srcLen){ 1131+ u8 *pData = (u8 *)src; 1132 u32 hash = 0; 1133 int i; 1134- for(i=0; i<nByte; i++){ 1135+ for(i=0; i<srcLen; i++){ 1136 hash = (hash*1039) + pData[i]; 1137 } 1138 return hash; 1139 } 1140+#endif 1141+/* 1142+** Return a 32-bit hash of the page data for pPage. 1143+*/ 1144+static u32 pager_datahash(int nByte, unsigned char *pData){ 1145+#if defined (__arm__) || defined (__aarch64__) 1146+ return deep_fast_hash_arm(pData, nByte); 1147+#else 1148+ return sqlite_orig(pData, nByte); 1149+#endif 1150+} 1151 static u32 pager_pagehash(PgHdr *pPage){ 1152 return pager_datahash(pPage->pPager->pageSize, (unsigned char *)pPage->pData); 1153 } 1154 static void pager_set_pagehash(PgHdr *pPage){ 1155+ if( pPage->pPager->pageSize<SQLITE_MIN_CHECK_PAGE_SIZE ) { 1156+ return; 1157+ } 1158 pPage->pageHash = pager_pagehash(pPage); 1159 } 1160 1161@@ -58338,8 +58470,12 @@ static void pager_set_pagehash(PgHdr *pPage){ 1162 #define CHECK_PAGE(x) checkPage(x) 1163 static void checkPage(PgHdr *pPg){ 1164 Pager *pPager = pPg->pPager; 1165- assert( pPager->eState!=PAGER_ERROR ); 1166- assert( (pPg->flags&PGHDR_DIRTY) || pPg->pageHash==pager_pagehash(pPg) ); 1167+ if( pPager->pageSize<SQLITE_MIN_CHECK_PAGE_SIZE || pPager->eState==PAGER_ERROR || pPg->flags&PGHDR_DIRTY ) { 1168+ return; 1169+ } 1170+ if( pPg->pgno!=1 && pPg->pageHash!=pager_pagehash(pPg) ){ 1171+ sqlite3_log(SQLITE_CORRUPT, "cache corruption occurs through checking page(%u)", pPg->pgno); 1172+ } 1173 } 1174 1175 #else 1176@@ -60354,6 +60490,9 @@ static int pagerWalFrames( 1177 } 1178 1179 #ifdef SQLITE_CHECK_PAGES 1180+ if( pPager->pageSize<SQLITE_MIN_CHECK_PAGE_SIZE ) { 1181+ return rc; 1182+ } 1183 pList = sqlite3PcacheDirtyList(pPager->pPCache); 1184 for(p=pList; p; p=p->pDirty){ 1185 pager_set_pagehash(p); 1186@@ -62683,7 +62822,12 @@ static int getPageNormal( 1187 assert( assert_pager_state(pPager) ); 1188 assert( pPager->hasHeldSharedLock==1 ); 1189 1190- if( pgno==0 ) return SQLITE_CORRUPT_BKPT; 1191+ if( pgno==0 ) { 1192+ const char *zMsg = "pgno should not be 0"; 1193+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPager->dbSize, 0, CORRUPT_TYPE_UNKOWN, 1194+ -1, 0, zMsg, NULL); 1195+ return SQLITE_CORRUPT_REPORT(&context); 1196+ } 1197 pBase = sqlite3PcacheFetch(pPager->pPCache, pgno, 3); 1198 if( pBase==0 ){ 1199 pPg = 0; 1200@@ -62715,7 +62859,11 @@ static int getPageNormal( 1201 ** (2) Never try to fetch the locking page 1202 */ 1203 if( pgno==PAGER_SJ_PGNO(pPager) ){ 1204- rc = SQLITE_CORRUPT_BKPT; 1205+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1206+ sqlite3_snprintf(sizeof(zMsg), zMsg, "try fetching the locking page(%u)", pgno); 1207+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPager->dbSize, pgno, CORRUPT_TYPE_UNKOWN, 1208+ -1, 0, zMsg, NULL); 1209+ rc = SQLITE_CORRUPT_REPORT(&context); 1210 goto pager_acquire_err; 1211 } 1212 1213@@ -62801,7 +62949,10 @@ static int getPageMMap( 1214 ** test in the previous statement, and avoid testing pgno==0 in the 1215 ** common case where pgno is large. */ 1216 if( pgno<=1 && pgno==0 ){ 1217- return SQLITE_CORRUPT_BKPT; 1218+ const char *zMsg = "pgno should not be 0"; 1219+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPager->dbSize, 0, CORRUPT_TYPE_UNKOWN, 1220+ -1, 0, zMsg, NULL); 1221+ return SQLITE_CORRUPT_REPORT(&context); 1222 } 1223 assert( pPager->eState>=PAGER_READER ); 1224 assert( assert_pager_state(pPager) ); 1225@@ -64413,7 +64564,11 @@ SQLITE_PRIVATE int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, i 1226 if( pPgOld ){ 1227 if( NEVER(pPgOld->nRef>1) ){ 1228 sqlite3PagerUnrefNotNull(pPgOld); 1229- return SQLITE_CORRUPT_BKPT; 1230+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1231+ sqlite3_snprintf(sizeof(zMsg), zMsg, "page(%u) should be no references, ref cnt:%d", pgno, (int)pPgOld->nRef); 1232+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPager->dbSize, pgno, CORRUPT_TYPE_UNKOWN, 1233+ -1, 0, zMsg, NULL); 1234+ return SQLITE_CORRUPT_REPORT(&context); 1235 } 1236 pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC); 1237 if( pPager->tempFile ){ 1238@@ -66346,7 +66501,13 @@ static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){ 1239 /* Write the aPgno[] array entry and the hash-table slot. */ 1240 nCollide = idx; 1241 for(iKey=walHash(iPage); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){ 1242- if( (nCollide--)==0 ) return SQLITE_CORRUPT_BKPT; 1243+ if( (nCollide--)==0 ){ 1244+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1245+ sqlite3_snprintf(sizeof(zMsg), zMsg, "no place for page(%u) to map into WAL, idx:%d", iPage, idx); 1246+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pWal->hdr.nPage, iPage, CORRUPT_TYPE_FRAME_WAL, 1247+ -1, 0, zMsg, NULL); 1248+ return SQLITE_CORRUPT_REPORT(&context); 1249+ } 1250 } 1251 sLoc.aPgno[idx-1] = iPage; 1252 AtomicStore(&sLoc.aHash[iKey], (ht_slot)idx); 1253@@ -67176,6 +67337,11 @@ static void walRestartHdr(Wal *pWal, u32 salt1){ 1254 assert( pInfo->aReadMark[0]==0 ); 1255 } 1256 1257+#ifdef SQLITE_HDR_CHECK 1258+static int checkHeaderValid(Pager *pager, u8 *zBuf, const char *logStr); 1259+static int checkDbHeaderValid(sqlite3 *db, int iDbpage, u8 *zBuf); 1260+#endif /* SQLITE_HDR_CHECK */ 1261+ 1262 /* 1263 ** Copy as much content as we can from the WAL back into the database file 1264 ** in response to an sqlite3_wal_checkpoint() request or the equivalent. 1265@@ -67291,7 +67457,13 @@ static int walCheckpoint( 1266 ** database plus the amount of data in the wal file, plus the 1267 ** maximum size of the pending-byte page (65536 bytes), then 1268 ** must be corruption somewhere. */ 1269- rc = SQLITE_CORRUPT_BKPT; 1270+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1271+ sqlite3_snprintf(sizeof(zMsg), zMsg, 1272+ "final db size unexpected,nSize=%lld,mxFrame=%u,pageSize=%d,nReq=%lld", 1273+ nSize, pWal->hdr.mxFrame, szPage, nReq); 1274+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, 0, CORRUPT_TYPE_FRAME_WAL, 1275+ -1, 0, zMsg, NULL); 1276+ rc = SQLITE_CORRUPT_REPORT(&context); 1277 }else{ 1278 sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT,&nReq); 1279 } 1280@@ -67317,6 +67489,10 @@ static int walCheckpoint( 1281 if( rc!=SQLITE_OK ) break; 1282 iOffset = (iDbpage-1)*(i64)szPage; 1283 testcase( IS_BIG_INT(iOffset) ); 1284+#ifdef SQLITE_HDR_CHECK 1285+ rc = checkDbHeaderValid(db, iDbpage, zBuf); 1286+ if( rc!=SQLITE_OK ) break; 1287+#endif /* SQLITE_HDR_CHECK */ 1288 rc = sqlite3OsWrite(pWal->pDbFd, zBuf, szPage, iOffset); 1289 if( rc!=SQLITE_OK ) break; 1290 } 1291@@ -68526,7 +68702,11 @@ static int walFindFrame( 1292 iRead = iFrame; 1293 } 1294 if( (nCollide--)==0 ){ 1295- return SQLITE_CORRUPT_BKPT; 1296+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1297+ sqlite3_snprintf(sizeof(zMsg), zMsg, "mis-match page(%u) to map into WAL", pgno); 1298+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pWal->hdr.nPage, pgno, CORRUPT_TYPE_FRAME_WAL, 1299+ -1, 0, zMsg, NULL); 1300+ return SQLITE_CORRUPT_REPORT(&context); 1301 } 1302 iKey = walNextHash(iKey); 1303 } 1304@@ -68894,6 +69074,13 @@ static int walWriteOneFrame( 1305 int rc; /* Result code from subfunctions */ 1306 void *pData; /* Data actually written */ 1307 u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */ 1308+#ifdef SQLITE_HDR_CHECK 1309+ if( pPage->pgno==1 ){ 1310+ rc = checkHeaderValid(pPage->pPager, pPage->pData, "walWrite"); 1311+ if( rc!=SQLITE_OK ) return rc; 1312+ } 1313+#endif /* SQLITE_HDR_CHECK */ 1314+ 1315 #ifdef SQLITE_HAS_CODEC 1316 if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM_BKPT; 1317 #else 1318@@ -69319,7 +69506,12 @@ SQLITE_PRIVATE int sqlite3WalCheckpoint( 1319 /* Copy data from the log to the database file. */ 1320 if( rc==SQLITE_OK ){ 1321 if( pWal->hdr.mxFrame && walPagesize(pWal)!=nBuf ){ 1322- rc = SQLITE_CORRUPT_BKPT; 1323+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1324+ sqlite3_snprintf(sizeof(zMsg), zMsg, "mis-match between pageSize=%d and bufferSize=%d, mxFrame=%u", 1325+ walPagesize(pWal),nBuf,pWal->hdr.mxFrame); 1326+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pWal->hdr.nPage, 0, CORRUPT_TYPE_FRAME_WAL, 1327+ -1, 0, zMsg, NULL); 1328+ rc = SQLITE_CORRUPT_REPORT(&context); 1329 }else{ 1330 sqlite3_int64 startTime; 1331 sqlite3OsCurrentTimeInt64(db->pVfs, &startTime); 1332@@ -70751,6 +70943,32 @@ SQLITE_PRIVATE sqlite3_uint64 sqlite3BtreeSeekCount(Btree *pBt){ 1333 } 1334 #endif 1335 1336+#ifdef SQLITE_HDR_CHECK 1337+static int checkHeaderValid(Pager *pager, u8 *zBuf, const char *logStr){ 1338+#ifdef SQLITE_HAS_CODEC 1339+ if( pager==NULL || pager->pCodec ){ 1340+ return SQLITE_OK; 1341+ } 1342+#endif /* SQLITE_HAS_CODEC */ 1343+ if( zBuf && strncmp((const char *)zBuf, zMagicHeader, 16)!=0 ){ 1344+ sqlite3_log(SQLITE_NOTADB, "[%s]wrong header format, memory might be overwritten!", logStr); 1345+ return SQLITE_NOTADB; 1346+ } 1347+ return SQLITE_OK; 1348+} 1349+ 1350+static int checkDbHeaderValid(sqlite3 *db, int iDbpage, u8 *zBuf){ 1351+ if( iDbpage==1 && db->aDb ){ 1352+ Btree *p = db->aDb[0].pBt; 1353+ if( p && p->pBt ){ 1354+ Pager *pager = sqlite3BtreePager(p); 1355+ return checkHeaderValid(pager, zBuf, "ckpt"); 1356+ } 1357+ } 1358+ return SQLITE_OK; 1359+} 1360+#endif /* SQLITE_HDR_CHECK */ 1361+ 1362 /* 1363 ** Implementation of the SQLITE_CORRUPT_PAGE() macro. Takes a single 1364 ** (MemPage*) as an argument. The (MemPage*) must not be NULL. 1365@@ -70761,22 +70979,22 @@ SQLITE_PRIVATE sqlite3_uint64 sqlite3BtreeSeekCount(Btree *pBt){ 1366 ** with the page number and filename associated with the (MemPage*). 1367 */ 1368 #ifdef SQLITE_DEBUG 1369-int corruptPageError(int lineno, MemPage *p){ 1370+int corruptPageError(int lineno, MemPage *p, sqlite3CorruptContext *context){ 1371 char *zMsg; 1372 sqlite3BeginBenignMalloc(); 1373- zMsg = sqlite3_mprintf("database corruption page %u of %s", 1374- p->pgno, sqlite3PagerFilename(p->pBt->pPager, 0) 1375+ zMsg = sqlite3_mprintf("database corruption page %d of %s", 1376+ (int)p->pgno, sqlite3PagerFilename(p->pBt->pPager, 0) 1377 ); 1378 sqlite3EndBenignMalloc(); 1379 if( zMsg ){ 1380 sqlite3ReportError(SQLITE_CORRUPT, lineno, zMsg); 1381 } 1382 sqlite3_free(zMsg); 1383- return SQLITE_CORRUPT_BKPT; 1384+ return SQLITE_CORRUPT_REPORT(context); 1385 } 1386-# define SQLITE_CORRUPT_PAGE(pMemPage) corruptPageError(__LINE__, pMemPage) 1387+# define SQLITE_CORRUPT_PAGE(context,pMemPage) corruptPageError(__LINE__, (pMemPage),(context)) 1388 #else 1389-# define SQLITE_CORRUPT_PAGE(pMemPage) SQLITE_CORRUPT_PGNO(pMemPage->pgno) 1390+# define SQLITE_CORRUPT_PAGE(context,pMemPage) SQLITE_CORRUPT_PGNO((pMemPage)->pgno,(context)) 1391 #endif 1392 1393 #ifndef SQLITE_OMIT_SHARED_CACHE 1394@@ -71454,7 +71672,12 @@ static int btreeMoveto( 1395 if( pIdxKey==0 ) return SQLITE_NOMEM_BKPT; 1396 sqlite3VdbeRecordUnpack(pKeyInfo, (int)nKey, pKey, pIdxKey); 1397 if( pIdxKey->nField==0 || pIdxKey->nField>pKeyInfo->nAllField ){ 1398- rc = SQLITE_CORRUPT_BKPT; 1399+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1400+ sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpected fields in total:%u, should != 0 and < %u", 1401+ pIdxKey->nField,pKeyInfo->nAllField); 1402+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pCur->pBt->nPage, 0, CORRUPT_TYPE_PAGE_BTREE_LEAF, 1403+ -1, 0, zMsg, NULL); 1404+ rc = SQLITE_CORRUPT_REPORT(&context); 1405 }else{ 1406 rc = sqlite3BtreeIndexMoveto(pCur, pIdxKey, pRes); 1407 } 1408@@ -71651,7 +71874,7 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){ 1409 assert( 0==PTRMAP_ISPAGE(pBt, PENDING_BYTE_PAGE(pBt)) ); 1410 1411 assert( pBt->autoVacuum ); 1412- if( key==0 ){ 1413+ if( key==0 ){ // The pgno of each entry on ptrmap page starts from 3, an unexpected pgno indicates data corrupted 1414 *pRC = SQLITE_CORRUPT_BKPT; 1415 return; 1416 } 1417@@ -71665,12 +71888,24 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){ 1418 /* The first byte of the extra data is the MemPage.isInit byte. 1419 ** If that byte is set, it means this page is also being used 1420 ** as a btree page. */ 1421- *pRC = SQLITE_CORRUPT_BKPT; 1422+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1423+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; 1424+ (void)sqlite3base16Encode((unsigned char *)sqlite3PagerGetExtra(pDbPage), 8, xBuffer, sizeof(xBuffer)); 1425+ sqlite3_snprintf(sizeof(zMsg), zMsg, "page(%u) been initialized before as a btree page, base16:%s", 1426+ iPtrmap, xBuffer); 1427+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, iPtrmap, CORRUPT_TYPE_PAGE_PTR_MAP, 1428+ -1, 0, zMsg, NULL); 1429+ *pRC = SQLITE_CORRUPT_REPORT(&context); 1430 goto ptrmap_exit; 1431 } 1432 offset = PTRMAP_PTROFFSET(iPtrmap, key); 1433 if( offset<0 ){ 1434- *pRC = SQLITE_CORRUPT_BKPT; 1435+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1436+ sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpect offset in ptrmap page(%u), target:%u, page usableSize=%u", 1437+ iPtrmap, key, pBt->usableSize); 1438+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, iPtrmap, CORRUPT_TYPE_PAGE_PTR_MAP, 1439+ -1, 0, zMsg, NULL); 1440+ *pRC = SQLITE_CORRUPT_REPORT(&context); 1441 goto ptrmap_exit; 1442 } 1443 assert( offset <= (int)pBt->usableSize-5 ); 1444@@ -71715,7 +71950,12 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){ 1445 offset = PTRMAP_PTROFFSET(iPtrmap, key); 1446 if( offset<0 ){ 1447 sqlite3PagerUnref(pDbPage); 1448- return SQLITE_CORRUPT_BKPT; 1449+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1450+ sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpect offset in ptrmap page(%d), target:%u, page usableSize=%u", 1451+ iPtrmap, key, pBt->usableSize); 1452+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, iPtrmap, CORRUPT_TYPE_PAGE_PTR_MAP, 1453+ -1, 0, zMsg, NULL); 1454+ return SQLITE_CORRUPT_REPORT(&context); 1455 } 1456 assert( offset <= (int)pBt->usableSize-5 ); 1457 assert( pEType!=0 ); 1458@@ -71723,7 +71963,15 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){ 1459 if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]); 1460 1461 sqlite3PagerUnref(pDbPage); 1462- if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_PGNO(iPtrmap); 1463+ if( *pEType<1 || *pEType>5 ){ 1464+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1465+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; // 5 bytes for each entry on ptrmap page 1466+ (void)sqlite3base16Encode(pPtrmap, 5, xBuffer, sizeof(xBuffer)); 1467+ sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpect entry type:%d, base16:%s", (int)*pEType, xBuffer); 1468+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, iPtrmap, CORRUPT_TYPE_PAGE_PTR_MAP, 1469+ offset, 5, zMsg, NULL); 1470+ return SQLITE_CORRUPT_REPORT_PGNO(&context); 1471+ } 1472 return SQLITE_OK; 1473 } 1474 1475@@ -72163,7 +72411,14 @@ static void ptrmapPutOvflPtr(MemPage *pPage, MemPage *pSrc, u8 *pCell,int *pRC){ 1476 Pgno ovfl; 1477 if( SQLITE_OVERFLOW(pSrc->aDataEnd, pCell, pCell+info.nLocal) ){ 1478 testcase( pSrc!=pPage ); 1479- *pRC = SQLITE_CORRUPT_BKPT; 1480+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1481+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; // Output cell header as much as possible, 4 bytes for overflow pgno 1482+ (void)sqlite3base16Encode(pCell, info.nSize - info.nLocal - 4, xBuffer, sizeof(xBuffer)); 1483+ sqlite3_snprintf(sizeof(zMsg), zMsg, "cell overflow, offset=%d, rest=%d, length=%u, base16:%s", 1484+ (int)(pCell - pPage->aData), (int)(pSrc->aDataEnd - pCell), info.nSize, xBuffer); 1485+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, 1486+ pCell - pPage->aData, info.nSize, zMsg, NULL); 1487+ *pRC = SQLITE_CORRUPT_REPORT(&context); 1488 return; 1489 } 1490 ovfl = get4byte(&pCell[info.nSize-4]); 1491@@ -72221,10 +72476,29 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ 1492 ** reconstruct the entire page. */ 1493 if( (int)data[hdr+7]<=nMaxFrag ){ 1494 int iFree = get2byte(&data[hdr+1]); 1495- if( iFree>usableSize-4 ) return SQLITE_CORRUPT_PAGE(pPage); 1496+ if( iFree>usableSize-4 ){ 1497+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1498+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; 1499+ (void)sqlite3base16Encode(data, 8, xBuffer, sizeof(xBuffer)); // Output first 8 bytes as it's page header 1500+ sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock offset=%d overflow, usableSize=%d, base16:%s", 1501+ iFree, usableSize, xBuffer); 1502+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, 1503+ 0, 8, zMsg, NULL); 1504+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1505+ } 1506 if( iFree ){ 1507 int iFree2 = get2byte(&data[iFree]); 1508- if( iFree2>usableSize-4 ) return SQLITE_CORRUPT_PAGE(pPage); 1509+ if( iFree2>usableSize-4 ){ 1510+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1511+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; 1512+ (void)sqlite3base16Encode(data, 4, xBuffer, sizeof(xBuffer)); // Output first freeblock's header 4 bytes 1513+ sqlite3_snprintf(sizeof(zMsg), zMsg, 1514+ "1st freeblock's next pointer overflow, point:%d, usableSize=%d, base16:%s", 1515+ iFree2, usableSize, xBuffer); 1516+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, 1517+ iFree, 4, zMsg, NULL); 1518+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1519+ } 1520 if( 0==iFree2 || (data[iFree2]==0 && data[iFree2+1]==0) ){ 1521 u8 *pEnd = &data[cellOffset + nCell*2]; 1522 u8 *pAddr; 1523@@ -72232,16 +72506,51 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ 1524 int sz = get2byte(&data[iFree+2]); 1525 int top = get2byte(&data[hdr+5]); 1526 if( top>=iFree ){ 1527- return SQLITE_CORRUPT_PAGE(pPage); 1528+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1529+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; 1530+ (void)sqlite3base16Encode(data, 8, xBuffer, sizeof(xBuffer)); // Print first 8 bytes which is page header 1531+ sqlite3_snprintf(sizeof(zMsg), zMsg, 1532+ "1st freeblock's offset:%d should > CellContentArea's offset:%d, base16:%s", 1533+ iFree, top, xBuffer); 1534+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, 1535+ iFree, 8, zMsg, NULL); 1536+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1537 } 1538 if( iFree2 ){ 1539- if( iFree+sz>iFree2 ) return SQLITE_CORRUPT_PAGE(pPage); 1540+ if( iFree+sz>iFree2 ){ 1541+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1542+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; 1543+ (void)sqlite3base16Encode(data, 8, xBuffer, sizeof(xBuffer)); // Print first 8 bytes which is page header 1544+ sqlite3_snprintf(sizeof(zMsg), zMsg, 1545+ "the 1st 2 freeblocks mis-order, 1st block offset:%d, size:%d, 2nd block offset:%d, base16:%s", 1546+ iFree, sz, iFree2, xBuffer); 1547+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, 1548+ iFree, 4, zMsg, NULL); 1549+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1550+ } 1551 sz2 = get2byte(&data[iFree2+2]); 1552- if( iFree2+sz2 > usableSize ) return SQLITE_CORRUPT_PAGE(pPage); 1553+ if( iFree2+sz2 > usableSize ){ 1554+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1555+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; 1556+ (void)sqlite3base16Encode(data + iFree2, 4, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to 2nd block 1557+ sqlite3_snprintf(sizeof(zMsg), zMsg, 1558+ "the 2nd freeblock overflow, offset:%d, size:%d, usableSize:%d, base16:%s", 1559+ iFree2, sz2, usableSize, xBuffer); 1560+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, 1561+ iFree2, 4, zMsg, NULL); 1562+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1563+ } 1564 memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz)); 1565 sz += sz2; 1566 }else if( iFree+sz>usableSize ){ 1567- return SQLITE_CORRUPT_PAGE(pPage); 1568+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1569+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; 1570+ (void)sqlite3base16Encode(data + iFree, 4, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to 1st block 1571+ sqlite3_snprintf(sizeof(zMsg), zMsg, 1572+ "the 1st freeblock overflow, offset:%d, size:%d, usableSize:%d, base16:%s", iFree, sz, usableSize, xBuffer); 1573+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, 1574+ iFree, 4, zMsg, NULL); 1575+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1576 } 1577 1578 cbrk = top+sz; 1579@@ -72273,14 +72582,25 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ 1580 /* These conditions have already been verified in btreeInitPage() 1581 ** if PRAGMA cell_size_check=ON. 1582 */ 1583- if( pc>iCellLast ){ 1584- return SQLITE_CORRUPT_PAGE(pPage); 1585+ if( pc<iCellStart || pc>iCellLast ){ 1586+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1587+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; // Print 4 bytes belong to 1st block 1588+ (void)sqlite3base16Encode(data + cellOffset + i*2, 2, xBuffer, sizeof(xBuffer)); 1589+ sqlite3_snprintf(sizeof(zMsg), zMsg, "%d-th cell pointer:%d out of range[%d, %d], base16:%s", 1590+ i, pc, iCellStart, iCellLast, xBuffer); 1591+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, 1592+ cellOffset + i*2, 2, zMsg, NULL); 1593+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1594 } 1595 assert( pc>=0 && pc<=iCellLast ); 1596 size = pPage->xCellSize(pPage, &src[pc]); 1597 cbrk -= size; 1598 if( cbrk<iCellStart || pc+size>usableSize ){ 1599- return SQLITE_CORRUPT_PAGE(pPage); 1600+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1601+ sqlite3_snprintf(sizeof(zMsg), zMsg, "move %d-th cell from %d using unexpected size:%d", i, pc, size); 1602+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, 1603+ -1, 0, zMsg, NULL); 1604+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1605 } 1606 assert( cbrk+size<=usableSize && cbrk>=iCellStart ); 1607 testcase( cbrk+size==usableSize ); 1608@@ -72294,7 +72614,13 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ 1609 defragment_out: 1610 assert( pPage->nFree>=0 ); 1611 if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){ 1612- return SQLITE_CORRUPT_PAGE(pPage); 1613+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1614+ sqlite3_snprintf(sizeof(zMsg), zMsg, 1615+ "after defragment, free bytes should not change, fragment bytes:%d, free space:%d, total:%d", 1616+ (int)data[hdr+7], cbrk-iCellFirst, pPage->nFree); 1617+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, 1618+ -1, 0, zMsg, NULL); 1619+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1620 } 1621 assert( cbrk>=iCellFirst ); 1622 put2byte(&data[hdr+5], cbrk); 1623@@ -72319,7 +72645,7 @@ defragment_out: 1624 ** will be ignored if adding the extra space to the fragmentation count 1625 ** causes the fragmentation count to exceed 60. 1626 */ 1627-static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ 1628+static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ // search on B-tree page 1629 const int hdr = pPg->hdrOffset; /* Offset to page header */ 1630 u8 * const aData = pPg->aData; /* Page data */ 1631 int iAddr = hdr + 1; /* Address of ptr to pc */ 1632@@ -72351,7 +72677,15 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ 1633 return &aData[pc]; 1634 }else if( x+pc > maxPC ){ 1635 /* This slot extends off the end of the usable part of the page */ 1636- *pRc = SQLITE_CORRUPT_PAGE(pPg); 1637+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1638+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; 1639+ (void)sqlite3base16Encode(aData + pc, 4, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to free block 1640+ sqlite3_snprintf(sizeof(zMsg), zMsg, 1641+ "freeblock rest bytes:%d begin at %d which cost %d, still exceed usableSize:%u, base16:%s", 1642+ x, pc, nByte, pPg->pBt->usableSize, xBuffer); 1643+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPg->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, 1644+ pc, 4, zMsg, NULL); 1645+ *pRc = SQLITE_CORRUPT_PAGE(&context, pPg); 1646 return 0; 1647 }else{ 1648 /* The slot remains on the free-list. Reduce its size to account 1649@@ -72366,14 +72700,25 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){ 1650 if( pc<=iAddr ){ 1651 if( pc ){ 1652 /* The next slot in the chain comes before the current slot */ 1653- *pRc = SQLITE_CORRUPT_PAGE(pPg); 1654+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1655+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; 1656+ (void)sqlite3base16Encode(pTmp, 2, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to free block 1657+ sqlite3_snprintf(sizeof(zMsg), zMsg, 1658+ "the next slot:%d in chain comes before current slot:%d, base16:%s", pc, iAddr, xBuffer); 1659+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPg->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, 1660+ iAddr, 2, zMsg, NULL); 1661+ *pRc = SQLITE_CORRUPT_PAGE(&context, pPg); 1662 } 1663 return 0; 1664 } 1665 } 1666 if( pc>maxPC+nByte-4 ){ 1667 /* The free slot chain extends off the end of the page */ 1668- *pRc = SQLITE_CORRUPT_PAGE(pPg); 1669+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1670+ sqlite3_snprintf(sizeof(zMsg), zMsg, "free slot:%d overflow, end:%d", pc, maxPC+nByte-4); 1671+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPg->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, 1672+ -1, 0, zMsg, NULL); 1673+ *pRc = SQLITE_CORRUPT_PAGE(&context, pPg); 1674 } 1675 return 0; 1676 } 1677@@ -72421,10 +72766,16 @@ static SQLITE_INLINE int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ 1678 if( top==0 && pPage->pBt->usableSize==65536 ){ 1679 top = 65536; 1680 }else{ 1681- return SQLITE_CORRUPT_PAGE(pPage); 1682+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1683+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; 1684+ (void)sqlite3base16Encode(data, 8, xBuffer, sizeof(xBuffer)); // Print 8 bytes belong to page header 1685+ sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpected cellContentArea offset:%d, base16:%s", top, xBuffer); 1686+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, 1687+ CORRUPT_TYPE_PAGE_BTREE_LEAF, 0, 8, zMsg, NULL); 1688+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1689 } 1690 }else if( top>(int)pPage->pBt->usableSize ){ 1691- return SQLITE_CORRUPT_PAGE(pPage); 1692+ return SQLITE_CORRUPT_PAGE(NULL, pPage); 1693 } 1694 1695 /* If there is enough space between gap and top for one more cell pointer, 1696@@ -72441,7 +72792,11 @@ static SQLITE_INLINE int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ 1697 assert( pSpace+nByte<=data+pPage->pBt->usableSize ); 1698 *pIdx = g2 = (int)(pSpace-data); 1699 if( g2<=gap ){ 1700- return SQLITE_CORRUPT_PAGE(pPage); 1701+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1702+ sqlite3_snprintf(sizeof(zMsg), zMsg, "cellpointers(end:%d) overlap with freeblock(%d)", gap, g2); 1703+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, 1704+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); 1705+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1706 }else{ 1707 return SQLITE_OK; 1708 } 1709@@ -72520,12 +72875,23 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ 1710 while( (iFreeBlk = get2byte(&data[iPtr]))<iStart ){ 1711 if( iFreeBlk<=iPtr ){ 1712 if( iFreeBlk==0 ) break; /* TH3: corrupt082.100 */ 1713- return SQLITE_CORRUPT_PAGE(pPage); 1714+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1715+ sqlite3_snprintf(sizeof(zMsg), zMsg, 1716+ "freeblock should order by asce, pre blocks:%d, next block:%d", (int)iPtr, (int)iFreeBlk); 1717+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, 1718+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); 1719+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1720 } 1721 iPtr = iFreeBlk; 1722 } 1723 if( iFreeBlk>pPage->pBt->usableSize-4 ){ /* TH3: corrupt081.100 */ 1724- return SQLITE_CORRUPT_PAGE(pPage); 1725+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1726+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; 1727+ (void)sqlite3base16Encode(data + iPtr, 4, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to freeblock 1728+ sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock offset:%d overflow, base16:%s", (int)iFreeBlk, xBuffer); 1729+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, 1730+ CORRUPT_TYPE_PAGE_BTREE_LEAF, iPtr, 4, zMsg, NULL); 1731+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1732 } 1733 assert( iFreeBlk>iPtr || iFreeBlk==0 || CORRUPT_DB ); 1734 1735@@ -72537,10 +72903,24 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ 1736 */ 1737 if( iFreeBlk && iEnd+3>=iFreeBlk ){ 1738 nFrag = iFreeBlk - iEnd; 1739- if( iEnd>iFreeBlk ) return SQLITE_CORRUPT_PAGE(pPage); 1740+ if( iEnd>iFreeBlk ){ 1741+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1742+ sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock offset:%d overlaps with pre block's end:%u", 1743+ (int)iFreeBlk, iEnd); 1744+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, 1745+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); 1746+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1747+ } 1748 iEnd = iFreeBlk + get2byte(&data[iFreeBlk+2]); 1749 if( iEnd > pPage->pBt->usableSize ){ 1750- return SQLITE_CORRUPT_PAGE(pPage); 1751+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1752+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; 1753+ (void)sqlite3base16Encode(data + iFreeBlk, 4, xBuffer, sizeof(xBuffer)); // Print 4 bytes belong to freeblock 1754+ sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock offset:%d, end:%u overflow, usableSize:%u, base16:%s", 1755+ (int)iFreeBlk, iEnd, pPage->pBt->usableSize, xBuffer); 1756+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, 1757+ CORRUPT_TYPE_PAGE_BTREE_LEAF, iFreeBlk, 4, zMsg, NULL); 1758+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1759 } 1760 iSize = iEnd - iStart; 1761 iFreeBlk = get2byte(&data[iFreeBlk]); 1762@@ -72553,13 +72933,27 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ 1763 if( iPtr>hdr+1 ){ 1764 int iPtrEnd = iPtr + get2byte(&data[iPtr+2]); 1765 if( iPtrEnd+3>=iStart ){ 1766- if( iPtrEnd>iStart ) return SQLITE_CORRUPT_PAGE(pPage); 1767+ if( iPtrEnd>iStart ){ 1768+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1769+ sqlite3_snprintf(sizeof(zMsg), zMsg, "check pre freeblock end:%d overlaps with the pending free block:%d", 1770+ iPtrEnd, (int)iStart); 1771+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, 1772+ CORRUPT_TYPE_PAGE_BTREE_LEAF, iPtr, iPtrEnd - iPtr, zMsg, NULL); 1773+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1774+ } 1775 nFrag += iStart - iPtrEnd; 1776 iSize = iEnd - iPtr; 1777 iStart = iPtr; 1778 } 1779 } 1780- if( nFrag>data[hdr+7] ) return SQLITE_CORRUPT_PAGE(pPage); 1781+ if( nFrag>data[hdr+7] ){ 1782+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1783+ sqlite3_snprintf(sizeof(zMsg), zMsg, "fragment free bytes:%d increase unexpectly, should be %d", 1784+ (int)nFrag, (int)data[hdr+7]); 1785+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, 1786+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); 1787+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1788+ } 1789 data[hdr+7] -= nFrag; 1790 } 1791 pTmp = &data[hdr+5]; 1792@@ -72573,8 +72967,21 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){ 1793 /* The new freeblock is at the beginning of the cell content area, 1794 ** so just extend the cell content area rather than create another 1795 ** freelist entry */ 1796- if( iStart<x ) return SQLITE_CORRUPT_PAGE(pPage); 1797- if( iPtr!=hdr+1 ) return SQLITE_CORRUPT_PAGE(pPage); 1798+ if( iStart<x ){ 1799+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1800+ sqlite3_snprintf(sizeof(zMsg), zMsg, 1801+ "new freeblock:%d should >= the beginning of the CellContentArea:%d", (int)x, (int)iStart); 1802+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, 1803+ CORRUPT_TYPE_PAGE_BTREE_LEAF, 0, 8, zMsg, NULL); 1804+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1805+ } 1806+ if( iPtr!=hdr+1 ){ 1807+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1808+ sqlite3_snprintf(sizeof(zMsg), zMsg, "1st freeblock's pos incorrect, hdr:%d, iPtr:%d", (int)hdr, (int)iPtr); 1809+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, 1810+ CORRUPT_TYPE_PAGE_BTREE_LEAF, 0, 8, zMsg, NULL); 1811+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1812+ } 1813 put2byte(&data[hdr+1], iFreeBlk); 1814 put2byte(&data[hdr+5], iEnd); 1815 }else{ 1816@@ -72628,7 +73035,13 @@ static int decodeFlags(MemPage *pPage, int flagByte){ 1817 pPage->intKeyLeaf = 0; 1818 pPage->xCellSize = cellSizePtrIdxLeaf; 1819 pPage->xParseCell = btreeParseCellPtrIndex; 1820- return SQLITE_CORRUPT_PAGE(pPage); 1821+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1822+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; 1823+ (void)sqlite3base16Encode(pPage->aData, 8, xBuffer, sizeof(xBuffer)); 1824+ sqlite3_snprintf(sizeof(zMsg), zMsg, "unrecognized flag:%d, base16:%s", flagByte, xBuffer); 1825+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, 1826+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); 1827+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1828 } 1829 }else{ 1830 pPage->childPtrSize = 4; 1831@@ -72659,7 +73072,13 @@ static int decodeFlags(MemPage *pPage, int flagByte){ 1832 pPage->pgno, flagByte, pPage->isInit, pPage->intKey, pPage->intKeyLeaf, pPage->leaf, 1833 pPage->childPtrSize, pPage->cellOffset, pPage->nCell, pPage->hdrOffset, pPage->minLocal, pPage->maxLocal, g_lastCkptTime); 1834 #endif /* LOG_DUMP */ 1835- return SQLITE_CORRUPT_PAGE(pPage); 1836+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1837+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; 1838+ (void)sqlite3base16Encode(pPage->aData, 8, xBuffer, sizeof(xBuffer)); 1839+ sqlite3_snprintf(sizeof(zMsg), zMsg, "unrecognized flag:%d, base16:%s", flagByte, xBuffer); 1840+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, 1841+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); 1842+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1843 } 1844 } 1845 return SQLITE_OK; 1846@@ -72710,12 +73129,20 @@ static int btreeComputeFreeSpace(MemPage *pPage){ 1847 /* EVIDENCE-OF: R-55530-52930 In a well-formed b-tree page, there will 1848 ** always be at least one cell before the first freeblock. 1849 */ 1850- return SQLITE_CORRUPT_PAGE(pPage); 1851+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1852+ sqlite3_snprintf(sizeof(zMsg), zMsg, "the 1st freeblock:%d before all cells:%d", pc, top); 1853+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, 1854+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); 1855+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1856 } 1857 while( 1 ){ 1858 if( pc>iCellLast ){ 1859 /* Freeblock off the end of the page */ 1860- return SQLITE_CORRUPT_PAGE(pPage); 1861+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1862+ sqlite3_snprintf(sizeof(zMsg), zMsg, "freeblock end:%d out of page range:%d", pc, iCellLast); 1863+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, 1864+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); 1865+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1866 } 1867 next = get2byte(&data[pc]); 1868 size = get2byte(&data[pc+2]); 1869@@ -72725,11 +73152,19 @@ static int btreeComputeFreeSpace(MemPage *pPage){ 1870 } 1871 if( next>0 ){ 1872 /* Freeblock not in ascending order */ 1873- return SQLITE_CORRUPT_PAGE(pPage); 1874+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1875+ sqlite3_snprintf(sizeof(zMsg), zMsg, "all freeblocks should order by asc, pre:%d, cur:%u", pc, next); 1876+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, 1877+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); 1878+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1879 } 1880 if( pc+size>(unsigned int)usableSize ){ 1881 /* Last freeblock extends past page end */ 1882- return SQLITE_CORRUPT_PAGE(pPage); 1883+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1884+ sqlite3_snprintf(sizeof(zMsg), zMsg, "last freeblock overflow, offset:%d, size:%u", pc, size); 1885+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, 1886+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); 1887+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1888 } 1889 } 1890 1891@@ -72741,7 +73176,13 @@ static int btreeComputeFreeSpace(MemPage *pPage){ 1892 ** area, according to the page header, lies within the page. 1893 */ 1894 if( nFree>usableSize || nFree<iCellFirst ){ 1895- return SQLITE_CORRUPT_PAGE(pPage); 1896+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1897+ sqlite3_snprintf(sizeof(zMsg), zMsg, 1898+ "CellContentArea plus free bytes(%d) should <= usableSize:%d, content offset:%d", 1899+ nFree, usableSize, iCellFirst); 1900+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, 1901+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); 1902+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1903 } 1904 pPage->nFree = (u16)(nFree - iCellFirst); 1905 return SQLITE_OK; 1906@@ -72772,12 +73213,20 @@ static SQLITE_NOINLINE int btreeCellSizeCheck(MemPage *pPage){ 1907 testcase( pc==iCellFirst ); 1908 testcase( pc==iCellLast ); 1909 if( pc<iCellFirst || pc>iCellLast ){ 1910- return SQLITE_CORRUPT_PAGE(pPage); 1911+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1912+ sqlite3_snprintf(sizeof(zMsg), zMsg, "cell pointer:%d indicate out of range:[%d, %d]", pc, iCellFirst, iCellLast); 1913+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, 1914+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); 1915+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1916 } 1917 sz = pPage->xCellSize(pPage, &data[pc]); 1918 testcase( pc+sz==usableSize ); 1919 if( pc+sz>usableSize ){ 1920- return SQLITE_CORRUPT_PAGE(pPage); 1921+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1922+ sqlite3_snprintf(sizeof(zMsg), zMsg, "unexpected cell size:%d,offset:%d, out of range:%d", sz, pc, usableSize); 1923+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, 1924+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); 1925+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1926 } 1927 } 1928 return SQLITE_OK; 1929@@ -72809,7 +73258,7 @@ static int btreeInitPage(MemPage *pPage){ 1930 /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating 1931 ** the b-tree page type. */ 1932 if( decodeFlags(pPage, data[0]) ){ 1933- return SQLITE_CORRUPT_PAGE(pPage); 1934+ return SQLITE_CORRUPT_PAGE(NULL, pPage); 1935 } 1936 assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); 1937 pPage->maskPage = (u16)(pBt->pageSize - 1); 1938@@ -72823,7 +73272,12 @@ static int btreeInitPage(MemPage *pPage){ 1939 pPage->nCell = get2byte(&data[3]); 1940 if( pPage->nCell>MX_CELL(pBt) ){ 1941 /* To many cells for a single page. The page must be corrupt */ 1942- return SQLITE_CORRUPT_PAGE(pPage); 1943+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1944+ sqlite3_snprintf(sizeof(zMsg), zMsg, "too many cells(%d) for the page:%u, offset:%d, out of range:%u", 1945+ (int)pPage->nCell, pPage->pgno, (int)pPage->hdrOffset + 3, MX_CELL(pBt)); 1946+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, 1947+ -1, 0, zMsg, NULL); 1948+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1949 } 1950 testcase( pPage->nCell==MX_CELL(pBt) ); 1951 /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only 1952@@ -72966,7 +73420,11 @@ static int getAndInitPage( 1953 1954 if( pgno>btreePagecount(pBt) ){ 1955 *ppPage = 0; 1956- return SQLITE_CORRUPT_BKPT; 1957+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1958+ sqlite3_snprintf(sizeof(zMsg), zMsg, "page number(%u) > db file size(%u)", pgno, btreePagecount(pBt)); 1959+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, 1960+ -1, 0, zMsg, NULL); 1961+ return SQLITE_CORRUPT_REPORT(&context); 1962 } 1963 rc = sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, bReadOnly); 1964 if( rc ){ 1965@@ -74439,7 +74897,12 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ 1966 if( eType==PTRMAP_OVERFLOW2 ){ 1967 /* The pointer is always the first 4 bytes of the page in this case. */ 1968 if( get4byte(pPage->aData)!=iFrom ){ 1969- return SQLITE_CORRUPT_PAGE(pPage); 1970+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1971+ sqlite3_snprintf(sizeof(zMsg), zMsg, "1st 4 bytes of ovrflow page(%u) point to next(%u), should be %u", 1972+ pPage->pgno, get4byte(pPage->aData), iFrom); 1973+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(0, pPage->pgno, CORRUPT_TYPE_PAGE_PTR_MAP, 1974+ 0, 4, zMsg, NULL); 1975+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1976 } 1977 put4byte(pPage->aData, iTo); 1978 }else{ 1979@@ -74458,7 +74921,13 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ 1980 pPage->xParseCell(pPage, pCell, &info); 1981 if( info.nLocal<info.nPayload ){ 1982 if( pCell+info.nSize > pPage->aData+pPage->pBt->usableSize ){ 1983- return SQLITE_CORRUPT_PAGE(pPage); 1984+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 1985+ sqlite3_snprintf(sizeof(zMsg), zMsg, 1986+ "btree cell contain ovrflow pointer overflow, offset:%d, size:%u, usableSize:%u", 1987+ (int)(pCell - pPage->aData), info.nSize, pPage->pBt->usableSize); 1988+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, 1989+ CORRUPT_TYPE_PAGE_PTR_MAP, pCell - pPage->aData, info.nSize, zMsg, NULL); 1990+ return SQLITE_CORRUPT_PAGE(&context, pPage); 1991 } 1992 if( iFrom==get4byte(pCell+info.nSize-4) ){ 1993 put4byte(pCell+info.nSize-4, iTo); 1994@@ -74467,7 +74936,13 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ 1995 } 1996 }else{ 1997 if( pCell+4 > pPage->aData+pPage->pBt->usableSize ){ 1998- return SQLITE_CORRUPT_PAGE(pPage); 1999+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 2000+ sqlite3_snprintf(sizeof(zMsg), zMsg, 2001+ "btree cell contain child pointer overflow, offset:%d, size:4, usableSize:%u", 2002+ (int)(pCell - pPage->aData), pPage->pBt->usableSize); 2003+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, 2004+ CORRUPT_TYPE_PAGE_PTR_MAP, pCell - pPage->aData, 4, zMsg, NULL); 2005+ return SQLITE_CORRUPT_PAGE(&context, pPage); 2006 } 2007 if( get4byte(pCell)==iFrom ){ 2008 put4byte(pCell, iTo); 2009@@ -74479,7 +74954,11 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){ 2010 if( i==nCell ){ 2011 if( eType!=PTRMAP_BTREE || 2012 get4byte(&pPage->aData[pPage->hdrOffset+8])!=iFrom ){ 2013- return SQLITE_CORRUPT_PAGE(pPage); 2014+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 2015+ sqlite3_snprintf(sizeof(zMsg), zMsg, "missing pointer point to overflow page on btree page(%u)", pPage->pgno); 2016+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, 2017+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); 2018+ return SQLITE_CORRUPT_PAGE(&context, pPage); 2019 } 2020 put4byte(&pPage->aData[pPage->hdrOffset+8], iTo); 2021 } 2022@@ -74612,7 +75091,11 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){ 2023 return rc; 2024 } 2025 if( eType==PTRMAP_ROOTPAGE ){ 2026- return SQLITE_CORRUPT_BKPT; 2027+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 2028+ sqlite3_snprintf(sizeof(zMsg), zMsg, "try vacuum root page(%u), should not happened", nFin); 2029+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, PTRMAP_PAGENO(pBt, iLastPg), 2030+ CORRUPT_TYPE_PAGE_PTR_MAP, -1, 0, zMsg, NULL); 2031+ return SQLITE_CORRUPT_REPORT(&context); 2032 } 2033 2034 if( eType==PTRMAP_FREEPAGE ){ 2035@@ -75688,7 +76171,12 @@ static int accessPayload( 2036 assert( eOp==0 || eOp==1 ); 2037 assert( pCur->eState==CURSOR_VALID ); 2038 if( pCur->ix>=pPage->nCell ){ 2039- return SQLITE_CORRUPT_PAGE(pPage); 2040+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 2041+ sqlite3_snprintf(sizeof(zMsg), zMsg, "cell index:%u exceed limit:%u on the page:%u", 2042+ pCur->ix, pPage->nCell, pPage->pgno); 2043+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, 2044+ -1, 0, zMsg, NULL); 2045+ return SQLITE_CORRUPT_PAGE(&context, pPage); 2046 } 2047 assert( cursorHoldsMutex(pCur) ); 2048 2049@@ -75703,7 +76191,12 @@ static int accessPayload( 2050 ** &aPayload[pCur->info.nLocal] > &pPage->aData[pBt->usableSize] 2051 ** but is recast into its current form to avoid integer overflow problems 2052 */ 2053- return SQLITE_CORRUPT_PAGE(pPage); 2054+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 2055+ sqlite3_snprintf(sizeof(zMsg), zMsg, "base on payload size:%u, the max offset(%d) should > %d", 2056+ pCur->info.nLocal, (int)(aPayload - pPage->aData), (int)(pBt->usableSize - pCur->info.nLocal)); 2057+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, 2058+ 0, 8, zMsg, NULL); 2059+ return SQLITE_CORRUPT_PAGE(&context, pPage); 2060 } 2061 2062 /* Check if data must be read/written to/from the btree page itself. */ 2063@@ -75765,7 +76258,16 @@ static int accessPayload( 2064 assert( rc==SQLITE_OK && amt>0 ); 2065 while( nextPage ){ 2066 /* If required, populate the overflow page-list cache. */ 2067- if( nextPage > pBt->nPage ) return SQLITE_CORRUPT_BKPT; 2068+ if( nextPage > pBt->nPage ){ 2069+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 2070+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; 2071+ (void)sqlite3base16Encode(aPayload + pCur->info.nLocal, 4, xBuffer, sizeof(xBuffer)); 2072+ sqlite3_snprintf(sizeof(zMsg), zMsg, "overflow page:%u should not exceed the size of database file, base16:%s", 2073+ nextPage, xBuffer); 2074+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, 2075+ aPayload - pPage->aData + pCur->info.nLocal, 4, zMsg, NULL); 2076+ return SQLITE_CORRUPT_REPORT(&context); 2077+ } 2078 assert( pCur->aOverflow[iIdx]==0 2079 || pCur->aOverflow[iIdx]==nextPage 2080 || CORRUPT_DB ); 2081@@ -75850,7 +76352,11 @@ static int accessPayload( 2082 2083 if( rc==SQLITE_OK && amt>0 ){ 2084 /* Overflow chain ends prematurely */ 2085- return SQLITE_CORRUPT_PAGE(pPage); 2086+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 2087+ sqlite3_snprintf(sizeof(zMsg), zMsg, "overflow chain ends prematurely, rest:%d", amt); 2088+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, 2089+ -1, 0, zMsg, NULL); 2090+ return SQLITE_CORRUPT_PAGE(&context, pPage); 2091 } 2092 return rc; 2093 } 2094@@ -76002,7 +76508,7 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){ 2095 && (pCur->pPage->nCell<1 || pCur->pPage->intKey!=pCur->curIntKey) 2096 ){ 2097 releasePage(pCur->pPage); 2098- rc = SQLITE_CORRUPT_PGNO(newPgno); 2099+ rc = SQLITE_CORRUPT_PGNO(newPgno, NULL); 2100 } 2101 if( rc ){ 2102 pCur->pPage = pCur->apPage[--pCur->iPage]; 2103@@ -76137,7 +76643,12 @@ static int moveToRoot(BtCursor *pCur){ 2104 ** (or the freelist). */ 2105 assert( pRoot->intKey==1 || pRoot->intKey==0 ); 2106 if( pRoot->isInit==0 || (pCur->pKeyInfo==0)!=pRoot->intKey ){ 2107- return SQLITE_CORRUPT_PAGE(pCur->pPage); 2108+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 2109+ sqlite3_snprintf(sizeof(zMsg), zMsg, "the page(%u) state illegal, isInit:%u, pKeyInfo%s0, intKey:%u", 2110+ pRoot->pgno, pRoot->isInit, ((pCur->pKeyInfo==0)?"==":"!="), pRoot->intKey); 2111+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pCur->pBt->nPage, pRoot->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, 2112+ -1, 0, zMsg, NULL); 2113+ return SQLITE_CORRUPT_PAGE(&context, pCur->pPage); 2114 } 2115 2116 skip_init: 2117@@ -76391,7 +76902,11 @@ SQLITE_PRIVATE int sqlite3BtreeTableMoveto( 2118 if( pPage->intKeyLeaf ){ 2119 while( 0x80 <= *(pCell++) ){ 2120 if( pCell>=pPage->aDataEnd ){ 2121- return SQLITE_CORRUPT_PAGE(pPage); 2122+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 2123+ sqlite3_snprintf(sizeof(zMsg), zMsg, "cell idx(%d) point to a cell should not out of page", idx); 2124+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, 2125+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); 2126+ return SQLITE_CORRUPT_PAGE(&context, pPage); 2127 } 2128 } 2129 } 2130@@ -76674,7 +77189,12 @@ bypass_moveto_root: 2131 testcase( nCell==1 ); /* Invalid key size: 0x80 0x80 0x01 */ 2132 testcase( nCell==2 ); /* Minimum legal index key size */ 2133 if( nCell<2 || nCell/pCur->pBt->usableSize>pCur->pBt->nPage ){ 2134- rc = SQLITE_CORRUPT_PAGE(pPage); 2135+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 2136+ sqlite3_snprintf(sizeof(zMsg), zMsg, "nCell:%d illegal, usableSize:%u, nPage:%u", 2137+ nCell, pCur->pBt->usableSize, pCur->pBt->nPage); 2138+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, 2139+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); 2140+ rc = SQLITE_CORRUPT_PAGE(&context, pPage); 2141 goto moveto_index_finish; 2142 } 2143 pCellKey = sqlite3Malloc( nCell+nOverrun ); 2144@@ -76748,7 +77268,7 @@ bypass_moveto_root: 2145 && (pCur->pPage->nCell<1 || pCur->pPage->intKey!=pCur->curIntKey) 2146 ){ 2147 releasePage(pCur->pPage); 2148- rc = SQLITE_CORRUPT_PGNO(chldPg); 2149+ rc = SQLITE_CORRUPT_PGNO(chldPg, NULL); 2150 } 2151 if( rc ){ 2152 pCur->pPage = pCur->apPage[--pCur->iPage]; 2153@@ -77032,7 +77552,13 @@ static int allocateBtreePage( 2154 n = get4byte(&pPage1->aData[36]); 2155 testcase( n==mxPage-1 ); 2156 if( n>=mxPage ){ 2157- return SQLITE_CORRUPT_BKPT; 2158+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 2159+ char xBuffer[SQLITE_PRINT_BUF_SIZE*3] = {0}; 2160+ (void)sqlite3base16Encode(pPage1->aData, 100, xBuffer, sizeof(xBuffer)); 2161+ sqlite3_snprintf(sizeof(zMsg), zMsg, 2162+ "total pages(%u) in freelist should not over the total size of db file(%u), base16:%s", n, mxPage, xBuffer); 2163+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, 1, CORRUPT_TYPE_FILE_HEADER, 36, 4, zMsg, NULL); 2164+ return SQLITE_CORRUPT_REPORT(&context); 2165 } 2166 if( n>0 ){ 2167 /* There are pages on the freelist. Reuse one of those pages. */ 2168@@ -77088,7 +77614,12 @@ static int allocateBtreePage( 2169 } 2170 testcase( iTrunk==mxPage ); 2171 if( iTrunk>mxPage || nSearch++ > n ){ 2172- rc = SQLITE_CORRUPT_PGNO(pPrevTrunk ? pPrevTrunk->pgno : 1); 2173+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 2174+ sqlite3_snprintf(sizeof(zMsg), zMsg, "freelist trunk page(%u) should <= the size of db(%u)", 2175+ iTrunk, mxPage); 2176+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, (pPrevTrunk ? pPrevTrunk->pgno : 1), 2177+ CORRUPT_TYPE_PAGE_FREE_LIST, -1, 0, zMsg, NULL); 2178+ rc = SQLITE_CORRUPT_REPORT_PGNO(&context); 2179 }else{ 2180 rc = btreeGetUnusedPage(pBt, iTrunk, &pTrunk, 0); 2181 } 2182@@ -77117,7 +77648,14 @@ static int allocateBtreePage( 2183 TRACE(("ALLOCATE: %u trunk - %u free pages left\n", *pPgno, n-1)); 2184 }else if( k>(u32)(pBt->usableSize/4 - 2) ){ 2185 /* Value of k is out of range. Database corruption */ 2186- rc = SQLITE_CORRUPT_PGNO(iTrunk); 2187+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 2188+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; 2189+ (void)sqlite3base16Encode(pTrunk->aData, 8, xBuffer, sizeof(xBuffer)); 2190+ sqlite3_snprintf(sizeof(zMsg), zMsg, "total leaf pages(%u) on trunk page over limit(%u), base16:%s", 2191+ k, (u32)(pBt->usableSize/4 - 2), xBuffer); 2192+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, iTrunk, CORRUPT_TYPE_PAGE_FREE_LIST, 2193+ 0, 8, zMsg, NULL); 2194+ rc = SQLITE_CORRUPT_REPORT_PGNO(&context); 2195 goto end_allocate_page; 2196 #ifndef SQLITE_OMIT_AUTOVACUUM 2197 }else if( searchList 2198@@ -77151,7 +77689,14 @@ static int allocateBtreePage( 2199 MemPage *pNewTrunk; 2200 Pgno iNewTrunk = get4byte(&pTrunk->aData[8]); 2201 if( iNewTrunk>mxPage ){ 2202- rc = SQLITE_CORRUPT_PGNO(iTrunk); 2203+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 2204+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; 2205+ (void)sqlite3base16Encode(pTrunk->aData, 12, xBuffer, sizeof(xBuffer)); 2206+ sqlite3_snprintf(sizeof(zMsg), zMsg, 2207+ "leaf page's pgno(%u) on trunk page exceed db file size(%u), base16:%s", iNewTrunk, mxPage, xBuffer); 2208+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, iTrunk, CORRUPT_TYPE_PAGE_FREE_LIST, 2209+ 8, 4, zMsg, NULL); 2210+ rc = SQLITE_CORRUPT_REPORT_PGNO(&context); 2211 goto end_allocate_page; 2212 } 2213 testcase( iNewTrunk==mxPage ); 2214@@ -77216,7 +77761,14 @@ static int allocateBtreePage( 2215 iPage = get4byte(&aData[8+closest*4]); 2216 testcase( iPage==mxPage ); 2217 if( iPage>mxPage || iPage<2 ){ 2218- rc = SQLITE_CORRUPT_PGNO(iTrunk); 2219+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 2220+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; 2221+ (void)sqlite3base16Encode(aData+8+closest*4, 4, xBuffer, sizeof(xBuffer)); 2222+ sqlite3_snprintf(sizeof(zMsg), zMsg, "leaf page's pgno(%u) out of range:[3, %d], base16:%s", 2223+ iPage, mxPage, xBuffer); 2224+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(mxPage, iTrunk, CORRUPT_TYPE_PAGE_FREE_LIST, 2225+ 8+closest*4, 4, zMsg, NULL); 2226+ rc = SQLITE_CORRUPT_REPORT_PGNO(&context); 2227 goto end_allocate_page; 2228 } 2229 testcase( iPage==mxPage ); 2230@@ -77401,7 +77953,14 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){ 2231 nLeaf = get4byte(&pTrunk->aData[4]); 2232 assert( pBt->usableSize>32 ); 2233 if( nLeaf > (u32)pBt->usableSize/4 - 2 ){ 2234- rc = SQLITE_CORRUPT_BKPT; 2235+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 2236+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; 2237+ (void)sqlite3base16Encode(pTrunk->aData, 4, xBuffer, sizeof(xBuffer)); 2238+ sqlite3_snprintf(sizeof(zMsg), zMsg, "the number of leaf page(%u) on trunk page(%d) exceed limit, base16:%s", 2239+ nLeaf, iTrunk, xBuffer); 2240+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pBt->nPage, iTrunk, CORRUPT_TYPE_PAGE_FREE_LIST, 2241+ 0, 4, zMsg, NULL); 2242+ rc = SQLITE_CORRUPT_REPORT(&context); 2243 goto freepage_out; 2244 } 2245 if( nLeaf < (u32)pBt->usableSize/4 - 8 ){ 2246@@ -77490,7 +78049,12 @@ static SQLITE_NOINLINE int clearCellOverflow( 2247 testcase( pCell + (pInfo->nSize-1) == pPage->aDataEnd ); 2248 if( pCell + pInfo->nSize > pPage->aDataEnd ){ 2249 /* Cell extends past end of page */ 2250- return SQLITE_CORRUPT_PAGE(pPage); 2251+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 2252+ sqlite3_snprintf(sizeof(zMsg), zMsg, "overflow end of page, pgno:%u, offset:%d, size:%u, usableSize:%u", 2253+ pPage->pgno, (int)(pCell - pPage->aData), pInfo->nSize, pPage->pBt->usableSize); 2254+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(btreePagecount(pPage->pBt), pPage->pgno, 2255+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); 2256+ return SQLITE_CORRUPT_PAGE(&context, pPage); 2257 } 2258 ovflPgno = get4byte(pCell + pInfo->nSize - 4); 2259 pBt = pPage->pBt; 2260@@ -77507,7 +78071,14 @@ static SQLITE_NOINLINE int clearCellOverflow( 2261 /* 0 is not a legal page number and page 1 cannot be an 2262 ** overflow page. Therefore if ovflPgno<2 or past the end of the 2263 ** file the database must be corrupt. */ 2264- return SQLITE_CORRUPT_BKPT; 2265+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 2266+ char xBuffer[SQLITE_PRINT_BUF_SIZE] = {0}; 2267+ (void)sqlite3base16Encode(pCell + pInfo->nSize - 4, 4, xBuffer, sizeof(xBuffer)); 2268+ sqlite3_snprintf(sizeof(zMsg), zMsg, "overflow page's pgno(%u) illegal, out of range:[2, %u], base16:%s", 2269+ ovflPgno, btreePagecount(pBt), xBuffer); 2270+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(btreePagecount(pBt), pPage->pgno, 2271+ CORRUPT_TYPE_PAGE_BTREE_LEAF, -1, 0, zMsg, NULL); 2272+ return SQLITE_CORRUPT_REPORT(&context); 2273 } 2274 if( nOvfl ){ 2275 rc = getOverflowPage(pBt, ovflPgno, &pOvfl, &iNext); 2276@@ -77780,7 +78351,12 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){ 2277 testcase( pc==(u32)get2byte(&data[hdr+5]) ); 2278 testcase( pc+sz==pPage->pBt->usableSize ); 2279 if( pc+sz > pPage->pBt->usableSize ){ 2280- *pRC = SQLITE_CORRUPT_BKPT; 2281+ char zMsg[SQLITE_PRINT_CORRUPT_SIZE] = {0}; 2282+ sqlite3_snprintf(sizeof(zMsg), zMsg, "cell offset:%u size:%d, idx:%d overflow, usableSize:%u", 2283+ pc, sz, idx, pPage->pBt->usableSize); 2284+ sqlite3CorruptContext context = SQLITE_CORRUPT_CONTEXT(pPage->pBt->nPage, pPage->pgno, CORRUPT_TYPE_PAGE_BTREE_LEAF, 2285+ -1, 0, zMsg, NULL); 2286+ *pRC = SQLITE_CORRUPT_REPORT(&context); 2287 return; 2288 } 2289 rc = freeSpace(pPage, pc, sz); 2290@@ -85096,7 +85672,7 @@ static int growOpArray(Vdbe *v, int nOp){ 2291 ** 2292 ** Other useful labels for breakpoints include: 2293 ** test_trace_breakpoint(pc,pOp) 2294-** sqlite3CorruptError(lineno) 2295+** sqlite3CorruptError(lineno,context) 2296 ** sqlite3MisuseError(lineno) 2297 ** sqlite3CantopenError(lineno) 2298 */ 2299@@ -93316,7 +93892,7 @@ SQLITE_API int sqlite3_found_count = 0; 2300 ** 2301 ** Other useful labels for breakpoints include: 2302 ** test_addop_breakpoint(pc,pOp) 2303-** sqlite3CorruptError(lineno) 2304+** sqlite3CorruptError(lineno,context) 2305 ** sqlite3MisuseError(lineno) 2306 ** sqlite3CantopenError(lineno) 2307 */ 2308@@ -93686,7 +94262,6 @@ static u16 numericType(Mem *pMem){ 2309 testcase( pMem->flags & MEM_Str ); 2310 testcase( pMem->flags & MEM_Blob ); 2311 return computeNumericType(pMem); 2312- return 0; 2313 } 2314 2315 #ifdef SQLITE_DEBUG 2316@@ -179837,6 +180412,12 @@ SQLITE_API int sqlite3_config(int op, ...){ 2317 #endif 2318 break; 2319 } 2320+ case SQLITE_CONFIG_CORRUPTION: { 2321+ typedef void(*CORRUPTION_FUNC_t)(void*, const void*); 2322+ sqlite3GlobalConfig.xCorruption = va_arg(ap, CORRUPTION_FUNC_t); 2323+ sqlite3GlobalConfig.pCorruptionArg = va_arg(ap, void*); 2324+ break; 2325+ } 2326 2327 default: { 2328 rc = SQLITE_ERROR; 2329@@ -183021,9 +183602,21 @@ SQLITE_PRIVATE int sqlite3ReportError(int iErr, int lineno, const char *zType){ 2330 zType, lineno, 20+sqlite3_sourceid()); 2331 return iErr; 2332 } 2333-SQLITE_PRIVATE int sqlite3CorruptError(int lineno){ 2334+SQLITE_PRIVATE int sqlite3CorruptError(int lineno, sqlite3CorruptContext *context){ 2335 testcase( sqlite3GlobalConfig.xLog!=0 ); 2336- return sqlite3ReportError(SQLITE_CORRUPT, lineno, "database corruption"); 2337+ if (context!=NULL && sqlite3GlobalConfig.xCorruption != 0) { 2338+ char zMsg[SQLITE_PRINT_BUF_SIZE] = {0}; /* Complete corruption log message */ 2339+ sqlite3_snprintf(sizeof(zMsg), zMsg, "pgno:%u,type:%d,range:{%d,%d},line:%d", 2340+ context->pgno, (int)context->type, (int)context->zoneRange.offset, (int)context->zoneRange.size, lineno); 2341+ sqlite3GlobalConfig.xCorruption(sqlite3GlobalConfig.pCorruptionArg, zMsg); 2342+ } 2343+ char zCorruptMsg[SQLITE_PRINT_BUF_SIZE * 10] = {0}; 2344+ if (context!=NULL && context->zMsg != NULL){ 2345+ sqlite3_snprintf(sizeof(zCorruptMsg), zCorruptMsg, "database corruption, %s", context->zMsg); 2346+ } else { 2347+ sqlite3_snprintf(sizeof(zCorruptMsg), zCorruptMsg, "database corruption"); 2348+ } 2349+ return sqlite3ReportError(SQLITE_CORRUPT, lineno, zCorruptMsg); 2350 } 2351 SQLITE_PRIVATE int sqlite3MisuseError(int lineno){ 2352 testcase( sqlite3GlobalConfig.xLog!=0 ); 2353@@ -183245,12 +183838,16 @@ SQLITE_API int sqlite3_file_control(sqlite3 *db, const char *zDbName, int op, vo 2354 *(unsigned int*)pArg = sqlite3PagerDataVersion(pPager); 2355 rc = SQLITE_OK; 2356 }else if( op==SQLITE_FCNTL_RESERVE_BYTES ){ 2357+#ifndef SQLITE_CKSUMVFS_STATIC 2358+ rc = SQLITE_OK; 2359+#else 2360 int iNew = *(int*)pArg; 2361 *(int*)pArg = sqlite3BtreeGetRequestedReserve(pBtree); 2362 if( iNew>=0 && iNew<=255 ){ 2363 sqlite3BtreeSetPageSize(pBtree, 0, iNew, 0); 2364 } 2365 rc = SQLITE_OK; 2366+#endif 2367 }else if( op==SQLITE_FCNTL_RESET_CACHE ){ 2368 sqlite3BtreeClearCache(pBtree); 2369 rc = SQLITE_OK; 2370@@ -255862,10 +256459,11 @@ static int MetaDwrCheckMeta(Btree *pBt) { 2371 } 2372 if (rc != SQLITE_OK) { 2373 sqlite3_log(rc, "Meta integrity check go wrong"); 2374+ sqlite3_free(errStr); 2375 return rc; 2376 } 2377- sqlite3_log(SQLITE_WARNING_DUMP, "Meta integrity check %s", errStr); 2378- sqlite3DbFree(pBt->db, errStr); 2379+ sqlite3_log(SQLITE_WARNING_DUMP, "Integrity check %s", errStr); 2380+ sqlite3_free(errStr); 2381 return SQLITE_CORRUPT; 2382 } 2383 2384@@ -256317,6 +256915,26 @@ static void walLogCheckpointInfo(Wal *pWal, sqlite3 *db, sqlite3_int64 startTime 2385 2386 // export the symbols 2387 #ifdef SQLITE_EXPORT_SYMBOLS 2388+#ifndef SQLITE_CKSUMVFS_STATIC 2389+int sqlite3_register_cksumvfs(const char *NotUsed){ 2390+ return SQLITE_MISUSE; 2391+} 2392+int sqlite3_unregister_cksumvfs(void){ 2393+ return SQLITE_MISUSE; 2394+} 2395+ 2396+struct sqlite3_api_routines_cksumvfs { 2397+ int (*register_cksumvfs)(const char *); 2398+ int (*unregister_cksumvfs)(); 2399+}; 2400+typedef struct sqlite3_api_routines_cksumvfs sqlite3_api_routines_cksumvfs; 2401+static const sqlite3_api_routines_cksumvfs sqlite3CksumvfsApis = { 2402+ sqlite3_register_cksumvfs, 2403+ sqlite3_unregister_cksumvfs 2404+}; 2405+ 2406+EXPORT_SYMBOLS const sqlite3_api_routines_cksumvfs *sqlite3_export_cksumvfs_symbols = &sqlite3CksumvfsApis; 2407+#endif 2408 struct sqlite3_api_routines_extra { 2409 int (*initialize)(); 2410 int (*config)(int,...); 2411-- 24122.47.0.windows.2 2413 2414