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