xref: /sqlite-3.40.0/test/dbfuzz.c (revision 134e5270)
16918e2f9Sdrh /*
26918e2f9Sdrh ** 2016-12-17
36918e2f9Sdrh **
46918e2f9Sdrh ** The author disclaims copyright to this source code.  In place of
56918e2f9Sdrh ** a legal notice, here is a blessing:
66918e2f9Sdrh **
76918e2f9Sdrh **    May you do good and not evil.
86918e2f9Sdrh **    May you find forgiveness for yourself and forgive others.
96918e2f9Sdrh **    May you share freely, never taking more than you give.
106918e2f9Sdrh **
116918e2f9Sdrh *************************************************************************
126918e2f9Sdrh **
136918e2f9Sdrh ** This program is designed for fuzz-testing SQLite database files.
146918e2f9Sdrh **
156918e2f9Sdrh ** This program reads fuzzed database files from the disk files named
166918e2f9Sdrh ** on the command-line.  Each database is loaded into an in-memory
176918e2f9Sdrh ** filesystem so that the original database file is unmolested.
186918e2f9Sdrh **
196918e2f9Sdrh ** The fuzzed database is then opened, and series of SQL statements
206918e2f9Sdrh ** are run against the database to ensure that SQLite can safely handle
216918e2f9Sdrh ** the fuzzed database.
226918e2f9Sdrh */
2322d709ddSdrh #include <assert.h>
246918e2f9Sdrh #include <stdio.h>
256918e2f9Sdrh #include <stdlib.h>
266918e2f9Sdrh #include <string.h>
276918e2f9Sdrh #include <stdarg.h>
286918e2f9Sdrh #include <ctype.h>
296918e2f9Sdrh #define ISSPACE(X) isspace((unsigned char)(X))
306918e2f9Sdrh #define ISDIGIT(X) isdigit((unsigned char)(X))
316918e2f9Sdrh #include "sqlite3.h"
326918e2f9Sdrh #ifdef __unix__
336918e2f9Sdrh # include <signal.h>
346918e2f9Sdrh # include <unistd.h>
356918e2f9Sdrh #endif
366918e2f9Sdrh 
376918e2f9Sdrh /*
386918e2f9Sdrh ** Print sketchy documentation for this utility program
396918e2f9Sdrh */
showHelp(const char * zArgv0)406918e2f9Sdrh static void showHelp(const char *zArgv0){
416918e2f9Sdrh   printf("Usage: %s [options] DATABASE ...\n", zArgv0);
426918e2f9Sdrh   printf(
436918e2f9Sdrh "Read databases into an in-memory filesystem.  Run test SQL as specified\n"
446918e2f9Sdrh "by command-line arguments or from\n"
456918e2f9Sdrh "\n"
466918e2f9Sdrh "    SELECT group_concat(sql) FROM autoexec;\n"
476918e2f9Sdrh "\n"
486918e2f9Sdrh "Options:\n"
496918e2f9Sdrh "  --help              Show this help text\n"
506918e2f9Sdrh "  -q|--quiet          Reduced output\n"
516918e2f9Sdrh "  --limit-mem N       Limit memory used by test SQLite instances to N bytes\n"
526918e2f9Sdrh "  --limit-vdbe        Panic if any test runs for more than 100,000 cycles\n"
536918e2f9Sdrh "  --no-lookaside      Disable the lookaside memory allocator\n"
546918e2f9Sdrh "  --timeout N         Timeout after N seconds.\n"
556918e2f9Sdrh "  --trace             Show the results of each SQL command\n"
566918e2f9Sdrh "  -v|--verbose        Increased output.  Repeat for more output.\n"
576918e2f9Sdrh   );
586918e2f9Sdrh   exit(0);
596918e2f9Sdrh }
606918e2f9Sdrh 
616918e2f9Sdrh /*
626918e2f9Sdrh ** Print an error message and quit.
636918e2f9Sdrh */
fatalError(const char * zFormat,...)646918e2f9Sdrh static void fatalError(const char *zFormat, ...){
656918e2f9Sdrh   va_list ap;
666918e2f9Sdrh   va_start(ap, zFormat);
676918e2f9Sdrh   vfprintf(stderr, zFormat, ap);
686918e2f9Sdrh   va_end(ap);
696918e2f9Sdrh   fprintf(stderr, "\n");
706918e2f9Sdrh   exit(1);
716918e2f9Sdrh }
726918e2f9Sdrh 
736918e2f9Sdrh /*
746918e2f9Sdrh ** Files in the virtual file system.
756918e2f9Sdrh */
766918e2f9Sdrh typedef struct VFile VFile;
776918e2f9Sdrh typedef struct VHandle VHandle;
786918e2f9Sdrh struct VFile {
796918e2f9Sdrh   char *zFilename;      /* Filename. NULL for delete-on-close. From malloc() */
806918e2f9Sdrh   int sz;               /* Size of the file in bytes */
816918e2f9Sdrh   int nRef;             /* Number of references to this file */
826918e2f9Sdrh   unsigned char *a;     /* Content of the file.  From malloc() */
836918e2f9Sdrh };
846918e2f9Sdrh struct VHandle {
856918e2f9Sdrh   sqlite3_file base;    /* Base class.  Must be first */
866918e2f9Sdrh   VFile *pVFile;        /* The underlying file */
876918e2f9Sdrh };
886918e2f9Sdrh 
896918e2f9Sdrh /*
906918e2f9Sdrh ** Maximum number of files in the in-memory virtual filesystem.
916918e2f9Sdrh */
926918e2f9Sdrh #define MX_FILE  10
936918e2f9Sdrh 
946918e2f9Sdrh /*
956918e2f9Sdrh ** Maximum allowed file size
966918e2f9Sdrh */
976918e2f9Sdrh #define MX_FILE_SZ 1000000
986918e2f9Sdrh 
996918e2f9Sdrh /*
1006918e2f9Sdrh ** All global variables are gathered into the "g" singleton.
1016918e2f9Sdrh */
1026918e2f9Sdrh static struct GlobalVars {
1036918e2f9Sdrh   VFile aFile[MX_FILE];            /* The virtual filesystem */
1046918e2f9Sdrh } g;
1056918e2f9Sdrh 
1066918e2f9Sdrh 
1076918e2f9Sdrh /*
1086918e2f9Sdrh ** Initialize the virtual file system.
1096918e2f9Sdrh */
formatVfs(void)1106918e2f9Sdrh static void formatVfs(void){
1116918e2f9Sdrh   int i;
1126918e2f9Sdrh   for(i=0; i<MX_FILE; i++){
1136918e2f9Sdrh     g.aFile[i].sz = -1;
1146918e2f9Sdrh     g.aFile[i].zFilename = 0;
1156918e2f9Sdrh     g.aFile[i].a = 0;
1166918e2f9Sdrh     g.aFile[i].nRef = 0;
1176918e2f9Sdrh   }
1186918e2f9Sdrh }
1196918e2f9Sdrh 
1206918e2f9Sdrh 
1216918e2f9Sdrh /*
1226918e2f9Sdrh ** Erase all information in the virtual file system.
1236918e2f9Sdrh */
reformatVfs(void)1246918e2f9Sdrh static void reformatVfs(void){
1256918e2f9Sdrh   int i;
1266918e2f9Sdrh   for(i=0; i<MX_FILE; i++){
1276918e2f9Sdrh     if( g.aFile[i].sz<0 ) continue;
1286918e2f9Sdrh     if( g.aFile[i].zFilename ){
1296918e2f9Sdrh       free(g.aFile[i].zFilename);
1306918e2f9Sdrh       g.aFile[i].zFilename = 0;
1316918e2f9Sdrh     }
1326918e2f9Sdrh     if( g.aFile[i].nRef>0 ){
1336918e2f9Sdrh       fatalError("file %d still open.  nRef=%d", i, g.aFile[i].nRef);
1346918e2f9Sdrh     }
1356918e2f9Sdrh     g.aFile[i].sz = -1;
1366918e2f9Sdrh     free(g.aFile[i].a);
1376918e2f9Sdrh     g.aFile[i].a = 0;
1386918e2f9Sdrh     g.aFile[i].nRef = 0;
1396918e2f9Sdrh   }
1406918e2f9Sdrh }
1416918e2f9Sdrh 
1426918e2f9Sdrh /*
1436918e2f9Sdrh ** Find a VFile by name
1446918e2f9Sdrh */
findVFile(const char * zName)1456918e2f9Sdrh static VFile *findVFile(const char *zName){
1466918e2f9Sdrh   int i;
1476918e2f9Sdrh   if( zName==0 ) return 0;
1486918e2f9Sdrh   for(i=0; i<MX_FILE; i++){
1496918e2f9Sdrh     if( g.aFile[i].zFilename==0 ) continue;
1506918e2f9Sdrh     if( strcmp(g.aFile[i].zFilename, zName)==0 ) return &g.aFile[i];
1516918e2f9Sdrh   }
1526918e2f9Sdrh   return 0;
1536918e2f9Sdrh }
1546918e2f9Sdrh 
1556918e2f9Sdrh /*
1566918e2f9Sdrh ** Find a VFile called zName.  Initialize it to the content of
1576918e2f9Sdrh ** disk file zDiskFile.
1586918e2f9Sdrh **
1596918e2f9Sdrh ** Return NULL if the filesystem is full.
1606918e2f9Sdrh */
createVFile(const char * zName,const char * zDiskFile)1616918e2f9Sdrh static VFile *createVFile(const char *zName, const char *zDiskFile){
1626918e2f9Sdrh   VFile *pNew = findVFile(zName);
1636918e2f9Sdrh   int i;
1646918e2f9Sdrh   FILE *in = 0;
1656918e2f9Sdrh   long sz = 0;
1666918e2f9Sdrh 
1676918e2f9Sdrh   if( pNew ) return pNew;
1686918e2f9Sdrh   for(i=0; i<MX_FILE && g.aFile[i].sz>=0; i++){}
1696918e2f9Sdrh   if( i>=MX_FILE ) return 0;
1706918e2f9Sdrh   if( zDiskFile ){
1716918e2f9Sdrh     in = fopen(zDiskFile, "rb");
1726918e2f9Sdrh     if( in==0 ) fatalError("no such file: \"%s\"", zDiskFile);
1736918e2f9Sdrh     fseek(in, 0, SEEK_END);
1746918e2f9Sdrh     sz = ftell(in);
1756918e2f9Sdrh     rewind(in);
1766918e2f9Sdrh   }
1776918e2f9Sdrh   pNew = &g.aFile[i];
1786918e2f9Sdrh   if( zName ){
1796918e2f9Sdrh     int nName = (int)strlen(zName)+1;
1806918e2f9Sdrh     pNew->zFilename = malloc(nName);
1816918e2f9Sdrh     if( pNew->zFilename==0 ){
1826918e2f9Sdrh       if( in ) fclose(in);
1836918e2f9Sdrh       return 0;
1846918e2f9Sdrh     }
1856918e2f9Sdrh     memcpy(pNew->zFilename, zName, nName);
1866918e2f9Sdrh   }else{
1876918e2f9Sdrh     pNew->zFilename = 0;
1886918e2f9Sdrh   }
1896918e2f9Sdrh   pNew->nRef = 0;
1906918e2f9Sdrh   pNew->sz = sz;
1916918e2f9Sdrh   pNew->a = malloc(sz);
1926918e2f9Sdrh   if( sz>0 ){
1936918e2f9Sdrh     if( pNew->a==0 || fread(pNew->a, sz, 1, in)<1 ){
1946918e2f9Sdrh       free(pNew->zFilename);
1956918e2f9Sdrh       free(pNew->a);
1966918e2f9Sdrh       pNew->a = 0;
1976918e2f9Sdrh       pNew->zFilename = 0;
1986918e2f9Sdrh       pNew->sz = -1;
1996918e2f9Sdrh       pNew = 0;
2006918e2f9Sdrh     }
2016918e2f9Sdrh   }
2026918e2f9Sdrh   if( in ) fclose(in);
2036918e2f9Sdrh   return pNew;
2046918e2f9Sdrh }
2056918e2f9Sdrh 
2066918e2f9Sdrh /* Methods for the VHandle object
2076918e2f9Sdrh */
inmemClose(sqlite3_file * pFile)2086918e2f9Sdrh static int inmemClose(sqlite3_file *pFile){
2096918e2f9Sdrh   VHandle *p = (VHandle*)pFile;
2106918e2f9Sdrh   VFile *pVFile = p->pVFile;
2116918e2f9Sdrh   pVFile->nRef--;
2126918e2f9Sdrh   if( pVFile->nRef==0 && pVFile->zFilename==0 ){
2136918e2f9Sdrh     pVFile->sz = -1;
2146918e2f9Sdrh     free(pVFile->a);
2156918e2f9Sdrh     pVFile->a = 0;
2166918e2f9Sdrh   }
2176918e2f9Sdrh   return SQLITE_OK;
2186918e2f9Sdrh }
inmemRead(sqlite3_file * pFile,void * pData,int iAmt,sqlite3_int64 iOfst)2196918e2f9Sdrh static int inmemRead(
2206918e2f9Sdrh   sqlite3_file *pFile,   /* Read from this open file */
2216918e2f9Sdrh   void *pData,           /* Store content in this buffer */
2226918e2f9Sdrh   int iAmt,              /* Bytes of content */
2236918e2f9Sdrh   sqlite3_int64 iOfst    /* Start reading here */
2246918e2f9Sdrh ){
2256918e2f9Sdrh   VHandle *pHandle = (VHandle*)pFile;
2266918e2f9Sdrh   VFile *pVFile = pHandle->pVFile;
2276918e2f9Sdrh   if( iOfst<0 || iOfst>=pVFile->sz ){
2286918e2f9Sdrh     memset(pData, 0, iAmt);
2296918e2f9Sdrh     return SQLITE_IOERR_SHORT_READ;
2306918e2f9Sdrh   }
2316918e2f9Sdrh   if( iOfst+iAmt>pVFile->sz ){
2326918e2f9Sdrh     memset(pData, 0, iAmt);
2336918e2f9Sdrh     iAmt = (int)(pVFile->sz - iOfst);
2346918e2f9Sdrh     memcpy(pData, pVFile->a, iAmt);
2356918e2f9Sdrh     return SQLITE_IOERR_SHORT_READ;
2366918e2f9Sdrh   }
2376918e2f9Sdrh   memcpy(pData, pVFile->a + iOfst, iAmt);
2386918e2f9Sdrh   return SQLITE_OK;
2396918e2f9Sdrh }
inmemWrite(sqlite3_file * pFile,const void * pData,int iAmt,sqlite3_int64 iOfst)2406918e2f9Sdrh static int inmemWrite(
2416918e2f9Sdrh   sqlite3_file *pFile,   /* Write to this file */
2426918e2f9Sdrh   const void *pData,     /* Content to write */
2436918e2f9Sdrh   int iAmt,              /* bytes to write */
2446918e2f9Sdrh   sqlite3_int64 iOfst    /* Start writing here */
2456918e2f9Sdrh ){
2466918e2f9Sdrh   VHandle *pHandle = (VHandle*)pFile;
2476918e2f9Sdrh   VFile *pVFile = pHandle->pVFile;
2486918e2f9Sdrh   if( iOfst+iAmt > pVFile->sz ){
2496918e2f9Sdrh     unsigned char *aNew;
2506918e2f9Sdrh     if( iOfst+iAmt >= MX_FILE_SZ ){
2516918e2f9Sdrh       return SQLITE_FULL;
2526918e2f9Sdrh     }
2536918e2f9Sdrh     aNew = realloc(pVFile->a, (int)(iOfst+iAmt));
2546918e2f9Sdrh     if( aNew==0 ){
2556918e2f9Sdrh       return SQLITE_FULL;
2566918e2f9Sdrh     }
2576918e2f9Sdrh     pVFile->a = aNew;
2586918e2f9Sdrh     if( iOfst > pVFile->sz ){
2596918e2f9Sdrh       memset(pVFile->a + pVFile->sz, 0, (int)(iOfst - pVFile->sz));
2606918e2f9Sdrh     }
2616918e2f9Sdrh     pVFile->sz = (int)(iOfst + iAmt);
2626918e2f9Sdrh   }
2636918e2f9Sdrh   memcpy(pVFile->a + iOfst, pData, iAmt);
2646918e2f9Sdrh   return SQLITE_OK;
2656918e2f9Sdrh }
inmemTruncate(sqlite3_file * pFile,sqlite3_int64 iSize)2666918e2f9Sdrh static int inmemTruncate(sqlite3_file *pFile, sqlite3_int64 iSize){
2676918e2f9Sdrh   VHandle *pHandle = (VHandle*)pFile;
2686918e2f9Sdrh   VFile *pVFile = pHandle->pVFile;
2696918e2f9Sdrh   if( pVFile->sz>iSize && iSize>=0 ) pVFile->sz = (int)iSize;
2706918e2f9Sdrh   return SQLITE_OK;
2716918e2f9Sdrh }
inmemSync(sqlite3_file * pFile,int flags)2726918e2f9Sdrh static int inmemSync(sqlite3_file *pFile, int flags){
2736918e2f9Sdrh   return SQLITE_OK;
2746918e2f9Sdrh }
inmemFileSize(sqlite3_file * pFile,sqlite3_int64 * pSize)2756918e2f9Sdrh static int inmemFileSize(sqlite3_file *pFile, sqlite3_int64 *pSize){
2766918e2f9Sdrh   *pSize = ((VHandle*)pFile)->pVFile->sz;
2776918e2f9Sdrh   return SQLITE_OK;
2786918e2f9Sdrh }
inmemLock(sqlite3_file * pFile,int type)2796918e2f9Sdrh static int inmemLock(sqlite3_file *pFile, int type){
2806918e2f9Sdrh   return SQLITE_OK;
2816918e2f9Sdrh }
inmemUnlock(sqlite3_file * pFile,int type)2826918e2f9Sdrh static int inmemUnlock(sqlite3_file *pFile, int type){
2836918e2f9Sdrh   return SQLITE_OK;
2846918e2f9Sdrh }
inmemCheckReservedLock(sqlite3_file * pFile,int * pOut)2856918e2f9Sdrh static int inmemCheckReservedLock(sqlite3_file *pFile, int *pOut){
2866918e2f9Sdrh   *pOut = 0;
2876918e2f9Sdrh   return SQLITE_OK;
2886918e2f9Sdrh }
inmemFileControl(sqlite3_file * pFile,int op,void * pArg)2896918e2f9Sdrh static int inmemFileControl(sqlite3_file *pFile, int op, void *pArg){
2906918e2f9Sdrh   return SQLITE_NOTFOUND;
2916918e2f9Sdrh }
inmemSectorSize(sqlite3_file * pFile)2926918e2f9Sdrh static int inmemSectorSize(sqlite3_file *pFile){
2936918e2f9Sdrh   return 512;
2946918e2f9Sdrh }
inmemDeviceCharacteristics(sqlite3_file * pFile)2956918e2f9Sdrh static int inmemDeviceCharacteristics(sqlite3_file *pFile){
2966918e2f9Sdrh   return
2976918e2f9Sdrh       SQLITE_IOCAP_SAFE_APPEND |
2986918e2f9Sdrh       SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN |
2996918e2f9Sdrh       SQLITE_IOCAP_POWERSAFE_OVERWRITE;
3006918e2f9Sdrh }
3016918e2f9Sdrh 
3026918e2f9Sdrh 
3036918e2f9Sdrh /* Method table for VHandle
3046918e2f9Sdrh */
3056918e2f9Sdrh static sqlite3_io_methods VHandleMethods = {
3066918e2f9Sdrh   /* iVersion    */  1,
3076918e2f9Sdrh   /* xClose      */  inmemClose,
3086918e2f9Sdrh   /* xRead       */  inmemRead,
3096918e2f9Sdrh   /* xWrite      */  inmemWrite,
3106918e2f9Sdrh   /* xTruncate   */  inmemTruncate,
3116918e2f9Sdrh   /* xSync       */  inmemSync,
3126918e2f9Sdrh   /* xFileSize   */  inmemFileSize,
3136918e2f9Sdrh   /* xLock       */  inmemLock,
3146918e2f9Sdrh   /* xUnlock     */  inmemUnlock,
3156918e2f9Sdrh   /* xCheck...   */  inmemCheckReservedLock,
3166918e2f9Sdrh   /* xFileCtrl   */  inmemFileControl,
3176918e2f9Sdrh   /* xSectorSz   */  inmemSectorSize,
3186918e2f9Sdrh   /* xDevchar    */  inmemDeviceCharacteristics,
3196918e2f9Sdrh   /* xShmMap     */  0,
3206918e2f9Sdrh   /* xShmLock    */  0,
3216918e2f9Sdrh   /* xShmBarrier */  0,
3226918e2f9Sdrh   /* xShmUnmap   */  0,
3236918e2f9Sdrh   /* xFetch      */  0,
3246918e2f9Sdrh   /* xUnfetch    */  0
3256918e2f9Sdrh };
3266918e2f9Sdrh 
3276918e2f9Sdrh /*
3286918e2f9Sdrh ** Open a new file in the inmem VFS.  All files are anonymous and are
3296918e2f9Sdrh ** delete-on-close.
3306918e2f9Sdrh */
inmemOpen(sqlite3_vfs * pVfs,const char * zFilename,sqlite3_file * pFile,int openFlags,int * pOutFlags)3316918e2f9Sdrh static int inmemOpen(
3326918e2f9Sdrh   sqlite3_vfs *pVfs,
3336918e2f9Sdrh   const char *zFilename,
3346918e2f9Sdrh   sqlite3_file *pFile,
3356918e2f9Sdrh   int openFlags,
3366918e2f9Sdrh   int *pOutFlags
3376918e2f9Sdrh ){
3386918e2f9Sdrh   VFile *pVFile = createVFile(zFilename, 0);
3396918e2f9Sdrh   VHandle *pHandle = (VHandle*)pFile;
3406918e2f9Sdrh   if( pVFile==0 ){
3416918e2f9Sdrh     return SQLITE_FULL;
3426918e2f9Sdrh   }
3436918e2f9Sdrh   pHandle->pVFile = pVFile;
3446918e2f9Sdrh   pVFile->nRef++;
3456918e2f9Sdrh   pFile->pMethods = &VHandleMethods;
3466918e2f9Sdrh   if( pOutFlags ) *pOutFlags = openFlags;
3476918e2f9Sdrh   return SQLITE_OK;
3486918e2f9Sdrh }
3496918e2f9Sdrh 
3506918e2f9Sdrh /*
3516918e2f9Sdrh ** Delete a file by name
3526918e2f9Sdrh */
inmemDelete(sqlite3_vfs * pVfs,const char * zFilename,int syncdir)3536918e2f9Sdrh static int inmemDelete(
3546918e2f9Sdrh   sqlite3_vfs *pVfs,
3556918e2f9Sdrh   const char *zFilename,
3566918e2f9Sdrh   int syncdir
3576918e2f9Sdrh ){
3586918e2f9Sdrh   VFile *pVFile = findVFile(zFilename);
3596918e2f9Sdrh   if( pVFile==0 ) return SQLITE_OK;
3606918e2f9Sdrh   if( pVFile->nRef==0 ){
3616918e2f9Sdrh     free(pVFile->zFilename);
3626918e2f9Sdrh     pVFile->zFilename = 0;
3636918e2f9Sdrh     pVFile->sz = -1;
3646918e2f9Sdrh     free(pVFile->a);
3656918e2f9Sdrh     pVFile->a = 0;
3666918e2f9Sdrh     return SQLITE_OK;
3676918e2f9Sdrh   }
3686918e2f9Sdrh   return SQLITE_IOERR_DELETE;
3696918e2f9Sdrh }
3706918e2f9Sdrh 
3716918e2f9Sdrh /* Check for the existance of a file
3726918e2f9Sdrh */
inmemAccess(sqlite3_vfs * pVfs,const char * zFilename,int flags,int * pResOut)3736918e2f9Sdrh static int inmemAccess(
3746918e2f9Sdrh   sqlite3_vfs *pVfs,
3756918e2f9Sdrh   const char *zFilename,
3766918e2f9Sdrh   int flags,
3776918e2f9Sdrh   int *pResOut
3786918e2f9Sdrh ){
3796918e2f9Sdrh   VFile *pVFile = findVFile(zFilename);
3806918e2f9Sdrh   *pResOut =  pVFile!=0;
3816918e2f9Sdrh   return SQLITE_OK;
3826918e2f9Sdrh }
3836918e2f9Sdrh 
3846918e2f9Sdrh /* Get the canonical pathname for a file
3856918e2f9Sdrh */
inmemFullPathname(sqlite3_vfs * pVfs,const char * zFilename,int nOut,char * zOut)3866918e2f9Sdrh static int inmemFullPathname(
3876918e2f9Sdrh   sqlite3_vfs *pVfs,
3886918e2f9Sdrh   const char *zFilename,
3896918e2f9Sdrh   int nOut,
3906918e2f9Sdrh   char *zOut
3916918e2f9Sdrh ){
3926918e2f9Sdrh   sqlite3_snprintf(nOut, zOut, "%s", zFilename);
3936918e2f9Sdrh   return SQLITE_OK;
3946918e2f9Sdrh }
3956918e2f9Sdrh 
3966918e2f9Sdrh /*
3976918e2f9Sdrh ** Register the VFS that reads from the g.aFile[] set of files.
3986918e2f9Sdrh */
inmemVfsRegister(void)3996918e2f9Sdrh static void inmemVfsRegister(void){
4006918e2f9Sdrh   static sqlite3_vfs inmemVfs;
4016918e2f9Sdrh   sqlite3_vfs *pDefault = sqlite3_vfs_find(0);
4026918e2f9Sdrh   inmemVfs.iVersion = 3;
4036918e2f9Sdrh   inmemVfs.szOsFile = sizeof(VHandle);
4046918e2f9Sdrh   inmemVfs.mxPathname = 200;
4056918e2f9Sdrh   inmemVfs.zName = "inmem";
4066918e2f9Sdrh   inmemVfs.xOpen = inmemOpen;
4076918e2f9Sdrh   inmemVfs.xDelete = inmemDelete;
4086918e2f9Sdrh   inmemVfs.xAccess = inmemAccess;
4096918e2f9Sdrh   inmemVfs.xFullPathname = inmemFullPathname;
4106918e2f9Sdrh   inmemVfs.xRandomness = pDefault->xRandomness;
4116918e2f9Sdrh   inmemVfs.xSleep = pDefault->xSleep;
4126918e2f9Sdrh   inmemVfs.xCurrentTimeInt64 = pDefault->xCurrentTimeInt64;
4136918e2f9Sdrh   sqlite3_vfs_register(&inmemVfs, 0);
4146918e2f9Sdrh };
4156918e2f9Sdrh 
4166918e2f9Sdrh /*
4176918e2f9Sdrh ** Timeout handler
4186918e2f9Sdrh */
4196918e2f9Sdrh #ifdef __unix__
timeoutHandler(int NotUsed)4206918e2f9Sdrh static void timeoutHandler(int NotUsed){
4216918e2f9Sdrh   (void)NotUsed;
4226918e2f9Sdrh   fatalError("timeout\n");
4236918e2f9Sdrh }
4246918e2f9Sdrh #endif
4256918e2f9Sdrh 
4266918e2f9Sdrh /*
4276918e2f9Sdrh ** Set the an alarm to go off after N seconds.  Disable the alarm
4286918e2f9Sdrh ** if N==0
4296918e2f9Sdrh */
setAlarm(int N)4306918e2f9Sdrh static void setAlarm(int N){
4316918e2f9Sdrh #ifdef __unix__
4326918e2f9Sdrh   alarm(N);
4336918e2f9Sdrh #else
4346918e2f9Sdrh   (void)N;
4356918e2f9Sdrh #endif
4366918e2f9Sdrh }
4376918e2f9Sdrh /***************************************************************************
4386918e2f9Sdrh ** String accumulator object
4396918e2f9Sdrh */
4406918e2f9Sdrh typedef struct Str Str;
4416918e2f9Sdrh struct Str {
4426918e2f9Sdrh   char *z;                /* The string.  Memory from malloc() */
4436918e2f9Sdrh   sqlite3_uint64 n;       /* Bytes of input used */
4446918e2f9Sdrh   sqlite3_uint64 nAlloc;  /* Bytes allocated to z[] */
4456918e2f9Sdrh   int oomErr;             /* OOM error has been seen */
4466918e2f9Sdrh };
4476918e2f9Sdrh 
4486918e2f9Sdrh /* Initialize a Str object */
StrInit(Str * p)4496918e2f9Sdrh static void StrInit(Str *p){
4506918e2f9Sdrh   memset(p, 0, sizeof(*p));
4516918e2f9Sdrh }
4526918e2f9Sdrh 
4536918e2f9Sdrh /* Append text to the end of a Str object */
StrAppend(Str * p,const char * z)4546918e2f9Sdrh static void StrAppend(Str *p, const char *z){
4556918e2f9Sdrh   sqlite3_uint64 n = strlen(z);
4566918e2f9Sdrh   if( p->n + n >= p->nAlloc ){
4576918e2f9Sdrh     char *zNew;
4586918e2f9Sdrh     sqlite3_uint64 nNew;
4596918e2f9Sdrh     if( p->oomErr ) return;
4606918e2f9Sdrh     nNew = p->nAlloc*2 + 100 + n;
461*134e5270Sdrh     zNew = sqlite3_realloc64(p->z, nNew);
4626918e2f9Sdrh     if( zNew==0 ){
4636918e2f9Sdrh       sqlite3_free(p->z);
4646918e2f9Sdrh       memset(p, 0, sizeof(*p));
4656918e2f9Sdrh       p->oomErr = 1;
4666918e2f9Sdrh       return;
4676918e2f9Sdrh     }
4686918e2f9Sdrh     p->z = zNew;
4696918e2f9Sdrh     p->nAlloc = nNew;
4706918e2f9Sdrh   }
471*134e5270Sdrh   memcpy(p->z + p->n, z, (int)n);
4726918e2f9Sdrh   p->n += n;
4736918e2f9Sdrh   p->z[p->n] = 0;
4746918e2f9Sdrh }
4756918e2f9Sdrh 
4766918e2f9Sdrh /* Return the current string content */
StrStr(Str * p)4776918e2f9Sdrh static char *StrStr(Str *p){
4786918e2f9Sdrh  return p->z;
4796918e2f9Sdrh }
4806918e2f9Sdrh 
4816918e2f9Sdrh /* Free the string */
StrFree(Str * p)4826918e2f9Sdrh static void StrFree(Str *p){
4836918e2f9Sdrh   sqlite3_free(p->z);
4846918e2f9Sdrh   StrInit(p);
4856918e2f9Sdrh }
4866918e2f9Sdrh 
4876918e2f9Sdrh /*
4886918e2f9Sdrh ** Return the value of a hexadecimal digit.  Return -1 if the input
4896918e2f9Sdrh ** is not a hex digit.
4906918e2f9Sdrh */
hexDigitValue(char c)4916918e2f9Sdrh static int hexDigitValue(char c){
4926918e2f9Sdrh   if( c>='0' && c<='9' ) return c - '0';
4936918e2f9Sdrh   if( c>='a' && c<='f' ) return c - 'a' + 10;
4946918e2f9Sdrh   if( c>='A' && c<='F' ) return c - 'A' + 10;
4956918e2f9Sdrh   return -1;
4966918e2f9Sdrh }
4976918e2f9Sdrh 
4986918e2f9Sdrh /*
4996918e2f9Sdrh ** Interpret zArg as an integer value, possibly with suffixes.
5006918e2f9Sdrh */
integerValue(const char * zArg)5016918e2f9Sdrh static int integerValue(const char *zArg){
5026918e2f9Sdrh   sqlite3_int64 v = 0;
5036918e2f9Sdrh   static const struct { char *zSuffix; int iMult; } aMult[] = {
5046918e2f9Sdrh     { "KiB", 1024 },
5056918e2f9Sdrh     { "MiB", 1024*1024 },
5066918e2f9Sdrh     { "GiB", 1024*1024*1024 },
5076918e2f9Sdrh     { "KB",  1000 },
5086918e2f9Sdrh     { "MB",  1000000 },
5096918e2f9Sdrh     { "GB",  1000000000 },
5106918e2f9Sdrh     { "K",   1000 },
5116918e2f9Sdrh     { "M",   1000000 },
5126918e2f9Sdrh     { "G",   1000000000 },
5136918e2f9Sdrh   };
5146918e2f9Sdrh   int i;
5156918e2f9Sdrh   int isNeg = 0;
5166918e2f9Sdrh   if( zArg[0]=='-' ){
5176918e2f9Sdrh     isNeg = 1;
5186918e2f9Sdrh     zArg++;
5196918e2f9Sdrh   }else if( zArg[0]=='+' ){
5206918e2f9Sdrh     zArg++;
5216918e2f9Sdrh   }
5226918e2f9Sdrh   if( zArg[0]=='0' && zArg[1]=='x' ){
5236918e2f9Sdrh     int x;
5246918e2f9Sdrh     zArg += 2;
5256918e2f9Sdrh     while( (x = hexDigitValue(zArg[0]))>=0 ){
5266918e2f9Sdrh       v = (v<<4) + x;
5276918e2f9Sdrh       zArg++;
5286918e2f9Sdrh     }
5296918e2f9Sdrh   }else{
5306918e2f9Sdrh     while( ISDIGIT(zArg[0]) ){
5316918e2f9Sdrh       v = v*10 + zArg[0] - '0';
5326918e2f9Sdrh       zArg++;
5336918e2f9Sdrh     }
5346918e2f9Sdrh   }
5356918e2f9Sdrh   for(i=0; i<sizeof(aMult)/sizeof(aMult[0]); i++){
5366918e2f9Sdrh     if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
5376918e2f9Sdrh       v *= aMult[i].iMult;
5386918e2f9Sdrh       break;
5396918e2f9Sdrh     }
5406918e2f9Sdrh   }
5416918e2f9Sdrh   if( v>0x7fffffff ) fatalError("parameter too large - max 2147483648");
5426918e2f9Sdrh   return (int)(isNeg? -v : v);
5436918e2f9Sdrh }
5446918e2f9Sdrh 
5456918e2f9Sdrh /*
5466918e2f9Sdrh ** This callback is invoked by sqlite3_log().
5476918e2f9Sdrh */
sqlLog(void * pNotUsed,int iErrCode,const char * zMsg)5486918e2f9Sdrh static void sqlLog(void *pNotUsed, int iErrCode, const char *zMsg){
5496918e2f9Sdrh   printf("LOG: (%d) %s\n", iErrCode, zMsg);
5506918e2f9Sdrh   fflush(stdout);
5516918e2f9Sdrh }
5526918e2f9Sdrh 
5536918e2f9Sdrh #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
5546918e2f9Sdrh /*
5556918e2f9Sdrh ** This an SQL progress handler.  After an SQL statement has run for
5566918e2f9Sdrh ** many steps, we want to interrupt it.  This guards against infinite
5576918e2f9Sdrh ** loops from recursive common table expressions.
5586918e2f9Sdrh **
5596918e2f9Sdrh ** *pVdbeLimitFlag is true if the --limit-vdbe command-line option is used.
5606918e2f9Sdrh ** In that case, hitting the progress handler is a fatal error.
5616918e2f9Sdrh */
progressHandler(void * pVdbeLimitFlag)5626918e2f9Sdrh static int progressHandler(void *pVdbeLimitFlag){
5636918e2f9Sdrh   if( *(int*)pVdbeLimitFlag ) fatalError("too many VDBE cycles");
5646918e2f9Sdrh   return 1;
5656918e2f9Sdrh }
5666918e2f9Sdrh #endif
5676918e2f9Sdrh 
56822d709ddSdrh /*
56922d709ddSdrh ** Allowed values for the runFlags parameter to runSql()
57022d709ddSdrh */
57122d709ddSdrh #define SQL_TRACE  0x0001     /* Print each SQL statement as it is prepared */
57222d709ddSdrh #define SQL_OUTPUT 0x0002     /* Show the SQL output */
5736918e2f9Sdrh 
57422d709ddSdrh /*
57522d709ddSdrh ** Run multiple commands of SQL.  Similar to sqlite3_exec(), but does not
57622d709ddSdrh ** stop if an error is encountered.
57722d709ddSdrh */
runSql(sqlite3 * db,const char * zSql,unsigned runFlags)57822d709ddSdrh static void runSql(sqlite3 *db, const char *zSql, unsigned  runFlags){
57922d709ddSdrh   const char *zMore;
58022d709ddSdrh   const char *zEnd = &zSql[strlen(zSql)];
58122d709ddSdrh   sqlite3_stmt *pStmt;
58222d709ddSdrh 
58322d709ddSdrh   while( zSql && zSql[0] ){
58422d709ddSdrh     zMore = 0;
58522d709ddSdrh     pStmt = 0;
58622d709ddSdrh     sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zMore);
58722d709ddSdrh     assert( zMore<=zEnd );
58822d709ddSdrh     if( zMore==zSql ) break;
58922d709ddSdrh     if( runFlags & SQL_TRACE ){
59022d709ddSdrh       const char *z = zSql;
59122d709ddSdrh       int n;
59222d709ddSdrh       while( z<zMore && ISSPACE(z[0]) ) z++;
59322d709ddSdrh       n = (int)(zMore - z);
59422d709ddSdrh       while( n>0 && ISSPACE(z[n-1]) ) n--;
59522d709ddSdrh       if( n==0 ) break;
59622d709ddSdrh       if( pStmt==0 ){
59722d709ddSdrh         printf("TRACE: %.*s (error: %s)\n", n, z, sqlite3_errmsg(db));
59822d709ddSdrh       }else{
59922d709ddSdrh         printf("TRACE: %.*s\n", n, z);
60022d709ddSdrh       }
60122d709ddSdrh     }
60222d709ddSdrh     zSql = zMore;
60322d709ddSdrh     if( pStmt ){
60422d709ddSdrh       if( (runFlags & SQL_OUTPUT)==0 ){
60522d709ddSdrh         while( SQLITE_ROW==sqlite3_step(pStmt) ){}
60622d709ddSdrh       }else{
60722d709ddSdrh         int nCol = -1;
60822d709ddSdrh         int nRow;
60922d709ddSdrh         for(nRow=0; SQLITE_ROW==sqlite3_step(pStmt); nRow++){
61022d709ddSdrh           int i;
61122d709ddSdrh           if( nCol<0 ){
61222d709ddSdrh             nCol = sqlite3_column_count(pStmt);
61322d709ddSdrh           }
61422d709ddSdrh           for(i=0; i<nCol; i++){
61522d709ddSdrh             int eType = sqlite3_column_type(pStmt,i);
61622d709ddSdrh             printf("ROW[%d].%s = ", nRow, sqlite3_column_name(pStmt,i));
61722d709ddSdrh             switch( eType ){
61822d709ddSdrh               case SQLITE_NULL: {
61922d709ddSdrh                 printf("NULL\n");
62022d709ddSdrh                 break;
62122d709ddSdrh               }
62222d709ddSdrh               case SQLITE_INTEGER: {
62322d709ddSdrh                 printf("INT %s\n", sqlite3_column_text(pStmt,i));
62422d709ddSdrh                 break;
62522d709ddSdrh               }
62622d709ddSdrh               case SQLITE_FLOAT: {
62722d709ddSdrh                 printf("FLOAT %s\n", sqlite3_column_text(pStmt,i));
62822d709ddSdrh                 break;
62922d709ddSdrh               }
63022d709ddSdrh               case SQLITE_TEXT: {
63122d709ddSdrh                 printf("TEXT [%s]\n", sqlite3_column_text(pStmt,i));
63222d709ddSdrh                 break;
63322d709ddSdrh               }
63422d709ddSdrh               case SQLITE_BLOB: {
63522d709ddSdrh                 printf("BLOB (%d bytes)\n", sqlite3_column_bytes(pStmt,i));
63622d709ddSdrh                 break;
63722d709ddSdrh               }
63822d709ddSdrh             }
63922d709ddSdrh           }
64022d709ddSdrh         }
64122d709ddSdrh       }
64222d709ddSdrh       sqlite3_finalize(pStmt);
64322d709ddSdrh     }
64422d709ddSdrh   }
64522d709ddSdrh }
6466918e2f9Sdrh 
main(int argc,char ** argv)6476918e2f9Sdrh int main(int argc, char **argv){
6486918e2f9Sdrh   int i;                 /* Loop counter */
64922d709ddSdrh   int nDb = 0;           /* Number of databases to fuzz */
650*134e5270Sdrh   char **azDb = 0;       /* Names of the databases (limit: 20) */
6516918e2f9Sdrh   int verboseFlag = 0;   /* True for extra output */
6526918e2f9Sdrh   int noLookaside = 0;   /* Disable lookaside if true */
6536918e2f9Sdrh   int vdbeLimitFlag = 0; /* Stop after 100,000 VDBE ops */
6546918e2f9Sdrh   int nHeap = 0;         /* True for fixed heap size */
6556918e2f9Sdrh   int iTimeout = 0;      /* Timeout delay in seconds */
6566918e2f9Sdrh   int rc;                /* Result code from SQLite3 API calls */
6576918e2f9Sdrh   sqlite3 *db;           /* The database connection */
6586918e2f9Sdrh   sqlite3_stmt *pStmt;   /* A single SQL statement */
6596918e2f9Sdrh   Str sql;               /* SQL to run */
66022d709ddSdrh   unsigned runFlags = 0; /* Flags passed to runSql */
6616918e2f9Sdrh 
6626918e2f9Sdrh   for(i=1; i<argc; i++){
663*134e5270Sdrh     char *z = argv[i];
6646918e2f9Sdrh     if( z[0]!='-' ){
6656918e2f9Sdrh       azDb = realloc(azDb, sizeof(azDb[0])*(nDb+1));
6666918e2f9Sdrh       if( azDb==0 ) fatalError("out of memory");
6676918e2f9Sdrh       azDb[nDb++] = z;
6686918e2f9Sdrh       continue;
6696918e2f9Sdrh     }
6706918e2f9Sdrh     z++;
6716918e2f9Sdrh     if( z[0]=='-' ) z++;
6726918e2f9Sdrh     if( strcmp(z, "help")==0 ){
6736918e2f9Sdrh       showHelp(argv[0]);
6746918e2f9Sdrh     }else if( strcmp(z, "limit-mem")==0 ){
6756918e2f9Sdrh       if( i==argc-1 ) fatalError("missing argument to %s", argv[i]);
6766918e2f9Sdrh       nHeap = integerValue(argv[++i]);
6776918e2f9Sdrh     }else if( strcmp(z, "no-lookaside")==0 ){
6786918e2f9Sdrh       noLookaside = 1;
6796918e2f9Sdrh     }else if( strcmp(z, "timeout")==0 ){
6806918e2f9Sdrh       if( i==argc-1 ) fatalError("missing argument to %s", argv[i]);
6816918e2f9Sdrh       iTimeout = integerValue(argv[++i]);
6826918e2f9Sdrh     }else if( strcmp(z, "trace")==0 ){
68322d709ddSdrh       runFlags |= SQL_OUTPUT|SQL_TRACE;
6846918e2f9Sdrh     }else if( strcmp(z, "limit-vdbe")==0 ){
6856918e2f9Sdrh       vdbeLimitFlag = 1;
6866918e2f9Sdrh     }else if( strcmp(z, "v")==0 || strcmp(z, "verbose")==0 ){
6876918e2f9Sdrh       verboseFlag = 1;
68822d709ddSdrh       runFlags |= SQL_TRACE;
6896918e2f9Sdrh     }else{
6906918e2f9Sdrh       fatalError("unknown command-line option: \"%s\"\n", argv[i]);
6916918e2f9Sdrh     }
6926918e2f9Sdrh   }
6936918e2f9Sdrh   if( nDb==0 ){
6946918e2f9Sdrh     showHelp(argv[0]);
6956918e2f9Sdrh   }
6966918e2f9Sdrh   if( verboseFlag ){
6976918e2f9Sdrh     sqlite3_config(SQLITE_CONFIG_LOG, sqlLog);
6986918e2f9Sdrh   }
6996918e2f9Sdrh   if( nHeap>0 ){
7006918e2f9Sdrh     void *pHeap = malloc( nHeap );
7016918e2f9Sdrh     if( pHeap==0 ) fatalError("cannot allocate %d-byte heap\n", nHeap);
7026918e2f9Sdrh     rc = sqlite3_config(SQLITE_CONFIG_HEAP, pHeap, nHeap, 32);
7036918e2f9Sdrh     if( rc ) fatalError("heap configuration failed: %d\n", rc);
7046918e2f9Sdrh   }
7056918e2f9Sdrh   if( noLookaside ){
7066918e2f9Sdrh     sqlite3_config(SQLITE_CONFIG_LOOKASIDE, 0, 0);
7076918e2f9Sdrh   }
7086918e2f9Sdrh   inmemVfsRegister();
7096918e2f9Sdrh   formatVfs();
7106918e2f9Sdrh   StrInit(&sql);
7116918e2f9Sdrh #ifdef __unix__
7126918e2f9Sdrh   signal(SIGALRM, timeoutHandler);
7136918e2f9Sdrh #endif
7146918e2f9Sdrh   for(i=0; i<nDb; i++){
7156918e2f9Sdrh     if( verboseFlag && nDb>1 ){
7166918e2f9Sdrh       printf("DATABASE-FILE: %s\n", azDb[i]);
7176918e2f9Sdrh       fflush(stdout);
7186918e2f9Sdrh     }
7196918e2f9Sdrh     if( iTimeout ) setAlarm(iTimeout);
7206918e2f9Sdrh     createVFile("test.db", azDb[i]);
7216918e2f9Sdrh     rc = sqlite3_open_v2("test.db", &db, SQLITE_OPEN_READWRITE, "inmem");
7226918e2f9Sdrh     if( rc ){
7236918e2f9Sdrh       printf("cannot open test.db for \"%s\"\n", azDb[i]);
7246918e2f9Sdrh       reformatVfs();
7256918e2f9Sdrh       continue;
7266918e2f9Sdrh     }
7276918e2f9Sdrh #ifndef SQLITE_OMIT_PROGRESS_CALLBACK
7286918e2f9Sdrh     if( vdbeLimitFlag ){
7296918e2f9Sdrh       sqlite3_progress_handler(db, 100000, progressHandler, &vdbeLimitFlag);
7306918e2f9Sdrh     }
7316918e2f9Sdrh #endif
7326918e2f9Sdrh     rc = sqlite3_prepare_v2(db, "SELECT sql FROM autoexec", -1, &pStmt, 0);
7336918e2f9Sdrh     if( rc==SQLITE_OK ){
7346918e2f9Sdrh       while( SQLITE_ROW==sqlite3_step(pStmt) ){
7356918e2f9Sdrh         StrAppend(&sql, (const char*)sqlite3_column_text(pStmt, 0));
7366918e2f9Sdrh         StrAppend(&sql, "\n");
7376918e2f9Sdrh       }
7386918e2f9Sdrh     }
7396918e2f9Sdrh     sqlite3_finalize(pStmt);
7406918e2f9Sdrh     StrAppend(&sql, "PRAGMA integrity_check;\n");
74122d709ddSdrh     runSql(db, StrStr(&sql), runFlags);
7426918e2f9Sdrh     sqlite3_close(db);
7436918e2f9Sdrh     reformatVfs();
7446918e2f9Sdrh     StrFree(&sql);
7456918e2f9Sdrh     if( sqlite3_memory_used()>0 ){
7466918e2f9Sdrh       free(azDb);
7476918e2f9Sdrh       reformatVfs();
7486918e2f9Sdrh       fatalError("memory leak of %lld bytes", sqlite3_memory_used());
7496918e2f9Sdrh     }
7506918e2f9Sdrh   }
7516918e2f9Sdrh   StrFree(&sql);
7526918e2f9Sdrh   reformatVfs();
7536918e2f9Sdrh   return 0;
7546918e2f9Sdrh }
755