• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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